le-fat-chaton
- 8 Devlogs
- 46 Total hours
a simple llm
a simple llm
Devlog #8 — phase 2 fixes
I’ve been getting a lot of issues with the first two for this model. I’ve gotten a lot of errors in Kaggle and Colab. I’ve tried everything, and I’m still fixing the code. It’s taking a good amount of time, but I think I’m almost there. I’ve gone through a lot of errors, and I’m probably right at the end of the errors. I might be able to start actually training it tomorrow, but for now I’ll stop.
phase 1 (sft) is done and phase 2 (rlvr) is running now on kaggle. this is the part where the model actually gets
trained on solving coding problems with our verifier giving rewards, not just imitating fable data.
honestly this is the part i care about more. sft just makes it mimic. rlvr is where it learns to actually fix
code. grpo with proportional rewards = the model gets partial credit for getting some tests passing, which is way
better than all-or-nothing.
while it runs im just waiting tbh. not much to build. the pipeline works, the eval works, the agent works.
next after this: full benchmark run. humaneval, swebench, agentic eval. we’ll see if all this actually made the
model good at coding or if i just spent a week on a worse qwen lol.
finally got the qwen finetune to actually run with 625 steps, took like 8 hours on kaggle. it finished.
havent run full benchmarks yet cause i was busy building other stuff while it trained. but it trained. thats the
main thing.
I also built a swebench agent that can actually navigate repos and edit files and make patches. not just the basic agent
loop that runs commands. this one actually works for real se tasks.
also added swebench eval so we can measure if the model is actually good at fixing bugs and coding
then i’ll run the benchmarks on the trained model and see if its actually any good lol.
So last time I had this whole plan. 10B MoE, from scratch, SwiGLU, GQA, all that. And I actually built it. Like 60 Python files, tests passing, RL pipeline, self-play data gen, the whole thing. It was kinda sick ngl.
But then I was like… wait. I’m building an ENGINE that TRAINS coding agents. Not the agent. And the engine is cool but training a 10B model from zero on $30 of Modal credits is not how you beat GLM-5.2.
You know what beats GLM-5.2? Fine-tuning a model that already knows how to code.
Qwen3.5-9B came out. 9B params. Fits on a Kaggle T4 with 4-bit QLoRA. And Kaggle gives me 30 HOURS of free GPU. 2× T4. That’s literally free training.
So I had to adapt the entire codebase to work with HuggingFace models instead of my custom GPT. Made like 5 new files. All the verifier/agent/reward stuff I built for the MoE? Now works with Qwen too. Didn’t have to
rewrite everything — just slapped a Qwen adapter on top.
Found this dataset on HF: Nexlab/fable5-agentic-coding-sft. 160K rows of Claude Fable 5 output. Like actual coding traces — building games, fixing bugs, writing shell scripts. Not just “write a function that passes a
test.” Real agentic stuff.
Training right now actually. Qwen3.5-9B on 10K rows. Should take like 8 hours on 2× T4. We’ll see if it doesn’t OOM again lol.
While waiting for training I read papers:
the first phase of training is going on right now, i’ll post another devlog once it’s done!
Devlog #4 — wait, why am I training on Wikipedia?
Last week I got le gros chaton (my from-scratch transformer) to actually train. Ran it on wikitext-103 in a Colab notebook on a free T4, 12k steps, val loss hit 3.73. Felt insane for something I wrote myself from PyTorch primitives.
But then I looked at what it generated. It could do English-ish. It knew about Singapore and stuff. The moment I asked it to write code? Total garbage. Fair enough. It has never seen a single line of code.
the pivot
I thought about what I actually want this thing to do. Answer: a coding agent. Something that mogs on terminal-bench, that you give a task and it runs commands, fixes its own bugs, gets it done. Qwen-coder territory.
Wikitext won’t get me there. You can’t learn Python from Wikipedia articles about the snake.
So the plan changed. The big project is now le fat chaton, the bigger sibling. And it’s a coder.
the architecture stuff
I went down a rabbit hole on what frontier coding models do. They’re basically all mixture-of-experts (MoE) now. Qwen3-coder is 480B params / 35B active. Deepseek-coder-v2-lite is 16B / 2.4B active. The trick:
Runs like a small model, knows like a big one. Exactly what I want for a snappy terminal agent.
So I rewrote the model. Added an MoE class. A gate routes each token to its top-2 experts out of 8, with a load-balance loss so the router doesn’t pick the same expert every time. Also threw in:
Fat config math: ~10.25B total / ~3.65B active. Not building that locally, it would crash my PC again.
the data question
Wikitext was a fine proof. For the coder I need code. Options:
Going with starcoderdata Python, blended with ~15-20% cosmopedia (prose) so it has general knowledge. That blend is the Qwen-coder recipe.
am I warm-starting from wikitext?
No. Different architecture entirely (17M dense vs 10B MoE, weights don’t fit). Even if they did, warm-starting a coder from prose wastes compute unlearning prose. Fresh random init on the mixed corpus. Clean slate.
This went from “lets make a little model that talks” to “lets build a coding agent that mogs the big labs” real fast. Ambitious for a solo student with a 2070 and $30 of Modal credits? Absolutely. Doing it anyway? Yeah.
Next: the eval harness so I can measure if this is making the model better at code (pass@1, pass@5 on HumanEval). Val loss going down means nothing if it still can’t write a
DEVLOG #3: teaching it to talk (fine-tuning)
the base model was a completer. ask it “what is 2+2?” and it just continues the sentence. fine-tuning is what makes it actually answer: same model, more training, but on prompt/response pairs.
i wrote ~48 Q&A pairs by hand. trivia, math, jokes, hellos. all in the same rigid Q: …\nA: format. new trick: loss masking. only the response counts toward the loss, not the prompt, so i set prompt targets to -100 (pytorch’s cross_entropy ignores that automatically, zero model changes). tested the mask boundary in isolation first. wrong mask = 400 steps of training the wrong thing.
the run: load base weights, 400 steps, lower lr. loss went 12.3 to 0.02.then the reality check. it nails everything in the set. capitals, math, jokes, “who are you,” verbatim. but something NOT in the set? slop. 17M params + 48 examples is a lookup table, not a reasoner. real chat models are billions of params. not a bug, just the scale.but it’s finally coherent. the first base model was word salad. now you type a question and get a real answer back that makes sense.
it’s tiny and dumb and can’t generalize, but it actually talks. that’s the win.
full pipeline done: tokenizer, model from scratch, pretrain on wikipedia, fine-tune, chat. mine, it talks, i understand every piece.
DEVLOG #2: real data, real loss, and a lesson about memorizing
split my data into 90% train / 10% val. before i only had one number, training loss, and it lies to you. you can’t tell learning from memorizing with just that. now i check both every 200 steps. rule: both go down = learning. train down but val up = memorizing = useless.also made the model bigger, 7M -> 17.7M params. immediately ran out of gpu memory lol. dropped batch size to 32 to fit my 8GB card.training: 3000 steps. loss started at 158 (should be ~10 for random , my first pass blew up and made garbage). recovered fast though, didn’t ruin the run.
right now the llm is spitting out gibberish and random words but after finetuning it should sound more coherent
DEVLOG #1: wiki text training
so i finally got the model to train on actual data instead of that one paragraph about singapore nature reserves lol. before this the whole thing was basically a joke, i trained a 7M parameter transformer on like 134 tokens and it just spat out jumbled fragments of the same sentence over and over. cool proof it worked but definitely not a “language model” in any real sense.anyway. the big move this week was swapping out the tiny json file for wikitext-2. that’s a huggingface dataset of wikipedia text, about 2.4 million tokens once you filter out the empty lines. that’s… a lot more than 134 lol. encoding it took maybe half a minute with tiktoken and the whole tensor fits on my gpu no problem (it’s only like 8MB of ints).