ml-property-predict-scd
Goal
Use SelfConditionedDenoisingAtoms for four related workflows:
- apply a frozen SCD checkpoint as a live atomistic encoder
- train a lightweight head on top of a frozen SCD backbone
- fine-tune an entire pretrained SCD checkpoint on a new property task
- pretrain a new SCD model or add a new dataset adapter
First Checks
- Use the
scd-agent environment from conda-envs/scd-agent/.
- Confirm the upstream repo exists at
../SelfConditionedDenoisingAtoms relative to AtomisticSkills, or create it with conda-envs/scd-agent/install.sh.
- Read the upstream
README.md and examples.ipynb.
- Then read the local references in this skill:
references/repo-map.md
references/transfer-recipes.md
references/config-recipes.md
references/dataset-contract.md if a new dataset is involved
Checkpoint Selection
- Use
ct-scd-pcq for molecule property prediction, molecule embeddings, and molecule-side transfer learning.
- Use
ct-scd-amp for materials property prediction, periodic materials embeddings, and materials-side transfer learning.
Do not swap these by default. The public checkpoints were pretrained on different domains.
Instructions
1. Frozen backbone embeddings
Default to out["mol_emb"] for graph-level downstream ML.
- Use
return_atom_embs=True only when the downstream task needs atom- or site-level features.
- Keep the checkpoint frozen and in
eval() mode.
- Disable the denoising head for this workflow to avoid wasted compute.
- Pass
graph_batch=batch only when allow_periodic or noise_in_loader is enabled. Do not force graph_batch on the fast molecular path.
- Reuse
templates/extract_embeddings.py as the starting point. It keeps the model live and returns embeddings on demand instead of defaulting to a frozen feature dump.
2. Lightweight training with a frozen SCD backbone
Use templates/train_lightweight_head.py for three lightweight options:
scalar_head
Appropriate for invariant scalar regression targets. This path trains only the model's native scalar_head using pretrained backbone weights.
atom_emb_mlp
Pools atom_embs with sum or mean, then trains a 1- or 2-layer MLP head.
mol_emb_mlp
Uses mol_emb directly, then trains a 1- or 2-layer MLP head.
Important details:
scalar_head is usually the lightest path for standard scalar property prediction.
reset_head() is a sensible default for scalar_head mode when switching to a new target.
set_head_agg controls the native scalar-head reduction and should be set through the checkpoint-loading path, not by editing tensors after the fact.
- the upstream model exposes
finetune() and reset_head(), but finetune() does not by itself implement scalar-head-only training; explicitly freeze non-scalar_head parameters in the lightweight script.
- the lightweight
scalar_head path should reset the checkpoint's output affine buffers to identity because pretrained mean/std buffers are not downstream target statistics.
- for
atom_emb_mlp, either sum or mean pooling may work better depending on whether the target behaves more like an extensive or intensive quantity.
atom_emb_mlp and mol_emb_mlp should compute frozen-backbone features on the fly, not treat a static embedding cache as the default workflow.
mol_emb_mlp is the cleanest external-head baseline on the pretrained graph representation.
3. Full-model finetuning
Use the native training path when you want all model weights updated:
# Env: scd-agent
cd ../SelfConditionedDenoisingAtoms
python train.py --conf configs/my_finetune.yaml --load-hf ct-scd-pcq --job-id my_run
or
# Env: scd-agent
cd ../SelfConditionedDenoisingAtoms
python train.py --conf configs/my_finetune.yaml --load-hf ct-scd-amp --job-id my_run
Start from:
templates/finetune_config.template.yaml
configs/finetune_qm9.yaml for public molecular examples
For public materials finetuning, do not rely on configs/finetune_matbench.yaml unless the private StructureCloud dependency is available. Copy the template and configure the periodic settings yourself.
Full-model finetuning usually gives better results than the lightweight frozen-backbone options, but it costs more GPU memory and more wall time.
4. Pretraining from scratch
Use the native training path:
# Env: scd-agent
cd ../SelfConditionedDenoisingAtoms
python train.py --conf configs/my_pretrain.yaml --job-id my_pretrain
Start from:
templates/pretrain_config.template.yaml
configs/pretrain_pcq.yaml for molecules
configs/pretrain_amp20.yaml for periodic materials
Dataset Onboarding
When adding a new dataset class under SelfConditionedDenoisingAtoms/data/datasets/:
- Start from
templates/dataset_template.py.
- Preserve the constructor signature
__init__(root, dataset_arg=None, transform=None, **kwargs).
- Return
torch_geometric.data.Data objects with the required fields for the training mode.
- Expose a stable per-sample identifier such as
idx and optionally a human-readable identifier on each Data object when practical.
- Export the dataset from
data/datasets/__init__.py, or train.py --dataset ... will reject it.
- If the task needs dataset-specific config knobs beyond
root, dataset_arg, and transform, wire them through train.py argparse and data/loaders.py.
- Prefer creating a new run config YAML instead of editing a shared baseline config in place. This makes experiment tracking and diffs much clearer.
- Add the new config file and smoke-test the run with a short
--num-steps override.
Smoke Test
Before launching a full run:
- check
nvidia-smi first to confirm CUDA-visible GPUs exist on the real machine and to see whether another job is already using them
- ask the user whether they want a single GPU or all available GPUs before choosing device placement
- if the user wants a single GPU, prefer a GPU with no active compute process and low memory usage instead of one that is already busy
- import the dataset class successfully in the target environment
- instantiate one dataset split and inspect one sample
- build one dataloader batch through
data/loaders.py
- run a short
train.py --conf ... --num-steps 100 or 200 check while actively watching live command-line output
- confirm checkpoints and W&B logging land in the expected run directory
Treat live stdout visibility as general guidance for SCD runs, not just these example wrappers. When possible, launch smoke tests and full runs with unbuffered stdout and without command-capture layers so startup messages stay visible.
- Use
nvidia-smi both before launch and during launch: before launch to choose devices, during launch to verify the intended GPU or GPUs are actually being used.
- Do not default to grabbing every GPU on a shared workstation. Ask first.
- Prefer
python -u ... and a TTY-capable shell session for smoke runs.
- If using
conda run, prefer conda run --no-capture-output ... so dataset downloads, checkpoint downloads, split generation, and normalization work are visible immediately.
- Treat an initially quiet terminal as ambiguous until you have checked live stdout. For first-run workflows, several minutes of startup can be legitimate while data or checkpoints are prepared.
- For the fastest smoke tests, copy the target config and disable expensive reporting such as
parity_plot: true before launching. Otherwise a max_steps=2 run can still spend significant extra time on parity-plot generation and repeated evaluation passes.
- Expect QM9-like runs to spend real wall time computing dataset
mean/std, sometimes more than once across train and test setup. This is startup work, not necessarily a hang.
- When launching on one physical GPU, set
CUDA_VISIBLE_DEVICES=<gpu_id> and pass --use-devices 0 so the upstream trainer uses only that logical device.
- When launching on multiple GPUs, set
CUDA_VISIBLE_DEVICES to the chosen physical ids and pass --use-devices 0 1 ... across the visible logical devices.
Examples
Check the detailed, reproducible examples in the examples/ directory:
- QM9 Lightweight Tuning: Finetuning example on molecular targets.
- Matbench Lightweight Tuning: Finetuning example on periodic materials.
Constraints
Environments: Scripts require the scd-agent Conda environment. Each code block MUST specify the environment.
train.py always creates a WandbLogger.
For finetuning runs, train.py derives the W&B project from the config dataset field, currently as SCD_bench_{dataset}.
The W&B run name and id both come from job_id, so set the specific run identifier in the config file or override it on the CLI.
train.py is configured with accelerator="gpu".
Native train.py handles standard pretraining and finetuning loops well, but special prediction/export flows or custom evaluation loops may still need a small wrapper script.
noise_in_loader: true is required for periodic materials and is the fallback when the optional TorchMD CUDA extension is not built.
Public repo examples cover PCQM4MV2, AlexMP20, QM9, MD17, and OMOL25 best.
The public checkpoints are downloaded as last.ckpt files from Hugging Face.
The upstream pretraining path freezes the scalar head, so reset_head: true is a reasonable downstream default when switching to a new scalar property during full-model finetuning. That is an inference from the code path, not a documented upstream requirement.
Troubleshooting
- Unknown keys in a run YAML fail fast during
--conf parsing.
- A dataset is not selectable from
--dataset until it is exported from data/datasets/__init__.py.
- If the TorchMD extension is not built, prefer
noise_in_loader: true for molecular runs.
- The default trainer is GPU-oriented, so verify the intended environment before debugging dataset code.
- If a run appears to hang at startup, first rerun it with visible live stdout before assuming the trainer is stuck. First-use QM9 or checkpointed runs may still be downloading data, creating splits, or computing dataset statistics.
- If GPU availability is unclear, rerun
nvidia-smi outside any restrictive sandbox before concluding that CUDA is unavailable.
- If the workstation is shared, check
nvidia-smi memory use and active compute processes before choosing devices. A GPU with near-zero utilization but several GiB already allocated may still belong to another live job.
wandb status may be inconclusive even when online login works through ~/.netrc. If you need certainty, run a tiny online wandb.init(..., mode="online") probe or observe the live W&B login lines during a real run.
References
- SelfConditionedDenoisingAtoms reference implementation.
Author: Ty Perez
Contact: tyjperez@gmail.com
1---2name: ml-property-predict-scd3description: Train a model to predict custom properties of molecules or periodic materials using pretrained SelfConditionedDenoisingAtoms (SCD) foundation models.4---56# ml-property-predict-scd78## Goal910Use `SelfConditionedDenoisingAtoms` for four related workflows:1112- apply a frozen SCD checkpoint as a live atomistic encoder13- train a lightweight head on top of a frozen SCD backbone14- fine-tune an entire pretrained SCD checkpoint on a new property task15- pretrain a new SCD model or add a new dataset adapter1617## First Checks18191. Use the `scd-agent` environment from `conda-envs/scd-agent/`.202. Confirm the upstream repo exists at `../SelfConditionedDenoisingAtoms` relative to `AtomisticSkills`, or create it with `conda-envs/scd-agent/install.sh`.213. Read the upstream `README.md` and `examples.ipynb`.224. Then read the local references in this skill:23 - `references/repo-map.md`24 - `references/transfer-recipes.md`25 - `references/config-recipes.md`26 - `references/dataset-contract.md` if a new dataset is involved2728## Checkpoint Selection2930- Use `ct-scd-pcq` for molecule property prediction, molecule embeddings, and molecule-side transfer learning.31- Use `ct-scd-amp` for materials property prediction, periodic materials embeddings, and materials-side transfer learning.3233Do not swap these by default. The public checkpoints were pretrained on different domains.3435## Instructions3637### 1. Frozen backbone embeddings3839Default to `out["mol_emb"]` for graph-level downstream ML.4041- Use `return_atom_embs=True` only when the downstream task needs atom- or site-level features.42- Keep the checkpoint frozen and in `eval()` mode.43- Disable the denoising head for this workflow to avoid wasted compute.44- Pass `graph_batch=batch` only when `allow_periodic` or `noise_in_loader` is enabled. Do not force `graph_batch` on the fast molecular path.45- Reuse `templates/extract_embeddings.py` as the starting point. It keeps the model live and returns embeddings on demand instead of defaulting to a frozen feature dump.4647### 2. Lightweight training with a frozen SCD backbone4849Use `templates/train_lightweight_head.py` for three lightweight options:50511. `scalar_head`52 Appropriate for invariant scalar regression targets. This path trains only the model's native `scalar_head` using pretrained backbone weights.532. `atom_emb_mlp`54 Pools `atom_embs` with `sum` or `mean`, then trains a 1- or 2-layer MLP head.553. `mol_emb_mlp`56 Uses `mol_emb` directly, then trains a 1- or 2-layer MLP head.5758Important details:5960- `scalar_head` is usually the lightest path for standard scalar property prediction.61- `reset_head()` is a sensible default for `scalar_head` mode when switching to a new target.62- `set_head_agg` controls the native scalar-head reduction and should be set through the checkpoint-loading path, not by editing tensors after the fact.63- the upstream model exposes `finetune()` and `reset_head()`, but `finetune()` does not by itself implement scalar-head-only training; explicitly freeze non-`scalar_head` parameters in the lightweight script.64- the lightweight `scalar_head` path should reset the checkpoint's output affine buffers to identity because pretrained `mean/std` buffers are not downstream target statistics.65- for `atom_emb_mlp`, either `sum` or `mean` pooling may work better depending on whether the target behaves more like an extensive or intensive quantity.66- `atom_emb_mlp` and `mol_emb_mlp` should compute frozen-backbone features on the fly, not treat a static embedding cache as the default workflow.67- `mol_emb_mlp` is the cleanest external-head baseline on the pretrained graph representation.6869### 3. Full-model finetuning7071Use the native training path when you want all model weights updated:7273```bash74# Env: scd-agent75cd ../SelfConditionedDenoisingAtoms76python train.py --conf configs/my_finetune.yaml --load-hf ct-scd-pcq --job-id my_run77```7879or8081```bash82# Env: scd-agent83cd ../SelfConditionedDenoisingAtoms84python train.py --conf configs/my_finetune.yaml --load-hf ct-scd-amp --job-id my_run85```8687Start from:8889- `templates/finetune_config.template.yaml`90- `configs/finetune_qm9.yaml` for public molecular examples9192For public materials finetuning, do not rely on `configs/finetune_matbench.yaml` unless the private `StructureCloud` dependency is available. Copy the template and configure the periodic settings yourself.9394Full-model finetuning usually gives better results than the lightweight frozen-backbone options, but it costs more GPU memory and more wall time.9596### 4. Pretraining from scratch9798Use the native training path:99100```bash101# Env: scd-agent102cd ../SelfConditionedDenoisingAtoms103python train.py --conf configs/my_pretrain.yaml --job-id my_pretrain104```105106Start from:107108- `templates/pretrain_config.template.yaml`109- `configs/pretrain_pcq.yaml` for molecules110- `configs/pretrain_amp20.yaml` for periodic materials111112## Dataset Onboarding113114When adding a new dataset class under `SelfConditionedDenoisingAtoms/data/datasets/`:1151161. Start from `templates/dataset_template.py`.1172. Preserve the constructor signature `__init__(root, dataset_arg=None, transform=None, **kwargs)`.1183. Return `torch_geometric.data.Data` objects with the required fields for the training mode.1194. Expose a stable per-sample identifier such as `idx` and optionally a human-readable `identifier` on each `Data` object when practical.1205. Export the dataset from `data/datasets/__init__.py`, or `train.py --dataset ...` will reject it.1216. If the task needs dataset-specific config knobs beyond `root`, `dataset_arg`, and `transform`, wire them through `train.py` argparse and `data/loaders.py`.1227. Prefer creating a new run config YAML instead of editing a shared baseline config in place. This makes experiment tracking and diffs much clearer.1238. Add the new config file and smoke-test the run with a short `--num-steps` override.124125## Smoke Test126127Before launching a full run:1281291. check `nvidia-smi` first to confirm CUDA-visible GPUs exist on the real machine and to see whether another job is already using them1302. ask the user whether they want a single GPU or all available GPUs before choosing device placement1313. if the user wants a single GPU, prefer a GPU with no active compute process and low memory usage instead of one that is already busy1324. import the dataset class successfully in the target environment1335. instantiate one dataset split and inspect one sample1346. build one dataloader batch through `data/loaders.py`1357. run a short `train.py --conf ... --num-steps 100` or `200` check while actively watching live command-line output1368. confirm checkpoints and W&B logging land in the expected run directory137138Treat live stdout visibility as general guidance for SCD runs, not just these example wrappers. When possible, launch smoke tests and full runs with unbuffered stdout and without command-capture layers so startup messages stay visible.139140- Use `nvidia-smi` both before launch and during launch: before launch to choose devices, during launch to verify the intended GPU or GPUs are actually being used.141- Do not default to grabbing every GPU on a shared workstation. Ask first.142- Prefer `python -u ...` and a TTY-capable shell session for smoke runs.143- If using `conda run`, prefer `conda run --no-capture-output ...` so dataset downloads, checkpoint downloads, split generation, and normalization work are visible immediately.144- Treat an initially quiet terminal as ambiguous until you have checked live stdout. For first-run workflows, several minutes of startup can be legitimate while data or checkpoints are prepared.145- For the fastest smoke tests, copy the target config and disable expensive reporting such as `parity_plot: true` before launching. Otherwise a `max_steps=2` run can still spend significant extra time on parity-plot generation and repeated evaluation passes.146- Expect QM9-like runs to spend real wall time computing dataset `mean/std`, sometimes more than once across train and test setup. This is startup work, not necessarily a hang.147- When launching on one physical GPU, set `CUDA_VISIBLE_DEVICES=<gpu_id>` and pass `--use-devices 0` so the upstream trainer uses only that logical device.148- When launching on multiple GPUs, set `CUDA_VISIBLE_DEVICES` to the chosen physical ids and pass `--use-devices 0 1 ...` across the visible logical devices.149150## Examples151152Check the detailed, reproducible examples in the `examples/` directory:153- [QM9 Lightweight Tuning](examples/CT-SCD_QM9/README.md): Finetuning example on molecular targets.154- [Matbench Lightweight Tuning](examples/CT-SCD_matbench/README.md): Finetuning example on periodic materials.155156## Constraints157158- **Environments**: Scripts require the `scd-agent` Conda environment. Each code block MUST specify the environment.159160- `train.py` always creates a `WandbLogger`.161- For finetuning runs, `train.py` derives the W&B project from the config `dataset` field, currently as `SCD_bench_{dataset}`.162- The W&B run `name` and `id` both come from `job_id`, so set the specific run identifier in the config file or override it on the CLI.163- `train.py` is configured with `accelerator="gpu"`.164- Native `train.py` handles standard pretraining and finetuning loops well, but special prediction/export flows or custom evaluation loops may still need a small wrapper script.165- `noise_in_loader: true` is required for periodic materials and is the fallback when the optional TorchMD CUDA extension is not built.166- Public repo examples cover `PCQM4MV2`, `AlexMP20`, `QM9`, `MD17`, and `OMOL25` best.167- The public checkpoints are downloaded as `last.ckpt` files from Hugging Face.168- The upstream pretraining path freezes the scalar head, so `reset_head: true` is a reasonable downstream default when switching to a new scalar property during full-model finetuning. That is an inference from the code path, not a documented upstream requirement.169170## Troubleshooting171172- Unknown keys in a run YAML fail fast during `--conf` parsing.173- A dataset is not selectable from `--dataset` until it is exported from `data/datasets/__init__.py`.174- If the TorchMD extension is not built, prefer `noise_in_loader: true` for molecular runs.175- The default trainer is GPU-oriented, so verify the intended environment before debugging dataset code.176- If a run appears to hang at startup, first rerun it with visible live stdout before assuming the trainer is stuck. First-use QM9 or checkpointed runs may still be downloading data, creating splits, or computing dataset statistics.177- If GPU availability is unclear, rerun `nvidia-smi` outside any restrictive sandbox before concluding that CUDA is unavailable.178- If the workstation is shared, check `nvidia-smi` memory use and active compute processes before choosing devices. A GPU with near-zero utilization but several GiB already allocated may still belong to another live job.179- `wandb status` may be inconclusive even when online login works through `~/.netrc`. If you need certainty, run a tiny online `wandb.init(..., mode="online")` probe or observe the live W&B login lines during a real run.180181## References182183- SelfConditionedDenoisingAtoms reference implementation.184185---186187**Author:** Ty Perez188**Contact:** [tyjperez@gmail.com](mailto:tyjperez@gmail.com)