<?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-22</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&#39;re starting a series where we build mvGPT, a minimum viable GPT, from scratch in PyTorch, and take it through the training pipeline of a language model. In this first episode, we look at TinyStories, the data we start with, and at Attention Is All You Need, and go through our decoder-only architecture. We see where its 14.6 million parameters are and how a prompt flows through it to the next token, then write it in PyTorch, class by class.</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>Today, we pretrain our GPT on TinyStories, starting with a word-level tokenizer and the next-token objective, with cross-entropy as the loss. We write the training loop, with AdamW, a learning rate that warms up and then follows a cosine, and gradient clipping, and train for ten minutes on a laptop. Then we write stories with the model and with an early checkpoint, and measure the checkpoints on held-out stories, from the loss and perplexity to the likeliest next tokens.</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 in this episode we fine-tune ours to follow instructions, with TinyStories-Instruct, where each story comes with words to use, features and a summary. We mask the loss so the model learns the story and not the instruction, pad batches of different lengths, and fine-tune for ten minutes. Then we measure the model before and after, on how many of the requested words its stories use, and move the run&#39;s logs over to TensorBoard.</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 runs the whole story through all its blocks for each token it writes, so this time we give it a KV cache, which keeps the keys and values of the earlier tokens. We add it to attention, with the positions and the mask it needs, and check that it changes nothing, with matching logits and stories. On a laptop, it writes about four times faster on the CPU, and less so on the GPU, and we finish with what a KV cache costs at the scale of Llama 3.1.</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>This time, we deploy our model, first to the Hugging Face Hub as a GPT-2 that transformers can load, with a tokenizer.json, an 8-bit ONNX export 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. And a single web page runs the model in the browser with Transformers.js, downloading it when you ask for a story.</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>In this episode, we look at where our model&#39;s time goes, starting with a graph of its 163 operations in Google&#39;s Model Explorer, exported with torch.export. Then PyTorch&#39;s profiler times a full pass and the writing of a token at a time, on the CPU and on the GPU. And we measure a few decisions in the code, such as our GELU written out, torch.compile and the size of the vocabulary, as each changes the speed by a different amount on each device.</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>In this episode, our model learns from preferences, with direct preference optimisation, DPO, which needs no reward model and no reinforcement learning. The fine-tuned model writes four stories per instruction, and code prefers the one that uses the most of the requested words to the one that uses the fewest. We train on 2,000 of these pairs for ten minutes, measure what changes, and run into reward hacking, as the model raises its score by writing longer stories.</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>This time, our model learns from its own stories as it writes them, with reinforcement learning and proximal policy optimisation, PPO, as in the PPO paper and InstructGPT. A reward scored by code counts the requested words, a critic learns what score to expect, and a KL penalty keeps the model near the fine-tuned one. We train for ten minutes with a small penalty and with a large one, and measure both against the fine-tuned model and DPO.</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>We&#39;re going to fine-tune with low-rank adaptation, LoRA, which freezes the pretrained weights and trains a small update beside each linear layer, as the product of two thin matrices. We write it in PyTorch, fine-tune on instructions for ten minutes with about 2% of the weights, and merge the update back into the model. Then we compare it with full fine-tuning from episode three, on the file we keep, the optimiser&#39;s memory, the losses and the stories.</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 that stops at its context window of 256 tokens, so today 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 pretrain for ten minutes next to episode two&#39;s model, and measure both past their context window, where our KV cache can now slide.</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 vocabulary of ten thousand into an unknown token, so in this episode we replace it with byte-pair encoding, the tokenizer of GPT-2. We write a Python reference after the paper, then the algorithm in C++, built into a Python module with pybind11 and tested against the reference. Then we pretrain on the stories in BPE, time C++ against Python, and compare the models in bits per character, as their losses per token can&#39;t be compared.</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>For this episode, we rent four RTX 4090s on Vast.ai and pretrain a model about six times bigger than our laptop&#39;s, in GPT-2 small&#39;s shape, with PyTorch&#39;s DistributedDataParallel and torchrun. We try it on the laptop first, then measure the training speed on one, two and four GPUs, and train for thirty minutes on all of TinyStories. And we compare the result with the laptop&#39;s model, in bits per character and in its stories, and save it for Hugging Face.</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 in this episode we write flash attention, which computes it a block at a time. We start with attention by hand and its memory on the Mac, then write the online softmax in PyTorch, and then as a Triton kernel on a rented RTX 4090. And we measure our kernel against FlashAttention-2, which PyTorch already runs on NVIDIA GPUs, and pretrain the model with each.</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 this episode, we serve our model to many users at once, say the players of a game like nanoMMO from my other series, through an API in the shape of OpenAI&#39;s completions. Written one request at a time, the wait grows with the queue, so the server writes the stories of the waiting requests together, as a batch padded on the left. We measure it with a script that simulates a crowd of players, put the server in Docker, and look at vLLM as the alternative.</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>This time, our GPT becomes a masked diffusion model, which writes a story by starting from a window of hidden tokens and unhiding the ones it&#39;s surest of, anywhere in the story. We write its loss and its sampler next to LLaDA&#39;s code, and train it for ten minutes on the laptop and for thirty on four rented RTX 4090s. Then we measure it against next-token prediction, fill in the middle of stories, and start a diffusion model from a next-token model&#39;s weights, as Dream 7B did.</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>Today, we write group relative policy optimisation, GRPO, the method behind DeepSeekMath and DeepSeek-R1, which does reinforcement learning without the critic our PPO needed. The model writes eight stories per instruction, and each story&#39;s advantage is its reward measured against the group&#39;s mean. We 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.</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, so in this episode we bring it up to date with the changes open models made, from LLaMA to Qwen3. Following their papers, we write RMSNorm, SwiGLU, QK-norm and linear layers without biases by hand, each behind a config field, with tests against PyTorch&#39;s own. And we keep our earlier checkpoints loading as before, and work out the parameter count before and after.</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, so this time we add grouped-query attention, as in Llama 2&#39;s bigger models and in Llama 3.1. Its query heads share their keys and values in groups, and we 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 takes a third of the memory.</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>In this episode, we move our model from children&#39;s stories to the web, with FineWeb-Edu, pages that a classifier scored as educational, and BPE merges learned on them. We work out how many tokens a night on one GPU can buy, against the Chinchilla paper&#39;s twenty tokens per parameter, and train a model of about 110 million parameters for nearly eight hours on a rented RTX 4090. In the morning, we measure it on HellaSwag next to GPT-2 small, and in bits per character on stories and on web pages.</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>Our web model writes fluent text but can&#39;t do arithmetic, so today we teach it to call a calculator, as Toolformer did, writing the call as plain text for the program running it to fill in. We generate fifty thousand questions and fine-tune for ten minutes on the laptop, with the questions and the calculator&#39;s results left out of the loss. Then we measure the calls on held-out questions, worded the way training words them and in new ways, with the calculator and without it.</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>In this episode, our model becomes an agent, fine-tuned once into three roles: the agent, which hands parts of a task to subagents, a math role with the calculator, and a files role in a sandbox. Each subagent works in a fresh context, and its answer is all that goes back to the agent. We fine-tune for thirty minutes on the laptop, measure each role on held-out tasks, compare subagents with one long context, and put the agent in a Gradio chat that shows each step.</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, and its loss climbs past them, so in this episode we stretch its rotary embeddings four ways, from position interpolation to YaRN. We 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 then we fine-tune on long pages for fifteen minutes with two of the methods.</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>
<url><loc>https://mvgpt.nenuadrian.com/ep023-optimizers/</loc><lastmod>2026-10-22</lastmod><image:image><image:loc>https://i.ytimg.com/vi/0ysdFCrmdlU/maxresdefault.jpg</image:loc></image:image><video:video><video:thumbnail_loc>https://i.ytimg.com/vi/0ysdFCrmdlU/maxresdefault.jpg</video:thumbnail_loc><video:title>Muon vs AdamW, Lion and Sophia: a fair race | Minimum Viable GPT #23</video:title><video:description>All our training scripts use AdamW, so in this episode we put it in a fair race with Lion, Sophia and Muon, each written from its paper, with tests. They train one model on one set of batches for a thousand steps, each at its best learning rate from a sweep, with three seeds. Muon reaches in 1,000 steps the loss AdamW needs about 1,840 for, while Lion and Sophia land behind a tuned AdamW.</video:description><video:player_loc>https://www.youtube.com/embed/0ysdFCrmdlU</video:player_loc><video:duration>2732</video:duration><video:publication_date>2026-10-22</video:publication_date><video:tag>gpt</video:tag><video:tag>optimizer</video:tag><video:tag>adamw</video:tag><video:tag>adam</video:tag><video:tag>muon</video:tag><video:tag>lion</video:tag><video:tag>sophia</video:tag><video:tag>newton-schulz</video:tag><video:tag>learning rate</video:tag><video:tag>hyperparameter tuning</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>from scratch</video:tag><video:tag>mvgpt</video:tag></video:video></url>
</urlset>
