pino-source-code / README.md
Matthew Ford
docs: final GPU readout in README + model card; add POM relation section
626674a
|
Raw
History Blame Contribute Delete
9.61 kB
---
title: PINO
emoji: 🧪
colorFrom: purple
colorTo: blue
sdk: docker
pinned: false
license: mit
---
# PINO — Physics-Informed Neural Olfaction
End-to-end fragrance intelligence: from molecular structure and Dortmund-UNIFAC thermodynamics to a multi-task transformer that predicts time-resolved odor trajectories.
## What it does
PINO combines a first-principles evaporation engine with a Physics-Informed Mixture Transformer (PIMT):
1. **Thermodynamic simulation** — Dortmund-Modified UNIFAC activity coefficients, stiff ODE evaporation, and headspace concentration profiles.
2. **Empirical bootstrap dataset** — 5,600+ real-world records (single-molecule controls + multi-component blends), all cut with a commercial 15% concentrate / 85% ethanol solvent envelope and padded to a fixed 49-step temporal grid.
3. **Multi-task transformer** — predicts objective odor trajectories, seasonality, gender/wearability profiles, and continuous alignment to the Principal Odor Map using an adaptive loss balancer.
4. **Formula generation** — CMA-ES-based inverse-design composer that evolves blends against a sensory brief while respecting IFRA limits.
## Quick start
```bash
# Install
python -m venv .venv
source .venv/bin/activate
pip install -e .
# Run tests (112 passed, 4 skipped)
python -m pytest tests/ -q
# Train the two-arm representation A/B locally (Morgan vs genuine OpenPOM)
python src/pino/train.py --structural-source morgan --epochs 6 --checkpoint-name pimt_ab_morgan.pt
python src/pino/train.py --structural-source openpom_256 --epochs 6 --checkpoint-name pimt_ab_openpom.pt
# Single preregistered readout on the frozen benchmarks (once per arm)
python scripts/evaluate_frozen_benchmarks.py --checkpoint models/pimt_ab_openpom.pt \
--structural-source openpom_256 --arm-label openpom_256 --output artifacts/frozen_eval_openpom_256.json
# Paper artifacts: canonical data macros + figures (from on-disk artifacts only)
python scripts/export_paper_data.py # -> artifacts/paper_data.yaml
python scripts/generate_paper_figures.py # -> figures/*.pdf
```
GPU training runs on Hugging Face Jobs against the published
`mattbitzesty/pino-source-code` model repo (`scripts/hf_gpu_ab_job.py`,
`scripts/hf_stats_job.py`); the legacy substantivity-GBM path is
`scripts/pimt_v9_train_publish.py`.
## Repository layout
| Path | Purpose |
|------|---------|
| `src/pino/thermo/` | VLE, evaporation, IFRA, natural-oil profiles, OAV semantics |
| `src/pino/pimt_model.py` | `FragranceTrajectoryDataset` and `PhysicsInformedMixtureTransformer` |
| `src/pino/train.py` | Training loop with `AdaptiveLossBalancer` and molecule-disjoint split |
| `src/pino/heads.py` | PIMT output heads: objective, subjective, continuous alignment |
| `src/pino/optimizer.py` / `cli.py` | Generative inverse-design composer |
| `scripts/` | Dataset generation, HF job entrypoint, diagnostic scripts |
| `data/` | Registry, empirical dataset, literature formulas, Pyrfume annotations |
| `tests/` | Pytest suite for the thermodynamic engine |
## Key design decisions
- **Natural oils are expanded** into pure constituent CASes before VLE so the engine runs real Dortmund-UNIFAC instead of falling back to Raoult's law.
- **All formulas are treated as 15% perfume oil concentrate + 85% ethanol**, mirroring real commercial fragrance products.
- **Molecule-disjoint train/validation split** prevents data leakage: if a molecule appears in a training formula, it never appears in validation.
- **Pure single-molecule controls follow the same molecule-disjoint split** as blends, so held-out compounds are not reintroduced through anchor records.
- **Adaptive loss balancing** (4 tasks: objective MSE, seasonality, wearability, continuous alignment) removes hand-tuned loss coefficients.
- **Continuous alignment head** replaces the legacy InfoNCE contrastive head with dense cosine similarity on the Principal Odor Map.
## Open design decisions
- **Representation (RESOLVED by ablation, 2026-07-17):** genuine 256-dim OpenPOM v1.0.0 beats the 138-dim Morgan fallback on every frozen predictive task (substantivity, odor-threshold, descriptor). See `artifacts/representation_ablation/`. Training now supports both via `--structural-source morgan|openpom_256` (input dim 151 vs 269); a two-arm A/B trains each once and evaluates on the frozen benchmarks head-to-head.
- **Objective target space (OPEN):** the curated 138-dim Pyrfume single-label basis vs the full molequles multi-tag vocabulary (575 tags at ≥10 occurrences, ~10 tags/CAS, mined from Arctander/Goodscents/TGSC monograph text). The richer space may be more insightful but changes the objective head, loss, and metrics. The 575-dim multi-hot target matrix is built (`data/molequles_tag_matrix.json`) and held as an ablation arm; attribution is cleaner if it lands after the representation A/B is read out.
- **Prospective formula benchmark:** 40 in-silico preregistered formulas from a 51-material hobbyist palette (option held open for a community physical-compounding arm). Intended family-profile labels are sequestered (`labels.sequestered.json`, `access=evaluation_only`) and forbidden in training/model selection.
## Representation A/B (two-arm, single readout)
Trained and evaluated **once per arm** on the frozen benchmarks. Authoritative
run: **20 epochs on T4 GPU** against the expanded **20-triplet** benchmark.
Results live in `mattbitzesty/pino-pimt-representation-ab` (public model repo).
| Metric | Morgan (151-d) | Genuine OpenPOM (269-d) |
|---|---|---|
| Final validation total loss (best epoch) | 0.3959 | **0.3600** |
| Substitution triplets (n=20, chance=0.5) | 0.30 | **0.45** |
| Prospective family cosine (n=40) | 0.5378 | **0.6121** |
- **Genuine OpenPOM ahead on all three metrics.** Largest margin on prospective
family-profile agreement (+0.074), most pronounced in citrus-cologne (0.56 vs
0.26, where Morgan collapses). Honest caveat: both arms are below chance on
triplets (0.30/0.45) — a reported negative, not a win.
- **Model-free ablation** (`artifacts/representation_ablation/`): OpenPOM beats
Morgan on every frozen predictive task (5-fold paired bootstrap CIs) — the
statistically strongest case.
- **CPU run (6 epochs, n=8)** was directional only and is superseded by the GPU run.
- Triplet benchmark expanded 8 → 20 by mining `material_profiles` (molequles) for
trade-name → SMILES in `scripts/build_substitution_triplets.py`, resolving
proprietary trade materials (Isobutavan, Canthoxal, Neofolione, Indocolore,
Centifolether, Romandolide, …). All 12 new triplets carry authoritative
Fraterworks preference provenance + verified structural discordance.
## Paper package
The paper build pulls facts from a single canonical source and renders figures
from on-disk artifacts — no retraining, no HF calls:
- `scripts/export_paper_data.py``artifacts/paper_data.yaml`: 49 lowerCamel
`data_macros` for the autopaper pipeline (builder prefixes `D`, digits→words;
e.g. `pomThreshRho``\DPomThreshRho`). Sourced verbatim from the frozen
ablation, the v10_line_drawn substantivity GBM, and the A/B frozen readout,
plus dataset curation stats and honest negatives.
- `scripts/generate_paper_figures.py``figures/*.pdf`: (a) ablation grouped
bars + 95% CI, (b) UMAP of genuine OpenPOM embeddings by odor family,
(c) objective-head trajectory pred-vs-target (sparsity annotated).
## Training-readiness gate
Training is gated by `scripts/freeze_representation_validation.py`, which inspects on-disk artifacts and reports `READY_FOR_TRAINING` only when all five checks pass: genuine-POM asset present, representation ablation complete, ≥1 discordant substitution triplet admitted, 30–50 prospective formulas frozen, and prospective labels sequestered. Current status: `artifacts/training_readiness.json`.
## Telemetry to verify on first HF training run
- **Step 1:** `AdaptiveLossBalancer` weights should be uniform (~0.25 each).
- **Step 10:** weights should shift dynamically as tasks progress at different rates.
- **Alignment loss:** starts near 1.0 and trends downward as the backbone organizes odor descriptors.
- **Validation loss:** reflects formulas whose active molecules are absent from training; mixed-boundary formulas are excluded to preserve isolation.
## Relation to the Principal Odor Map (Lee et al., Science 2023)
PINO does not compete with Google's Principal Odor Map — it **builds on it** and
extends it to a harder problem:
| | POM (Lee et al. 2023) | PINO |
|---|---|---|
| Object | single molecule | multi-component blend |
| Output | static odor descriptors | time-resolved odor trajectory (49 steps) |
| Physics | none | Dortmund-UNIFAC evaporation |
| Validation | human panel, 400 novel odorants | frozen in-silico benchmarks |
| Human validation | yes (n=15 panel) | not yet (future work) |
| Formulation / IFRA | no | yes |
POM validated odor *description* for single molecules against a trained human
panel. PINO consumes that map as an input representation (the OpenPOM arm) and
shows, in a controlled two-arm A/B plus a model-free ablation, that the perceptual
representation is also the right foundation for **blend-trajectory** modeling —
a task POM did not address. The controlled comparison (paired bootstrap CIs +
identical-corpus two-arm training) is methodologically tighter than POM's
transfer-study baselines. The acknowledged gap vs POM is human-panel prospective
validation; PINO's prospective eval is in-silico against sequestered intended
profiles.
## License
MIT — see `LICENSE`.