Skill Tracer
Skills › Scientific Agent Skills › scvi-tools › models-scrna-seq.md

models-scrna-seq.md

178 lines · skills/scvi-tools/references/models-scrna-seq.md at 5f2bc03

Open on GitHub
1# RNA models
2
3Targets scvi-tools 1.5.1. Code is illustrative and source-verified; short synthetic
4SCVI/SCANVI fitting, predictions, DE and persistence were exercised in CPU tests. Unless stated otherwise, examples require an
5AnnData with measured RNA counts in `layers['counts']`, unique gene/cell IDs and
6valid named metadata. Complete QC and feature selection before setup.
7

RNA models

Targets scvi-tools 1.5.1. Code is illustrative and source-verified; short synthetic SCVI/SCANVI fitting, predictions, DE and persistence were exercised in CPU tests. Unless stated otherwise, examples require an AnnData with measured RNA counts in layers['counts'], unique gene/cell IDs and valid named metadata. Complete QC and feature selection before setup.

Raw lines 1 to 7
8## SCVI and SCANVI
9
10```python
11import scvi
13scvi.model.SCVI.setup_anndata(adata, layer="counts", batch_key="batch")
14rna_model = scvi.model.SCVI(adata, n_latent=20, gene_likelihood="nb")
15rna_model.train()
16adata.obsm["X_scVI"] = rna_model.get_latent_representation()
17normalized = rna_model.get_normalized_expression(library_size=1e4)
19# cell_type contains known labels and a literal Unknown for unlabeled cells.
20scanvi_model = scvi.model.SCANVI.from_scvi_model(
21 rna_model, labels_key="cell_type", unlabeled_category="Unknown",
23scanvi_model.train()
24predictions = scanvi_model.predict()
25probabilities = scanvi_model.predict(soft=True)
26```
28For training from scratch, use `SCANVI.setup_anndata` with `labels_key` and
29`unlabeled_category`, then `SCANVI(adata)`. There is no `predict_proba()` method;
30`predict(soft=True)` returns class probabilities. Provide `labels_key` explicitly
31when the source SCVI model was not registered with labels. Do not reuse a SCANVI
32registry to initialize a different class without that class's setup.
34SCVI defaults include `n_latent=10`, `n_hidden=128`, `n_layers=1`,
35`dropout_rate=0.1`, `gene_likelihood='zinb'`, and `dispersion='gene'`.
36Dispersion options include gene, gene-batch, gene-label and gene-cell; a gene-batch
37parameter is not a cell-specific parameter. Choice of likelihood requires checking
38the assay and fit, not simply counting zeros.
40Embeddings are candidates for integration, not guaranteed batch-free biology.
41Normalized expression is decoded model output and does not replace measured counts.
42Evaluate annotation on held-out donors, label ontology consistency and absent
43reference types; large class probabilities alone do not establish calibration.

SCVI and SCANVI

import scvi

scvi.model.SCVI.setup_anndata(adata, layer="counts", batch_key="batch")
rna_model = scvi.model.SCVI(adata, n_latent=20, gene_likelihood="nb")
rna_model.train()
adata.obsm["X_scVI"] = rna_model.get_latent_representation()
normalized = rna_model.get_normalized_expression(library_size=1e4)

# cell_type contains known labels and a literal Unknown for unlabeled cells.
scanvi_model = scvi.model.SCANVI.from_scvi_model(
    rna_model, labels_key="cell_type", unlabeled_category="Unknown",
)
scanvi_model.train()
predictions = scanvi_model.predict()
probabilities = scanvi_model.predict(soft=True)

For training from scratch, use SCANVI.setup_anndata with labels_key and unlabeled_category, then SCANVI(adata). There is no predict_proba() method; predict(soft=True) returns class probabilities. Provide labels_key explicitly when the source SCVI model was not registered with labels. Do not reuse a SCANVI registry to initialize a different class without that class's setup.

SCVI defaults include n_latent=10, n_hidden=128, n_layers=1, dropout_rate=0.1, gene_likelihood='zinb', and dispersion='gene'. Dispersion options include gene, gene-batch, gene-label and gene-cell; a gene-batch parameter is not a cell-specific parameter. Choice of likelihood requires checking the assay and fit, not simply counting zeros.

Embeddings are candidates for integration, not guaranteed batch-free biology. Normalized expression is decoded model output and does not replace measured counts. Evaluate annotation on held-out donors, label ontology consistency and absent reference types; large class probabilities alone do not establish calibration.

Raw lines 8 to 44
45## AUTOZI
47```python
48scvi.model.AUTOZI.setup_anndata(adata, layer="counts")
49model = scvi.model.AUTOZI(adata)
50model.train()
51posterior_beta_parameters = model.get_alphas_betas()
52```
54AUTOZI assesses evidence for extra zero inflation under its count-mixture model.
55`get_alphas_betas()` returns beta-distribution parameters, not a vector labeling
56technical zeros or direct per-gene dropout probabilities. It does not determine
57whether a particular observed zero is biological or technical.

AUTOZI

scvi.model.AUTOZI.setup_anndata(adata, layer="counts")
model = scvi.model.AUTOZI(adata)
model.train()
posterior_beta_parameters = model.get_alphas_betas()

AUTOZI assesses evidence for extra zero inflation under its count-mixture model. get_alphas_betas() returns beta-distribution parameters, not a vector labeling technical zeros or direct per-gene dropout probabilities. It does not determine whether a particular observed zero is biological or technical.

Raw lines 45 to 58
59## VELOVI
61VELOVI requires **preprocessed continuous** spliced and unspliced abundance layers,
62commonly scVelo moments `Ms` and `Mu`. Preserve original spliced/unspliced counts
63and record filtering, normalization, neighborhood and scaling choices.
65```python
66scvi.external.VELOVI.setup_anndata(
67 velocity_adata, spliced_layer="Ms", unspliced_layer="Mu",
69velocity_model = scvi.external.VELOVI(velocity_adata)
70velocity_model.train()
71latent_time = velocity_model.get_latent_time()
72velocities = velocity_model.get_velocity()
73rates = velocity_model.get_rates()
74```
76This setup has no batch-covariate argument. Do not advertise generic batch-corrected
77velocity. Latent time can be gene/cell-specific and is not observed chronological
78time. Validate kinetic assumptions, phase portraits, direction uncertainty and
79preprocessing sensitivity before interpreting a trajectory or causal transition.
80Follow the official velocity tutorial when exporting rescaled values to scVelo;
81raw model outputs are not an interchangeable velocity graph.

VELOVI

VELOVI requires preprocessed continuous spliced and unspliced abundance layers, commonly scVelo moments Ms and Mu. Preserve original spliced/unspliced counts and record filtering, normalization, neighborhood and scaling choices.

scvi.external.VELOVI.setup_anndata(
    velocity_adata, spliced_layer="Ms", unspliced_layer="Mu",
)
velocity_model = scvi.external.VELOVI(velocity_adata)
velocity_model.train()
latent_time = velocity_model.get_latent_time()
velocities = velocity_model.get_velocity()
rates = velocity_model.get_rates()

This setup has no batch-covariate argument. Do not advertise generic batch-corrected velocity. Latent time can be gene/cell-specific and is not observed chronological time. Validate kinetic assumptions, phase portraits, direction uncertainty and preprocessing sensitivity before interpreting a trajectory or causal transition. Follow the official velocity tutorial when exporting rescaled values to scVelo; raw model outputs are not an interchangeable velocity graph.

Raw lines 59 to 82
83## ContrastiveVI
85```python
86import numpy as np
88scvi.external.ContrastiveVI.setup_anndata(adata, layer="counts", batch_key="batch")
89model = scvi.external.ContrastiveVI(
90 adata, n_background_latent=10, n_salient_latent=10,
92background_idx = np.flatnonzero(adata.obs["condition"].eq("control"))
93target_idx = np.flatnonzero(adata.obs["condition"].eq("treated"))
94assert len(background_idx) and len(target_idx)
95model.train(background_indices=background_idx, target_indices=target_idx)
96background = model.get_latent_representation(representation_kind="background")
97salient = model.get_latent_representation(representation_kind="salient")
98```
100The salient latent variable models target-specific variation. Confounding between
101condition, donor or technology can also enter that space; it does not isolate a
102causal perturbation effect automatically.

ContrastiveVI

import numpy as np

scvi.external.ContrastiveVI.setup_anndata(adata, layer="counts", batch_key="batch")
model = scvi.external.ContrastiveVI(
    adata, n_background_latent=10, n_salient_latent=10,
)
background_idx = np.flatnonzero(adata.obs["condition"].eq("control"))
target_idx = np.flatnonzero(adata.obs["condition"].eq("treated"))
assert len(background_idx) and len(target_idx)
model.train(background_indices=background_idx, target_indices=target_idx)
background = model.get_latent_representation(representation_kind="background")
salient = model.get_latent_representation(representation_kind="salient")

The salient latent variable models target-specific variation. Confounding between condition, donor or technology can also enter that space; it does not isolate a causal perturbation effect automatically.

Raw lines 83 to 103
104## CellAssign
106Use a **genes-by-cell-types** binary marker DataFrame. Match marker rows exactly
107to the modeled gene order, and compute size factors from the full count library
108before restricting to marker genes.
110```python
111import numpy as np
112import pandas as pd
114markers = pd.DataFrame({
115 "CD4 T": [1, 1, 0, 0], "CD8 T": [1, 0, 1, 0], "B": [0, 0, 0, 1],
116}, index=["CD3D", "CD4", "CD8A", "CD19"])
117assert markers.index.isin(adata.var_names).all()
118lib = np.asarray(adata.layers["counts"].sum(axis=1)).ravel()
119assert (lib > 0).all()
120adata.obs["size_factor"] = lib / lib.mean()
121marker_adata = adata[:, markers.index].copy()
122scvi.external.CellAssign.setup_anndata(
123 marker_adata, layer="counts", size_factor_key="size_factor",
125model = scvi.external.CellAssign(marker_adata, markers)
126model.train()
127probabilities = model.predict()
128```
130This tiny marker matrix illustrates orientation, not a validated annotation panel.
131Marker absence, non-specific expression and missing reference types affect results.
132`predict` returns soft assignments; select labels only after checking uncertainty.

CellAssign

Use a genes-by-cell-types binary marker DataFrame. Match marker rows exactly to the modeled gene order, and compute size factors from the full count library before restricting to marker genes.

import numpy as np
import pandas as pd

markers = pd.DataFrame({
    "CD4 T": [1, 1, 0, 0], "CD8 T": [1, 0, 1, 0], "B": [0, 0, 0, 1],
}, index=["CD3D", "CD4", "CD8A", "CD19"])
assert markers.index.isin(adata.var_names).all()
lib = np.asarray(adata.layers["counts"].sum(axis=1)).ravel()
assert (lib > 0).all()
adata.obs["size_factor"] = lib / lib.mean()
marker_adata = adata[:, markers.index].copy()
scvi.external.CellAssign.setup_anndata(
    marker_adata, layer="counts", size_factor_key="size_factor",
)
model = scvi.external.CellAssign(marker_adata, markers)
model.train()
probabilities = model.predict()

This tiny marker matrix illustrates orientation, not a validated annotation panel. Marker absence, non-specific expression and missing reference types affect results. predict returns soft assignments; select labels only after checking uncertainty.

Raw lines 104 to 133
134## SOLO
136```python
137# rna_model must have been trained using only counts and optional batch_key.
138solo = scvi.external.SOLO.from_scvi_model(rna_model, restrict_to_batch="capture1")
139solo.train()
140scores = solo.predict(soft=True, return_logits=False)
141```
143SOLO does not support extra categorical/continuous covariates in the source model.
144Analyze separate captures appropriately: simulated cross-capture doublets are not
145physical droplet doublets. `restrict_to_batch` must match a registered batch value.
146Returned rows correspond to source-cell barcodes (simulated doublets are omitted by
147default); align the index before writing into `.obs`, especially after restriction.
148Probability thresholds and expected doublet rates require assay-specific validation.

SOLO

# rna_model must have been trained using only counts and optional batch_key.
solo = scvi.external.SOLO.from_scvi_model(rna_model, restrict_to_batch="capture1")
solo.train()
scores = solo.predict(soft=True, return_logits=False)

SOLO does not support extra categorical/continuous covariates in the source model. Analyze separate captures appropriately: simulated cross-capture doublets are not physical droplet doublets. restrict_to_batch must match a registered batch value. Returned rows correspond to source-cell barcodes (simulated doublets are omitted by default); align the index before writing into .obs, especially after restriction. Probability thresholds and expected doublet rates require assay-specific validation.

Raw lines 134 to 149
150## LinearSCVI and AmortizedLDA
152```python
153scvi.model.LinearSCVI.setup_anndata(adata, layer="counts", batch_key="batch")
154linear = scvi.model.LinearSCVI(adata, n_latent=10)
155linear.train()
156loadings = linear.get_loadings()
158scvi.model.AmortizedLDA.setup_anndata(adata, layer="counts")
159lda = scvi.model.AmortizedLDA(adata, n_topics=10)
160lda.train()
161cell_topics = lda.get_latent_representation()
162gene_topics = lda.get_feature_by_topic()
163```
165Linear decoder loadings and LDA topics can aid interpretation; assess stability and
166gene enrichment rather than treating components as uniquely identified pathways.
167AmortizedLDA does not inherit every SCVI normalization or covariate API.
169Sources: [SCVI](https://docs.scvi-tools.org/en/stable/api/reference/scvi.model.SCVI.html),
170[SCANVI](https://docs.scvi-tools.org/en/stable/api/reference/scvi.model.SCANVI.html),
171[RNA prediction mixin](https://github.com/scverse/scvi-tools/blob/1.5.1/src/scvi/model/base/_training_mixin.py),
172[AUTOZI](https://github.com/scverse/scvi-tools/blob/1.5.1/src/scvi/model/_autozi.py),
173[VELOVI](https://github.com/scverse/scvi-tools/blob/1.5.1/src/scvi/external/velovi/_model.py),
174[ContrastiveVI](https://github.com/scverse/scvi-tools/blob/1.5.1/src/scvi/external/contrastivevi/_model.py),
175[CellAssign](https://github.com/scverse/scvi-tools/blob/1.5.1/src/scvi/external/cellassign/_model.py),
176[SOLO](https://github.com/scverse/scvi-tools/blob/1.5.1/src/scvi/external/solo/_model.py),
177[LinearSCVI](https://github.com/scverse/scvi-tools/blob/1.5.1/src/scvi/model/_linear_scvi.py),
178[AmortizedLDA](https://github.com/scverse/scvi-tools/blob/1.5.1/src/scvi/model/_amortizedlda.py).

LinearSCVI and AmortizedLDA

scvi.model.LinearSCVI.setup_anndata(adata, layer="counts", batch_key="batch")
linear = scvi.model.LinearSCVI(adata, n_latent=10)
linear.train()
loadings = linear.get_loadings()

scvi.model.AmortizedLDA.setup_anndata(adata, layer="counts")
lda = scvi.model.AmortizedLDA(adata, n_topics=10)
lda.train()
cell_topics = lda.get_latent_representation()
gene_topics = lda.get_feature_by_topic()

Linear decoder loadings and LDA topics can aid interpretation; assess stability and gene enrichment rather than treating components as uniquely identified pathways. AmortizedLDA does not inherit every SCVI normalization or covariate API.

Sources: SCVI, SCANVI, RNA prediction mixin, AUTOZI, VELOVI, ContrastiveVI, CellAssign, SOLO, LinearSCVI, AmortizedLDA.

Raw lines 150 to 178