Skip to content
posttrainllm docs
Esc
navigateopen⌘Jpreview
On this page

Learning journal

Learning journal

A running log of questions, hunches, “wait, why does anyone do it this way?” moments, and tangents that come up during the curriculum sessions.

Discipline: capture without committing. Most entries will turn out to be rediscoveries of known ideas or open questions the curriculum will address later. Occasionally something will graduate into a real investigation — when it does, we do a prior-art pass before chasing it.

Why a journal alongside the polished curriculum: the polished session-XX-*.md files are the explanation. This journal is the thought process that produced the explanation. Anyone using this curriculum later sees both — and the journal is what makes it pedagogically distinctive. Most textbooks hide the questions.


2026-06-06 — Entry 1: “Is this just linear regression?”

During Session 1. After landing the “neuron = line being fit to data” idea, the natural realization:

Is this what linear regression is, essentially?

Yes. A single neuron with no activation function = exactly linear regression. Same equation, same fitting procedure, same idea.

Statisticians (Gauss, Legendre) were doing this in the early 1800s. The “neural” in neural network is mostly marketing inheritance from 1950s cognitive science — researchers loosely analogized the multiply-and-add operation to brain neurons “weighing” inputs.

So the honest framing of the whole field:

            stack many of them
            ↓ + non-linearities
LINEAR  ───────────────────────────→  NEURAL
REGRESSION                            NETWORK
(1800s, Gauss)                        (1950s+)

Same fitting equation. Same gradient descent. Just composed in more
flexible ways.

The boundary between “statistics” and “deep learning” is way blurrier than the marketing makes it sound.

Open question to revisit: at what point does a neural network stop being equivalent to linear regression and become something genuinely more powerful?

Spoiler (to be unpacked in a later session): when you stack layers AND put a non-linear function between them. Two linear layers without a non-linearity in between collapse algebraically into one linear layer — so depth alone buys nothing. The “neural” part is really the non-linear bumps.


2026-06-06 — Entry 2: clarification surfaced by Session 1 self-check

When asked “what does it mean to learn m and b?”, the first instinct was:

“Trying different values of x and y until we figure out what m and b are.”

The wobble: x and y don’t change. They come from data, fixed forever. What changes is m and b.

This distinction (inputs/outputs vs parameters) is one of the most load-bearing ideas in ML — and it’s the kind of thing the curriculum should make stupidly explicit, since it tripped a thoughtful first-time reader. Session 1 was revised to include an explicit “what’s fixed vs what changes” sidebar before this entry was filed.

Takeaway for the curriculum: any time a concept has “two kinds of variables doing different jobs,” call it out with a table. Don’t trust prose to make the distinction stick.


2026-06-06 — Entry 3: Why squared, not absolute (or |x|³)?

During Session 2. Question that came up naturally after introducing MSE: why square the error? Why not just take the absolute value? And — sharper follow-up — why not |x|³?

|x| is a real option

Absolute-error loss exists and is used. Called MAE (mean absolute error) or L1 loss. The reasons we default to squared (MSE / L2):

  1. Smoothness. has a defined slope everywhere. |x| has a kink at zero where the slope jumps from −1 to +1 discontinuously. Gradient descent doesn’t love kinks.
  2. Closed-form solution for linear models. For y = mx + b with MSE, you can solve algebraically for the best (m, b) — Gauss did it in 1805 (the “normal equation”). For MAE, no such closed form.
  3. Matches Gaussian noise. See below.

|x|³ is mathematically valid but pointless

Sharper follow-up — if smoothness is the issue with |x|, why not |x|³?

Math check: |x|³ = (x²)^{3/2}. Derivative is 3x·|x|, which is 0 at x = 0. So |x|³ IS smooth (twice continuously differentiable). Good catch — smoothness alone isn’t a reason to reject it.

Why nobody uses it anyway:

  • More outlier-sensitive than . |x|³ grows cubically, quadratically. An error of 100 contributes 1,000,000 under |x|³ vs 10,000 under . If you were worried about outliers under MSE, you’d be much more worried under cube.
  • No closed-form solution. The 1805 trick doesn’t extend.
  • No natural noise interpretation. What probability distribution does |x|³ correspond to? Some exotic generalized-normal with no name and no intuition.
  • Strictly worse than without any compensating advantage.

The deep reason is special: Gaussian noise

isn’t privileged because of smoothness. Many functions are smooth. It’s privileged because of its connection to the Gaussian (bell-curve, “normal”) distribution.

Take real measurements of anything — baby weights, house prices, sensor readings. Plot how often each value occurs. The shape is almost always bell-shaped: clustered near a mean, tailing off in both directions.

Why? The Central Limit Theorem: when many small independent random influences add up, the sum tends to a Gaussian — regardless of what each influence looks like individually. A baby’s weight = genetics + diet + sleep + a thousand other tiny factors. The sum is Gaussian.

The MSE connection: if you model your data as “true line + Gaussian noise,” then minimizing MSE gives the maximum-likelihood line — the single most-probable line consistent with your data. One line of algebra proves this (Gaussian density’s log is −(x−μ)² / 2σ² — squared distance pops out).

So MSE isn’t arbitrary. It’s the natural loss for the natural noise model in nature.

If your noise isn’t Gaussian — heavy-tailed, lots of rare outliers — MSE becomes inappropriate. Then MAE (which corresponds to Laplace noise, heavier tails) is better. Huber loss is a hybrid: squared near zero (smooth, MSE-like), absolute far out (outlier-robust, MAE-like).

Loss Punishes outliers Smooth? Closed-form? Implicit noise model
MSE (L2) a lot yes yes (linear) Gaussian
MAE (L1) proportionally no no Laplace
Huber tunably yes no mixture

Open question to revisit: when scaling up to deep networks, does the choice of loss still matter as much, or do non-linearities and overparameterization dominate? (Spoiler from memory: it matters a lot for the early-training dynamics and for specific tasks; less for “final accuracy” on well-behaved problems.)


2026-06-06 — Entry 4: Mini-batch noise — bug or feature?

During Session 2. When mini-batches were introduced as “we don’t compute the gradient on all data, just a slice,” the natural worry: different batches will push toward different gradients. Won’t that cause chaos?

They do disagree. By design.

Each batch’s gradient is a noisy estimate of the true full-data gradient. Imagine 100 batches drawn from the same dataset:

  • Batch 1 says go [+2, +3]
  • Batch 2 says go [+1, +4]
  • Batch 3 says go [+3, +2]

If you AVERAGED all 100, you’d get back exactly the true full-data gradient. So each batch is “the truth + random noise.”

In practice we use one batch per step instead of averaging. Over many steps, the random noise averages out; the systematic downhill direction wins. We take many tiny noisy steps instead of fewer accurate ones. We end up in the same valley.

The twist: noise is a feature

Surprising result: even with infinite compute (so full-batch GD is free), you’d usually still want noise. Reasons:

  1. Flatter minima generalize better. SGD’s noise tends to find broad, flat valleys in the loss landscape. Flat valleys → models that generalize to new data. Full-batch tends to find sharp narrow minima that perform well on the training set but worse on new data. This is the flat minimum hypothesis — observed empirically, theoretical foundations active research.

  2. Escape from saddle points. High-dimensional loss landscapes are full of saddles where gradient descent slows to a crawl. Noise kicks you off.

  3. Implicit regularization. SGD’s noise behaves mathematically like an extra regularization term that prevents overfitting. You’d have to add this manually with full-batch.

There’s an active line of research on this — search “implicit bias of SGD” or “edge of stability” for current papers.

Pre-selected chunks vs random?

Real concept and people have studied it. The default is random for good reasons, but task-specific schemes exist:

  • Random — each batch is an unbiased estimate of the true gradient. Default for almost everything. Simple, has theoretical guarantees.
  • Curriculum learning — order from easy to hard. Sometimes helps, especially for RL and code generation. Often doesn’t.
  • Stratified sampling — ensure each batch represents every class. Common in classification with imbalanced classes (1% positive, 99% negative).
  • Hard example mining — deliberately oversample examples the model currently gets wrong. Used in object detection.

Random wins by default because any fixed scheme is biased toward whatever pattern you chose, and “representative” requires you to define representativeness — another modeling decision with its own biases.

Open question to revisit: the “flat minimum hypothesis” is folk wisdom that’s been challenged by some recent theoretical work. How robust is it really? Worth a deeper dive when we cover regularization.


2026-06-06 — Entry 5: Why is ML research still in flux?

During Session 3. Question that came up: why are research still pending on these things? (depth, why neural nets generalize, etc.)

Honest framing

ML is currently an empirical science, not a deductive one. The state of the field rhymes with physics around 1900: lots of working theory for specific things, no overarching framework that predicts what will work next. Most progress is empirical — try it, see if it works, generalize from observation.

What’s actually open

These are not closed problems:

  • Generalization theory. Classical learning theory says: more parameters than data → overfit catastrophically. Reality: modern LLMs have orders of magnitude more parameters than training data and generalize fine. The classical framework is wrong; nobody knows what the correct framework looks like. Search “double descent,” “benign overfitting,” “implicit bias of SGD.”
  • Mechanistic interpretability. What does each layer actually compute? What do individual neurons mean? Anthropic, DeepMind, EleutherAI all have teams attacking this. Early progress (Sparse Autoencoders, induction heads) but the bulk is open.
  • Scaling laws. How does loss / capability scale with parameters, data, compute? Chinchilla and OpenAI scaling papers gave power-law predictions that hold across orders of magnitude — but we don’t know why they hold, or when they’ll break.
  • Sample efficiency. Humans learn from orders of magnitude less data. Why? What’s the right inductive bias?
  • Why attention works. We use it because it works. No proof that it has to.
  • Loss landscape geometry. Why doesn’t gradient descent get stuck in bad local minima in high dimensions? “Loss landscape is mostly saddles” is the working hypothesis but not theorem.

The takeaway

We have a hammer that works (SGD on big transformer + lots of data). We don’t fully understand why. Most “research” is either incremental improvements to that hammer, or trying to understand why it works.

The field moves faster than any deductive science because it accepts empirical demonstration as sufficient — wait for a proof and you lose to someone who skipped that step.


2026-06-06 — Entry 6: Are people working on non-linearities specifically?

During Session 3. Companion question: and I assume people are working on non-linearities constantly?

Yes, but it’s a mature subfield

Activation functions are still being researched, but the wins are small and incremental. The timeline:

Year Function Why it mattered
1958 step function original perceptron — too harsh, no gradients
~1989 sigmoid / tanh smooth, differentiable, dominant for decades
2010 ReLU (Glorot, Bengio) huge leap — solved vanishing gradients in deep nets
2016 GELU (Hendrycks) smoother ReLU, became transformer default
2017 Swish / SiLU (Ramachandran et al) smooth self-gated, marginal improvement
2020 SwiGLU (Shazeer) gated variant, now default in Llama / Mistral / Qwen

Why gains have shrunk

After ReLU’s leap, every subsequent activation function delivers a few percent improvement at most. The field has converged on a small family (ReLU, GELU, SwiGLU, occasional experiments).

Where the order-of-magnitude wins live now:

  • Architecture changes (attention variants, Mixture-of-Experts, sparse attention, MLA, state-space models like Mamba)
  • Training procedures (RLHF, DPO, constitutional AI, RLAIF)
  • Data quality and curation (filtered web corpora, synthetic data, textbook-quality data)
  • Scaling laws and compute optimization

The takeaway

Activation functions still matter and people still propose new ones, but they’re no longer where the order-of-magnitude leverage is. People still publish on them — there’s “polishing the hammer” research and “designing a new tool” research, and activations are now the former.

If you wanted to publish on activations today, the bar is high: you’d need to show meaningful improvement across a broad set of architectures and tasks, and the existing functions are already very good.


2026-06-06 — Entry 7: The taxonomy of ML approaches (and where transformers fit)

During Session 3 model dive. Question: “is there also tree regression? RL? learning by doing? Transformers don’t use all of them — what are the other kinds of training and why aren’t transformers used for them?”

The premise conflates three orthogonal axes. Untangling:

Axis 1 — Training signal (what you learn FROM)

Paradigm Signal looks like Example
Supervised (input, correct answer) pairs spam classification with labels
Self-supervised label derived from input next-token prediction — the label IS the next word in your data
Unsupervised no labels clustering, dimensionality reduction
Reinforcement reward signal from environment game-playing agent, RLHF
Semi-supervised mix of labeled + unlabeled rare in modern practice

Axis 2 — Model family (what shape the function takes)

Family Shape Best for
Linear regression / GLMs line/plane tabular numeric prediction
Decision trees, gradient-boosted trees (XGBoost, LightGBM) tree of threshold splits tabular data — often beats neural nets here
SVMs margin-maximizing boundary classical classification, small data
k-NN “copy the nearest examples’ answers” recommenders, image lookup
Bayesian methods full probability distributions calibrated uncertainty matters
Neural networks (CNN, RNN, Transformer) stacked linear+non-linear high-dim data with lots of examples

Axis 3 — Parameter update algorithm

Algorithm Used for
Gradient descent / SGD / Adam anything differentiable
Closed-form (normal equation) linear regression with MSE
Tree-building (CART, ID3, gradient boosting) decision trees
EM (Expectation Maximization) mixture models, HMMs
Policy gradient / Q-learning / Actor-Critic RL
MCMC Bayesian inference

These axes are mostly independent

The big realization: you can mix and match.

  • Transformer + supervised + SGD = standard fine-tuning
  • Transformer + self-supervised + SGD = pretraining (next-token prediction, what huge-base-v1.tinygpt does)
  • Transformer + RL + policy gradient = RLHF (the second stage that turned GPT-3 into ChatGPT)
  • Tree + supervised + boosting = XGBoost (often beats neural nets on tabular tasks)
  • Neural net + RL = AlphaGo, AlphaStar

Correcting the premise

“Transformers don’t use RL” is wrong. RLHF is exactly transformer + RL. ChatGPT, Claude, Llama-Chat all use it. Transformer = model family; RL = training signal; they compose.

When transformers are NOT the right tool

  • Tabular data, no sequence structure → tree ensembles win.
  • Tiny datasets (hundreds, not millions) → simpler models with stronger inductive biases (Bayesian, SVMs) often beat NNs.
  • Calibrated probability matters more than raw accuracy → Bayesian.

Transformer’s superpower is sequential, high-dimensional data with lots of examples — text, audio, video, DNA. For everything else, classical methods are often better.

Curriculum implication: this whole taxonomy is its own session waiting to be written. For now, the journal entry serves as the placeholder.


2026-06-07 — Entry 8: Loss numbers aren’t comparable across setups

During Session 5. The user observed: small browser-trained models had lower loss than the 22M huge-base-v1. If bigger is supposed to be better, what’s going on?

The instinct is right, but the conclusion is wrong

Loss isn’t an absolute quality measure. It’s tied to the prediction task (specifically: vocab size and bytes-per-token), and the same “quality” shows up as very different absolute numbers in different setups.

Why the absolute numbers diverge

Cross-entropy loss has a different ceiling at each vocab size. A model that uniformly guesses across the vocab achieves loss log(vocab):

Setup vocab random-baseline loss
Browser byte-level 256 log(256) ≈ 5.55
huge-base-v1 (SmolLM2 BPE) 49,152 log(49152) ≈ 10.80

So a byte model with loss 2.5 went from random (5.55) to 2.5 — about 55% of the way to perfect. huge-base-v1 with loss 4.16 went from random (10.80) to 4.16 — about 61% of the way. The bigger model is actually further from random even though its absolute loss number is bigger.

Bits per byte: the apples-to-apples metric

To compare across vocab sizes, normalize:

bpb = loss / log(2) / (avg bytes per token)

Byte models: 1 byte per token. BPE models (English): typically ~4 bytes per token.

Model Loss bpb (approx)
Byte browser model 2.5 2.5 / 0.693 / 1 ≈ 3.6 bpb
huge-base-v1 (BPE) 4.16 4.16 / 0.693 / 4 ≈ 1.5 bpb
Frontier LLM (varies) ~0.6 bpb

Same metric, both setups normalized: the BPE model is ~2.4× more efficient at modeling English than the byte model. The “smaller raw number” on the byte model was an illusion of the different task.

When can you compare loss directly?

Only when the prediction task is identical: same vocab, same tokenizer, same dataset, same eval procedure. Within those constraints, raw loss is fine. Across them, normalize to bpb or use a held-out benchmark.

Takeaway for the curriculum

Future Session on training mechanics should call this out explicitly: a loss number alone is roughly meaningless. A loss curve at a fixed setup is meaningful (relative motion within one task). Comparison across setups requires bpb or held-out benchmark scores.


2026-06-07 — Entry 9: LLMs as decoders for “blind spots” in unknown texts

During Session 5. Question: “if I have a large alien language text with some blind spots, can LLMs help decode the blind spots?”

Yes — that’s exactly what masked language modeling does

Train an LM on the available alien-language data (self-supervised: the labels are just other parts of the same text). The model learns the language’s patterns — which tokens commonly follow which, what sentence shapes exist, what the local grammar looks like. Then for a blind spot, ask the model “given the surrounding context, what’s the most likely fill?” It returns a probability distribution over candidates.

Real precedent: Ithaca (DeepMind, 2022)

A transformer trained on ancient Greek inscriptions, fielded for restoring damaged text in actual archaeological fragments and attributing inscriptions to time and place. Same mechanism the user described: train on intact context, infer over missing pieces. Worked because language has redundancy; a model that internalized the redundancy can fill local gaps better than human experts in many cases.

Constraints for true alien text

  • Need substantial intact corpus. Roughly 1 MB minimum, ideally 10 MB+, of clean unbroken passages. Below that, the model can’t internalize the patterns.
  • Blind spots must be local. Filling a few missing tokens between intact context works well. Filling entire pages without surrounding context doesn’t (and the further “out” you extrapolate, the worse the model gets).
  • No way to validate. With known languages you can grade predictions against ground truth. For true alien text, you only get the model’s guess with confidence — and the confidence may be miscalibrated on out-of-distribution material.
  • Will produce something even when it shouldn’t. Models almost never refuse to predict; you must hold outputs as “best guess given patterns” not “the answer.”

A subtler use: structural inspection

Even without filling blanks, training an LM on the alien corpus and inspecting WHAT IT LEARNS (which tokens cluster, which sequences are common, where the entropy spikes) reveals language structure. This is computational decipherment — a real subfield in linguistics that’s been quietly LLM-augmented in the last few years.

Open question to revisit

How does this work for languages with VERY different statistical structure from English? (E.g., agglutinative languages with very long words, or pictographic systems.) The Ithaca result is on a Indo-European language with copious cognate data. The story might be more brittle for truly novel statistical structures.


2026-06-07 — Entry 10: Chinchilla is compute-optimal, not globally optimal

During Session 5 self-check. User answered “if you trained the same 22M model on 10× the data, would that help?” with: “nope, we are at optimal ratio, if more it will get overtrained based on research.”

That’s a common misconception worth pinning down: Chinchilla’s “20 tokens per param” rule is COMPUTE-OPTIMAL, not GLOBALLY OPTIMAL.

Two different “optima”

Concept What it asks Answer
Compute-optimal (Chinchilla) given a fixed compute budget, what params/tokens split minimizes loss? ≈ 20 tokens / param
Global-optimal for a target model size given that I want a small model, how much data should I train it on? as much as you can afford

The original Chinchilla paper (Hoffmann et al., 2022) framed itself in terms of compute-optimal training. Reading it as “training small models past 20:1 is wasted” is wrong — the paper just doesn’t address that question directly.

What modern practice actually does

Frontier labs deliberately over-train small models:

  • Llama-3-8B: ~15 trillion tokens of training. Ratio ≈ 15T / 8B ≈ 1,875 tokens/param — almost 100× past Chinchilla.
  • Phi-3-mini: similar over-trained regime, with the extra twist of textbook-quality curated data.
  • Llama-3.1, Llama-3.3, Qwen 2.5, Mistral Small: all trained well past Chinchilla.

Why over-train?

Inference cost. A bigger Chinchilla-optimal model is smarter per training dollar, but you pay its inference cost every time you serve it, forever. A smaller over-trained model is “more expensive to train per quality point” but “much cheaper to RUN per quality point.”

Math sketch: a model deployed to serve N inferences over its lifetime has total cost ≈ training_compute + N × inference_compute_per_call. For high-N regimes (consumer products, agents that call the model millions of times), inference dominates. Over-training trades training compute (one-time) for inference compute (per-call, forever).

The Phi-3 corollary

Combining over-training with carefully curated textbook-quality data breaks the scaling-laws curve. Phi-3-mini (3.8B params) matches much larger models on reasoning benchmarks because:

  1. It’s over-trained (much more data than Chinchilla would allocate)
  2. The data is hand-curated for educational value (Phi’s “textbooks”)

Both moves happen outside the standard scaling-laws framework. Scaling laws describe “more compute → less loss”; Phi-3 shows “better data + over-training → orders of magnitude better practical capability.”

Implications for huge-base-v1

If you trained huge-base-v1 (22M params) on 4.1B tokens (10× more, ~120 hours wall time), you would NOT hit a wall. You’d get a meaningfully better 22M model — just at the cost of spending 10× the training time. Whether that’s worth it depends on how often you’ll run it: high throughput → yes; low throughput → no.

For posttrainllm specifically: the product framing is “Mac platform for building specialists for your specific tasks.” Those specialists will be hit many times (chat, completions, etc.) — so over-training the base might be a real lever to pull, distinct from “make the base bigger.”

Open question to revisit

The over-training regime has been popular for ~18 months at the time of writing. Where does the curve actually flatten for small models trained WAY past Chinchilla — 1000× the optimum, say? The Phi/Llama-3 regime suggests there’s still meaningful improvement at 100×; nobody (publicly) knows where it stops.


2026-06-07 — Entry 11: Embedding is dictionary, body is reader

During Session 6. User asked: “if 57% of huge-base-v1’s parameters are in the embedding, what’s the remaining 43% storing that’s MORE valuable than the embedding?” Plus a related model: “embeddings are like chains of text, and the model tries to fit input words into those chains.”

Both are excellent questions and both deserve a careful answer because the misconceptions are common.

Embeddings are NOT chains

Each token has ONE vector. For huge-base-v1, that’s 256 floats. Total storage for the whole embedding = vocab × d_model = 12.5M floats.

The vector is a fixed POINT in a high-dimensional concept space, not a chain or tree of related concepts. Similar concepts (cat, dog) cluster near each other in this space; distant ones (cat, differential equations) are far apart. But there’s no linked list, no graph, no chain.

When the model receives an input, it looks up the vectors for each token in the input and feeds them into the transformer body. There’s no “walking through chains.”

The body is what does the actual reasoning

The 12 transformer blocks (~9.5M params, 43% of total) handle three distinct jobs that embeddings can’t:

  1. Attention. For each token, computes “which OTHER tokens in the sequence matter for predicting the next one?” This is where contextual meaning is resolved. The word bank has the same embedding vector regardless of context. But when surrounded by river, attention draws connections to river and produces a “river-bank” interpretation for the next prediction. When surrounded by money, it draws connections to money and produces “financial-bank” interpretation. Same embedding; different runtime computation.
  2. MLPs (feedforward). Combines features from many positions to derive higher-order patterns. “These two phrases together imply this concept.” This is where pattern recognition and combinatorial reasoning live.
  3. Layer norms + residuals. Plumbing that keeps gradients flowing and keeps representations well-scaled across depth.

The dictionary-reader analogy

  • Embedding = dictionary. Each word has a fixed definition. Looking up a word gives you its meaning in isolation.
  • Body = reader. Combines word meanings sequentially, resolves ambiguities from context, derives sentence-level and discourse-level meaning, predicts what comes next.

You need both. But:

  • Huge dictionary + tiny reader = can recall lots of word definitions but can’t compose them into thoughts.
  • Smaller dictionary + bigger reader = can do deep reasoning on a slightly less rich vocabulary.

For language MODEL capability, the body is more valuable per parameter than the embedding past a certain point. This is why huge-base-v1’s 57% embedding share is suboptimal — too much budget on the dictionary, too little on the reader.

Practical consequence

For a fixed total parameter budget:

  • Larger vocab → larger dictionary → smaller reader → less compute-capable
  • Smaller vocab → smaller dictionary → larger reader → more compute-capable
  • The optimum depends on the data and task, but for small models on general English text, ~16K–30K vocab is typically a better balance than 49K.

Open question to revisit

For multimodal models (vision + language), the embedding handles a much larger “vocabulary” (image patches, audio frames). Does the dictionary vs reader trade-off still apply, or does the multimodal regime have different optima? The recent MM-LLM literature is just beginning to publish on this.


2026-06-07 — Entry 12: Memorization vs generalization (the Harry Potter test)

Surfaced during Session 6 experiments. User asked: “if I train the model on, let’s say, Harry Potter text, won’t it be able to predict the story from any given sentence?”

Yes — and that’s the point of overfitting / memorization. Worth unpacking because it’s the cleanest concrete case for understanding when a model is “learning” vs “memorizing.”

Capacity vs data ratio drives the answer

  • Harry Potter complete series ≈ 1.1M words ≈ 1.5M tokens
  • huge-base-v1: 22M params
  • Ratio: 22M params ÷ 1.5M tokens ≈ 15 params per token

Inverse Chinchilla: instead of 20 tokens per param, this is ~0.07 tokens per param. The model has MASSIVELY more capacity than data. The result is overfitting: the model has plenty of room to memorize the exact text.

What “predict the story” would actually look like

  • Give it a UNIQUE early sentence ("Mr. and Mrs. Dursley, of number four, Privet Drive...") → very high chance of near-verbatim continuation of the original passage.
  • Give it a COMMON sentence ("He said.") → could continue in many directions; might mix passages.
  • With temperature = 0 (greedy) → deterministic, often near-perfect recall.
  • With temperature > 0 → recognizable Harry Potter style but with variations.

This is exactly what the existing data/checkpoints/huge-shakespeare-5000-loss1.22.tinygpt demonstrates: huge trained on Shakespeare for 5000 steps achieved loss 1.22 because the model essentially memorized large chunks of Shakespeare. The same recipe on Harry Potter would produce a “Harry Potter parrot.”

When this is feature vs bug

Feature: for specialists, memorization of the specific domain is exactly what you want. A code completion model SHOULD remember common idioms; a SQL specialist SHOULD memorize syntax patterns; a customer support specialist SHOULD memorize the company’s product details.

Bug: for general-purpose LMs, memorization is a generalization failure. The model can’t help you with NEW Harry-Potter-style stories; it can only recite existing passages. Also legally fraught (this is the core of the OpenAI / NYT / authors copyright lawsuits — GPT-4 has been shown to reproduce copyrighted text verbatim).

Connection to the curriculum

This is the Q5 trap from Session 2 made concrete. “Loss = 0 means perfect predictions” sounds great, but if it’s predicting verbatim from memorized training data, that’s not “the model learned the structure” — it’s “the model became a compressed copy of the training set.”

The diagnostic: train/val gap. If training loss is near 0 but validation loss (on held-out passages) is high, you have memorization without generalization. If both are low, you have actual learning.

Open question to revisit

What’s the minimum model size that still meaningfully generalizes from a small corpus rather than memorizing? Phi-3’s “textbook quality” data trick may partly work because curated data forces patterns the model has to learn rather than memorize. But this isn’t well-characterized academically yet.


2026-06-07 — Entry 13: Temperature ≠ creativity (variety vs capability)

During Session 7. User asked: “why can’t I just increase the temperature to make the model creative?”

Worth pinning down because temperature-as-creativity-dial is a common beginner misconception.

What temperature does

Reshapes the next-token probability distribution before sampling:

  • T = 0 → greedy, deterministic, “boring but coherent”
  • T = 1 → natural distribution
  • T > 1 → flatten distribution, sample more from low-probability tokens
  • T → ∞ → uniform sampling, garbage

What’s in the tail (which T amplifies)

  • ✓ Novel combinations the model considered but didn’t favor
  • ✓ Less obvious continuations
  • ✗ Errors, hallucinations
  • ✗ Off-topic tokens
  • ✗ Grammar mistakes
  • ✗ Incoherent transitions

Temperature can’t distinguish these. It amplifies ALL of the tail. High T = high variance: occasionally brilliant, often garbage.

Variety vs creativity

Aspect Variety (T-controllable) Creativity (capability-controlled)
What different outputs each sample novel BUT coherent combinations
Mechanism sampling reshape underlying distribution shape
Knob temperature base model + training data
Hard limit model’s existing distribution capacity to generate quality rare options

Crucial insight: a model can only “be creative” within its training distribution. Temperature lets you SEE the diversity that’s already there; it doesn’t ADD diversity that isn’t.

Distribution vs capability framing

Think of the model as a search engine over its learned distribution:

  • Small/weak model = small index. High T = same boring stuff with errors mixed in.
  • Large/strong model = rich index. Moderate T = genuine variety because many plausible-and-good options exist in the distribution.

Temperature is a band-aid for an underpowered model, not a substitute for capability.

Usually paired with temperature in modern sampling:

  • top-k: consider only the k most likely tokens, then sample. Cuts worst tail.
  • top-p (nucleus): consider tokens until cumulative probability ≥ p, then sample. Adaptive version of top-k.

These let you raise T for variety within plausible options while clipping the obvious garbage. Modern systems typically combine moderate T (≈0.8)

  • top-p (≈0.9). Best of both worlds.

Practical advice for character/NPC work

  • T ≈ 0.7–0.9 = sweet spot for character work. Some variety, mostly stays in character.
  • T = 0 → NPCs robotic, identical responses.
  • T > 1.2 → NPCs unpredictable AND incoherent. Often break character.

If a character feels boring, the fix is more diverse training data + a better base + moderate T. NOT crank T higher on a weak base.


2026-06-07 — Entry 14: Optimization audit — posttrainllm vs Kaiju + modern small models

Triggered by HuggingFace research for the character recipe. User asked: “how can we use the different optimisations [from Character.AI Kaiju + modern small models] in our own model training regimen?”

Short answer: posttrainllm already ships virtually all of them. The gap is that the default huge preset deliberately doesn’t enable them — it’s a vanilla GPT-2 teaching baseline. Modernizing the preset would be a free quality bump.

Full audit table

Optimization Where it comes from posttrainllm status Used by huge preset?
MQA (Multi-Query Attention) Kaiju ✅ shipped (nKvHeads: 1) ❌ (uses full MHA)
GQA (Grouped Query Attention) Llama-2+ ✅ shipped ❌ (uses full MHA)
Sliding window attention Mistral, Kaiju (5:1 ratio) ✅ shipped (--sliding-window N)
Cross-layer KV sharing (YOCO) Kaiju, Sun et al. 2024 ✅ shipped (--yoco, CrossAttention.swift)
INT8/INT4 quantization (inference) Standard ✅ shipped (MLXNN.quantize) n/a (inference)
KV cache quantization (KIVI) KIVI paper ✅ shipped (--kv-quantize) n/a (inference)
QAT (Quantization-Aware Training) Kaiju ✅ shipped (--qat) optional
RMSNorm Llama+ ✅ shipped (cfg.useRMSNorm) ❌ (uses LayerNorm)
SwiGLU MLP Llama+, PaLM ✅ shipped (cfg.useSwiGLU) ❌ (uses GELU)
RoPE positional encoding Llama+ ✅ shipped (cfg.useRoPE) ❌ (uses learned positional)
Embedding RMSNorm Recent 2025 finding ✅ shipped (cfg.useEmbeddingRMSNorm)
DeepNorm residual scaling Microsoft 2022 ✅ shipped (cfg.useDeepNorm)
Layer-wise LR decay Standard fine-tune trick ✅ shipped (cfg.lrLayerDecay) optional
Cosine warmup schedule Standard ✅ shipped (--lr-schedule cosine) optional
WSD schedule MiniCPM ✅ shipped (--lr-schedule wsd) ✅ (huge uses this)
BPE dropout Provilkov 2019 ✅ shipped (BPEDropout.swift) optional
Knowledge distillation Hinton et al. ✅ shipped (posttrainllm distill) n/a
DPO / SimPO / KTO / ORPO RLHF alternatives ✅ shipped (posttrainllm dpo with flags) n/a
LoRA + DoRA + VeRA + LoftQ + AdaLoRA + RsLoRA + PISSA + LoRA-FA + LayerDrop various ✅ shipped (entire bundle) n/a
Multi-Token Prediction (MTP) Gloeckle 2024, DeepSeek-V3 ✅ shipped (cfg.mtpHorizons > 1)
MoE (dense routing) Switch Transformer ✅ shipped (cfg.nExperts > 1)
NEFTune (noisy embeddings) Jain 2024 ✅ shipped (--neftune-alpha) n/a (SFT-time)
Curriculum-quality classifier FineWeb-Edu approach ✅ shipped (posttrainllm train-quality-classifier) n/a (data)
Speculative decoding (Medusa, EAGLE-2) Standard ✅ shipped (--draft, --heads) n/a (inference)
Synthetic data generation Phi-3 textbook approach ✅ shipped (posttrainllm synthesize) n/a
ALiBi positional Press 2022 ✅ shipped (alt to RoPE)
Tied embeddings Standard ✅ shipped ✅ (huge uses this)
Gradient checkpointing Standard ✅ shipped optional
Squinch gradient compression Kaiju proprietary ❌ not shipped n/a (multi-GPU only; mostly irrelevant for Mac local)
Sparse MoE kernels DeepSeek ⬜ TODO (dense routing works; sparse compute is on backlog) n/a
Token-preserving trajectory recorder Poolside ⬜ TODO (B22 in PLAN.md) n/a (RL feature)

Headline finding

~95% of modern small-model + Kaiju optimizations are already shipped in posttrainllm. The remaining gaps are either niche (Squinch is for multi-GPU communication, mostly irrelevant on single-Mac), niche-2-2 (sparse MoE kernels — dense routing works for training, sparse compute is a future engineering project), or non-architectural (B22 trajectory recorder is RL infrastructure, not a base-training optimization).

The real opportunity: modernize the huge preset

The huge preset (ModelConfig.huge in ModelConfig.swift) currently uses GPT-2-vanilla architecture:

  • LayerNorm (not RMSNorm)
  • GELU MLP (not SwiGLU)
  • Learned positional embeddings (not RoPE)
  • Full MHA (not GQA/MQA)
  • No YOCO

This is a teaching choice — the preset is deliberately “what a clean GPT-2 looks like” so the curriculum can introduce modernizations one at a time later. But for production-quality small models, the huge preset is leaving free quality on the table.

A modernized huge-v2 preset turning these on by default would:

  • Reduce loss by approximately 5-15% (free win from SwiGLU + RoPE + RMSNorm based on published ablations)
  • Reduce inference memory ~30% (free win from GQA + YOCO)
  • Train slightly slower per step but converge in fewer total steps

Worth a small PRD. Flagged in factory-character-specialist-recipe.md as out-of-scope but mentioned.

Curriculum implication

A future Session 8 — production training optimizations could walk through this audit, explaining what each optimization does and why modern small models use most of them. The journal entry is the short-form reference; the session would be the long-form teaching version. Adding to the curriculum backlog.


2026-07-25 — Entry 15: The gradient that should be zero

During autocorrect task 5.1 (wiring LoRA onto FLAN-T5-small). While writing the tests, a question that felt like a bug report:

Why is dL/dA exactly zero after the first backward pass? Did I detach the branch by accident?

No — it is forced by the math. LoRA computes ΔW = BA with B initialized to zeros. Then dL/dA = scaling · Bᵀ · dL/dy · xᵀ, and every term is multiplied by B = 0. Meanwhile dL/dB = scaling · dL/dy · (Ax)ᵀ is perfectly non-zero. So at step 0, B learns and A waits; once B moves off zero, A wakes up.

Why this is worth writing down: it inverts into a test. A LoRA branch that is genuinely broken — detached from the graph, or wrapped so the forward pass never touches it — gives zero gradient on both matrices. So “A is zero AND B is not” is a signature that distinguishes correct wiring from a plausible-looking bug. A loss-goes-down smoke test would pass in both cases.

The general shape: an initialization chosen for one reason (start at the base model) hands you a second, free property (a falsifiable assertion about the gradients). Worth looking for elsewhere — the same trick should apply to any zero-initialized residual branch, e.g. adapters with zero-init output projections or the gate in a zero-init attention variant.

Tangent that did not graduate

ByT5 is architecturally the right model for typo repair — typos are byte-level events, and SentencePiece fragments misspellings badly. It lost the bake-off anyway: 899 ms median end-to-end against a 250 ms gate, ~7× the latency of FLAN-T5-small.

The instinct was to argue the gate was too strict. The discipline was to record it as a resource loss with the theory intact: byte-level was not disproven, it was priced. If a future target has a looser latency envelope, ByT5 goes back on the shortlist unchanged. Filed rather than chased.


2026-07-25 — Entry 16: A gate that passes for the wrong reason

During autocorrect task 5.3. The tiny-overfit gate passed cleanly — exact match 1.0 at step 50 of a 200-step budget, loss 1.585 → 0.030. The instinct was to write “gate passed” and move on.

Then a fixture detail: all 8 rows derive from one source sentence, so all 8 targets are the identical string. Which means the pass condition, “reproduce every target exactly,” is satisfiable by a model that learned to emit one constant and ignore its input entirely.

Not a bug in the run. A weakness in the gate’s discriminating power — and one that only shows up if you ask what else could produce this number.

The check that resolved it was cheap: run the trained adapter on three inputs it had never seen. It had not collapsed to a constant (outputs varied), but it copied an unseen typo through uncorrected, prefixed an unrelated sentence with a spurious Please bled from the training sentence, and echoed the prompt instruction on the third. All three are predicted failure modes — but none of them were visible in the metric that “passed.”

The generalizable move: for any gate, ask what degenerate policy also clears this bar? If one exists, the gate needs either a harder fixture or a companion probe that the degenerate policy would fail. A pass whose alternative explanations you have not enumerated is a number, not evidence.

Corollary for fixture design: a memorization gate with one unique target conflates “memorized the data” with “emitted a constant.” More than one distinct target separates them for free. Filed as a v2 fixture improvement rather than fixed mid-lane — the thresholds are frozen and this run’s evidence is already recorded.


2026-07-25 — Entry 17: Two walls and no floor between them

During autocorrect tasks 5.4–5.5. The tiny gate’s probe showed copy bias: the adapter passed a typo through untouched. The obvious next sentence to write was “training will fix this.”

Fifty steps on twelve rows later, the pilot scored −0.8125 error reduction. Negative. The output was further from the clean reference than the typo’d input had been. remeber became remind you. teh team became your team. tomorroww became tomorrow morning. Meanwhile repourt sat there unrepaired.

It did not travel from “copies too much” toward “repairs correctly.” It travelled from one wall to the opposite wall and kept going.

The reframe: minimum-edit repair is not a point you approach from the copy side. It is a narrow band between two failure modes — copy everything (zero repair) and rewrite everything (negative repair) — and plain sequence loss on a small dataset has no reason to stop in the middle. Nothing in the objective says “prefer the smallest edit that works.” The model is only asked to match a target string, and paraphrasing matches it approximately in a way the loss tolerates.

That is what killed the edit-aware objective before it was written. It up-weights the positions that need correcting — pressure toward more editing, aimed at a model that had already overshot. The technique was not wrong; it was pointed at the wrong wall.

Second finding: a stop rule that could not be satisfied

The pilot halted at step 50 of 300 on clean_preservation < 0.995. Then: the base model’s zero-shot clean preservation is 0.667. So the rule fired at the first evaluation no matter what training did. The pilot was never able to run its budget.

A ship bar had been reused as a training guard, which silently turns “stop if we regress” into “stop always.” Check every stop rule against the baseline’s measured value, not against the target. Obvious in hindsight; invisible when the threshold file and the baseline file are written weeks apart and never compared.

Both findings are cheap only because the run was 21 seconds. The same two mistakes on a 6-hour job would have cost a day each.

Was this page helpful?