上一章中,我们讨论了大语言模型(例如,Transformer)的模型结构。
在本章中,我们将讨论如何训练大语言模型。
本章分成目标函数和优化算法两部分。
我们研究三类语言模型的目标函数:
我们可以使用任何模型将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)].
回想一下,自回归语言模型定义了一个条件分布:
p ( x i ∣ x 1 : i − 1 ) . p(x_i \mid x_{1:i-1}). p(xi∣x1:i−1).
我们将其定义如下:
简洁地:
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).
设 θ \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).
并且,有很多的方法可以有效地优化这一目标函数。
使用上述最大似然可以训练得到Decoder-only模型,它会产生(单向)上下文嵌入。但如果我们不需要生成,我们可以提供更强的双向上下文嵌入。
我们首先介绍BERT的目标函数,它包含以下两个部分:
以自然语言推理(预测隐含、矛盾或中性)任务中的序列为例:
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:
根据上一章的公式,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)根据序列返回以下两个矢量之一
BERT-large有 n heads = 16 n_\text{heads} = 16 nheads=16个注意头,并且 d model = 1024 d_\text{model} = 1024 dmodel=1024,总共355M个参数。
掩码语言模型的基本思想是通过加噪然后预测来进行训练:
[ 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.
建模:我们首先定义模型分布。给定输入 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):
x 1 : L ⏟ original ⇒ A x ~ 1 : L ⏟ noised . \underbrace{x_{1:L}}_\text{original} \stackrel{A}{\Rightarrow} \underbrace{\tilde x_{1:L}}_\text{noised}. original x1:L⇒Anoised x~1:L.
以下是 A A A的定义:
减少分布偏移: 如果我们总是使用 [MASK] \text{[MASK]} [MASK]来替换 I I I中选定的token,则:
回想一下,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]的嵌入来做二分类。
D \mathcal{D} D是按如下方式构造的一组样本 ( x 1 : L , c ) (x_{1:L}, c) (x1:L,c):
BERT的训练目标是:
O ( θ ) = ∑ ( x 1 : L , c ) ∈ D E I , x ~ 1 : L ∼ A ( ⋅ ∣ x 1 : L , I ) [ ∑ i ∈ I − log p θ ( x ~ i ∣ x 1 : L ) ] ⏟ masked language modeling + − log p ( c ∣ ϕ ( x 1 : L ) 1 ) ⏟ next sentence prediction . \mathcal{O}(\theta) = \sum_{(x_{1:L},c) \in \mathcal{D}} \underbrace{\mathbb{E}_{I, \tilde x_{1:L} \sim A(\cdot \mid x_{1:L}, I)}[\sum_{i \in I} -\log p_\theta(\tilde x_i \mid x_{1:L})]}_\text{masked language modeling} + \underbrace{-\log p(c \mid \phi(x_{1:L})_1)}_\text{next sentence prediction}. O(θ)=(x1:L,c)∈D∑masked language modeling EI,x~1:L∼A(⋅∣x1:L,I)[i∈I∑−logpθ(x~i∣x1:L)]+next sentence prediction −logp(c∣ϕ(x1:L)1).
稍后我们将讨论训练,这里简要总结一下BERT:
RoBERTa对BERT进行了以下改进:
任务示例(表格生成文本):
[ name , : , Clowns , | , eatType , : , coffee , shop ] R i g h t a r r o w [ Clowns , is , a , coffee , shop ] . [\text{name}, \text{:}, \text{Clowns}, \text{|}, \text{eatType}, \text{:}, \text{coffee}, \text{shop}] \mathbb{R}ightarrow [\text{Clowns}, \text{is}, \text{a}, \text{coffee}, \text{shop}]. [name,:,Clowns,|,eatType,:,coffee,shop]Rightarrow[Clowns,is,a,coffee,shop].
回想一下编码器-解码器模型(例如,BART、T5):
BART (Lewis et al. 2019)是基于Transformer的编码器-解码器模型。
BART使用了以下变换 A ( x ~ 1 : L ∣ x 1 : L ) A(\tilde x_{1:L} \mid x_{1:L}) A(x~1:L∣x1:L):
基于BERT的实验,最终模型进行以下了变换:
最后,通过微调,BART在分类和生成任务上都展示了强大的效果。
T5 (Raffel et al., 2020)是另一种基于Transformer的编码器-解码器模型。
预训练任务:
给定一段文本,在随机位置将其分割为输入和输出:
[ the , mouse ] ⇒ [ ate , the , cheese ] . [\text{the}, \text{mouse}] \Rightarrow [\text{ate}, \text{the}, \text{cheese}]. [the,mouse]⇒[ate,the,cheese].
论文尝试了许多不同的无监督目标:
并发现“i.i.d. noise, replace spans”效果最好(尽管许多目标相似)。
论文还将所有经典的NLP任务放在一个统一的框架中,称为“Text-to-Text”任务:
以分类任务任务为例,不同模型的差异如下:
注意:
现在,我们将注意力转向如何优化目标函数。
为了简单起见,让我们以自回归语言模型为例:
O ( θ ) = ∑ x ∈ D − log p θ ( x ) . O(\theta) = \sum_{x \in D} -\log p_\theta(x). O(θ)=x∈D∑−logpθ(x).
最简单的优化算法是用小批量进行随机梯度下降,该算法的步骤如下:
优化的关键点包括:
这些点往往相互矛盾(例如,通过低精度训练,可以实现快速收敛、减少内存占用,但是会导致训练不稳定)
因此,我们可以从几个层次来进行优化:
Adam算法拥有以下两个创新:
它的步骤如下:
计算梯度
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∣1x∈Bt∑∇θ(−logpθ(x)).
更新一阶、二阶动量
m t ← β 1 m t − 1 + ( 1 − β 1 ) g t v t ← β 2 v t − 1 + ( 1 − β 2 ) g t 2 m_t \leftarrow \beta_1 m_{t-1} + (1 - \beta_1) g_t \\ v_t \leftarrow \beta_2 v_{t-1} + (1 - \beta_2) g_t^2 mt←β1mt−1+(1−β1)gtvt←β2vt−1+(1−β2)gt2
对偏差进行修正
m ^ t ← m t / ( 1 − β 1 t ) v ^ t ← v t / ( 1 − β 2 t ) \hat m_t \leftarrow m_t / (1 - \beta_1^t) \\ \hat v_t \leftarrow v_t / (1 - \beta_2^t) m^t←mt/(1−β1t)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)。
AdaFactor是一种为减少存储占用的优化算法。它有如下特点:
混合精度训练是另一种减少存储的方法
以GPT-3为例,使用的参数如下: