CachedSearch ImageReward Verifier
What the ImageReward Verifier actually scores
- verifier
This node generates nothing. No image input, no model input, no wires going in at all - you drop it on the canvas, set two numbers, and its single output feeds the verifier socket on the CachedSearch Sampler. It exists because best-of-N is only as good as the thing picking the winner, and if you're about to spend a 30-minute Wan render on one seed out of eight, you want the decision to be better than "take the third one."
It's the referee. ImageReward, averaged across a handful of frames, decides which candidate seed gets re-rendered at full compute.
How it scores
The mechanism is small enough to state honestly. The sampler hands it a decoded draft clip; the verifier flattens that clip to a frame stack, picks frames_to_score frames at evenly spaced intervals (fewer if the clip is shorter than your setting), converts each to a PIL image, and asks ImageReward how well that frame matches your prompt. The candidate's score is the mean of those per-frame numbers.
Two consequences worth feeling:
- It's prompt alignment, not beauty. ImageReward was trained on human preference data over image-and-prompt pairs, so what it rewards is "this matches the sentence." A candidate that nails your composition wording but has mushier texture can beat a prettier one that ignored the prompt. That's the paper's choice - the sampler optimizes for adherence.
- Your prompt is the entire case file. The sampler's
promptbox is the only text the verifier sees. Leave it empty, or paste something different from what you encoded intopositive, and you've hired a judge who wasn't told what the crime was. Empty prompt means the alignment term has nothing to align to and the "winner" is close to a coin flip.
Inputs and output
Two knobs, both required.
frames_to_score (default 8, range 1–64) - uniformly spaced frames scored per candidate, per the author's tooltip. On a 5-second clip, 8 frames samples about 1.5 frames per second, so fast action between samples is invisible to the scorer. Raise it if the clip is about motion; keep it low for static shots. Cost is linear: one ImageReward forward pass per frame, times your search width.
device - auto (default), cuda, or cpu. auto picks CUDA when torch can see it. Leave it there unless you're offloading to CPU to free VRAM for a big video model, and expect that to hurt: you're running frames_to_score × search_width reward evaluations per generation, and a CPU can turn that into minutes by itself.
The output is verifier, type CS_VERIFIER, wired into the sampler's verifier input. It's an object, not a tensor - it carries a score(images, prompt) -> float method, and that's the whole contract. The README says any node with that shape can replace it, so a different reward model or your own heuristic is a tiny node away.
Installing it
Same pack, same install as the sampler:
cd ComfyUI/custom_nodes
git clone https://github.com/shreshthsaini/ComfyUI-CachedSearch
pip install -r ComfyUI-CachedSearch/requirements.txt
That requirements file is one line: image-reward. ComfyUI Manager will do the same if you search the pack title. Restart after.
Two things about the download: image-reward brings its own dependency chain, and the ImageReward-v1.0 checkpoint is fetched on first use, not at install. So the first scoring run is slow and needs a live connection; on an offline box, pre-warm it before queueing an eight-candidate video search. Windows portable users, install into the embedded interpreter - python_embeded\python.exe -m pip install image-reward - or you'll get an import error at execute time.
Convenient detail: the pack's EasyCache dependency is imported lazily inside the sampler, so this node loads fine on older ComfyUI builds. It appears in the menu and builds a verifier object. It just has nothing to score until the sampler works.
Where people get burned
Read the scores. The sampler emits draft_scores as JSON in seed order. If your winner is dull, look there first: eight numbers clustered within a few hundredths means the verifier was guessing, and the fix is a real prompt, more frames, or accepting that best-of-N won't help that shot.
Cached drafts are not full-quality drafts. The candidates being ranked came out of EasyCache, and the community read on these caches on video models is that they're fine on slow static shots and degrade noticeably on complex motion - "there is a noticeable decline in quality for realism or videos with complex movement." A smeared draft can lose to a seed that would have won at full compute. That doesn't ruin the final output, since the sampler's commit re-renders the winner uncached, but it does bend the ranking. If the winner keeps disappointing, lower cache_threshold on the sampler before blaming ImageReward.
Don't fix VRAM here. The sampler decodes every draft through the VAE to feed this node, whole clip either way. On small GPUs you cut search_width - the author's own advice. Trimming frames_to_score saves scoring time, not the decode memory that's actually killing you.
Inputs (2)
| Name | Type | Default | Description |
|---|---|---|---|
| frames_to_score | INT | 81–64 | Uniformly spaced frames scored per candidate; the mean is the candidate's score. |
| device | COMBO | auto | 3 options: auto, cuda, cpu |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| verifier | CS_VERIFIER | — |