Other technologies

DECIPHER supports a variety of other technologies for spatial transcriptomics, including but not limited to:

  • MERFISH (see our manuscript)

  • Xenium (see our manuscript)

  • CosMx (see below)

  • CODEX (see below)

[2]:
import decipher
import scanpy as sc
import pandas as pd
from decipher import DECIPHER
from decipher.utils import scanpy_viz

CosMx

We use the CosMx data from the paper: High-plex imaging of RNA and proteins at subcellular resolution in fixed tissue by spatial molecular imaging

This slice contains ~700k cells with 960 genes

[25]:
cosmx = sc.read_h5ad('../../../Spider-dev/benchmark/data/human_NSCLC_CosMx/data/annotated/Lung13.h5ad')
[9]:
cosmx.X = cosmx.layers['counts'].copy()
cosmx
[9]:
AnnData object with n_obs × n_vars = 71094 × 960
    obs: 'fov', 'Area', 'AspectRatio', 'CenterX_global_px', 'CenterY_global_px', 'Width', 'Height', 'Mean.MembraneStain', 'Max.MembraneStain', 'Mean.PanCK', 'Max.PanCK', 'Mean.CD45', 'Max.CD45', 'Mean.CD3', 'Max.CD3', 'Mean.DAPI', 'Max.DAPI', 'cell_ID', 'n_genes', 'Omics', 'Species', 'Tissue_0', 'Tissue_1', 'Disease', 'Platform', 'Technology', 'Index', 'batch', 'n_counts', 'leiden', 'cell_type', 'leiden_nbr_celltype', 'region'
    var: 'n_cells', 'mean', 'std'
    uns: 'cell_type_colors', 'leiden', 'leiden_colors', 'leiden_nbr_celltype_colors', 'neighbors', 'pca', 'rank_genes_groups', 'spatial_', 'umap'
    obsm: 'X_nbr_celltype', 'X_pca', 'X_umap', 'X_umap_nbr_celltype', 'spatial', 'spatial_fov'
    varm: 'PCs'
    layers: 'counts'
    obsp: 'connectivities', 'distances'
[ ]:
model = DECIPHER(work_dir='./decipher_cosmx', overwrite=True)
model.register_data(cosmx)
2025-06-20 15:59:16.560 | SUCCESS  | decipher.utils:global_seed:332 - Global seed set to 0.
2025-06-20 15:59:16.566 | DEBUG    | decipher.data.process:omics_data_process:68 - adata 0 has 71094 cells, 960 genes.
2025-06-20 15:59:16.572 | INFO     | decipher.data.process:omics_data_process:86 - Input: 1 slice(s) with 71094 cells and 1 batches.
2025-06-20 15:59:16.573 | INFO     | decipher.data.process:_preprocess_adata:98 - Preprocessing 71094 cells.
2025-06-20 15:59:16.767 | WARNING  | decipher.data.process:_preprocess_adata:113 - hvg:2000 >= n_vars:960, set all genes as HVGs.
/flash/grp/gglab/xiacr/DECIPHER-dev/conda/lib/python3.11/site-packages/scanpy/preprocessing/_scale.py:318: UserWarning: Received a view of an AnnData. Making a copy.
  view_to_actual(adata)
2025-06-20 15:59:19.825 | SUCCESS  | decipher.data.process:_preprocess_adata:148 - Preprocessing finished in 3.25 seconds.
2025-06-20 15:59:21.960 | SUCCESS  | decipher.graphic.build:build_graph:102 - Built knn graph with 71094 nodes and 1421880 edges, 20.00 edges/node.
[12]:
model.fit_omics()
gex_embedding = model.center_emb
nbr_embedding = model.nbr_emb
2025-06-20 15:59:27.096 | INFO     | decipher.emb:sc_emb:157 - Not found pre-trained model: list index out of range
2025-06-20 15:59:27.099 | INFO     | decipher.emb:_update_config:37 - Using 960 genes as model input.
2025-06-20 15:59:27.106 | DEBUG    | decipher.nn.models._basic:__init__:37 - {'model_dir': 'pretrain', 'fix_sc': False, 'spatial_emb': 'attn', 'transformer_layers': 3, 'num_heads': 1, 'dropout': 0.1, 'prj_dims': [128, 32, 32], 'temperature_center': 0.07, 'temperature_nbr': 0.07, 'lr_base': 0.01, 'lr_min': 0.001, 'weight_decay': 1e-05, 'first_cycle_steps': 831, 'warmup_steps': 83, 'epochs': 3, 'nbr_loss_weight': 0.5, 'plot': False, 'plot_hist': False, 'device': 'auto', 'select_gpu': True, 'device_num': 1, 'fp16': True, 'patient': 10, 'log_every_n_steps': 1, 'gradient_clip_val': 5.0, 'check_val_every_n_epoch': 1, 'max_steps': 831, 'augment': {'dropout_gex': 0.5, 'dropout_nbr_prob': -1, 'mask_hop': -1, 'max_neighbor': 21}, 'emb_dim': 128, 'gex_dims': [960, 256, 128], 'marker_list': None, 'save_h5ad': False, 'work_dir': './decipher_cosmx', 'force': False}
2025-06-20 15:59:27.600 | INFO     | decipher.utils:select_free_gpu:295 - Using GPU [1] as computation device.
2025-06-20 15:59:27.606 | DEBUG    | decipher.nn.trainer:init_trainer:60 - Run model with precision 16-mixed
/flash/grp/gglab/xiacr/DECIPHER-dev/conda/lib/python3.11/site-packages/lightning_fabric/plugins/environments/slurm.py:204: The `srun` command is available on your system but is not used. HINT: If your intention is to run Lightning on SLURM, prepend your python command with `srun` like so: srun python /flash/grp/gglab/xiacr/DECIPHER-dev/conda/lib/python ...
Using 16bit Automatic Mixed Precision (AMP)
GPU available: True (cuda), used: True
TPU available: False, using: 0 TPU cores
HPU available: False, using: 0 HPUs
2025-06-20 15:59:27.659 | INFO     | decipher.nn.trainer:fit:99 - Start training single cell model.
You are using a CUDA device ('NVIDIA A100-SXM4-80GB') that has Tensor Cores. To properly utilize them, you should set `torch.set_float32_matmul_precision('medium' | 'high')` which will trade-off precision for performance. For more details, read https://pytorch.org/docs/stable/generated/torch.set_float32_matmul_precision.html#torch.set_float32_matmul_precision
Missing logger folder: decipher_cosmx/pretrain/lightning_logs
/flash/grp/gglab/xiacr/DECIPHER-dev/conda/lib/python3.11/site-packages/pytorch_lightning/callbacks/model_checkpoint.py:652: Checkpoint directory /flash/grp/gglab/xiacr/DECIPHER-dev/docs/tutorials/decipher_cosmx/pretrain exists and is not empty.
LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]

  | Name           | Type       | Params | Mode
------------------------------------------------------
0 | center_encoder | MLP        | 279 K  | train
1 | criterion      | NTXentLoss | 0      | train
------------------------------------------------------
279 K     Trainable params
0         Non-trainable params
279 K     Total params
1.118     Total estimated model params size (MB)
2025-06-20 15:59:36.007 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:41 - Save embedding to disk
2025-06-20 15:59:36.027 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:56 - Save embedding to adata
Metric train/total_loss improved. New best score: 1.115
Epoch 0, global step 277: 'train/total_loss' reached 1.11548 (best 1.11548), saving model to '/flash/grp/gglab/xiacr/DECIPHER-dev/docs/tutorials/decipher_cosmx/pretrain/epoch=0-step=277.ckpt' as top 3
2025-06-20 15:59:41.608 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:41 - Save embedding to disk
2025-06-20 15:59:41.630 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:56 - Save embedding to adata
Metric train/total_loss improved by 0.171 >= min_delta = 0.0. New best score: 0.944
Epoch 1, global step 554: 'train/total_loss' reached 0.94401 (best 0.94401), saving model to '/flash/grp/gglab/xiacr/DECIPHER-dev/docs/tutorials/decipher_cosmx/pretrain/epoch=1-step=554.ckpt' as top 3
2025-06-20 15:59:47.297 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:41 - Save embedding to disk
2025-06-20 15:59:47.311 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:56 - Save embedding to adata
Metric train/total_loss improved by 0.148 >= min_delta = 0.0. New best score: 0.796
Epoch 2, global step 831: 'train/total_loss' reached 0.79581 (best 0.79581), saving model to '/flash/grp/gglab/xiacr/DECIPHER-dev/docs/tutorials/decipher_cosmx/pretrain/epoch=2-step=831.ckpt' as top 3
`Trainer.fit` stopped: `max_steps=831` reached.
2025-06-20 15:59:47.768 | SUCCESS  | decipher.nn.trainer:fit:113 - Train finished in 20.11s.
2025-06-20 15:59:47.769 | INFO     | decipher.emb:_update_config:37 - Using 960 genes as model input.
/flash/grp/gglab/xiacr/DECIPHER-dev/conda/lib/python3.11/site-packages/torch_geometric/data/lightning/datamodule.py:43: The 'shuffle=True' option is ignored in 'LightningSpatialMNNData'. Remove it from the argument list to disable this warning
2025-06-20 15:59:47.801 | DEBUG    | decipher.nn.models._basic:__init__:37 - {'model_dir': 'model', 'fix_sc': False, 'spatial_emb': 'attn', 'transformer_layers': 3, 'num_heads': 1, 'dropout': 0.1, 'prj_dims': [128, 32, 32], 'temperature_center': 0.07, 'temperature_nbr': 0.07, 'lr_base': 0.0001, 'lr_min': 1e-05, 'weight_decay': 1e-05, 'first_cycle_steps': 1662, 'warmup_steps': 166, 'epochs': 6, 'nbr_loss_weight': 0.5, 'plot': False, 'plot_hist': False, 'device': 'auto', 'select_gpu': True, 'device_num': 1, 'fp16': True, 'patient': 10, 'log_every_n_steps': 1, 'gradient_clip_val': 5.0, 'check_val_every_n_epoch': 1, 'max_steps': 1662, 'augment': {'dropout_gex': 0.5, 'dropout_nbr_prob': -1, 'mask_hop': -1, 'max_neighbor': 21}, 'emb_dim': 128, 'gex_dims': [960, 256, 128], 'marker_list': None, 'save_h5ad': False, 'work_dir': './decipher_cosmx'}
2025-06-20 15:59:48.221 | INFO     | decipher.utils:select_free_gpu:295 - Using GPU [1] as computation device.
2025-06-20 15:59:48.223 | DEBUG    | decipher.nn.trainer:init_trainer:60 - Run model with precision 16-mixed
/flash/grp/gglab/xiacr/DECIPHER-dev/conda/lib/python3.11/site-packages/lightning_fabric/plugins/environments/slurm.py:204: The `srun` command is available on your system but is not used. HINT: If your intention is to run Lightning on SLURM, prepend your python command with `srun` like so: srun python /flash/grp/gglab/xiacr/DECIPHER-dev/conda/lib/python ...
Using 16bit Automatic Mixed Precision (AMP)
GPU available: True (cuda), used: True
TPU available: False, using: 0 TPU cores
HPU available: False, using: 0 HPUs
2025-06-20 15:59:48.270 | INFO     | decipher.nn.trainer:fit:99 - Start training spatial omics model.
Missing logger folder: decipher_cosmx/model/lightning_logs
/flash/grp/gglab/xiacr/DECIPHER-dev/conda/lib/python3.11/site-packages/pytorch_lightning/callbacks/model_checkpoint.py:652: Checkpoint directory /flash/grp/gglab/xiacr/DECIPHER-dev/docs/tutorials/decipher_cosmx/model exists and is not empty.
LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]

  | Name             | Type             | Params | Mode
--------------------------------------------------------------
0 | nbr_encoder      | ViT1D            | 299 K  | train
1 | projection_head  | MLP              | 5.2 K  | train
2 | attn_pool        | AttentionPooling | 16.6 K | train
3 | center_criterion | NTXentLoss       | 0      | train
4 | nbr_criterion    | NTXentLoss       | 0      | train
5 | center_encoder   | MLP              | 279 K  | train
--------------------------------------------------------------
600 K     Trainable params
0         Non-trainable params
600 K     Total params
2.402     Total estimated model params size (MB)
2025-06-20 16:00:15.483 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:41 - Save embedding to disk
2025-06-20 16:00:15.498 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:56 - Save embedding to adata
2025-06-20 16:00:15.500 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:41 - Save embedding to disk
2025-06-20 16:00:15.505 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:56 - Save embedding to adata
Metric train/total_loss improved. New best score: 1.613
Epoch 0, global step 277: 'train/total_loss' reached 1.61313 (best 1.61313), saving model to '/flash/grp/gglab/xiacr/DECIPHER-dev/docs/tutorials/decipher_cosmx/model/epoch=0-step=277.ckpt' as top 3
2025-06-20 16:00:40.308 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:41 - Save embedding to disk
2025-06-20 16:00:40.323 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:56 - Save embedding to adata
2025-06-20 16:00:40.324 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:41 - Save embedding to disk
2025-06-20 16:00:40.329 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:56 - Save embedding to adata
Metric train/total_loss improved by 0.287 >= min_delta = 0.0. New best score: 1.326
Epoch 1, global step 554: 'train/total_loss' reached 1.32637 (best 1.32637), saving model to '/flash/grp/gglab/xiacr/DECIPHER-dev/docs/tutorials/decipher_cosmx/model/epoch=1-step=554.ckpt' as top 3
2025-06-20 16:01:05.053 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:41 - Save embedding to disk
2025-06-20 16:01:05.067 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:56 - Save embedding to adata
2025-06-20 16:01:05.068 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:41 - Save embedding to disk
2025-06-20 16:01:05.073 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:56 - Save embedding to adata
Metric train/total_loss improved by 0.138 >= min_delta = 0.0. New best score: 1.188
Epoch 2, global step 831: 'train/total_loss' reached 1.18810 (best 1.18810), saving model to '/flash/grp/gglab/xiacr/DECIPHER-dev/docs/tutorials/decipher_cosmx/model/epoch=2-step=831.ckpt' as top 3
2025-06-20 16:01:29.560 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:41 - Save embedding to disk
2025-06-20 16:01:29.574 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:56 - Save embedding to adata
2025-06-20 16:01:29.575 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:41 - Save embedding to disk
2025-06-20 16:01:29.580 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:56 - Save embedding to adata
Epoch 3, global step 1108: 'train/total_loss' reached 1.19467 (best 1.18810), saving model to '/flash/grp/gglab/xiacr/DECIPHER-dev/docs/tutorials/decipher_cosmx/model/epoch=3-step=1108.ckpt' as top 3
2025-06-20 16:01:54.380 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:41 - Save embedding to disk
2025-06-20 16:01:54.411 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:56 - Save embedding to adata
2025-06-20 16:01:54.413 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:41 - Save embedding to disk
2025-06-20 16:01:54.418 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:56 - Save embedding to adata
Metric train/total_loss improved by 0.072 >= min_delta = 0.0. New best score: 1.116
Epoch 4, global step 1385: 'train/total_loss' reached 1.11565 (best 1.11565), saving model to '/flash/grp/gglab/xiacr/DECIPHER-dev/docs/tutorials/decipher_cosmx/model/epoch=4-step=1385.ckpt' as top 3
2025-06-20 16:02:19.190 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:41 - Save embedding to disk
2025-06-20 16:02:19.219 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:56 - Save embedding to adata
2025-06-20 16:02:19.221 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:41 - Save embedding to disk
2025-06-20 16:02:19.226 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:56 - Save embedding to adata
Metric train/total_loss improved by 0.023 >= min_delta = 0.0. New best score: 1.092
Epoch 5, global step 1662: 'train/total_loss' reached 1.09247 (best 1.09247), saving model to '/flash/grp/gglab/xiacr/DECIPHER-dev/docs/tutorials/decipher_cosmx/model/epoch=5-step=1662.ckpt' as top 3
`Trainer.fit` stopped: `max_steps=1662` reached.
2025-06-20 16:02:20.995 | SUCCESS  | decipher.nn.trainer:fit:113 - Train finished in 152.73s.
LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]
2025-06-20 16:02:24.822 | INFO     | decipher.cls:fit_omics:177 - Results saved to decipher_cosmx
[13]:
cosmx.obsm['X_center'] = gex_embedding
cosmx.obsm['X_nbr'] = nbr_embedding
cosmx = scanpy_viz(cosmx, ['center', 'nbr'], rapids=False)
2025-06-20 16:02:29.239 | INFO     | decipher.utils:select_free_gpu:295 - Using GPU [1, 0] as computation device.
[14]:
cosmx.obsm['X_umap'] = cosmx.obsm['X_umap_center'].copy()
sc.pl.umap(cosmx, color=['cell_type'])
../_images/tutorials_4-more_techs_8_0.png
[26]:
cosmx.obs['region'] = 'Region-' + cosmx.obs['leiden'].astype(str)
[27]:
# cosmx.obsm['X_umap'] = cosmx.obsm['X_umap_nbr'].copy()
sc.pl.spatial(cosmx, color=['region'], spot_size=80)
../_images/tutorials_4-more_techs_10_0.png

CODEX

We use the CODEX showd in Seurat tutorial (from https://app.globus.org/file-manager?origin_id=af603d86-eab9-4eec-bb1d-9d26556741bb&origin_path=%2Fc95d9373d698faf60a66ffdc27499fe1%2Fdrv_CX_20-008_lymphnode_n10_reg001%2Fprocessed_2020-12-2320-008LNn10r001%2Fsegm%2Fsegm-1%2Ffcs%2Fcompensated%2F)

This data contains ~180k cells with 28 channels (proteins)

[3]:
df = pd.read_csv('./LN7910_20_008_11022020_reg001_compensated.csv')

[4]:
df.head()
[4]:
cell_id:cell_id region:region tile_num:tile_num x:x y:y z:z x_tile:x_tile y_tile:y_tile size:size cyc001_ch001:DAPI-01 ... cyc012_ch002:Empty cyc012_ch003:CD5 cyc012_ch004:CD1c cyc013_ch001:DAPI-13 cyc013_ch002:Blank cyc013_ch003:Blank cyc013_ch004:Blank tsne_x:tsne_x tsne_y:tsne_y homogeneity:homogeneity
0 1 1 1 0 35 0 0 35 252 3310.841270 ... 25.424603 2616.575397 219.369048 4316.603175 145.150794 2553.150794 586.170635 -10.111384 1.329884 4.940698
1 2 1 1 0 58 0 0 58 168 3548.982143 ... 30.821429 1316.398810 83.398810 4396.845238 132.089286 2457.708333 582.702381 -5.833877 10.265185 5.079799
2 3 1 1 11 16 0 11 16 472 3271.690678 ... 33.824153 1573.379237 68.144068 3855.362288 146.904661 2473.086864 575.338983 -4.819608 -3.919313 5.122119
3 4 1 1 2 78 0 2 78 204 3900.813725 ... 46.470588 957.465686 101.593137 4725.897059 141.676471 2805.235294 625.181373 -14.063901 9.582250 4.097429
4 5 1 1 0 186 0 0 186 184 3557.576087 ... 31.135870 2493.706522 103.733696 5087.902174 156.603261 2853.277174 695.146739 6.660976 -14.633474 4.527107

5 rows × 64 columns

[5]:
# df.head()
# fitler the cols whose name starts with 'cyc'
feature = df.loc[:, df.columns.str.startswith('cyc')]
# filter out cols contains 'Blank' and 'DAPI'
feature = feature.loc[:, ~feature.columns.str.contains('Blank|DAPI|Empty')]
[6]:
codex = sc.AnnData(X=feature.values)
codex.var = pd.DataFrame(index=feature.columns)
codex.obsm['spatial'] = df[['x:x', 'y:y']].values
codex
[6]:
AnnData object with n_obs × n_vars = 188450 × 28
    obsm: 'spatial'
[7]:
from muon import prot as pt
pt.pp.clr(codex)
[8]:
sc.pp.scale(codex, max_value=10)
[12]:
codex.X = codex.X.astype('float32')
[13]:
model = DECIPHER(work_dir='./decipher_codex')
model.register_data(codex, preprocess=False)
2025-06-20 16:30:02.611 | WARNING  | decipher.cls:__init__:49 - decipher_codex already exists but `recover` is False.
2025-06-20 16:30:02.626 | SUCCESS  | decipher.utils:global_seed:332 - Global seed set to 0.
2025-06-20 16:30:02.628 | WARNING  | decipher.cls:register_data:108 - Skip preprocessing, make sure the input data is ready.
2025-06-20 16:30:05.332 | SUCCESS  | decipher.graphic.build:build_graph:102 - Built knn graph with 188450 nodes and 3769000 edges, 20.00 edges/node.
[14]:
model.fit_omics()
gex_embedding = model.center_emb
nbr_embedding = model.nbr_emb
2025-06-20 16:30:06.138 | INFO     | decipher.emb:sc_emb:157 - Not found pre-trained model: list index out of range
2025-06-20 16:30:06.141 | INFO     | decipher.emb:_update_config:37 - Using 28 genes as model input.
2025-06-20 16:30:06.144 | DEBUG    | decipher.nn.models._basic:__init__:37 - {'model_dir': 'pretrain', 'fix_sc': False, 'spatial_emb': 'attn', 'transformer_layers': 3, 'num_heads': 1, 'dropout': 0.1, 'prj_dims': [128, 32, 32], 'temperature_center': 0.07, 'temperature_nbr': 0.07, 'lr_base': 0.01, 'lr_min': 0.001, 'weight_decay': 1e-05, 'first_cycle_steps': 2208, 'warmup_steps': 200, 'epochs': 3, 'nbr_loss_weight': 0.5, 'plot': False, 'plot_hist': False, 'device': 'auto', 'select_gpu': True, 'device_num': 1, 'fp16': True, 'patient': 10, 'log_every_n_steps': 1, 'gradient_clip_val': 5.0, 'check_val_every_n_epoch': 1, 'max_steps': 2208, 'augment': {'dropout_gex': 0.5, 'dropout_nbr_prob': -1, 'mask_hop': -1, 'max_neighbor': 21}, 'emb_dim': 128, 'gex_dims': [28, 256, 128], 'marker_list': None, 'save_h5ad': False, 'work_dir': './decipher_codex', 'force': False}
2025-06-20 16:30:06.276 | INFO     | decipher.utils:select_free_gpu:295 - Using GPU [1] as computation device.
2025-06-20 16:30:06.278 | DEBUG    | decipher.nn.trainer:init_trainer:60 - Run model with precision 16-mixed
/flash/grp/gglab/xiacr/DECIPHER-dev/conda/lib/python3.11/site-packages/lightning_fabric/plugins/environments/slurm.py:204: The `srun` command is available on your system but is not used. HINT: If your intention is to run Lightning on SLURM, prepend your python command with `srun` like so: srun python /flash/grp/gglab/xiacr/DECIPHER-dev/conda/lib/python ...
Using 16bit Automatic Mixed Precision (AMP)
GPU available: True (cuda), used: True
TPU available: False, using: 0 TPU cores
HPU available: False, using: 0 HPUs
2025-06-20 16:30:06.365 | INFO     | decipher.nn.trainer:fit:99 - Start training single cell model.
/flash/grp/gglab/xiacr/DECIPHER-dev/conda/lib/python3.11/site-packages/pytorch_lightning/callbacks/model_checkpoint.py:652: Checkpoint directory /flash/grp/gglab/xiacr/DECIPHER-dev/docs/tutorials/decipher_codex/pretrain exists and is not empty.
LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]

  | Name           | Type       | Params | Mode
------------------------------------------------------
0 | center_encoder | MLP        | 40.8 K | train
1 | criterion      | NTXentLoss | 0      | train
------------------------------------------------------
40.8 K    Trainable params
0         Non-trainable params
40.8 K    Total params
0.163     Total estimated model params size (MB)
2025-06-20 16:30:17.118 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:41 - Save embedding to disk
2025-06-20 16:30:17.148 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:56 - Save embedding to adata
Metric train/total_loss improved. New best score: 3.103
Epoch 0, global step 736: 'train/total_loss' reached 3.10262 (best 3.10262), saving model to '/flash/grp/gglab/xiacr/DECIPHER-dev/docs/tutorials/decipher_codex/pretrain/epoch=0-step=736.ckpt' as top 3
2025-06-20 16:30:27.089 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:41 - Save embedding to disk
2025-06-20 16:30:27.119 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:56 - Save embedding to adata
Metric train/total_loss improved by 0.007 >= min_delta = 0.0. New best score: 3.096
Epoch 1, global step 1472: 'train/total_loss' reached 3.09583 (best 3.09583), saving model to '/flash/grp/gglab/xiacr/DECIPHER-dev/docs/tutorials/decipher_codex/pretrain/epoch=1-step=1472.ckpt' as top 3
2025-06-20 16:30:42.897 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:41 - Save embedding to disk
2025-06-20 16:30:42.932 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:56 - Save embedding to adata
Metric train/total_loss improved by 0.188 >= min_delta = 0.0. New best score: 2.908
Epoch 2, global step 2208: 'train/total_loss' reached 2.90752 (best 2.90752), saving model to '/flash/grp/gglab/xiacr/DECIPHER-dev/docs/tutorials/decipher_codex/pretrain/epoch=2-step=2208.ckpt' as top 3
`Trainer.fit` stopped: `max_steps=2208` reached.
2025-06-20 16:30:43.197 | SUCCESS  | decipher.nn.trainer:fit:113 - Train finished in 36.83s.
2025-06-20 16:30:43.198 | INFO     | decipher.emb:_update_config:37 - Using 28 genes as model input.
/flash/grp/gglab/xiacr/DECIPHER-dev/conda/lib/python3.11/site-packages/torch_geometric/data/lightning/datamodule.py:43: The 'shuffle=True' option is ignored in 'LightningSpatialMNNData'. Remove it from the argument list to disable this warning
2025-06-20 16:30:43.402 | DEBUG    | decipher.nn.models._basic:__init__:37 - {'model_dir': 'model', 'fix_sc': False, 'spatial_emb': 'attn', 'transformer_layers': 3, 'num_heads': 1, 'dropout': 0.1, 'prj_dims': [128, 32, 32], 'temperature_center': 0.07, 'temperature_nbr': 0.07, 'lr_base': 0.0001, 'lr_min': 1e-05, 'weight_decay': 1e-05, 'first_cycle_steps': 4416, 'warmup_steps': 200, 'epochs': 6, 'nbr_loss_weight': 0.5, 'plot': False, 'plot_hist': False, 'device': 'auto', 'select_gpu': True, 'device_num': 1, 'fp16': True, 'patient': 10, 'log_every_n_steps': 1, 'gradient_clip_val': 5.0, 'check_val_every_n_epoch': 1, 'max_steps': 4416, 'augment': {'dropout_gex': 0.5, 'dropout_nbr_prob': -1, 'mask_hop': -1, 'max_neighbor': 21}, 'emb_dim': 128, 'gex_dims': [28, 256, 128], 'marker_list': None, 'save_h5ad': False, 'work_dir': './decipher_codex'}
2025-06-20 16:30:43.473 | INFO     | decipher.utils:select_free_gpu:295 - Using GPU [1] as computation device.
2025-06-20 16:30:43.475 | DEBUG    | decipher.nn.trainer:init_trainer:60 - Run model with precision 16-mixed
/flash/grp/gglab/xiacr/DECIPHER-dev/conda/lib/python3.11/site-packages/lightning_fabric/plugins/environments/slurm.py:204: The `srun` command is available on your system but is not used. HINT: If your intention is to run Lightning on SLURM, prepend your python command with `srun` like so: srun python /flash/grp/gglab/xiacr/DECIPHER-dev/conda/lib/python ...
Using 16bit Automatic Mixed Precision (AMP)
GPU available: True (cuda), used: True
TPU available: False, using: 0 TPU cores
HPU available: False, using: 0 HPUs
2025-06-20 16:30:43.526 | INFO     | decipher.nn.trainer:fit:99 - Start training spatial omics model.
Missing logger folder: decipher_codex/model/lightning_logs
/flash/grp/gglab/xiacr/DECIPHER-dev/conda/lib/python3.11/site-packages/pytorch_lightning/callbacks/model_checkpoint.py:652: Checkpoint directory /flash/grp/gglab/xiacr/DECIPHER-dev/docs/tutorials/decipher_codex/model exists and is not empty.
LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]

  | Name             | Type             | Params | Mode
--------------------------------------------------------------
0 | nbr_encoder      | ViT1D            | 299 K  | train
1 | projection_head  | MLP              | 5.2 K  | train
2 | attn_pool        | AttentionPooling | 16.6 K | train
3 | center_criterion | NTXentLoss       | 0      | train
4 | nbr_criterion    | NTXentLoss       | 0      | train
5 | center_encoder   | MLP              | 40.8 K | train
--------------------------------------------------------------
361 K     Trainable params
0         Non-trainable params
361 K     Total params
1.447     Total estimated model params size (MB)
2025-06-20 16:31:42.060 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:41 - Save embedding to disk
2025-06-20 16:31:42.092 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:56 - Save embedding to adata
2025-06-20 16:31:42.093 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:41 - Save embedding to disk
2025-06-20 16:31:42.102 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:56 - Save embedding to adata
Metric train/total_loss improved. New best score: 2.307
Epoch 0, global step 736: 'train/total_loss' reached 2.30658 (best 2.30658), saving model to '/flash/grp/gglab/xiacr/DECIPHER-dev/docs/tutorials/decipher_codex/model/epoch=0-step=736.ckpt' as top 3
2025-06-20 16:32:37.553 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:41 - Save embedding to disk
2025-06-20 16:32:37.586 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:56 - Save embedding to adata
2025-06-20 16:32:37.588 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:41 - Save embedding to disk
2025-06-20 16:32:37.596 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:56 - Save embedding to adata
Metric train/total_loss improved by 0.049 >= min_delta = 0.0. New best score: 2.258
Epoch 1, global step 1472: 'train/total_loss' reached 2.25759 (best 2.25759), saving model to '/flash/grp/gglab/xiacr/DECIPHER-dev/docs/tutorials/decipher_codex/model/epoch=1-step=1472.ckpt' as top 3
2025-06-20 16:33:33.959 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:41 - Save embedding to disk
2025-06-20 16:33:33.990 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:56 - Save embedding to adata
2025-06-20 16:33:33.992 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:41 - Save embedding to disk
2025-06-20 16:33:34.000 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:56 - Save embedding to adata
Epoch 2, global step 2208: 'train/total_loss' reached 2.37143 (best 2.25759), saving model to '/flash/grp/gglab/xiacr/DECIPHER-dev/docs/tutorials/decipher_codex/model/epoch=2-step=2208.ckpt' as top 3
2025-06-20 16:34:30.486 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:41 - Save embedding to disk
2025-06-20 16:34:30.518 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:56 - Save embedding to adata
2025-06-20 16:34:30.520 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:41 - Save embedding to disk
2025-06-20 16:34:30.528 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:56 - Save embedding to adata
Metric train/total_loss improved by 0.026 >= min_delta = 0.0. New best score: 2.231
Epoch 3, global step 2944: 'train/total_loss' reached 2.23122 (best 2.23122), saving model to '/flash/grp/gglab/xiacr/DECIPHER-dev/docs/tutorials/decipher_codex/model/epoch=3-step=2944.ckpt' as top 3
2025-06-20 16:35:29.432 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:41 - Save embedding to disk
2025-06-20 16:35:29.462 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:56 - Save embedding to adata
2025-06-20 16:35:29.463 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:41 - Save embedding to disk
2025-06-20 16:35:29.471 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:56 - Save embedding to adata
Epoch 4, global step 3680: 'train/total_loss' reached 2.23444 (best 2.23122), saving model to '/flash/grp/gglab/xiacr/DECIPHER-dev/docs/tutorials/decipher_codex/model/epoch=4-step=3680.ckpt' as top 3
2025-06-20 16:36:26.742 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:41 - Save embedding to disk
2025-06-20 16:36:26.772 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:56 - Save embedding to adata
2025-06-20 16:36:26.774 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:41 - Save embedding to disk
2025-06-20 16:36:26.782 | DEBUG    | decipher.nn.models._omics_mixin:save_embedding:56 - Save embedding to adata
Metric train/total_loss improved by 0.013 >= min_delta = 0.0. New best score: 2.219
Epoch 5, global step 4416: 'train/total_loss' reached 2.21861 (best 2.21861), saving model to '/flash/grp/gglab/xiacr/DECIPHER-dev/docs/tutorials/decipher_codex/model/epoch=5-step=4416.ckpt' as top 3
`Trainer.fit` stopped: `max_steps=4416` reached.
2025-06-20 16:36:28.304 | SUCCESS  | decipher.nn.trainer:fit:113 - Train finished in 344.78s.
LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]
2025-06-20 16:36:34.101 | INFO     | decipher.cls:fit_omics:177 - Results saved to decipher_codex
[20]:
codex.obsm['X_center'] = gex_embedding
codex.obsm['X_nbr'] = nbr_embedding
codex = scanpy_viz(codex, ['center', 'nbr'], rapids=False)
2025-06-20 16:39:49.506 | INFO     | decipher.utils:select_free_gpu:295 - Using GPU [1, 0] as computation device.
[21]:
sc.pl.spatial(codex, color=['leiden_center', 'leiden_nbr'], spot_size=15, ncols=1)
../_images/tutorials_4-more_techs_22_0.png
[24]:
codex.obsm['X_umap'] = codex.obsm['X_umap_center'].copy()
sc.pl.umap(codex, color=['leiden_center'], ncols = 1)
codex.obsm['X_umap'] = codex.obsm['X_umap_nbr'].copy()
sc.pl.umap(codex, color=['leiden_nbr'], ncols = 1)

../_images/tutorials_4-more_techs_23_0.png
../_images/tutorials_4-more_techs_23_1.png