Single-cell and perturbations
Library-size-scaled rates and batch-specific dispersion
scVItotalVIMULTIVI
Free account with email, Google or GitHub. Your code runs in an isolated PyTorch sandbox.
Your task
Turn supported gene logits into proportions that sum to one, scale them by each cell’s library size, and select the requested dispersion parameters. Return proportions, rates, dispersion, and library size.
Function signature
library_size_dispersion_decoder(
gene_logits: torch.Tensor,
gene_mask: torch.Tensor,
library: torch.Tensor,
log_dispersion: torch.Tensor,
batch_id: torch.Tensor | None = None,
library_mode: str = 'log',
dispersion_mode: str = 'gene',
) -> dict[str, torch.Tensor]Worked example
Allocate a library to unequal gene proportions
For one cell use gene_logits=[[0,log(3),100]], gene_mask=[[True,True,False]], library=[[8]], log_dispersion=[0,log(2),log(4)], and batch_id=[0]. Set library_mode="observed" and dispersion_mode="gene". Only weights 1 and 3 enter the softmax denominator, so proportions=[[0.25,0.75,0]], rate=[[2,6,0]], and library_size=[[8]]. The excluded large logit receives no molecules. Dispersion describes the parameter table, so inverse_dispersion=[[1,2,4]] includes the excluded gene.
Parameters
| Parameter | Shape and meaning |
|---|---|
gene_logitstorch.Tensor | [B, G]Finite unnormalized expression-composition logits. |
gene_masktorch.Tensor | [B, G]True includes a gene in the simplex support. |
librarytorch.Tensor | [B, 1]Log depth in log mode, nonnegative raw depth in observed mode. |
log_dispersiontorch.Tensor | [G] or [K, G]Gene parameters or [K,G] batch-by-gene parameters, as configured. |
batch_idtorch.Tensor | NoneDefault None | [B]Batch IDs; ignored in gene dispersion mode. |
library_modestrDefault 'log' | "log" exponentiates the supplied log library; "observed" uses the supplied nonnegative library size directly. |
dispersion_modestrDefault 'gene' | "gene" shares one dispersion vector across cells; "batch" selects a batch-by-gene row using batch_id. |
Return
dict[str, torch.Tensor]
Return exactly the named fields applicable to this operation.
Required behavior
- Build a masked gene composition,
library-scaled RNA rates and positive inverse dispersion.gene_logitsandgene_maskhave shape[B,G], with cells on axis0and genes on axis1.gene_maskis boolean andTruemeans a gene is in this cell's composition support; it is not a mask inferred from observed nonzero counts. libraryhas shape[B,1].log_dispersionis[G]for gene mode or[K,G]for batch mode.batch_idis integer[B].B,G,K \ge 1. Inputs are finite, and all testedlibrary/dispersion exponentials fit the dtype. No clipping, softplus-scale alternative or\epsilonis used.- Choose the library and dispersion conventions:
library_mode="log"(default):\mathrm{depth}=\operatorname{exp}(\mathrm{library}). The supplied log depth may itself originate from a latent sample or an observedlibrary; this operation does not infer it. library_mode="observed":libraryis a nonnegative raw molecule count/size factor, so\mathrm{depth}=\mathrm{library}; zero is allowed and produces zero rates.dispersion_mode="gene"(default):\theta[b,g]=\operatorname{exp}(\mathrm{log\_dispersion}[g]);batch_idis ignored.dispersion_mode="batch":\theta[b,g]=\operatorname{exp}(\mathrm{log\_dispersion}[\mathrm{batch\_id}[b],g]); eachbatch_idmust be in[0,K).- For every nonempty mask row,
proportions[b,g]is the softmax ofgene_logitsover onlyTruegenes, and zero atFalsegenes. Implement the softmax manually with a masked row maximum and safe denominator.library_sizeis the effective depth: depth for nonempty support and zero for an all-masked row. \mathrm{rate} = \mathrm{library\_size}\cdot \mathrm{proportions}. Thus\sum_{g} \mathrm{rate}[b,g] = \mathrm{library\_size}[b,0]; it equals the supplied raw/exp depth whenever there is at least one supported gene. All-masked rows have exactly zeroproportions, effective depth and rates even when supplied depth was positive.- Dispersion stays positive at every gene, including masked genes, since it is a parameter table rather than an observation. Return new parameter tensors, not residual updates, and do not modify inputs. Reject unknown modes, negative observed depth, and out-of-range batch IDs with
ValueError. - Other declared shapes/dtypes/finiteness are preconditions.
Why this matters
Softmax allocates one cell’s library size across supported genes, while shared-gene parameters or the selected learned batch row determine positive dispersion according to dispersion_mode.
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 library_size_dispersion_decoder(
gene_logits: torch.Tensor, # (B, G)
gene_mask: torch.Tensor, # (B, G)
library: torch.Tensor, # (B, 1)
log_dispersion: torch.Tensor, # (G,) or (K, G)
batch_id: torch.Tensor | None = None, # (B,)
library_mode: str = 'log',
dispersion_mode: str = 'gene',
) -> dict[str, torch.Tensor]:
"""Return dict[str, torch.Tensor]:
proportions: (B, G).
rate: (B, G).
inverse_dispersion: (B, G).
library_size: (B, 1)."""
# Implement the operation. Inputs and test setup are supplied by BioTorch.
raise NotImplementedError("Implement library_size_dispersion_decoder")
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.