Skip to content

FEAT: ChargE3Net Fine-Tuning Pipeline on LeMatRho - #8

Open
speckhard wants to merge 7 commits into
LeMaterial:mainfrom
speckhard:feat/charge3net
Open

FEAT: ChargE3Net Fine-Tuning Pipeline on LeMatRho#8
speckhard wants to merge 7 commits into
LeMaterial:mainfrom
speckhard:feat/charge3net

Conversation

@speckhard

@speckhardspeckhard commented Mar 17, 2026

Copy link
Copy Markdown
Collaborator

`feat/charge3net` — ChargE3Net Fine-Tuning Pipeline

Overview

Fine-tunes ChargE3Net (Koker et al., npj Computational Materials 2024) on LeMatRho charge density data. The approach is:

  1. Clone the official AIforGreatGood/charge3net repo as a sibling directory — this provides both the model code (E3DensityModel) and the pre-trained Materials Project checkpoint (models/charge3net_mp.pt, 23 MB, 1.9M params, trained for 245 epochs / 407k steps on MP charge densities).
  2. Load those pre-trained weights into our wrapper and fine-tune on 65,239 LeMatRho materials (10×10×10 compressed charge density grids stored in Parquet).
  3. Train on Jean Zay (1× A100, 20h SLURM jobs), resuming across jobs via latest.pt.

The training pipeline lives in charge3net_ft/ — a self-contained package within this repo.

Setup

# 1. Clone charge3net as a sibling of LeMat-Rho (required — provides model + checkpoint)
git clone https://github.com/AIforGreatGood/charge3net ../charge3net
# 2. Install dependencies
uv sync
# 3. Set data path (or pass --parquet-dir directly)export LEMATRHO_DATA_DIR=/path/to/lematrho_full_10x10x10
# 4. Run a smoke test to verify everything works
python -m charge3net_ft.train --smoke-test

On Jean Zay, submit with sbatch submit_charge3net.sh — it auto-resumes from $SCRATCH/charge3net_checkpoints/latest.pt if present.

New Files

FileLinesPurpose
charge3net_ft/data.py270Lazy-loading PyTorch Dataset. Reads LeMatRho Parquet chunks, converts to ase.Atoms + density grids, builds charge3net-compatible graph dicts via KdTreeGraphConstructor. Per-worker table cache so each chunk file is read from disk once per worker, not once per sample.
charge3net_ft/model.py115Thin wrapper around charge3net's E3DensityModel. Handles instantiation with MP checkpoint hyperparameters and loading from 3 checkpoint formats (legacy PyTorch Lightning, new charge3net, raw state_dict).
charge3net_ft/train.py310Full training script with CLI. Supports normal training, smoke test, single-batch overfit test, W&B logging (online/offline), checkpoint resumption across SLURM jobs. Train/val/test three-way split with held-out test evaluation at the end.
submit_charge3net.sh47SLURM GPU submission script for Jean Zay (A100, 20h wall time). Auto-resumes from latest.pt if present.
tests/test_metrics.pyParametrized tests for compute_nmape, compute_rmse, compute_nrmse including padding-mask correctness.
tests/test_data.pyUnit tests for _parse_grid_json, _row_to_atoms_and_density, and _build_parquet_index using synthetic Parquet files — no real data needed.
tests/test_model.pyTests all 3 checkpoint-loading branches with mock state dicts.

Modified Files

FileChange
pyproject.tomlAdded torch>=2.0, numpy>=1.24, charge3net (git dep); loosened aggressive version pins
.gitignoreAdded *.pt to prevent accidental checkpoint commits

Training Results (30 epochs across 3 SLURM jobs)

Epochtrain L1 (e/ų)val L1 (e/ų)val NMAPE (%)val RMSE (e/ų)val NRMSE (%)
15.273.9414.158.9931.89
52.853.0310.666.4822.45
102.482.669.405.6219.55
152.312.569.005.4518.83
202.232.448.555.1717.91
252.132.408.435.0817.55
302.052.328.104.8416.76

Best checkpoint: best.pt at epoch 30 (8.10% val NMAPE). Model is still improving — no plateau observed. Note: these are val-set numbers (used for checkpoint selection). Test-set numbers will be reported after the next training run using the new three-way split.

Git Log

dae2b45 Add PYTHONUNBUFFERED=1 to SLURM script for real-time log output
f3ffde4 Add --resume-from for checkpoint resumption across SLURM jobs
252acac Fix wandb on air-gapped clusters: add offline mode and init timeout
99d391a Add W&B logging, RMSE/NRMSE metrics, and Jean Zay SLURM script
f72fa52 Training pipeline to train Charge3net on LeMat-Rho

- Add wandb integration with --wandb-project/--wandb-entity/--no-wandb flags
- Add compute_rmse() and compute_nrmse() validation metrics
- Log per-step train loss and per-epoch train/val metrics to W&B
- Load WANDB_API_KEY from .env via python-dotenv
- Add submit_charge3net.sh for Jean Zay A100 GPU jobs
- Add .gitignore (excludes .env, checkpoints, wandb, etc.)
- save_checkpoint now includes global_step
- load_checkpoint restores model, optimizer, scheduler, epoch, best_nmape, global_step
- SLURM script auto-detects latest.pt and passes --resume-from
@speckhard
speckhard marked this pull request as draft April 7, 2026 14:34
@speckhardspeckhard changed the title FEAT: ChargE3Net Fine-Tuning Pipeline on LeMatRho[DRAFT] FEAT: ChargE3Net Fine-Tuning Pipeline on LeMatRhoApr 7, 2026
@speckhard

Copy link
Copy Markdown
CollaboratorAuthor

@mfranckel let me try to create a job script for adastra so you can run this yourself.

@speckhard

Copy link
Copy Markdown
CollaboratorAuthor

Sorry still needs to be cleaned up before you review it, just wanted to make you aware of it

@speckhardspeckhard changed the title [DRAFT] FEAT: ChargE3Net Fine-Tuning Pipeline on LeMatRhoFEAT: ChargE3Net Fine-Tuning Pipeline on LeMatRhoApr 17, 2026
@speckhard
speckhard marked this pull request as ready for review May 12, 2026 10:34
speckhard added a commit to speckhard/LeMat-Rho that referenced this pull request Jun 1, 2026
Reviewer flagged two worth-flagging items.
LeMaterial#4 CHGCAR directory layout
* was: chgcar_root / f"{model}__{material_id}/CHGCAR"
* now: chgcar_root / model / material_id / CHGCAR
* the flat layout would have been ambiguous for synthesised IDs
containing the separator (e.g. "oqmd__1234"). Nested avoids that
entirely and is also more ls-friendly when sweeping models.
* new test test_chgcar_layout_is_nested_by_model_then_material_id
asserts the path tail.
LeMaterial#8 Test-data realism
* the existing _toy_parquet uses 2-atom H2 cells with
grid_shape=(4,4,4) and n_electrons=2.0 -- a missing n_electrons
rescale, a positions-reshape bug, or a grid/atom mismatch would
all pass silently.
* new TestRealisticRow.test_5_atom_asymmetric_grid_unequal_n_electrons
exercises an FeO4 row with grid_shape=(8,10,12) and n_electrons=12.5
!= sum(Z). Catches mutations on the reshape and rescale paths.
16 / 16 tests green; full suite green.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@speckhard