8000 Seed Search images: Jev image relevance and reference labels by daoudclarke · Pull Request #612 · mwmbl/mwmbl · GitHub
[go: up one dir, main page]

Skip to content

Seed Search images: Jev image relevance and reference labels - #612

Merged
daoudclarke merged 7 commits into
seed-images-eval-harnessfrom
seed-images-eval-labels
Nov 10, 2026
Merged

daoudclarke merged 7 commits into
seed-images-eval-harnessfrom
seed-images-eval-labels

Conversation

@daoudclarke
@daoudclarke daoudclarke commented Nov 9, 2026 •
Copy link
Copy Markdown
Contributor

Stack

PR 2 of 7 in the #610 evaluation stack: #611 ← #612 ← #613 ← #616 ← #615 ← #617 ← #614. Merge in that order.

What changed

The labelling half of the query-gate and image-ranking evaluation, in mwmbl/rankeval/seed_images/:

  • run_relevance asks Jev, in separate mode, how good each candidate is as an image result. One request per query, train and en-gb. Candidates are those with Jev NSFW below 1.0. Results are cached, with each request's latency.
  • label_batches writes self-contained batch files for Sonnet judges. Their rubrics are worded separately from the Jev questions, so the reference stays independent. It covers image need, text relevance and a vision spot-check.
  • labels validates the judges' out_*.txt files and joins them to each batch's manifest. It fails loudly, naming the batch, on a malformed line, an unknown or repeated id, a score outside 0–3 or an unlabelled item.
  • gate_data holds the shared Jev-safe filter. jev_images gains relevance_request.

Results

Jev relevance:

  • Candidates without Jev NSFW ≥ 1.0: 15,846 of 16,512 images kept.
  • 946 queries, one request each, 16.8 images per request on average.
Relevance latency p50 p90 p95 Worst
Per request 0.34 s 0.47 s 0.56 s 0.99 s

Reference labels (Sonnet judges):

Label set Scale Items Notes
Image need 0–3 849 train queries 200 (23.6%) scored 2 or more
Text relevance 0–3 1,689 images top 12 candidates of 150 queries, equally from the 5 quintiles of Jev need; queries with ≥ 3 candidates
Vision spot-check 0–3 100 images only images every local layer passed; judge saw the 320px thumbnail plus the text

Validation:

  • All 34 batches validated. Every id was labelled exactly once.
  • 718 of the 849 need reasons are distinct.
  • 40 of the 150 sampled queries have all 12 images at 0. Spot checks show these are genuine: "cardiff" returns pictures of Quebec, "alcaraz" the Spanish town.
  • The vision thumbnails were written to disk for the judge, a one-off exception the user approved, and deleted after labelling.

How verified

  • make check passes, as do test/test_seed_images_labels.py (new) and test/test_seed_images_eval.py.
  • A code-review subagent reviewed the change. Fixes that followed:
    • A JSON true passed as a level 1 label, because True == 1. Booleans are now rejected.
    • The test imported the shared test image as test.test_seed_images_eval, which fails in CI, where test is Python's own package.
  • Coverage: mwmbl/rankeval/seed_images/* is omitted from coverage (set in Add a harness to evaluate images in Seed Search #611), because it is offline evaluation code.

Decisions already made

  • Only images that pass the Jev NSFW check (score below 1.0) are shown or indexed. There is no additional pixel check behind it.

Nothing outside mwmbl/rankeval imports this code, so production is unchanged.

Part of #610

🤖 Generated with Claude Code

run_relevance asks Jev how good each Jev-safe candidate (NSFW score below 1.0)
is as an image result for its query. label_batches writes reference-label
batches for Sonnet judges: image need for every train query, text relevance for
a sample stratified by Jev need, and a vision spot-check of images every local
safety layer passed. labels checks the judges' output and joins it to the
batches' manifests.

Part of #610

No functional changes to the crawler.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
daoudclarke and others added 3 commits November 9, 2026 17:27
json.loads gives True for true, and True is an int equal to 1, so a judge
writing true passed as a level 1 label.

No functional changes to the crawler.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
No functional changes to the crawler.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
In CI, `test` resolves to Python's own test package, so
`from test.test_seed_images_eval` fails there. pytest puts this directory
on the path, so the module imports directly both locally and in CI.

No functional changes to the crawler.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@codecov
codecov Bot commented Nov 9, 2026
Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

ITEM_MARK = "### "

NEED_RUBRIC = """\
You are helping evaluate a UK web search engine. For each query below, picture its results page: the ten web \
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should mention UK. As far as I know, Mwmbl aims to be a global search engine. There's nothing UK-specific about it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Evaluation is with respect to a specific locale, and at the moment, we are using the UK-English locale. At some point we will be more general.

first web results for the query are shown to tell you which meaning of an ambiguous query is meant.

0 - Wrong. A different subject, the wrong meaning of the query, or nothing anyone searching this would want. \
Example: for "jaguar" (the car), a photo of the cat; for "anna friel", a photo of a different actress.
@blueheron786 blueheron786 Nov 9, 2026 •
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do we do about ambiguous cases that require context?

For example, if someone searches for something ambiguous, like jaguar, what then? Do we show the cat, the car, neither, both?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: if the first query result clearly and unambiguously resolves this, go with that (e.g. jaguar the cat? show the cat image).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reply from Claude: The relevance labels already work this way. Each query's batch shows its first three web results, and the rubric says they are there "to tell you which meaning of an ambiguous query is meant". The rubric's 0 example is exactly this case: for "jaguar" (the car), a photo of the cat.

The gap is on the Jev side. Jev's image-relevance question sees only the query, not the web results. In the holistic comparison (#615), wrong-sense strips were the main losses: people with the same name ("boone helm", "isak"), and the palace for "versailles series". Your suggestion is the natural fix. It's now in the production recommendations (#614): give Jev's relevance question the top web results, re-tune the relevance minimum with that prompt, and drop images that don't match. That means relevance waits for Staan. Only the Commons fetch and the NSFW check can run in parallel with it.

def stratified_sample(scores: dict[str, float], strata: int, total: int, rng: random.Random) -> list[str]:
"""`total` keys, an equal share from each of `strata` equal-sized bands of their score."""
ranked = sorted(scores, key=lambda key: (scores[key], key))
bands = [ranked[band * len(ranked) // strata : (band + 1) * len(ranked) // strata] for band in range(strata)]
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dividing by strata works with larger sets. If we get a smaller data set, sample will raise a value error. Should we check or require a specific minimum data-set size here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Presumably if this was an issue it would have been found when running the evaluation.

daoudclarke and others added 3 commits November 9, 2026 21:34
Mwmbl is a global search engine, so the reference judges shouldn't be told the
searcher is in the UK. The #610 labels were made with the old wording and are not
redone; the module docstring says so.

stratified_sample now raises a clear ValueError when asked for more keys than it
has, rather than letting random.sample fail on a short band.

No functional changes to the crawler.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…sample size"

This reverts commit 5e053c4. The evaluation is for
the UK-English locale, so the rubrics keep saying so, and the sample size was never
a problem in the runs, so it needs no check.

No functional changes to the crawler.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
No functional changes to the crawler.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@daoudclarke
daoudclarke merged commit 0b161ab into wikicommons_image_search Nov 10, 2026
10 checks passed
@daoudclarke
daoudclarke deleted the seed-images-eval-labels branch November 10, 2026 06:13
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.

2 participants

0