Ran a render-based derivation for the style role on the model: held the real
style settings fixed, varied only the 12 layers across seven candidates,
rendered and scored look-transfer minus subject-leak.
- The shipped STYLE table scored best (objective 0.106); the shallow-tap table
was worst - render evidence supports spiking the effective deep taps.
- But differences were small and every output was nearly the same bowl: at
realistic style settings the layer table is a second-order knob. The primary
look-vs-subject control is strength and the shape/global split.
Bottom line committed to the README: the reliable way to set the layers is
render-based measurement (conditioning analysis alone misleads); applying it
shows the shipped tables are directionally right and, for the style role,
near-optimal. The durable deliverable is the render harness, which can
re-derive or verify the layers for any future checkpoint. Full result + images
in local_records.
Ran the decisive test on the model: isolate specific taps (shape=1, global=0),
render, measure. Result flipped the conditioning-level read:
- Mechanism confirmed live (feature width 30720 = 12x2560, split engages).
- Clean-stimuli Stage 1 does show proportional selectivity (shallow taps lean
palette, middle lean texture) - but render validation shows it is
practically irrelevant: the deep taps' large magnitude dominates the pixel
effect. Spiking taps 7/8/10 reproduced the reference entirely; spiking the
shallow taps did nothing.
- So the shipped tables spiking 7/8/10 target the effective (high-leverage)
taps, which the model's projector also emphasizes; the effective taps move
palette+texture+subject together and do not cleanly separate.
The load-bearing lesson for reliable derivation: conditioning-level analysis
misleads because magnitude and the nonlinear diffusion path dominate - the
layers can only be derived reliably from renders. README Stage 1/2 updated;
full arc + validation images in local_records.
Installed V10 + the probe node on the render box, generated a controlled
reference set, and ran the encode-only selectivity harness on the real Krea 2
model. First actual measurement of the 12 text-layer taps:
- Mechanism confirmed live: probe reports feature width 30720 (= 12 x 2560),
divisible by 12, so the tap split engages on the model (no fallback). Tap
magnitude rises with depth.
- No strong per-tap specialization: after removing the depth-magnitude
confound, every tap carries essentially the same attribute mix (palette
0.20 / structure 0.33 / texture 0.35 / lighting 0.12; cross-tap std-dev
~0.01). Taps differ by overall magnitude (depth), not by which attribute
they encode - only a faint depth gradient in the design direction, far too
weak to justify the tables' 5x spikes. The "tap 8 = palette" premise is not
supported.
Caveats recorded honestly (seq-mean signature, weak palette axis from a
near-neutral base, single scene). README Stage 1 updated with the result;
raw signatures + full write-up in local_records. Also fixes the probe graph
generator to supply the V10 card's full widget set (API validation).
Replaces "borrow a template + eyeball renders" with a staged pipeline for
setting the 12 layer-gain values, cheapest/most-targeted first:
- Stage 0 (done, local): extract_model_prior.py reads Krea 2's own learned
per-tap weighting (txtfusion.projector [1,12]) from the checkpoint;
compare_to_model_prior.py scores each shipped table against it. Finding:
the model leans hardest on taps 7>9>4>10>8 but the tables spike 8>10>7
(rank-corr only +0.58..+0.64) - the borrowed template does not track how
the model uses the taps. model_prior.json records the values.
- Stage 1 (harness ready, no render): probe_node/ is a tiny ComfyUI node
that saves per-tap conditioning signatures; probe_selectivity.py does a
variance decomposition (eta^2) of each tap against palette/structure/
texture/lighting over a controlled reference set; generate_probe_graphs.py
builds the encode-only graphs. The selectivity math passes a synthetic
self-test (recovers an injected tap->attribute map exactly). Running it for
real needs V10 + the probe node installed on a box, plus controlled image
sets - it renders nothing (text-encoder passes only).
- Stages 2-3 (documented, need a V10 box): metric-scored render validation,
then black-box optimization of the 12-gain vector against a stated
objective, held-out validated.
README section 4 rewritten as the methodology. All scripts run/validate
locally; tooling stays under docs/ (excluded from registry packs).
Traced the real provenance (Kevin's Codex dev sessions) and verified the
mechanism against the Krea 2 model on the render box. Two earlier claims
(07d2f0b) were wrong and are now fixed across the docs:
1. Mechanism: the 12 "deepstack chunks" are the 12 TEXT-encoder layer taps
Krea 2 conditions on (comfy/text_encoders/krea2.py: hidden_states
[2,5,8,...,35], (B,12,seq,2560) flattened to 30720), NOT the 3 vision
deepstack taps (qwen3vl.py deepstack_visual_indexes=[5,11,17]) the name
implies. 30720 % 12 == 0, so the node's split lands on the taps and the
per-layer gains do apply (no fallback) - confirmed from the model weights
(txtfusion.projector [1,12], layerwise blocks at 2560).
2. Provenance: the 12 values were NOT derived by a per-chunk sweep. They
were adopted from the third-party ComfyUI-ConditioningKrea2Rebalance node
(DEFAULT_WEIGHTS spike 8>10>7, matching STYLE_LAYER_PULL) plus the
shallow=structure/deep=appearance principle; only the scalar shape (0.45
->0.35) and cap (->0.9) were empirically tuned. The four role tables are
scalings of one template, so their agreement is design self-consistency,
not independent measurement - the "convergent evidence" framing is
withdrawn.
docs/deepstack-layers/ rewritten to separate verified mechanism, traced
provenance, and the still-unrun single-tap sweep. Corrections propagated to
the V9 technical paper (5.2 + architecture note + glossary), the V10 guide
and companion, custom_recipes/README, the V10 node doc, and CHANGELOG. Full
evidence chain preserved in local_records (gitignored).
SaveImage prefix now targets output/claude-generations/krea-deepstack-sweep/
on the render box, per Kevin's instruction that generated images go to a
dedicated folder and nothing else is opened. The tool only downloads back
the images it just generated.
New docs/deepstack-layers/ is the authoritative, reproducible account of
the 12 layers values, at three separated confidence levels:
1. Structure (verified from code): the values are gains on 12 equal
deepstack chunks - features from 12 successive Qwen3-VL encoder-depth
bands. Shown in kg_krea_v9/clip_hooks.py (the deepstack feature list)
and conditioning.py (the 12-way width split).
2. Semantics (convergent evidence): analyze_tables.py reads the live
tables and shows the four independently-tuned appearance tables
(style/palette/material/lighting) agree chunk-for-chunk - 0-4 carry
structure (monotonic depth ramp, all suppress), 5-6 transition, 7/8/10
carry appearance (all spike, chunk 8 strongest, then 10, then 7). Four
tables tuned for four different jobs converging is the measurement
encoded as data, not an assertion.
3. Precise response curve (fresh measurement): generate_sweep.py is a
turnkey single-chunk-spike sweep (the paper's section 16.4 method),
emitting each spike as a V10 custom recipe validated against the real
node code. Dry-run works anywhere; rendering needs the V10 nodes on a
ComfyUI box (single-chunk tables are not V9-expressible), so the
measured-verdict table is staged pending a V10-equipped render box.
SCORING.md defines the rubric.
Cross-linked from technical paper 5.2, the recipe guide, and
custom_recipes/README. Tooling lives under docs/ (excluded from registry
packs by .comfyignore). sweep_out/ is gitignored.