Skip to content

LayerAwareObjectInsertion: nima_score not emitted natively by evaluate() (requires post-hoc rescoring) #3

Description

@mohitgargai

Problem

layout-8 / LayerAwareObjectInsertion (and its peers in the layer-aware-edit
family) declare nima_score as a primary/reported metric upstream, but the
native BaseBenchmark.evaluate() method does not produce nima_score for
these benchmarks. The benchmark's native metric set is identity-preservation
(clip_identity, dino_identity, dreamsim_distance, lpips, hpsv3, …).

The nima_score values we report upstream for layout-8 (e.g. 4.5225 for
claude-sonnet-4-20250514 in outputs/parity_claude_code.rescored.json) are
produced via a separate post-hoc rescoring pass over the output PNGs using
pyiqa's NIMA model (see nima_real_rescore.json / scripts/merge_parity_results.py
flow).

This creates an asymmetry:

  • A fresh upstream run that calls bench.evaluate() (e.g. via
    run_benchmarks.py) returns NaN / absent nima_score for layout-8.
  • Only after the rescoring side-pass do the "canonical" parity numbers appear.

Any external harness (Harbor adapter, other evaluators, or a clean re-run) that
consumes evaluate() output directly will see nima_score = NaN for layout-8
and peers, and produce a 0-reward or skip the benchmark entirely.

Expected behavior

LayerAwareObjectInsertion.evaluate() (and any other layer-aware benchmark that
ships nima_score as part of its reported metric set) should natively compute
nima_score via pyiqa.create_metric("nima", …) on the generated image, so
downstream consumers don't need a separate rescoring pipeline.

Proposed fix

Add a _compute_nima helper to BaseBenchmark (or a mixin) that:

  1. Loads pyiqa.create_metric("nima", device=…) once per process (cached).
  2. Runs it on each sample's generated image.
  3. Populates scores["nima_score"] in evaluate() output.

Then gate it on a benchmark-class flag such as REPORTS_NIMA = True to avoid
paying the model-load cost for benchmarks that don't report it.

Workaround used downstream

For the Harbor GDB adapter, we ship a post-hoc fallback in the Harbor verifier
(evaluate.py) that mirrors the upstream rescoring pass: when the primary
metric is nima_score and bench.evaluate() does not return it, we compute it
ourselves with pyiqa.create_metric("nima", device="cpu") against
/workspace/output.png. This keeps parity numbers comparable across harnesses,
but it's a shim — the clean fix is upstream in this repo.

Repro

bench = LayerAwareObjectInsertion(...)
result = bench.evaluate(samples)
assert "nima_score" in result.scores  # fails today

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions