Views
No views yet
1d58906scripts/run_scgpt.pydata/manifests/replogle.yaml--stop-metric pearson_delta (per-perturbation Pearson on Δ-expression) for early-stopping and best-checkpoint selection — this metric directly measures perturbation-effect prediction quality, whereas full-expression pearson is dominated by the unchanged-genes baseline.| Hardware | NVIDIA H100 PCIe (80 GB) |
| Train batch size | 192 |
| Eval batch size | 192 |
| Max epochs | 30 |
| Early-stop patience | 10 |
| Stop metric | pearson_delta |
| Epochs trained | 19 (early-stopped) |
| Best epoch | 9 |
Best val pearson_delta | 0.1944 |
| Training cells seen | 3,420,399 |
| Wall clock | 254.6 min (~4.25 h) |
| AMP | fp16 |
| Optimizer | Adam, lr=1e-4, StepLR γ=0.9 |
| metric | mean | median | max |
|---|---|---|---|
| pearson_delta | 0.5080 | 0.5057 | 0.6985 |
| pr_auc | 0.5304 | 0.5239 | 0.9234 |
| roc_auc | 0.3878 | 0.3868 | 0.4872 |
| overlap_at_N | 0.5533 | 0.5596 | 0.9260 |
| de_sig_genes_recall | 0.6401 | 0.6540 | 0.9552 |
| de_direction_match | 0.6174 | 0.6315 | 0.7602 |
| discrimination_score_l1 | 0.5037 | 0.5014 | 1.0000 |
| mae_delta | 0.1650 | 0.1624 | 0.2221 |
full-profile numbers are not directly comparable to the scGPT or State paper headline numbers — those report different splits (within-cell-line on Norman, or 4-line leave-one-out via Replogle-Nadig). Companion runs in progress: (a) base scGPT without the ESM prior on the same K562/Jurkat/HepG2 → RPE1 split; (b) crosscoder-style model-diffing on the two finetuned models. The headline scientific question — does the ESM prior improve cross-cell-line transfer in scGPT — needs (a) before this artifact alone can answer it.pr_auc, roc_auc, de_sig_genes_recall, de_direction_match) are computed against K562-derived DE rankings; ideal for an RPE1 test set would be RPE1-derived DE rankings on the truth side.best_model.pt — fine-tuned weights (~210 MB)args.json — scGPT architecture config (inherited from scGPT_human)vocab.json — scGPT gene → token id mapping (inherited)scgpt_esm_prior.safetensors — frozen ESM2-15B per-gene prior aligned to scGPT's 60,697-token vocab — required at load time, the model expects ESM-augmented embeddingstraining_stats.json — epoch count, best metric, wall clock, wandb URLpredictions/scgpt_replogle_test.h5ad — .X = predicted expression, .layers['truth'] = ground truth; includes 10,691 real RPE1 controls; 119,898 cells × 6,546 geneseval/agg_results.csv — cell-eval full-profile aggregated stats across 1,047 RPE1 test perturbationseval/results.csv — cell-eval full-profile per-perturbation metrics1from pathlib import Path
2import torch, json
3from huggingface_hub import snapshot_download
4from scgpt.model import TransformerGenerator
5from scgpt.model.gene_priors import GenePriorEncoder
6from scgpt.tokenizer.gene_tokenizer import GeneVocab
7
8ckpt = Path(snapshot_download('matthewshu/scgpt-replogle-esm-ft'))
9vocab = GeneVocab.from_file(str(ckpt / 'vocab.json'))
10for tok in ('<pad>', '<cls>', '<eoc>'):
11 if tok not in vocab: vocab.append_token(tok)
12margs = json.load(open(ckpt / 'args.json'))
13gene_prior = GenePriorEncoder.from_safetensors(
14 ckpt / 'scgpt_esm_prior.safetensors', d_model=margs['embsize']
15)
16model = TransformerGenerator(
17 ntoken=len(vocab), d_model=margs['embsize'], nhead=margs['nheads'],
18 d_hid=margs['d_hid'], nlayers=margs['nlayers'], nlayers_cls=3,
19 n_cls=1, vocab=vocab, dropout=margs.get('dropout', 0.0),
20 pad_token=margs.get('pad_token', '<pad>'),
21 pad_value=margs.get('pad_value', 0),
22 pert_pad_id=margs.get('pert_pad_id', 2),
23 use_fast_transformer=False, gene_prior=gene_prior,
24)
25state = torch.load(ckpt / 'best_model.pt', map_location='cpu')
26model.load_state_dict(state)
27model.eval()
28