Foundations Isle: fastbook ch.13–20 (CNNs, ResNets, optimizers, from-scratch Learner)#6
Foundations Isle: fastbook ch.13–20 (CNNs, ResNets, optimizers, from-scratch Learner)#6CodeWithOz wants to merge 3 commits into
Conversation
…, from-scratch Learner) Adds a new landmass south of the Frontier, reached by ferry, covering the final eight chapters. Same digits, seen deeper: everything trains live. Engine: conv2d / adaptive avg pool / batchnorm with real backward passes (feature maps as [batch, C*H*W]); Momentum / RMSProp / Adam / grouped-SGD to the book's formulas. All finite-difference gradient-checked. Scenarios: the book's simple_cnn; a residual net racing a skipless twin (identity-init blocks); a four-optimizer derby on one lr dial; a siamese pair-matcher whose encoder is cut from the trained CNN; a from-scratch MiniLearner with an event/callback loop and a NaN guard. World: ferry + sea (no bridge), island landmass (MAP_H→106), sand/dock tiles, a sweeping lighthouse beacon, tour stops 22–30, ~25 inspection panels. README/AGENTS updated; 54 tests pass. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- BatchNorm running stats now advance once per step: the base trainStep's recorded display pass no longer folds into them (stats=null on record). - Momentum Desk reads the moving average straight from the live optimizer after step() instead of re-deriving the update rule (every-number-real). - MiniLearner.reset() also restarts loop counters (stepsDone, epochsDone, eventCounts, lastTrace) so the Callback Rack's reset button truly resets. - Removed 4 chapter-number leaks from in-world panel copy (residual, saliency, atelier, learnerhall). - Fixed the siamese logits label order (index 0 = different, 1 = same). - Momentum Desk looks the racer up by type, not a fixed index. - Guarded the Stability Observatory against an empty actStats. - Documented that Adam deliberately follows the book's simplified form (first-moment debias only, eps inside the sqrt), not the canonical paper. Added regression assertions for the reset and momentum-read fixes. All 54 tests pass; build clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
dl-world | bbd1f45 | Commit Preview URL Branch Preview URL |
Jul 06 2026, 01:21 PM |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (6)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (4)
WalkthroughThis PR adds convolution and optimizer primitives to the tensor engine, introduces new training scenarios and learner callbacks, expands the world with a ferry-connected island and new buildings, adds educational UI panels, and updates documentation and tests. ChangesFoundations Isle Feature
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)sequenceDiagram
participant Player
participant Game
participant City
Player->>Game: interact near ferry pier
Game->>City: ferryAt(tx, ty)
City-->>Game: island / mainland / null
Game->>Game: startFerry(dest), mode="boat"
Game->>Game: render() draws ferry hull during crossing
sequenceDiagram
participant LearnerLab
participant MiniLearner
participant LabCallback
participant SGD
LearnerLab->>MiniLearner: oneBatch()
MiniLearner->>LabCallback: fire before_batch
MiniLearner->>MiniLearner: buildLoss() / forward
MiniLearner->>SGD: backward + step()
LabCallback-->>MiniLearner: CancelFitException on NaN loss
MiniLearner->>LabCallback: fire after_batch / after_cancel_fit
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (4)
tests/engine.test.ts (1)
243-254: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd a gradient check for
batchNormeval-mode backward.
batchNormhas two distinct backward branches (training stats vs. the eval-mode affine map at conv.ts Lines 274-283). Only the training branch is gradient-checked (Line 236); the eval branch is exercised for forward output only here, leaving its backward unverified.💚 Suggested eval-mode gradCheck
it("batchNorm eval mode uses running stats", () => { const stats = makeBnStats(1, 1); // momentum 1: running stats = last batch stats const gamma = Tensor.fromArray([2]); const beta = Tensor.fromArray([1]); const xTrain = Tensor.fromArray([0, 2, 4, 6], [4, 1]); batchNorm(xTrain, gamma, beta, 1, stats, true); expect(stats.runMean[0]).toBeCloseTo(3, 5); const xEval = Tensor.fromArray([3], [1, 1]); const yEval = batchNorm(xEval, gamma, beta, 1, stats, false); // (3-3)/std*2 + 1 = 1 expect(yEval.data[0]).toBeCloseTo(1, 4); + // eval-mode backward is an affine map through frozen stats — verify it + const xg = Tensor.randn([3, 2 * 2], 1, rand); + const gg = Tensor.randn([2], 0.5, rand); + const bg = Tensor.randn([2], 0.5, rand); + const evalStats = makeBnStats(2, 1); + evalStats.runMean.set([0.2, -0.1]); + evalStats.runVar.set([1.3, 0.8]); + gradCheck((inp) => mean(mul(batchNorm(inp[0], inp[1], inp[2], 2, evalStats, false), inp[0])), [xg, gg, bg]); });As per path instructions: "Any new engine operation must have a finite-difference gradient check using the existing
gradCheckhelper, and backward functions must match the clamped/actual forward behavior."🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/engine.test.ts` around lines 243 - 254, Add a finite-difference gradient check for the eval-mode backward path of batchNorm in the engine tests. Extend the existing batchNorm coverage in tests/engine.test.ts to call the same `gradCheck` helper on the eval branch (the `batchNorm` path that uses running stats and the affine map), and verify its gradients against the forward behavior. Keep the current training-mode check, but add a separate eval-mode case so both branches of `batchNorm` are validated.Source: Path instructions
src/ui/panels/atelier.ts (1)
225-235: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
digit14is a byte-for-byte duplicate of the same helper insrc/ui/panels/saliency.ts(lines 16-26).Both compute a 2×2-average-pooled 14×14 downsample of a 28×28 test image with identical logic. Worth extracting to a shared helper (e.g.
common.ts) so the two copies can't drift.♻️ Proposed extraction
+// src/ui/panels/common.ts +export function digit14(world: World, i: number): Float32Array { + const out = new Float32Array(196); + const imgs = world.data.testImages; + const off = i * 784; + for (let r = 0; r < 14; r++) + for (let c = 0; c < 14; c++) { + const o = off + r * 2 * 28 + c * 2; + out[r * 14 + c] = (imgs[o] + imgs[o + 1] + imgs[o + 28] + imgs[o + 29]) / 4 / 255; + } + return out; +}Then import it in both
atelier.tsandsaliency.tsinstead of the local copies.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/ui/panels/atelier.ts` around lines 225 - 235, The digit14 helper is duplicated in both atelier.ts and saliency.ts, so extract the shared 14x14 downsampling logic into a common helper (for example in common.ts) and update both digit14 call sites to import and use that shared function. Keep the existing behavior and signature consistent by preserving the World/testImages-based pooling logic in the shared helper and removing the local copies.src/sim/learner.ts (1)
221-228: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueCancelFit attribution is hard-coded to
TerminateOnNaN.If a future callback throws
CancelFitException, the catch block always searches for an enabledTerminateOnNaNand reports that as the canceller (by), which would be wrong. Today onlyTerminateOnNaNthrows so this is latent, but attributing by the actual raising callback would be more robust.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/sim/learner.ts` around lines 221 - 228, The CancelFitException handling in learner.ts is attributing cancellation to a hard-coded TerminateOnNaN callback, which is too narrow. Update the catch block in the fit flow to identify the actual callback that raised the exception instead of always searching for TerminateOnNaN, and use that callback’s name when setting this.cancelled.by. If needed, thread the throwing callback identity through CancelFitException or the callback invocation path so the attribution in the cancel handling remains correct for any future callback.tests/island.test.ts (1)
71-81: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueLoss-reduction assertion may be flaky.
late/8 < early/8after only 8+24+8 heavy conv steps on a tiny batch (12) can occasionally fail on adverse batch draws even when training is healthy. Averaging windows help but don't eliminate it. Consider a small tolerance (e.g.late/8 < early/8 * 1.0→< early/8 - epsis stricter; instead assertlate/8 <= early/8), or seed-fix the loader for determinism. Low priority given the fixed data seed already in the scenario.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/island.test.ts` around lines 71 - 81, The training-loss test in ConvNet is too brittle because the `expect(late / 8).toBeLessThan(early / 8)` assertion can fail on normal batch variance even when `trainStep()` is working. Update the `reduces its training loss over a short run` test in `tests/island.test.ts` to use a non-flaky check, either by adding a small tolerance around the comparison or by relaxing it to an inclusive/seeded deterministic assertion tied to `ConvNet` and its `trainStep()` loop.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@src/sim/learner.ts`:
- Around line 221-228: The CancelFitException handling in learner.ts is
attributing cancellation to a hard-coded TerminateOnNaN callback, which is too
narrow. Update the catch block in the fit flow to identify the actual callback
that raised the exception instead of always searching for TerminateOnNaN, and
use that callback’s name when setting this.cancelled.by. If needed, thread the
throwing callback identity through CancelFitException or the callback invocation
path so the attribution in the cancel handling remains correct for any future
callback.
In `@src/ui/panels/atelier.ts`:
- Around line 225-235: The digit14 helper is duplicated in both atelier.ts and
saliency.ts, so extract the shared 14x14 downsampling logic into a common helper
(for example in common.ts) and update both digit14 call sites to import and use
that shared function. Keep the existing behavior and signature consistent by
preserving the World/testImages-based pooling logic in the shared helper and
removing the local copies.
In `@tests/engine.test.ts`:
- Around line 243-254: Add a finite-difference gradient check for the eval-mode
backward path of batchNorm in the engine tests. Extend the existing batchNorm
coverage in tests/engine.test.ts to call the same `gradCheck` helper on the eval
branch (the `batchNorm` path that uses running stats and the affine map), and
verify its gradients against the forward behavior. Keep the current
training-mode check, but add a separate eval-mode case so both branches of
`batchNorm` are validated.
In `@tests/island.test.ts`:
- Around line 71-81: The training-loss test in ConvNet is too brittle because
the `expect(late / 8).toBeLessThan(early / 8)` assertion can fail on normal
batch variance even when `trainStep()` is working. Update the `reduces its
training loss over a short run` test in `tests/island.test.ts` to use a
non-flaky check, either by adding a small tolerance around the comparison or by
relaxing it to an inclusive/seeded deterministic assertion tied to `ConvNet` and
its `trainStep()` loop.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 5ec6a192-07c2-48c1-82cf-cf4b21aead10
📒 Files selected for processing (27)
AGENTS.mdREADME.mdsrc/engine/conv.tssrc/engine/optim.tssrc/engine/tensor.tssrc/main.tssrc/sim/learner.tssrc/sim/scenarios.tssrc/sim/scenarios3.tssrc/sim/trainer.tssrc/sim/world.tssrc/ui/panels/atelier.tssrc/ui/panels/beacon.tssrc/ui/panels/convworks.tssrc/ui/panels/index.tssrc/ui/panels/institute.tssrc/ui/panels/kernels.tssrc/ui/panels/learnerhall.tssrc/ui/panels/quarry.tssrc/ui/panels/residual.tssrc/ui/panels/saliency.tssrc/ui/widgets.tssrc/world/buildings.tssrc/world/city.tssrc/world/game.tstests/engine.test.tstests/island.test.ts
…, test coverage) - CancelFitException now carries the name of the callback that raised it, stamped in MiniLearner.call(), so the "halted by" attribution is correct for any callback instead of a hardcoded TerminateOnNaN lookup. - Extracted the duplicated 14×14 downsample helper (digit14) into panels/common.ts; the Saliency Lighthouse and Architecture Atelier now share it. - Added a finite-difference gradient check for batchNorm's eval-mode backward path (running stats + affine map), which the training-mode check didn't cover. 55 tests pass; build clean; panels + NaN-guard attribution verified in preview. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
What this adds
A new landmass — the Foundations Isle, reached by ferry across a new sea south of the Frontier — extending DL World from fastbook ch.4–12 through ch.13–20. Same MNIST digits, seen deeper: everything trains live, in the same spirit as the existing city.
Chapter → in-world mapping (concept-first names; the chapter map lives only in the README):
simple_cnnlearning its own kernels, feature-map floor, receptive-field tracing, the "colorful dimension" stability plot with a batchnorm switch)x + f(x)racing a skipless twin) + Saliency Lighthouse (CAM / Grad-CAM shining a light back through the live model)Engine
src/engine/conv.ts—conv2d, adaptive average pooling, batchnorm with real backward passes (feature maps stored as[batch, C·H·W]), plus im2col / upsample / transposed-conv demo helperssrc/engine/optim.ts— Momentum / RMSProp / Adam / grouped-SGD to the book's formulastests/engine.test.tsWorld
MAP_H→ 106), sand/dock tiles, a sweeping lighthouse beacon, tour stops ㉒–㉚, and ~25 new inspection panelsWorld(convnet, resnet, optrace, siamese, learnerlab)Reviewer notes
epsinside the sqrt), not the canonical paper — matching the vendored chapter is the project's governing rule (AGENTS.md). A code comment flags this so it isn't "corrected" later.Verification
npm test— 54 passing (engine gradient checks + island smoke/property tests, including regression assertions for the review fixes)npm run build— clean (tsc + vite)🤖 Generated with Claude Code
Summary by CodeRabbit