Preparing the GPT Model for Classification 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 Text but Not Your Question
A pre-trained GPT model has already learned general patterns from a large amount of text. That general knowledge is valuable, but the model was not built to answer one specific question, such as whether a message is spam or not spam. To use it for a classification task, two things must happen before fine-tuning begins: its final layer has to be adapted so it produces one output for each class the task requires, and the model has to be placed on the device where it will run. This article walks through the setup step that adapts the final layer, and then the step that prepares the model to run on an available device.
The setup is short, but every line changes something specific. As you read it, ask two questions about each line: what object is being changed, and what value does that object end up holding? Keeping those two questions in mind will make the rest of the article easier to follow.
The Model Before and After the Swap
The key idea is that only one part of the model is swapped out. The replacement is a single assignment to the model's out_head attribute. 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, the one that turns internal representations into outputs, is changed.
Read the diagram as a comparison. On the left is the model as it was loaded, with its original output layer. On the right is the same model after the assignment. The output layer is the only element marked as changed. The rest of the architecture is shown on both sides because it carries over untouched.
Reading the Replacement Line by Line
The replacement follows the pattern described in the setup. The left side of the assignment names the spot in the model that gets overwritten. The right side creates a new torch.nn.Linear object, and the assignment stores that object in place of the old layer. Here is the replacement in the form the setup describes, with num_classes set to 2 before the layer is created:
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 fixed at 768 in this setup, while the out_features value is taken from num_classes. This means that changing the number of classes changes only the output side of the layer.
Setting out_features from the Number of Classes
The value of num_classes becomes the out_features argument, so it determines how many outputs the new layer produces. Each output position corresponds to one class. With num_classes equal to 2, the layer produces two outputs, one for each class. Changing the task to a different number of classes means changing only that value.
What do you think happens?
If num_classes were set to 3 instead of 2, how many outputs would the new layer produce?
Reveal answer
3
The out_features argument is taken from num_classes, so a value of 3 gives three outputs. The 768 input features stay the same, because they describe what the layer receives, not how many classes there are.
Changing the task from two classes to four
A classification task now needs four classes instead of two. Which value changes, and what is the resulting layer?
- 1Identify the value that depends on the class count
The setup ties
out_featurestonum_classes, sonum_classesis the value to change. - 2Update num_classes
Set
num_classes= 4 before the layer is created. - 3Check what stays fixed
in_featuresstays at 768, because it describes the width of the input the layer receives and does not depend on the class count. - 4Write the new layer
The replacement becomes
torch.nn.Linear(in_features=768, out_features=4).
The new output layer has 768 input features and 4 outputs, one for each class. Only out_features changed.
Common mistake Changing in_features when the number of classes changes
What it looks likeSetting in_features=4 because the task now has four classes
Why it failsin_featuresdescribes the width of what the layer receives from the rest of the model. It does not depend on the number of classes.Do this insteadKeep in_features at 768 and change only num_classes, which feeds out_features.
Common mistake Assuming the whole model is rebuilt by the replacement line
Why it failsThe replacement is a single assignment to
out_head. Nothing else in the setup redefines the model.Do this insteadExpect the rest of the GPT architecture to stay as it was loaded.
Choosing and Moving the Device
After the output layer is replaced, the setup prepares where the model will run. 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 chosen based on what the machine offers rather than being hard-coded. The final line, model.to(device), applies that choice to the model.
The flowchart traces one decision. The check asks whether CUDA is available. A yes answer selects cuda, and a no answer selects cpu. Both paths then reach the same final step, model.to(device), which moves the model onto the selected device. The device is therefore chosen at run time from what the machine offers, and the model follows that choice.
Notice the order of the setup. The device selection comes after the output layer replacement. The model is first adapted to the classification task, and then it is placed on the device where it will run. Both steps happen before any training or fine-tuning begins.
Mistakes When Preparing the Model
Common mistake Hard-coding the device as CUDA
Why it failsThe device is chosen from what the machine offers. A hard-coded CUDA device would fail on a machine where CUDA is not available.
Do this insteadCreate the device with the torch.cuda.is_available() check, which selects CUDA when available and the CPU otherwise.
Common mistake Running the device step before the layer replacement and assuming the order does not matter
Why it failsThe setup adapts the model to the classification task first and places it on the device second. Keeping that sequence makes the setup easy to read and matches the described order.
Do this insteadReplace the output layer first, then choose the device and call model.to(device).
Check Your Setup Reasoning
A colleague says that to adapt a model for a four-class task, they changed in_features from 768 to 4 and left num_classes unchanged. Explain which value is wrong, what each value should be, and what the layer's outputs would be after the correct change.
Hints
- Ask which value describes the width of the input the layer receives from the rest of the model.
- Ask which value is taken from
num_classesand feedsout_features. - Compare your answer with the worked example on changing from two classes to four.
Key Takeaways
- A pre-trained GPT model is not built for a specific question, so its output layer is replaced with a new torch.nn.Linear layer that produces one output per class.
- The replacement is a single assignment to model.out_head, and the rest of the GPT architecture stays as it was loaded.
in_featuresis fixed at 768, andout_featuresis taken fromnum_classes, so changing the class count changes only the output side of the layer.- The device is chosen with
torch.cuda.is_available(), selecting CUDA when available and the CPU otherwise, andmodel.to(device)applies that choice to the model. - Both the output layer replacement and the device selection happen before fine-tuning begins.