stared/mushroom-hunting-llm-bench

Mushroom hunting LLM benchmark based on FungiTastic dataset

1

stars

18

commits

Python

primary language

Sep 8, 2026

updated

README

shroombench

How well do vision LLMs name a mushroom from one photo, and how often do they call a poisonous one edible? Code and results behind the post Mushroom hunting with LLMs.

Photos and expert labels come from FungiTastic (Atlas of Danish Fungi). Models are called through OpenRouter. Nothing is trained; a model sees one photo and the prompt below, and returns five Latin names.

Which mushroom species is it? Reply with a JSON array of the 5 most likely species as Latin binomials, most likely first. Output only the JSON array, nothing else.

Setup

Python 3.11+ and uv. Dependencies install on first uv run.

git clone https://github.com/BohemianVRA/FungiTastic.git   # data layout and download script only
export OPENROUTER_API_KEY=sk-or-v1-...

Download the metadata and the 500px photos of the test and validation splits (the post's photos: 926 from test, 114 from val for species with too few test photos). Zips are deleted after extraction.

filedownload
metadata.zip0.3 GB
FungiTastic-test-500p.zip5.9 GB
FungiTastic-val-500p.zip5.5 GB
cd FungiTastic/dataset/data
base=https://cmp.felk.cvut.cz/datagrid/FungiTastic/shared/download
for f in metadata.zip FungiTastic-test-500p.zip FungiTastic-val-500p.zip; do
  wget -nc $base/$f && unzip -q $f -d FungiTastic && rm $f
done
cd ../../..

The code expects FungiTastic/dataset/data/FungiTastic/metadata/FungiTastic/*.csv and FungiTastic/dataset/data/FungiTastic/FungiTastic/{test,val}/500p/. The train split (22.7 GB) is not needed; the upstream dataset/download.py fetches all splits at once.

Reproduce the post

The 1,040 photos (55 species, up to 20 each) are listed in results/poland20-images.jsonl. Ask all 16 models about every photo, about $60 and 20 minutes at this concurrency:

uv run python -m shroombench.run --images-from results/poland20-images.jsonl \
  --split test-full,val-full --top5 --max-tokens 8192 --concurrency 32 --out results/my-run.jsonl

Rerun the same command to resume: photos already answered are skipped, API errors are retried. Add --models google/gemini-3.7-flash for one model, --concurrency 4 if a model rate-limits you.

Score it:

uv run python -m shroombench.report results/my-run.jsonl        # accuracy per model
uv run python -m shroombench.safety results/my-run.jsonl        # edible called poisonous, poisonous called edible
uv run python -m shroombench.safety results/my-run.jsonl --species

Grading is string matching against the ground-truth binomial with accepted synonyms (grading.py); top1 means the first name is right, topk right within the five, trunc means the model spent the whole token budget reasoning and returned nothing. Edibility of the names models return is a hand-made table in edibility.py.

Results in this repo

filewhat
results/poland20.jsonlthe post's run: 16 models x 1,040 photos
results/poland20-images.jsonlthe photo list of that run
results/poland-*.jsonlearlier 5-photos-per-species runs, incl. the "photo from Denmark" hint
results/scale-glm.jsonlGLM-5.3-Flash on 2,301 species of the full test split
results/prompt-noonly-40.jsonlprompt without "Output only the JSON array" on 40 photos
results/photo_filter.jsonwhich photos are ordinary photos (not micrographs), cached VLM pass

One record per (model, photo): the raw answer, parsed names, verdict, tokens, cost, latency.

Picking your own photos

Without --images-from, run.py samples photos itself: --poland for the post's 55 species, --per-species 20, --split test-full. It uses only photos that passed the ordinary-photo filter; run photo_filter.py first for a split not yet in the cache. LAB_NOTEBOOK.md is the running log of everything tried, including dead ends.

Layout

  • shroombench/data.py — FungiTastic metadata, species lists (Polish sellable, deadly), sampling
  • shroombench/run.py — the sweep: prompt, OpenRouter calls, resume, per-record output
  • shroombench/grading.py — name matching, synonyms, verdicts
  • shroombench/report.py, safety.py, errors.py — accuracy, error direction, what was answered instead
  • shroombench/edibility.py — edible / poisonous / deadly for every name the models returned
  • shroombench/photo_filter.py — cached VLM pass that keeps only ordinary photos
  • shroombench/models.py, list_models.py — the model roster, and how to refresh it

Contributors

stared

18 commits

stared/mushroom-hunting-llm-bench

Mushroom hunting LLM benchmark based on FungiTastic dataset

1

stars

18

commits

Python

primary language

Sep 8, 2026

updated

README

shroombench

How well do vision LLMs name a mushroom from one photo, and how often do they call a poisonous one edible? Code and results behind the post Mushroom hunting with LLMs.

Photos and expert labels come from FungiTastic (Atlas of Danish Fungi). Models are called through OpenRouter. Nothing is trained; a model sees one photo and the prompt below, and returns five Latin names.

Which mushroom species is it? Reply with a JSON array of the 5 most likely species as Latin binomials, most likely first. Output only the JSON array, nothing else.

Setup

Python 3.11+ and uv. Dependencies install on first uv run.

git clone https://github.com/BohemianVRA/FungiTastic.git   # data layout and download script only
export OPENROUTER_API_KEY=sk-or-v1-...

Download the metadata and the 500px photos of the test and validation splits (the post's photos: 926 from test, 114 from val for species with too few test photos). Zips are deleted after extraction.

filedownload
metadata.zip0.3 GB
FungiTastic-test-500p.zip5.9 GB
FungiTastic-val-500p.zip5.5 GB
cd FungiTastic/dataset/data
base=https://cmp.felk.cvut.cz/datagrid/FungiTastic/shared/download
for f in metadata.zip FungiTastic-test-500p.zip FungiTastic-val-500p.zip; do
  wget -nc $base/$f && unzip -q $f -d FungiTastic && rm $f
done
cd ../../..

The code expects FungiTastic/dataset/data/FungiTastic/metadata/FungiTastic/*.csv and FungiTastic/dataset/data/FungiTastic/FungiTastic/{test,val}/500p/. The train split (22.7 GB) is not needed; the upstream dataset/download.py fetches all splits at once.

Reproduce the post

The 1,040 photos (55 species, up to 20 each) are listed in results/poland20-images.jsonl. Ask all 16 models about every photo, about $60 and 20 minutes at this concurrency:

uv run python -m shroombench.run --images-from results/poland20-images.jsonl \
  --split test-full,val-full --top5 --max-tokens 8192 --concurrency 32 --out results/my-run.jsonl

Rerun the same command to resume: photos already answered are skipped, API errors are retried. Add --models google/gemini-3.7-flash for one model, --concurrency 4 if a model rate-limits you.

Score it:

uv run python -m shroombench.report results/my-run.jsonl        # accuracy per model
uv run python -m shroombench.safety results/my-run.jsonl        # edible called poisonous, poisonous called edible
uv run python -m shroombench.safety results/my-run.jsonl --species

Grading is string matching against the ground-truth binomial with accepted synonyms (grading.py); top1 means the first name is right, topk right within the five, trunc means the model spent the whole token budget reasoning and returned nothing. Edibility of the names models return is a hand-made table in edibility.py.

Results in this repo

filewhat
results/poland20.jsonlthe post's run: 16 models x 1,040 photos
results/poland20-images.jsonlthe photo list of that run
results/poland-*.jsonlearlier 5-photos-per-species runs, incl. the "photo from Denmark" hint
results/scale-glm.jsonlGLM-5.3-Flash on 2,301 species of the full test split
results/prompt-noonly-40.jsonlprompt without "Output only the JSON array" on 40 photos
results/photo_filter.jsonwhich photos are ordinary photos (not micrographs), cached VLM pass

One record per (model, photo): the raw answer, parsed names, verdict, tokens, cost, latency.

Picking your own photos

Without --images-from, run.py samples photos itself: --poland for the post's 55 species, --per-species 20, --split test-full. It uses only photos that passed the ordinary-photo filter; run photo_filter.py first for a split not yet in the cache. LAB_NOTEBOOK.md is the running log of everything tried, including dead ends.

Layout

  • shroombench/data.py — FungiTastic metadata, species lists (Polish sellable, deadly), sampling
  • shroombench/run.py — the sweep: prompt, OpenRouter calls, resume, per-record output
  • shroombench/grading.py — name matching, synonyms, verdicts
  • shroombench/report.py, safety.py, errors.py — accuracy, error direction, what was answered instead
  • shroombench/edibility.py — edible / poisonous / deadly for every name the models returned
  • shroombench/photo_filter.py — cached VLM pass that keeps only ordinary photos
  • shroombench/models.py, list_models.py — the model roster, and how to refresh it

Contributors

stared

18 commits

Languages

Python

100.0%