<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1">
<url><loc>https://mvgpt.nenuadrian.com/</loc><lastmod>2026-10-20</lastmod></url>
<url><loc>https://mvgpt.nenuadrian.com/about/</loc></url>
<url><loc>https://mvgpt.nenuadrian.com/ep001-architecture/</loc><lastmod>2026-10-15</lastmod><image:image><image:loc>https://i.ytimg.com/vi/Vff1s2GzI_o/maxresdefault.jpg</image:loc></image:image><video:video><video:thumbnail_loc>https://i.ytimg.com/vi/Vff1s2GzI_o/maxresdefault.jpg</video:thumbnail_loc><video:title>Build a GPT from scratch in PyTorch | Minimum Viable GPT #1</video:title><video:description>We start a series that builds mvGPT, a minimum viable GPT, from scratch in PyTorch, and takes it through the training pipeline of a language model. We look at TinyStories, the data we&#39;re going to start with, and at Attention Is All You Need, and at what we change from it. Then we go through our decoder-only architecture twice: where its 14.6 million parameters are, and how a prompt flows through it to the next token. And we write it in PyTorch, class by class: the config, causal self-attention, the MLP with GELU written out, the transformer block, the GPT and its generate function. Then we print the model the way PyTorch sees it.</video:description><video:player_loc>https://www.youtube.com/embed/Vff1s2GzI_o</video:player_loc><video:duration>1900</video:duration><video:publication_date>2026-10-15</video:publication_date><video:tag>gpt</video:tag><video:tag>transformer</video:tag><video:tag>pytorch</video:tag><video:tag>language model</video:tag><video:tag>llm</video:tag><video:tag>attention is all you need</video:tag><video:tag>self-attention</video:tag><video:tag>multi-head attention</video:tag><video:tag>gelu</video:tag><video:tag>tinystories</video:tag><video:tag>deep learning</video:tag><video:tag>machine learning</video:tag><video:tag>from scratch</video:tag><video:tag>mvgpt</video:tag></video:video></url>
<url><loc>https://mvgpt.nenuadrian.com/ep002-pretraining/</loc><lastmod>2026-10-15</lastmod><image:image><image:loc>https://i.ytimg.com/vi/KA0aVTQ5Wak/maxresdefault.jpg</image:loc></image:image><video:video><video:thumbnail_loc>https://i.ytimg.com/vi/KA0aVTQ5Wak/maxresdefault.jpg</video:thumbnail_loc><video:title>Pretraining a GPT from scratch in PyTorch | Minimum Viable GPT #2</video:title><video:description>To pretrain our GPT, we write a word-level tokenizer, download TinyStories and store it as token ids, and go through the next-token objective and cross-entropy. Then the training loop: random batches, AdamW with weight decay, a learning rate that warms up and then follows a cosine over the training time, and gradient clipping. We train for ten minutes on a laptop, write stories with the model and with an early checkpoint, try a high temperature, and measure the checkpoints on held-out stories: loss, perplexity, accuracy, and the five likeliest next tokens after &#34;Once upon a time, there was a little&#34;. This is episode 2 of a series that builds mvGPT, a minimum viable GPT, from scratch in PyTorch, and takes it through the training pipeline of a language model.</video:description><video:player_loc>https://www.youtube.com/embed/KA0aVTQ5Wak</video:player_loc><video:duration>1603</video:duration><video:publication_date>2026-10-15</video:publication_date><video:tag>gpt</video:tag><video:tag>pretraining</video:tag><video:tag>pytorch</video:tag><video:tag>language model</video:tag><video:tag>llm</video:tag><video:tag>tokenizer</video:tag><video:tag>tinystories</video:tag><video:tag>cross entropy</video:tag><video:tag>adamw</video:tag><video:tag>learning rate schedule</video:tag><video:tag>perplexity</video:tag><video:tag>training loop</video:tag><video:tag>deep learning</video:tag><video:tag>from scratch</video:tag><video:tag>mvgpt</video:tag></video:video></url>
<url><loc>https://mvgpt.nenuadrian.com/ep003-sft/</loc><lastmod>2026-10-15</lastmod><image:image><image:loc>https://i.ytimg.com/vi/WUsVr66Bgq0/maxresdefault.jpg</image:loc></image:image><video:video><video:thumbnail_loc>https://i.ytimg.com/vi/WUsVr66Bgq0/maxresdefault.jpg</video:thumbnail_loc><video:title>SFT: fine-tuning a GPT to follow instructions | Minimum Viable GPT #3</video:title><video:description>A pretrained model is an autocomplete, so we fine-tune ours on TinyStories-Instruct, where each story comes with instructions: words to use, features such as a dialogue, a sentence the story should contain, and a summary. We parse the instructions into one order, mask the loss so the model learns the story and not the instruction, pad batches of different lengths, and fine-tune for ten minutes at a lower learning rate. Then we compare the model before and after, on how many of the requested words its stories use, how often they end on their own, and the loss on held-out stories. Last, we swap the run&#39;s JSON log for TensorBoard, and read its logs back in Python to plot them with matplotlib. This is episode 3 of a series that builds mvGPT, a minimum viable GPT, from scratch in PyTorch, and takes it through the training pipeline of a language model.</video:description><video:player_loc>https://www.youtube.com/embed/WUsVr66Bgq0</video:player_loc><video:duration>1609</video:duration><video:publication_date>2026-10-15</video:publication_date><video:tag>gpt</video:tag><video:tag>supervised fine-tuning</video:tag><video:tag>sft</video:tag><video:tag>instruction tuning</video:tag><video:tag>pytorch</video:tag><video:tag>language model</video:tag><video:tag>llm</video:tag><video:tag>tinystories</video:tag><video:tag>loss masking</video:tag><video:tag>cross entropy</video:tag><video:tag>evaluation</video:tag><video:tag>tensorboard</video:tag><video:tag>matplotlib</video:tag><video:tag>deep learning</video:tag><video:tag>from scratch</video:tag><video:tag>mvgpt</video:tag></video:video></url>
<url><loc>https://mvgpt.nenuadrian.com/ep004-kv-cache/</loc><lastmod>2026-10-15</lastmod><image:image><image:loc>https://i.ytimg.com/vi/JPlzOZouQxQ/maxresdefault.jpg</image:loc></image:image><video:video><video:thumbnail_loc>https://i.ytimg.com/vi/JPlzOZouQxQ/maxresdefault.jpg</video:thumbnail_loc><video:title>KV cache from scratch in PyTorch | Minimum Viable GPT #4</video:title><video:description>Our model writes a token at a time, and runs the whole story through all its blocks for each one, so we give it a KV cache. As attention is causal, the keys and values of the earlier tokens don&#39;t change, so we keep them in a cache, a set per block, and run the new token alone. We add the cache to attention, with the positions and the mask it needs, and use it to generate. Then we check that it changes nothing, with matching logits, stories and evaluation numbers, and time it on a laptop&#39;s CPU and GPU: about four times faster on the CPU, and less on the GPU for one story, as with a model this small, most of a step on the GPU goes to launching its operations. Last, what a KV cache costs at the scale of Llama 3.1. This is episode 4 of a series that builds mvGPT, a minimum viable GPT, from scratch in PyTorch, and takes it through the training pipeline of a language model.</video:description><video:player_loc>https://www.youtube.com/embed/JPlzOZouQxQ</video:player_loc><video:duration>1198</video:duration><video:publication_date>2026-10-15</video:publication_date><video:tag>gpt</video:tag><video:tag>kv cache</video:tag><video:tag>inference</video:tag><video:tag>generation</video:tag><video:tag>attention</video:tag><video:tag>pytorch</video:tag><video:tag>language model</video:tag><video:tag>llm</video:tag><video:tag>transformer</video:tag><video:tag>benchmark</video:tag><video:tag>gpu</video:tag><video:tag>mps</video:tag><video:tag>grouped-query attention</video:tag><video:tag>vllm</video:tag><video:tag>from scratch</video:tag><video:tag>mvgpt</video:tag></video:video></url>
<url><loc>https://mvgpt.nenuadrian.com/ep005-deploy/</loc><lastmod>2026-10-16</lastmod><image:image><image:loc>https://i.ytimg.com/vi/rn72Y_9dVE0/maxresdefault.jpg</image:loc></image:image><video:video><video:thumbnail_loc>https://i.ytimg.com/vi/rn72Y_9dVE0/maxresdefault.jpg</video:thumbnail_loc><video:title>Deploy a GPT: Hugging Face, Gradio, a browser | Minimum Viable GPT #5</video:title><video:description>A checkpoint loads with our own code and nothing else, so today we deploy the model: to the Hugging Face Hub, and to a VPS that hosts it and serves it. It has GPT-2&#39;s architecture, so we save its weights under GPT-2&#39;s names, write its word-level vocabulary as a tokenizer.json, and check that transformers loads it with our token ids and logits. We export it to ONNX, quantize it to 8 bits, and push it to the Hugging Face Hub, with a model card and a tag per episode. Then a Gradio app loads each version from the Hub and writes stories, on my machine, and in Docker on a VPS, deployed over SSH. Last, a single page runs the model in the browser with Transformers.js, downloading it when you ask for a story. This is episode 5 of a series that builds mvGPT, a minimum viable GPT, from scratch in PyTorch, and takes it through the training pipeline of a language model.</video:description><video:player_loc>https://www.youtube.com/embed/rn72Y_9dVE0</video:player_loc><video:duration>1659</video:duration><video:publication_date>2026-10-16</video:publication_date><video:tag>gpt</video:tag><video:tag>deployment</video:tag><video:tag>hugging face</video:tag><video:tag>transformers</video:tag><video:tag>transformers.js</video:tag><video:tag>gradio</video:tag><video:tag>onnx</video:tag><video:tag>quantization</video:tag><video:tag>docker</video:tag><video:tag>vps</video:tag><video:tag>pytorch</video:tag><video:tag>language model</video:tag><video:tag>llm</video:tag><video:tag>gpt-2</video:tag><video:tag>tokenizer</video:tag><video:tag>safetensors</video:tag><video:tag>from scratch</video:tag><video:tag>mvgpt</video:tag></video:video></url>
<url><loc>https://mvgpt.nenuadrian.com/ep006-profiling/</loc><lastmod>2026-10-16</lastmod><image:image><image:loc>https://i.ytimg.com/vi/7C0USj9KtI0/maxresdefault.jpg</image:loc></image:image><video:video><video:thumbnail_loc>https://i.ytimg.com/vi/7C0USj9KtI0/maxresdefault.jpg</video:thumbnail_loc><video:title>Profiling a GPT with PyTorch&#39;s profiler | Minimum Viable GPT #6</video:title><video:description>We export the model with torch.export and look at it in Google&#39;s Model Explorer, as a graph of 163 operations. Then PyTorch&#39;s profiler shows where the time goes, on a full pass and while the model writes a token at a time, on the CPU and on the GPU, where the profiler times the CPU handing the work over. We colour the graph by each operation&#39;s time, and measure decisions in the code: our GELU written out, attention written by hand, torch.compile and the size of the vocabulary. Each changes the speed by a different amount on the CPU and on the GPU, so we measure both before we decide what to keep. This is episode 6 of a series that builds mvGPT, a minimum viable GPT, from scratch in PyTorch, and takes it through the training pipeline of a language model.</video:description><video:player_loc>https://www.youtube.com/embed/7C0USj9KtI0</video:player_loc><video:duration>1100</video:duration><video:publication_date>2026-10-16</video:publication_date><video:tag>gpt</video:tag><video:tag>profiling</video:tag><video:tag>pytorch profiler</video:tag><video:tag>model explorer</video:tag><video:tag>torch.export</video:tag><video:tag>torch.compile</video:tag><video:tag>performance</video:tag><video:tag>gpu</video:tag><video:tag>mps</video:tag><video:tag>cpu</video:tag><video:tag>attention</video:tag><video:tag>gelu</video:tag><video:tag>pytorch</video:tag><video:tag>language model</video:tag><video:tag>llm</video:tag><video:tag>from scratch</video:tag><video:tag>mvgpt</video:tag></video:video></url>
<url><loc>https://mvgpt.nenuadrian.com/ep007-dpo/</loc><lastmod>2026-10-16</lastmod><image:image><image:loc>https://i.ytimg.com/vi/aQ4WxQfB2S4/maxresdefault.jpg</image:loc></image:image><video:video><video:thumbnail_loc>https://i.ytimg.com/vi/aQ4WxQfB2S4/maxresdefault.jpg</video:thumbnail_loc><video:title>DPO: teaching a GPT from preferences | Minimum Viable GPT #7</video:title><video:description>Supervised fine-tuning shows a model the answers we want, and preference optimisation shows it two answers and which is better. Our preferences are scored by code: the fine-tuned model writes four stories for an instruction, and the one that uses the most of the words asked for is preferred to the one that uses the fewest. Then direct preference optimisation, DPO, learns from 2,000 pairs, against a frozen copy of the model, with no reward model and no reinforcement learning. We measure the share of the requested words its stories use, and what that costs on held-out stories, and see reward hacking: the model raising its score with longer stories, which have more chances to use the words, whether or not they&#39;re better. This is episode 7 of a series that builds mvGPT, a minimum viable GPT, from scratch in PyTorch, and takes it through the training pipeline of a language model.</video:description><video:player_loc>https://www.youtube.com/embed/aQ4WxQfB2S4</video:player_loc><video:duration>1038</video:duration><video:publication_date>2026-10-16</video:publication_date><video:tag>gpt</video:tag><video:tag>dpo</video:tag><video:tag>direct preference optimization</video:tag><video:tag>preference optimization</video:tag><video:tag>rlhf</video:tag><video:tag>alignment</video:tag><video:tag>fine-tuning</video:tag><video:tag>pytorch</video:tag><video:tag>language model</video:tag><video:tag>llm</video:tag><video:tag>tinystories</video:tag><video:tag>reward hacking</video:tag><video:tag>evaluation</video:tag><video:tag>from scratch</video:tag><video:tag>mvgpt</video:tag></video:video></url>
<url><loc>https://mvgpt.nenuadrian.com/ep008-ppo/</loc><lastmod>2026-10-18</lastmod><image:image><image:loc>https://i.ytimg.com/vi/8ewa70rUPME/maxresdefault.jpg</image:loc></image:image><video:video><video:thumbnail_loc>https://i.ytimg.com/vi/8ewa70rUPME/maxresdefault.jpg</video:thumbnail_loc><video:title>PPO: reinforcement learning for a GPT | Minimum Viable GPT #8</video:title><video:description>DPO learned from pairs of stories written ahead of time. Today the model learns from its own stories as it writes them, with reinforcement learning: each rollout writes 128 stories, a reward scored by code counts the share of the requested words they use, a critic learns what score to expect, and proximal policy optimisation, PPO, makes the stories that did better than expected more likely, with its clipped objective and a KL penalty that keeps the model near the fine-tuned one. We go through the PPO paper and InstructGPT, write it in PyTorch, train for ten minutes with a small penalty and a large one, and measure both against the fine-tuned model and DPO, along with what&#39;s real and what&#39;s scaled down. This is episode 8 of a series that builds mvGPT, a minimum viable GPT, from scratch in PyTorch, and takes it through the training pipeline of a language model.</video:description><video:player_loc>https://www.youtube.com/embed/8ewa70rUPME</video:player_loc><video:duration>1343</video:duration><video:publication_date>2026-10-18</video:publication_date><video:tag>gpt</video:tag><video:tag>ppo</video:tag><video:tag>proximal policy optimization</video:tag><video:tag>reinforcement learning</video:tag><video:tag>rlhf</video:tag><video:tag>instructgpt</video:tag><video:tag>kl divergence</video:tag><video:tag>advantage</video:tag><video:tag>policy gradient</video:tag><video:tag>pytorch</video:tag><video:tag>language model</video:tag><video:tag>llm</video:tag><video:tag>tinystories</video:tag><video:tag>from scratch</video:tag><video:tag>mvgpt</video:tag></video:video></url>
<url><loc>https://mvgpt.nenuadrian.com/ep009-lora/</loc><lastmod>2026-10-16</lastmod><image:image><image:loc>https://i.ytimg.com/vi/m5THIkAJJFk/maxresdefault.jpg</image:loc></image:image><video:video><video:thumbnail_loc>https://i.ytimg.com/vi/m5THIkAJJFk/maxresdefault.jpg</video:thumbnail_loc><video:title>LoRA: fine-tuning a GPT with 2% of its weights | Minimum Viable GPT #9</video:title><video:description>Full fine-tuning updates each of the model&#39;s weights and saves a full copy of it. Low-rank adaptation, LoRA, freezes the pretrained weights and trains a small update beside each linear layer of attention and the MLP, as the product of two thin matrices, B and A, with B starting at zero. We write it in PyTorch, fine-tune on instructions for ten minutes, and merge the update back into the weights, then measure it against full fine-tuning from episode three: the weights trained, the file we keep, the optimiser&#39;s memory, the losses and the requested words the stories use, along with what changes for models of billions of parameters. This is episode 9 of a series that builds mvGPT, a minimum viable GPT, from scratch in PyTorch, and takes it through the training pipeline of a language model.</video:description><video:player_loc>https://www.youtube.com/embed/m5THIkAJJFk</video:player_loc><video:duration>898</video:duration><video:publication_date>2026-10-16</video:publication_date><video:tag>lora</video:tag><video:tag>low-rank adaptation</video:tag><video:tag>peft</video:tag><video:tag>parameter-efficient fine-tuning</video:tag><video:tag>fine-tuning</video:tag><video:tag>adapters</video:tag><video:tag>pytorch</video:tag><video:tag>gpt</video:tag><video:tag>language model</video:tag><video:tag>llm</video:tag><video:tag>tinystories</video:tag><video:tag>instruction tuning</video:tag><video:tag>from scratch</video:tag><video:tag>mvgpt</video:tag></video:video></url>
<url><loc>https://mvgpt.nenuadrian.com/ep010-rope/</loc><lastmod>2026-10-18</lastmod><image:image><image:loc>https://i.ytimg.com/vi/CVeEPW67Gv8/maxresdefault.jpg</image:loc></image:image><video:video><video:thumbnail_loc>https://i.ytimg.com/vi/CVeEPW67Gv8/maxresdefault.jpg</video:thumbnail_loc><video:title>RoPE: rotary position embeddings from scratch | Minimum Viable GPT #10</video:title><video:description>Our model learned a table of positions, a vector for each of its 256 places, which stops at the context window and keeps its KV cache from sliding past it. We replace it with rotary position embeddings, from the RoFormer paper: each query and key is turned by an angle that grows with its position, so attention depends on how far apart two tokens are. We add them to the model as a config option, with a cache that slides, pretrain for ten minutes next to episode two&#39;s model, and measure both past their context window, on the CPU and the GPU of a laptop. This is episode 10 of a series that builds mvGPT, a minimum viable GPT, from scratch in PyTorch, and takes it through the training pipeline of a language model.</video:description><video:player_loc>https://www.youtube.com/embed/CVeEPW67Gv8</video:player_loc><video:duration>1043</video:duration><video:publication_date>2026-10-18</video:publication_date><video:tag>gpt</video:tag><video:tag>rope</video:tag><video:tag>rotary position embeddings</video:tag><video:tag>position embeddings</video:tag><video:tag>roformer</video:tag><video:tag>kv cache</video:tag><video:tag>context window</video:tag><video:tag>attention</video:tag><video:tag>transformer</video:tag><video:tag>pytorch</video:tag><video:tag>language model</video:tag><video:tag>llm</video:tag><video:tag>tinystories</video:tag><video:tag>from scratch</video:tag><video:tag>mvgpt</video:tag></video:video></url>
<url><loc>https://mvgpt.nenuadrian.com/ep011-bpe/</loc><lastmod>2026-10-18</lastmod><image:image><image:loc>https://i.ytimg.com/vi/_o0mJYWdKQQ/maxresdefault.jpg</image:loc></image:image><video:video><video:thumbnail_loc>https://i.ytimg.com/vi/_o0mJYWdKQQ/maxresdefault.jpg</video:thumbnail_loc><video:title>BPE in C++: a byte-level tokenizer for a GPT | Minimum Viable GPT #11</video:title><video:description>Our word-level tokenizer turns any word outside its ten thousand into an unknown token, and drops spaces and new lines. We replace it with byte-pair encoding, the tokenizer of GPT-2: a Python reference after the paper, then that algorithm in C++, with a heap of pair counts, built into a Python module with pybind11 and tested against the reference. The model gets a tokenizer on top of it, we pretrain on the stories in BPE, time the C++ against Python, and compare the word-level and BPE models in bits per character, as their losses per token can&#39;t be compared. This is episode 11 of a series that builds mvGPT, a minimum viable GPT, from scratch in PyTorch, and takes it through the training pipeline of a language model.</video:description><video:player_loc>https://www.youtube.com/embed/_o0mJYWdKQQ</video:player_loc><video:duration>1898</video:duration><video:publication_date>2026-10-18</video:publication_date><video:tag>bpe</video:tag><video:tag>byte pair encoding</video:tag><video:tag>tokenizer</video:tag><video:tag>byte-level bpe</video:tag><video:tag>subword units</video:tag><video:tag>c++</video:tag><video:tag>pybind11</video:tag><video:tag>gpt-2</video:tag><video:tag>tokenization</video:tag><video:tag>bits per character</video:tag><video:tag>pytorch</video:tag><video:tag>gpt</video:tag><video:tag>language model</video:tag><video:tag>llm</video:tag><video:tag>from scratch</video:tag><video:tag>mvgpt</video:tag></video:video></url>
<url><loc>https://mvgpt.nenuadrian.com/ep012-distributed/</loc><lastmod>2026-10-18</lastmod><image:image><image:loc>https://i.ytimg.com/vi/5-RJVvuGZyE/maxresdefault.jpg</image:loc></image:image><video:video><video:thumbnail_loc>https://i.ytimg.com/vi/5-RJVvuGZyE/maxresdefault.jpg</video:thumbnail_loc><video:title>Distributed training in PyTorch: 4 GPUs, DDP | Minimum Viable GPT #12</video:title><video:description>Our model has about fourteen million parameters and trains for ten minutes on a laptop, so this time we rent four RTX 4090s on Vast.ai and pretrain one about six times bigger, in GPT-2 small&#39;s shape, with data parallelism: PyTorch&#39;s DistributedDataParallel and torchrun, tried first on the laptop with gloo. We tokenize all of TinyStories on all of the rented machine&#39;s cores, measure the training speed on one, two and four GPUs, train for thirty minutes, and compare the result with the laptop&#39;s model in bits per character and in its stories. Then we save it for Hugging Face as a GPT-NeoX, with a byte-level BPE tokenizer.json. This is episode 12 of a series that builds mvGPT, a minimum viable GPT, from scratch in PyTorch, and takes it through the training pipeline of a language model.</video:description><video:player_loc>https://www.youtube.com/embed/5-RJVvuGZyE</video:player_loc><video:duration>1726</video:duration><video:publication_date>2026-10-18</video:publication_date><video:tag>distributed training</video:tag><video:tag>data parallel</video:tag><video:tag>distributeddataparallel</video:tag><video:tag>ddp</video:tag><video:tag>torchrun</video:tag><video:tag>nccl</video:tag><video:tag>multi-gpu</video:tag><video:tag>rtx 4090</video:tag><video:tag>vast.ai</video:tag><video:tag>gpu rental</video:tag><video:tag>pytorch</video:tag><video:tag>pretraining</video:tag><video:tag>gpt-2 small</video:tag><video:tag>gpt-neox</video:tag><video:tag>hugging face</video:tag><video:tag>gpt</video:tag><video:tag>language model</video:tag><video:tag>llm</video:tag><video:tag>from scratch</video:tag><video:tag>mvgpt</video:tag></video:video></url>
<url><loc>https://mvgpt.nenuadrian.com/ep013-flash-attention/</loc><lastmod>2026-10-16</lastmod><image:image><image:loc>https://i.ytimg.com/vi/HEYzYWquKos/maxresdefault.jpg</image:loc></image:image><video:video><video:thumbnail_loc>https://i.ytimg.com/vi/HEYzYWquKos/maxresdefault.jpg</video:thumbnail_loc><video:title>Flash attention from scratch: PyTorch, Triton | Minimum Viable GPT #13</video:title><video:description>Attention as the paper writes it keeps a table of scores that grows with the square of the length, so we write it by hand and measure its memory and time on the Mac. Then flash attention&#39;s online softmax computes that attention a block at a time, first in PyTorch, then as a Triton kernel on a rented RTX 4090, forwards and backwards, tested against PyTorch&#39;s attention in float64. We find that PyTorch&#39;s attention already runs FlashAttention-2 on NVIDIA GPUs, measure our kernel against it, and pretrain the model with each. This is episode 13 of a series that builds mvGPT, a minimum viable GPT, from scratch in PyTorch, and takes it through the training pipeline of a language model.</video:description><video:player_loc>https://www.youtube.com/embed/HEYzYWquKos</video:player_loc><video:duration>2346</video:duration><video:publication_date>2026-10-16</video:publication_date><video:tag>flash attention</video:tag><video:tag>flashattention</video:tag><video:tag>flashattention-2</video:tag><video:tag>triton</video:tag><video:tag>gpu kernel</video:tag><video:tag>cuda</video:tag><video:tag>attention</video:tag><video:tag>online softmax</video:tag><video:tag>pytorch</video:tag><video:tag>scaled dot product attention</video:tag><video:tag>apple silicon</video:tag><video:tag>rtx 4090</video:tag><video:tag>gpt</video:tag><video:tag>language model</video:tag><video:tag>llm</video:tag><video:tag>from scratch</video:tag><video:tag>mvgpt</video:tag></video:video></url>
<url><loc>https://mvgpt.nenuadrian.com/ep014-serving/</loc><lastmod>2026-10-18</lastmod><image:image><image:loc>https://i.ytimg.com/vi/6XGhd_83uwU/maxresdefault.jpg</image:loc></image:image><video:video><video:thumbnail_loc>https://i.ytimg.com/vi/6XGhd_83uwU/maxresdefault.jpg</video:thumbnail_loc><video:title>Batching: serving a GPT to many users at once | Minimum Viable GPT #14</video:title><video:description>In a game such as nanoMMO, the MMO of my other series, many players could ask a storyteller for a story at once. So we serve the model from the Hub as an API in the shape of OpenAI&#39;s completions, with Python&#39;s own HTTP server and a thread for the model, and measure it with a script that simulates a crowd of players. One request at a time, the wait grows with the queue. Then the server writes the stories for the waiting requests together, as a batch padded on the left, with an attention mask and each row&#39;s own positions, tested against writing each prompt alone, and we measure it again, with batches of 16 and 64. The server goes into a Docker image of its own, and we look at vLLM, with continuous batching and PagedAttention, as the alternative, which runs on the CPU too. This is episode 14 of a series that builds mvGPT, a minimum viable GPT, from scratch in PyTorch, and takes it through the training pipeline of a language model.</video:description><video:player_loc>https://www.youtube.com/embed/6XGhd_83uwU</video:player_loc><video:duration>1515</video:duration><video:publication_date>2026-10-18</video:publication_date><video:tag>llm serving</video:tag><video:tag>batching</video:tag><video:tag>dynamic batching</video:tag><video:tag>continuous batching</video:tag><video:tag>vllm</video:tag><video:tag>openai api</video:tag><video:tag>completions api</video:tag><video:tag>http server</video:tag><video:tag>python</video:tag><video:tag>threading</video:tag><video:tag>kv cache</video:tag><video:tag>padding</video:tag><video:tag>attention mask</video:tag><video:tag>docker</video:tag><video:tag>pytorch</video:tag><video:tag>transformers</video:tag><video:tag>gpt</video:tag><video:tag>language model</video:tag><video:tag>llm</video:tag><video:tag>from scratch</video:tag><video:tag>mvgpt</video:tag><video:tag>nanommo</video:tag></video:video></url>
<url><loc>https://mvgpt.nenuadrian.com/ep015-diffusion/</loc><lastmod>2026-10-18</lastmod><image:image><image:loc>https://i.ytimg.com/vi/LVWHstzgqE4/maxresdefault.jpg</image:loc></image:image><video:video><video:thumbnail_loc>https://i.ytimg.com/vi/LVWHstzgqE4/maxresdefault.jpg</video:thumbnail_loc><video:title>Text diffusion: a GPT that writes all at once | Minimum Viable GPT #15</video:title><video:description>A masked diffusion model is the transformer we have, with attention both ways and one new token, [MASK]. It learns to fill in the tokens hidden in a window, from a few to nearly all of them, and it writes a story by starting from a window of [MASK] and unhiding the tokens it&#39;s surest of, a few at a time, anywhere in the story. We write the loss, a bound on the negative log likelihood, and the sampler, next to LLaDA&#39;s code, which trains this recipe at 8 billion parameters. We train it for ten minutes on the laptop and for thirty on four rented RTX 4090s, as episode twelve&#39;s model was, measure it in bits per character against next-token prediction, measure its loss at each share of tokens hidden, time it against the KV cache, fill in the middle of stories, and start a diffusion model from the weights of a next-token model, as Dream 7B did. This is episode 15 of a series that builds mvGPT, a minimum viable GPT, from scratch in PyTorch, and takes it through the training pipeline of a language model.</video:description><video:player_loc>https://www.youtube.com/embed/LVWHstzgqE4</video:player_loc><video:duration>2018</video:duration><video:publication_date>2026-10-18</video:publication_date><video:tag>diffusion language model</video:tag><video:tag>masked diffusion</video:tag><video:tag>text diffusion</video:tag><video:tag>llada</video:tag><video:tag>mdlm</video:tag><video:tag>dream 7b</video:tag><video:tag>discrete diffusion</video:tag><video:tag>denoising</video:tag><video:tag>infilling</video:tag><video:tag>bidirectional attention</video:tag><video:tag>elbo</video:tag><video:tag>gpt</video:tag><video:tag>transformer</video:tag><video:tag>pytorch</video:tag><video:tag>language model</video:tag><video:tag>llm</video:tag><video:tag>from scratch</video:tag><video:tag>rtx 4090</video:tag><video:tag>vast.ai</video:tag><video:tag>mvgpt</video:tag></video:video></url>
<url><loc>https://mvgpt.nenuadrian.com/ep016-grpo/</loc><lastmod>2026-10-18</lastmod><image:image><image:loc>https://i.ytimg.com/vi/SoFl6r8Qz-0/maxresdefault.jpg</image:loc></image:image><video:video><video:thumbnail_loc>https://i.ytimg.com/vi/SoFl6r8Qz-0/maxresdefault.jpg</video:thumbnail_loc><video:title>GRPO: reinforcement learning without a critic | Minimum Viable GPT #16</video:title><video:description>In episode eight, PPO needed a critic to say what score a story should get. Group relative policy optimisation, GRPO, the method behind DeepSeekMath and DeepSeek-R1, does without one: the model writes a group of eight stories for each instruction, and each story&#39;s advantage is its reward against the group&#39;s mean, in units of the group&#39;s spread. We go through the DeepSeekMath and DeepSeek-R1 papers, write GRPO in PyTorch next to our PPO, train for ten minutes with a KL penalty and without one, on episode eight&#39;s reward, and measure both against the fine-tuned model and PPO, along with what&#39;s real and what&#39;s scaled down. This is episode 16 of a series that builds mvGPT, a minimum viable GPT, from scratch in PyTorch, and takes it through the training pipeline of a language model.</video:description><video:player_loc>https://www.youtube.com/embed/SoFl6r8Qz-0</video:player_loc><video:duration>1303</video:duration><video:publication_date>2026-10-18</video:publication_date><video:tag>gpt</video:tag><video:tag>grpo</video:tag><video:tag>group relative policy optimization</video:tag><video:tag>ppo</video:tag><video:tag>reinforcement learning</video:tag><video:tag>deepseek</video:tag><video:tag>deepseek-r1</video:tag><video:tag>deepseekmath</video:tag><video:tag>reasoning</video:tag><video:tag>advantage</video:tag><video:tag>kl divergence</video:tag><video:tag>pytorch</video:tag><video:tag>language model</video:tag><video:tag>llm</video:tag><video:tag>tinystories</video:tag><video:tag>from scratch</video:tag><video:tag>mvgpt</video:tag></video:video></url>
<url><loc>https://mvgpt.nenuadrian.com/ep017-modern-block/</loc><lastmod>2026-10-18</lastmod><image:image><image:loc>https://i.ytimg.com/vi/cPiQO4AilGY/maxresdefault.jpg</image:loc></image:image><video:video><video:thumbnail_loc>https://i.ytimg.com/vi/cPiQO4AilGY/maxresdefault.jpg</video:thumbnail_loc><video:title>RMSNorm, SwiGLU, QK-norm: a modern GPT block | Minimum Viable GPT #17</video:title><video:description>Our transformer block still follows GPT-2&#39;s, with a LayerNorm before each sublayer, GELU in the MLP, and biases in its linear layers and norms. We bring it up to date with the changes recent open models made, from LLaMA to Qwen3: RMSNorm, which divides each token&#39;s channels by their root mean square, with no mean and no bias; SwiGLU, an MLP with a gate, eight thirds of the embedding size wide; QK-norm, an RMSNorm on each head&#39;s queries and keys, which keeps the attention scores from growing with the weights; and no biases. We go through the RMSNorm, GLU variants, QK-norm, ViT-22B, small-scale proxies, LLaMA, PaLM and Qwen3 papers, write each change by hand behind a config field, test it, keep our earlier checkpoints loading as before, and work out the parameter count before and after, along with what&#39;s real and what&#39;s scaled down. This is episode 17 of a series that builds mvGPT, a minimum viable GPT, from scratch in PyTorch, and takes it through the training pipeline of a language model.</video:description><video:player_loc>https://www.youtube.com/embed/cPiQO4AilGY</video:player_loc><video:duration>2172</video:duration><video:publication_date>2026-10-18</video:publication_date><video:tag>gpt</video:tag><video:tag>transformer</video:tag><video:tag>transformer block</video:tag><video:tag>rmsnorm</video:tag><video:tag>swiglu</video:tag><video:tag>glu</video:tag><video:tag>qk-norm</video:tag><video:tag>qk normalization</video:tag><video:tag>layernorm</video:tag><video:tag>silu</video:tag><video:tag>llama</video:tag><video:tag>palm</video:tag><video:tag>qwen3</video:tag><video:tag>olmo 2</video:tag><video:tag>attention logits</video:tag><video:tag>pytorch</video:tag><video:tag>language model</video:tag><video:tag>llm</video:tag><video:tag>from scratch</video:tag><video:tag>mvgpt</video:tag></video:video></url>
<url><loc>https://mvgpt.nenuadrian.com/ep018-gqa/</loc><lastmod>2026-10-18</lastmod><image:image><image:loc>https://i.ytimg.com/vi/SpKMenz36TM/maxresdefault.jpg</image:loc></image:image><video:video><video:thumbnail_loc>https://i.ytimg.com/vi/SpKMenz36TM/maxresdefault.jpg</video:thumbnail_loc><video:title>Grouped-query attention: a smaller KV cache | Minimum Viable GPT #18</video:title><video:description>Our KV cache keeps a key and a value for each of the six heads in each block. With grouped-query attention, from the GQA paper and used in Llama 2&#39;s bigger models and in Llama 3.1, the query heads share their keys and values in groups. We go through multi-query attention, GQA and Llama 2&#39;s papers, draw our six heads three ways, and write it into our model as a config option, with tests against multi-head attention and against writing without the cache. With two key and value heads in place of six, the cache and the key and value projections take a third of the memory, which we work out from the config and print with summary.py. There&#39;s no training this time, just the code and the sizes, along with what&#39;s real and what&#39;s scaled down. This is episode 18 of a series that builds mvGPT, a minimum viable GPT, from scratch in PyTorch, and takes it through the training pipeline of a language model.</video:description><video:player_loc>https://www.youtube.com/embed/SpKMenz36TM</video:player_loc><video:duration>1346</video:duration><video:publication_date>2026-10-18</video:publication_date><video:tag>gpt</video:tag><video:tag>grouped-query attention</video:tag><video:tag>gqa</video:tag><video:tag>multi-query attention</video:tag><video:tag>mqa</video:tag><video:tag>multi-head attention</video:tag><video:tag>kv cache</video:tag><video:tag>attention</video:tag><video:tag>inference</video:tag><video:tag>llama 2</video:tag><video:tag>llama 3</video:tag><video:tag>transformer</video:tag><video:tag>pytorch</video:tag><video:tag>language model</video:tag><video:tag>llm</video:tag><video:tag>from scratch</video:tag><video:tag>mvgpt</video:tag></video:video></url>
<url><loc>https://mvgpt.nenuadrian.com/ep019-web/</loc><lastmod>2026-10-18</lastmod><image:image><image:loc>https://i.ytimg.com/vi/15vafg1wdpI/maxresdefault.jpg</image:loc></image:image><video:video><video:thumbnail_loc>https://i.ytimg.com/vi/15vafg1wdpI/maxresdefault.jpg</video:thumbnail_loc><video:title>Pretraining on the web: a GPT overnight | Minimum Viable GPT #19</video:title><video:description>So far, our models have learned from TinyStories, short stories for small children. This time, we train on FineWeb-Edu, web pages that a classifier scored as educational, with BPE merges learned on the web. We work out how many tokens a night on one GPU can buy, against the Chinchilla paper&#39;s twenty tokens per parameter, give pretraining gradient accumulation and a way to resume from a checkpoint, and train a model of about a hundred and ten million parameters for nearly eight hours, on one RTX 4090 rented on Vast.ai with the four dollars left on the account. In the morning, we measure it on HellaSwag, next to GPT-2 small and to the model we trained on stories, and in bits per character on stories and on web pages. This is episode 19 of a series that builds mvGPT, a minimum viable GPT, from scratch in PyTorch, and takes it through the training pipeline of a language model.</video:description><video:player_loc>https://www.youtube.com/embed/15vafg1wdpI</video:player_loc><video:duration>1603</video:duration><video:publication_date>2026-10-18</video:publication_date><video:tag>pretraining</video:tag><video:tag>fineweb-edu</video:tag><video:tag>fineweb</video:tag><video:tag>web data</video:tag><video:tag>common crawl</video:tag><video:tag>chinchilla</video:tag><video:tag>scaling laws</video:tag><video:tag>gradient accumulation</video:tag><video:tag>checkpointing</video:tag><video:tag>hellaswag</video:tag><video:tag>benchmark</video:tag><video:tag>gpt-2 small</video:tag><video:tag>rtx 4090</video:tag><video:tag>vast.ai</video:tag><video:tag>gpu rental</video:tag><video:tag>bpe</video:tag><video:tag>tokenizer</video:tag><video:tag>pytorch</video:tag><video:tag>gpt</video:tag><video:tag>language model</video:tag><video:tag>llm</video:tag><video:tag>from scratch</video:tag><video:tag>mvgpt</video:tag></video:video></url>
<url><loc>https://mvgpt.nenuadrian.com/ep020-tools/</loc><lastmod>2026-10-18</lastmod><image:image><image:loc>https://i.ytimg.com/vi/UrlqjWEuYH4/maxresdefault.jpg</image:loc></image:image><video:video><video:thumbnail_loc>https://i.ytimg.com/vi/UrlqjWEuYH4/maxresdefault.jpg</video:thumbnail_loc><video:title>LLM tool calling from scratch: a calculator | Minimum Viable GPT #20</video:title><video:description>Last time, we pretrained a model of 110 million parameters on educational web pages, overnight. It writes fluent text, but it can&#39;t do arithmetic. This time, we teach it to call a calculator, as Toolformer did: the model writes the call as plain text, the program running it computes the result and puts it into the text, and the model carries on. We generate fifty thousand questions, fine-tune for ten minutes on the laptop with the questions and the calculator&#39;s results left out of the loss, and measure the calls on held-out questions, worded the way training words them and in new ways, with the calculator and without it. This is episode 20 of a series that builds mvGPT, a minimum viable GPT, from scratch in PyTorch, and takes it through the training pipeline of a language model.</video:description><video:player_loc>https://www.youtube.com/embed/UrlqjWEuYH4</video:player_loc><video:duration>1250</video:duration><video:publication_date>2026-10-18</video:publication_date><video:tag>tool use</video:tag><video:tag>function calling</video:tag><video:tag>calculator</video:tag><video:tag>toolformer</video:tag><video:tag>fine-tuning</video:tag><video:tag>sft</video:tag><video:tag>loss masking</video:tag><video:tag>gpt</video:tag><video:tag>language model</video:tag><video:tag>llm</video:tag><video:tag>from scratch</video:tag><video:tag>mvgpt</video:tag></video:video></url>
<url><loc>https://mvgpt.nenuadrian.com/ep021-agent/</loc><lastmod>2026-10-18</lastmod><image:image><image:loc>https://i.ytimg.com/vi/9SYXGDioA6g/maxresdefault.jpg</image:loc></image:image><video:video><video:thumbnail_loc>https://i.ytimg.com/vi/9SYXGDioA6g/maxresdefault.jpg</video:thumbnail_loc><video:title>AI agent from scratch, with subagents | Minimum Viable GPT #21</video:title><video:description>Last episode, our model learned to call a calculator. This time it becomes an agent: one model, fine-tuned once into three roles. The agent writes and lists files and hands the rest of a task to subagents, the math role with the calculator and the files role, which reads, writes and adds up files. Each subagent is the same model in a fresh context, and only its answer goes back. The files live in a sandbox whose limits the program enforces, whatever the model asks. We generate sixty thousand traces, fine-tune for thirty minutes on the laptop, measure each role on held-out tasks, and compare the agent with subagents against one context on a long task: right more often, with a far smaller context, for more tokens in all. Then we put it in a Gradio chat that shows each step. This is episode 21 of a series that builds mvGPT, a minimum viable GPT, from scratch in PyTorch, and takes it through the training pipeline of a language model.</video:description><video:player_loc>https://www.youtube.com/embed/9SYXGDioA6g</video:player_loc><video:duration>1360</video:duration><video:publication_date>2026-10-18</video:publication_date><video:tag>agents</video:tag><video:tag>ai agents</video:tag><video:tag>subagents</video:tag><video:tag>tool use</video:tag><video:tag>function calling</video:tag><video:tag>sandbox</video:tag><video:tag>orchestrator</video:tag><video:tag>context window</video:tag><video:tag>fine-tuning</video:tag><video:tag>gradio</video:tag><video:tag>gpt</video:tag><video:tag>language model</video:tag><video:tag>llm</video:tag><video:tag>from scratch</video:tag><video:tag>mvgpt</video:tag></video:video></url>
<url><loc>https://mvgpt.nenuadrian.com/ep022-long-context/</loc><lastmod>2026-10-20</lastmod><image:image><image:loc>https://i.ytimg.com/vi/2C2JYv2agzo/maxresdefault.jpg</image:loc></image:image><video:video><video:thumbnail_loc>https://i.ytimg.com/vi/2C2JYv2agzo/maxresdefault.jpg</video:thumbnail_loc><video:title>Long context LLM: stretching RoPE with YaRN | Minimum Viable GPT #22</video:title><video:description>Our web model was pretrained on windows of 1,024 tokens. Its rotary embeddings let it read further, but past the window, its loss climbs, as some pairs of channels turn to angles it didn&#39;t see in training. We stretch the rotations four ways: position interpolation, NTK-aware interpolation, NTK-by-parts and YaRN, from the papers that introduced them, and measure each on long web pages, by position, against a sliding window, and with the pass key test, a number hidden in filler. YaRN keeps the loss flat out to 4,096 tokens with no training at all, and finds the key thousands of tokens back. Then fifteen minutes of fine-tuning on long pages, on the laptop, with position interpolation and with YaRN, and what a longer window costs in memory, along with what&#39;s real and what&#39;s scaled down. This is episode 22 of a series that builds mvGPT, a minimum viable GPT, from scratch in PyTorch, and takes it through the training pipeline of a language model.</video:description><video:player_loc>https://www.youtube.com/embed/2C2JYv2agzo</video:player_loc><video:duration>2330</video:duration><video:publication_date>2026-10-20</video:publication_date><video:tag>gpt</video:tag><video:tag>long context</video:tag><video:tag>context window</video:tag><video:tag>rope</video:tag><video:tag>rotary position embeddings</video:tag><video:tag>yarn</video:tag><video:tag>position interpolation</video:tag><video:tag>ntk-aware</video:tag><video:tag>rope scaling</video:tag><video:tag>context extension</video:tag><video:tag>passkey retrieval</video:tag><video:tag>kv cache</video:tag><video:tag>fine-tuning</video:tag><video:tag>pytorch</video:tag><video:tag>language model</video:tag><video:tag>llm</video:tag><video:tag>from scratch</video:tag><video:tag>mvgpt</video:tag></video:video></url>
</urlset>
