|
| 1 | +"""Joint Embedding SCVI model.""" |
| 2 | + |
| 3 | +from __future__ import annotations |
| 4 | + |
| 5 | +from typing import TYPE_CHECKING |
| 6 | + |
| 7 | +from scvi.model._scvi import SCVI |
| 8 | +from scvi.module import JointEmbeddingVAE |
| 9 | + |
| 10 | +if TYPE_CHECKING: |
| 11 | + from typing import Literal |
| 12 | + |
| 13 | + from anndata import AnnData |
| 14 | + |
| 15 | + |
| 16 | +class JointEmbeddingSCVI(SCVI): |
| 17 | + """SCVI with joint embedding loss using binomial thinning and CCO. |
| 18 | +
|
| 19 | + This model extends the standard SCVI with a cross-correlation objective (CCO) |
| 20 | + loss that encourages the embedding of a thinned view to match the embedding |
| 21 | + of the original data. This promotes robustness to count dropout/noise. |
| 22 | +
|
| 23 | + Thinning probabilities are dynamically sampled per cell to produce target |
| 24 | + library sizes that are log-uniform between min_library_size and the observed |
| 25 | + library size. This matches realistic library size variation in single-cell data. |
| 26 | +
|
| 27 | + Parameters |
| 28 | + ---------- |
| 29 | + adata |
| 30 | + AnnData object that has been registered via :meth:`~scvi.model.SCVI.setup_anndata`. |
| 31 | + registry |
| 32 | + Registry of the datamodule used to train the model, passed through when training |
| 33 | + without an :class:`~anndata.AnnData` object (see :class:`~scvi.model.SCVI`). |
| 34 | + joint_embedding_weight |
| 35 | + Weight for the CCO loss. Default is 100.0. |
| 36 | + lambda_off_diag |
| 37 | + Off-diagonal penalty in CCO loss. Default is 0.01. |
| 38 | + min_library_size |
| 39 | + Minimum target library size for thinning. Default is 10. |
| 40 | + Thinned library sizes are sampled log-uniformly between this |
| 41 | + value and the observed library size. |
| 42 | + reconstruction_weight |
| 43 | + Weight for reconstruction loss. Default is 1.0. |
| 44 | + Set to 0.0 for pure self-supervised training with only CCO loss. |
| 45 | + variance_weight |
| 46 | + Weight for variance regularization loss (VICReg-style). Default is 0.0. |
| 47 | + Set to positive value (e.g., 1.0) to prevent dimension collapse |
| 48 | + in self-supervised training. |
| 49 | + use_joint_embedding |
| 50 | + Whether to use joint embedding loss. Default is True. |
| 51 | + Set to False to train as standard SCVI. |
| 52 | + n_hidden |
| 53 | + Number of nodes per hidden layer. |
| 54 | + n_latent |
| 55 | + Dimensionality of the latent space. |
| 56 | + n_layers |
| 57 | + Number of hidden layers used for encoder and decoder NNs. |
| 58 | + dropout_rate |
| 59 | + Dropout rate for neural networks. |
| 60 | + dispersion |
| 61 | + One of the following: |
| 62 | +
|
| 63 | + * ``'gene'`` - dispersion parameter of NB is constant per gene across cells |
| 64 | + * ``'gene-batch'`` - dispersion can differ between different batches |
| 65 | + * ``'gene-label'`` - dispersion can differ between different labels |
| 66 | + * ``'gene-cell'`` - dispersion can differ for every gene in every cell |
| 67 | + gene_likelihood |
| 68 | + One of: |
| 69 | +
|
| 70 | + * ``'nb'`` - Negative binomial distribution |
| 71 | + * ``'zinb'`` - Zero-inflated negative binomial distribution |
| 72 | + * ``'poisson'`` - Poisson distribution |
| 73 | + * ``'normal'`` - ``EXPERIMENTAL`` Normal distribution |
| 74 | + use_observed_lib_size |
| 75 | + If ``True``, use the observed library size for RNA as the scaling factor in the mean of the |
| 76 | + conditional distribution. |
| 77 | + latent_distribution |
| 78 | + One of: |
| 79 | +
|
| 80 | + * ``'normal'`` - Normal distribution |
| 81 | + * ``'ln'`` - Logistic normal distribution (Normal(0, I) transformed by softmax) |
| 82 | + **kwargs |
| 83 | + Additional keyword arguments for :class:`~scvi.module.JointEmbeddingVAE`. |
| 84 | +
|
| 85 | + Examples |
| 86 | + -------- |
| 87 | + >>> adata = anndata.read_h5ad(path_to_anndata) |
| 88 | + >>> scvi.model.JointEmbeddingSCVI.setup_anndata(adata, batch_key="batch") |
| 89 | + >>> model = scvi.model.JointEmbeddingSCVI( |
| 90 | + ... adata, |
| 91 | + ... joint_embedding_weight=1.0, |
| 92 | + ... lambda_off_diag=0.01, |
| 93 | + ... ) |
| 94 | + >>> model.train() |
| 95 | + >>> latent = model.get_latent_representation() |
| 96 | +
|
| 97 | + See Also |
| 98 | + -------- |
| 99 | + :class:`~scvi.model.SCVI` |
| 100 | + :class:`~scvi.module.JointEmbeddingVAE` |
| 101 | + """ |
| 102 | + |
| 103 | + _module_cls = JointEmbeddingVAE |
| 104 | + |
| 105 | + def __init__( |
| 106 | + self, |
| 107 | + adata: AnnData | None = None, |
| 108 | + registry: dict | None = None, |
| 109 | + joint_embedding_weight: float = 100.0, |
| 110 | + lambda_off_diag: float = 0.01, |
| 111 | + min_library_size: float = 10.0, |
| 112 | + reconstruction_weight: float = 1.0, |
| 113 | + variance_weight: float = 0.0, |
| 114 | + use_joint_embedding: bool = True, |
| 115 | + n_hidden: int = 128, |
| 116 | + n_latent: int = 10, |
| 117 | + n_layers: int = 1, |
| 118 | + dropout_rate: float = 0.1, |
| 119 | + dispersion: Literal["gene", "gene-batch", "gene-label", "gene-cell"] = "gene", |
| 120 | + gene_likelihood: Literal["zinb", "nb", "poisson", "normal"] = "zinb", |
| 121 | + use_observed_lib_size: bool = True, |
| 122 | + latent_distribution: Literal["normal", "ln"] = "normal", |
| 123 | + **kwargs, |
| 124 | + ): |
| 125 | + # Pass joint embedding params through kwargs to module |
| 126 | + super().__init__( |
| 127 | + adata=adata, |
| 128 | + registry=registry, |
| 129 | + n_hidden=n_hidden, |
| 130 | + n_latent=n_latent, |
| 131 | + n_layers=n_layers, |
| 132 | + dropout_rate=dropout_rate, |
| 133 | + dispersion=dispersion, |
| 134 | + gene_likelihood=gene_likelihood, |
| 135 | + use_observed_lib_size=use_observed_lib_size, |
| 136 | + latent_distribution=latent_distribution, |
| 137 | + joint_embedding_weight=joint_embedding_weight, |
| 138 | + lambda_off_diag=lambda_off_diag, |
| 139 | + min_library_size=min_library_size, |
| 140 | + reconstruction_weight=reconstruction_weight, |
| 141 | + variance_weight=variance_weight, |
| 142 | + use_joint_embedding=use_joint_embedding, |
| 143 | + **kwargs, |
| 144 | + ) |
| 145 | + |
| 146 | + # Update model summary string |
| 147 | + self._model_summary_string = ( |
| 148 | + "JointEmbeddingSCVI model with the following parameters: \n" |
| 149 | + f"n_hidden: {n_hidden}, n_latent: {n_latent}, n_layers: {n_layers}, " |
| 150 | + f"dropout_rate: {dropout_rate}, dispersion: {dispersion}, " |
| 151 | + f"gene_likelihood: {gene_likelihood}, latent_distribution: {latent_distribution}, " |
| 152 | + f"joint_embedding_weight: {joint_embedding_weight}, " |
| 153 | + f"lambda_off_diag: {lambda_off_diag}, min_library_size: {min_library_size}, " |
| 154 | + f"reconstruction_weight: {reconstruction_weight}, " |
| 155 | + f"variance_weight: {variance_weight}, " |
| 156 | + f"use_joint_embedding: {use_joint_embedding}." |
| 157 | + ) |
0 commit comments