Chapter 6 -Fine-tuning for classification
6.5-Adding a classification head
-
为进行分类微调,须修改预训练的大语言模型(LLM)。我们将原本把隐藏表征映射到含50,257个词的词表的输出层,替换为一个更小、仅映射到 “0(非垃圾邮件)” 和 “1(垃圾邮件)” 这两个类别的输出层如下图所示。除输出层外,模型其余部分保持不变 。
print(model)
-
我们的目标是替换和微调输出层, 为了实现这一点,我们首先冻结模型,这意味着我们使所有层都不可训练。
for param in model.parameters(): param.requires_grad = False
然后,我们替换输出层(‘model.out_head’)
torch.manual_seed(123) num_classes = 2 model.out_head = torch.nn.Linear(in_features=BASE_CONFIG["emb_dim"], out_features=num_classes)
在这个新模型中,
out_head
输出层的requires_grad
属性默认设置为True
,这意味着它是模型中唯一一个在训练期间更新的层。从技术上讲,仅训练我们刚刚添加的输出层就足够了。然而,正如我在实验中发现的那样,微调附加层可以显著提高模型的预测性能(更多详细信息请参阅附录 B)。此外,我们还配置了最后一个 Transformer 块以及将该块连接到输出层的最终LayerNorm
模块,使其参与训练,如下图所示。
GPT 模型包含 12 个重复的 Transformer 块。在输出层附近,我们将最后一个 LayerNormalization 层和最后一个 Transformer 块设置为可训练(trainable),而其余 11 个 Transformer 块和嵌入层保持不变,设置为不可训练(non-trainable)。为了使最后一个 LayerNormalization 层和最后一个 Transformer 块可训练,我们将它们各自的
requires_grad
属性设置为True
。for param in model.trf_blocks[-1].parameters(): param.requires_grad = True for param in model.final_norm.parameters(): param.requires_grad = True
-
即使我们添加了一个新的输出层并将某些层标记为可训练或不可训练,我们仍然可以像以前一样使用这个模型。例如,我们可以编辑一个与之前使用的示例文本相同的示例文本
inputs = tokenizer.encode("Do you have time") inputs = torch.tensor(inputs).unsqueeze(0) print("Inputs:", inputs) print("Inputs dimensions:", inputs.shape) # shape: (batch_size, num_tokens) """输出""" Inputs: tensor([[5211, 345, 423, 640]]) Inputs dimensions: torch.Size([1, 4])
但是与之前不同的是,它现在有两个输出维度,而不是50,257
with torch.no_grad(): outputs = model(inputs) print("Outputs:\n", outputs) print("Outputs dimensions:", outputs.shape) # shape: (batch_size, num_tokens, num_classes) """输出""" Outputs: tensor([[[-1.5854, 0.9904], [-3.7235, 7.4548], [-2.2661, 6.6049], [-3.5983, 3.9902]]]) Outputs dimensions: torch.Size([1, 4, 2])
-
请记住,我们有兴趣对这个模型进行微调以返回一个类标签,该标签指示模型输入是“垃圾邮件”还是“非垃圾邮件”。我们不需要对所有四个输出行进行微调;相反,我们可以专注于单个输出令牌。特别是,我们将关注与最后一个输出令牌对应的最后一行,如下图所示
第3章讨论了将各输入令牌相互连接的注意力机制,还介绍类GPT模型中使用的因果注意掩码(使当前令牌仅关注当前及先前令牌位置),基于此因果注意机制,最后一个令牌包含信息最多,故将对其进行微调以用于垃圾邮件分类任务 。
print("Last output token:", outputs[:, -1, :]) """输出""" Last output token: tensor([[-3.5983, 3.9902]])