Full Fine-tuning › Implementation Deep Dive

Michael BrenndoerferNovember 25, 20259 min read
Language AI HandbookAll chapters
Part 34 of 67Fine-tuning Fundamentals
Chapter 250Full Fine-tuning › Implementation Deep Dive
Reading section 7 of 11 · Implementation Deep Dive · 9 minSection 7 of 11 · 9 min

Book contents

Section 7 of 11 · 9 min read

Full Fine-tuning › Implementation Deep DiveOne section · Sections in this chapter7 / 11 ↓
Reading tools Definitions & inline links

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

Let's walk through a complete fine-tuning implementation, examining each component in detail. Understanding the underlying mechanics of the training loop gives you the ability to debug problems, implement custom modifications, and reason about what is happening during training. High-level APIs are convenient, but knowing what they are doing under the hood is needed for serious practitioners.

The training loop has a deceptively simple structure: iterate over batches, compute loss, compute gradients, update parameters. But each of these steps involves important decisions that affect training stability and final performance. The details of gradient clipping, optimizer parameter grouping, and evaluation frequency all matter for achieving good results.

Setting Up the Training Loop

While high-level APIs handle many details, understanding the underlying training loop gives insight into what is happening during fine-tuning. The key components are the optimizer, the learning rate scheduler, and the parameter grouping strategy.

Notice the parameter grouping: we apply weight decay to most parameters but exclude biases and layer normalization weights. This follows the original BERT fine-tuning recipe and prevents these parameters from being pushed toward zero unnecessarily. The no_decay list identifies parameters that should remain free from regularization pressure. Biases are typically small in magnitude and contribute little to overfitting. Layer normalization parameters are scaling and shifting factors that should be free to take whatever values the model needs for proper normalization.

The AdamW optimizer is the standard choice for fine-tuning transformers. It implements decoupled weight decay, maintaining the beneficial adaptive learning rate behavior of Adam while correctly separating the regularization effect of weight decay. Using standard Adam with L2 regularization added to the loss produces suboptimal results for transformers because the adaptive learning rates interact with the gradient in a way that diminishes the regularization effect. AdamW avoids this issue by applying weight decay directly to parameters after the gradient update.

The Training Step

Each training step involves a forward pass, loss computation, backward pass, and parameter update. The implementation below shows the needed operations, including gradient clipping, which is a necessary stability measure for fine-tuning.

Gradient clipping prevents any single batch from causing excessively large updates. The maximum gradient norm of 1.0 is a common choice for fine-tuning, constraining the total magnitude of gradients across all parameters to prevent training instability. The clip_grad_norm_ function computes the global gradient norm (the L2 norm across all parameter gradients), and if it exceeds the specified maximum, scales all gradients down proportionally so that the total norm equals exactly 1.0. This operation does not change the direction of the update, only its magnitude.

Gradient clipping is particularly important in the early epochs of fine-tuning, when the classification head is still learning rapidly and may produce large gradients. Without clipping, a single bad batch could push the backbone parameters far from their pre-trained values. The clipping threshold of 1.0 was chosen empirically and has become a community standard for BERT-style fine-tuning. For larger models, you may occasionally need to adjust this threshold if you observe that gradients are being clipped too aggressively.

Evaluation

Evaluating during fine-tuning helps monitor for overfitting and select the best checkpoint. Evaluation should be done frequently enough to detect overfitting early, but not so frequently that it materially slows down training. Evaluating once per epoch is usually sufficient for fine-tuning runs of 2-5 epochs.

The torch.no_grad() context manager is necessary during evaluation: it disables gradient computation, reducing memory usage and speeding up the forward pass. During evaluation, we don't need gradients because we are not updating parameters. Forgetting to use torch.no_grad() during evaluation can cause memory exhaustion and materially slow down your training loop, especially when evaluating on large validation sets.

The model.eval() call is equally important: it switches certain layers from their training behavior to their evaluation behavior. Dropout layers, for example, randomly zero out activations during training to prevent co-adaptation of neurons, but should be disabled during evaluation to produce consistent predictions. Batch normalization layers similarly behave differently during training and evaluation. Failing to call model.eval() before evaluation will produce inconsistent results and may underestimate the model's true performance.

Complete Training Run

Putting it all together into a complete training run:

Out[26]:
Console
Device: cpu
Total training steps: 8
Warmup steps: 0

The training configuration shows the total number of parameter updates that will occur during fine-tuning. The warmup steps stand for the initial phase where the learning rate gradually increases, helping stabilize training from the randomly initialized classification head.

Out[28]:
Console
Epoch 1/1 (demo subset: 128 train, 64 val)
  Train Loss: 0.7556
  Val Loss: 0.4590
  Val Accuracy: 0.9531

Best validation accuracy: 0.9531
Note: demo run on small subset; real fine-tuning on the full dataset reaches ~87% after 3 epochs.

The key parameters for full fine-tuning are:

  • learning_rate: Controls how much weights change per update. Typically 1e-5 to 5e-5 for transformer fine-tuning.
  • num_train_epochs: Number of passes through the training data. Usually 2-5 epochs for fine-tuning.
  • per_device_train_batch_size: Samples per batch on each device. Common values are 16-32 for BERT-sized models.
  • warmup_ratio: Fraction of training for learning rate warmup. Typically 0.06-0.1 (6-10%).
  • weight_decay: L2 regularization strength. Common value is 0.01.
  • gradient_accumulation_steps: Number of batches to accumulate before updating. Use to simulate larger batch sizes.

The training progresses through multiple epochs, with both training and validation metrics tracked at each step. The best model checkpoint is saved based on validation accuracy, which helps prevent overfitting by selecting the model state that generalizes best to unseen data. The final validation accuracy shows how well the fine-tuned model performs on held-out examples.

Visualizing Training Progress

Tracking loss and accuracy across epochs helps diagnose training issues. The training curves encode a wealth of information about what is happening during optimization, and learning to read them fluently is one of the most useful skills for a practitioner.

Out[29]:
Visualization
Line plot showing training loss and validation loss decreasing over three epochs.
Training and validation loss during BERT fine-tuning on sentiment classification across three epochs (illustrative). Training loss decreases from 0.45 to 0.15, showing effective adaptation. The widening gap between validation (0.40 to 0.20) and training loss indicates mild overfitting, which is typical of small fine-tuning datasets and suggests that regularization or early stopping could further improve generalization.
Line plot showing validation accuracy increasing from 0.78 to 0.87 over three epochs.
Validation accuracy during BERT fine-tuning on sentiment classification across three epochs (illustrative). Accuracy rises from 78% to 87% with diminishing returns, showing the model is approaching its performance ceiling on this dataset. The flattening trajectory between epochs 2 and 3 suggests that additional epochs would give minimal improvement while increasing overfitting risk.

The training curves reveal the dynamics of fine-tuning. Training loss should decrease steadily across epochs. Validation loss may decrease initially but can increase if the model begins overfitting. The gap between training and validation loss indicates the degree of overfitting, and a widening gap is a signal to consider stronger regularization or reducing the number of epochs. The validation accuracy curve gives the most direct measure of task performance and is typically the metric used to select the best checkpoint for deployment.