Initializing and Preparing the GPT Model for Fine-Tuning
The output layer of a pre-trained GPT model is replaced with a new torch.nn.Linear layer so the model can produce one output per class.
A Model That Knows Language but Not Your Task
A pre-trained GPT model has already learned general patterns from a large amount of text. That learning is valuable, but the model was not built to answer one specific question, such as whether a message is spam or not spam. Before it can be fine-tuned for a classification task, its final layer has to be adapted so that it produces one output for each class the task requires.
This article follows the setup step that does exactly that, and then prepares the model to run on an available device. The setup is short, but every line changes something specific. As you read, ask two questions about each line: what object is being changed, and what value does it end up holding? Keeping those two questions in mind will make the rest of the article much easier to follow.
Tracing the Model Before Any Change
Think of the pre-trained model as a stack of components. Most of the stack is the GPT architecture itself, which turns input text into internal representations. The last component is the output layer, which turns those internal representations into the outputs that the model was originally built to produce. For a language model, those outputs are scores for possible next tokens, which is why the original output layer is sized to the model's vocabulary.
A classifier needs something different. It must produce one output per class, and the number of outputs should match the number of categories in the task. The setup therefore leaves the body of the model alone and swaps only the final layer. The diagram below shows the change: the input width stays the same, while the output side is redrawn for the classes.
Replacing the Output Layer in One Assignment
The replacement is a single assignment to the model's out_head attribute. The right side of the assignment creates a new torch.nn.Linear object. The left side stores that object in place of the old layer. Nothing else in the setup code redefines the model, so the rest of the GPT architecture stays exactly as it was loaded. Only the final layer that turns internal representations into outputs is changed.
num_classes= 2 sets the number of classes before the layer is created- model.out_head is the spot in the model that gets overwritten
torch.nn.Linear(...)builds the new layer whose shape is defined by the argumentsin_features=768 is fixed in this setup and does not depend on the class countout_features=num_classestakes its value from the class count
Read the anatomy from left to right. The attribute on the left is the location being overwritten. The call on the right defines the new layer's shape. The in_features value is 768 in this setup, and the out_features value comes from num_classes. Changing the number of classes therefore changes only the output side of the layer, while the input side stays fixed at 768.
Following the Setup Line by Line
The setup can be read as a sequence of state changes. Each line leaves the model in a new state, and the next line builds on it. The diagram traces the model from the pre-trained version through the output layer replacement and the device placement. The states are listed in the order the code runs.
Notice what does not appear in this trace. The body of the GPT architecture is never reassigned, so its learned parameters are carried forward unchanged from the pre-trained model. The only new object is the output layer, and the only new placement is the device the model is moved to. Both the output replacement and the device selection happen before any fine-tuning begins.
Choosing the Device and Moving the Model
After the output layer is replaced, the setup prepares the device the model will run on. The setup code first creates a device object. It selects CUDA when torch.cuda.is_available() reports that CUDA is available, and selects the CPU otherwise. The device is therefore chosen based on what the machine offers, rather than being hard-coded into the program.
torch.cuda.is_available()reports whether CUDA is available on this machine- the conditional expression selects cuda when available and cpu otherwise
torch.device(...)creates the device object that stores that choicemodel.to(device)applies the choice to the model
The order of the two steps matters for reading the code. The model is first adapted to the classification task by replacing its output layer, and then it is placed on the device where it will run. Reversing the order would not change which layer is replaced, but the setup as written adapts the model first and places it second.
Mistakes Beginners Make with the Setup
Common mistake Changing in_features when the number of classes changes
What it looks likeSetting in_features=2 because the task has two classes.
Why it failsin_featuresdescribes the width of what the layer receives from the model body, which stays at 768. The class count controls only the output side.Do this insteadKeep in_features=768 and change only num_classes, which feeds out_features.
Common mistake Assuming the whole model is rebuilt
What it looks likeBelieving that creating a new layer resets the GPT architecture.
Why it failsThe setup is a single assignment to
out_head. Nothing else in the setup code redefines the model.Do this insteadRecognize that only the final layer is new, and the rest of the loaded architecture is unchanged.
Common mistake Hard-coding the device
What it looks likeWriting device = "cuda" on a machine without CUDA.
Why it failsThe setup chooses the device from what the machine offers, using
torch.cuda.is_available().Do this insteadUse the conditional expression that selects cuda when available and cpu otherwise.
Common mistake Forgetting that model.to(device) is the step that applies the choice, so creating a device object alone leaves the model where it was.
Predicting the Shape of the New Head
A fine-tuning task has four classes. Before reading the answer, predict the out_features value of the new layer and whether the in_features value changes. Then explain which dimension of the layer's weight matrix corresponds to outputs and which to inputs.
Hints
- Follow the setup pattern:
out_featuresis taken fromnum_classes. in_featuresdescribes the representations received from the model body, not the classes.- In a linear layer, the weight matrix maps inputs to outputs, so one of its two dimensions tracks the output count and the other tracks the input count.
Explain, in one sentence, why changing the number of classes from 2 to 5 should not change the 768 input features. Then state which single line of the setup would need to change.
Hints
- Think about what 768 describes: the width of what the layer receives.
- Look for the line that assigns
num_classes.
Key Takeaways
- A pre-trained GPT model's output layer is replaced with a new torch.nn.Linear layer so the model can produce one output per class.
- The replacement is a single assignment to model.out_head, with
in_featuresfixed at 768 andout_featurestaken fromnum_classes. - Changing the number of classes changes only
out_features, leaving the rest of the GPT architecture as it was loaded. - The device is chosen with
torch.cuda.is_available(), selecting CUDA when available and the CPU otherwise, andmodel.to(device)applies that choice before fine-tuning begins.