Porting a DRVI model (drvi-py < 0.3) to scvi.external.DRVI (scvi-tools)#
DRVI’s PyTorch model has moved into scvi-tools as scvi.external.DRVI. A model that was
trained and saved with drvi-py (< 0.3) can be migrated to the scvi-tools layout with
drvi.utils.port_to_scvi_tools and then loaded via scvi.external.DRVI.load.
The port is pure checkpoint surgery (no need to load the actual model). This minimal notebook trains a tiny DRVI model with drvi-py, ports it, loads it into scvi-tools, and shows that both produce exactly the same latent representation.
Requires: drvi-py >= 0.2.7 (which provides port_to_scvi_tools) and a scvi-tools that ships
scvi.external.DRVI (>= 1.5.0).
import os
import tempfile
import numpy as np
import pandas as pd
import anndata as ad
import drvi
import scvi
print("drvi", drvi.__version__)
print("scvi", scvi.__version__)
save_dir = tempfile.TemporaryDirectory()
drvi 0.2.7
scvi 1.5.0
Synthetic count data#
rng = np.random.default_rng(0)
n_cells, n_genes = 300, 60
X = rng.poisson(1.0, size=(n_cells, n_genes)).astype(np.float32)
adata = ad.AnnData(
X=X,
obs=pd.DataFrame(
{"batch": [f"b{i % 2}" for i in range(n_cells)]},
index=[f"cell_{i}" for i in range(n_cells)],
),
var=pd.DataFrame(index=[f"gene_{i}" for i in range(n_genes)]),
)
adata.layers["counts"] = X.copy()
adata
AnnData object with n_obs × n_vars = 300 × 60
obs: 'batch'
layers: None, 'counts'
Train and save a DRVI model (drvi-py)#
drvi.model.DRVI.setup_anndata(adata, layer="counts", batch_key="batch")
model = drvi.model.DRVI(adata, n_latent=16)
model.train(max_epochs=3)
# Latent representation from the original drvi-py model
z_drvi = model.get_latent_representation()
model_path = os.path.join(save_dir.name, "drvi_model")
model.save(model_path, overwrite=True)
z_drvi.shape
INFO DRVI: The model has been initialized
(300, 16)
Port the checkpoint to scvi-tools#
port_to_scvi_tools reads the saved model.pt, rewrites it to the scvi-tools DRVI layout, and
writes a new model directory (default: "<source>_scvi_tools", i.e. next to the source inside our
temporary directory).
ported_dir = os.path.join(save_dir.name, "drvi_model_scvi_tools")
drvi.utils.port_to_scvi_tools(model_path, ported_dir, overwrite=True)
ported_dir
'/var/folders/v8/zg0d9qwx18q2vw5thhsl2jfh0000gn/T/tmpls2gg_7e/drvi_model_scvi_tools'
Load with scvi.external.DRVI#
The port does not touch the data, so we load the ported model against the same adata
(matching var_names and the covariate columns used at setup time).
scvi_model = scvi.external.DRVI.load(ported_dir, adata)
z_scvi = scvi_model.get_latent_representation()
z_scvi.shape
INFO File /var/folders/v8/zg0d9qwx18q2vw5thhsl2jfh0000gn/T/tmpls2gg_7e/drvi_model_scvi_tools/model.pt already
downloaded
INFO The model has been initialized
(300, 16)
The latents are identical#
max_abs_diff = np.abs(z_drvi - z_scvi).max()
print("max absolute difference:", max_abs_diff)
print("exactly equal:", np.array_equal(z_drvi, z_scvi))
assert np.allclose(z_drvi, z_scvi, atol=1e-6)
print("OK - drvi-py and scvi.external.DRVI produce the same latent representation.")
max absolute difference: 0.0
exactly equal: True
OK - drvi-py and scvi.external.DRVI produce the same latent representation.