Single-cell and perturbations
Gaussian reparameterization, KL, and a minibatch ELBO
scVIscANVItotalVIMULTIVICPA
Free account with email, Google or GitHub. Your code runs in an isolated PyTorch sandbox.
Your task
Sample a diagonal-Gaussian latent variable using supplied noise and compute its posterior/prior densities and analytic KL divergence. Combine these with supplied reconstruction terms into a masked minibatch negative ELBO.
Function signature
diagonal_gaussian_vae_terms(
mean: torch.Tensor,
log_variance: torch.Tensor,
noise: torch.Tensor,
prior_mean: torch.Tensor,
prior_log_variance: torch.Tensor,
reconstruction_log_prob: torch.Tensor,
library_kl: torch.Tensor,
masks: dict,
kl_weight: float = 1.0,
) -> dict[str, torch.Tensor]Worked example
A sample and a distribution penalty are different
Take one cell and one latent dimension: mean=[[1]], log_variance=[[0]], noise=[[1]], prior_mean=[0], prior_log_variance=[0]. Both standard deviations are 1, so z=[[2]]. The analytic KL compares the distributions, while the two densities are evaluated at that sample:
\begin{aligned}
\mathrm{KL}(q\parallel p)&=\tfrac12(1+1^2-1)=0.5,\\
\log q(z)&=-\tfrac12\bigl(\log(2\pi)+1\bigr)\approx-1.418939,\\
\log p(z)&=-\tfrac12\bigl(\log(2\pi)+4\bigr)\approx-2.918939.
\end{aligned}
The last two quantities are returned as log_qz and log_pz. With reconstruction_log_prob=[[-2]], observed_mask=[[True]], library_kl=[0.25], cell_mask=[True], and kl_weight=2, reconstruction NLL is 2 and both the cell negative ELBO and minibatch negative ELBO are 2 + 2·0.5 + 0.25 = 3.25.
Parameters
| Parameter | Shape and meaning |
|---|---|
meantorch.Tensor | [B, D][B,D] posterior means. |
log_variancetorch.Tensor | [B, D]Posterior log variances. |
noisetorch.Tensor | [B, D]Supplied fixed Gaussian variates for reparameterization. |
prior_meantorch.Tensor | [D] or [B, D]Prior mean shared across cells or supplied separately for each cell. |
prior_log_variancetorch.Tensor | [D] or [B, D]Or [B,D] prior log variances. |
reconstruction_log_probtorch.Tensor | [B, G]Supplied per-gene log likelihoods; finite ignored values allowed at missing entries. |
library_kltorch.Tensor | [B]Supplied unannealed KL contribution, commonly all zero. |
masksdict | Supplied masks. Each field below defines what True includes or permits. |
kl_weightfloatDefault 1.0 | Multiplier on the latent KL term. |
Return
dict[str, torch.Tensor]
Return exactly the named fields applicable to this operation.
Required behavior
- Implement a diagonal-Gaussian sample, log densities, analytic KL and minibatch negative ELBO.
mean,log_varianceand suppliednoisehave shape(B,D).prior_meanandprior_log_variancehave shape(D,)or(B,D)and broadcast over cells. All tensors are finite and exponentials of tested log-variances are representable. - Log-variance is
\operatorname{log}(\sigma^{2}), not a standard deviation or variance.B,D,G \ge 1.noiseis already sampled; do not generate randomness.z = \operatorname{mean} + \operatorname{exp}(0.5\cdot \mathrm{log\_variance})\cdot \mathrm{noise}. \mathrm{log\_qz}[b] = -0.5\cdot \sum_{d}[\operatorname{log}(2\cdot \pi)+\mathrm{log\_variance}+(z-\operatorname{mean})^{2}\cdot \operatorname{exp}(-\mathrm{log\_variance})].log_pzusesprior_meanandprior_log_variancein the same density, evaluated atz.\begin{gathered}\mathrm{kl}[b] = 0.5\cdot \sum_{d}[\mathrm{prior\_log\_variance}-\mathrm{log\_variance} + \operatorname{exp}(\mathrm{log\_variance}-\mathrm{prior\_log\_variance})\\{}+(\operatorname{mean}-\mathrm{prior\_mean})^{2}\cdot \operatorname{exp}(-\mathrm{prior\_log\_variance})-1]\end{gathered}.- The
log_qzquadratic can equivalently be\mathrm{noise}^{2}at the supplied reparameterized sample.reconstruction_log_probis a supplied[B,G]tensor, not recomputed fromzhere.observed_maskis bool[B,G]:Trueincludes a gene likelihood,Falseis missing. \mathrm{reconstruction\_nll}[b] = -\sum_{g} \operatorname{where}(\mathrm{observed\_mask}, \mathrm{reconstruction\_log\_prob}, 0). A zero-valued log probability is not missing.library_klis a supplied[B]term, usually zero with observed libraries. The onlyoptioniskl_weight(default1.0, nonnegative).\mathrm{cell\_negative\_elbo} = \mathrm{reconstruction\_nll} + \mathrm{kl\_weight}\cdot \mathrm{kl} + \mathrm{library\_kl}.Only the latentklis annealed;library_klis never multiplied bykl_weight.cell_maskis bool[B]:Trueincludes a cell innegative_elbo, which is themeanofcell_negative_elboover included cells.- If none are included, return exactly zero. A valid cell with no observed genes still contributes its KL terms unless excluded by
cell_mask. Other outputs, including per-cell diagnostics, are not cell-masked. Do not clamp the analytic KL or add\epsilon. - Reject a negative
kl_weightwithValueError; other declared input conditions are preconditions.
Why this matters
Reparameterization separates supplied randomness from differentiable mean/variance parameters; the ELBO then balances reconstruction and regularization.
Starter code
You write the body of this function in the BioTorch workspace. Your code runs in an isolated PyTorch sandbox; Run checks the public examples and Submit grades the full test suite, including gradients.
import torch
def diagonal_gaussian_vae_terms(
mean: torch.Tensor, # (B, D)
log_variance: torch.Tensor, # (B, D)
noise: torch.Tensor, # (B, D)
prior_mean: torch.Tensor, # (D,) or (B, D)
prior_log_variance: torch.Tensor, # (D,) or (B, D)
reconstruction_log_prob: torch.Tensor, # (B, G)
library_kl: torch.Tensor, # (B,)
masks: dict,
kl_weight: float = 1.0,
) -> dict[str, torch.Tensor]:
"""Return dict[str, torch.Tensor]:
z: (B, D).
log_qz: (B,).
log_pz: (B,).
kl: (B,).
reconstruction_nll: (B,).
cell_negative_elbo: (B,).
negative_elbo: Scalar tensor, shape ()."""
# Implement the operation. Inputs and test setup are supplied by BioTorch.
raise NotImplementedError("Implement diagonal_gaussian_vae_terms")
Ready to implement it?
3 progressive hints, a solution walkthrough, and grading that checks values, shapes and gradients are waiting in the workspace.
Free account with email, Google or GitHub. Your code runs in an isolated PyTorch sandbox.
Sources and further reading
A primitive exercise, not an end-to-end reproduction of the named models. No affiliation or endorsement is implied.