📚 Documentation: https://zaoqu-liu.github.io/CellODE/
Overview
CellODE is an R implementation for inferring continuous cellular dynamics from single-cell transcriptomic data using deep generative models. The framework integrates Variational Autoencoders (VAE) with Neural Ordinary Differential Equations (Neural ODE) to learn a continuous representation of cellular state transitions.
This package provides an R-native interface to the methodology originally described in scTour (Li et al., 2023), with full compatibility for the Seurat ecosystem.
Methodology
CellODE employs a unified framework that jointly learns:
Temporal Representation: An encoder network maps gene expression profiles to developmental pseudotime, parameterizing the position of each cell along a continuous trajectory.
Latent Dynamics: A Neural ODE defines the instantaneous rate of change in the latent space, enabling the model to capture complex, non-linear dynamics:
- Generative Decoder: The decoder reconstructs gene expression from latent representations, supporting multiple likelihood models (Gaussian, Negative Binomial, Zero-Inflated Negative Binomial).
Key Features
| Feature | Description |
|---|---|
| Pseudotime Inference | Automatically infers developmental ordering without predefined root cells |
| Latent Space Learning | VAE-based dimensionality reduction with ODE-constrained dynamics |
| Vector Field Analysis | Computes cellular velocity in latent and embedding spaces |
| Seurat Integration | Native support for Seurat V4/V5 objects |
| GPU Acceleration | Supports CUDA (NVIDIA) and MPS (Apple Silicon) backends |
| Scalability | Efficient training on datasets with >100,000 cells |
Installation
From R-universe (Recommended)
install.packages("CellODE", repos = "https://zaoqu-liu.r-universe.dev")From GitHub
# Install dependencies
install.packages(c("torch", "R6", "Matrix", "ggplot2", "Rcpp", "RcppArmadillo"))
# Install torch backend (run once)
torch::install_torch()
# Install CellODE
remotes::install_github("Zaoqu-Liu/CellODE")Quick Start
library(CellODE)
library(Seurat)
# Load preprocessed Seurat object
seurat_obj <- readRDS("your_data.rds")
# Initialize trainer
trainer <- Trainer$new(
seurat_obj = seurat_obj,
n_latent = 5, # Latent space dimensionality
n_ode_hidden = 25, # ODE network hidden units
n_vae_hidden = 128, # VAE encoder/decoder hidden units
loss_mode = "nb", # Likelihood: "mse", "nb", or "zinb"
nepoch = 100, # Training epochs
batch_size = 1024 # Mini-batch size
)
# Train the model
trainer$train()
# Extract pseudotime
pseudotime <- trainer$get_time()
seurat_obj$pseudotime <- pseudotime
# Extract latent representations
latent <- trainer$get_latentsp(alpha_z = 0.5, alpha_predz = 0.5)
seurat_obj@misc$X_zs <- latent$mix_zs
# Compute vector field
vf <- trainer$get_vector_field(pseudotime, latent$mix_zs)
seurat_obj@misc$X_VF <- vf
# Visualization
plot_pseudotime(seurat_obj, time_key = "pseudotime", embedding_key = "umap")
plot_vector_field(seurat_obj, zs_key = "X_zs", vf_key = "X_VF")
# Save trained model
trainer$save_model("cellode_model")API Reference
Model Training
| Function | Description |
|---|---|
Trainer$new() |
Initialize trainer with model hyperparameters |
trainer$train() |
Execute model training |
trainer$get_time() |
Extract pseudotime estimates |
trainer$get_latentsp() |
Extract latent representations |
trainer$get_vector_field() |
Compute velocity vector field |
trainer$save_model() |
Serialize trained model |
Prediction
| Function | Description |
|---|---|
load_model() |
Deserialize trained model |
predict_time() |
Infer pseudotime for query cells |
predict_latentsp() |
Predict latent representations |
predict_vector_field() |
Predict velocity field |
predict_ltsp_from_time() |
Interpolate latent space at specified time points |
Visualization
| Function | Description |
|---|---|
plot_pseudotime() |
Visualize pseudotime on embedding |
plot_vector_field() |
Visualize cellular dynamics |
plot_loss() |
Display training/validation loss curves |
Utilities
| Function | Description |
|---|---|
reverse_time() |
Reverse pseudotime direction |
cosine_similarity() |
Compute transition probability matrix |
vector_field_embedding() |
Project velocity to embedding space |
Model Architecture
The TNODE (Time Neural ODE) model consists of:
Input: Gene Expression Matrix (cells × genes)
│
▼
┌───────────────────────┐
│ Encoder │
│ FC → [BN] → ReLU │
└───────────────────────┘
│
┌────────┴────────┐
▼ ▼
┌──────────┐ ┌──────────────┐
│ Time (t) │ │ Latent (z) │
│ Sigmoid │ │ μ, log(σ²) │
└──────────┘ └──────────────┘
│ │
└────────┬────────┘
▼
┌───────────────────────┐
│ Neural ODE Solver │
│ dz/dt = f_θ(z, t) │
└───────────────────────┘
│
▼
┌───────────────────────┐
│ Decoder │
│ FC → [BN] → ReLU │
│ → Softmax (NB/ZINB) │
└───────────────────────┘
│
▼
Reconstructed Expression
Loss Functions
CellODE supports three reconstruction likelihoods:
- MSE: Mean Squared Error for log-normalized data
- NB: Negative Binomial for UMI count data
- ZINB: Zero-Inflated Negative Binomial for sparse count data
The total loss combines reconstruction error, KL divergence, and latent space consistency:
Citation
If you use CellODE in your research, please cite:
@software{liu2026cellode,
author = {Liu, Zaoqu},
title = {{CellODE}: Cellular Dynamics Inference Using Neural ODE in {R}},
year = {2026},
url = {https://github.com/Zaoqu-Liu/CellODE},
note = {R package version 1.0.0}
}Please also cite the original scTour methodology:
@article{li2023sctour,
title = {scTour: a deep learning architecture for robust inference and
accurate prediction of cellular dynamics},
author = {Li, Sheng and Zhang, Pengzhi and Chen, Wei and Ye, Lingxiang and
Branez, Kristy W and Le, Tram and Zheng, Jean Fan},
journal = {Genome Biology},
volume = {24},
pages = {149},
year = {2023},
doi = {10.1186/s13059-023-02988-9}
}Related Resources
- scTour - Original Python implementation
- torchdiffeq - Neural ODE solver library
- scvelo - RNA velocity analysis
- Seurat - Single-cell analysis toolkit
Contact
Zaoqu Liu
Email: liuzaoqu@163.com
GitHub: https://github.com/Zaoqu-Liu