大模型理论基础初步学习笔记——第六章 模型训练篇
第6章 模型训练
本文GitHub地址https://github.com/panda-like-bamboo/Study-CS324
上一章中,我们讨论了大语言模型(例如,Transformer)的模型结构。
在本章中,我们将讨论如何训练大语言模型。
本章分成目标函数和优化算法两部分。
6.1 目标函数
我们研究三类语言模型的目标函数:
- 只包含解码器(Decoder-only)的模型(例如,GPT-3):计算单向上下文嵌入(contextual embeddings),一次生成一个token
- 只包含编码器(Encoder-only)的模型(例如,BERT):计算双向上下文嵌入
- 编码器解码器(Encoder-decoder)模型(例如,T5):编码输入,解码输出
我们可以使用任何模型将token序列映射到上下文嵌入中(例如,LSTM、Transformers):
ϕ : V L → R d × L . \phi : V^L \to \mathbb{R}^{d \times L}. ϕ:VL→Rd×L.
[ the , mouse , ate , the , cheese ] ⇒ ϕ [ ( 1 0.1 ) , ( 0 1 ) , ( 1 1 ) , ( 1 − 0.1 ) , ( 0 − 1 ) ] . \left[\text{the}, \text{mouse}, \text{ate}, \text{the}, \text{cheese}\right] \stackrel{\phi}{\Rightarrow} \left[\binom{1}{0.1}, \binom{0}{1}, \binom{1}{1}, \binom{1}{-0.1}, \binom{0}{-1} \right]. [the,mouse,ate,the,cheese]⇒ϕ[(0.11),(10),(11),(−0.11),(−10)].
注解:
在这个公式中,
ϕ
\phi
ϕ 是一个函数,它将一个由长度为
L
L
L 的词汇表
V
V
V 中的单词构成的序列映射到一个实数矩阵
R
d
×
L
\mathbb{R}^{d \times L}
Rd×L。
-
V V V:表示词汇表,其中包含了模型训练时所涉及的所有单词。
-
L L L:表示输入序列的长度,即包含了 L L L个单词的序列。
-
R d × L \mathbb{R}^{d \times L} Rd×L:表示一个实数矩阵,该矩阵的维度为 d × L d \times L d×L,其中 d d d 是嵌入空间的维度, L L L 是序列的长度。这个矩阵存储了输入序列中每个单词的嵌入表示。
如何理解具体的映射过程?给定一个由单词构成的序列 [ the , mouse , ate , the , cheese ] [\text{the}, \text{mouse}, \text{ate}, \text{the}, \text{cheese}] [the,mouse,ate,the,cheese],这个序列中包含了 L = 5 L=5 L=5 个单词。通过映射函数 ϕ \phi ϕ,我们将每个单词映射到嵌入空间中的向量。
例如,假设嵌入空间的维度 d = 2 d=2 d=2,那么每个单词将被映射为一个二维向量。这个映射的结果可以表示为:
[ the , mouse , ate , the , cheese ] ⇒ ϕ [ ( 1 0.1 ) , ( 0 1 ) , ( 1 1 ) , ( 1 − 0.1 ) , ( 0 − 1 ) ] . \left[\text{the}, \text{mouse}, \text{ate}, \text{the}, \text{cheese}\right] \stackrel{\phi}{\Rightarrow} \left[\binom{1}{0.1}, \binom{0}{1}, \binom{1}{1}, \binom{1}{-0.1}, \binom{0}{-1} \right]. [the,mouse,ate,the,cheese]⇒ϕ[(0.11),(10),(11),(−0.11),(−10)].
这里,每一列对应于序列中一个单词的嵌入表示。例如,单词 “the” 在嵌入空间中的表示是 ( 1 0.1 ) \binom{1}{0.1} (0.11),单词 “mouse” 的表示是 ( 0 1 ) \binom{0}{1} (10),以此类推。这些嵌入表示在训练语言模型时会被调整,以使模型能够更好地捕捉输入序列中的语义信息。
6.1.1 Decoder-only 模型
回想一下,自回归语言模型定义了一个条件分布:
p ( x i ∣ x 1 : i − 1 ) . p(x_i \mid x_{1:i-1}). p(xi∣x1:i−1).
表示在给定前 (i-1) 个词的情况下,生成下一个词 (x_i) 的概率。
我们将其定义如下:
- 将 x 1 : i − 1 x_{1:i-1} x1:i−1 映射到上下文嵌入 ϕ ( x 1 : i − 1 ) \phi(x_{1:i-1}) ϕ(x1:i−1)。
- 应用嵌入矩阵 E ∈ R V × d E \in \R^{V \times d} E∈RV×d 来获得每个token的得分 E ϕ ( x 1 : i − 1 ) i − 1 E \phi(x_{1:i-1})_{i-1} Eϕ(x1:i−1)i−1 。
- 对其进行指数化和归一化,得到预测 x i x_i xi的 分布。
简洁地:
p ( x i + 1 ∣ x 1 : i ) = s o f t m a x ( E ϕ ( x 1 : i ) i ) . p(x_{i+1} \mid x_{1:i}) = softmax(E \phi(x_{1:i})_i). p(xi+1∣x1:i)=softmax(Eϕ(x1:i)i).
注释
这个公式描述了在语言模型中生成下一个词的过程。
-
x 1 : i x_{1:i} x1:i 表示从位置 1 1 1 到位置 i i i 的输入序列,即前 i i i 个词。
-
ϕ ( x 1 : i ) \phi(x_{1:i}) ϕ(x1:i) 是将输入序列 x 1 : i x_{1:i} x1:i 映射到上下文嵌入的函数。这里, ϕ \phi ϕ 是前面提到的将词汇表序列映射到实数矩阵的函数。
-
ϕ ( x 1 : i ) i \phi(x_{1:i})_i ϕ(x1:i)i 表示在位置 i i i 处的上下文嵌入向量,它是由映射函数 ϕ \phi ϕ 产生的。
-
E E E 是一个嵌入矩阵,它包含了模型学习到的所有词汇表中单词的嵌入表示。因此, E ϕ ( x 1 : i ) i E \phi(x_{1:i})_i Eϕ(x1:i)i 将给出位置 i i i 处每个单词在嵌入空间的表示。
-
s o f t m a x softmax softmax 函数将这些表示转换为一个概率分布,表示下一个词 x i + 1 x_{i+1} xi+1 在词汇表中的可能性。 s o f t m a x softmax softmax 的公式如下:
s o f t m a x ( z ) j = e z j ∑ k = 1 V e z k softmax(z)_j = \frac{e^{z_j}}{\sum_{k=1}^{V} e^{z_k}} softmax(z)j=∑k=1Vezkezj
其中 z z z 是输入向量, j j j 是词汇表中的某个单词, V V V 是词汇表的大小。 s o f t m a x softmax softmax 函数将输入向量的每个元素转化为非负值,并且这些值的总和等于1,因此可以解释为概率分布。
-
最终, p ( x i + 1 ∣ x 1 : i ) p(x_{i+1} \mid x_{1:i}) p(xi+1∣x1:i) 表示在给定前 i i i 个词的情况下,生成下一个词 x i + 1 x_{i+1} xi+1 的概率。这个概率由上述步骤计算得出,表示为 s o f t m a x ( E ϕ ( x 1 : i ) i ) softmax(E \phi(x_{1:i})_i) softmax(Eϕ(x1:i)i)。
总的来说,这个公式描述了在语言模型中,给定上下文中的一些词,模型如何计算生成下一个词的概率分布。这是训练语言模型时用于计算损失函数的一部分,而损失函数的目标是使模型生成的下一个词的概率分布尽可能接近实际的词汇分布。
6.1.1.1 最大似然
设
θ
\theta
θ 是大语言模型的所有参数。设
D
D
D 是由一组序列组成的训练数据。
然后,我们可以遵循最大似然原理,定义以下负对数似然目标函数:
O ( θ ) = ∑ x ∈ D − log p θ ( x ) = ∑ x ∈ D ∑ i = 1 L − log p θ ( x i ∣ x 1 : i − 1 ) . O(\theta) = \sum_{x \in D} - \log p_\theta(x) = \sum_{x \in D} \sum_{i=1}^L -\log p_\theta(x_i \mid x_{1:i-1}). O(θ)=x∈D∑−logpθ(x)=x∈D∑i=1∑L−logpθ(xi∣x1:i−1).
并且,有很多的方法可以有效地优化这一目标函数。
注释
θ \theta θ 是大语言模型的所有参数,包括权重矩阵、偏置等。
D D D 是由一组序列组成的训练数据集,包含多个文本序列。
对数似然表示为 log p θ ( x ) \log p_\theta(x) logpθ(x),即在模型参数 θ \theta θ 下生成整个序列 x x x 的概率的对数。
负对数似然目标函数 O ( θ ) O(\theta) O(θ) 是对数似然的相反数,通过取负对数似然可以将最大似然估计问题转化为最小化问题。这是因为最大化似然性等价于最小化负对数似然。
公式中的第二项 ∑ i = 1 L − log p θ ( x i ∣ x 1 : i − 1 ) \sum_{i=1}^L -\log p_\theta(x_i \mid x_{1:i-1}) ∑i=1L−logpθ(xi∣x1:i−1) 表示在给定前 i − 1 i-1 i−1 个词的情况下,生成下一个词 x i x_i xi 的概率的对数。这一项的加总表示对整个序列的负对数似然。
总体而言,这个目标函数的目标是通过调整模型的参数 θ \theta θ,最小化训练数据集中所有序列的负对数似然,从而提高模型在生成文本时的准确性。通过使用梯度下降等优化算法,可以找到使得这个目标函数最小化的模型参数。这是深度学习中常见的一种训练方式。
6.1.1.2最似然估计知识点
(没学好概率论的回旋镖,再一次把我击倒)
最大似然估计(Maximum Likelihood Estimation,简称MLE)是一种统计估计方法,用于估计概率模型的参数。它的基本思想是:选择那些使观测到的数据出现的概率最大的模型参数作为估计值。在统计学中,这被解释为找到参数值,使得观测到的数据在给定模型下的概率最大。
具体来说,设 θ \theta θ 是模型的参数, X X X 是观测到的数据。MLE 的目标是找到使得观测到数据 X X X 的条件概率 P ( X ∣ θ ) P(X | \theta) P(X∣θ) 最大的参数 θ \theta θ。
形式化地,给定模型参数 θ \theta θ,我们可以定义似然函数(Likelihood Function) L ( θ ) L(\theta) L(θ),表示观测到数据 X X X 的概率:
$ L(\theta) = P(X | \theta) $
如果我们有独立同分布(independent and identically distributed,简称 i.i.d.)的观测数据,那么总的似然函数就是各个观测数据的概率的乘积:
$ L(\theta) = \prod_{i=1}^n P(x_i | \theta) $
其中, n n n 是观测数据的数量, x i x_i xi 是第 i i i 个观测数据。
为了方便计算,通常使用对数似然函数(Log-Likelihood) l ( θ ) l(\theta) l(θ),即似然函数取对数:
$ l(\theta) = \log L(\theta) $
**最大似然估计的目标是找到使对数似然函数最大的参数 θ \theta θ,**即:
$ \hat{\theta}{\text{MLE}} = \arg\max{\theta} l(\theta) $
在实际应用中,通常使用梯度下降等优化算法来寻找对数似然函数的最大值,从而得到参数的估计值。
最大似然估计在统计学和机器学习中被广泛应用,它是一种常见的参数估计方法,可用于估计各种概率模型的参数,包括回归模型、分类模型等。
6.1.2 Encoder-only 模型
6.1.2.1 单向到双向
使用上述最大似然可以训练得到Decoder-only模型,它会产生(单向)上下文嵌入。但如果我们不需要生成,我们可以提供更强的双向上下文嵌入。
6.1.2.2 BERT
我们首先介绍BERT的目标函数,它包含以下两个部分:
- 掩码语言模型(Masked language modeling)
- 下一句预测(Next sentence prediction)
以自然语言推理(预测隐含、矛盾或中性)任务中的序列为例:
x 1 : L = [ [CLS] , all , animals , breathe , [SEP] , cats , breathe ] . x_{1:L} = [\text{[CLS]}, \text{all}, \text{animals}, \text{breathe}, \text{[SEP]}, \text{cats}, \text{breathe}]. x1:L=[[CLS],all,animals,breathe,[SEP],cats,breathe].
其中有两个特殊的token:
- [CLS] \text{[CLS]} [CLS] :包含用于驱动分类任务的嵌入
- [SEP] \text{[SEP]} [SEP] :用于告诉模型第一个序列(例如,前提)与第二个序列(例如,假设)的位置。
根据上一章的公式,BERT模型定义为:
BERT ( x 1 : L ) = TransformerBlock 24 ( EmbedTokenWithPosition ( x 1 : L ) + SentenceEmbedding ( x 1 : L ) ) ∈ R d × L , \text{BERT}(x_{1:L}) = \text{TransformerBlock}^{24}(\text{EmbedTokenWithPosition}(x_{1:L}) + \text{SentenceEmbedding}(x_{1:L})) \in \mathbb{R}^{d \times L}, BERT(x1:L)=TransformerBlock24(EmbedTokenWithPosition(x1:L)+SentenceEmbedding(x1:L))∈Rd×L,
其中, SentenceEmbedding ( x 1 : L ) \text{SentenceEmbedding}(x_{1:L}) SentenceEmbedding(x1:L) 根据序列返回以下两个矢量之一
- 对于 [SEP] \text{[SEP]} [SEP] 左边的,返回 e A ∈ R d e_A \in \mathbb{R}^d eA∈Rd
- 对于 [SEP] \text{[SEP]} [SEP] 右边的,返回 e B ∈ R d e_B \in \mathbb{R}^d eB∈Rd
注释
这个公式描述了BERT模型的整体结构,下面对其进行解释:
-
x 1 : L x_{1:L} x1:L 表示输入序列,其中 L L L 是序列的长度。这个序列包含了一段文本,比如一句话,它由一系列token组成。
-
EmbedTokenWithPosition ( x 1 : L ) \text{EmbedTokenWithPosition}(x_{1:L}) EmbedTokenWithPosition(x1:L) 表示对输入序列进行token嵌入,并考虑了它们在序列中的位置。这通常使用类似于嵌入层(embedding layer)和位置编码(position encoding)的方法来实现,以将每个token映射到一个高维的向量空间。
-
SentenceEmbedding ( x 1 : L ) \text{SentenceEmbedding}(x_{1:L}) SentenceEmbedding(x1:L) 表示对整个序列进行句子级别的嵌入。对于BERT来说,这是通过Transformer的多个注意力头来实现的,其中模型可以捕捉序列中不同部分之间的关系。
-
TransformerBlock 24 \text{TransformerBlock}^{24} TransformerBlock24 表示使用Transformer结构,这个结构由24个块组成。每个块都包含多头自注意力机制和前馈神经网络。这个结构允许模型在序列中进行多层次的、高效的学习。
-
BERT ( x 1 : L ) \text{BERT}(x_{1:L}) BERT(x1:L) 表示整个BERT模型的输出,是一个矩阵,其维度为 R d × L \mathbb{R}^{d \times L} Rd×L,其中 d d d 是每个token的嵌入维度, L L L 是序列的长度。这个输出矩阵中的每一列对应输入序列中每个token的表示。
总体而言,这个公式描述了BERT如何通过多层Transformer块对输入序列进行处理,考虑了token的嵌入、位置信息以及句子级别的关系,最终得到了每个token在高维向量空间中的表示。这种表示包含了丰富的上下文信息,可以用于各种自然语言处理任务。
BERT-large有 n heads = 16 n_\text{heads} = 16 nheads=16 个注意头,并且 d model = 1024 d_\text{model} = 1024 dmodel=1024 ,总共355M个参数。
6.1.2.2.1 掩码语言模型
掩码语言模型的基本思想是通过加噪然后预测来进行训练:
[ the , [MASK] , ate , [MASK] , cheese ] ⇒ [ the , mouse , ate , the , cheese ] . [\text{the}, \text{[MASK]}, \text{ate}, \text{[MASK]}, \text{cheese}] \Rightarrow [\text{the}, \text{mouse}, \text{ate}, \text{the}, \text{cheese}]. [the,[MASK],ate,[MASK],cheese]⇒[the,mouse,ate,the,cheese].
更普遍地说,我们可以将其视为类似于去噪自动编码器,其中我们映射有噪声/不完整版本 x ~ 1 : L \tilde x_{1:L} x~1:L ,并尝试重建原始 x 1 : L x_{1:L} x1:L 。
x ~ 1 : L ⇒ x 1 : L . \tilde x_{1:L} \Rightarrow x_{1:L}. x~1:L⇒x1:L.
注释
6.1.2.2.1.1随机噪声:
随机噪声函数 A ( x ~ 1 : L ∣ x 1 : L ) A(\tilde x_{1:L} \mid x_{1:L}) A(x~1:L∣x1:L) 被用于掩码语言模型,它在输入序列 x ~ 1 : L \tilde x_{1:L} x~1:L 中引入随机性,以帮助模型学习对噪声和不完整信息的鲁棒性。这个函数定义了在训练过程中如何生成带有噪声的输入序列。
注释.1随机噪声函数的定义:
-
假设 I ⊂ { 1 , … , L } I \subset \{1, \dots, L\} I⊂{1,…,L} 代表所有位置中随机的15%。
这里, I I I 是一个包含序列位置的集合,表示被选中引入噪声的位置。
-
对于每个 i ∈ I i \in I i∈I:
-
以80%的概率, x ~ i \tilde x_i x~i 被替换为 [MASK] \text{[MASK]} [MASK]
这意味着在80%的情况下,模型将原始输入序列中的某些位置替换为掩码符号 [MASK] \text{[MASK]} [MASK]。
-
以10%的概率, x ~ i \tilde x_i x~i 被替换为 x i x_i xi
以10%的概率,模型将原始输入序列中的某些位置替换为其原始的单词。
-
以10%的概率, x ~ i \tilde x_i x~i 被替换为从词汇表中随机选择的单词
以10%的概率,模型将原始输入序列中的某些位置替换为来自词汇表的随机单词。
-
注释.2举例说明:
考虑一个原始序列为:
[ The , cat , sat , on , the , mat ] . [\text{The}, \text{cat}, \text{sat}, \text{on}, \text{the}, \text{mat}]. [The,cat,sat,on,the,mat].
通过随机噪声函数的作用,可能会得到带有噪声的序列:
[ [MASK] , cat , sat , on , [MASK] , mat ] . [\text{[MASK]}, \text{cat}, \text{sat}, \text{on}, \text{[MASK]}, \text{mat}]. [[MASK],cat,sat,on,[MASK],mat].
在这个例子中,15%的位置(可能是第一个和第五个)被随机选择,并且根据上述概率规则,一些位置被替换为 [MASK] \text{[MASK]} [MASK],一些位置被替换为原始的单词,一些位置被替换为随机选择的单词。这样,模型通过处理带有不同噪声的输入来学习鲁棒的语言表示。
建模:我们首先定义模型分布。给定输入 x ~ 1 : L \tilde x_{1:L} x~1:L 及其上下文嵌入,模型独立地预测每个token:
p ( x i ∣ x ~ 1 : L ) = softmax ( E ϕ ( x ~ 1 : L ) i ) . p(x_i \mid \tilde x_{1:L}) = \text{softmax}(E \phi(\tilde x_{1:L})_i). p(xi∣x~1:L)=softmax(Eϕ(x~1:L)i).
掩码: 我们定义了一个(随机)噪声函数 A ( x ~ 1 : L ∣ x 1 : L ) A(\tilde x_{1:L} \mid x_{1:L}) A(x~1:L∣x1:L) :
以下是 A A A 的定义:
- 假设 I ⊂ { 1 , … , L } I \subset \{1, \dots, L\} I⊂{1,…,L} 代表所有位置中随机的15%。
- 对于每个
i
∈
I
i \in I
i∈I :
- 以0.8的概率, x ~ i ← [MASK] \tilde x_i \leftarrow \text{[MASK]} x~i←[MASK]
- 以0.1的概率, x ~ i ← x i \tilde x_i \leftarrow x_i x~i←xi
- 以0.1的概率, x ~ i ← random word from V \tilde x_i \leftarrow \text{random word from } \mathcal{V} x~i←random word from V
减少分布偏移: 如果我们总是使用 [MASK] \text{[MASK]} [MASK] 来替换 I I I 中选定的token,则:
- 在训练期间,输入到BERT的都是带 [MASK] \text{[MASK]} [MASK] 的序列。
- 而在测试时,我们会输入没有 [MASK] \text{[MASK]} [MASK] 的句子,这将导致分布发生变化。一种启发式的解决方法是在20%的时间内(此处指训练的时间)用真实单词替换。
6.1.2.2.2 下一句预测
回想一下,BERT是在拼接好的成对句子上训练的。下一句预测的目标是预测第二句是否跟随第一句。
[ [CLS] , the , mouse , ate , the , cheese , [SEP] , it , was , full ] ⇒ 1. [\text{[CLS]}, \text{the}, \text{mouse}, \text{ate}, \text{the}, \text{cheese}, \text{[SEP]}, \text{it}, \text{was}, \text{full}] \Rightarrow 1. [[CLS],the,mouse,ate,the,cheese,[SEP],it,was,full]⇒1.
[ [CLS] , the , mouse , ate , the , cheese , [SEP] , hello , world ] ⇒ 0. [\text{[CLS]}, \text{the}, \text{mouse}, \text{ate}, \text{the}, \text{cheese}, \text{[SEP]}, \text{hello}, \text{world}] \Rightarrow 0. [[CLS],the,mouse,ate,the,cheese,[SEP],hello,world]⇒0.
然后使用 [CLS] \text{[CLS]} [CLS] 的嵌入来做二分类。
注释
在文中提到的 “然后使用 [CLS] \text{[CLS]} [CLS] 的嵌入来做二分类” 意味着在进行下一句预测任务时,BERT(或类似的模型)使用句子对中的特殊标记 [CLS] \text{[CLS]} [CLS] 对应的嵌入来进行二分类。
下一句预测的任务描述:
-
输入序列的构建: 在进行下一句预测任务时,每个输入序列由两个句子构成,通过特殊的标记 [SEP] \text{[SEP]} [SEP] 分隔。一个句子的开始用 [CLS] \text{[CLS]} [CLS] 表示。例如:
[ [CLS] , the , mouse , ate , the , cheese , [SEP] , it , was , full ] [\text{[CLS]}, \text{the}, \text{mouse}, \text{ate}, \text{the}, \text{cheese}, \text{[SEP]}, \text{it}, \text{was}, \text{full}] [[CLS],the,mouse,ate,the,cheese,[SEP],it,was,full]
这个例子中,第一句是 “the mouse ate the cheese”,第二句是 “it was full”,它们之间由 [SEP] \text{[SEP]} [SEP] 分隔。
-
目标预测: 下一句预测的目标是预测第二句是否是紧随第一句的。在给定的例子中:
- 对于第一对句子: [ [CLS] , the , mouse , ate , the , cheese , [SEP] , it , was , full ] [\text{[CLS]}, \text{the}, \text{mouse}, \text{ate}, \text{the}, \text{cheese}, \text{[SEP]}, \text{it}, \text{was}, \text{full}] [[CLS],the,mouse,ate,the,cheese,[SEP],it,was,full],模型的目标输出是 1 1 1,表示第二句紧随第一句。
- 对于第二对句子: [ [CLS] , the , mouse , ate , the , cheese , [SEP] , hello , world ] [\text{[CLS]}, \text{the}, \text{mouse}, \text{ate}, \text{the}, \text{cheese}, \text{[SEP]}, \text{hello}, \text{world}] [[CLS],the,mouse,ate,the,cheese,[SEP],hello,world],模型的目标输出是 0 0 0,表示第二句不是紧随第一句的。
-
使用 [CLS] \text{[CLS]} [CLS] 的嵌入进行二分类: 在进行预测时,模型使用 [CLS] \text{[CLS]} [CLS] 对应的嵌入作为整个句子对的表示,并将其输入到一个二分类器中。这个二分类器的目标是判断第二句是否紧随第一句。
这种方法可以通过训练来学习句子对之间的语义关系,使模型在理解文本中句子的连贯性和关联性方面更为有效。
6.1.2.2.3 数据集
D \mathcal{D} D 是按如下方式构造的一组样本 ( x 1 : L , c ) (x_{1:L}, c) (x1:L,c) :
- 令 A A A 是语料库中的一个句子。
- 以0.5的概率, B B B 是下一句话。
- 以0.5的概率, B B B 是语料库中的一个随机句子。
- 令 x 1 : L = [ [CLS] , A , [SEP] , B ] x_{1:L} = [\text{[CLS]}, A, \text{[SEP]}, B] x1:L=[[CLS],A,[SEP],B]
- 令 c c c 表示 B B B 是否是下一句。
稍后我们将讨论训练,这里简要总结一下BERT:
- BERT(以及ELMo和ULMFiT)表明,一个统一的体系结构(Transformer)可以用于多个分类任务。
- BERT真正将NLP社区转变为预培训+微调的范式。
- BERT显示了深度双向上下文嵌入的重要性,尽管通过模型大小和微调策略可能会弥补这一点
6.1.2.3 RoBERTa
RoBERTa对BERT进行了以下改进:
- 删除了下一句预测这一目标函数(发现它没有帮助)。
- 使用更多数据训练(16GB文本 ⇒ \Rightarrow ⇒ 160GB文本 )。
- 训练时间更长。
- RoBERTa在各种基准上显著提高了BERT的准确性(例如,在SQuAD上由81.8到89.4)。
这部分介绍了Encoder-Decoder模型,以及两个基于Transformer的编码器-解码器模型,即BART和T5。
6.1.3 Encoder-Decoder 模型
在Encoder-Decoder模型中,给出了一个任务示例,其中输入是一个包含表格信息的序列,例如:
[ name , : , Clowns , | , eatType , : , coffee , shop ] ⇒ [ Clowns , is , a , coffee , shop ] . [\text{name}, \text{:}, \text{Clowns}, \text{|}, \text{eatType}, \text{:}, \text{coffee}, \text{shop}] \Rightarrow [\text{Clowns}, \text{is}, \text{a}, \text{coffee}, \text{shop}]. [name,:,Clowns,|,eatType,:,coffee,shop]⇒[Clowns,is,a,coffee,shop].
这个任务涉及生成文本,通过对输入序列进行编码,然后解码生成相应的输出文本。
6.1.3.1 BART (Bidirectional Auto-Regressive Transformers)
BART是一种基于Transformer的编码器-解码器模型,它使用与RoBERTa相同的编码器架构(12层,隐藏维度1024),并使用相似的训练数据。BART在预训练阶段引入了一些变换,例如对文档中30%的token进行掩码和子句的打乱。最后,通过微调,BART在分类和生成任务上表现强大。
6.1.3.2 T5 (Text-to-Text Transfer Transformer)
T5是另一种基于Transformer的编码器-解码器模型。在预训练任务中,给定一段文本,将其分割为输入和输出。例如:
[ the , mouse ] ⇒ [ ate , the , cheese ] . [\text{the}, \text{mouse}] \Rightarrow [\text{ate}, \text{the}, \text{cheese}]. [the,mouse]⇒[ate,the,cheese].
T5尝试了多个无监督目标,并发现"i.i.d. noise, replace spans"效果最好。论文还将所有经典的NLP任务放在一个统一的框架中,称为"Text-to-Text"任务。对于分类任务,不同模型的处理方式不同,例如BERT使用 [CLS] \text{[CLS]} [CLS] 的嵌入来预测,而生成模型(如T5、GPT-2、GPT-3)将分类任务转换成自然语言生成。
该文研究了多个方面,包括数据集、模型大小、训练目标等,并基于这些见解训练了一个11B的模型。这些模型在多个NLP任务上展现出了出色的性能。
6.2 优化算法
现在,我们将注意力转向如何优化目标函数。
以自回归语言模型为例:
O ( θ ) = ∑ x ∈ D − log p θ ( x ) . O(\theta) = \sum_{x \in D} -\log p_\theta(x). O(θ)=x∈D∑−logpθ(x).
注释
方程表示了一个目标函数 O ( θ ) O(\theta) O(θ),通常在深度学习中用于训练模型。
O ( θ ) = ∑ x ∈ D − log p θ ( x ) . O(\theta) = \sum_{x \in D} -\log p_\theta(x). O(θ)=x∈D∑−logpθ(x).
其中:
- O ( θ ) O(\theta) O(θ) 是目标函数,即我们希望最小化的损失函数。
- θ \theta θ 是模型的参数集合,这些参数用于定义模型的预测分布。
- D D D 是训练数据集,其中包含多个样本 x x x。
目标函数的具体形式是由每个样本的对数似然的负数之和组成的。组成为:
-
p θ ( x ) p_\theta(x) pθ(x):这表示模型给定参数 θ \theta θ 的条件概率分布,即模型对样本 x x x 的预测。
-
log p θ ( x ) \log p_\theta(x) logpθ(x):这是对数似然,表示观察到数据 x x x 的对数概率。对数似然通常在深度学习中用作损失函数,因为它有助于避免数值不稳定性,并且它与概率的乘法转化为对数的加法。
-
− log p θ ( x ) -\log p_\theta(x) −logpθ(x):这是对数似然的负数。在优化中,我们通常希望最小化损失函数,因此采用负对数似然。
-
∑ x ∈ D − log p θ ( x ) \sum_{x \in D} -\log p_\theta(x) ∑x∈D−logpθ(x):这是对所有训练样本的损失的总和。我们的目标是通过调整模型参数 θ \theta θ 来最小化这个总损失。
这样的目标函数通常用于监督学习问题,其中我们有一组带有标签的训练数据,并且我们的目标是训练模型以最小化它对标签的预测与实际标签之间的差距。这个差距由损失函数度量,而对数似然是一种常用的损失函数,尤其在分类问题中。
6.2.1 随机梯度下降(SGD)
最简单的优化算法是用小批量进行随机梯度下降,该算法的步骤如下:
- 初始化参数 θ 0 \theta_0 θ0
- 重复以下步骤:
- 采样小批量 B t ⊂ D B_t \subset D Bt⊂D
- 根据梯度更新参数:
θ t ← θ t − 1 − η 1 ∣ B t ∣ ∑ x ∈ B t ∇ θ ( − log p θ ( x ) ) . \theta_t \leftarrow \theta_{t-1} - \eta \frac{1}{|B_t|} \sum_{x \in B_t} \nabla_\theta (-\log p_\theta(x)). θt←θt−1−η∣Bt∣1x∈Bt∑∇θ(−logpθ(x)).
注释
这是优化算法中的更新规则,通常用于随机梯度下降(SGD)或其变体,其中:
- θ t \theta_t θt 是在时间步 t t t 更新后的模型参数。
- θ t − 1 \theta_{t-1} θt−1 是上一个时间步的模型参数。
- η \eta η 是学习率,它控制了每次参数更新的步长。
- ∣ B t ∣ |B_t| ∣Bt∣ 表示小批量(mini-batch)的大小,即每次更新用于计算梯度的样本数量。
- ∑ x ∈ B t ∇ θ ( − log p θ ( x ) ) \sum_{x \in B_t} \nabla_\theta (-\log p_\theta(x)) ∑x∈Bt∇θ(−logpθ(x)) 表示对当前小批量样本集 B t B_t Bt 中的每个样本 x x x 计算模型参数 θ \theta θ 对负对数似然的梯度,并将梯度求和。
更新规则的含义是:通过从整个训练数据集 D D D 中随机抽取小批量 B t B_t Bt,计算对应于这个小批量的负对数似然梯度,然后按照学习率 η \eta η 的大小,更新当前模型参数 θ t − 1 \theta_{t-1} θt−1,以最小化损失函数 − log p θ ( x ) -\log p_\theta(x) −logpθ(x)。
这个过程是一个迭代的优化算法,通过不断迭代地更新模型参数,希望在训练数据上找到一个使得损失函数最小化的最优参数配置 θ \theta θ。这是深度学习模型训练的基本步骤之一。
优化的关键点包括:
- 我们希望参数 θ \theta θ 可以快速收敛
- 我们希望优化在数值上是稳定的
- 我们希望内存高效(尤其是对于大模型)
这些点往往相互矛盾(例如,通过低精度训练,可以实现快速收敛、减少内存占用,但是会导致训练不稳定)
因此,我们可以从几个层次来进行优化:
- 针对经典优化:二阶方法、约束优化等。
- 针对机器学习:随机方法、隐式正则化+早停法
- 针对深度学习:初始化、归一化(更改模型架构)
- 针对大语言模型:由于稳定性问题,学习率和一些直觉(例如,二阶方法)仍然有用,但要使大语言模型有效训练,还需要克服许多其他独特的挑战。不幸的是,其中大部分内容都是特别的,人们对此了解甚少。
6.2.2 Adam (adaptive moment estimation)
Adam算法拥有以下两个创新:
- 引入动量(继续朝同一方向移动)。
- 参数 θ 0 \theta_0 θ0 的每个维度都有一个自适应(不同)的步长(受二阶方法启发)。
它的步骤如下:
- 初始化参数 θ 0 \theta_0 θ0
- 初始化动量 m 0 , v 0 ← 0 m_0, v_0 \leftarrow 0 m0,v0←0
- 重复以下步骤:
- 采样小批量 B t ⊂ D B_t \subset D Bt⊂D
- 按照如下步骤更新参数:
- 计算梯度
g t ← 1 ∣ B t ∣ ∑ x ∈ B t ∇ θ ( − log p θ ( x ) ) . g_t \leftarrow \frac{1}{|B_t|} \sum_{x \in B_t} \nabla_\theta (-\log p_\theta(x)). gt←∣Bt∣1∑x∈Bt∇θ(−logpθ(x)).
- 更新一阶、二阶动量
m t ← β 1 m t − 1 + ( 1 − β 1 ) g t m_t \leftarrow \beta_1 m_{t-1} + (1 - \beta_1) g_t mt←β1mt−1+(1−β1)gt
v t ← β 2 v t − 1 + ( 1 − β 2 ) g t 2 v_t \leftarrow \beta_2 v_{t-1} + (1 - \beta_2) g_t^2 vt←β2vt−1+(1−β2)gt2
- 对偏差进行修正
m ^ t ← m t / ( 1 − β 1 t ) \hat m_t \leftarrow m_t / (1 - \beta_1^t) m^t←mt/(1−β1t)
v ^ t ← v t / ( 1 − β 2 t ) \hat v_t \leftarrow v_t / (1 - \beta_2^t) v^t←vt/(1−β2t)
- 更新参数
θ t ← θ t − 1 − η m ^ t / ( v ^ t + ϵ ) . \theta_t \leftarrow \theta_{t-1} - \eta \, \hat m_t / (\sqrt{\hat v_t} + \epsilon). θt←θt−1−ηm^t/(v^t+ϵ).
存储占用分析:
Adam将存储从2倍的模型参数( θ t , g t \theta_t,g_t θt,gt )增加到了4倍( θ t , g t , m t , v t \theta_t,g_t,m_t,v_t θt,gt,mt,vt )。。
注释
上述文段讨论了Adam优化算法的主要步骤和创新点。
-
Adam的创新点:
- 引入动量: Adam算法引入了动量的概念,这意味着在参数更新时,模型会继续沿着之前的方向移动。这有助于克服SGD的一些缺点,如在非凸优化问题中易陷入局部极小值。
- 自适应学习率: Adam为每个参数的每个维度都引入了自适应的学习率。这是通过维护两个额外的指数移动平均变量 m t m_t mt和 v t v_t vt来实现的。这样,每个参数都有不同的学习率,有助于更灵活地调整参数。
-
Adam的步骤:
- 初始化: 首先,需要初始化模型参数 θ 0 \theta_0 θ0 以及动量变量 m 0 m_0 m0 和 v 0 v_0 v0 为零。
- 小批量采样: 从整个训练数据集 D D D 中随机采样小批量 B t B_t Bt。
- 计算梯度: 计算小批量中每个样本的梯度 ∇ θ ( − log p θ ( x ) ) \nabla_\theta(-\log p_\theta(x)) ∇θ(−logpθ(x))。
- 更新一阶、二阶动量: 使用指数移动平均更新动量变量 m t m_t mt 和 v t v_t vt。
- 对偏差进行修正: 对更新的动量进行修正,以避免在训练初期偏向零的情况。
- 更新参数: 使用修正后的动量和二阶动量,按照更新规则更新模型参数 θ t \theta_t θt。
-
存储占用分析:
- Adam引入了两个额外的变量 m t m_t mt 和 v t v_t vt,因此存储占用从原来的2倍模型参数增加到了4倍。这需要更多的内存,但也使得Adam更为灵活,具有自适应学习率的优势。
总体来说,Adam算法在深度学习中被广泛使用,因为它在实践中表现良好,并结合了动量和自适应学习率的优点。
6.2.3 AdaFactor
AdaFactor是一种为减少存储占用的优化算法。它有如下特点:
- 它不储存 m t , v t m_t,v_t mt,vt 这样的 O ( m × n ) O(m \times n) O(m×n) 矩阵,而是存储行和列的和 O ( m + n ) O(m + n) O(m+n) 并重构矩阵
- 去除动量
- 它被用来训练T5
- AdaFactor可能使训练变得困难(见Twitter thread和blog post)
6.2.4 混合精度训练
混合精度训练是另一种减少存储的方法
- 通常来说,默认的精度是:FP32(32位浮点)
- 其他可选精度:FP16(16位浮点),但问题是任何小于 2 − 24 2^{-24} 2−24 的值都会变为0。
- 解决方案:将主权重存储在FP32中,并在FP16中执行其他所有操作。
- 损失缩放:按比例放大损失,以避免梯度数值太小。
- 结果:存储减少了一半。
6.2.5 学习率
- 通常情况下,学习率会随着时间的推移而衰减。
- 对于Transformer模型,我们实际上需要通过预热(warmup)提高学习率。
- Huang et al., 2020表明,一个潜在的原因是防止层归一化的梯度消失,导致使用Adam优化器训练时不稳定。
6.2.6 初始化
- 给定矩阵 W ∈ R m × n W \in \mathbb{R}^{m \times n} W∈Rm×n ,标准初始化(即,xavier初始化)为 W i j ∼ N ( 0 , 1 / n ) W_{ij} \sim N(0, 1/n) Wij∼N(0,1/n) 。
- GPT-2和GPT-3通过额外的 1 / N 1/\sqrt{N} 1/N 缩放权重,其中 N N N 是残差层的数量。
- T5将注意力矩阵增加一个 1 / d 1/\sqrt{d} 1/d (代码)。
以GPT-3为例,使用的参数如下:
- Adam参数: β 1 = 0.9 , β 2 = 0.95 , ϵ = 1 0 − 8 \beta_1 = 0.9, \beta_2 = 0.95, \epsilon = 10^{-8} β1=0.9,β2=0.95,ϵ=10−8
- 批量小:320万个token(约1500个序列)
- 使用梯度剪裁( g t ← g t / min ( 1 , ∥ g ∥ 2 ) g_t \leftarrow g_t / \min(1, \|g\|_2) gt←gt/min(1,∥g∥2) )
- 线性学习率预热(前3.75亿个token)
- 余弦学习率衰减到10%
- 逐渐增加批大小
- 权重衰减设为0.1
延伸阅读
- 混合精度训练
- Fixing Weight Decay Regularization in Adam. I. Loshchilov, F. Hutter. 2017. 介绍了AdamW
- ELECTRA: Pre-training Text Encoders as Discriminators Rather Than Generators. Kevin Clark, Minh-Thang Luong, Quoc V. Le, Christopher D. Manning. ICLR 2020.
- DeBERTa: Decoding-enhanced BERT with Disentangled Attention. Pengcheng He, Xiaodong Liu, Jianfeng Gao, Weizhu Chen. ICLR 2020.
参考:
[1]datawhale讲义: https://github.com/datawhalechina/so-large-lm
[2]CS324: https://stanford-cs324.github.io/winter2022/lectures/