Appendix D. Adding Bells and Whistles to the Training Loop
This appendix refines the training loop used for pretraining and finetuning by adding practical stability and convergence improvements. To keep the material self-contained, it reinitializes the GPT model and reconstructs the data loaders from earlier chapters, using a short story dataset for demonstration. The overarching goal is to introduce and then integrate three techniques—learning rate warmup, cosine decay, and gradient clipping—into a cohesive training function that can reliably pretrain a small LLM.
The first enhancement is learning rate warmup, which starts training with small updates and linearly raises the learning rate from an initial value to a user-defined peak over a fixed number of steps (for example, from 0.0001 to 0.01 over 20 steps). After warmup, a cosine decay schedule gradually reduces the learning rate from its peak toward a small floor (for example, 0.1 times the initial learning rate) following a half-cosine curve across the remaining training steps. Together, these schedules help avoid destabilizing updates early on and reduce the risk of overshooting minima later by slowing the learning rate as training progresses.
The appendix also adds gradient clipping to curb exploding gradients by constraining the L2 norm of all parameter gradients to a specified maximum (for example, max_norm = 1.0 via clip_grad_norm_). The text explains the L2 norm notionally and demonstrates, with a simple measurement of per-parameter gradients before and after clipping, that the largest gradients are reduced to a safer range. In the final step, all three techniques—warmup, cosine decay, and gradient clipping—are combined within the training loop to stabilize and improve LLM pretraining.
Figure D.1 The learning rate warmup increases the learning rate for the first 20 training steps. After 20 steps, the learning rate reaches the peak of 0.01 and remains constant for the rest of the training.
Figure D.2 The first 20 steps of linear learning rate warmup are followed by a cosine decay, which reduces the learning rate in a half-cosine cycle until it reaches its minimum point at the end of training.
D.4 The modified training function
In this final section of this appendix, we improve the train_model_simple training function we used in chapter 5 by adding the three concepts we introduced: linear warmup, cosine decay, and gradient clipping. Together, these methods help stabilize LLM training.
The code is as follows, with the changes compared to the train_model_simple annotated:
After defining the train_model function, we can use it in a similar fashion to train the model compared to the train_model_simple method in chapter 5:
The training will take about 5 minutes to complete on a MacBook Air or similar laptop and print the following outputs:
Like chapter 5, the model begins to overfit after a few epochs since it is a very small dataset, and we iterate over it multiple times. However, we can see that the function is working since it minimizes the training set loss.
Readers are encouraged to train the model on a larger text dataset and compare the results obtained with this more sophisticated training function to the results that can be obtained with the train_model_simple function used in chapter 5.
Build a Large Language Model (From Scratch) ebook for free