Skip to content

Baseline embedding-extraction scripts and documentation pass - #2

Merged
ComDec merged 9 commits into
mainfrom
baselines/v1
Sep 18, 2026
Merged

ComDec merged 9 commits into
mainfrom
baselines/v1

Conversation

@ComDec

@ComDec ComDec commented Sep 18, 2026

Copy link
Copy Markdown
Owner

This PR adds baselines/, the embedding-extraction script of each baseline model, and a
documentation pass over the toolkit's text. It builds on the reproducibility release already on
main (#1): the Hugging Face datasets and baseline embeddings, evaluators whose defaults reproduce
the published numbers, and per-table reproduction scripts with reference values.

Baseline extraction scripts

baselines/<model>/extract_chirality.py turns the chirality conformers into the embedding matrix
the evaluator reads, in dataset row order and under the documented array key.

Model Dim Output key Hydrogens Pooling Upstream dependency
E3FP 1024 bits e3fp (pickle) kept — (fingerprint) e3fp==1.2.7
GemNet-Q 128 gemnet RemoveAllHs, heavy atoms only mean over atoms TUM-DAML/gemnet_pytorch @ a0164f7 + its pretrained/GemNet-Q
Uni-Mol 512 arr_0 removed (no-H checkpoint) [CLS] token deepmodeling/Uni-Mol @ 90f52c4, dptech-corp/Uni-Core @ ace6fae, mol_pre_no_h_220816.pt
Mol-AE 512 arr_0 removed (no-H checkpoint) [CLS] token same Uni-Mol / Uni-Core, Mol-AE checkpoint_7_1000000.pt
MolSpectra 256 arr_0 removed (Z != 1) sum over atoms AzureLeon1/MolSpectra @ 8846530 + a checkpoint supplied by the caller
MACE 256 arr_0 kept mean over atoms mace-torch==0.3.15, MACE-MP-0 medium
FMG 128 embeddings dropped (C, O, N, F channels only) mean over the 24³ grid Dumitrescu-Alexandru/FMG @ 13a0a7c + model-120qm9_3rd_run.pt

Common to all of them, resolved by baselines/common.py:

  • --dataset takes the same value in every script: hf:EscheWang/3dcs:chirality (Hub repository
    and config), hf:<repo> or a bare Hub id (config chirality), hfdisk:<dir> or a plain
    save_to_disk directory of that config, a pickle of RDKit molecules (a list or a dict of
    lists), or lmdb:<file> for a rotation shard. Hugging Face rows are read in ascending offset
    and each row's offset is checked against the running conformer count, so mol_blocks
    concatenated that way is the row order of the published files.
  • --limit N / --start N run a slice of the conformers, in every script.
  • Each script prints the versions of every numerically relevant library, its own arguments, the
    SHA-256 of the weights it loaded and the SHA-256 of the file it wrote, and refuses to skip a
    conformer it cannot featurise rather than shifting the row order.
  • --verify [REFERENCE] compares the file just written with the published embedding of that model
    in EscheWang/3dcs-embeddings (or hub:<path>, or a local file) and prints both checksums, the
    elementwise differences and the per-row cosine similarity.
  • --verify-rows says which rows of the reference the output covers, so a partial run is
    verifiable: prefix (the default when the output is shorter), full, a <start>:<stop> slice,
    <start>+, or @<file> of 0-based row indices; --start N implies N+. The report names the
    selection, how many rows it compared and which rows of the reference it used.
  • baselines/README.md carries one runnable command per model, with the flags that model needs.

No third-party code or weights are redistributed. Every model directory has an ENVIRONMENT.md
with the upstream repository and commit, the weight file with its SHA-256 and where to download it,
the exact install commands and the measured cost of a full run, plus a pinned requirements.txt.
Every weight these scripts need is publicly downloadable without an account: the FMG checkpoint
from the Drive folder the upstream README links (gdown command and file id in
fmg/ENVIRONMENT.md), the Mol-AE checkpoint from the Drive link in the Mol-AE README, which
arrives as a ZIP archive that has to be unpacked before torch.load (command and both checksums in
molae/ENVIRONMENT.md), and the rest from GitHub releases or checkouts.

Agreement with the published embeddings

The published embedding files were computed from the source RDKit molecules, whose coordinates
carry full float precision; the public EscheWang/3dcs dataset stores the same geometries as V2000
MOL blocks, which hold four decimals. The table below is the comparison from the full-precision
molecules; baselines/README.md carries the same comparison from the published mol_blocks over
the first 2,000 conformers, which is what a run from the released dataset gives, and the per-model
effect of the rounding (2.8 % of rows for Mol-AE, 1.2 % for MolSpectra, 0.4 % for FMG, 0.1 % for
Uni-Mol, max|diff| = 5.1e-04 for GemNet-Q, 3.8e-05 for MACE, 2,846 of 3,000 sampled fingerprints
for E3FP).

Each script was run over all 52,391 conformers and compared with the published file of that model.
"Metrics" is the largest absolute difference over the six chirality metrics (ES-AUC, NN@1-Acc, SCI,
SCI_unsup, Hopkins, DBI) computed by evaluate chirality --distance euclidean --metric-version paper from the published file and from the regenerated file.

Model Bytes identical Per-row cosine max abs diff mean abs diff Metrics
E3FP yes, all 52,391 fingerprints — (identical bits) 0
GemNet-Q no min 0.99923; 52,390 of 52,391 rows ≥ 0.9999996 3.3e-04 1.6e-04
Uni-Mol no min 0.9999999995 1.18e-04 1.01e-06 1.42e-05
Mol-AE no min 0.9999997616 7.77e-04 5.72e-07 8.3e-05
MolSpectra no mean −0.18 5.5e-02
MACE no min 0.9999997634 4.90e-03 2.42e-08 8.9e-07
FMG no min 0.99999970 6.00e-04 6.60e-06 6.6e-05

The neural files are not byte-identical and are not expected to be: the forward passes run in
float32 on the GPU, where the reduction order depends on the batch size, the library build and the
device. Two runs of the same script on the same machine measure the size of that effect (FMG: up to
6e-4 per element; MACE, batch size 1 against 16: 1.4e-7 on a 128-conformer sample; GemNet, TF32 on
against off: 2.0e-3). The MolSpectra entry is the largest difference over the five metrics of
reproduce/table2_chirality/expected.csv; DBI was not recorded for that run.

MolSpectra publishes no checkpoint, so one has to be supplied by the caller; the script computes the
documented quantity (the per-atom scalar representation of the MolSpectra equivariant Transformer
summed over the atoms of the molecule), and the row above used the public denoised-pcqm4mv2.ckpt
that MolSpectra initialises from. The published
chirality/molspectra/sampled_mol_feature.npz is the artifact the paper's MolSpectra values were
computed from. baselines/README.md states this per model.

Documentation

  • README.md: a "Baseline embeddings" section linking baselines/ and the published embeddings.
  • docs/EMBEDDINGS.md: a pointer from each published file to the script that computes it, and the
    E3FP fingerprint parameters.
  • docs/METRICS.md, docs/metrics/{geometry,chirality,energy}.md, reproduce/*/README.md and the
    notes column of every expected.csv: a wording pass that states what each evaluator computes in
    paper and in v2, the molecule populations behind every mean, and the provenance of every
    reference value. No numeric value, tolerance or paper_value was changed.

Released data (already on the Hub, nothing to merge here)

Repository Contents
EscheWang/3dcs the four conformer configs chirality, rotation, traj_frames, traj_energies, loadable with load_dataset("EscheWang/3dcs", name=..., split="train")
EscheWang/3dcs-embeddings the 139 baseline embedding files used for the paper's evaluations (21.2 GB) with a manifest.csv (path, size, SHA-256, keys, shapes, provenance), the per-molecule metric outputs of the original runs, and the rMD17 split files

Verification

Tests and lint. pytest 217 passed on Python 3.11 with PYTHONPATH=src; ruff check and
ruff format --check on src/ tests/ examples/ reproduce/ baselines/ clean.
tests/test_baselines.py (86 tests) runs offline and without any model: the --dataset
specification table, reading a save_to_disk copy in offset order with --limit/--start, each
of the seven scripts accepting each input form and resolving the Hub form, the --verify-rows
selections and their error messages, subset comparison of vectors and of fingerprints, and that
every command in baselines/README.md uses flags its script has.

E3FP, end to end. baselines/e3fp/extract_chirality.py over the 52,391 chirality conformers
(214 s, --jobs 24, e3fp 1.2.7, rdkit 2026.03.6) reproduces the published
chirality/e3fp/sampled_chi.pkl bit for bit (identical 52391, tanimoto_min 1), and evaluating
the regenerated file gives ES-AUC 0.485935, NN@1-Acc 0.177939, SCI −0.012543, SCI_unsup 0.033825 —
equal at six decimals to reproduce/table2_chirality/expected.csv.

All seven from the released dataset, on one A100-80GB. Each script run from the Hugging Face
input in the environment its ENVIRONMENT.md builds, with --limit/--start and --verify
against the published file: E3FP (hfdisk:, 300 rows, 292 bit-identical, Tanimoto mean 0.9942),
MACE (hf:, 200 rows, cosine min 0.99999999), Uni-Mol (hfdisk:, 500 rows, cosine min 0.99994),
Mol-AE (hfdisk: and hf:, 2,000 and 64 rows, cosine mean 0.9999948), GemNet-Q (hfdisk:, 2,000
rows, cosine min 0.99999966), MolSpectra (hfdisk:, 256 rows, cosine mean −0.17 with the
substitute checkpoint, as documented), FMG (hfdisk: with --start 100 --limit 100, compared with
reference rows 100..199, cosine mean 0.9999998). baselines/fmg/requirements.txt was installed
into a fresh conda env (python 3.10, torch 2.0.0+cu118 first) and FMG run in it against the
published file (64 rows, cosine mean 0.9999999996).

Mol-AE and GemNet-Q input precision. Measured by running each of them twice over the first
2,000 conformers, once from the published mol_blocks and once from the full-precision molecules,
on the same machine in the same environment; the numbers are in their ENVIRONMENT.md.

Not re-run here: the full 52,391-conformer neural extractions, whose numbers in the table above
come from the runs that produced them.

Scope

  • The repository is the evaluation toolkit. Fine-tuning code and checkpoints (Tables 5, 8, 9) are
    not part of it; the rMD17 fine-tuning inputs correspond to the official split 01, included under
    splits/rmd17/.
  • The chirality set is what the extraction scripts cover. The GemNet script also reads the
    per-shard rotation inputs (see baselines/gemnet/ENVIRONMENT.md); the trajectory embeddings are
    published and are not regenerated here.

🤖 Generated with Claude Code

Xi Wang and others added 5 commits September 18, 2026 11:16
Rewrite the user-facing text of the release so that it states, for every
option and every published file, what the code computes and what the
artifact contains:

- README: replace the per-model status matrix with a coverage table of the
  published artifacts; point at docs/EMBEDDINGS.md for the per-file details.
- docs/METRICS.md, docs/metrics/*: describe `paper` and `v2` as the two sets
  of definitions the evaluators implement, keep the measured effect of each
  choice, and document the embedding indexing that --replicate-offset-drift
  reproduces.
- docs/EMBEDDINGS.md: list the format, key, dimension and E3FP parameters of
  each published embedding file.
- reproduce/: expected.csv keeps paper_value as printed and expected_value as
  the reference value of this release; the notes column now describes the
  metric version, the variant, the molecule population and the provenance of
  each reference value.
- CLI help and docstrings: `v2` is the alternative definition set.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
One script per baseline model (E3FP, GemNet-Q, Uni-Mol, Mol-AE, MolSpectra, MACE,
FMG) that turns the chirality conformers into the embedding matrix the evaluator
reads, in dataset row order and under the documented array key.

Each script takes the Hugging Face config or a pickle of RDKit molecules, prints
the versions and checksums of everything it used, and has a --verify flag that
compares the file it wrote with the published embedding of that model in
EscheWang/3dcs-embeddings (checksums, elementwise differences, per-row cosine).
baselines/common.py holds the input loading, the npz writing and the comparison.

No third-party code or weights are redistributed: every model directory carries an
ENVIRONMENT.md with the upstream repository and commit, the weight file with its
SHA-256 and where to download it, and the exact install commands.
baselines/README.md tabulates the output dimension, array key, hydrogen handling,
pooling and upstream dependency of each model, and the measured agreement between a
full 52,391-conformer run of each script and the published file.

tests/test_baselines.py covers --help of every script and the helpers in common.py
offline; baselines/ is added to the ruff paths of the Makefile and of CI.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Adds a "Baseline embeddings" section to the README and a pointer from the embedding
documentation to the per-model extraction scripts, and records that recomputing the
E3FP fingerprints with the documented parameters reproduces all 52,391 published
fingerprints bit for bit.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The MACE batch-size figure is from a 128-conformer sample, and the MolSpectra entry
is the largest difference over the five metrics of expected.csv.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@codacy-production

codacy-production Bot commented Sep 18, 2026

Copy link
Copy Markdown

Not up to standards ⛔

🔴 Issues 3 critical · 1 high · 30 medium · 66 minor

Alerts:
⚠ 100 issues (≤ 0 issues of at least minor severity)

Results:
100 new issues

Category Results
Documentation 48 minor
Security 10 minor
1 high
3 critical
8 medium
CodeStyle 8 minor
Complexity 22 medium

View in Codacy

🟢 Metrics 1052 complexity · 45 duplication

Metric Results
Complexity 1052
Duplication 45

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

ComDec and others added 3 commits September 18, 2026 17:03
…row subset

`baselines/common.py` resolves the input specification for all seven scripts
(`parse_dataset_spec`, `load_conformers`, `iter_conformers`): `hf:<repo>[:<config>]`,
`hfdisk:<dir>` or a plain `save_to_disk` directory, a bare Hub dataset id, a pickle of
RDKit molecules (a list or a dict of lists), and `lmdb:<file>` for a rotation shard. Each
script calls it through its own `load_molecules`, so the same `--dataset` value works
everywhere; the Mol-AE script reads the `mol_blocks` list of every dataset row, i.e. one
row per conformer in ascending `offset`. `--limit` and `--start` run a slice of the
conformers in every script.

`--verify` compares the rows a run produced. `parse_row_selection` resolves `--verify-rows`
into indices into the reference file: `prefix` (the default for a shorter output), `full`,
a `<start>:<stop>` slice, `<start>+`, or `@<file>` of 0-based indices; `--start N` implies
`N+`. The report names the selection, the number of rows compared and the reference rows
used, and the per-row cosine, allclose and difference statistics are computed over them.
For fingerprints the same selection applies to the Tanimoto comparison.

`tests/test_baselines.py` covers the specification table, reading a `save_to_disk` copy in
`offset` order with `--limit`/`--start`, every script accepting every input form and
resolving the Hub form, the row selections and their errors, subset comparison of vectors
and fingerprints, and that each command in `baselines/README.md` uses flags its script
has.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ile belongs to

`baselines/fmg/requirements.txt` carries `tqdm>=4.66.3`, the floor `datasets==4.0.0`
requires, so `pip install -r` resolves in one pass; verified in a fresh conda env
(python 3.10, torch 2.0.0+cu118 first, then the file), which gives torch 2.0.0+cu118,
numpy 1.26.4, rdkit 2024.9.6, einops 0.7.0, datasets 4.0.0 and tqdm 4.70.1 — the versions
`fmg/ENVIRONMENT.md` lists. Its header names `baselines/fmg/extract_chirality.py`, the
path of the script it builds the environment for.

The `datasets` / `huggingface_hub` lines of e3fp, mace, molae and molspectra name the
`--dataset` forms and `--verify` they are needed for, in the wording the other files use.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`fmg/ENVIRONMENT.md` gives the public Google Drive folder the upstream FMG README links
for the pre-trained weights, the file id of `model-120qm9_3rd_run.pt`, the `gdown` command
for the folder or the single file, and the sha256 to check the download against.
`molae/ENVIRONMENT.md` says that the Mol-AE Drive download is a ZIP archive named
`checkpoint_7_1000000.pt` (611,355,678 bytes) holding the 760,699,523-byte checkpoint,
gives the unzip command and both checksums, and notes that the file-id form of `gdown`
works on every version.

Every `ENVIRONMENT.md` now opens its "Input precision" section with the input the
published file and the numbers in `baselines/README.md` were computed from — the source
RDKit molecules, at full float precision — and with what the four-decimal `mol_blocks` of
the public dataset change. Mol-AE and GemNet-Q have that measurement: over the first 2,000
conformers, one machine and one environment, Mol-AE moves by `max|diff| = 4.4e-01`,
per-row cosine mean 0.9999948 and minimum 0.9921 with 2.8 % of rows below 1 - 1e-6;
GemNet-Q by `max|diff| = 5.1e-04`, per-row cosine at least 0.999999996 with no row below
1 - 1e-6.

`baselines/README.md` splits the agreement table into the run from the full-precision
molecules over all 52,391 conformers and the run from the published `mol_blocks` over the
first 2,000, lists the per-model effect of the rounding with a link to each
`ENVIRONMENT.md`, documents the shared `--dataset` table, `--limit`/`--start` and
`--verify-rows`, and carries one runnable command per model. The root `README.md` and
`docs/EMBEDDINGS.md` state the same input syntax and subset verification.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@ComDec
ComDec marked this pull request as ready for review September 18, 2026 09:31
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 18, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-18T09:35:49.634845Z 6aabd7e Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@ComDec
ComDec merged commit b2229ee into main Sep 18, 2026
5 of 6 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6aabd7e999

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +363 to +368
if not os.path.exists(lmdb_path):
mols = load_molecules(args.dataset, args.hf_split, args.hf_config, limit=args.limit, start=args.start)
n = build_lmdb(mols, lmdb_path)
print(f"[info] wrote {n} records to {lmdb_path}")
else:
print(f"[info] reusing existing LMDB {lmdb_path}")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Rebuild stale Mol-AE input databases

When --work-dir points to a directory used by an earlier run, the script silently reuses molae_input.lmdb without checking the current dataset, --start, or --limit. For example, a full run after a --limit 2000 smoke test will emit only the old 2,000 embeddings while otherwise succeeding, and default verification merely treats them as a valid prefix. Rebuild the LMDB for each invocation or persist and validate its source parameters before reuse.

Useful? React with 👍 / 👎.

Comment on lines +169 to +172
rec = _record_from_mol(mol, align, allowed, bond_order_map)
if rec is None:
skipped += 1
continue

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve FMG rows instead of skipping unsupported inputs

When a supported pickle or LMDB input contains a conformer with no atom in --atom-channels (or lacks a conformer), this branch drops it and shifts every subsequent embedding row. The evaluator assumes one output per input conformer, so the resulting metrics are assigned to the wrong molecules; this also violates the shared baseline contract that unfeaturizable rows cause an error rather than being skipped. Abort with the offending input index instead of continuing.

Useful? React with 👍 / 👎.

Comment on lines +21 to +25
# only for the Hugging Face --dataset forms (hf:<repo>[:<config>], hfdisk:<dir>, a
# save_to_disk directory or a bare Hub id)
# datasets
# only for --verify
# huggingface_hub

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Install dependencies required by the documented Mol-AE command

After following the Mol-AE installation instructions, the documented --dataset hf:EscheWang/3dcs:chirality ... --verify command fails before extraction because both datasets and huggingface_hub are commented out here, and the explicit install command in ENVIRONMENT.md also omits them. In particular, load_conformers immediately imports datasets; the environment guide even incorrectly says this dependency is included in this requirements file.

Useful? React with 👍 / 👎.

Sign up for free to 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