洛可可
8 min read Hero Image LLM / transformer

Happy-LLM 章节疑难点(2) 预训练语言模型

通过 Happy-LLM 学习预训练语言模型和 BERT 等基础内容

01 预训练语言模型概念

Transformer 并不是一个具体的、可以直接和你对话的模型,而是一种神经网络架构

在 Transformer 出现之前,AI 处理自然语言效率很低。Transformer 引入了“注意力机制(Attention)”,让 AI 能够一眼看到句子的全局,理解词与词之间的强弱联系。最初由两个核心模块组成:

  • Encoder(编码器): 负责“理解”输入的内容,提取特征。
  • Decoder(解码器): 负责根据理解的内容“生成”最终的输出。

预训练语言模型 (PLM) 预训练(Pre-training) 是一种训练方法。

过去训练 AI,是直接教它做特定任务(比如专门训练它做英翻中)。而预训练,就像是把一个装载了 Transformer 架构的初始 AI 放入一个极其庞大的互联网文本里,让它自己去阅读、填词。在这个漫长的阶段,它不为了完成任何特定关卡,仅仅是为了掌握人类语言的语法规律和世界常识。

所以,预训练语言模型(PLM) = 强大的 Transformer 架构 + 海量无标注数据的预训练

各大厂商开始基于这个基础,点了不同分支:

  • 一:只用 Encoder(谷歌的 BERT)
    • 做法: 谷歌仅提取了 Transformer 的 Encoder 层进行堆叠,让模型做“完形填空”(也就是图片中提到的 MLM 掩码语言模型任务)。
    • 优势: 极其擅长自然语言理解 (NLU),比如阅读理解、文本分类。它能精准看懂文字,但不擅长自由创作。
  • 二:只用 Decoder(OpenAI 的 GPT 系列)
    • 做法: OpenAI 另辟蹊径,选择了 Transformer 的 Decoder 层,让模型做最传统的“文字接龙”(预测下一个词,即 LM 任务)。
    • 优势: 极其擅长自然语言生成 (NLG)。因为它的底层逻辑就是“顺着往下写”,这赋予了它强大的文本生成能力。这就是现在大火的大语言模型(LLM)的绝对基座。 现在使用的 ChatGPT,其底层逻辑依然是在做极为复杂的“预测下一个词”。
  • 三:保留 Encoder + Decoder(谷歌的 T5)
    • 做法: 完整保留了最初的架构,将所有 NLP 任务都统一转化为“文本输入到文本输出”的形式。

02 BERT

1. 继承 transformer

hidden_states 的具体含义及其在 Transformer 中的对应关系:

hidden_states 就是这些向量在经过每一层网络计算后的“实时状态”。

  • 初始状态(图左上): Tokenizer 把文本切词后,经过 Embedding(词嵌入),输出了第一波 hidden_states。此时它代表的是带有位置信息的词向量初始值

  • 计算状态(图中部 EncoderLayer): hidden_states 流入每一层 EncoderLayer。它不仅自己进行计算,还会与经过注意力机制、前馈神经网络后的结果进行残差连接(也就是图中的 + 号),然后输出更新后的 hidden_states,继续传给下一层。

  • 拆分状态(图右侧 Attention): 这是最核心的一步。hidden_states 进入 Attention 模块后,直接被“克隆”并分别通过线性变换,变成了大名鼎鼎的 query_states (Q)、key_states (K) 和 value_states (V)。

简而言之,hidden_states 就是模型“思考”过程中,对当前输入文本特征的内部高维表示。

BERT 所使用的激活函数是 GELU 函数,全名为高斯误差线性单元激活函数,这也是自 BERT 才开始被普遍关注的激活函数。GELU 的计算方式为:

原始 BERT(即论文提出)使用和 Transformer 一致的绝对位置编码,后续改进(包括 BERT 的各种变体)使用了上述相对位置编码。

在完成注意力分数的计算之后,先通过 Position Embedding 层来融入相对位置信息。这里的 Position Embedding 层,其实就是一层线性矩阵。通过可训练的参数来拟合相对位置,相对而言比 Transformer 使用的绝对位置编码 Sinusoidal 能够拟合更丰富的相对位置信息,但是,这样也增加了不少模型参数,同时完全无法处理超过模型训练长度的输入(例如,对 BERT 而言能处理的最大上下文长度是 512 个 token)。

2. 预训练任务

LM 预训练任务的一大缺陷在于,其直接拟合从左到右的语义关系,但忽略了双向的语义关系。虽然 Transformer 中通过位置编码表征了文本序列中的位置信息,但这和直接拟合双向语义关系还是有本质区别。

3. 下游微调

BERT 会在其首部加入一个特殊 token <CLS>。在后续编码中,该 token 代表的即是整句的状态,也就是句级的语义表征。在进行 NSP 预训练时,就使用了该 token 对应的特征向量来作为最后分类器的输入。

在完成预训练后,针对每一个下游任务,只需要使用一定量的全监督人工标注数据,对预训练的 BERT 在该任务上进行微调即可。所谓微调,其实和训练时更新模型参数的策略一致,只不过在特定的任务、更少的训练数据、更小的 batch_size 上进行训练,更新参数的幅度更小

4. RoBERTa

既然RoBERTa取消了NSP任务,那它是如何学习句子间关系的?

RoBERTa 并没有引入一个全新的特定任务来替代 NSP,而是通过改变输入数据的构造方式,以及利用更长的连续上下文,让模型在纯粹的 MLM(掩码语言模型)任务中隐式地、更深层地学习句子间的语义关系。

具体来说,它是通过以下几个核心策略来实现的:

1. 采用“单文档连续采样”构建长输入 研究者质疑 NSP 任务过于简单,不仅不能提高模型性能,反而可能因为人为截断或打乱句子而带来负面效果。为此,RoBERTa 进行了对比实验,测试了不同的输入构造方式:

  • 跨越文档的 MLM(Full-sentences): 取消 NSP,直接从一个或多个文档中连续采样完整的句子,直到填满 512 的最大输入长度。
  • 单文档的 MLM(Doc-sentences): 取消 NSP,限制只从同一个单一文档中连续采样完整的句子来填满输入。

实验证明,直接输入连续的句子(即上述两种方式)显著优于原本带有 NSP 的训练方式,其中“单文档的 MLM”在下游任务微调时性能最佳

2. 全程保持 512 的长序列训练 BERT 在训练时,大部分时间使用的是 256 的序列长度,只有在最后阶段才使用 512 长度。而 RoBERTa 全程都在 512 长度上进行训练。结合上面提到的连续采样策略,这意味着模型每次处理的都是长达 512 Token 的、逻辑连贯的真实自然段落。

3. 配合动态遮蔽(Dynamic Masking)机制 RoBERTa 将 Mask 的操作放在了训练阶段动态进行,确保模型在不同的 Epoch 中看到的掩码位置都不一样,迫使模型更全面地学习上下文特征。(不同于原先BERT的Mask)

总结它的学习逻辑: 由于输入的是长达 512 Token 且原本就自然连续的句子集合,模型在执行 MLM(完形填空)任务时,为了精准预测某个被遮蔽的词,其自注意力机制必须跨越当前句子的边界,去前后其他句子中寻找语境线索。这种在长篇连贯文本中反复进行上下文预测的过程,使得模型能够非常自然地捕捉到深层的跨句逻辑和长距离依赖关系,这比人为构造的“判断两句话是否相连”的简单二分类 NSP 任务要有效得多。

03 LLaMA

LLaMA-3 模型结构的图,其中的LLaMaRMSNorm,repeat_kv,以及MLP层里面的内容,都如何解释

1. LLaMaRMSNorm 层:稳定学习过程

LLaMA-3 模型使用了 RMSNorm(均方根归一化)来替代传统的 LayerNorm。RMSNorm函数可以用以下数学公式表示: 其中:

  • xi​ 是输入向量的第 i 个元素
  • γ 是可学习的缩放参数
  • n 是输入向量的维度数量
  • ϵ 是一个小常数,用于数值稳定性(以避免除以零的情况)

这种归一化有助于通过确保权重的规模不会变得过大或过小来稳定学习过程,这在具有许多层的深度学习模型中特别有用。

  • 计算方式:它通过计算每个神经元激活值的均方根来进行归一化。
  • 优势:与 LayerNorm 相比,RMSNorm 的参数设置更简单,只有一个可学习参数。这种归一化方式能够确保权重的规模不会变得过大或过小,从而稳定学习过程,这在深度学习模型中特别有用。
  • 代码实现:在代码实现中,输入 x 首先被转换为 float 类型,然后乘以输入平方均值的平方根的倒数(加上一个极小的常数 eps 以防除零),最后再转回原来的数据类型并乘以可学习的缩放因子 weight。归一化操作不会改变输入张量的形状。

2. repeat_kv 机制:支持 GQA(分组查询注意力)

在 LLaMA 模型的注意力计算中,查询(Q)、键(K)和值(V)会被拆分成多个头。

  • 目的:虽然在 LLaMA2 中只有 70B 模型使用了分组查询注意力机制(GQA),但这里依然使用 GQA 来构建 Attention 模块,因为它可以提高模型效率并节省显存。由于采用了 GQA,键和值的头数(n_kv_heads)可能少于查询的头数,因此在计算注意力之前,必须将键(K)和值(V)的维度扩展到与查询(Q)一致
  • 操作逻辑:如果重复次数 n_rep 为 1,则不需要重复。否则,在键/值对头的维度之后添加一个新维度,使用 expand 方法将其扩展到 n_rep 的大小,最后通过 reshape 将扩展后的维度合并回键/值对头的数量中,从而实现维度的对齐。扩展后的 K 和 V 才会和转置后的 Q 投入注意力计算。

3. MLP 层:进一步特征提取

在完成注意力层的计算并加上残差后,hidden_states 会进入 MLP(多层感知机)层进行进一步的特征提取。

  • 结构与维度变换:在 MLP 层中,模型通常通过全连接层将 hidden_states 映射到一个中间维度(在未指定的情况下,通常是输入维度的 4 倍的 2/3 的近似倍数),然后再通过另一个全连接层将特征重新映射回原始的 hidden_states 维度。
  • 非线性变换:中间过程会使用激活函数(如 SILU)进行非线性变换,以增加模型的非线性能力。
  • 具体计算逻辑:具体到前向传播过程,输入 x 会首先分别通过第一层线性变换(w1)加上 SILU 激活函数,以及第三层线性变换(w3),两者的结果相乘后,再依次通过第二层线性变换(w2)和 Dropout 层,得到最终输出。

可以更进一步阅读: 一文读懂 Llama 架构:它对经典 Transformer 做了哪些改动? - 知乎 为什么大模型越聊越慢?一文看懂 KV Cache 的前世今生 - 知乎