本章以 Llama 3 为讨论对象。

2.1 模型设计

Llama 3 的模型架构较为常规,但值得一提的是其模型尺寸的选择。Llama 3 的旗舰版本是 405B 而非常见的 70B,这一选择是经过了充分分析和论证的。

给定总计算量(这直接由预算决定),Llama 团队希望训练出一个尽可能强的模型。盲目增加参数量并不是最优解:增加参数意味着减少训练数据量,而一个欠拟合的大模型未必比一个充分拟合的较小模型更优。DeepMind 团队在 2022 年研究了该问题。这篇文章在固定总计算量的条件下训练了大量不同尺寸的 LLM,并观察到(最小化 loss 意义下的)最优模型尺寸与总计算量之间存在与数据相当吻合的经验关系。Llama 3 沿用了这一方法,但重做了其中的实验。实验得出的数据与原文有差异,但结论是一致的。405B 的选择正是根据这项数据外推得来。

图片出自 Training Compute-Optimal Large Language Models

作者曾经读到过一句话:“工程师是能用最低限度的创新达成目的的人。”Llama 3 正是这样:其成功的最主要原因并非其方法论所含的原创性,而是大量人力、算力资源的投入以及对现有 best practice 的有效整合。这样的工作是否预示着在不久的将来,深度学习领域“单打独斗”的时代将会迎来结束?这是一个引人遐想的问题。

2.2 Pre-training

Llama 3 的预训练分为三个步骤:初始训练、上下文增长和 annealing(冷却?)。

2.2.1 初始训练

训练由一个较短的预热阶段(学习率线性增长)和一个较长的主阶段(学习率余弦衰减)组成。模型初始阶段很不稳定,因此使用更低的学习率和更小的 batch size 以保证梯度在合理范围内,使模型的学习更加可控。

值得一提的是,训练数据不仅在内容上进行了多方面的把控,不同类型数据的配比也是刻意调整优化过的。得益于 scaling law,小模型上的实验结果可以较为可靠地迁移到大模型上,使得对训练数据配比的调优成为可能。展现了深度学习中炼金术的一面

2.2.2 上下文增长

由于 transformer 模型的算力消耗随输入长度是超线性增长的,以超长上下文训练会拖慢训练效率。因此,模型在初始训练阶段以 8K 上下文长度进行训练,训练好之后逐步增长到 128K。

用于监控训练进程的指标是原长度下的表现和新长度下 needle in a haystack 测试的成功率。当模型 100% 完成 needle in a haystack 任务,且在原长度下的表现恢复到训练前水平时,即认为模型适应了新的上下文长度,接下来再进行下一轮上下文增长,直到达到最终的 128K。

2.2.3 冷却

在以上两个阶段后,还会再进行一个较短的冷却阶段(学习率线性衰减)。这一阶段使用精选的高质量数据进行训练。这或许是 LLM 版的“考前冲刺”?

2.3 Post-training

经过 pre-training 后,模型具有了理解语言的能力,但它只学习了文本续写这一项任务。想要让模型顺利地和人类对话,还需要作出一定微调。

2.3.1 Instruction Tuning

首先,需要规定一种用于对话的格式,以便 LLM 知道上文的每一部分都来自于谁(系统/用户/LLM/工具...)。以 Llama 3.1 为例,一个简单的 prompt 如下:(形如 <|begin_of_text|> 的为特殊 token)

1
2
3
4
5
6
7
8
<|begin_of_text|><|start_header_id|>system<|end_header_id|>

Cutting Knowledge Date: December 2023
Today Date: 23 July 2024

You are a helpful assistant<|eot_id|><|start_header_id|>user<|end_header_id|>

What is the capital of France?<|eot_id|><|start_header_id|>assistant<|end_header_id|>

定义了对话格式后,需要在对话数据上微调 LLM。对话数据可能来自于人,也可能由已经 post-training 过的 LLM 生成。

2.3.2 偏好学习

仅仅在格式上让 LLM 适配对话是不够的。互联网上存在大量的低质量内容,也包含很多我们不希望 LLM 去模仿的行为(如恶意言论)。因此,需要让 LLM 学习在人类看来更加“正确”的行为,而非无意识地模仿互联网上的内容。

构建高质量的对话数据集是较为困难的。但是还有一种相对容易的获取人类偏好的方式:让人类比较对同一问题的两个回答孰优孰劣。模型通过某种方式的学习,提高生成较优答案的概率,降低生成较劣答案的概率,从而实现适配人类偏好的效果。

受限于作者的数学水平,本节只概括性地描述偏好学习的理念,不涉及具体细节。

一个典型的 RLHF (Reinforcement Learning from Human Feedback) 流程如下:

  1. 收集偏好数据。一条偏好数据是形如 \(\mathrm{(input,\,output\_win,\,output\_lose)}\) 的三元组。
  2. 根据偏好数据训练一个模型(通常是 LLM 附加一个分类层),用于给 \(\mathrm{(input,\,output)}\) 对打分。训练时最大化打分和偏好数据的吻合程度(给 \(\mathrm{output\_win}\) 高分,给 \(\mathrm{output\_lose}\) 低分)。这个模型被称为 reward model。
  3. 以 reward model 为指导微调模型。这一步最大化模型输出在 reward model 上的得分,同时通过一个惩罚项避免模型偏离太远。由于 reward model 并不可微,这一步无法使用梯度下降法。通常使用强化学习领域的 PPO 算法进行优化。

PPO 过程较为繁琐,需要训练辅助模型和使用相对复杂的优化算法。DPO 通过一些数学上的调整,在保留原本算法的优秀性质的同时不再需要 reward model 和强化学习,而是直接更新模型参数。DPO 的复杂性显著低于 PPO,同时性能接近或更优。

Transformer 模型通常采用三种主要架构:encoder-decoder、encoder-only 和 decoder-only。

1.1 Encoder-decoder

图片出自 Attention Is All You Need

Transformer 原始论文中设计的模型架构就是 encoder-decoder 的。Encoder 通过双向自注意力处理输入,decoder 通过单向自注意力逐个生成输出,encoder 通过互注意力向 decoder 传递信息。

Encoder-decoder 架构起源于机器翻译等输入和输出之间具有一定异质性的任务。对于这种任务,使用一个模型理解输入,另一个模型生成输出是合理的做法。然而,在 LLM 的主要任务(QA、续写、聊天等)中,输入和输出是高度同质的(它们大概率是同一种语言,且在逻辑上相承接),这时使用两个模型分别处理两部分信息不仅没有必要,还会在模型设计中引入额外的复杂性。因此,LLM 架构中 decoder-only 的占比远远高于 encoder-decoder。

1.2 Encoder-only

这类模型的典型代表为 BERT。这一模型是文本理解领域的经典 backbone。

BERT 的预训练是自监督的,包括两个任务。

较为重要的一个是预测被 mask 的 token,一种类似于 denoising autoencoder 的经典预训练方法。具体而言,输入中随机 15% 的 token 会被 mask 掉(80% 概率变为 [MASK],10% 概率变为随机 token,10% 概率不变),而模型的任务就是还原这些 token。通过这个任务,模型可以学到 token 与 token 之间的双向关系,这是 next token prediction 做不到的。

另一个任务是 next sentence prediction,即输入两个语段,预测它们是否出自同一篇文章的相邻片段。这个任务可以加强模型对语段之间关系的理解。

BERT 可以生成用于下游文本理解任务的 deep representation,但不适合用于文本生成。虽然确实存在这样的方法,但其生成过程明显比 decoder-only 模型更复杂。究其原因,BERT 被训练为利用双向信息理解语言,但生成文本的过程本质上是单向的(生成文本时,模型只知道已经生成的 token,但不知道未来的 token)。这导致朴素的生成方式用于 BERT 时效果很差。

1.3 Decoder-only

目前的绝大多数 LLM 都是 decoder-only 语言模型。这类语言模型主要由四部分组成:

  1. Tokenizer:tokenizer 负责在输入文本和 token 序列之间相互转换。token 是语言模型处理信息的最小单位。对于英语输入,token 通常是一个完整单词或较不常用单词的一部分(在 ChatGPT 的 tokenizer 中,一个 token 大概相当于 3/4 个英文单词)。可能的 token 总数大致为 \(10^5\) 量级。
  2. Embedding:embedding 层是一个可学习的表,将每个 token 映射到一个高维向量。经过 tokenizer 和 embedding 层之后,文本输入被转化为一个 \(\mathrm{num\_tokens} \times \mathrm{embed\_dim}\) 的矩阵。
  3. Transformer 网络: 这一部分包含了模型的绝大部分计算量。每个 transformer 块包含一个掩蔽多头自注意力层和一个 feed-forward network(通常是两层神经网络),配有归一化和残差连接。在 LLM 中,整个网络通常由连续数十个规模相同的 transformer 块组成。
  4. LM head:这是模型的输出层,将 transformer 网络的输出转化为下一个 token 的概率分布。推理时,LM head 的输出通过一些采样方法生成出 token 序列,再通过 tokenizer 转换为文本。

以下是 Meta-Llama-3.1-8B-InstructQwen2.5-7B-Instruct 的大致架构,可以发现两者大同小异:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
LlamaForCausalLM(
(model): LlamaModel(
(embed_tokens): Embedding(128256, 4096, padding_idx=128004)
(layers): ModuleList(
(0-31): 32 x LlamaDecoderLayer(
(self_attn): LlamaSdpaAttention(
(q_proj): Linear(in_features=4096, out_features=4096, bias=False)
(k_proj): Linear(in_features=4096, out_features=1024, bias=False)
(v_proj): Linear(in_features=4096, out_features=1024, bias=False)
(o_proj): Linear(in_features=4096, out_features=4096, bias=False)
(rotary_emb): LlamaRotaryEmbedding()
)
(mlp): LlamaMLP(
(gate_proj): Linear(in_features=4096, out_features=14336, bias=False)
(up_proj): Linear(in_features=4096, out_features=14336, bias=False)
(down_proj): Linear(in_features=14336, out_features=4096, bias=False)
(act_fn): SiLU()
)
(input_layernorm): LlamaRMSNorm((4096,), eps=1e-05)
(post_attention_layernorm): LlamaRMSNorm((4096,), eps=1e-05)
)
)
(norm): LlamaRMSNorm((4096,), eps=1e-05)
(rotary_emb): LlamaRotaryEmbedding()
)
(lm_head): Linear(in_features=4096, out_features=128256, bias=False)
)

Qwen2ForCausalLM(
(model): Qwen2Model(
(embed_tokens): Embedding(152064, 3584)
(layers): ModuleList(
(0-27): 28 x Qwen2DecoderLayer(
(self_attn): Qwen2SdpaAttention(
(q_proj): Linear(in_features=3584, out_features=3584, bias=True)
(k_proj): Linear(in_features=3584, out_features=512, bias=True)
(v_proj): Linear(in_features=3584, out_features=512, bias=True)
(o_proj): Linear(in_features=3584, out_features=3584, bias=False)
(rotary_emb): Qwen2RotaryEmbedding()
)
(mlp): Qwen2MLP(
(gate_proj): Linear(in_features=3584, out_features=18944, bias=False)
(up_proj): Linear(in_features=3584, out_features=18944, bias=False)
(down_proj): Linear(in_features=18944, out_features=3584, bias=False)
(act_fn): SiLU()
)
(input_layernorm): Qwen2RMSNorm((3584,), eps=1e-06)
(post_attention_layernorm): Qwen2RMSNorm((3584,), eps=1e-06)
)
)
(norm): Qwen2RMSNorm((3584,), eps=1e-06)
)
(lm_head): Linear(in_features=3584, out_features=152064, bias=False)
)

Decoder-only 语言模型的预训练任务为 next token prediction。具体而言,模型对每个位置预测其 token 种类的概率分布(由于 transformer decoder 使用的是掩蔽自注意力,模型预测某个位置时只能看到它之前的 token),训练目标为最大化正确文本的 log likelihood。推理与其他模型类似,逐个采样即可。

在 decoder-only 语言模型的发展过程中,积累的量变产生了质变。这一点由 GPT 系列的发展可见一斑:

  • GPT-1:模型尺寸约 0.1B,训练语料来自书籍。在完成下游任务时仍然需要微调。
  • GPT-2:模型尺寸约 1.5B,训练语料来自互联网。可以 few-shot 完成下游任务,但通常需要精心设计的 prompt。
  • GPT-3:模型尺寸最大 175B,训练语料来自经过调配的多个数据集。可以 zero-shot 完成一些任务,也能理解一般的自然语言 prompt。
0%