LoRA Rank Explorer
Plot how the reconstruction quality of W ≈ B·A varies with the LoRA rank r. The y-axis is the reconstruction residual ||W − Bᵣ·Aᵣ||; the x-axis is r ∈ [1, min(rows, cols)]. Drag the slider and watch the marker walk along the curve — as r grows, the rank-r approximation approaches W, and the curve makes that approach legible.
Different from LoRaFactorizationViz, which renders the factorization geometrically as three blocks (ΔW = B · A). LoRaRankExplorer plots reconstruction quality — same idea, different lens.
LoRA rank explorer: reconstruction error vs rank curve.LoRA reconstruction curve. Target is 8×8. Frobenius residual at r=1: 4.572.
Reconstruction vs rank8×8 · Frobenius · r=1
1
- Frobenius residual
- 4.572
- captured energy
- 90.8%
Customize
Rank
1
Metric
Installation
npx shadcn@latest add https://craftbits.dev/r/lora-rank-explorer.jsonUsage
import { LoRaRankExplorer } from "@craft-bits/core";
<LoRaRankExplorer defaultR={1} />Provide your own target matrix W:
<LoRaRankExplorer
targetMatrix={[
[4, 3, 2, 1],
[3, 2, 1, 0],
[2, 1, 0, -1],
[1, 0, -1, -2],
]}
defaultR={1}
/>Drive the rank from outside the component:
const [r, setR] = useState(2);
<LoRaRankExplorer r={r} onRChange={setR} />Switch to the spectral metric for a sharper "step" curve when W has a few dominant directions:
<LoRaRankExplorer metric="spectral" defaultR={1} />Understanding the component
- One curve, one slider. Each x-tick is an integer rank. Each y-value is the reconstruction residual at that rank — the gap between
Wand its best rank-rapproximationWᵣ = Bᵣ · Aᵣ. The marker dot and the dashed vertical cursor mark the currentr. Drag the slider, the marker walks along the curve. - Curve shape tells the LoRA story. The default synthetic target has two dominant singular directions plus low-amplitude noise — the curve drops sharply through
r = 1, 2, then plateaus. That's the "you only need a handful of ranks" lesson in a single picture. Hand it a differenttargetMatrixand the curve tells a different story (a noise-y matrix decays slowly; a clean rank-kmatrix hits zero atr = k). - Two metrics, one picture.
metric="frobenius"plots||W − Wᵣ||_F = sqrt(Σⱼ>ᵣ σⱼ²)— total squared residual energy.metric="spectral"plotsσ_{r+1}directly — the largest singular value of the residual, per Eckart–Young. Spectral curves drop in visible "steps" between each σⱼ; Frobenius curves are smoother. - Captured-energy readout. Below the curve, a
Σⱼ≤ᵣ σⱼ² / ||W||_F²panel renders the fraction of the matrix's energy the rank-rapproximation captures. The number stays meaningful in both metrics — it always answers "how much ofWdoes rank-rreproduce?" - Pure / deterministic math. Truncated SVD via seeded power-iteration deflation. Same
targetMatrixalways produces the same curve — no Math.random, no hydration drift. Singular values are computed once pertargetMatrix; the curve isO(rMax)after that. - Controlled + uncontrolled. Pass
r+onRChangeto drive the rank from a parent; omit them and the component owns its own state viadefaultR. The rank clamps to[1, min(rows, cols)]. - Reduced motion. When
prefers-reduced-motion: reduceis set, the cursor + marker springs collapse toduration: 0— they jump to the new position instead of springing.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
targetMatrix | readonly (readonly number[])[] | synthetic 8×8 | The matrix W the rank-r factorization approximates. Rows must be the same length; non-finite values fall back to the synthetic default. |
r | number | — | Controlled rank. Pair with onRChange. Clamps to [1, min(rows, cols)]. |
defaultR | number | 1 | Uncontrolled initial rank. |
onRChange | (r) => void | — | Fires when the rank changes. |
metric | 'frobenius' | 'spectral' | 'frobenius' | Reconstruction-quality norm. Frobenius is sqrt(Σⱼ>ᵣ σⱼ²); spectral is σ_{r+1}. |
transition | Transition | SPRINGS.snap | Spring for the marker + cursor. Curve animation always uses SPRINGS.smooth. |
className | string | — | Merged onto the root via cn(). |
Accessibility
- The root is
role="figure"with a visually-hiddenaria-live="polite"summary that re-announces the metric and the current residual wheneverrchanges. - The rank slider is a native
<input type="range">viaLabeledSlider— keyboard arrows, screen-reader value announcements, and:focus-visiblerings come for free. - The plot uses
role="img"with a labelledaria-labelledbyso SVG-aware screen readers describe the figure. - Color is never the only signal — every axis carries a label (
rank r,‖W − BA‖_F/σ_{r+1}) and the readout panel renders the numbers infont-variant-numeric: tabular-nums. prefers-reduced-motion: reducecollapses every spring to an instant swap.
Credits
- Extracted from:
craftingattention(app/src/lessons/primitives/viz/LoRaRankExplorer.tsx). The source was a lesson-mode widget withWidgetchrome (undo/redo history, bookmarks, formula bar), an Explore / Predict / Challenge ModeStrip with quiz rounds and challenge progression, three side-by-side heatmaps (frozen W, A·B update, merged W + α·A·B), an alpha-scaling knob, and a hard-coded6 × 6target plus frozen matrix. The library extract is the pure rank-vs-reconstruction primitive — one curve, one slider, two metrics, a captured-energy readout. The modes, heatmaps, alpha control, and lesson scaffolding live in the consuming lesson, not the primitive.