文本将回答训练LLM分类器的以下问题:
为什么要微调最后一个 token,而不是第一个 token?
1
微调语言模型的最常见方法是指令微调和分类微调。指令微调涉及使用特定指令在一组任务上训练语言模型,以提高其理解和执行自然语言提示中描述的任务的能力,如下图所示。

在分类微调中,该模型经过训练以识别一组特定的类标签,例如 “spam” 和 “not spam”。分类任务的示例不仅限于大型语言模型和电子邮件筛选;它们包括从图像中识别不同种类的植物,将新闻文章分类为体育、政治或技术等主题,以及在医学成像中区分良性和恶性肿瘤。
指令微调和分类微调模型相比,指令微调模型通常能够执行更广泛的任务。我们可以将分类微调模型视为高度专业化的模型,通常,开发专业化模型比开发在各种任务中都能正常工作的通用模型更容易。
2
修改预训练的大型语言模型,使其为分类微调做好准备。为此,将原始输出层替换为一个较小的输出层,该层将隐藏的表示映射到 50,257 个唯一标记的词汇表,该输出层映射到两个类:0(“非垃圾邮件”)和 1(“垃圾邮件”),如下图所示。

model=GPTModel(BASE_CONFIG)
forparaminmodel.parameters():
param.requires_grad=False
torch.manual_seed(123)
num_classes=2
model.out_head=torch.nn.Linear(
in_features=BASE_CONFIG["emb_dim"],
out_features=num_classes
)
#最终的LayerNorm和最后一个transformer模块可训练
forparaminmodel.trf_blocks[-1].parameters():
param.requires_grad=True
forparaminmodel.final_norm.parameters():
param.requires_grad=True
下图所示的因果注意力掩码设置,序列中的最后一个标记积累的信息最多,因为它是唯一可以访问所有先前标记数据的标记。因此,在垃圾邮件分类任务中,我们专注于微调过程中的最后一个令牌。

3
- 我们需要训练所有层吗?

如表所示,训练所有层的性能略好:96.67% 对 95.00%。(不过,这将运行时间增加了大约 2.5 倍。
- 为什么要微调最后一个 token,而不是第一个 token?
BERT 这样的编码器风格的语言模型有一个指定的分类标记作为它们的第一个标记;GPT 是一种解码器风格的模型,带有因果注意力掩码。这意味着第一个标记在输入中没有任何其他标记的上下文信息。只有最后一个令牌包含有关所有其他令牌的信息。因此,如果我们想使用像 GPT 这样的模型进行分类微调,我们应该专注于最后一个标记来捕获所有其他输入标记的上下文信息。

小型 GPT-2 模型和 BERT 在垃圾邮件分类数据集上表现相似。
在大一点的数据集IMDB Movie Review进行情感分类。

由于我们在下一个单词预测任务上训练类似 GPT 的模型,因此 GPT 架构的一个核心特征是因果注意力掩码(不同于 BERT 模型或原始的 transformer 架构)。
但是,我们实际上可以在分类微调期间删除因果掩码,这将允许我们微调第一个而不是最后一个标记,因为未来的标记将不再被掩码,并且第一个标记可以看到所有其他标记。
在类似 LLM只需要更改 2 行代码:
classMultiheadAttention(nn.Module):
def__init__(self,d_in,d_out,context_length,dropout,num_heads):
super().__init__()
#...
defforward(self,x):
b,num_tokens,d_in=x.shape
keys=self.W_key(x)#Shape
b,num_tokens,d_out)
queries=self.W_query(x)
values=self.W_value(x)
#...
attn_scores=queries@keys.transpose(2,3)
#Commentoutthecausalattentionmaskpart
#mask_bool=self.mask.bool()[:num_tokens,:num_tokens]
#attn_scores.masked_fill_(mask_bool,-torch.inf)
attn_weights=torch.softmax(
attn_scores/keys.shape[-1]**0.5,dim=-1
)
context_vec=(attn_weights@values).transpose(1,2)
context_vec=context_vec.contiguous().view(
b,num_tokens,self.d_out
)
context_vec=self.out_proj(context_vec)
returncontext_vec
可以看到,当我们在微调期间禁用因果掩码时,我们可以得到一个小的改进。这本身和任务的难度有关系。
- 增加模型大小有什么影响?
到目前为止,我们只研究了最小的 GPT-2 模型的性能,即 1.24 亿个参数的版本。它与具有 3.55 亿、7.74 亿和 15 亿个参数的大型变体相比如何。

正如表所示,较大的模型会显著提高预测准确性(但是,GPT-2 medium在这里是一个异常值。这个模型在其他数据集上的性能很差,我怀疑这个模型可能没有经过很好的预训练。)
在第一个问题中,我们发现,当只微调最后一个 transformer 模块而不是微调整个模型时,我们可以(几乎)匹配分类性能。仅微调最后一个块的优点是训练更快,因为并非所有权重参数都被更新。

在小型模型上,LoRA 的速度略慢,因为添加 LoRA 层的额外开销可能大于好处,但是在训练更大的 15 亿个参数模型时,LoRA 的训练速度提高了 1.53 倍。
如果我们想在训练或推理期间批量处理数据(这涉及一次处理多个输入序列),我们需要插入填充标记以确保训练样本的长度相等。

在常规的文本生成任务中,填充不会影响模型响应,因为填充标记通常会添加到右侧,并且由于前面讨论的因果掩码,这些填充标记不会影响其他标记。
我们微调最后一个令牌实验时,由于填充标记位于最后一个标记的左侧,因此填充标记可能会影响结果。

参考
Building A GPT-Style LLM Classifier From Scratch
Finetuning for Text Classification