Files
kgilper-krea-reference/docs/deepstack-layers/analyze_tables.py
T
Kevin Gilper 07d2f0b763 Determine and document what each deepstack layer carries
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.
2026-07-03 00:59:35 -04:00

107 lines
4.2 KiB
Python

"""Convergent-evidence analysis of the deepstack layer-gain tables.
Reproduces the qualitative chunk->function determination from the repo's own
tuned tables, with no rendering required. The argument: the five built-in
layer tables were tuned independently for five different jobs (style,
palette, material, lighting, and the even baseline). Where the four
appearance-borrowing tables AGREE about a chunk - all suppress it, or all
spike it - that agreement is convergent evidence about what the chunk
carries, because four independent tuning targets converged on the same
treatment of that chunk.
Run: python docs/deepstack-layers/analyze_tables.py
Reads the live tables from kg_krea_v9/recipes.py via the test stubs, so the
output tracks the code and can never silently drift from it.
"""
import sys
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(REPO_ROOT / "tests"))
from _kg_stub_env import load_module # noqa: E402
CHUNKS = 12
# The four tables whose job is to import appearance and reject structure.
# Their agreement is the evidence; the even baseline is the neutral control.
APPEARANCE = ("style", "palette", "material", "lighting")
def load_tables():
v9, _ = load_module("kg_krea_v9", "kg_deepstack_table_analysis")
r = v9.recipes
return {
"even": list(r.EVEN_LAYER_PULL),
"style": list(r.STYLE_LAYER_PULL),
"palette": list(r.PALETTE_LAYER_PULL),
"material": list(r.MATERIAL_LAYER_PULL),
"lighting": list(r.LIGHTING_LAYER_PULL),
}
def classify(chunk_vals):
"""Consensus verdict for one chunk across the appearance tables."""
lo, hi = min(chunk_vals), max(chunk_vals)
mean = sum(chunk_vals) / len(chunk_vals)
if hi < 1.0:
return mean, "STRUCTURE (all suppress <1.0)"
if all(abs(v - 1.0) < 1e-9 for v in chunk_vals):
return mean, "TRANSITION (all neutral)"
if lo >= 1.0 and mean > 1.5:
return mean, "APPEARANCE (all spike >1.0)"
if lo >= 1.0:
return mean, "mild-positive (all >=1.0, gentle)"
return mean, "mixed"
def main():
tables = load_tables()
print("=" * 78)
print("Per-chunk gains across the five tuned tables")
print("=" * 78)
print("chunk | " + " ".join(f"{n:>8}" for n in tables))
for i in range(CHUNKS):
print(f" {i:>2} | " + " ".join(f"{tables[n][i]:>8.2f}" for n in tables))
print("\n" + "=" * 78)
print("Consensus of the four appearance tables (style/palette/material/lighting)")
print("=" * 78)
print("chunk | mean | min | max | consensus verdict")
verdicts = []
for i in range(CHUNKS):
vals = [tables[n][i] for n in APPEARANCE]
mean, verdict = classify(vals)
verdicts.append((i, mean, verdict))
print(f" {i:>2} | {mean:>5.2f} | {min(vals):.2f} | {max(vals):.2f} | {verdict}")
print("\n" + "=" * 78)
print("Findings")
print("=" * 78)
structure = [i for i, _, v in verdicts if v.startswith("STRUCTURE")]
appearance = [i for i, _, v in verdicts if v.startswith("APPEARANCE")]
ranked = sorted(appearance, key=lambda i: -sum(tables[n][i] for n in APPEARANCE))
print(f" Structure-carrying chunks (all 4 suppress): {structure}")
print(f" Appearance-carrying chunks (all 4 spike): {appearance}")
print(" Appearance response ranking (strongest first):")
for rank, i in enumerate(ranked, 1):
m = sum(tables[n][i] for n in APPEARANCE) / len(APPEARANCE)
print(f" #{rank} chunk {i:>2} mean {m:.2f}x")
# Monotonic front ramp = structure fades in smoothly with depth 0->5.
print(" Front-ramp monotonicity (chunks 0-5, structure fading in with depth):")
for n in APPEARANCE:
front = tables[n][:6]
mono = all(front[j] <= front[j + 1] for j in range(5))
print(f" {n:>8}: {front} monotonic-rising={mono}")
print("\n Interpretation: four tables tuned for FOUR DIFFERENT jobs agree that")
print(" chunks 0-4 carry structure (all suppress, smooth depth ramp), chunks 5-6")
print(" are transitional, and chunks 7/8/10 carry appearance (all spike, chunk 8")
print(" strongest). That agreement is the measurement encoded as data.")
if __name__ == "__main__":
main()