赞
踩
注意:文章内容参考了斯坦福CS324 - Large Language Models课程,以及Datawhale的一起学相关课程中的内容。
模型架构(第三章)总结:大模型的结构如何构建?主要由分词(Tokenization)和模型架构(主要是Transformer)
构成。分词就是将自然语言转为机器语言的过程(可以这样理解),Transformer 是典型的编解码结构(encoder-decoder
)。
新的模型架构(第四章)总结:是在第三章的基础上为了扩大模型规模,需要改进稠密Transformer
。混合专家和基于检索的方法
相结合更有效。如何设计更好的、可扩展的体系结构仍然是一个悬而未决的问题。
接下来就是满满的干货了
对于初学者,为了更好的了解整体的功能结构(而不从一开始就陷入局部的结构细节)我们可以将大模型看成一个黑箱,即输入提示(prompt)输出(completion)符合需求的结果
:
p
r
o
m
p
t
⇝
m
o
d
e
l
c
o
m
p
l
e
t
i
o
n
o
r
m
o
d
e
l
(
p
r
o
m
p
t
)
=
c
o
m
p
l
e
t
i
o
n
prompt \overset{model}{\leadsto} completion \ \ or \ \ model(prompt) = completion
prompt⇝modelcompletion or model(prompt)=completion
将着重讨论两个主题,分别是分词和模型架构:
我们知道语言模型 p p p 是建立在词元(token)序列的上的一个概率分布输出,其中每个词元来自某个词汇表 V V V,如下的形式。
[the, mouse, ate, the, cheese]
Tips: 词元(token)一般在NLP(自然语言处理)中来说,通常指的是一个文本序列中的最小单元,可以是单词、标点符号、数字、符号或其他类型的语言元素。通常,对于NLP任务,文本序列会被分解为一系列的tokens,以便进行分析、理解或处理。在英文中一个"token"可以是一个单词,也可以是一个标点符号。在中文中,通常以字或词作为token(这其中就包含一些字符串分词的差异性,将在后续内容中讲到)。
然而,自然语言并不是以词元序列的形式出现,而是以字符串的形式存在(具体来说,是Unicode字符的序列),比如上面的序列的自然语言为“the mouse ate the cheese”。
分词器将任意字符串转换为词元序列:
the mouse ate the cheese.
⇒
[
t
h
e
,
m
o
u
s
e
,
a
t
e
,
t
h
e
,
c
h
e
e
s
e
,
.
]
\Rightarrow [the, mouse, ate, the, cheese, .]
⇒[the,mouse,ate,the,cheese,.]小明看到湖岸上的花草,一株不知名的小花引起了他的注意
⇒
[
小明
,
看到
,
湖岸
,
上的
,
花
,
草,一株
,
不知名的
,
小花
,
引起了
,
他的
,
注意
]
\Rightarrow [小明,看到,湖岸,上的,花,草,一株,不知名的,小花,引起了,他的,注意]
⇒[小明,看到,湖岸,上的,花,草,一株,不知名的,小花,引起了,他的,注意]Tips: 熟悉计算机的可能清晰字符串和序列的差异性,这里只做一个简要的说明。
字符串:所以字母、符号和空格都是这这个字符串的一部分。
词元序列:由多个字符串组成(相当于把一个字符串分割为了多了子字符串,每个子字符串是一个词元)
这里需要注意的是,虽然这部分并不一定是语言建模中最引人注目的部分,但在确定模型的工作效果方面起着非常重要的作用。我们也可以将这个方式理解为自然语言和机器语言的一种隐式的对齐,也可能是大家对于语言模型可能开始接触的时候最困惑的地方,特别是做机器学习相关的人员,因为我们所日常了解的输入需要是数值的,从而才能在模型中被计算,所以,如果输入是非数值类型的字符串是怎么处理的呢?
接下来我们就一步一步来看.
Tips:为什么说是“隐式的对齐”,这是由于每一个词在模型中,都有一个其确定的词向量。
可视化的词编码:https://observablehq.com/@simonw/gpt-tokenizer
此方法对于英文比较友好,中文就不太好。
分词,其实从字面很好理解,就是把词分开,从而方便对于词进行单独的编码,对于英文字母来说,由于其天然的主要由单词+空格+标点符号组成,最简单的解决方案是使用text.split(’ ')方式进行分词,这种分词方式对于英文这种按照空格,且每个分词后的单词有语义关系的文本是简单而直接的分词方式。然而,对于一些语言,如中文,句子中的单词之间没有空格,例如
"小明看到湖岸上的花草,一株不知名的小花引起了他的注意。"
\text{"小明看到湖岸上的花草,一株不知名的小花引起了他的注意。"}
"小明看到湖岸上的花草,一株不知名的小花引起了他的注意。"
目前从直觉和工程实践的角度来说,什么样的分词才是好的:
将字节对编码(BPE)算法应用于数据压缩领域,用于生成其中一个最常用的分词器。BPE分词器需要通过模型训练数据进行学习,获得需要分词文本的一些频率特征。
such as :
Input:
I = [['the car','the cat','the rat']]
Step1. 对输入input的每一项进行切分:
[['t', 'h', 'e', '$\space$', 'c', 'a', 'r'],
['t', 'h', 'e', '$\space$', 'c', 'a', 't'],
['t', 'h', 'e', '$\space$', 'r', 'a', 't']]
对于着三个切分后的集合我们求其并集,
$V$=['t','h','e',' ','c','a','r','t']。
在此基础上我们假设期望继续扩充
V
V
V,我们找
V
V
V中共同出现次数最多的元素对
x
,
x
′
x,x'
x,x′:
我们找到
V
V
V中共同出现次数最多的元素对
x
,
x
′
x,x'
x,x′,我们发现’t’和’h’按照’th’形式一起出现了三次,‘h’和’e’按照’he’形式一起出现了三次,我们可以随机选择其中一组,假设我们选择了’th’。
接下来,继续执行. 用一个新的符号
x
x
′
xx'
xx′ 替换所有
x
,
x
′
x,x'
x,x′ 的出现:
将之前的序列更新如下:(th 出现了 3次)
[[th, e, $\sqcup$, c, a, r],
[th, e, $\sqcup$, c, a, t],
[th, e, $\sqcup$, r, a, t]]
最后我们再执行 添加. 将
x
x
′
xx'
xx′ 添加到V中:
从而得到了一次更新后的词汇表
$V$=['t','h','e',' ','c','a','r','t','th']。
接下来如此往复:
[the, ⊔ , c , a , r ] \sqcup , c, a, r] ⊔,c,a,r], [the, ⊔ , c , a , t ] , [ \sqcup , c, a, t],[ ⊔,c,a,t],[ the, ⊔ , r , a , t ] \sqcup , r, a, t] ⊔,r,a,t] (the 出现了 3次)
[the, ⊔ , c a , r ] \sqcup , ca, r] ⊔,ca,r], [the, ⊔ , c a , t ] , [ \sqcup , ca, t],[ ⊔,ca,t],[ the, ⊔ , r a , t ] \sqcup , ra, t] ⊔,ra,t] (ca 出现了 2次)
Unicode(统一码)是当前主流的一种编码方式。其中这种编码方式对BPE分词产生了一个问题(尤其是在多语言环境中),Unicode字符非常多(共144,697个字符)。在训练数据中我们不可能见到所有的字符。
为了进一步减少数据的稀疏性,我们可以对字节而不是Unicode字符运行BPE算法(Wang等人,2019年)。
以中文为例:
今天 ⇒ [x62, x11, 4e, ca] \text { 今天} \Rightarrow \text {[x62, x11, 4e, ca]} 今天⇒[x62, x11, 4e, ca]
BPE算法在这里的作用是为了进一步减少数据的稀疏性。通过对字节级别进行分词,可以在多语言环境中更好地处理Unicode字符的多样性,并减少数据中出现的低频词汇,提高模型的泛化能力。通过使用字节编码,可以将不同语言中的词汇统一表示为字节序列,从而更好地处理多语言数据。
上下文向量表征 (Contextual Embedding): 作为先决条件,主要的关键发展是将词元序列与相应的上下文的向量表征:
[
t
h
e
,
m
o
u
s
e
,
a
t
e
,
t
h
e
,
c
h
e
e
s
e
]
⇒
ϕ
[
(
1
0.1
)
,
(
0
1
)
,
(
1
1
)
,
(
1
−
0.1
)
,
(
0
−
1
)
]
.
[the, mouse, ate, the, cheese] \stackrel{\phi}{\Rightarrow}\left[\left(
正如名称所示,词元的上下文向量表征取决于其上下文(周围的单词);例如,考虑mouse的向量表示需要关注到周围某个窗口大小的其他单词。
符号表示:我们将 ϕ : V L → R d × L ϕ:V^{L}→ℝ^{d×L} ϕ:VL→Rd×L 定义为嵌入函数(类似于序列的特征映射,映射为对应的向量表示)。
对于词元序列 x 1 : L = [ x 1 , … , x L ] x1:L=[x_{1},…,x_{L}] x1:L=[x1,…,xL], ϕ ϕ ϕ 生成上下文向量表征 ϕ ( x 1 : L ) ϕ(x_{1:L}) ϕ(x1:L)。
编码端主要用来生成上下文向量表征,但不能直接用于生成文本。可以表示为, x 1 : L ⇒ ϕ ( x 1 : L ) x_{1:L}⇒ϕ(x_{1:L}) x1:L⇒ϕ(x1:L) 。这些上下文向量表征通常用于分类任务(也被称为自然语言理解任务)。任务形式比较简单,下面以情感分类/自然语言推理任务举例:
情感分析输入与输出形式: [ [ C L S ] , 他们 , 移动 , 而 , 强大 ] ⇒ 正面情绪 情感分析输入与输出形式:[[CLS], 他们, 移动, 而, 强大]\Rightarrow 正面情绪 情感分析输入与输出形式:[[CLS],他们,移动,而,强大]⇒正面情绪
自然语言处理输入与输出形式: [ [ C L S ] , 所有 , 动物 , 都 , 喜欢 , 吃 , 饼干 , 哦 ] ⇒ 蕴涵 自然语言处理输入与输出形式:[[CLS], 所有, 动物, 都, 喜欢, 吃, 饼干, 哦]⇒蕴涵 自然语言处理输入与输出形式:[[CLS],所有,动物,都,喜欢,吃,饼干,哦]⇒蕴涵
该架构的优势是对于文本的上下文信息有更好的理解,因此该模型架构才会多用于理解任务。
解码器架构的著名模型就是大名鼎鼎的GPT系列模型。这些是我们常见的自回归语言模型,给定一个提示
x
1
:
i
x_{1:i}
x1:i ,它们可以生成上下文向量表征,并对下一个词元
x
i
+
1
x_{i+1}
xi+1 (以及递归地,整个完成
x
i
+
1
:
L
x_{i+1:L}
xi+1:L) 生成一个概率分布。
x
1
:
i
⇒
ϕ
(
x
1
:
i
)
,
p
(
x
i
+
1
∣
x
1
:
i
)
x_{1:i}⇒ϕ(x_{1:i}),p(x_{i+1}∣x_{1:i})
x1:i⇒ϕ(x1:i),p(xi+1∣x1:i) 。我们以自动补全任务来说,输入与输出的形式为,
[
[
C
L
S
]
,
他们
,
移动
,
而
]
⇒
强大
[[CLS], 他们, 移动, 而]⇒强大
[[CLS],他们,移动,而]⇒强大 。与编码端架构比,其优点为能够自然地生成完成文本,有简单的训练目标(最大似然)。缺点也很明显,对于每个
x
i
xi
xi ,上下文向量表征只能单向地依赖于左侧上下文 (
x
1
:
i
−
1
x_{1:i−1}
x1:i−1) 。
编码-解码端架构就是最初的Transformer模型,其他的还有如BART、T5等模型。这些模型在某种程度上结合了两者的优点:它们可以使用双向上下文向量表征来处理输入 x 1 : L x_{1:L} x1:L ,并且可以生成输出 y 1 : L y_{1:L} y1:L 。可以公式化为:
x 1 : L ⇒ ϕ ( x 1 : L ) , p ( y 1 : L ∣ ϕ ( x 1 : L ) ) 。 x1:L⇒ϕ(x1:L),p(y1:L∣ϕ(x1:L))。 x1:L⇒ϕ(x1:L),p(y1:L∣ϕ(x1:L))。
以表格到文本生成任务为例,其输入和输出的可以表示为:
[ 名称 : , 植物 , ∣ , 类型 : , 花卉 , 商店 ] ⇒ [ 花卉 , 是 , 一 , 个 , 商店 ] 。 [名称:, 植物, |, 类型:, 花卉, 商店]⇒[花卉, 是, 一, 个, 商店]。 [名称:,植物,∣,类型:,花卉,商店]⇒[花卉,是,一,个,商店]。
该模型的具有编码端,解码端两个架构的共同的优点,对于每个 x i x_{i} xi ,上下文向量表征可以双向地依赖于左侧上下文 x 1 : i − 1 x_{1:i−1} x1:i−1 ) 和右侧上下文 ( x i + 1 : L x_{i+1:L} xi+1:L ),可以自由的生成文本数据。缺点就说需要更多的特定训练目标。
首先需要介绍将词元序列转换为向量序列的函数。EmbedToken()函数将词元序列中的每个词元转化为每个词元对应的向量(上下文无关):
E m b e d T o k e n ( x 1 : L : V L ) → R d × L EmbedToken(x_{1:L}:V^{L})→ℝ^{d×L} EmbedToken(x1:L:VL)→Rd×L :
第一个真正的序列模型是递归神经网络(RNN),它是一类模型,包括简单的RNN、LSTM和GRU。基本形式的RNN通过递归地计算一系列隐藏状态来进行计算。
S e q u e n c e R N N ( x : R d × L ) → R d × L SequenceRNN(x:ℝ^{d×L})→ℝ^{d×L} SequenceRNN(x:Rd×L)→Rd×L :
实际完成工作的模块是RNN,类似于有限状态机,它接收当前状态h、新观测值x,并返回更新后的状态:
R N N ( h : R d , x : R d ) → R d RNN(h:ℝ^d,x:ℝ^d)→ℝ^d RNN(h:Rd,x:Rd)→Rd :
注意:
Transformer(Vaswani等人,2017),这是真正推动大型语言模型发展的序列模型。正如之前所提到的,Transformer模型将其分解为Decoder-Only(GPT-2,GPT-3)、Encoder-Only(BERT,RoBERTa)和Encoder-Decoder(BART,T5)模型的构建模块。
关于Transformer的学习资源有很多:
强烈建议您阅读这些参考资料。该课程主要依据代码函数和接口进行讲解。
Transformer的关键是注意机制,这个机制早在机器翻译中就被开发出来了(Bahdananu等人,2017)。可以将注意力视为一个“软”查找表,其中有一个查询 y y y,我们希望将其与序列 x 1 : L = [ x 1 , … , x L ] x_{1:L}=[x_1,…,x_L] x1:L=[x1,…,xL] 的每个元素进行匹配。我们可以通过线性变换将每个 x i x_{i} xi 视为表示键值对:
( W k e y x i ) : ( W v a l u e x i ) (W_{key}x_{i}):(W_{value}x_{i}) (Wkeyxi):(Wvaluexi)
并通过另一个线性变换形成查询:
W q u e r y y W_{query}y Wqueryy
可以将键和查询进行比较,得到一个分数:
s c o r e i = x i ⊤ W k e y ⊤ W q u e r y y score_{i}=x^{⊤}_{i}W^{⊤}_{key}W_{query}y scorei=xi⊤Wkey⊤Wqueryy
这些分数可以进行指数化和归一化,形成关于词元位置 1 , … , L {1,…,L} 1,…,L的概率分布:
[ α 1 , … , α L ] = s o f t m a x ( [ s c o r e 1 , … , s c o r e L ] ) [α_{1},…,α_{L}]=softmax([score_{1},…,score_{L}]) [α1,…,αL]=softmax([score1,…,scoreL])
然后最终的输出是基于值的加权组合:
∑
i
=
1
L
α
i
(
W
v
a
l
u
e
x
i
)
\sum_{i=1}^L \alpha_i\left(W_{value} x_i\right)
i=1∑Lαi(Wvaluexi)
tips: 这点可以看李沐的动手学深度学习讲的很好
残差连接:计算机视觉中的一个技巧是残差连接(ResNet)。我们不仅应用某个函数f:
f
(
x
1
:
L
)
,
f(x1:L),
f(x1:L),
而是添加一个残差(跳跃)连接,以便如果
f
f
f的梯度消失,梯度仍然可以通过
x
1
:
L
x_{1:L}
x1:L 进行计算:
x 1 : L + f ( x 1 : L ) 。 x_{1:L}+f(x_{1:L})。 x1:L+f(x1:L)。
层归一化:另一个技巧是层归一化,它接收一个向量并确保其元素不会太大:
L a y e r N o r m ( x 1 : L : R d × L ) → R d × L LayerNorm(x_{1:L}:ℝ^{d×L})→ℝ^{d×L} LayerNorm(x1:L:Rd×L)→Rd×L :
我们首先定义一个适配器函数,该函数接受一个序列模型 f f f并使其“鲁棒”:
A d d N o r m ( f : ( R d × L → R d × L ) , x 1 : L : R d × L ) → R d × L AddNorm(f:(ℝd^{×L}→ℝ^{d×L}),x_{1:L}:ℝ_{d×L})→ℝ^{d×L} AddNorm(f:(Rd×L→Rd×L),x1:L:Rd×L)→Rd×L :
这里就讲了改进transformer的过程
混合专家的想法可以追溯到Jacobs et al. (1991)。
为了介绍基本思想,假设我们正在解决一个预测问题:
x ∈ R d ⇒ y ∈ R d . x \in \mathbb{R}^d \Rightarrow y \in \mathbb{R}^d. x∈Rd⇒y∈Rd.
让我们从学习前馈(ReLU)神经网络开始:
h θ ( x ) = W 2 max ( W 1 x , 0 ) , h_\theta(x) = W_2 \max(W_1 x, 0), hθ(x)=W2max(W1x,0),
其中参数为 θ = ( W 1 , W 2 ) \theta = (W_1, W_2) θ=(W1,W2) 。
但专家的混合方法是:
定义 E E E 个专家。
每个专家 e = 1 , … , E e = 1, \dots, E e=1,…,E 都具有自己的嵌入 w e ∈ R d w_e \in \mathbb{R}^d we∈Rd 。
将门控函数定义为 E E E 个专家上的概率分布:
g e ( x ) = exp ( w e ⋅ x ) ∑ e ′ = 1 E exp ( w e ′ ⋅ x ) . g_e(x) = \frac{\exp(w_e \cdot x)}{\sum_{e' = 1}^E \exp(w_{e'} \cdot x)}. ge(x)=∑e′=1Eexp(we′⋅x)exp(we⋅x).
每个专家 e = 1 , … , E e = 1, \dots, E e=1,…,E 都具有自己的参数 θ ( e ) = ( W 1 ( e ) , W 2 ( e ) ) \theta^{(e)} = (W_1^{(e)}, W_2^{(e)}) θ(e)=(W1(e),W2(e)) 。
根据专家特定参数定义每个专家函数:
h θ e ( x ) = W 2 ( e ) max ( W 1 ( e ) x , 0 ) . h_{\theta_e}(x) = W_2^{(e)} \max(W_1^{(e)} x, 0). hθe(x)=W2(e)max(W1(e)x,0).
f ( x ) = ∑ e = 1 E g e ( x ) ⏟ gating h θ e ( x ) ⏟ expert . f(x) = \sum_{e=1}^E \underbrace{g_e(x)}_\text{gating} \underbrace{h_{\theta_e}(x)}_\text{expert}. f(x)=e=1∑Egating ge(x)expert hθe(x).
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。