Spatial tissue niche discovery

Here we will use slideseqv2_mouse_hippocampus datasets as an example to illustrate how Garfield performs spatial tissue niche discovery for multiple batches. Data access: https://singlecell.broadinstitute.org/single_cell/study/SCP815/highly-sensitive-spatial-transcriptomics-at-near-cellular-resolution-with-slide-seqv2.

[1]:
import os

os.chdir('/data2/zhouwg_data/project/Garfield')
os.getcwd()
[1]:
'/data2/zhouwg_data/project/Garfield'
[2]:
# load packages
import os
import warnings
import Garfield as gf
import scanpy as sc

warnings.simplefilter(action="ignore", category=FutureWarning)
warnings.simplefilter(action='ignore', category=UserWarning)

gf.__version__
[2]:
'1.0.0'
[3]:
# Load data
# Define paths
st_data_folder_path = "/home/zhouweige/zhouwg_data/project/Garfield_tutorials/data" # spatially resolved transcriptomics data

dataset = "slideseqv2_mouse_hippocampus"
cell_type_key = "cell_type"

adata = sc.read_h5ad(f"{st_data_folder_path}/{dataset}.h5ad")
adata.var_names_make_unique(join="++")
adata
[3]:
AnnData object with n_obs × n_vars = 41786 × 4000
    obs: 'cell_type', 'batch'
    obsm: 'spatial'
    layers: 'counts'
[4]:
# check the celltype information of this dataset
adata.obs['cell_type'].value_counts()
[4]:
cell_type
CA1_CA2_CA3_Subiculum       7649
DentatePyramids             6606
Astrocytes                  6543
Interneurons                3672
Oligodendrocytes            3602
Subiculum_Entorhinal_cl2    2896
Endothelial_Stalk           1991
Subiculum_Entorhinal_cl3    1985
Polydendrocytes             1449
Endothelial_Tip             1317
Microglia                   1298
Mural                       1027
Neurogenesis                 938
Ependymal                    813
Name: count, dtype: int64
[5]:
# check the batch information of this dataset
adata.obs['batch'].value_counts()
[5]:
batch
sample1    41786
Name: count, dtype: int64
[6]:
# Ensure adata.X is counts.
adata.X = adata.layers['counts'].copy()
adata.X.max()
[6]:
169.0

Integrating spatially resolved transcriptomics data using Garfield

For spatial niche discovery from spatially resolved transcriptomics data, we should adjust the following paremeters, and all parameter introductions can be found in Garfield_Model_Parameters.

[7]:
# set workdir
workdir = '/home/zhouweige/zhouwg_data/project/Garfield_tutorials/result/garfield_spRNA_mouse_hippocampus'
gf.settings.set_workdir(workdir)

### modify parameter
user_config = dict(
    ## Input options
    adata_list=adata,
    profile='spatial',
    data_type='single-modal',
    sample_col=None,
    weight=0.5,
    ## Preprocessing options
    graph_const_method='mu_std', # mu_std, Radius, KNN, Squidpy
    used_hvg=True,
    min_cells=3,
    min_features=0,
    keep_mt=False,
    target_sum=1e4,
    rna_n_top_features=3000,
    n_components=50,
    n_neighbors=5,
    metric='euclidean',
    svd_solver='arpack',
    # datasets
    used_pca_feat=False,
    adj_key='connectivities',
    # data split parameters
    edge_val_ratio=0.1,
    edge_test_ratio=0.,
    node_val_ratio=0.1,
    node_test_ratio=0.,
    ## Model options
    augment_type='dropout',
    svd_q=5,
    use_FCencoder=True,
    conv_type='GAT', # GAT or GATv2Conv or GCN
    gnn_layer=2,
    hidden_dims=[128, 128],
    bottle_neck_neurons=20,
    cluster_num=20,
    drop_feature_rate=0.2,
    drop_edge_rate=0.2,
    num_heads=3,
    dropout=0.2,
    concat=True,
    used_edge_weight=False,
    used_DSBN=False,
    used_mmd=False,
    # data loader parameters
    num_neighbors=5,
    loaders_n_hops=2,
    edge_batch_size=4096,
    node_batch_size=256, # None
    # loss parameters
    include_edge_recon_loss=True,
    include_gene_expr_recon_loss=True,
    lambda_latent_contrastive_instanceloss=1.0,
    lambda_latent_contrastive_clusterloss=0.5,
    lambda_gene_expr_recon=1., #
    lambda_edge_recon=1., #
    lambda_latent_adj_recon_loss=2.,
    lambda_omics_recon_mmd_loss=0.2,
    # train parameters
    n_epochs_no_edge_recon=0,
    learning_rate=0.001,
    weight_decay=1e-05,
    gradient_clipping=5,
    # other parameters
    latent_key='garfield_latent',
    reload_best_model=True,
    use_early_stopping=True,
    early_stopping_kwargs=None,
    monitor=True,
    device_id=0,
    seed=2024,
    verbose=True
)
dict_config = gf.settings.set_gf_params(user_config)
Saving results in: /home/zhouweige/zhouwg_data/project/Garfield_tutorials/result/garfield_spRNA_mouse_hippocampus
[8]:
from Garfield.model import Garfield

# Initialize model
model = Garfield(dict_config)
--- DATA LOADING AND PREPROCESSING ---
/home/zhouweige/anaconda3/envs/Garfield/lib/python3.9/site-packages/scipy/sparse/_index.py:143: SparseEfficiencyWarning: Changing the sparsity structure of a csr_matrix is expensive. lil_matrix is more efficient.
  self._set_arrayXarray(i, j, x)
------Calculating spatial graph...
COSINE SIM GRAPH DECODER -> dropout_rate: 0.2
[9]:
# Train model
model.train()

--- INITIALIZING TRAINER ---
Using GPU: device-0
Number of training nodes: 37607
Number of validation nodes: 4179
Number of training edges: 246872
Number of validation edges: 27430
Edge batch size: 4096
Node batch size: 256

--- MODEL TRAINING ---
Epoch 1/100 |--------------------| 1.0% val_auroc_score: 0.7848; val_auprc_score: 0.7722; val_best_acc_score: 0.7072; val_best_f1_score: 0.7397; train_kl_reg_loss: 5.3870; train_edge_recon_loss: 1128.2625; train_gene_expr_recon_loss: 5881.1682; train_lambda_latent_adj_recon_loss: 507.5772; train_lambda_latent_contrastive_instanceloss: 7.9475; train_lambda_latent_contrastive_clusterloss: 3.6782; train_global_loss: 7534.0206; train_optim_loss: 7534.0206; val_kl_reg_loss: 6.1536; val_edge_recon_loss: 1083.1054; val_gene_expr_recon_loss: 5576.5709; val_lambda_latent_adj_recon_loss: 281.4440; val_lambda_latent_contrastive_instanceloss: 7.7274; val_lambda_latent_contrastive_clusterloss: 3.6211; val_global_loss: 6958.6225; val_optim_loss: 6958.6225
Epoch 2/100 |--------------------| 2.0% val_auroc_score: 0.8478; val_auprc_score: 0.8315; val_best_acc_score: 0.7703; val_best_f1_score: 0.7877; train_kl_reg_loss: 11.4613; train_edge_recon_loss: 1104.2606; train_gene_expr_recon_loss: 5569.7317; train_lambda_latent_adj_recon_loss: 396.2759; train_lambda_latent_contrastive_instanceloss: 7.7764; train_lambda_latent_contrastive_clusterloss: 3.5816; train_global_loss: 7093.0875; train_optim_loss: 7093.0875; val_kl_reg_loss: 10.3879; val_edge_recon_loss: 958.1587; val_gene_expr_recon_loss: 5412.4221; val_lambda_latent_adj_recon_loss: 247.5001; val_lambda_latent_contrastive_instanceloss: 7.2457; val_lambda_latent_contrastive_clusterloss: 3.2742; val_global_loss: 6638.9887; val_optim_loss: 6638.9887
Epoch 3/100 |--------------------| 3.0% val_auroc_score: 0.8699; val_auprc_score: 0.8576; val_best_acc_score: 0.7905; val_best_f1_score: 0.8012; train_kl_reg_loss: 16.8834; train_edge_recon_loss: 1079.7648; train_gene_expr_recon_loss: 5482.7694; train_lambda_latent_adj_recon_loss: 337.1196; train_lambda_latent_contrastive_instanceloss: 7.5458; train_lambda_latent_contrastive_clusterloss: 3.3266; train_global_loss: 6927.4095; train_optim_loss: 6927.4095; val_kl_reg_loss: 14.0382; val_edge_recon_loss: 942.1677; val_gene_expr_recon_loss: 5430.3401; val_lambda_latent_adj_recon_loss: 238.6033; val_lambda_latent_contrastive_instanceloss: 7.1921; val_lambda_latent_contrastive_clusterloss: 2.9268; val_global_loss: 6635.2683; val_optim_loss: 6635.2683
Epoch 4/100 |--------------------| 4.0% val_auroc_score: 0.8961; val_auprc_score: 0.8795; val_best_acc_score: 0.8228; val_best_f1_score: 0.8309; train_kl_reg_loss: 21.4036; train_edge_recon_loss: 1062.1254; train_gene_expr_recon_loss: 5422.4451; train_lambda_latent_adj_recon_loss: 307.0592; train_lambda_latent_contrastive_instanceloss: 7.4323; train_lambda_latent_contrastive_clusterloss: 3.0600; train_global_loss: 6823.5256; train_optim_loss: 6823.5256; val_kl_reg_loss: 17.9631; val_edge_recon_loss: 921.3791; val_gene_expr_recon_loss: 5400.9174; val_lambda_latent_adj_recon_loss: 230.3073; val_lambda_latent_contrastive_instanceloss: 7.1721; val_lambda_latent_contrastive_clusterloss: 2.7270; val_global_loss: 6580.4661; val_optim_loss: 6580.4661
Epoch 5/100 |█-------------------| 5.0% val_auroc_score: 0.9090; val_auprc_score: 0.8964; val_best_acc_score: 0.8357; val_best_f1_score: 0.8425; train_kl_reg_loss: 25.5544; train_edge_recon_loss: 1046.1013; train_gene_expr_recon_loss: 5415.6353; train_lambda_latent_adj_recon_loss: 287.4162; train_lambda_latent_contrastive_instanceloss: 7.3693; train_lambda_latent_contrastive_clusterloss: 2.9010; train_global_loss: 6784.9775; train_optim_loss: 6784.9775; val_kl_reg_loss: 20.8134; val_edge_recon_loss: 906.2025; val_gene_expr_recon_loss: 5326.2641; val_lambda_latent_adj_recon_loss: 222.6087; val_lambda_latent_contrastive_instanceloss: 7.1553; val_lambda_latent_contrastive_clusterloss: 2.6319; val_global_loss: 6485.6759; val_optim_loss: 6485.6759
Epoch 6/100 |█-------------------| 6.0% val_auroc_score: 0.9114; val_auprc_score: 0.8985; val_best_acc_score: 0.8368; val_best_f1_score: 0.8443; train_kl_reg_loss: 28.9820; train_edge_recon_loss: 1036.2737; train_gene_expr_recon_loss: 5392.3060; train_lambda_latent_adj_recon_loss: 273.4741; train_lambda_latent_contrastive_instanceloss: 7.3133; train_lambda_latent_contrastive_clusterloss: 2.7849; train_global_loss: 6741.1340; train_optim_loss: 6741.1340; val_kl_reg_loss: 25.0810; val_edge_recon_loss: 908.6509; val_gene_expr_recon_loss: 5372.3361; val_lambda_latent_adj_recon_loss: 219.8521; val_lambda_latent_contrastive_instanceloss: 7.1244; val_lambda_latent_contrastive_clusterloss: 2.5197; val_global_loss: 6535.5644; val_optim_loss: 6535.5644
Epoch 7/100 |█-------------------| 7.0% val_auroc_score: 0.9144; val_auprc_score: 0.9027; val_best_acc_score: 0.8392; val_best_f1_score: 0.8470; train_kl_reg_loss: 31.9467; train_edge_recon_loss: 1028.0276; train_gene_expr_recon_loss: 5397.0987; train_lambda_latent_adj_recon_loss: 263.5325; train_lambda_latent_contrastive_instanceloss: 7.2752; train_lambda_latent_contrastive_clusterloss: 2.7025; train_global_loss: 6730.5832; train_optim_loss: 6730.5832; val_kl_reg_loss: 28.3704; val_edge_recon_loss: 909.8115; val_gene_expr_recon_loss: 5316.6828; val_lambda_latent_adj_recon_loss: 218.3748; val_lambda_latent_contrastive_instanceloss: 7.1163; val_lambda_latent_contrastive_clusterloss: 2.4582; val_global_loss: 6482.8141; val_optim_loss: 6482.8141
Epoch 8/100 |█-------------------| 8.0% val_auroc_score: 0.9176; val_auprc_score: 0.9056; val_best_acc_score: 0.8439; val_best_f1_score: 0.8529; train_kl_reg_loss: 34.7242; train_edge_recon_loss: 1019.9997; train_gene_expr_recon_loss: 5364.1691; train_lambda_latent_adj_recon_loss: 254.7003; train_lambda_latent_contrastive_instanceloss: 7.2467; train_lambda_latent_contrastive_clusterloss: 2.6258; train_global_loss: 6683.4658; train_optim_loss: 6683.4658; val_kl_reg_loss: 30.9783; val_edge_recon_loss: 904.0569; val_gene_expr_recon_loss: 5328.9678; val_lambda_latent_adj_recon_loss: 213.3122; val_lambda_latent_contrastive_instanceloss: 7.1096; val_lambda_latent_contrastive_clusterloss: 2.3953; val_global_loss: 6486.8202; val_optim_loss: 6486.8202
Epoch 9/100 |█-------------------| 9.0% val_auroc_score: 0.9215; val_auprc_score: 0.9107; val_best_acc_score: 0.8483; val_best_f1_score: 0.8548; train_kl_reg_loss: 37.6573; train_edge_recon_loss: 1013.4732; train_gene_expr_recon_loss: 5346.9208; train_lambda_latent_adj_recon_loss: 248.7668; train_lambda_latent_contrastive_instanceloss: 7.2233; train_lambda_latent_contrastive_clusterloss: 2.5597; train_global_loss: 6656.6010; train_optim_loss: 6656.6010; val_kl_reg_loss: 34.9444; val_edge_recon_loss: 904.8325; val_gene_expr_recon_loss: 5278.8454; val_lambda_latent_adj_recon_loss: 213.0423; val_lambda_latent_contrastive_instanceloss: 7.1197; val_lambda_latent_contrastive_clusterloss: 2.3675; val_global_loss: 6441.1519; val_optim_loss: 6441.1519
Epoch 10/100 |██------------------| 10.0% val_auroc_score: 0.9253; val_auprc_score: 0.9157; val_best_acc_score: 0.8538; val_best_f1_score: 0.8599; train_kl_reg_loss: 40.0304; train_edge_recon_loss: 1007.8231; train_gene_expr_recon_loss: 5328.1161; train_lambda_latent_adj_recon_loss: 243.4221; train_lambda_latent_contrastive_instanceloss: 7.2154; train_lambda_latent_contrastive_clusterloss: 2.5188; train_global_loss: 6629.1260; train_optim_loss: 6629.1260; val_kl_reg_loss: 37.3020; val_edge_recon_loss: 902.2868; val_gene_expr_recon_loss: 5272.3921; val_lambda_latent_adj_recon_loss: 211.4311; val_lambda_latent_contrastive_instanceloss: 7.1061; val_lambda_latent_contrastive_clusterloss: 2.3183; val_global_loss: 6432.8364; val_optim_loss: 6432.8364
Epoch 11/100 |██------------------| 11.0% val_auroc_score: 0.9284; val_auprc_score: 0.9207; val_best_acc_score: 0.8556; val_best_f1_score: 0.8609; train_kl_reg_loss: 42.1992; train_edge_recon_loss: 1003.3689; train_gene_expr_recon_loss: 5320.7985; train_lambda_latent_adj_recon_loss: 238.6463; train_lambda_latent_contrastive_instanceloss: 7.2006; train_lambda_latent_contrastive_clusterloss: 2.4720; train_global_loss: 6614.6855; train_optim_loss: 6614.6855; val_kl_reg_loss: 40.6042; val_edge_recon_loss: 900.4749; val_gene_expr_recon_loss: 5286.1482; val_lambda_latent_adj_recon_loss: 208.3427; val_lambda_latent_contrastive_instanceloss: 7.0959; val_lambda_latent_contrastive_clusterloss: 2.2627; val_global_loss: 6444.9286; val_optim_loss: 6444.9286
Epoch 12/100 |██------------------| 12.0% val_auroc_score: 0.9303; val_auprc_score: 0.9233; val_best_acc_score: 0.8571; val_best_f1_score: 0.8621; train_kl_reg_loss: 44.3698; train_edge_recon_loss: 998.3073; train_gene_expr_recon_loss: 5308.4645; train_lambda_latent_adj_recon_loss: 234.5036; train_lambda_latent_contrastive_instanceloss: 7.1910; train_lambda_latent_contrastive_clusterloss: 2.4309; train_global_loss: 6595.2672; train_optim_loss: 6595.2672; val_kl_reg_loss: 42.7152; val_edge_recon_loss: 902.3191; val_gene_expr_recon_loss: 5268.0654; val_lambda_latent_adj_recon_loss: 208.6045; val_lambda_latent_contrastive_instanceloss: 7.0970; val_lambda_latent_contrastive_clusterloss: 2.2379; val_global_loss: 6431.0391; val_optim_loss: 6431.0391
Epoch 13/100 |██------------------| 13.0% val_auroc_score: 0.9336; val_auprc_score: 0.9250; val_best_acc_score: 0.8619; val_best_f1_score: 0.8669; train_kl_reg_loss: 46.1923; train_edge_recon_loss: 994.2458; train_gene_expr_recon_loss: 5297.0569; train_lambda_latent_adj_recon_loss: 230.6976; train_lambda_latent_contrastive_instanceloss: 7.1839; train_lambda_latent_contrastive_clusterloss: 2.3983; train_global_loss: 6577.7748; train_optim_loss: 6577.7748; val_kl_reg_loss: 46.1184; val_edge_recon_loss: 898.5275; val_gene_expr_recon_loss: 5255.3697; val_lambda_latent_adj_recon_loss: 205.7938; val_lambda_latent_contrastive_instanceloss: 7.0965; val_lambda_latent_contrastive_clusterloss: 2.2186; val_global_loss: 6415.1247; val_optim_loss: 6415.1247
Epoch 14/100 |██------------------| 14.0% val_auroc_score: 0.9349; val_auprc_score: 0.9261; val_best_acc_score: 0.8631; val_best_f1_score: 0.8682; train_kl_reg_loss: 47.6387; train_edge_recon_loss: 990.7952; train_gene_expr_recon_loss: 5296.9750; train_lambda_latent_adj_recon_loss: 228.0738; train_lambda_latent_contrastive_instanceloss: 7.1751; train_lambda_latent_contrastive_clusterloss: 2.3696; train_global_loss: 6573.0274; train_optim_loss: 6573.0274; val_kl_reg_loss: 45.9330; val_edge_recon_loss: 895.7226; val_gene_expr_recon_loss: 5225.4683; val_lambda_latent_adj_recon_loss: 202.6950; val_lambda_latent_contrastive_instanceloss: 7.0972; val_lambda_latent_contrastive_clusterloss: 2.1968; val_global_loss: 6379.1128; val_optim_loss: 6379.1128
Epoch 15/100 |███-----------------| 15.0% val_auroc_score: 0.9361; val_auprc_score: 0.9274; val_best_acc_score: 0.8647; val_best_f1_score: 0.8698; train_kl_reg_loss: 49.0725; train_edge_recon_loss: 988.3823; train_gene_expr_recon_loss: 5296.1879; train_lambda_latent_adj_recon_loss: 225.4141; train_lambda_latent_contrastive_instanceloss: 7.1702; train_lambda_latent_contrastive_clusterloss: 2.3497; train_global_loss: 6568.5768; train_optim_loss: 6568.5768; val_kl_reg_loss: 48.3474; val_edge_recon_loss: 896.2615; val_gene_expr_recon_loss: 5237.8419; val_lambda_latent_adj_recon_loss: 202.6539; val_lambda_latent_contrastive_instanceloss: 7.1008; val_lambda_latent_contrastive_clusterloss: 2.1894; val_global_loss: 6394.3949; val_optim_loss: 6394.3949
Epoch 16/100 |███-----------------| 16.0% val_auroc_score: 0.9379; val_auprc_score: 0.9298; val_best_acc_score: 0.8670; val_best_f1_score: 0.8719; train_kl_reg_loss: 50.3630; train_edge_recon_loss: 985.6939; train_gene_expr_recon_loss: 5272.6490; train_lambda_latent_adj_recon_loss: 222.4369; train_lambda_latent_contrastive_instanceloss: 7.1643; train_lambda_latent_contrastive_clusterloss: 2.3290; train_global_loss: 6540.6361; train_optim_loss: 6540.6361; val_kl_reg_loss: 50.1794; val_edge_recon_loss: 894.4276; val_gene_expr_recon_loss: 5202.4649; val_lambda_latent_adj_recon_loss: 202.8389; val_lambda_latent_contrastive_instanceloss: 7.0885; val_lambda_latent_contrastive_clusterloss: 2.1455; val_global_loss: 6359.1449; val_optim_loss: 6359.1449
Epoch 17/100 |███-----------------| 17.0% val_auroc_score: 0.9387; val_auprc_score: 0.9303; val_best_acc_score: 0.8680; val_best_f1_score: 0.8728; train_kl_reg_loss: 51.4169; train_edge_recon_loss: 983.4045; train_gene_expr_recon_loss: 5285.5260; train_lambda_latent_adj_recon_loss: 220.2423; train_lambda_latent_contrastive_instanceloss: 7.1549; train_lambda_latent_contrastive_clusterloss: 2.3026; train_global_loss: 6550.0473; train_optim_loss: 6550.0473; val_kl_reg_loss: 50.9615; val_edge_recon_loss: 892.9413; val_gene_expr_recon_loss: 5205.1772; val_lambda_latent_adj_recon_loss: 199.4189; val_lambda_latent_contrastive_instanceloss: 7.0920; val_lambda_latent_contrastive_clusterloss: 2.1472; val_global_loss: 6357.7381; val_optim_loss: 6357.7381
Epoch 18/100 |███-----------------| 18.0% val_auroc_score: 0.9391; val_auprc_score: 0.9303; val_best_acc_score: 0.8689; val_best_f1_score: 0.8730; train_kl_reg_loss: 52.3619; train_edge_recon_loss: 980.9914; train_gene_expr_recon_loss: 5283.2702; train_lambda_latent_adj_recon_loss: 218.3410; train_lambda_latent_contrastive_instanceloss: 7.1553; train_lambda_latent_contrastive_clusterloss: 2.2937; train_global_loss: 6544.4135; train_optim_loss: 6544.4135; val_kl_reg_loss: 52.9606; val_edge_recon_loss: 892.3161; val_gene_expr_recon_loss: 5223.5675; val_lambda_latent_adj_recon_loss: 198.7384; val_lambda_latent_contrastive_instanceloss: 7.0897; val_lambda_latent_contrastive_clusterloss: 2.1517; val_global_loss: 6376.8239; val_optim_loss: 6376.8239
Epoch 19/100 |███-----------------| 19.0% val_auroc_score: 0.9392; val_auprc_score: 0.9307; val_best_acc_score: 0.8683; val_best_f1_score: 0.8740; train_kl_reg_loss: 53.6962; train_edge_recon_loss: 979.7246; train_gene_expr_recon_loss: 5278.8383; train_lambda_latent_adj_recon_loss: 217.6898; train_lambda_latent_contrastive_instanceloss: 7.1508; train_lambda_latent_contrastive_clusterloss: 2.2790; train_global_loss: 6539.3787; train_optim_loss: 6539.3787; val_kl_reg_loss: 52.9283; val_edge_recon_loss: 891.2258; val_gene_expr_recon_loss: 5276.3486; val_lambda_latent_adj_recon_loss: 196.0161; val_lambda_latent_contrastive_instanceloss: 7.0874; val_lambda_latent_contrastive_clusterloss: 2.1156; val_global_loss: 6425.7215; val_optim_loss: 6425.7215
Epoch 20/100 |████----------------| 20.0% val_auroc_score: 0.9396; val_auprc_score: 0.9300; val_best_acc_score: 0.8696; val_best_f1_score: 0.8741; train_kl_reg_loss: 54.7219; train_edge_recon_loss: 977.0739; train_gene_expr_recon_loss: 5273.4524; train_lambda_latent_adj_recon_loss: 214.7041; train_lambda_latent_contrastive_instanceloss: 7.1474; train_lambda_latent_contrastive_clusterloss: 2.2570; train_global_loss: 6529.3568; train_optim_loss: 6529.3568; val_kl_reg_loss: 54.8765; val_edge_recon_loss: 892.5430; val_gene_expr_recon_loss: 5252.6808; val_lambda_latent_adj_recon_loss: 196.6868; val_lambda_latent_contrastive_instanceloss: 7.0819; val_lambda_latent_contrastive_clusterloss: 2.1001; val_global_loss: 6405.9689; val_optim_loss: 6405.9689
Epoch 21/100 |████----------------| 21.0% val_auroc_score: 0.9419; val_auprc_score: 0.9336; val_best_acc_score: 0.8721; val_best_f1_score: 0.8771; train_kl_reg_loss: 55.9248; train_edge_recon_loss: 975.8963; train_gene_expr_recon_loss: 5255.5584; train_lambda_latent_adj_recon_loss: 213.8182; train_lambda_latent_contrastive_instanceloss: 7.1440; train_lambda_latent_contrastive_clusterloss: 2.2400; train_global_loss: 6510.5816; train_optim_loss: 6510.5816; val_kl_reg_loss: 56.4149; val_edge_recon_loss: 889.6046; val_gene_expr_recon_loss: 5198.2423; val_lambda_latent_adj_recon_loss: 196.1945; val_lambda_latent_contrastive_instanceloss: 7.0856; val_lambda_latent_contrastive_clusterloss: 2.0940; val_global_loss: 6349.6357; val_optim_loss: 6349.6357
Epoch 22/100 |████----------------| 22.0% val_auroc_score: 0.9422; val_auprc_score: 0.9346; val_best_acc_score: 0.8721; val_best_f1_score: 0.8776; train_kl_reg_loss: 56.9404; train_edge_recon_loss: 975.1945; train_gene_expr_recon_loss: 5251.8127; train_lambda_latent_adj_recon_loss: 212.9738; train_lambda_latent_contrastive_instanceloss: 7.1415; train_lambda_latent_contrastive_clusterloss: 2.2308; train_global_loss: 6506.2938; train_optim_loss: 6506.2938; val_kl_reg_loss: 57.0986; val_edge_recon_loss: 889.3088; val_gene_expr_recon_loss: 5204.8764; val_lambda_latent_adj_recon_loss: 193.6755; val_lambda_latent_contrastive_instanceloss: 7.0878; val_lambda_latent_contrastive_clusterloss: 2.1027; val_global_loss: 6354.1497; val_optim_loss: 6354.1497
Epoch 23/100 |████----------------| 23.0% val_auroc_score: 0.9420; val_auprc_score: 0.9336; val_best_acc_score: 0.8720; val_best_f1_score: 0.8773; train_kl_reg_loss: 57.7304; train_edge_recon_loss: 972.8330; train_gene_expr_recon_loss: 5244.1349; train_lambda_latent_adj_recon_loss: 210.5924; train_lambda_latent_contrastive_instanceloss: 7.1421; train_lambda_latent_contrastive_clusterloss: 2.2189; train_global_loss: 6494.6517; train_optim_loss: 6494.6517; val_kl_reg_loss: 58.9109; val_edge_recon_loss: 888.5466; val_gene_expr_recon_loss: 5232.9234; val_lambda_latent_adj_recon_loss: 193.4982; val_lambda_latent_contrastive_instanceloss: 7.0829; val_lambda_latent_contrastive_clusterloss: 2.0864; val_global_loss: 6383.0485; val_optim_loss: 6383.0485
Epoch 24/100 |████----------------| 24.0% val_auroc_score: 0.9436; val_auprc_score: 0.9346; val_best_acc_score: 0.8749; val_best_f1_score: 0.8792; train_kl_reg_loss: 58.5212; train_edge_recon_loss: 971.9691; train_gene_expr_recon_loss: 5243.5717; train_lambda_latent_adj_recon_loss: 210.2255; train_lambda_latent_contrastive_instanceloss: 7.1351; train_lambda_latent_contrastive_clusterloss: 2.2029; train_global_loss: 6493.6255; train_optim_loss: 6493.6255; val_kl_reg_loss: 59.3352; val_edge_recon_loss: 890.0997; val_gene_expr_recon_loss: 5238.8110; val_lambda_latent_adj_recon_loss: 194.7279; val_lambda_latent_contrastive_instanceloss: 7.0863; val_lambda_latent_contrastive_clusterloss: 2.0925; val_global_loss: 6392.1526; val_optim_loss: 6392.1526
Epoch 25/100 |█████---------------| 25.0% val_auroc_score: 0.9438; val_auprc_score: 0.9359; val_best_acc_score: 0.8750; val_best_f1_score: 0.8795; train_kl_reg_loss: 59.2990; train_edge_recon_loss: 970.9260; train_gene_expr_recon_loss: 5265.2547; train_lambda_latent_adj_recon_loss: 208.6764; train_lambda_latent_contrastive_instanceloss: 7.1365; train_lambda_latent_contrastive_clusterloss: 2.2007; train_global_loss: 6513.4933; train_optim_loss: 6513.4933; val_kl_reg_loss: 59.5585; val_edge_recon_loss: 887.8429; val_gene_expr_recon_loss: 5210.1071; val_lambda_latent_adj_recon_loss: 191.6170; val_lambda_latent_contrastive_instanceloss: 7.0896; val_lambda_latent_contrastive_clusterloss: 2.0841; val_global_loss: 6358.2992; val_optim_loss: 6358.2992

Reducing learning rate: metric has not improved more than 0.0 in the last 4 epochs.
New learning rate is 0.0001.

Epoch 26/100 |█████---------------| 26.0% val_auroc_score: 0.9446; val_auprc_score: 0.9367; val_best_acc_score: 0.8745; val_best_f1_score: 0.8793; train_kl_reg_loss: 59.7228; train_edge_recon_loss: 969.2287; train_gene_expr_recon_loss: 5232.8439; train_lambda_latent_adj_recon_loss: 208.1203; train_lambda_latent_contrastive_instanceloss: 7.1374; train_lambda_latent_contrastive_clusterloss: 2.2018; train_global_loss: 6479.2550; train_optim_loss: 6479.2550; val_kl_reg_loss: 60.6127; val_edge_recon_loss: 887.4112; val_gene_expr_recon_loss: 5133.7036; val_lambda_latent_adj_recon_loss: 191.0741; val_lambda_latent_contrastive_instanceloss: 7.0808; val_lambda_latent_contrastive_clusterloss: 2.0602; val_global_loss: 6281.9426; val_optim_loss: 6281.9426
Epoch 27/100 |█████---------------| 27.0% val_auroc_score: 0.9438; val_auprc_score: 0.9347; val_best_acc_score: 0.8751; val_best_f1_score: 0.8805; train_kl_reg_loss: 59.9173; train_edge_recon_loss: 969.1290; train_gene_expr_recon_loss: 5229.4897; train_lambda_latent_adj_recon_loss: 207.7686; train_lambda_latent_contrastive_instanceloss: 7.1336; train_lambda_latent_contrastive_clusterloss: 2.1899; train_global_loss: 6475.6282; train_optim_loss: 6475.6282; val_kl_reg_loss: 60.7459; val_edge_recon_loss: 887.9291; val_gene_expr_recon_loss: 5167.0638; val_lambda_latent_adj_recon_loss: 190.4045; val_lambda_latent_contrastive_instanceloss: 7.0770; val_lambda_latent_contrastive_clusterloss: 2.0720; val_global_loss: 6315.2923; val_optim_loss: 6315.2923
Epoch 28/100 |█████---------------| 28.0% val_auroc_score: 0.9445; val_auprc_score: 0.9354; val_best_acc_score: 0.8750; val_best_f1_score: 0.8804; train_kl_reg_loss: 60.0907; train_edge_recon_loss: 968.2249; train_gene_expr_recon_loss: 5243.8397; train_lambda_latent_adj_recon_loss: 207.8056; train_lambda_latent_contrastive_instanceloss: 7.1319; train_lambda_latent_contrastive_clusterloss: 2.1862; train_global_loss: 6489.2790; train_optim_loss: 6489.2790; val_kl_reg_loss: 61.0254; val_edge_recon_loss: 886.7026; val_gene_expr_recon_loss: 5215.5517; val_lambda_latent_adj_recon_loss: 192.0533; val_lambda_latent_contrastive_instanceloss: 7.0826; val_lambda_latent_contrastive_clusterloss: 2.0794; val_global_loss: 6364.4950; val_optim_loss: 6364.4950
Epoch 29/100 |█████---------------| 29.0% val_auroc_score: 0.9448; val_auprc_score: 0.9369; val_best_acc_score: 0.8758; val_best_f1_score: 0.8803; train_kl_reg_loss: 59.9719; train_edge_recon_loss: 968.2728; train_gene_expr_recon_loss: 5228.9737; train_lambda_latent_adj_recon_loss: 207.6368; train_lambda_latent_contrastive_instanceloss: 7.1318; train_lambda_latent_contrastive_clusterloss: 2.1875; train_global_loss: 6474.1745; train_optim_loss: 6474.1745; val_kl_reg_loss: 60.9045; val_edge_recon_loss: 887.8273; val_gene_expr_recon_loss: 5192.4658; val_lambda_latent_adj_recon_loss: 190.7073; val_lambda_latent_contrastive_instanceloss: 7.0761; val_lambda_latent_contrastive_clusterloss: 2.0699; val_global_loss: 6341.0510; val_optim_loss: 6341.0510
Epoch 30/100 |██████--------------| 30.0% val_auroc_score: 0.9455; val_auprc_score: 0.9371; val_best_acc_score: 0.8766; val_best_f1_score: 0.8807; train_kl_reg_loss: 60.1584; train_edge_recon_loss: 968.0897; train_gene_expr_recon_loss: 5235.3950; train_lambda_latent_adj_recon_loss: 207.0717; train_lambda_latent_contrastive_instanceloss: 7.1310; train_lambda_latent_contrastive_clusterloss: 2.1928; train_global_loss: 6480.0386; train_optim_loss: 6480.0386; val_kl_reg_loss: 61.2421; val_edge_recon_loss: 886.7793; val_gene_expr_recon_loss: 5209.3997; val_lambda_latent_adj_recon_loss: 191.9946; val_lambda_latent_contrastive_instanceloss: 7.0864; val_lambda_latent_contrastive_clusterloss: 2.0714; val_global_loss: 6358.5735; val_optim_loss: 6358.5735

Reducing learning rate: metric has not improved more than 0.0 in the last 4 epochs.
New learning rate is 1e-05.

Epoch 31/100 |██████--------------| 31.0% val_auroc_score: 0.9461; val_auprc_score: 0.9385; val_best_acc_score: 0.8766; val_best_f1_score: 0.8815; train_kl_reg_loss: 60.2164; train_edge_recon_loss: 968.0784; train_gene_expr_recon_loss: 5225.1694; train_lambda_latent_adj_recon_loss: 207.3752; train_lambda_latent_contrastive_instanceloss: 7.1328; train_lambda_latent_contrastive_clusterloss: 2.1873; train_global_loss: 6470.1596; train_optim_loss: 6470.1596; val_kl_reg_loss: 61.1259; val_edge_recon_loss: 886.3493; val_gene_expr_recon_loss: 5189.7393; val_lambda_latent_adj_recon_loss: 192.0157; val_lambda_latent_contrastive_instanceloss: 7.0793; val_lambda_latent_contrastive_clusterloss: 2.0729; val_global_loss: 6338.3822; val_optim_loss: 6338.3822
Epoch 32/100 |██████--------------| 32.0% val_auroc_score: 0.9453; val_auprc_score: 0.9377; val_best_acc_score: 0.8760; val_best_f1_score: 0.8808; train_kl_reg_loss: 60.1959; train_edge_recon_loss: 968.2590; train_gene_expr_recon_loss: 5237.1731; train_lambda_latent_adj_recon_loss: 207.1313; train_lambda_latent_contrastive_instanceloss: 7.1311; train_lambda_latent_contrastive_clusterloss: 2.1876; train_global_loss: 6482.0780; train_optim_loss: 6482.0780; val_kl_reg_loss: 61.1736; val_edge_recon_loss: 887.1943; val_gene_expr_recon_loss: 5212.0062; val_lambda_latent_adj_recon_loss: 191.6209; val_lambda_latent_contrastive_instanceloss: 7.0895; val_lambda_latent_contrastive_clusterloss: 2.0963; val_global_loss: 6361.1807; val_optim_loss: 6361.1807
Epoch 33/100 |██████--------------| 33.0% val_auroc_score: 0.9467; val_auprc_score: 0.9385; val_best_acc_score: 0.8785; val_best_f1_score: 0.8829; train_kl_reg_loss: 60.2250; train_edge_recon_loss: 967.8500; train_gene_expr_recon_loss: 5237.6586; train_lambda_latent_adj_recon_loss: 206.6367; train_lambda_latent_contrastive_instanceloss: 7.1301; train_lambda_latent_contrastive_clusterloss: 2.1838; train_global_loss: 6481.6842; train_optim_loss: 6481.6842; val_kl_reg_loss: 61.1430; val_edge_recon_loss: 886.0104; val_gene_expr_recon_loss: 5205.8841; val_lambda_latent_adj_recon_loss: 190.2358; val_lambda_latent_contrastive_instanceloss: 7.0813; val_lambda_latent_contrastive_clusterloss: 2.0675; val_global_loss: 6352.4224; val_optim_loss: 6352.4224
Epoch 34/100 |██████--------------| 34.0% val_auroc_score: 0.9453; val_auprc_score: 0.9364; val_best_acc_score: 0.8768; val_best_f1_score: 0.8817; train_kl_reg_loss: 60.2026; train_edge_recon_loss: 968.1556; train_gene_expr_recon_loss: 5221.0603; train_lambda_latent_adj_recon_loss: 207.4286; train_lambda_latent_contrastive_instanceloss: 7.1327; train_lambda_latent_contrastive_clusterloss: 2.1960; train_global_loss: 6466.1759; train_optim_loss: 6466.1759; val_kl_reg_loss: 61.1081; val_edge_recon_loss: 886.8730; val_gene_expr_recon_loss: 5185.8363; val_lambda_latent_adj_recon_loss: 191.4617; val_lambda_latent_contrastive_instanceloss: 7.0747; val_lambda_latent_contrastive_clusterloss: 2.0495; val_global_loss: 6334.4030; val_optim_loss: 6334.4030

Stopping early: metric has not improved more than 0.0 in the last 8 epochs.
If the early stopping criterion is too strong, please instantiate it with different parameters in the train method.
Model training finished after 22 min 46 sec.
Using best model state, which was in epoch 26.

--- MODEL EVALUATION ---
val AUROC score: 0.9449
val AUPRC score: 0.9367
val best accuracy score: 0.8758
val best F1 score: 0.8801
val MSE score: 0.2599
[10]:
# Compute latent neighbor graph
latent_key = 'garfield_latent'
sc.pp.neighbors(model.adata,
                use_rep=latent_key,
                key_added=latent_key)
# Compute UMAP embedding
sc.tl.umap(model.adata,
           neighbors_key=latent_key)

Visualize Garfield Latent Space

[11]:
sc.settings.set_figure_params(dpi=100, facecolor='white')

## cell distribution colored by original celltype
sc.pl.umap(model.adata, color=['cell_type'], show=True, size=3)
../_images/tutorial_05.Garfield_spatial_niche_slideseqv2_mouse_hippocampus_15_0.png
[12]:
# Compute latent Leiden clustering
latent_leiden_resolution = 0.5
latent_cluster_key = f"latent_leiden_{str(latent_leiden_resolution)}"
latent_key = "garfield_latent"

sc.tl.leiden(adata=model.adata,
             resolution=latent_leiden_resolution,
             key_added=latent_cluster_key,
             neighbors_key=latent_key)
len(model.adata.obs[latent_cluster_key].unique())
[12]:
12
[13]:
# Visualize cell-level annotated data in physical space
model.adata.obsm['spatial'][:, 1] *= -1  # 翻转 y 坐标 手动修正
sc.pl.embedding(model.adata, basis="spatial",
            color=["cell_type"],
            ncols=1, wspace=0.20, edges=False)

## niches
sc.pl.embedding(model.adata, basis="spatial",
            color=[latent_cluster_key],
            ncols=1, wspace=0.20, edges=False)
../_images/tutorial_05.Garfield_spatial_niche_slideseqv2_mouse_hippocampus_17_0.png
../_images/tutorial_05.Garfield_spatial_niche_slideseqv2_mouse_hippocampus_17_1.png
[14]:
# Save trained model
model_folder_path = f"{workdir}/model"
os.makedirs(model_folder_path, exist_ok=True)

model.save(dir_path=model_folder_path,
           overwrite=True,
           save_adata=True,
           adata_file_name="adata_ref.h5ad")
Model saved successfully using pickle at /home/zhouweige/zhouwg_data/project/Garfield_tutorials/result/garfield_spRNA_mouse_hippocampus/model/attr.pkl
[ ]: