Skip to content

Train and ship a public-domain aroma descriptor model - #82

Merged
rvnminers-A-and-N merged 2 commits into
mainfrom
aroma-descriptor-model
Jul 4, 2026
Merged

rvnminers-A-and-N merged 2 commits into
mainfrom
aroma-descriptor-model

Conversation

@rvnminers-A-and-N

Copy link
Copy Markdown
Collaborator

Aroma is now predicted, not deferred. PubChem's 'Odor' annotation is public domain (HSDB/Haz-Map) for ~2,200 compounds β€” the clean source the earlier audit missed.

Pipeline: build_odor_notes.py --pubchem-all (corpus + SMILES) β†’ build_aroma_dataset.py (free text β†’ controlled multi-label descriptor vocabulary) β†’ train_aroma.py (RandomForest per descriptor, taste stack). 13 heads clear CV-AUROC β‰₯ 0.70 β€” ammoniacal 0.96, medicinal 0.96, almond 0.91, citrus 0.90, garlic 0.88, fishy 0.85, fruity/minty/camphor 0.84, ethereal 0.82, floral 0.80, pungent 0.80.

predict_aroma() predicts for any molecule (verified: ethyl hexanoate, not in corpus β†’ 'fruity' 0.81). /api/aroma + workbench show predicted descriptors with AUROC alongside documented odor + threshold.

Honest ceiling (AROMA.md): presence/absence, not intensity β€” a scored map still needs licensed/customer panel data.

Also: substitution cards now show common + IUPAC + SMILES.

The earlier audit missed a clean source: PubChem's 'Odor' annotation is public
domain (HSDB/Haz-Map) for ~2,200 compounds. New pipeline:
- build_odor_notes.py --pubchem-all now also captures SMILES (for fingerprints).
- build_aroma_dataset.py keyword-normalizes the free-text odor into a controlled
  multi-label descriptor vocabulary (presence/absence) -> aroma_train.parquet.
- train_aroma.py trains one RandomForest per descriptor on Morgan FP (the taste
  stack); keeps the 13 heads that clear CV-AUROC >= 0.70 (ammoniacal 0.96,
  medicinal 0.96, almond 0.91, citrus 0.90, garlic 0.88, fishy 0.85, fruity/minty/
  camphor 0.84, ethereal 0.82, floral 0.80, pungent 0.80).
- predict_aroma() surfaces predicted descriptors for ANY molecule; /api/aroma
  returns them alongside documented odor + threshold; the workbench shows them as
  bars with each head's AUROC.

Honest ceiling documented in AROMA.md: presence/absence, not intensity (free text
carries no scores); a scored map still needs licensed/customer panel data.

Also: substitution neighbor cards now show IUPAC (common + IUPAC + SMILES).
Signed-off-by: Austin L. <86896075+rvnminers-A-and-N@users.noreply.github.com>
predict_aroma now returns descriptors when aroma_models/ is present and an honest
'not trained here' marker otherwise (CI has no models). The test asserts both
branches instead of the old fixed 'see AROMA.md' placeholder string.

Signed-off-by: Austin L. <86896075+rvnminers-A-and-N@users.noreply.github.com>
@rvnminers-A-and-N
rvnminers-A-and-N merged commit 186d323 into main Jul 4, 2026
3 checks passed
@rvnminers-A-and-N
rvnminers-A-and-N deleted the aroma-descriptor-model branch July 4, 2026 18:08
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