Skip to content

feat(drug-discovery)!: featurize molecules as AttentiveFP does - #49

Merged
mahdi-shafiei merged 1 commit into
mainfrom
feat/attentivefp-featurization
Nov 8, 2026
Merged

mahdi-shafiei merged 1 commit into
mainfrom
feat/attentivefp-featurization

Conversation

@mahdi-shafiei

Copy link
Copy Markdown
Collaborator

Summary

Molecular graphs carry the AttentiveFP featurization (Xiong et al. 2019), as DGL-LifeSci's
AttentiveFPAtomFeaturizer and AttentiveFPBondFeaturizer (Apache-2.0) define it.

 smiles_to_graph / batch_smiles_to_graphs
-  atoms: element(12) degree 0-6(7) charge -2..2(5) hybridization(4) aromatic H 0-4(5)   = 34
-  bonds: type(4)                                                                         = 4
+  atoms: element(15 + unknown) degree 0-5(6) charge radicals hybridization(5 + unknown)
+         aromatic H 0-4(5) chiral-centre CIP R/S(2)                                      = 39
+  bonds: type(4) conjugated in-ring stereo none/any/Z/E(4)                               = 10
  • The value sets are tuples matched against RDKit enum names, so DEFAULT_ATOM_FEATURES and
    DEFAULT_BOND_FEATURES are derived without importing RDKit. Every operator default follows
    them (since fix(drug_discovery): operator input widths default to the featurizer's #48).
  • AtomFeatureConfig, DEFAULT_ATOM_CONFIG and ATOM_TYPES are removed; get_atom_features
    takes no configuration. This is a clean break with no alias.
  • Docs: the API and user-guide feature tables, the shapes, the config row naming the removed
    class, and the fingerprint example's shape output.

Evidence

Before: on main, test_attentivefp_features.py and the updated test_molecular_graphs.py
fail 19 and pass 6 (the padding, x64 and refusal tests).
After: 25 passed.

ethanol atoms == DGL-LifeSci's documented 'CCO' rows      hot [1,17,26,34] [1,18,26,33] [3,17,26,32]
ethanol bonds == [single, -, -, no stereo] both directions
N[C@@H](C)C(=O)O -> S, N[C@H](C)C(=O)O -> R, both chiral-centre
C/C=C/C -> E, C/C=C\C -> Z
the six BBBP stereoisomer pairs -> distinct graphs
[Na+].[Cl-] -> unknown element and hybridization, charge +1 / -1;  [CH3] -> 1 radical
SF6 sulfur (degree 6) -> degree block all zero, as in the reference

BBBP identical-graph groups (every split, the shipped builder, all groups stereo-only):

main this branch
SMILES as MolNet supplies it 6 groups, 12 molecules, 2 with conflicting labels 0
canonical SMILES 20 groups, 41 molecules, 4 with conflicting labels 0

Speed, RTX 4090, jax 0.11.1. Main and the branch alternate, 2 rounds each:

main branch
Adam step, nnx.value_and_grad through nnx.vmap, 64 padded BBBP molecules: MolecularPropertyPredictor 41.2, 42.9 ms 46.8, 42.6 ms
same step, CircularFingerprint 15.5, 16.7 ms 15.7, 15.7 ms
same step, AttentiveFP 11.0, 10.8 ms 9.5, 10.4 ms
host batch_smiles_to_graphs, 256 BBBP molecules, CPU backend, best of 15 87.3, 85.3 ms 126.8, 136.6 ms

The training steps are within run-to-run noise at these shapes. The host cost per molecule is
about the same (_host_graph over 256 molecules: 59.6 and 61.3 ms against 66.7 and 71.0 ms). The
batch is slower because its dense (B, N, N, F_bond) edge array grows from 41 MB to 102 MB with
the bond width: the NumPy fill goes from 4.4 to about 12 ms, the transfer to the GPU from about 5
to 13 ms. The cost belongs to the dense layout; the padding change that follows works on that
layout.

Gate: tests/operators/drug_discovery and tests/operators/test_drug_discovery.py 146 passed;
the MolNet and DTI benchmark tests and the experimental-boundary test 21 passed; pre-commit
over all files, ruff, ruff format, lint-imports (6 kept), pyright on the changed files, and
mkdocs build --clean --strict all pass.

Merge Danger

Door: two-way

A revert restores the 34 and 4 widths. Nothing persists graphs or trained weights at these
widths in the repository.

Blast Radius: featurization

Every graph, and every operator built with default widths, changes width; models trained on the
old graphs need retraining. Code that passed a config to get_atom_features, or imported
AtomFeatureConfig, DEFAULT_ATOM_CONFIG or ATOM_TYPES, breaks. Within the repository, the
benchmarks and scripts refer to the widths by symbol only. The random-init numbers printed on
the example pages were already stale on main (the fingerprint page shows 0.4735 where main
computes 0.4362), because scripts/generate_example_outputs.py fails at import on the installed
matplotlib (plt.BarContainer). That defect is left for the docs change.

smiles_to_graph and batch_smiles_to_graphs now produce the AttentiveFP
featurization (Xiong et al. 2019) as DGL-LifeSci's
AttentiveFPAtomFeaturizer and AttentiveFPBondFeaturizer define it: 39
atom features and 10 bond features, against 34 and 4. The graphs gain
chirality, CIP labels, radical electrons, conjugation, ring membership
and bond stereo, so stereoisomers no longer share one graph. On BBBP as
MolNet supplies it, 12 molecules in 6 groups did, 2 of the groups with
conflicting labels; none do now.

The value sets are tuples matched against RDKit enum names, so the
widths are known without importing RDKit, and DEFAULT_ATOM_FEATURES and
DEFAULT_BOND_FEATURES are derived from them. AtomFeatureConfig,
DEFAULT_ATOM_CONFIG and ATOM_TYPES are removed, and get_atom_features
takes no configuration. The ethanol test vectors are the reference's
documented output.

The API and user-guide pages describe the new features, and their
shapes, the removed config row and the example output follow.
@mahdi-shafiei
mahdi-shafiei marked this pull request as ready for review November 8, 2026 17:50
@mahdi-shafiei
mahdi-shafiei merged commit f4bc83f into main Nov 8, 2026
14 checks passed
@mahdi-shafiei
mahdi-shafiei deleted the feat/attentivefp-featurization branch November 8, 2026 17:50
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