Note: This environment variable is required for fully deterministic CuBLAS ops on CUDA >= 10.2 when
reproducible=Trueis set below. Without it, PyTorch raises aRuntimeErrorinstead of training deterministically. It must be set beforetorchis imported. See the README FAQ for details.
%env CUBLAS_WORKSPACE_CONFIG=:16:8
env: CUBLAS_WORKSPACE_CONFIG=:16:8
How To Use Stackix¶
Stackix is our implementation of a stacked/hierarchical autoencoder.
This tutorial follows the structure of our Getting Started - Vanillix, but is less extensive because
our pipeline works similarly for different architectures. Here, we focus only on Stackix specifics.
AUTOENCODIX supports far more functionality than shown here, so we’ll also point to advanced tutorials where relevant.
IMPORTANT
This tutorial only shows the specifics of the Stackix pipeline. If you're unfamiliar with general concepts,
we recommend following theGetting Started - Vanillixtutorial first.
Stackix Theory¶
In our implementation, we train one variational autoencoder (VAE) per data modality end-to-end.
The latent spaces of these outer autoencoders are then concatenated and used as input to another inner autoencoder.
Downstream visualization and evaluation are performed on this meta-latent space, which represents a joint embedding of all modalities.
For unpaired data, each outer autoencoder is trained on all available samples of its modality, even if the corresponding sample is missing in other modalities.
When constructing the input for the inner autoencoder, non-overlapping samples are dropped to ensure consistency across modalities.
This approach has two main goals:
- To produce more informative latent spaces for each modality.
- To provide a richer, joint representation for the inner autoencoder.
We also store the dropped samples and their indices. This allows us to reconstruct the full dataset: the output of the inner autoencoder can be passed back through the outer autoencoders, where decoding recovers the original modalities.
What You'll Learn¶
You’ll learn how to:
- Initialize the pipeline and run it.
- Understand the Stackix-specific pipeline steps (paired vs. unpaired data).
- Access the Stackix-specific results (sub-results for "outer" autoencoders).
- Visualize outputs.
- Apply custom parameters.
- Save, load, and reuse a trained pipeline.
Let’s get started! 🚀
1) Initialize and Run Stackix¶
We set a few custom parameters of the config file. For a deep dive into the config object, see:
Tutorials/DeepDives/ConfigTutorial.ipynb
1.1 The Dataset¶
We use a real multi-omics dataset: a balanced subset of the TCGA pan-cancer cohort (autoencodix/tcga on Hugging Face), combining RNA-seq and DNA methylation.
The dataset is accompanied by clinical annotation data containing metadata such as cancer type.
import pandas as pd
from huggingface_hub import hf_hub_download
import autoencodix as acx
from autoencodix.configs.default_config import DataCase
from autoencodix.configs.stackix_config import StackixConfig
from autoencodix.data.datapackage import DataPackage
# Data is hosted on Hugging Face Hub (autoencodix/tcga) and downloaded (and locally cached) automatically
HF_REPO_ID = "autoencodix/tcga"
rna_path = hf_hub_download(repo_id=HF_REPO_ID, repo_type="dataset", filename="rna.parquet")
meth_path = hf_hub_download(repo_id=HF_REPO_ID, repo_type="dataset", filename="methylation.parquet")
clin_path = hf_hub_download(repo_id=HF_REPO_ID, repo_type="dataset", filename="clinical.parquet")
rna_full = pd.read_parquet(rna_path)
meth_full = pd.read_parquet(meth_path)
clin_full = pd.read_parquet(clin_path)
# Keep only samples present in all three modalities
shared_ids = rna_full.index.intersection(meth_full.index).intersection(clin_full.index)
# Balanced subsample across the 5 broad TCGA cancer types
n_per_type = 120
sampled_ids = (
clin_full.loc[shared_ids]
.groupby("CANCER_TYPE", group_keys=False)
.apply(lambda g: g.sample(n=min(n_per_type, len(g)), random_state=42), include_groups=False)
.index
)
raw_rna = rna_full.loc[sampled_ids]
raw_meth = meth_full.loc[sampled_ids]
annotation = clin_full.loc[sampled_ids]
tcga_multi_bulk = DataPackage(
multi_bulk={"rna": raw_rna, "meth": raw_meth},
annotation={"paired": annotation},
)
my_config = StackixConfig(
epochs=100,
beta=0.01,
checkpoint_interval=20,
default_vae_loss="kl", # kl or mmd possible
data_case=DataCase.MULTI_BULK,
k_filter=2000,
reproducible=True,
global_seed=5,
)
print("\n")
print("Starting Pipeline")
print("-" * 50)
print("-" * 50)
stackix = acx.Stackix(data=tcga_multi_bulk, config=my_config)
result = stackix.run()
Starting Pipeline -------------------------------------------------- -------------------------------------------------- in handle_direct_user_data with data: <class 'autoencodix.data.datapackage.DataPackage'> anno key: paired Reproducibility settings for device auto are not implemented or necessary i.e. for cpu. Training each modality model... Training modality: rna Training modality: rna Reproducibility settings for device auto are not implemented or necessary i.e. for cpu.
/home/alicia/dev/biomarker_autoencoder/autoencodix_package/src/autoencodix/trainers/_general_trainer.py:233: UserWarning: Gradient clipping was first applied in epoch 0. Total norm of gradients (adjusted for number of features): 9.6730 exceeded max norm of 5. warnings.warn(
Epoch 20 - Train Loss: 862.4087 Sub-losses: recon_loss: 862.4078, var_loss: 0.0009, anneal_factor: 0.0020, effective_beta_factor: 0.0000 Epoch 20 - Valid Loss: 802.0719 Sub-losses: recon_loss: 802.0713, var_loss: 0.0006, anneal_factor: 0.0020, effective_beta_factor: 0.0000 Epoch 40 - Train Loss: 806.1211 Sub-losses: recon_loss: 806.0600, var_loss: 0.0611, anneal_factor: 0.0998, effective_beta_factor: 0.0010 Epoch 40 - Valid Loss: 740.7936 Sub-losses: recon_loss: 740.7423, var_loss: 0.0513, anneal_factor: 0.0998, effective_beta_factor: 0.0010 Epoch 60 - Train Loss: 763.1939 Sub-losses: recon_loss: 762.3805, var_loss: 0.8135, anneal_factor: 0.8581, effective_beta_factor: 0.0086 Epoch 60 - Valid Loss: 727.0296 Sub-losses: recon_loss: 726.3649, var_loss: 0.6646, anneal_factor: 0.8581, effective_beta_factor: 0.0086 Epoch 80 - Train Loss: 751.2939 Sub-losses: recon_loss: 750.0782, var_loss: 1.2157, anneal_factor: 0.9970, effective_beta_factor: 0.0100 Epoch 80 - Valid Loss: 714.5604 Sub-losses: recon_loss: 713.5505, var_loss: 1.0099, anneal_factor: 0.9970, effective_beta_factor: 0.0100 Epoch 100 - Train Loss: 731.9706 Sub-losses: recon_loss: 730.5090, var_loss: 1.4617, anneal_factor: 0.9999, effective_beta_factor: 0.0100 Epoch 100 - Valid Loss: 713.0892 Sub-losses: recon_loss: 711.9360, var_loss: 1.1532, anneal_factor: 0.9999, effective_beta_factor: 0.0100 Training modality: meth Training modality: meth Reproducibility settings for device auto are not implemented or necessary i.e. for cpu.
/home/alicia/dev/biomarker_autoencoder/autoencodix_package/src/autoencodix/trainers/_general_trainer.py:233: UserWarning: Gradient clipping was first applied in epoch 0. Total norm of gradients (adjusted for number of features): 11.1517 exceeded max norm of 5. warnings.warn(
Epoch 20 - Train Loss: 661.1864 Sub-losses: recon_loss: 661.1857, var_loss: 0.0007, anneal_factor: 0.0020, effective_beta_factor: 0.0000 Epoch 20 - Valid Loss: 655.0351 Sub-losses: recon_loss: 655.0345, var_loss: 0.0007, anneal_factor: 0.0020, effective_beta_factor: 0.0000 Epoch 40 - Train Loss: 612.0515 Sub-losses: recon_loss: 611.9937, var_loss: 0.0579, anneal_factor: 0.0998, effective_beta_factor: 0.0010 Epoch 40 - Valid Loss: 603.8224 Sub-losses: recon_loss: 603.7703, var_loss: 0.0520, anneal_factor: 0.0998, effective_beta_factor: 0.0010 Epoch 60 - Train Loss: 561.3298 Sub-losses: recon_loss: 560.5643, var_loss: 0.7655, anneal_factor: 0.8581, effective_beta_factor: 0.0086 Epoch 60 - Valid Loss: 562.8977 Sub-losses: recon_loss: 562.1656, var_loss: 0.7321, anneal_factor: 0.8581, effective_beta_factor: 0.0086 Epoch 80 - Train Loss: 559.0962 Sub-losses: recon_loss: 557.9058, var_loss: 1.1905, anneal_factor: 0.9970, effective_beta_factor: 0.0100 Epoch 80 - Valid Loss: 569.2817 Sub-losses: recon_loss: 568.1283, var_loss: 1.1534, anneal_factor: 0.9970, effective_beta_factor: 0.0100 Epoch 100 - Train Loss: 541.3964 Sub-losses: recon_loss: 539.8498, var_loss: 1.5466, anneal_factor: 0.9999, effective_beta_factor: 0.0100 Epoch 100 - Valid Loss: 555.4448 Sub-losses: recon_loss: 553.9160, var_loss: 1.5288, anneal_factor: 0.9999, effective_beta_factor: 0.0100 Found 420 common samples for the stacked autoencoder. Found 60 common samples for the stacked autoencoder. finished training each modality model Reproducibility settings for device auto are not implemented or necessary i.e. for cpu.
/home/alicia/dev/biomarker_autoencoder/autoencodix_package/src/autoencodix/trainers/_general_trainer.py:233: UserWarning: Gradient clipping was first applied in epoch 0. Total norm of gradients (adjusted for number of features): 73.4787 exceeded max norm of 5. warnings.warn(
Epoch 20 - Train Loss: 363.1186 Sub-losses: recon_loss: 363.1184, var_loss: 0.0002, anneal_factor: 0.0020, effective_beta_factor: 0.0000 Epoch 20 - Valid Loss: 321.1639 Sub-losses: recon_loss: 321.1637, var_loss: 0.0002, anneal_factor: 0.0020, effective_beta_factor: 0.0000 Epoch 40 - Train Loss: 247.1598 Sub-losses: recon_loss: 247.1190, var_loss: 0.0408, anneal_factor: 0.0998, effective_beta_factor: 0.0010 Epoch 40 - Valid Loss: 209.5626 Sub-losses: recon_loss: 209.5314, var_loss: 0.0312, anneal_factor: 0.0998, effective_beta_factor: 0.0010 Epoch 60 - Train Loss: 214.3203 Sub-losses: recon_loss: 213.7860, var_loss: 0.5344, anneal_factor: 0.8581, effective_beta_factor: 0.0086 Epoch 60 - Valid Loss: 176.2616 Sub-losses: recon_loss: 175.7611, var_loss: 0.5005, anneal_factor: 0.8581, effective_beta_factor: 0.0086 Epoch 80 - Train Loss: 205.4680 Sub-losses: recon_loss: 204.5926, var_loss: 0.8753, anneal_factor: 0.9970, effective_beta_factor: 0.0100 Epoch 80 - Valid Loss: 159.1377 Sub-losses: recon_loss: 158.3056, var_loss: 0.8321, anneal_factor: 0.9970, effective_beta_factor: 0.0100 Epoch 100 - Train Loss: 206.6958 Sub-losses: recon_loss: 205.5899, var_loss: 1.1059, anneal_factor: 0.9999, effective_beta_factor: 0.0100 Epoch 100 - Valid Loss: 146.7249 Sub-losses: recon_loss: 145.8031, var_loss: 0.9218, anneal_factor: 0.9999, effective_beta_factor: 0.0100 Reproducibility settings for device auto are not implemented or necessary i.e. for cpu. Found 120 common samples for the stacked autoencoder. <autoencodix.data._numeric_dataset.NumericDataset object at 0x7891a5e5a770> Successfully created annotated latent space object (adata_latent).
2) Stackix-Specific Steps¶
Stackix does not introduce additional steps to the overall pipeline. However, its preprocessing and training differ slightly from Varix and Vanillix. Stackix processes each data modality individually and thus supports unpaired data input.
This is enabled by setting the config parameter requires_paired=False.
In the following example, we build unpaired data by dropping some samples from our raw_rna data. The outer autoencoder for the methylation modality still trains on all methylation samples, including those without corresponding RNA. These RNA samples are only excluded when concatenating the latent spaces for the inner autoencoder. Later, we can add these samples back to the inner AE output and feed them into the decoder of the outer methylation autoencoder, allowing full reconstruction.
import pandas as pd
from autoencodix.data.datapackage import DataPackage
from autoencodix.configs.stackix_config import StackixConfig
from autoencodix.configs.default_config import DataCase
import autoencodix as acx
dropped_ids = raw_rna.sample(n=20, random_state=42).index
rna_anno: pd.DataFrame = annotation.drop(index=dropped_ids)
print(rna_anno.shape)
rna_unpaired: pd.DataFrame = raw_rna.drop(index=dropped_ids)
print(rna_unpaired.shape)
unpaired_dp: DataPackage = DataPackage(
multi_bulk={"rna": rna_unpaired, "meth": raw_meth},
annotation={"rna": rna_anno, "meth": annotation},
)
unpaired_config: StackixConfig = StackixConfig(
data_case=DataCase.MULTI_BULK, requires_paired=False
)
unpaired_stackix: acx.Stackix = acx.Stackix(data=unpaired_dp, config=unpaired_config)
unpaired_result = unpaired_stackix.run()
(580, 56) (580, 17448) in handle_direct_user_data with data: <class 'autoencodix.data.datapackage.DataPackage'> anno key: rna anno key: meth Training each modality model... Training modality: rna Training modality: rna
/home/alicia/dev/biomarker_autoencoder/autoencodix_package/src/autoencodix/trainers/_general_trainer.py:233: UserWarning: Gradient clipping was first applied in epoch 0. Total norm of gradients (adjusted for number of features): 10.8362 exceeded max norm of 5. warnings.warn(
Epoch 3 - Train Loss: 53474.2982 Sub-losses: recon_loss: 18050.3304, var_loss: 35423.9675, anneal_factor: 0.9656, effective_beta_factor: 0.0966 Epoch 3 - Valid Loss: 2383693.7091 Sub-losses: recon_loss: 2383298.5129, var_loss: 395.0898, anneal_factor: 0.9656, effective_beta_factor: 0.0966 Training modality: meth Training modality: meth
/home/alicia/dev/biomarker_autoencoder/autoencodix_package/src/autoencodix/trainers/_general_trainer.py:233: UserWarning: Gradient clipping was first applied in epoch 0. Total norm of gradients (adjusted for number of features): 11.6226 exceeded max norm of 5. warnings.warn(
Epoch 3 - Train Loss: 7836.0943 Sub-losses: recon_loss: 7752.6758, var_loss: 83.4184, anneal_factor: 0.9656, effective_beta_factor: 0.0966 Epoch 3 - Valid Loss: 11965.9589 Sub-losses: recon_loss: 10710.3828, var_loss: 1255.5765, anneal_factor: 0.9656, effective_beta_factor: 0.0966 Found 406 common samples for the stacked autoencoder. Found 58 common samples for the stacked autoencoder. finished training each modality model
/home/alicia/dev/biomarker_autoencoder/autoencodix_package/src/autoencodix/trainers/_general_trainer.py:233: UserWarning: Gradient clipping was first applied in epoch 0. Total norm of gradients (adjusted for number of features): 3753.9534 exceeded max norm of 5. warnings.warn(
Epoch 3 - Train Loss: 1097675.9266 Sub-losses: recon_loss: 1097672.9758, var_loss: 2.9551, anneal_factor: 0.9656, effective_beta_factor: 0.0966 Epoch 3 - Valid Loss: 14828.0579 Sub-losses: recon_loss: 14827.8384, var_loss: 0.2195, anneal_factor: 0.9656, effective_beta_factor: 0.0966 Found 116 common samples for the stacked autoencoder. <autoencodix.data._numeric_dataset.NumericDataset object at 0x7891a6988ca0> Successfully created annotated latent space object (adata_latent).
3) Access Stackix-Specific Outputs¶
As explained above, we train outer autoencoders for each data modality and one shared inner autoencoder.
The results (losses, reconstructions, latent spaces, etc.) for the inner autoencoder can be accessed in the same way as for the Vanillix autoencoder (see [1] and [2]).
The results for the outer autoencoders are stored in a special sub_results structure, as illustrated in the Python code below.
The sub_results can be accessed as an attribute of the result object.
On the first level, this is a Dict with keys corresponding to the data modalities (as defined in Step 1).
The value for each key is a result object analogous to the general result object.
These can be accessed via our standard API (see also [2]).
[1] Tutorials/PipelineTutorials/Vanillix.ipynb
[2] Tutorials/DeepDives/PipelineOutputTutorial.ipynb
outer_result = result.sub_results
print(outer_result.keys())
dict_keys(['rna', 'meth'])
print(outer_result["meth"])
# access latent space of outer methylation autoencoder
outer_result["meth"].latentspaces.get(split="test", epoch=-1)
Result Object Public Attributes:
------------------------------
latentspaces: TrainingDynamics object
sample_ids: TrainingDynamics object
reconstructions: TrainingDynamics object
mus: TrainingDynamics object
sigmas: TrainingDynamics object
losses: TrainingDynamics object
sub_losses: LossRegistry(_losses={'recon_loss': TrainingDynamics(), 'var_loss': TrainingDynamics(), 'anneal_factor': TrainingDynamics(), 'effective_beta_factor': TrainingDynamics()})
preprocessed_data: Tensor of shape (0,)
model: VarixArchitecture
model_checkpoints: TrainingDynamics object
datasets: DatasetContainer(train=None, valid=None, test=None)
new_datasets: DatasetContainer(train=None, valid=None, test=None)
adata_latent: AnnData object with n_obs × n_vars = 0 × 0
final_reconstruction: None
sub_results: None
sub_reconstructions: None
embedding_evaluation: Empty DataFrame
Columns: []
Index: []
embedding_attributions: Empty DataFrame
Columns: []
Index: []
embedding_explanations: Dict with 0 items
array([[ 0.881716 , 1.2293729 , 0.72128266, ..., 2.4728608 ,
6.5299053 , 1.1532463 ],
[ 1.9333293 , 1.5813494 , 1.2028021 , ..., 5.103081 ,
4.5182433 , 0.36976436],
[ 2.459379 , 5.0468388 , 5.430481 , ..., -1.0237892 ,
7.628327 , 2.1867306 ],
...,
[ 7.0717545 , 6.199747 , 1.9782643 , ..., 5.257984 ,
11.63677 , 2.5935605 ],
[ 0.21196252, 0.7826589 , 0.6282544 , ..., 3.063758 ,
0.6773172 , 1.109165 ],
[ 1.9420035 , 8.156875 , 11.350476 , ..., -0.08163258,
-0.7722243 , 7.3420835 ]], shape=(120, 16), dtype=float32)
# the inner result can be accessed directly
result.latentspaces.get(split="test", epoch=-1)
# or as dataframe with ids
result.get_latent_df(split="test", epoch=-1)
| LatDim_0 | LatDim_1 | LatDim_2 | LatDim_3 | LatDim_4 | LatDim_5 | LatDim_6 | LatDim_7 | LatDim_8 | LatDim_9 | LatDim_10 | LatDim_11 | LatDim_12 | LatDim_13 | LatDim_14 | LatDim_15 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| TCGA-05-4250-01 | -0.178447 | 2.736038 | -0.746352 | -0.764565 | -0.667412 | 1.717845 | -1.600573 | -2.225891 | -0.023309 | -0.783873 | 3.320147 | 4.199130 | 2.715884 | -1.023837 | 4.936493 | 4.073131 |
| TCGA-05-4410-01 | 1.164364 | 2.972247 | 0.209474 | 1.088743 | -1.119766 | 0.989842 | -0.003885 | 0.724461 | -0.071547 | 0.963581 | 0.872269 | 0.817888 | 1.490780 | 0.051327 | 4.229981 | 1.636360 |
| TCGA-05-4420-01 | 1.361521 | 1.197402 | -0.829542 | 0.702733 | -0.512372 | 1.131414 | -1.352620 | -0.470067 | -0.032610 | 1.409997 | 1.676570 | 0.123716 | 2.481240 | -0.988570 | 2.873714 | 2.274129 |
| TCGA-09-1669-01 | 2.612077 | -1.159732 | 7.229315 | 3.524749 | 6.000990 | 1.690343 | 4.885739 | 3.818074 | -0.478044 | 3.715651 | 0.476996 | 0.767875 | 1.055437 | 2.921402 | -0.180995 | 3.041923 |
| TCGA-22-4593-01 | 3.863706 | 3.513688 | 0.021320 | -0.020089 | 1.680466 | 1.819478 | 2.799454 | -1.362118 | -0.463396 | 0.361181 | 3.289376 | 2.742913 | 0.733315 | 0.009830 | 0.341899 | 1.380868 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| TCGA-N6-A4VG-01 | -0.880361 | -0.243074 | 2.120545 | 1.021668 | 2.617247 | -0.430215 | 1.809526 | 2.903714 | 1.668174 | 2.780136 | -0.252894 | 1.573203 | 0.784559 | -0.269361 | 0.238475 | 2.426823 |
| TCGA-N8-A4PO-01 | 1.481126 | -2.683304 | 1.949788 | 2.023833 | 1.298192 | -0.061461 | 1.690637 | 2.657233 | 0.093063 | 2.080896 | 0.789955 | -0.788211 | 0.750470 | 0.405041 | 1.829427 | 1.536629 |
| TCGA-NH-A6GB-01 | 0.255358 | 4.532810 | 0.593342 | 0.999461 | 1.193891 | 4.012676 | 1.292557 | -1.233316 | -0.566902 | 5.227308 | 2.996989 | 1.983964 | 5.743472 | -0.511556 | 12.264321 | 8.587306 |
| TCGA-NJ-A55O-01 | 1.698997 | 3.414874 | 0.111533 | -1.128163 | -1.770032 | 1.333727 | 0.781384 | -2.327469 | 0.565355 | -1.284287 | 4.022061 | 3.694236 | 0.719250 | 0.880401 | 3.481593 | -0.799701 |
| TCGA-OY-A56Q-01 | 0.691096 | 0.585042 | 6.418207 | 1.646888 | 5.743044 | -0.536256 | 4.440415 | 3.600572 | -1.788529 | 4.797790 | 0.456047 | -1.309754 | -0.816833 | -0.180086 | -0.457702 | 0.608442 |
120 rows × 16 columns
4) Visualize Outputs¶
This works exactly as for our other pipelines, by calling the show_result method.
For more information, see our Visualization Deep Dive.
We can pass a column from the annotation file using the keyword argument params to color the plots according to this column.
stackix.show_result(params=["CANCER_TYPE"])
Creating plots ...
5) Customize Stackix Parameters¶
Since Stackix is composed of variational autoencoders, there are no Stackix-specific customizations that were not already shown in the Varix tutorial.
However, it is possible to change the architecture to a vanilla autoencoder via the model_type attribute when initializing Stackix.
Please note that this attribute expects a class type, not an instance of the class.
Therefore, you need to import the appropriate Architecture (see API reference) and the corresponding loss type (e.g., VanillixLoss if using a vanilla autoencoder).
See the code below for a clearer example.
import autoencodix as acx
from autoencodix.configs.default_config import DataCase
from autoencodix.configs.stackix_config import StackixConfig
from autoencodix.modeling import VanillixArchitecture
from autoencodix.utils import VanillixLoss
my_config = StackixConfig(
epochs=27,
checkpoint_interval=5,
data_case=DataCase.MULTI_BULK,
k_filter=2000,
)
stackix_custom = acx.Stackix(
data=tcga_multi_bulk,
config=my_config,
model_type=VanillixArchitecture,
loss_type=VanillixLoss,
)
result_custom = stackix_custom.run()
in handle_direct_user_data with data: <class 'autoencodix.data.datapackage.DataPackage'> anno key: paired Training each modality model... Training modality: rna Training modality: rna
/home/alicia/dev/biomarker_autoencoder/autoencodix_package/src/autoencodix/trainers/_general_trainer.py:233: UserWarning: Gradient clipping was first applied in epoch 0. Total norm of gradients (adjusted for number of features): 23.0555 exceeded max norm of 5. warnings.warn(
Epoch 5 - Train Loss: 856.5413 Sub-losses: recon_loss: 856.5413 Epoch 5 - Valid Loss: 1227.5358 Sub-losses: recon_loss: 1227.5358 Epoch 10 - Train Loss: 796.2182 Sub-losses: recon_loss: 796.2182 Epoch 10 - Valid Loss: 1179.8255 Sub-losses: recon_loss: 1179.8255 Epoch 15 - Train Loss: 761.0203 Sub-losses: recon_loss: 761.0203 Epoch 15 - Valid Loss: 1156.3602 Sub-losses: recon_loss: 1156.3602 Epoch 20 - Train Loss: 740.2954 Sub-losses: recon_loss: 740.2954 Epoch 20 - Valid Loss: 1145.7398 Sub-losses: recon_loss: 1145.7398 Epoch 25 - Train Loss: 738.6436 Sub-losses: recon_loss: 738.6436 Epoch 25 - Valid Loss: 1138.0193 Sub-losses: recon_loss: 1138.0193 Epoch 27 - Train Loss: 722.9525 Sub-losses: recon_loss: 722.9525 Epoch 27 - Valid Loss: 1129.5311 Sub-losses: recon_loss: 1129.5311 Training modality: meth Training modality: meth
/home/alicia/dev/biomarker_autoencoder/autoencodix_package/src/autoencodix/trainers/_general_trainer.py:233: UserWarning: Gradient clipping was first applied in epoch 0. Total norm of gradients (adjusted for number of features): 19.4628 exceeded max norm of 5. warnings.warn(
Epoch 5 - Train Loss: 659.6040 Sub-losses: recon_loss: 659.6040 Epoch 5 - Valid Loss: 531.5841 Sub-losses: recon_loss: 531.5841 Epoch 10 - Train Loss: 602.5172 Sub-losses: recon_loss: 602.5172 Epoch 10 - Valid Loss: 484.7523 Sub-losses: recon_loss: 484.7523 Epoch 15 - Train Loss: 577.7273 Sub-losses: recon_loss: 577.7273 Epoch 15 - Valid Loss: 466.4911 Sub-losses: recon_loss: 466.4911 Epoch 20 - Train Loss: 573.4865 Sub-losses: recon_loss: 573.4865 Epoch 20 - Valid Loss: 463.3812 Sub-losses: recon_loss: 463.3812 Epoch 25 - Train Loss: 558.4631 Sub-losses: recon_loss: 558.4631 Epoch 25 - Valid Loss: 447.9033 Sub-losses: recon_loss: 447.9033 Epoch 27 - Train Loss: 538.6525 Sub-losses: recon_loss: 538.6525 Epoch 27 - Valid Loss: 448.4826 Sub-losses: recon_loss: 448.4826 Found 420 common samples for the stacked autoencoder. Found 60 common samples for the stacked autoencoder. finished training each modality model
/home/alicia/dev/biomarker_autoencoder/autoencodix_package/src/autoencodix/trainers/_general_trainer.py:233: UserWarning: Gradient clipping was first applied in epoch 0. Total norm of gradients (adjusted for number of features): 35.7969 exceeded max norm of 5. warnings.warn(
Epoch 5 - Train Loss: 25.4678 Sub-losses: recon_loss: 25.4678 Epoch 5 - Valid Loss: 20.9136 Sub-losses: recon_loss: 20.9136 Epoch 10 - Train Loss: 20.5687 Sub-losses: recon_loss: 20.5687 Epoch 10 - Valid Loss: 16.4208 Sub-losses: recon_loss: 16.4208 Epoch 15 - Train Loss: 17.1140 Sub-losses: recon_loss: 17.1140 Epoch 15 - Valid Loss: 12.7210 Sub-losses: recon_loss: 12.7210 Epoch 20 - Train Loss: 15.5596 Sub-losses: recon_loss: 15.5596 Epoch 20 - Valid Loss: 9.8392 Sub-losses: recon_loss: 9.8392 Epoch 25 - Train Loss: 14.3893 Sub-losses: recon_loss: 14.3893 Epoch 25 - Valid Loss: 8.7181 Sub-losses: recon_loss: 8.7181 Epoch 27 - Train Loss: 14.2813 Sub-losses: recon_loss: 14.2813 Epoch 27 - Valid Loss: 9.0706 Sub-losses: recon_loss: 9.0706 Found 120 common samples for the stacked autoencoder. <autoencodix.data._numeric_dataset.NumericDataset object at 0x7890f06ec2e0> Successfully created annotated latent space object (adata_latent).
6) Saving, Loading and Reusing¶
This works for Stackix as for any other models, by using the save and load methods.
import os
import glob
outpath = os.path.join("tutorial_res", "stackix")
stackix.save(file_path=outpath, save_all=False)
folder = os.path.dirname(outpath)
pkl_files = glob.glob(os.path.join(folder, "*.pkl"))
model_files = glob.glob(os.path.join(folder, "*.pth"))
print("PKL files:", pkl_files)
print("Model files:", model_files)
# The load functionality will automatically rebuild the pipeline object
# from the saved files.
stackix_loaded = acx.Stackix.load(outpath)
Preprocessor saved successfully. saving memory efficient Pipeline object saved successfully. PKL files: ['tutorial_res/van_preprocessor.pkl', 'tutorial_res/stackix_preprocessor.pkl'] Model files: ['tutorial_res/stackix_model.pth', 'tutorial_res/van_model.pth'] Attempting to load a pipeline from tutorial_res/stackix... Pipeline object loaded successfully. Actual type: Stackix Preprocessor loaded successfully.
stackix_loaded.predict(data=tcga_multi_bulk)
Reproducibility settings for device auto are not implemented or necessary i.e. for cpu. in handle_direct_user_data with data: <class 'autoencodix.data.datapackage.DataPackage'> Found 600 common samples for the stacked autoencoder. <autoencodix.data._numeric_dataset.NumericDataset object at 0x7890f077c040> Successfully created annotated latent space object (adata_latent).
Result Object Public Attributes:
------------------------------
latentspaces: TrainingDynamics object
sample_ids: TrainingDynamics object
reconstructions: TrainingDynamics object
mus: TrainingDynamics object
sigmas: TrainingDynamics object
losses: TrainingDynamics object
sub_losses: LossRegistry(_losses={'recon_loss': TrainingDynamics(), 'var_loss': TrainingDynamics(), 'anneal_factor': TrainingDynamics(), 'effective_beta_factor': TrainingDynamics()})
preprocessed_data: Tensor of shape (0,)
model: VarixArchitecture
model_checkpoints: TrainingDynamics object
datasets: DatasetContainer(train=None, valid=None, test=None)
new_datasets: DatasetContainer(train=<autoencodix.data._multimodal_dataset.MultiModalDataset object at 0x7890f077c550>, valid=None, test=<autoencodix.data._multimodal_dataset.MultiModalDataset object at 0x7890f075f8b0>)
adata_latent: AnnData object with n_obs × n_vars = 600 × 16
final_reconstruction: multi_bulk:
rna: 600 samples × 1000 features
meth: 600 samples × 1000 features
annotation:
rna: 600 samples × 56 features
meth: 600 samples × 56 features
sub_results: None
sub_reconstructions: Dict with 2 items
embedding_evaluation: Empty DataFrame
Columns: []
Index: []
embedding_attributions: Empty DataFrame
Columns: []
Index: []
embedding_explanations: Dict with 0 items
stackix_loaded.show_result(params=["CANCER_TYPE"])
Creating plots ... Absolute loss plot not found in the plots dictionary This happens, when you did not run visualize() or if you saved and loaded the model with `save_all=False`
/home/alicia/dev/biomarker_autoencoder/autoencodix_package/src/autoencodix/utils/_result.py:348: UserWarning: Could not retrieve latent representations for epoch 99 and split 'train'. Returning empty DataFrame. This may be due to missing data in the Result object or incorrect keys. warnings.warn( /home/alicia/dev/biomarker_autoencoder/autoencodix_package/src/autoencodix/utils/_result.py:348: UserWarning: Could not retrieve latent representations for epoch 99 and split 'valid'. Returning empty DataFrame. This may be due to missing data in the Result object or incorrect keys. warnings.warn(
/home/alicia/dev/biomarker_autoencoder/autoencodix_package/src/autoencodix/utils/_result.py:348: UserWarning: Could not retrieve latent representations for epoch 99 and split 'train'. Returning empty DataFrame. This may be due to missing data in the Result object or incorrect keys. warnings.warn( /home/alicia/dev/biomarker_autoencoder/autoencodix_package/src/autoencodix/utils/_result.py:348: UserWarning: Could not retrieve latent representations for epoch 99 and split 'valid'. Returning empty DataFrame. This may be due to missing data in the Result object or incorrect keys. warnings.warn(
Generate New Data¶
For a variational autoencoder, the generate or sample_latent_space step draws new latent vectors from the model’s learned latent distribution.
Latent Sampling: The model first aggregates the posterior over all encoded latent vectors in the chosen split and epoch by computing the mean (global_mu) and log-variance (global_logvar). It then samples new latent points from a diagonal Gaussian defined by these aggregate statistics, using the reparameterization trick to inject Gaussian noise.
Number of Samples (n_samples): Users can specify how many latent points to generate. The method expands the aggregated mean and log-variance to match the requested number of samples before sampling.
Custom Latent Prior:
Optionally, a custom latent_prior can be provided (a tensor or NumPy array with shape (n_samples, latent_dim)), which will be used directly instead of the aggregated posterior. This is basically the decode step.
generated_reconstructions = stackix_loaded.generate(n_samples=5)
print(generated_reconstructions)
Reproducibility settings for device auto are not implemented or necessary i.e. for cpu.
tensor([[3.4581, 0.9484, 4.1967, 3.9275, 1.9968, 2.9378, 4.8404, 0.7652, 1.7989,
3.4892, 4.3203, 2.6945, 4.6708, 2.5322, 2.8759, 2.5423, 2.4730, 1.9494,
2.3085, 3.2754, 1.2611, 1.5800, 1.2624, 0.8034, 2.3158, 1.8371, 1.3834,
1.5676, 4.7108, 3.6217, 3.6610, 1.9044],
[2.1054, 0.3580, 2.1148, 2.7985, 2.3127, 3.2155, 4.1482, 0.2411, 1.6331,
3.5144, 2.3068, 1.7943, 4.4628, 2.9603, 1.4355, 3.1935, 4.0196, 0.9700,
1.3288, 4.3767, 1.0587, 2.1889, 1.4707, 1.4002, 2.4744, 1.8154, 0.7167,
1.8016, 6.1686, 3.6641, 4.3081, 1.0681],
[2.6230, 0.8783, 2.3425, 2.3219, 0.7897, 1.7055, 2.0328, 0.6214, 1.6282,
1.3181, 2.5319, 1.6533, 3.8746, 2.2606, 3.1658, 1.1123, 3.1643, 1.9209,
3.5270, 3.4991, 0.8759, 1.0293, 1.9819, 1.9077, 0.9971, 2.9004, 2.7484,
2.6436, 3.1948, 2.0975, 2.6535, 1.4968],
[2.0150, 0.2640, 1.5693, 2.5754, 2.5612, 3.5448, 4.0910, 0.3010, 1.6050,
3.6853, 1.8136, 1.4669, 4.5368, 3.2322, 1.1564, 3.6678, 4.7639, 0.8124,
1.2205, 4.8529, 0.8840, 2.6619, 1.3899, 1.5971, 2.6096, 1.8496, 0.5474,
1.6788, 6.9905, 3.7056, 5.2951, 0.8230],
[1.8622, 0.4379, 1.8554, 2.4348, 1.9814, 2.7654, 3.4940, 0.3476, 1.4768,
3.1238, 1.9821, 1.5522, 3.7548, 2.6011, 1.1652, 2.8673, 3.9613, 0.8608,
1.2565, 4.0677, 0.8878, 2.0812, 1.4148, 1.5123, 2.1441, 1.7084, 0.8382,
1.7734, 5.5824, 3.1738, 4.0036, 0.8762]])