mirror of
https://github.com/harvard-edge/cs249r_book.git
synced 2026-05-07 02:03:55 -05:00
feat(vault): add first visual-question exemplar + authoring guide
Seeds the visuals/ directory with a reference pattern so future authors have a concrete template to clone. Exemplar: Ring AllReduce on 4 ranks (cloud track, L3, apply/analyze). - SVG follows .claude/rules/svg-style.md: 680×460 viewBox, Helvetica Neue, compute-blue ranks, orthogonal ring arrows, 10-px grid. - YAML wires the visual block (kind=svg, path=cloud-visual-001.svg, alt + caption) and pairs it with a matching question: 'Using the diagram, calculate the total time to complete the full AllReduce.' - The realistic_solution walks through 2(N−1)/N × data / bw and explains the common failure mode (forgetting the all-gather phase). Napkin math shows the step-time decomposition. AUTHORING.md: the when/how/why guide for future visual questions. - When a visual earns its place — three criteria (ask requires the diagram, encodes info text cannot, static suffices). - High-value candidate topics — ring/tree AllReduce, roofline, KV cache, pipeline bubbles, memory hierarchy, MCU memory maps, systolic arrays, attention, MoE. - Step-by-step authoring workflow pointing at the book's SVG style guide for the visual system — readers already know the visual vocabulary from the book, so consistency transfers. - Accessibility requirements (non-negotiable): alt is enforced by the Pydantic schema, colour never the sole semantic channel, text in <text> elements not paths, WCAG AA contrast. - Explicit anti-patterns: no inline SVG in YAML, no mermaid for non-graph content, no decorative effects, no label duplication of scenario prose.
This commit is contained in:
52
interviews/vault/questions/cloud/cloud-visual-001.yaml
Normal file
52
interviews/vault/questions/cloud/cloud-visual-001.yaml
Normal file
@@ -0,0 +1,52 @@
|
||||
schema_version: '1.0'
|
||||
id: cloud-visual-001
|
||||
track: cloud
|
||||
level: L3
|
||||
zone: analyze
|
||||
topic: data-parallelism
|
||||
competency_area: parallelism
|
||||
bloom_level: apply
|
||||
phase: training
|
||||
title: Ring AllReduce Latency on 4 Ranks
|
||||
scenario: >-
|
||||
Four GPU ranks are participating in a Ring AllReduce to aggregate gradients
|
||||
after a training step. The gradient tensor is 400 MB in total, split evenly
|
||||
into 4 chunks of 100 MB each. Every inter-rank link runs at 200 GB/s. The
|
||||
ring passes chunks clockwise: each rank sends one chunk to the next rank
|
||||
while receiving a chunk from the previous rank.
|
||||
question: "Using the diagram, calculate the total time to complete the full AllReduce across all 4 ranks, and justify the formula you used."
|
||||
visual:
|
||||
kind: svg
|
||||
path: cloud-visual-001.svg
|
||||
alt: >-
|
||||
Four rank boxes arranged in a square: Rank 0 top-left, Rank 1 top-right,
|
||||
Rank 2 bottom-right, Rank 3 bottom-left. Clockwise arrows between adjacent
|
||||
ranks are labelled chunk 0 through chunk 3, each carrying 100 MB at
|
||||
200 GB/s. A legend below notes total gradient 400 MB, N equals 4 ranks,
|
||||
and that the full AllReduce comprises reduce-scatter plus all-gather.
|
||||
caption: Ring AllReduce on 4 ranks passing 100 MB chunks clockwise at 200 GB/s.
|
||||
details:
|
||||
realistic_solution: >-
|
||||
Total AllReduce time = 2(N−1)/N × data / bw = 2(3)/4 × 400 MB / 200 GB/s
|
||||
= 1.5 × 0.002 s = 3 ms. The Ring AllReduce has two phases: a reduce-scatter
|
||||
(each rank ends up owning a reduced shard) and an all-gather (each rank
|
||||
collects the full reduced tensor). Each phase completes in (N−1)/N × data
|
||||
/ bw = 1.5 ms, yielding 3 ms total. The key insight is that only one chunk
|
||||
(data/N = 100 MB) traverses each link per step, so wall-time is set by
|
||||
the number of steps (2(N−1) = 6) times step-time (100 MB / 200 GB/s = 0.5 ms).
|
||||
common_mistake: >-
|
||||
Dividing the full 400 MB gradient by 200 GB/s to get 2 ms misses that
|
||||
Ring AllReduce requires 2(N−1) = 6 sequential steps, not one. Alternatively,
|
||||
some learners compute (N−1)/N × data / bw = 1.5 ms and forget to double
|
||||
it for the all-gather phase, giving 1.5 ms instead of 3 ms. The 2(N−1)/N
|
||||
factor captures both the parallelism benefit (only 1/N of data per step)
|
||||
and the phase count.
|
||||
napkin_math: >-
|
||||
data = 400 MB, N = 4, bw = 200 GB/s. Step time = (data/N)/bw =
|
||||
100 MB / 200 GB/s = 0.5 ms. Reduce-scatter takes N−1 = 3 steps = 1.5 ms.
|
||||
All-gather also takes N−1 = 3 steps = 1.5 ms. Total = 3 ms.
|
||||
status: draft
|
||||
provenance: llm-draft
|
||||
expected_time_minutes: 5
|
||||
requires_explanation: false
|
||||
validated: false
|
||||
115
interviews/vault/visuals/AUTHORING.md
Normal file
115
interviews/vault/visuals/AUTHORING.md
Normal file
@@ -0,0 +1,115 @@
|
||||
# Authoring visual questions
|
||||
|
||||
StaffML questions can optionally attach a diagram. The practice page renders
|
||||
it between the scenario prose and the answer textarea, and the `question`
|
||||
field always stays sticky at the top — reading flow is **scenario →
|
||||
diagram → answer**.
|
||||
|
||||
Use visuals sparingly. A good visual earns its place; a bad one is
|
||||
noise that slows the reader down.
|
||||
|
||||
## When a visual earns its place
|
||||
|
||||
A visual earns its place when **all three** hold:
|
||||
|
||||
1. **The ask requires reading the diagram.** If the question can be
|
||||
answered from the scenario alone, the visual is decorative — omit it.
|
||||
2. **The visual encodes information that text cannot.** Topology,
|
||||
memory layouts, roofline curves, pipeline timelines, dataflow —
|
||||
things where spatial structure *is* the payload.
|
||||
3. **A static image suffices.** Animation, interactivity, and
|
||||
multi-step reveals are out of scope.
|
||||
|
||||
### High-value candidate topics
|
||||
|
||||
Target these first; each one repeats across many chain positions, so
|
||||
one good diagram earns its keep across dozens of questions.
|
||||
|
||||
- Ring / tree AllReduce topologies (show the ring, ask for latency)
|
||||
- Parameter-server vs. AllReduce dataflow
|
||||
- Roofline diagrams with workload points plotted
|
||||
- KV-cache growth vs. sequence length
|
||||
- Pipeline parallelism bubble / Gantt charts
|
||||
- Memory hierarchy: HBM + SRAM + host DRAM + disk
|
||||
- TinyML MCU memory map (flash + SRAM + model footprint)
|
||||
- Systolic array dataflow (weight-stationary vs. output-stationary)
|
||||
- Attention computation graph (Q·Kᵀ then softmax then ·V)
|
||||
- MoE all-to-all shuffle topology
|
||||
|
||||
## Authoring workflow
|
||||
|
||||
1. **Draft the SVG** following `.claude/rules/svg-style.md` (the book's
|
||||
SVG system). Non-negotiables:
|
||||
- `viewBox="0 0 680 460"` default (widen only when content demands).
|
||||
- `font-family="Helvetica Neue, Helvetica, Arial, sans-serif"` on
|
||||
the root `<svg>`.
|
||||
- Semantic palette — compute blue `#cfe2f3`/`#4a90c4`, data green
|
||||
`#d4edda`/`#3d9e5a`, routing orange `#fdebd0`/`#c87b2a`, error
|
||||
red `#f9d6d5`/`#c44`, MIT red accent `#a31f34`.
|
||||
- Orthogonal routing (no diagonals except genuine topology diagrams).
|
||||
- Arrows anchor at box edges, route around obstacles with ≥10px
|
||||
clearance.
|
||||
- Integer coordinates on a 10-px grid.
|
||||
- Text in `<text>` elements (not paths) — selectable + accessible.
|
||||
2. **Save** to `interviews/vault/visuals/<track>/<id>.svg` where
|
||||
`<track>` matches the question's track (cloud, edge, mobile, tinyml,
|
||||
global) and `<id>` matches the question's YAML id. Bare filename
|
||||
only — no subdirectories, no path traversal.
|
||||
3. **Add the `visual:` block** to the matching YAML:
|
||||
```yaml
|
||||
visual:
|
||||
kind: svg
|
||||
path: <id>.svg
|
||||
alt: >-
|
||||
Full accessibility description — objective, concrete, ≤400
|
||||
chars. Describe what the diagram SHOWS, not why it matters.
|
||||
caption: "Short caption rendered below the figure. ≤120 chars. Optional."
|
||||
```
|
||||
4. **Build** — `vault build --legacy-json`. This copies the SVG to
|
||||
`interviews/staffml/public/question-visuals/<track>/` and surfaces
|
||||
the `visual` metadata in the corpus bundle.
|
||||
5. **Preview** at `/practice?q=<id>` on the dev server.
|
||||
|
||||
## Reference exemplar
|
||||
|
||||
`cloud/cloud-visual-001.yaml` + `cloud/cloud-visual-001.svg` — Ring
|
||||
AllReduce on 4 ranks. Diagram shows the ring topology + chunk labels +
|
||||
bandwidth annotations; scenario gives concrete numbers; question asks
|
||||
for the total AllReduce time. Solution walks through the
|
||||
2(N−1)/N × data / bw formula. Copy this pattern.
|
||||
|
||||
## Accessibility requirements (non-negotiable)
|
||||
|
||||
- **`alt` is required** and is enforced by the schema. A visual
|
||||
without alt fails Pydantic validation; `vault build` will reject it.
|
||||
- Colour is never the sole semantic channel — pair colour with label
|
||||
text, line style, or shape. A colour-blind reader must still be able
|
||||
to parse the diagram.
|
||||
- Text in SVG `<text>` elements (not baked into paths) so it's
|
||||
selectable and screen-reader friendly.
|
||||
- WCAG AA contrast on any label over a coloured fill: `#333` text on
|
||||
`#cfe2f3` compute-blue passes; `#999` text on the same fill fails.
|
||||
|
||||
## Anti-patterns to reject
|
||||
|
||||
- Inline `<svg>` markup inside YAML. The schema's `path` field is a
|
||||
bare filename — path traversal is rejected. Use the file-reference
|
||||
pattern.
|
||||
- Mermaid source for anything other than simple node-edge graphs. The
|
||||
renderer MVP supports SVG only; `kind: mermaid` is reserved for a
|
||||
future inline-text path and is currently a no-op.
|
||||
- Label text that duplicates the scenario prose. The diagram should
|
||||
encode *additional* information, not restate the scenario.
|
||||
- Decorative gradients, fake 3-D, beveled edges, drop shadows. Every
|
||||
mark earns its place (Tufte's data-ink principle — see the SVG
|
||||
style guide for the full chart-junk policy).
|
||||
- Icons or emoji in the SVG. Use neutral shapes + labels.
|
||||
- Watermarks, signatures, tool branding. The caption handles attribution.
|
||||
|
||||
## Build artifacts
|
||||
|
||||
The directory `interviews/staffml/public/question-visuals/` is a
|
||||
build output (written by `copy_visual_assets` during `vault build
|
||||
--legacy-json`). Source files live under `interviews/vault/visuals/`.
|
||||
Do not edit the build output directly — changes will be overwritten
|
||||
on the next build.
|
||||
68
interviews/vault/visuals/cloud/cloud-visual-001.svg
Normal file
68
interviews/vault/visuals/cloud/cloud-visual-001.svg
Normal file
@@ -0,0 +1,68 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 680 460"
|
||||
font-family="Helvetica Neue, Helvetica, Arial, sans-serif">
|
||||
<rect width="680" height="460" fill="#fff" rx="4"/>
|
||||
|
||||
<defs>
|
||||
<marker id="arrow" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
|
||||
<path d="M0,0 L8,3 L0,6 Z" fill="#555"/>
|
||||
</marker>
|
||||
</defs>
|
||||
|
||||
<!-- ===== Title ===== -->
|
||||
<text x="340" y="32" text-anchor="middle" font-size="13" font-weight="700" fill="#333">
|
||||
Ring AllReduce — 4 ranks, one reduce-scatter step
|
||||
</text>
|
||||
|
||||
<!-- ===== Ranks (compute blue) ===== -->
|
||||
<!-- Rank 0: top-left -->
|
||||
<rect x="110" y="110" width="140" height="80" rx="4"
|
||||
fill="#cfe2f3" stroke="#4a90c4" stroke-width="1.5"/>
|
||||
<text x="180" y="156" text-anchor="middle" font-size="12" font-weight="700" fill="#333">Rank 0</text>
|
||||
|
||||
<!-- Rank 1: top-right -->
|
||||
<rect x="430" y="110" width="140" height="80" rx="4"
|
||||
fill="#cfe2f3" stroke="#4a90c4" stroke-width="1.5"/>
|
||||
<text x="500" y="156" text-anchor="middle" font-size="12" font-weight="700" fill="#333">Rank 1</text>
|
||||
|
||||
<!-- Rank 2: bottom-right -->
|
||||
<rect x="430" y="290" width="140" height="80" rx="4"
|
||||
fill="#cfe2f3" stroke="#4a90c4" stroke-width="1.5"/>
|
||||
<text x="500" y="336" text-anchor="middle" font-size="12" font-weight="700" fill="#333">Rank 2</text>
|
||||
|
||||
<!-- Rank 3: bottom-left -->
|
||||
<rect x="110" y="290" width="140" height="80" rx="4"
|
||||
fill="#cfe2f3" stroke="#4a90c4" stroke-width="1.5"/>
|
||||
<text x="180" y="336" text-anchor="middle" font-size="12" font-weight="700" fill="#333">Rank 3</text>
|
||||
|
||||
<!-- ===== Ring arrows (clockwise) ===== -->
|
||||
<!-- R0 → R1 (top edge) -->
|
||||
<line x1="252" y1="150" x2="428" y2="150" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
|
||||
<text x="340" y="140" text-anchor="middle" font-size="10" font-weight="700" fill="#333">chunk 0</text>
|
||||
<text x="340" y="172" text-anchor="middle" font-size="9" fill="#555">100 MB @ 200 GB/s</text>
|
||||
|
||||
<!-- R1 → R2 (right edge) -->
|
||||
<line x1="500" y1="192" x2="500" y2="288" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
|
||||
<text x="514" y="234" text-anchor="start" font-size="10" font-weight="700" fill="#333">chunk 1</text>
|
||||
<text x="514" y="250" text-anchor="start" font-size="9" fill="#555">100 MB @ 200 GB/s</text>
|
||||
|
||||
<!-- R2 → R3 (bottom edge) -->
|
||||
<line x1="428" y1="330" x2="252" y2="330" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
|
||||
<text x="340" y="322" text-anchor="middle" font-size="10" font-weight="700" fill="#333">chunk 2</text>
|
||||
<text x="340" y="352" text-anchor="middle" font-size="9" fill="#555">100 MB @ 200 GB/s</text>
|
||||
|
||||
<!-- R3 → R0 (left edge) -->
|
||||
<line x1="180" y1="288" x2="180" y2="192" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
|
||||
<text x="166" y="234" text-anchor="end" font-size="10" font-weight="700" fill="#333">chunk 3</text>
|
||||
<text x="166" y="250" text-anchor="end" font-size="9" fill="#555">100 MB @ 200 GB/s</text>
|
||||
|
||||
<!-- ===== Context legend ===== -->
|
||||
<rect x="190" y="395" width="300" height="40" rx="5"
|
||||
fill="#f7f7f7" stroke="#bbb" stroke-width="1"/>
|
||||
<text x="340" y="412" text-anchor="middle" font-size="10" font-weight="700" fill="#333">
|
||||
Total gradient: 400 MB · N = 4 ranks · 200 GB/s links
|
||||
</text>
|
||||
<text x="340" y="426" text-anchor="middle" font-size="9" fill="#555">
|
||||
Full AllReduce = reduce-scatter (N−1 steps) + all-gather (N−1 steps)
|
||||
</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.4 KiB |
Reference in New Issue
Block a user