Skip to content

Commit 3f589f8

Browse files
authored
Improve Section 04 architecture visualizations (#6)
* Align architecture schematic arrows with TabICLv2 core data flow * Clarify final-block output selection across implementations
1 parent 437d033 commit 3f589f8

2 files changed

Lines changed: 41 additions & 27 deletions

File tree

‎materials/website/index.html‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,8 +1068,8 @@ <h3>How does the frozen graph use context to answer a query?</h3>
10681068
</div>
10691069
<div class="prose reveal">
10701070
<p>
1071-
Inference repeats the same preprocessing and 3-column / 3-row / 12-ICL-block
1072-
forward graph, but stops after prediction. Context labels are embedded; the query
1071+
In this classifier-core schematic, inference repeats the nanoTabICL preprocessing
1072+
and 3-column / 3-row / 12-ICL-block forward graph, but stops after prediction. Context labels are embedded; the query
10731073
label is unavailable; pretrained weights remain frozen. There is no loss,
10741074
backpropagation, or task-specific optimizer step in this diagram.
10751075
<a class="cite" href="https://arxiv.org/abs/2602.11139" target="_blank" rel="noopener">[Qu et al., 2026]</a>
@@ -1089,7 +1089,7 @@ <h3>How does the frozen graph use context to answer a query?</h3>
10891089
<div>
10901090
<span class="mono">same graph · inference mode · weights frozen</span>
10911091
<h3 id="inference-live-title">Trace the same toy table without an update step</h3>
1092-
<p>This is a shape-faithful schematic. Select a stage to inspect what is reused from training and what changes at inference.</p>
1092+
<p>This schematic shows the classifier core. The full browser classifier additionally preprocesses and ensembles eight views. Select a stage to inspect the core data flow.</p>
10931093
</div>
10941094
</header>
10951095
<nav class="inference-live__steps architecture-flow" aria-label="Inference architecture stages">

‎materials/website/js/site.js‎

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1389,16 +1389,18 @@ function createTensorScene(canvas, render) {
13891389
}
13901390
}
13911391

1392-
function datasetAttention(x, y, labels = null, showOutput = true) {
1393-
const queryY = y + 9 * 31;
1392+
function datasetAttention(x, y, labels = null) {
1393+
// Show the final block explicitly. C′ and Q′ have already passed through
1394+
// blocks 1–11, where both context and query read context K/V only.
1395+
const queryY = y + 9 * 27;
13941396
for (let row = 0; row < 10; row++) {
1395-
const cy = y + row * 31;
1397+
const cy = y + row * 27;
13961398
ctx.fillStyle = row === 9 ? "rgba(255,132,108,.28)" : "rgba(154,124,255,.24)";
13971399
ctx.strokeStyle = row === 9 ? TECH.coral : TECH.violet;
13981400
ctx.fillRect(x, cy, 72, 20);
13991401
ctx.strokeRect(x, cy, 72, 20);
14001402
const label = labels?.[row] ?? row % 2;
1401-
mono(row === 9 ? "Q · y=?" : `C${row + 1} · y=${label}`, x + 36, cy + 10, 10,
1403+
mono(row === 9 ? "Q′ · no y" : `C${row + 1}′ · y=${label}`, x + 36, cy + 10, 10,
14021404
row === 9 ? TECH.coral : TECH.text, "center", 650);
14031405
if (row < 9) {
14041406
arrow(x + 76, cy + 10, x + 150, queryY + 10, "rgba(53,217,255,.52)", 1);
@@ -1410,19 +1412,12 @@ function createTensorScene(canvas, render) {
14101412
ctx.arc(x + 166, queryY + 10, 15, 0, Math.PI * 2);
14111413
ctx.fill();
14121414
ctx.stroke();
1413-
text("Q", x + 166, queryY + 10, 13, TECH.coral, "center", 750);
1414-
if (showOutput) {
1415-
arrow(x + 183, queryY + 10, x + 222, queryY + 10, TECH.coral, 1.5);
1416-
cube(x + 228, queryY - 18, 66, 55, 10, "head", "1×10", TECH.coral);
1417-
arrow(x + 306, queryY + 10, x + 336, queryY + 10, TECH.gold, 1.5);
1418-
ctx.fillStyle = "rgba(255,209,102,.22)";
1419-
ctx.strokeStyle = TECH.gold;
1420-
ctx.fillRect(x + 342, queryY - 17, 55, 23);
1421-
ctx.fillRect(x + 342, queryY + 13, 34, 23);
1422-
ctx.strokeRect(x + 342, queryY - 17, 55, 23);
1423-
ctx.strokeRect(x + 342, queryY + 13, 34, 23);
1424-
mono("2 classes", x + 370, queryY + 52, 11, TECH.gold, "center", 700);
1425-
}
1415+
text("Q″", x + 166, queryY + 10, 13, TECH.coral, "center", 750);
1416+
// The query's own representation participates in attention and residuals.
1417+
// Its label is absent, but its features must not disappear from the graph.
1418+
arrow(x + 76, queryY + 10, x + 149, queryY + 10, TECH.coral, 1.5);
1419+
mono("block 12 shown · query output retained", x + 115, queryY + 37, 9, TECH.muted, "center", 700);
1420+
return { outputX: x + 183, outputY: queryY + 10 };
14261421
}
14271422

14281423
function background() {
@@ -1541,17 +1536,28 @@ function initTrainingLive() {
15411536
arrow(635, 267, 662, 267, TECH.violet, 2);
15421537
panel(669, 82, 271, 372, TECH.coral);
15431538
mono("3 · DATASET ICL ATTENTION", 687, 104, 12, TECH.coral, "left", 700);
1544-
mono("11 blocks: C,Q read C · final: Q reads C", 687, 124, 9, TECH.muted);
1545-
datasetAttention(692, 146, y, false);
1546-
arrow(875, 435, 898, 435, TECH.coral, 1.4);
1547-
mono("LN→MLP→1×10", 934, 450, 9, TECH.gold, "right", 700);
1539+
mono("before block 1: C += y_embed_icl · Q has no y", 687, 124, 9, TECH.coral);
1540+
mono("blocks 1–11: C,Q read C K/V → C′,Q′", 687, 144, 9, TECH.muted);
1541+
const iclOutput = datasetAttention(692, 163, y);
1542+
arrow(iclOutput.outputX, iclOutput.outputY, 925, iclOutput.outputY, TECH.coral, 1.4);
1543+
mono("LN + MLP", 906, 395, 8, TECH.gold, "center", 700);
1544+
mono("1×10", 906, 432, 9, TECH.gold, "center", 700);
15481545
} else if (active === 2) {
15491546
title("Step 03 · query loss", "The toy query contributes 10-way cross-entropy", "illustrative values · training only");
15501547
panel(72, 115, 260, 240, TECH.coral);
15511548
mono("HIDDEN TRUTH", 202, 144, 12, TECH.coral, "center", 700);
15521549
text(`query y = ${y[9]}`, 202, 218, 30, TECH.text, "center", 800);
15531550
mono("query label never enters forward pass", 202, 319, 11, TECH.muted, "center");
1554-
arrow(350, 235, 405, 235, TECH.coral, 2);
1551+
// The hidden label is a loss target, never an input to the output head.
1552+
ctx.strokeStyle = TECH.coral;
1553+
ctx.lineWidth = 1.5;
1554+
ctx.beginPath();
1555+
ctx.moveTo(202, 355);
1556+
ctx.lineTo(202, 382);
1557+
ctx.lineTo(841, 382);
1558+
ctx.stroke();
1559+
arrow(841, 382, 841, 357, TECH.coral, 1.5);
1560+
mono("hidden target → loss only", 490, 370, 11, TECH.coral, "center", 700);
15551561
panel(426, 115, 250, 240, TECH.cyan);
15561562
mono("ILLUSTRATIVE OUTPUT", 551, 144, 12, TECH.cyan, "center", 700);
15571563
cube(492, 181, 118, 82, 15, "LN + MLP", "1×10 logits", TECH.cyan);
@@ -1673,8 +1679,16 @@ function initInferenceLive() {
16731679
} else {
16741680
title("Stage 04 · dataset ICL + output", "Twelve ICL blocks turn context into query logits", "no loss · no backward · no update");
16751681
panel(49, 90, 474, 356, TECH.coral);
1676-
mono("C += y_embed_icl · Q has no y · K/V = context only", 286, 116, 10, TECH.coral, "center", 700);
1677-
datasetAttention(82, 139, y, false);
1682+
mono("before block 1: C += y_embed_icl · Q has no y", 286, 116, 10, TECH.coral, "center", 700);
1683+
mono("blocks 1–11: C,Q read C K/V → C′,Q′", 286, 140, 10, TECH.muted, "center", 700);
1684+
const iclOutput = datasetAttention(82, 159, y);
1685+
v.ctx.strokeStyle = TECH.coral;
1686+
v.ctx.lineWidth = 1.5;
1687+
v.ctx.beginPath();
1688+
v.ctx.moveTo(iclOutput.outputX, iclOutput.outputY);
1689+
v.ctx.lineTo(550, iclOutput.outputY);
1690+
v.ctx.lineTo(550, 268);
1691+
v.ctx.stroke();
16781692
arrow(550, 268, 603, 268, TECH.coral, 2);
16791693
panel(628, 134, 268, 270, TECH.gold);
16801694
mono("FROZEN OUTPUT HEAD", 762, 163, 12, TECH.gold, "center", 700);

0 commit comments

Comments
 (0)