Flavor = taste + aroma. The taste side ships and is clean (sweet/bitter/umami ~0.95 AUROC + intensity + sour/salty). The aroma side is deliberately deferred β not for lack of effort, but because the public, commercially-clean data is insufficient. This documents the evaluation, so the decision is legible.
A model mapping a molecule's structure β odor descriptors (sweet, floral,
woodyβ¦). The state of the art is the Principal Odor Map (Lee et al., Science
2023; Google/Osmo), reimplemented open-source as OpenPOM (BioMachineLearning/ openpom, MIT) β a message-passing GNN trained on ~5,000 expert-labeled molecules
(the GS-LF dataset).
OpenPOM's code is MIT, but its training data is restricted. A full audit of the
Pyrfume catalogue (see DATA-SOURCES.md) found that every rich
odor-descriptor dataset is proprietary or NonCommercial β Leffingwell, GoodScents,
Arctander, Flavornet (Β©Datu), FlavorDB / FooDB (NC), OlfactionBase ("all rights
reserved"), AromaDB (CSIR), Dravnieks (ASTM Β©), sharma_2021 (ACS Β©), snitz_2019
(CC-BY-NC). The only commercially-clean odor-descriptor set is keller_2016
(Keller & Vosshall 2016, BMC Neuroscience, CC-BY-4.0; ~480 molecules, 20 descriptors).
Yes for the engine, no for the fuel it ships with β and that distinction is the whole answer:
| Component | License | Commercial use |
|---|---|---|
| OpenPOM code (the GNN / message-passing model) | MIT | β Yes β use the architecture freely |
Bundled data (curated_GS_LF_merged_4983.csv) |
GS-LF = Leffingwell/GoodScents, NonCommercial | β No β the MIT repo does not relicense third-party data it doesn't own (same rule as Pyrfume/SweetenersDB: a repo's license only covers what the uploader authored) |
| Any pretrained weights trained on that data | derivative of NonCommercial data | β Murky/risky β a model trained on NC data and used commercially is legally unsettled; not something to bet a product on |
So OpenPOM does not "come with commercially-allowed data" β it comes with NonCommercial data. The code was never the blocker; the data always was.
What this means for us: we keep only OpenPOM's code β the MIT architecture and training recipe β and we never use its GS-LF-trained weights. When clean fuel exists we train our own weights from scratch on it: either a licensed copy (Leffingwell PMP 2001, ~$2,775, ideally licensed by the customer and run on-prem) or the customer's own odor data. There is no shortcut around this β a usable aroma model must be our own, trained on data we can legally use. That's exactly the taste pipeline over again: structures + labels in, model out. (For a small set, plain RandomForest suffices β see the taste heads; OpenPOM's GNN only earns its keep once the labeled set is large, thousands of expert-labeled molecules like PMP 2001 β so "keep OpenPOM" really means keep the option of its architecture, not any pre-baked model.) The only requirements: the labels are expert sensory descriptors (GC-MS identifies the molecules but carries no smell labels) and the data is ours/licensed.
We aggregated keller_2016 (training/build_aroma_dataset.py)
and trained one RandomForest regressor per descriptor on 2048-bit Morgan fingerprints
(training/train_aroma.py), scored by honest 5-fold
cross-validation (400 trees):
| descriptor | CV-RΒ² | descriptor | CV-RΒ² | descriptor | CV-RΒ² | descriptor | CV-RΒ² |
|---|---|---|---|---|---|---|---|
| acid | β0.24 | cold | β0.19 | fruit | β0.05 | sour | β0.05 |
| ammonia | β0.15 | decayed | β0.20 | garlic | β0.12 | spices | β0.12 |
| bakery | β0.22 | edible | β0.19 | grass | β0.45 | sweaty | +0.03 |
| burnt | β0.13 | fish | β0.04 | musky | β0.23 | sweet | β0.05 |
| chemical | β0.10 | flower | β0.12 | warm | β0.28 | wood | β0.08 |
All 20 descriptors scored CV-RΒ² β€ 0 (range β0.45 to +0.03) β every model is worse than predicting the mean. 0/20 usable heads.
keller_2016 is naive-subject data: random volunteers rating unfamiliar
molecules on a 0β100 scale. People can't reliably name what a molecule smells like,
so the labels are noise (the per-descriptor means compress to ~22β30 for nearly every
molecule). The learnable odor data uses expert labels β which is exactly the
data that's restricted. That is the structural reason the entire field trains on
GS-LF, and why a clean public aroma model isn't currently possible.
We do not ship a negative-RΒ² model β it would output confident, wrong smells, and
a flavor chemist would catch it instantly (worse than nothing). predict_aroma()
returns an honest "not available" marker, and we lead with the taste engine.
We carry no dead scaffold β the architecture decision lives here, not in an
unrunnable stub. OpenPOM is the chosen architecture (MIT, re-addable in an
afternoon) for large sets; RandomForest suffices for small ones, exactly as the
taste heads and the train_aroma.py evaluation already demonstrate. We build the
training script when clean fuel exists:
- License PMP 2001 (~$2,775, Leffingwell & Associates) β re-curate β train.
- A customer's own odor data (the paid pilot) β train on-prem.
- A future open expert-labeled dataset, if one emerges.
Until then: aroma comes with your data β which is on-thesis (public data proves the method; the customer's data unlocks the rest).