ComfyUI Node

Tile Test: Captions

Captions — Read the Tags Before You Spend the Render

By Blakeem·Created 3 months ago·Updated 8 days ago· 28
Tile Test: Captions
  • image
  • layout
  • clip
  • captions
  • tile_texts
  • tiles
  • prompt_tags
  • tags_listed
  • tags_verified
  • tags_final
◄tiles►
◄with_neighborstrue►
◄position_termstrue►
◄caption_megapixels0.79►
◄tile_caption_max_tokens768►
◄global_style_max_tokens768►
◄tile_tags_verification_threshold1.0000►
◄tile_tags_position_threshold0.90►
◄prompt_tags_verification_threshold1.0000►
◄prompt—►
◄global_style_instruction—►
◄tile_caption_instruction—►
◄tile_tags_instruction—►
◄prompt_tags_instruction—►
◄tile_tags_verification_statement—►

There's a failure in tiled upscaling that no blend can fix: a tile that should be empty sky grows a car, because your global prompt says "red car" and the model doing that tile was never told it's looking at the sky.

This pack solves it by throwing the global prompt away: each tile's positive conditioning is built from the image itself - vision tokens of the tile's crop, its slice of a whole-image encode, and a short bit of text naming what's actually there. Tile Test: Captions is that text pass, on its own.

Why you'd split it out

Captioning is the slowest part of a VL upscale - every tile needs a vision encode plus a text pass. When something comes out wrong you want to know whether the tile text was bad or the sampling was, and in the all-in-one node you can't tell. Here you get the answer as text before rendering anything: every stage of the tags pass prints as Markdown.

It also has no seed, which matters more than it looks. ComfyUI caches it, so re-rolling the seed downstream leaves the tile texts alone.

Two kinds, and you pick one

The mode is decided by which instruction socket you connect. Connect tile_caption_instruction or tile_tags_instruction - never both, and leaving both off leaves the node idle.

Tags (the shipped tags preset) is the interesting one. Three stages: the VL model lists what it sees in the tile; each candidate is scored true-or-false against the tile and only near-certain ones are kept; then six strips - three rows, three columns - decide each tag's position, and a tag no strip can hold is dropped. Scoring runs through logit-classifier, the pack's one Python dependency.

Caption asks one question about each tile's crop and uses the answer as that tile's text. A preset can also write a style caption from the whole image once and place it on top of every tile's text.

The inputs a beginner actually touches

  • image and layout - the canvas from Tile Test: Upscale, and the CATR_LAYOUT the tiles are captioned from.
  • clip - a vision-language text encoder with a text generator, from the Krea 2 family. SD/SDXL CLIP, T5 and plain Qwen3 are rejected with a clear error.
  • tiles - comma-separated tile numbers as the Layout overlay labels them. Empty captions everything. This is the widget the chain is built around.
  • with_neighbors (on) - also caption the bordering tiles of each named tile. Must match Tile Test: Render's setting, or Render comes up short.
  • position_terms (on) - the strip scoring. Off, tags are written without a term like top-left and nothing is dropped for failing a strip.

Then the tuning numbers, each wireable from Tile Test: Settings: caption_megapixels, the two token budgets tile_caption_max_tokens and global_style_max_tokens (which also cover the model's hidden reasoning turn, hence the generous 768 default), and the three tag thresholds, defaulting to near-certainty. Optional strings in: prompt, global_style_instruction, prompt_tags_instruction, tile_tags_verification_statement.

The outputs

captions is the CATR_CAPTIONS object - wire it to Tile Test: Render. tile_texts is Markdown listing the style caption and then each tile's text, exactly what Render conditions on. tiles passes the named tile list through for Render's tiles input; empty in, empty out.

Then the four inspection outputs - prompt_tags, tags_listed, tags_verified, tags_final - which are the reason to use this node instead of the all-in-one. They're Markdown for Preview as Text's Markdown mode, so Nodes 2.0 needs to be on.

About that prompt input

The diffusion model never reads your prompt. On the tags preset the VL model reads it once per image to list the physical things it names, and each tile checks that list against its own content - a checklist, not conditioning. In a caption preset, {PROMPT} in the instructions is filled from it, and a preset whose instruction carries {PROMPT} errors if prompt is empty; the tags preset just skips its prompt question.

Install

ComfyUI Manager → search "Context-Anchored Tile Refine". Or:

cd ComfyUI/custom_nodes
git clone https://github.com/Blakeem/ComfyUI-ContextAnchoredTileRefine
cd ComfyUI-ContextAnchoredTileRefine
pip install -r requirements.txt
cp settings.toml settings.user.toml

logit-classifier>=0.4.0 is the only dependency. You'll want the Krea 2 stack too - the model, the Qwen3-VL encoder (~8GB) and the Qwen-Image VAE - because without a vision-language encoder there's nothing to run on.

Where it goes wrong

Wiring both instruction sockets. Exactly one of the two must be on - an easy mistake, since both sit in the same optional block.

A tag list that looks empty. Usually the thresholds doing their job: near-certainty cuts hard, and a scene the VL model is unsure about produces short tags. Loosen tile_tags_verification_threshold carefully.

A broken settings file. If this node is missing from the menu entirely, the settings file has a syntax error; ComfyUI prints the filename and the problem to the console, and the node stays gone until you fix it.

Categoryimage/upscaling/tile testing

Inputs (18)

NameTypeDefaultDescription
imageIMAGEThe canvas from Tile Test: Upscale, at the layout's target size.
layoutCATR_LAYOUTThe layout from Tile Test: Layout. The tiles are captioned from it.
clipCLIPMust be a vision-language text encoder with a text generator (Krea 2 family).
tilesSTRINGComma separated tile numbers, as Tile Test: Layout labels them. Empty captions every tile. The same list comes out of the tiles output for Tile Test: Render.
with_neighborsBOOLEANtrueCaption the bordering tiles of every named tile as well, which Tile Test: Render needs when its with_neighbors is on. Off captions the named tiles only.
position_termsBOOLEANtrueScore each kept tag on six strips of its tile, drop a tag no strip holds, and write a position term such as top-left. Off writes each tag without a term, makes no strip requests and drops no tag for its strips. Read by the tags kind when tile_tags_verification_statement is connected, and ignored by the caption kind.
caption_megapixelsFLOAT0.790–2How much of the picture the VL model reads for every caption this node writes, the tile captions and the style caption. Use 0 for the picture's own size, capped at 2.0 megapixels. The tags kind reads it for the style caption only, since its tags questions read a fixed copy of about 1 megapixel. Can take the caption_megapixels output of Tile Test: Settings.
tile_caption_max_tokensINT7681–4096Generation budget for each tile caption, which also covers the model's hidden reasoning turn. Read by the caption kind and ignored by the tags kind. Can take the tile_caption_max_tokens output of Tile Test: Settings.
global_style_max_tokensINT7681–4096Generation budget for the style caption, which also covers the model's hidden reasoning turn. Read when global_style_instruction is connected. Can take the global_style_max_tokens output of Tile Test: Settings.
tile_tags_verification_thresholdFLOAT1.00000.00001–1The score tile_tags_verification_statement must reach on the entire tile to keep a tag the tile's own list names. Read by the tags kind when tile_tags_verification_statement is connected. Can take the tile_tags_verification_threshold output of Tile Test: Settings.
tile_tags_position_thresholdFLOAT0.900–1The score tile_tags_verification_statement must reach on one of the six strips of a tile for that strip to hold a tag. A tag no strip holds is dropped, and a strip that is the only one holding a tag on its axis names the tag's position term. A center column adds no word beside a row word. Read by the tags kind when position_terms is on. Can take the tile_tags_position_threshold output of Tile Test: Settings.
prompt_tags_verification_thresholdFLOAT1.00000.00001–1The score tile_tags_verification_statement must reach on the entire tile to keep a thing from the prompt that the tile's own list lacks. Read by the tags kind when prompt_tags_instruction and tile_tags_verification_statement are connected. Can take the prompt_tags_verification_threshold output of Tile Test: Settings.
promptoptSTRINGOptional. The prompt the image was made from, as a text link. Connect the positive prompt's text. With the tags preset the VL model lists the things the prompt names, and a tile adds a listed thing to its tags when the VL model confirms it in that tile. In a caption preset it fills {PROMPT} in the instructions, and a preset with {PROMPT} needs it connected. The diffusion model never reads the prompt text itself.
global_style_instructionoptSTRINGWhat the VL model is asked about the entire image, for one style caption placed on top of every tile's text, in either kind. {PROMPT} is filled from prompt. Unconnected, or holding only whitespace, writes no style caption.
tile_caption_instructionoptSTRINGWhat the VL model is asked about each tile, which runs the caption kind. {PROMPT} is filled from prompt. Connect this or tile_tags_instruction, never both. Unconnected leaves the caption kind off.
tile_tags_instructionoptSTRINGThe question that asks the VL model to list the things in each tile as comma separated tags, which runs the tags kind. It cannot hold {PROMPT}. Connect this or tile_caption_instruction, never both. Unconnected leaves the tags kind off.
prompt_tags_instructionoptSTRINGThe question that asks the VL model to list the things the prompt names, once per picture. It must hold {PROMPT}, where the prompt goes. Every tile checks the listed things. Read by the tags kind when prompt is connected. Unconnected lists no things from the prompt.
tile_tags_verification_statementoptSTRINGThe statement each candidate tag is scored true or false against on its tile. It must hold {TAG}, where the tag goes, and a tag is kept at tile_tags_verification_threshold. Read by the tags kind only. Unconnected keeps every candidate unchecked and writes no position terms.

Outputs (7)

NameTypeDescription
captionsCATR_CAPTIONSThe style caption and every captioned tile's text, for the captions input of Tile Test: Render.
tile_textsSTRINGMarkdown that lists the style caption once and then each captioned tile's own text, the texts Tile Test: Render conditions on.
tilesSTRINGThe named tile numbers, comma separated, for the tiles input of Tile Test: Render. It is empty when the tiles input was empty.
prompt_tagsSTRINGMarkdown of the tags kind's prompt stage: the question sent once per picture, the VL model's reply and whether each listed tag was kept.
tags_listedSTRINGMarkdown of the tags kind's listing stage: each tile's VL model reply and the tags parsed from it.
tags_verifiedSTRINGMarkdown of the tags kind's verification stage: each tile's candidate tags with their scores and whether each was kept.
tags_finalSTRINGMarkdown of the tags kind's last stage: each tile's tags after the subset and position checks, and the tile text they make.