Normalization Viz
A teaching primitive for the dimensions that each normalization scheme reduces over. The same 4D tensor (N, C, H, W) is rendered as a stack of sample cards; switching schemes recolours the cells so that any two cells which share a (mu, sigma) statistic share a hue. The colour map is the lesson — there is no other signal to learn.
BatchNorm → one (mu, sigma) per channel across (N, H, W)
LayerNorm → one (mu, sigma) per sample across (C, H, W)
GroupNorm → one (mu, sigma) per (n, group) across (group_channels, H, W)
InstanceNorm → one (mu, sigma) per (n, channel) across (H, W)
BatchNorm on a (4, 8, 4, 4) tensor. 8 normalization statistics across (N, H, W) — one statistic per channel.
Normalization(4, 8, 4, 4)
sample 0C=8
sample 1C=8
sample 2C=8
sample 3C=8
BatchNorm across (N, H, W) — one statistic per channel.
Customize
Scheme
batchnorm
Tensor shape
4
8
4
4
GroupNorm
2
Chrome
Installation
npx shadcn@latest add https://craftbits.dev/r/normalization-viz.jsonUsage
import { NormalizationViz } from "@craft-bits/core";
<NormalizationViz defaultScheme="batchnorm" />Drive the active scheme from outside the component:
const [scheme, setScheme] = useState<NormalizationScheme>("layernorm");
<NormalizationViz scheme={scheme} onSchemeChange={setScheme} />Pin a specific tensor shape and GroupNorm split:
<NormalizationViz
defaultScheme="groupnorm"
tensorShape={{ batch: 2, channels: 6, height: 3, width: 3 }}
numGroups={3}
/>Hide the picker for a fully-controlled embed (e.g. an animated narration):
<NormalizationViz scheme="instancenorm" showSchemePicker={false} />Anatomy
- Cells, not numbers. The component renders empty cells — no activation values, no statistics readouts. The point of this primitive is the grouping, not the maths. Cells that share a colour share a
(mu, sigma)statistic; that's the entire signal. - Stack of samples. The tensor is laid out as one card per
n ∈ [0, batch). Each card containsCrows, one per channel. Each row is anH × Wmini-grid. The spatial order is preserved across scheme switches so the eye can track a single cell through every scheme. - Six-hue OKLCH palette. Group ids are hashed against
(220, 160, 30, 320, 270, 90)— six perceptually-spaced hues. The cycle is long enough to disambiguate common shapes; when group counts exceed six (e.g.InstanceNormon a large tensor) the structured group-id ordering still keeps adjacent groups visually distinct. - GroupNorm divisor clamping. If
numGroupsdoes not dividechannels, the component walksnumGroupsdownward to the next valid divisor so every group has the same width. The fallback is alwaysnumGroups=1(LayerNorm-on-the-channel-axis), which divides any positivechannels. SPRINGS.smoothon every cell. Switching schemes animatesbackgroundColorandborderColoron each cell withSPRINGS.smoothfrom@craft-bits/core/motion. The animation is the bridge that lets the learner see which cells regrouped.prefers-reduced-motion: reducecollapses every transition to an instant swap.- Controlled + uncontrolled.
schemefollows the Radixvalue/defaultValuepattern: passscheme+onSchemeChangeto drive externally, ordefaultSchemeto let the component own its own state. The picker is arole="radiogroup"; passshowSchemePicker={false}for a chrome-free embed.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
scheme | NormalizationScheme | — | Controlled active scheme. Pair with onSchemeChange. |
defaultScheme | NormalizationScheme | "batchnorm" | Uncontrolled initial scheme. |
onSchemeChange | (scheme) => void | — | Fires when the scheme changes. |
tensorShape | Partial<NormalizationTensorShape> | { batch: 4, channels: 8, height: 4, width: 4 } | 4D shape (N, C, H, W). Each dim clamped to a legible range. |
numGroups | number | 2 | Number of GroupNorm groups. Clamped to the next divisor of channels. |
showSchemePicker | boolean | true | Show the segmented scheme picker. |
showCaption | boolean | true | Show the footer caption explaining the active scheme. |
transition | Transition | SPRINGS.smooth | Spring for cell colour transitions. |
className | string | — | Merged onto the root <div> via cn(). |
Accessibility
- The root is
role="figure"witharia-labelledbynaming the chart "Normalization" and anaria-live="polite"summary announcing the active scheme, tensor shape, number of statistics, and reduction dimensions whenever the scheme changes. - The scheme picker is a
role="radiogroup"ofrole="radio"buttons witharia-checkedreflecting the active scheme — keyboard users tab into the group, and screen readers narrate the selection. - The tensor is a
role="list"ofrole="listitem"sample cards; each channel row carries anaria-labelof the formChannel n=X, c=Y, group Zso assistive tech can navigate one channel at a time. - Group identity is signalled by colour and the channel-row label includes the group id — no information depends on colour alone.
prefers-reduced-motion: reducecollapses every cell transition to an instant swap.
Credits
- Extracted from:
craftingattention(app/src/lessons/primitives/viz/NormalizationViz.tsx). The source coupled aModeStripexplore / predict toggle, a 6-roundusePredictRoundsquiz, aLabeledSliderpair for the learnableγ/βaffine parameters, a deterministic 8-element bar histogram with liveμ,σreadouts,ChallengeBtn/TogglePill/FeedbackBadge/ScoreDots/DoneCardchrome, and a per-sample noise sampler — all centred on the mathematics of one-dimensional normalization. The library version drops the predict mode, the bar chart, the affine sliders, the narration heuristics, and every piece of source-project chrome. Reframed as the primitive every modern-normalization lesson needs: the dimensions view — a stack of sample cards whose cells colour by(mu, sigma)group under each of BatchNorm / LayerNorm / GroupNorm / InstanceNorm. Replaced the raw--color-accent-*/--color-ink-*palette with six-hue OKLCH groups; switched to--cb-*tokens for chrome; clamped(channels, numGroups)to uniform divisors; exposed Radix controlled / uncontrolledscheme; added arole="radiogroup"picker witharia-checked; and gated every transition onprefers-reduced-motion. Sits in ML Viz → Regularization alongsideOverfittingGapViz,RunningStatsViz,VarianceCompoundViz,L2WeightDecayViz, andDropoutToggle.