Skip to content
incrediblecrabPublic

About

Ingredient embedding models evaluated against a popularity baseline on 4.65M recipes

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

59 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

llmmm

llmmm trains ingredient predictors and recipe-ranking models, with public weights at llmmm-recipes, a browser demo at llmmm-recipes-demo, and the public ingredient dataset at llmmm-recipe-ingredients. The released model has weights and biases trained from scratch on canonical recipe ingredient sets; no pretrained model initialized it.

Objective: build reproducible ingredient-completion and recipe-ranking experiments, publish only authorized aggregate artifacts, and keep the provenance and limits of each release auditable.

Inputs: tracked experiment declarations and receipts, an authorized private recipe corpus or recovery bundle for training, public Hugging Face releases for inspection, and the Python, Make and browser tooling under model/.

Files:

  • model/: training, evaluation, recovery tooling, browser demo source and recorded results
  • prior-study/: replication work, source readers and normalization dependencies
  • raw-data/: source inventory and provenance; source bytes stay outside git
  • paper/: the Epicure paper copy used by the original study

Try it: cd model && make check-code runs the local code checks that do not need the private data bundle.

Public recipe demo

Try the demo | Download the ingredient dataset

The demo searches all 4,653,430 canonical ingredient records and runs the published supervised ranker in your browser. Each result card shows the recipe's recorded title and original ingredient lines, with a link for the cooking steps where one opens: the recorded page, or its Internet Archive copy for sites whose own pages failed a September 23 or 24, 2026 check that their archived copies passed. It needs no private recipe database, login or API key. Choose pantry ingredients, source-time and missing-item limits, required/excluded ingredients and reported servings; switch to the simple baseline to compare the ordering. The example pantries show precomputed cards at once. An optional 36.1 MiB index download enables local search; recipe-text and link files load as needed. Hosting uses a free Static Space, not paid inference hardware. Pantry inputs are not sent to a server or stored between visits.

The index contains normalized ingredient names, source-reported times and servings, source identifiers, recorded source URLs, card links, and each record's recorded title and ingredient lines with the amounts the source recorded. 4,503,160 records have titles and 4,503,161 have ingredient lines. It does not copy cooking instructions, descriptions or images. 2,292,411 records have a recorded source URL; 2,361,019 do not. 1,918,825 have a card link: 1,652,643 open the recorded page over HTTPS and 266,182 open the Internet Archive's copy. The other 373,586 come from sites that passed neither check and show no link. The link checks record each site's rule and sampled links. Of 300 card links drawn at random after the rules were fixed, 298 opened their recipe (Wilson 95% interval 97.6–99.8%). An earlier draw scored 271 of 300, mostly because www.povarenok.ru was failing; that build was not published, and povarenok cards now open 2025 archive copies. The link-only filter is on by default. Disable it to include records without a link.

Every record is checked against the hard constraints. At most 2,000 feasible records, selected by the baseline, receive learned scores. This is not a guaranteed global learned top-k or a collection of unique, complete cooking recipes. Unknown metadata cannot pass a corresponding constraint. The private finder's recovery benchmark below does not evaluate this browser retrieval pipeline.

The release receipt pins the public dataset, Space, model and source revisions. It records an independent comparison of every exported row, 36,707,624 ingredient slots and all 1,918,825 card links, a byte-for-byte check of all 2,273 recipe-text shards, anonymous browser operation, and the dataset viewer's complete record count. Every title and ingredient line was first recomputed from the private catalog in the index verification. The model-card update changed documentation only; weights and existing model tags were preserved. Earlier releases stay pinned by their receipts and tags: the recipe-card release by dataset tag v0.2.0 and Space tag v0.3.0-recipe-cards, and the ingredient-only release by dataset tag v0.1.0 and Space tag v0.2.0-ingredient-search. Build and publication instructions include rebuilding from the public index without the private corpus.

Deleted sample dataset

The earlier twelve-recipe Wikibooks sample dataset, incrediblecrab/llmmm-recipe-sample, was deleted from Hugging Face on September 24, 2026 at the owner's request; the deletion receipt records its final commit, tags and files and the checks showing it is gone. The ingredient dataset is the project's single source of truth and only public dataset. The sample's recipes, CC BY-SA 4.0 attribution and source revisions stay tracked in model/demo_data for local previews; before deletion, their Git blob hashes matched the dataset's three content files. Its original release receipt and the Space tag v0.1.0-sample record the earlier demonstration.

Evaluated results

This section is generated from recorded artifacts. Run make -C model status to inspect it and model/.venv/bin/python model/scripts/project_status.py --write to refresh it. make -C model docs rejects edits or stale values in this section.

Corpus v2: 4,653,430 recipes, 36,707,624 ingredient slots, 1,790 ingredients, 29 source groups.

Published benchmark: all-v2, 16 recorded runs, recipe-holdout, 20,000 completion instances. Popularity baseline: 0.3650.

All score columns are recall@10. Native is the full predictor where available; a dash means no separate native scorer. Rows retain the published ordering: native where available, otherwise raw vectors.

Model Raw vectors Centered vectors Native predictor
masked-set 0.1229 0.2132 0.6178
ease 0.1422 0.1645 0.5872
svd-ppmi 0.4505 0.4493 -
concat 0.4446 0.4446 -
residual 0.4235 0.4235 -
sgns-core 0.4065 0.3970 -
sgns-cooc 0.3885 0.3871 -
text-aligned 0.3216 0.3038 -
glove 0.2211 0.4928 -
lightgcn 0.1837 0.2060 -
text-embed 0.1077 0.1123 -
sgc 0.0777 0.0939 -
ials 0.0426 0.0558 -
chem-svd 0.0152 0.0088 -
sgns-chem 0.0149 0.0201 -
item2vec 0.0123 0.1483 -

Evaluated training cohort: train-v2-20260909 (2/2 runs scored).

Model Seed Native recall@10 Lift over popularity Training time
ease 42 0.5872 +0.2222 1.3s
masked-set 42 0.6150 +0.2500 332.7s

masked-set settings: 3 epochs, sampling cap 600,000 recipes, maximum training recipe length 32.

Sources: corpus marker, corpus accounting, benchmark runs, current experiment.

Recall@10 measures whether a hidden ingredient appears in the top ten predictions. It does not measure cooking quality, food safety or generalization to new sources.

The full-partition run removed the recipe-sampling cap while keeping the architecture, seed and epoch count fixed. Its evaluation records the paired comparison and export verification. The manifest counts recipes that passed the length filter: 3,145,078 records. Its weights remain available as v0.2.0-preview, with the original upload record.

llmmm-recipes: all-record checkpoint

Training completed on all 4,653,430 canonical recipe records. The all-record declaration used no sampling cap or length exclusion. Each of three epochs processed every record exactly once: 13,960,290 recipe presentations and 110,122,872 ingredient-slot presentations in total. Records with one to 98 ingredients were included intact. These are record counts, not a claim of unique recipe content.

The completion verification checks the saved per-epoch counters against the checksum-verified corpus and restores the complete predictor. The export evidence records identical state tensors and exact logits on 192 synthetic reload comparisons. This verifies the package, not its prediction quality.

The current public release is llmmm-recipes, v0.4.0-recipe-search. It is public and ungated. The ingredient predictor's weights remain unchanged from v0.3.0-all-recipes; this release adds separate recipe-ranking policies and the finder described below. The release receipt records preserved native artifact hashes and older tags, anonymous installation of the pinned SDK source, and isolated inference before and after upload. The earlier access release records when the ingredient checkpoint became public. No training-corpus recipe text was uploaded to the model repository. Since October 15, 2026, the model (v0.4.2-cc-by-nc), the dataset (v0.3.1-cc-by-nc) and the demo (v0.4.1-cc-by-nc) are released under CC BY-NC 4.0, for non-commercial use such as education and research. Those commits changed only the cards, LICENSE files, the model's two release policies and the dataset and demo manifests' records of those files, as the model license receipt and dataset and demo license receipt record. Copies taken under the earlier v0.4.1-mit tag (receipt) keep the MIT License.

The old holdout is part of this training data, so the production checkpoint has no held-out score from this corpus and does not enter the scored leaderboard. The earlier evaluated checkpoint improved recall@10 from 61.5% to 65.5% on 20,000 completion cases, as recorded in its comparison. Those scores do not apply to these weights. More training records alone do not establish better predictions.

Finding recipes

Give the finder ingredients and a time limit. It retrieves matching records from a local recipe catalog, with source links, source-reported times, matched and missing canonical ingredients, and the original instructions. Required and excluded ingredients, missing-item limits, reported servings and source language are enforced before ranking. A learned score cannot relax those constraints.

The private catalog contains 4,653,430 records. Only 681,275 have known source total times; unknown times do not pass a time limit. Prep-plus-cook sums are kept separately and never substituted. The catalog report records coverage and the distinction between stored text and non-whitespace instructions. Nonempty fields are not a cooking-quality certificate.

Search requires the authorized local catalog, its derived metadata index, and the canonical recipe_ids.npz ingredient corpus. The core recovery bundle supplies the ingredient corpus; the catalog and metadata index must be rebuilt from authorized sources. None of these data files is included in the public model. The finder checks their hashes and filters numeric metadata and ingredient sets before fetching recipe text. Retrieval remains bounded and reports when a shortlist or scan limit is reached.

With the canonical corpus and authorized raw sources restored, make -C model text builds the immutable text-v2 index and make -C model recipe-catalog builds the catalog and metadata cache. For a catalog already restored without its cache, use make -C model recipe-metadata instead. These commands refuse to overwrite existing outputs. Reported search measurements are bound to the evaluated catalog; changed source metadata requires a new evaluation.

cd model
.venv/bin/im find \
  --ingredients chicken rice broccoli \
  --must-use chicken --max-total-minutes 30 --max-missing 2 \
  --catalog data/recipes/recipe_search.sqlite \
  --corpus data/recipes/recipe_ids.npz \
  --revision v0.4.0-recipe-search

Ingredient matching uses the canonical vocabulary, not every component of a source ingredient. Review the raw ingredient list and warnings before cooking. Exclusions are not an allergen-safety assessment. Missing quantity units are not invented, inconsistent name/quantity arrays are not paired, and serving counts do not scale quantities or cooking time. Ranking scores are not probabilities.

Ranking training

The ranker has 705 parameters, initialized from scratch. Supervised listwise training was followed by sampled-action REINFORCE with an entropy term and a KL penalty to the supervised policy. Each stage processed every canonical record once: 9,306,860 training queries, 72,710 optimizer steps, and 18,613,720 sampled reinforcement actions. The verification record checks the saved per-row counts against the checksum-verified corpus.

The reward is recovery of a source recipe's canonical ingredient set, not human preference. Pantry hashes separate training, validation and test queries; recipes and duplicate families are not held out. Sampled candidate lists deliberately include the feasible source recipe.

Ranker Source-set recovery at rank 1
Heuristic 95.62%
Supervised 97.23%
REINFORCE 97.34%

These are 2,852 nontrivial sampled test shortlists, not full-catalog retrieval results. Validation selected the supervised policy. REINFORCE did not establish an additional validation gain, so its slightly higher test point estimate is not a reason to switch policies.

Live search evaluation

The live evaluation used 200 validation and 200 test pantry queries, with no source recipe inserted into retrieval. Half included a source-total-time limit. Supervised ranking was selected on validation before any test scoring.

Ranker Test source-set recovery in the top five
Heuristic 75.5%
Supervised 83.5%
REINFORCE 84.0%

The supervised improvement over the heuristic was 8.0 percentage points, with a paired query-bootstrap 95% interval of 4.5 to 12.0 points. Its test requests took 0.43 seconds median and 2.05 seconds at p95, excluding initialization. It had no timeouts, empty results or constraint violations in either partition. REINFORCE did not establish an extra validation gain and had one validation timeout; the cause was not isolated.

The source set reached the test shortlist on 99% of queries, but 162 of 200 test queries reached a retrieval budget. These are synthetic queries over known recipes, not evidence of taste, food safety or unseen-recipe generalization.

The supervised policy is the public default. Both trained policies are included in the Hugging Face release, with checkpoint-bound export evidence. The existing ingredient checkpoint is unchanged. To reproduce ranking training and verify its coverage:

make setup-hf
make train-recipe-policy RECIPE_RUN=training/new-recipe-ranking-run
make verify-recipe-policy RECIPE_RUN=training/new-recipe-ranking-run \
  RECIPE_TRAINING_REPORT=results/new-recipe-ranking-run.json

Training outputs and verification records are immutable. Choose fresh output paths for another run; no GitHub Actions or hosted training services are used.

Generation and evaluation work

The ingredient checkpoint predicts names; the finder retrieves existing recipes. Writing new recipes is separate, unfinished work.

The external completion diagnostic compares saved native predictors with pinned Epicure Cooc/Core weights and RecipeBERT ingredient-name representations. It reports raw vectors, centered vectors and native predictions separately, with paired intervals, subgroup results and provenance.

The comparison has limits: source overlap is known or possible, the row split does not separate duplicate recipe families, and the historical popularity control uses full-corpus frequencies. The RecipeBERT adapter embeds ingredient names; it does not evaluate RecipeBERT's original masked-language task. T5 is pinned but has not been compared.

The original text audit exposed a Food.com quantity column being used in place of ingredient names. The rebuilt text-v2 audit confirms that names are recovered. Separate quantities are retained without inventing missing units; lists with different lengths are explicitly flagged and must not be paired.

The new index is recipe_text_v2.parquet; the original recipe_text.parquet was deleted on September 28, 2026 to reclaim disk space, and its audit remains in the linked results file. Every rebuilt row was checked against the canonical ingredient corpus. Failed builds do not publish partial indexes, and existing indexes are not overwritten. The canonical ingredient sets used by the predictors have not changed.

The next quality comparison needs new test recipes, with duplicate families and source overlap accounted for. A future generator should be compared with T5 under equal output budgets, checking ingredient use, quantities, instructions and blinded quality judgments.

cd model
make setup-hf
make hf-compare
make generation-audit  # requires the optional full-text index
make train-all-recipes
make verify-all-recipes
make export-all-recipes PRODUCTION_EXPORT=/private/unused/output-directory

Baseline downloads contain public model assets only; inference stays local. hf-compare does not download T5 or call a hosted model. None of these commands publishes a model or runs GitHub Actions.

The native-only exporter and publisher admit seven model-package files, including the CC BY-NC 4.0 LICENSE that licensing.py defines for every Hugging Face release, and refuse unexpected remote additions. The latest license change, which left every weight, data and application file untouched, used scripts/publish_license_update.py, a dry run unless given --publish; scripts/publish_model_license.py made the earlier MIT release. Recipe-search releases use scripts/export_recipe_search.py and scripts/publish_recipe_search.py instead; they preserve the existing native artifacts while adding only ranking weights, configuration and aggregate evidence.

For a recipe-search release, complete make evaluate-recipe-search, commit and push the tested source, then run make export-recipe-search. Publication is a separate, explicit command: python scripts/publish_recipe_search.py --public --folder /private/export-directory. The publisher checks anonymously installable pinned source, isolated inference, remote hashes and preserved tags. Catalogs, raw text, private query cases and coverage arrays are excluded. Existing outputs, version tags and publication receipts are not overwritten.

MLX support for experiments with the pinned Qwen base is the optional generation extra (.venv/bin/pip install -e '.[generation]' from model/), installed alongside the native PyTorch environment. The base is downloaded; culinary fine-tuning and generation evaluation have not run.

One source of truth

Question Authority
Which benchmark, evaluated training cohort and default embedding? model/workspace.json
Which all-record production training and coverage? Declaration and completion verification
Which recipe-ranking training, coverage and sampled evaluation? Verified training record
Which source metadata supports recipe-search constraints? Catalog coverage and provenance
Which public ingredient facts, recipe-card text and browser implementation? Full dataset and live-release receipt, index and card-text verification, browser implementation and publication scope
Which complete sample recipes and attribution? Sample card and source revisions/mappings, tracked for local previews; the sample's Hub dataset was deleted (deletion receipt)
Which corpus and normalizer? model/data/GENERATION.json, verified against the corpus SHA-256 before current training
What actually ran and how did it score? Each run's manifest.json and metrics.json under model/results/runs/
Which private artifact bytes restore this workspace? model/artifacts.lock.json, generated by make snapshot
Which normalization fixes were used? The tracked code and model/data/aliases/
Where did source corpora come from? raw-data/README.md and raw-data/MANIFEST.md
Which external model revisions and exact assets were compared? model/hf_baselines.lock.json and the diagnostic's code/weight fingerprints
Which model version and model card are on Hugging Face? Model release receipt, card formatting update, the recipe-link release the MIT license receipt and the CC BY-NC license receipt, which made the latest card update and records the current file inventory; the base card is rendered by export_recipe_search.py
Which public demo, dataset and historical sample versions? CC BY-NC license update, which records the current dataset and demo file inventories, recipe-link release, recipe-card release, earlier ingredient-only release and original sample release, including pinned revisions, tags and artifact hashes; the card formatting update records the documentation-only revisions between the ingredient-only and recipe-card releases, and the sample deletion receipt records the sample dataset's removal
Which bytes, data identities and model-selection results were exported? Recipe-search export evidence
Which ingredient-only access and documentation updates preceded this release? Public-access receipt and earlier card receipt

New training leaves the published benchmark unchanged. Older investigations remain in the model notes, architecture notes and prior study. Use the generated section above for the evaluated cohorts selected in workspace.json.

Restore and train

From a fresh checkout:

cd model
make setup-train
make check-code
make restore BUNDLE=/private/path/workspace-v2-20260909.tar.gz
make verify
make check-core
make train
make status

make setup-train installs the package, tests, and local PyTorch support. make check-code runs locally and needs no private data. make train reads the experiment named by workspace.json, verifies its corpus generation and checksum, and resumes only that experiment's unfinished runs. EASE is the inexpensive control; masked-set is the conditional model being trained. Each run manifest records its sampling cap, length filter, epochs and other resolved parameters.

A git-only clone can inspect recorded results, but cannot train without the private data bundle or an equivalent locally rebuilt corpus. Supply an authorized local bundle to make restore. Restoration verifies archive and file checksums and refuses conflicting files.

Snapshot packing and restoration currently require macOS or Linux (POSIX directory operations and hard links). The recovery command itself needs only Python's standard library: from model/, it can also be run as python3 -m ingredient_model.recovery restore --bundle /private/path/archive.tar.gz before installing the scientific dependencies.

The core bundle deliberately excludes raw recipe downloads, the optional full-text index, credentials, caches and virtual environments. make check-core checks prepared training artifacts. make check additionally replays source records and requires the original raw-data/ files. Browsing full recipe instructions requires rebuilding the text index with make text from those sources.

Existing artifact owners can create a recovery bundle:

cd model
make snapshot BUNDLE=../.artifacts/workspace-v2-20260909.tar.gz

Keep that archive in private storage. Commit its checksum lock, not the archive. The input allowlist is in workspace.json; the command does not archive the whole working directory.

Inspect the models

cd model
.venv/bin/im list
.venv/bin/im report
.venv/bin/im explain tomato basil
.venv/bin/im neighbors all-v2/svd-ppmi-recipe-holdout-s0 tomato -k 10
.venv/bin/im eval train-v2-20260909/masked-set-recipe-holdout-s42

Reports can read tracked metadata without model weights. Prediction and re-evaluation require the corresponding weights. Re-evaluation restores the full predictor for models that have one. The default explainer uses the embedding named in workspace.json.

Acknowledgements

This project started with a replication and audit of Epicure by Jakub Radzikowski and Josef Chen. Their ingredient-embedding work and published source inventory informed that research. llmmm-recipes is a separately trained model with its own learned weights and biases, not a fine-tune of Epicure or another pretrained model.

The method draws on Transformer attention (Vaswani and coauthors), masked prediction in BERT (Devlin and coauthors), and work on attention over unordered sets (Lee and coauthors). Our implementation uses a standard Transformer encoder without positional encodings, rather than the Set Transformer reference architecture.

The ranking experiment uses REINFORCE (Ronald J. Williams), with a supervised warm-start and KL regularization. SQLite FTS5 supplies ingredient-token retrieval. These are method and implementation credits, not imported learned weights.

We credit the authors and curators of RecipeNLG and the other datasets in our source inventory. Epicure Cooc, Epicure Core and RecipeBERT were comparison models; their weights are not part of this checkpoint. The implementation uses PyTorch, and Hugging Face Hub hosts the release.

The Wikibooks sample credits Wikibooks Cookbook contributors. Its attribution and license record includes the additional Wikipedia credit for Oat Porridge. That recipe-text license does not relicense the model weights or project code.

Ideas for using this model

  • Add ingredient autocomplete to a recipe editor. After a user enters at least two known ingredients, show ranked suggestions for them to accept or reject.
  • Search an authorized recipe collection using pantry ingredients and a time limit. Show source links, missing canonical ingredients and data-quality warnings.
  • Compare heuristic, supervised and reinforcement-trained ranking on held-out pantry queries. Keep the simpler policy when an improvement is not established.
  • Use it in a learning experiment. Change the input ingredients and inspect how the rankings move, or compare it with popularity and co-occurrence baselines on genuinely new recipes.

License

MIT. See LICENSE. It covers this repository's project code and documentation. The Hugging Face releases, the llmmm-recipes weights, the llmmm-recipe-ingredients dataset and the llmmm-recipes-demo Space, are released under CC BY-NC 4.0 for non-commercial use, such as education and research, and each carries its legal code as LICENSE. Copies of the weights taken under the earlier v0.4.1-mit tag keep the MIT License. Two tracked items are not covered: the Wikibooks recipe text in model/demo_data/, which stays under CC BY-SA 4.0 as its card records, and paper/epicure.pdf, a copy of the Epicure paper that remains its authors' work.

About

Ingredient embedding models evaluated against a popularity baseline on 4.65M recipes

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages