Skip to content

Commit 08db020

Browse files
apartsinclaude
andcommitted
Add 48 illustrations across 8 chapters, fix low-value code fragments, add code caption detection
Illustrations: Generate and embed 48 new illustrations in chapters 8, 23-26, 34-35, and 36-38 (Part XI). Chapters that had 0 illustrations now have 5-6 each. Part XI chapters gain 9 additional non-opener illustrations. Code quality: Merge or replace 5 low-value code fragments (36.2.1, 36.3.1, 22.6.1, 7.4.4, 13.2.6) that were pure definitions without AI library usage. Update code pedagogy agent with "Value Gate" rule requiring every code fragment to demonstrate an AI/ML technique. Update illustrator agent with Gemini batch API instructions. Code captions: Add 658 placeholder captions to uncaptioned code blocks across 189 section files. Create detection scripts for low-value code and missing captions (scripts/detect/). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 881b96b commit 08db020

266 files changed

Lines changed: 1846 additions & 482 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

agents/08-code-pedagogy.html

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,36 @@ <h3 id="3-pedagogical-effectiveness">3. Pedagogical Effectiveness</h3>
4343
<li>Variable names should be descriptive and match the prose terminology</li>
4444
<li>Code should be minimal: remove everything that does not serve the teaching goal</li>
4545
</ul>
46-
<h3 id="4-progressive-complexity">4. Progressive Complexity</h3>
46+
<h3 id="4-value-gate">4. Value Gate: Every Code Fragment Must Earn Its Place</h3>
47+
<p><strong>A code fragment that does not solve a specific task, demonstrate a library function, or produce a meaningful output should not exist.</strong> Defining a dataclass, configuration object, or data structure is not a code example; it is a schema. If the code only declares something without <em>doing</em> anything with it, either:</p>
48+
<ul>
49+
<li><strong>Merge it</strong> into the next code fragment that actually uses it, so the reader sees definition and usage together.</li>
50+
<li><strong>Replace it</strong> with a code fragment that demonstrates the concept in action (input, processing, output).</li>
51+
<li><strong>Remove it</strong> entirely if the prose or a callout box conveys the same information more efficiently.</li>
52+
</ul>
53+
<p>Ask: "If I ran this code, would I learn something from the output?" If the answer is "it just prints a summary of what I typed in," the fragment fails the value gate.</p>
54+
<p><strong>Signs of a low-value code fragment:</strong></p>
55+
<ul>
56+
<li>The entire block is a class/dataclass/enum definition with no usage</li>
57+
<li>The only "output" is printing what was hardcoded in the input</li>
58+
<li>The code restates in Python what the prose already explains in English</li>
59+
<li>No library, algorithm, or technique is being demonstrated</li>
60+
<li>Removing the code fragment would not reduce the reader's understanding</li>
61+
</ul>
62+
<p><strong>This book is about LLMs and AI.</strong> Every code fragment must involve AI/ML libraries, LLM API calls, prompt engineering, evaluation, embeddings, tokenization, fine-tuning, agent logic, or similar AI-relevant functionality. Code that is purely organizational (form-filling dataclasses, business logic scorecards, project management checklists, configuration dicts with no library calls) does not belong as a standalone code fragment. Either:</p>
63+
<ul>
64+
<li><strong>Merge it</strong> into a fragment that actually calls an AI library or API, so the definition and AI usage appear together.</li>
65+
<li><strong>Replace it with prose</strong>: a table, callout box, or bullet list often conveys configuration and schema better than a Python dict literal.</li>
66+
<li><strong>Delete it</strong> if the surrounding text already covers the same information.</li>
67+
</ul>
68+
<p><strong>Concrete test:</strong> "Does this code fragment import or call anything from an AI/ML library, or demonstrate a technique specific to AI systems?" If no, it fails the gate.</p>
69+
<h3 id="5-progressive-complexity">5. Progressive Complexity</h3>
4770
<ul>
4871
<li>First code example in a section: simple, 5 to 10 lines</li>
4972
<li>Later examples: build on earlier ones, add one new element at a time</li>
5073
<li>Final example: brings it together, realistic but not overwhelming</li>
5174
</ul>
52-
<h3 id="5-reproducibility">5. Reproducibility</h3>
75+
<h3 id="6-reproducibility">6. Reproducibility</h3>
5376
<ul>
5477
<li>Pin library versions in requirements or comments</li>
5578
<li>Use deterministic seeds for random operations</li>

agents/31-illustrator.html

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,35 @@ <h3 id="step-2-prompt">Step 2: Craft the Gemini Prompt</h3>
8484
<h3 id="step-3-generate">Step 3: Generate the Image</h3>
8585
<p><strong>FIRST</strong>, create the images directory (this MUST run before any generation):</p>
8686
<pre><code class="language-bash">mkdir -p "{module-folder}/images"</code></pre>
87-
<p><strong>THEN</strong> run the generation script:</p>
87+
88+
<h4>Single Image (one-off generation)</h4>
8889
<pre><code class="language-bash">python "C:/Users/apart/.claude/skills/gemini-imagegen/scripts/generate_image.py" \
8990
--prompt "[your crafted prompt]" \
9091
--output "{module-folder}/images/{descriptive-filename}.png" \
9192
--aspect-ratio 4:3 \
9293
--image-size 1K</code></pre>
9394

95+
<h4>Batch Mode (PREFERRED for 2+ images, 50% cost discount)</h4>
96+
<p>When generating multiple illustrations (e.g., for a full chapter pass or book-wide sweep), <strong>always use Gemini batch API mode</strong>. This provides a 50% cost reduction and processes all images in parallel.</p>
97+
<ol>
98+
<li>Create a JSON file with all illustration prompts:
99+
<pre><code class="language-json">[
100+
{
101+
"name": "descriptive-id",
102+
"prompt": "Simple, cartoon-like educational illustration...",
103+
"output": "relative/path/to/images/filename.png"
104+
}
105+
]</code></pre>
106+
</li>
107+
<li>Run the batch generation script:
108+
<pre><code class="language-bash">python "C:/Users/apart/.claude/skills/book-skills/scripts/generate_icons_gemini.py" \
109+
--engine gemini \
110+
--batch \
111+
--input prompts.json</code></pre>
112+
</li>
113+
</ol>
114+
<p><strong>IMPORTANT:</strong> Output paths in the JSON are resolved relative to the current working directory. Run the script from the book root (<code>E:/Projects/LLMCourse</code>) so paths like <code>part-X/module-Y/images/file.png</code> resolve correctly.</p>
115+
94116
<h3 id="step-4-embed">Step 4: Embed in HTML</h3>
95117
<p>Insert a <code>&lt;figure&gt;</code> block at the identified location:</p>
96118
<pre><code class="language-html">&lt;figure class="illustration"&gt;

part-1-foundations/module-00-ml-pytorch-foundations/section-0.1.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,7 @@ <h3>Variants of Gradient Descent</h3>
308308
Step 3: w = 1.5816, loss = 2.0113
309309
Step 4: w = 2.0218, loss = 0.9572
310310
Step 5: w = 2.3116, loss = 0.4739</div>
311+
<div class="code-caption"><strong>Code Fragment 0.1.9:</strong> Simulating mini-batch SGD on a simple quadratic loss</div>
311312
<div class="code-caption"><strong>Code Fragment 0.1.2:</strong> Simulating mini-batch SGD on a simple quadratic loss.</div>
312313

313314
<p>Even with noisy gradients, the parameter <code>w</code> steadily moves toward the true minimum at 3.0. Each step is imprecise, but the overall trajectory converges. This is the core principle that scales all the way up to training models with billions of parameters.</p>
@@ -558,6 +559,7 @@ <h3>K-Fold Cross-Validation</h3>
558559
Fold 5: MSE = 0.2336
559560

560561
Mean MSE: 0.2553 (+/- 0.0383)</div>
562+
<div class="code-caption"><strong>Code Fragment 0.1.8:</strong> K-Fold cross-validation from scratch</div>
561563

562564
<div class="callout tip">
563565
<div class="callout-title">Production Alternative</div>

part-1-foundations/module-00-ml-pytorch-foundations/section-0.3.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ <h3>1.2 Indexing, Slicing, and Reshaping</h3>
132132
Flat: tensor([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
133133
Shape before unsqueeze: torch.Size([3])
134134
Shape after unsqueeze(0): torch.Size([1, 3])</div>
135+
<div class="code-caption"><strong>Code Fragment 0.3.42:</strong> PyTorch implementation</div>
135136
<div class="code-caption"><strong>Code Fragment 0.3.2:</strong> Reshaping, slicing, and fancy indexing on tensors. These operations return views when possible, avoiding unnecessary copies.</div>
136137

137138
<h3>1.3 Broadcasting</h3>

part-1-foundations/module-00-ml-pytorch-foundations/section-0.4.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,7 @@ <h2>4. Policy Gradients: Learning by Trial and Feedback <span class="level-badge
382382
Episode 600 | Last reward: +1.0 | Action 2 rate: 96%
383383
Episode 800 | Last reward: +1.0 | Action 2 rate: 99%
384384
Episode 1000 | Last reward: +1.0 | Action 2 rate: 100%</div>
385+
<div class="code-caption"><strong>Code Fragment 0.4.8:</strong> Define SimpleEnv; implement reset, step</div>
385386
<div class="code-caption"><strong>Code Fragment 0.4.2:</strong> REINFORCE policy gradient sketch in PyTorch. The PolicyNetwork maps states to action probabilities, mirroring how an LLM transformer maps token sequences to next-token distributions. The reinforce_episode function collects a trajectory, computes discounted returns, and nudges the policy toward actions that led to higher rewards.</div>
386387

387388
<div class="callout note">
@@ -757,6 +758,7 @@ <h3>Step 1: Build an AI milestone timeline</h3>
757758
plt.savefig("ml_timeline.png", dpi=150, bbox_inches="tight")
758759
plt.show()
759760
print("Timeline saved to ml_timeline.png")</code></pre>
761+
<div class="code-caption"><strong>Code Fragment 0.4.7:</strong> TODO: add description</div>
760762
</div>
761763

762764
<div class="lab-step">
@@ -787,6 +789,7 @@ <h3>Step 2: Implement a GridWorld environment</h3>
787789
env = GridWorld()
788790
print(f"Start: {env.reset()}, Goal: {env.goal}")</code></pre>
789791
<div class="code-output">Start: (0, 0), Goal: (3, 3)</div>
792+
<div class="code-caption"><strong>Code Fragment 0.4.6:</strong> TODO: add description</div>
790793
</div>
791794

792795
<div class="lab-step">
@@ -828,6 +831,7 @@ <h3>Step 3: Train a Q-learning agent from scratch</h3>
828831
Row 1: ['right', 'right', 'down', 'down']
829832
Row 2: ['right', 'right', 'right', 'down']
830833
Row 3: ['right', 'right', 'right', 'right']</div>
834+
<div class="code-caption"><strong>Code Fragment 0.4.5:</strong> states (4x4) x actions (4)</div>
831835
</div>
832836

833837
<div class="lab-step">
@@ -847,6 +851,7 @@ <h3>Step 4: Visualize the Q-values as a heatmap</h3>
847851
plt.tight_layout()
848852
plt.savefig("gridworld_values.png", dpi=150)
849853
plt.show()</code></pre>
854+
<div class="code-caption"><strong>Code Fragment 0.4.4:</strong> Value function: max Q at each state</div>
850855
</div>
851856
</div>
852857

part-1-foundations/module-01-foundations-nlp-text-representation/section-1.2.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,7 @@ <h2>Bag-of-Words (BoW) <span class="level-badge intermediate" title="Intermediat
429429
[[1 0 0 0 1 1 1 2]
430430
[0 0 1 1 0 1 1 2]
431431
[1 1 1 0 0 0 0 2]]</div>
432+
<div class="code-caption"><strong>Code Fragment 1.2.13:</strong> Implementation example</div>
432433
<div class="code-caption"><strong>Code Fragment 1.2.3:</strong> This snippet demonstrates this approach. Study the implementation details to understand how each component contributes to the overall computation. Tracing through each step builds the intuition needed when debugging or extending similar systems.</div>
433434

434435
<div class="callout practical-example">
@@ -697,6 +698,7 @@ <h2>One-Hot Encoding and Its Limitations <span class="level-badge intermediate"
697698

698699
Distance cat to dog: 1.41
699700
Distance cat to democracy: 1.41</div>
701+
<div class="code-caption"><strong>Code Fragment 1.2.12:</strong> One-hot encoding: see the problem for yourself</div>
700702
<div class="code-caption"><strong>Code Fragment 1.2.6:</strong> One-hot encoding: see the problem for yourself.</div>
701703

702704
<p>

part-1-foundations/module-01-foundations-nlp-text-representation/section-1.3.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,7 @@ <h2>Training Word2Vec from Scratch <span class="level-badge advanced" title="Adv
352352
Most similar to 'cat': [('dog', 0.91), ('sat', 0.78), ('mat', 0.72)]
353353

354354
Embedding matrix shape: (24, 50)</div>
355+
<div class="code-caption"><strong>Code Fragment 1.3.16:</strong> NumPy computation</div>
355356
<div class="code-caption"><strong>Code Fragment 1.3.1:</strong> Sample corpus (in practice, use millions of sentences).</div>
356357

357358
<h2>Measuring Similarity: Cosine Similarity <span class="level-badge intermediate" title="Intermediate">INTERMEDIATE</span></h2>
@@ -421,6 +422,7 @@ <h2>Measuring Similarity: Cosine Similarity <span class="level-badge intermediat
421422
0.1342
422423
0.6510
423424
0.7703</div>
425+
<div class="code-caption"><strong>Code Fragment 1.3.15:</strong> Measuring cosine similarity between word vectors</div>
424426

425427
<div class="callout library-shortcut">
426428
<div class="callout-title">Library Shortcut</div>
@@ -738,6 +740,7 @@ <h2>Visualizing Embeddings <span class="level-badge intermediate" title="Interme
738740
plt.annotate(word, (vectors_2d[i, 0]+0.5, vectors_2d[i, 1]+0.5), fontsize=12)
739741
plt.title("Word Embeddings Projected to 2D with t-SNE")
740742
plt.show()</code></pre>
743+
<div class="code-caption"><strong>Code Fragment 1.3.14:</strong> Implementation example</div>
741744

742745
<pre><code class="language-python">
743746
# NumPy computation

part-1-foundations/module-01-foundations-nlp-text-representation/section-1.4.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ <h2>Contextual Embeddings in Code <span class="level-badge intermediate" title="
325325
<div class="code-output">Cosine distance between 'bank' in different contexts: 0.349
326326
Distance bank(river) to shore: 0.218
327327
Distance bank(river) to bank(money): 0.349</div>
328+
<div class="code-caption"><strong>Code Fragment 1.4.7:</strong> Demonstrating contextual embeddings: same word, different vectors</div>
328329

329330
<div class="callout library-shortcut">
330331
<div class="callout-title">Library Shortcut</div>
@@ -653,6 +654,7 @@ <h3>Step 1: Train Word2Vec on a sample corpus</h3>
653654
for word in ["king", "queen", "man"]:
654655
neighbors = model.wv.most_similar(word, topn=3)
655656
print(f"{word}: {[(w, f'{s:.2f}') for w, s in neighbors]}")</code></pre>
657+
<div class="code-caption"><strong>Code Fragment 1.4.6:</strong> Sample corpus (in practice, use a larger dataset)</div>
656658
</div>
657659

658660
<div class="lab-step">
@@ -678,6 +680,7 @@ <h3>Step 2: Visualize embeddings with t-SNE</h3>
678680
plt.tight_layout()
679681
plt.savefig("word2vec_tsne.png", dpi=150)
680682
plt.show()</code></pre>
683+
<div class="code-caption"><strong>Code Fragment 1.4.5:</strong> TODO: add description</div>
681684
</div>
682685

683686
<div class="lab-step">
@@ -732,6 +735,7 @@ <h3>Step 3: Compare static vs. contextual embeddings</h3>
732735
'We sat on the river bank' vs 'Fish swim near the bank of the stream'
733736
[2] vs [3]: 0.762
734737
'The bank approved the loan' vs 'Fish swim near the bank of the stream'</div>
738+
<div class="code-caption"><strong>Code Fragment 1.4.4:</strong> TODO: add description</div>
735739
<details>
736740
<summary>Expected pattern</summary>
737741
<p>Financial sentences (0 and 2) should have higher cosine similarity with each other than with the river sentences (1 and 3). This confirms that BERT produces different representations for "bank" depending on context, unlike Word2Vec.</p>
@@ -765,6 +769,7 @@ <h3>Step 4: Visualize contextual differences</h3>
765769
plt.tight_layout()
766770
plt.savefig("contextual_bank.png", dpi=150)
767771
plt.show()</code></pre>
772+
<div class="code-caption"><strong>Code Fragment 1.4.3:</strong> TODO: add description</div>
768773
</div>
769774
</div>
770775

part-1-foundations/module-02-tokenization-subword-models/section-2.1.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ <h3>Seeing the Tradeoff in Numbers</h3>
262262
Subword tokens (GPT-4): 11 tokens
263263
Decoded: ['Token', 'ization', ' determines', ' the', ' model', "'s", ' vocabulary', ' and', ' sequence', ' length', '.']
264264
</div>
265+
<div class="code-caption"><strong>Code Fragment 2.1.14:</strong> Comparing tokenization granularities</div>
265266
<div class="code-caption"><strong>Code Fragment 2.1.1:</strong> Comparing tokenization granularities.</div>
266267

267268
<p>
@@ -318,6 +319,7 @@ <h3>The Token Tax on Different Languages</h3>
318319
Japanese : 14 tokens, 1 words, ratio = 14.0 tokens/word
319320
Hindi : 28 tokens, 7 words, ratio = 4.0 tokens/word
320321
</div>
322+
<div class="code-caption"><strong>Code Fragment 2.1.13:</strong> Demonstrating the "token tax" across languages</div>
321323
<div class="code-caption"><strong>Code Fragment 2.1.2:</strong> Demonstrating the "token tax" across languages.</div>
322324

323325
<div class="callout warning">
@@ -487,6 +489,7 @@ <h3>Artifact 1: Inconsistent Splitting</h3>
487489
'tokenization' => ['token', 'ization']
488490
' tokenization' => [' token', 'ization']
489491
</div>
492+
<div class="code-caption"><strong>Code Fragment 2.1.12:</strong> Demonstrating context-sensitive tokenization</div>
490493
<div class="code-caption"><strong>Code Fragment 2.1.3:</strong> Demonstrating context-sensitive tokenization.</div>
491494

492495
<p>
@@ -527,6 +530,7 @@ <h3>Artifact 2: Arithmetic Failures</h3>
527530
381 => ['38', '1']
528531
380 => ['380']
529532
</div>
533+
<div class="code-caption"><strong>Code Fragment 2.1.11:</strong> See how numbers tokenize differently</div>
530534
<div class="code-caption"><strong>Code Fragment 2.1.4:</strong> See how numbers tokenize differently.</div>
531535

532536
<p>

part-1-foundations/module-02-tokenization-subword-models/section-2.2.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ <h3>The BPE Merge Algorithm</h3>
146146

147147
<span class="algo-line-keyword">return</span> vocab, merges
148148
</code></pre>
149+
<div class="code-caption"><strong>Code Fragment 2.2.12:</strong> TODO: add description</div>
149150
</div>
150151

151152
<!-- DIAGRAM 1: BPE merge tree -->
@@ -272,6 +273,7 @@ <h3>Lab: Implementing BPE from Scratch</h3>
272273
newest&lt;/w&gt; (freq=1)
273274
wi d est&lt;/w&gt; (freq=1)
274275
</div>
276+
<div class="code-caption"><strong>Code Fragment 2.2.11:</strong> Minimal BPE implementation from scratch</div>
275277

276278
<div class="callout tip">
277279
<div class="callout-title">Production Alternative</div>
@@ -350,6 +352,7 @@ <h3>Encoding New Text with Learned Merges</h3>
350352
'newer' -> ['new', 'e', 'r', '&lt;/w&gt;']
351353
'slowly' -> ['s', 'lo', 'w', 'l', 'y', '&lt;/w&gt;']
352354
</div>
355+
<div class="code-caption"><strong>Code Fragment 2.2.10:</strong> Encode a new word using the learned merge table</div>
353356
<div class="code-caption"><strong>Code Fragment 2.2.2:</strong> Encode a new word using the learned merge table.</div>
354357

355358
<p>
@@ -433,6 +436,7 @@ <h3>WordPiece at Inference: MaxMatch</h3>
433436
'players' -> ['play', '##er', '##s']
434437
'helpless' -> ['help', '##less']
435438
</div>
439+
<div class="code-caption"><strong>Code Fragment 2.2.9:</strong> Simulated WordPiece MaxMatch tokenization</div>
436440

437441
<div class="callout library-shortcut">
438442
<div class="callout-title">Library Shortcut</div>
@@ -743,6 +747,7 @@ <h3>Comparison of the Three Methods</h3>
743747
print("Decoded:", sp.decode(ids))
744748
os.unlink(tmp.name)
745749
</code></pre>
750+
<div class="code-caption"><strong>Code Fragment 2.2.8:</strong> pip install sentencepiece</div>
746751
</div>
747752

748753
<div class="callout practical-example">
@@ -767,6 +772,7 @@ <h3>Comparison of the Three Methods</h3>
767772
print("Tokens:", output.tokens)
768773
print("IDs:", output.ids)
769774
</code></pre>
775+
<div class="code-caption"><strong>Code Fragment 2.2.7:</strong> pip install tokenizers</div>
770776
</div>
771777

772778
<!-- ============================== BYTE-LEVEL BPE ============================== -->

0 commit comments

Comments
 (0)