MIT深度学习课程第八讲:Tunable Self-Attention、BERT 与 Transformer 应用
本节课继续讲 transformer,是上一讲之后的第二轮深入。
老师说明,本节前半部分会更深入地穿过 transformer stack,其中一段可能是整门课中最难的内容之一。
本节主线包括:
- 复习
transformer encoder的三个目标。 - 回到上一节
ATIS slot fillingColab,并说明模型效果。 - 用矩阵形式重写
self-attention。 - 引入可学习的
Q、K、V矩阵,让 self-attention 变成 tunable。 - 解释为什么 multi-head attention 在有参数之后才真正有意义。
- 补全真实 transformer encoder 中的
residual connection与layer normalization。 - 说明 transformer encoder 的几类常见 NLP 用法:classification、labeling、sequence generation。
- 引入
CLS token做 sequence classification。 - 用
self-supervised learning解释BERT的预训练方式。 - 演示 Hugging Face
pipeline的 out-of-the-box NLP 能力。 - 说明
Vision Transformer、Tab Transformer与多模态 Transformer 的基本思想。
一、上一讲回顾:为什么需要 Transformer
老师先回顾上一节课的核心目标。
我们需要一种架构,能够同时满足三个条件:
- 输出长度与输入长度相同。
- 能考虑输入中的上下文。
- 能考虑输入中的顺序。
transformer architecture 可以满足这三个要求。
对于短语:
the train left the station每个词首先有一个:
standalone embedding也就是上一讲中说的:
uncontextual embedding这些 embeddings 可以是:
- pre-trained embeddings
- random embeddings
上一讲的 Colab 中,课程直接从 random weights 开始学习 embeddings。
二、Positional Input Embeddings 的流程
每个词进入 transformer 前,会先处理位置信息。
流程是:
- 取词本身的 standalone embedding。
- 取该词所在位置的 positional embedding。
- 两者逐元素相加。
- 得到该词的 positional input embedding。
也就是:
word embedding + positional embedding = positional input embedding这些 positional input embeddings 会进入 transformer encoder stack。
输出则是:
contextual embeddings也就是说,输入是未上下文化或位置增强后的 embeddings,输出是结合上下文后的 embeddings。
三、上一节 Colab:Word-to-Slot Classification
上一节把 transformer stack 用在:
word-to-slot classification每条自然语言查询进入模型后:
- 先计算 positional embeddings。
- 再通过 transformer stack。
- 得到 contextual embeddings。
- 每个输出 embedding 都要被分类到
125种可能类别之一。 - 对每个 embedding 接一个
ReLU与softmax。
这是上一节 ATIS slot filling 的基本模型。
四、课堂问答:增加 Attention Heads 还是增加 Blocks
有学生问,如何决定是在一个 block 中增加更多 self-attention heads,还是增加更多 transformer layers。
老师回答:
GPT-3有96个 transformer blocks。- 增加 attention heads,可以让模型在同一抽象层级捕捉更多 patterns。
- 增加 transformer blocks,则像 CNN 中更深层卷积一样,可以逐步构建更高层级的 abstraction。
老师用视觉模型类比:
- 低层可能捕捉 lines。
- 进一步组合成 edges。
- 再进一步组合出 nose、eyes、face 等更高层结构。
两种扩展方式都有效,但前提是有足够数据训练。
如果模型很大而数据不足,就会遇到:
overfitting因此,模型容量与数据规模之间始终存在 tradeoff。
五、补完上一节 Colab:模型训练结果
上一节没有实际运行 Colab,本节老师回到 Colab 说明结果。
模型使用的训练设置包括:
- 训练
10epochs。 - batch size 设为
64。 - 在 test set 上评估。
结果是:
overall accuracy ≈ 99%这个结果只用了:
one transformer block老师提醒,slot filling 中有一个评价陷阱。
由于大多数词都属于:
O也就是 other 类别,一个 naive model 可以把所有输入词都预测成 O,也会得到不差的整体准确率。
这类似于分类问题中某个 majority class 占据绝大多数样本。
因此,更重要的是看 non-O slots 的准确率。
本节模型在真正关心的 non-O slots 上达到:
accuracy ≈ 93%老师还提到,Colab 中可以尝试一些有趣或故意刁难模型的 query,例如:
cheapest flight to fly from MIT to Mars六、本节要补充的三个复杂点
老师说明,本节会在上一讲的 encoder 基础上加入三个新复杂点。
加入这三个部分后,就基本得到 2017 年原始 transformer 论文中的真实 transformer。
三个复杂点是:
- tunable self-attention
- residual connection
- layer normalization
其中第一个最难,因此老师从 self-attention 的矩阵化开始慢慢展开。
七、复习 Self-Attention 的基本逻辑
上一讲中,针对某个词,例如:
station我们希望把它的 positional embedding 转换成 contextual embedding。
做法是:
- 计算该词与句子中其他每个词的 dot product。
- dot products 可能为正也可能为负。
- 用
softmax把这些分数变成非负且总和为1的权重。 - 用这些权重对原始 embeddings 做 weighted average。
- 得到目标词的 contextual embedding。
形式上,W6 的 contextual embedding 可以写成:
W6_hat = S1 * W1 + S2 * W2 + ... + S6 * W6这里的 S1 到 S6 是通过 dot product 与 softmax 得到的 attention weights。
虽然上一讲只讲了一个词,但同样操作要对每个词都做一遍:
W5_hat, W4_hat, W3_hat, ...因此,self-attention 内部有大量相似计算:
- dot products
- softmax
- weighted average
自然问题是:
能否把这些计算组织得非常高效?答案是可以。
老师强调,正是因为可以把这些操作打包成高效的矩阵运算,并放到 GPU 上运行,才有了 transformer 的大规模成功。
八、矩阵化 Self-Attention:用 I love HODL 举例
为了说明矩阵化,老师换了一个更短的句子:
I love HODL假设三个词的 embeddings 是:
W1, W2, W3这里假设它们已经完成 positional encoding,进入 self-attention layer 的就是这些位置增强后的 embeddings。
把三个 embeddings 放在一起,可以看成一个矩阵:
X也就是:
X = [W1, W2, W3]老师接着让 X 分成三份拷贝。
前两份用于计算所有 token pair 之间的 dot products。
九、用 X X^T 一次性计算所有 Dot Products
self-attention 需要计算每一对词之间的相关性。
对于:
I love HODL需要计算:
W1与W1W1与W2W1与W3W2与W1- ...
W3与W3
也就是所有 pairwise dot products。
矩阵形式非常简洁:
X * X^T其中:
X是输入 embeddings 组成的矩阵。X^T是转置后的矩阵。
一次 matrix multiplication 就可以得到一个网格,里面包含所有词对的 dot product。
如果句子有 3 个词,就会得到 3 x 3 = 9 个 dot products。
老师也提到,如果有 1,000,000 个词,理论上会有数量级约为:
1 trillion的 pairwise computations。
这里存在一些重复,例如:
W1 dot W3 = W3 dot W1但核心点是:矩阵乘法可以一次性组织这些运算。
十、对每一行做 Softmax
X X^T 得到的每个数字都是 dot product,可能为正,也可能为负。
为了得到真正的 attention weights,需要对每一行做:
softmax也就是对每个数取指数,再除以该行所有指数值之和。
结果是一个权重表。
例如第一行可能表示:
第一个词:0.1 * W1 + 0.7 * W2 + 0.2 * W3这些权重加起来为 1。
十一、再乘第三份 X 得到 Contextual Embeddings
前两份 X 用于计算:
softmax(X X^T)第三份 X 用于最终 weighted average。
整体计算可以写成:
softmax(X X^T) X输出就是所有词的 contextual embeddings。
老师强调,整个 self-attention 操作可以写成一个非常紧凑的矩阵公式:
X -> X^T -> X X^T -> softmax(X X^T) -> softmax(X X^T) X这就是 transformer 可以在 GPU 上高效运行的关键。
十二、问题:普通 Self-Attention 里没有可学习参数
上一讲的简化版 self-attention 存在一个问题:
self-attention layer 里面没有参数。也就是说:
- 没有 weights。
- 没有 biases。
- 没有 coefficients。
如果只是用 X、X^T、dot product、softmax 和 weighted average,那么模型在 self-attention 内部没有东西可以学习。
因此需要引入:
tunable self-attention layer也就是让 self-attention 里面出现可学习参数。
十三、Tunable Self-Attention:引入 K、Q、V
为了让 self-attention 可调,老师引入三个可学习矩阵:
AK
AQ
AV输入仍然是:
X但不再把三个 X 拷贝原样送入计算。
而是先做三次矩阵变换:
K = X * AK
Q = X * AQ
V = X * AV其中:
AK是 key matrix。AQ是 query matrix。AV是 value matrix。- 三个矩阵中的数值会通过
backprop学习。
老师提到,K/Q/V 的命名有 information retrieval 的历史来源,但他在课堂中不采用这种解释,而是把它们理解成让 self-attention 可调的三组变换。
十四、为什么要先乘这些矩阵
X 乘以这些矩阵后,会被转换成新的表示。
核心目的不是人为规定 K、Q、V 一定代表什么,而是给模型更强的:
expressive power或:
modeling capacity如果某个变换确实对任务有帮助,训练会学出有用的矩阵。
如果变换没有帮助,矩阵也可以学成近似:
identity matrix这样输出接近原始输入。
也就是说,引入矩阵至少不会剥夺模型表达原始表示的能力,但给了它学习更有用中间表示的机会。
十五、真实 Self-Attention 公式
引入 K、Q、V 后,pairwise dot products 不再是:
X X^T而是:
Q K^T然后对每一行做 softmax:
softmax(Q K^T)最后再乘以:
V于是 self-attention 的核心形式变成:
softmax(Q K^T) V老师把它概括为:
X输入。- 三条路径分别变成
K、Q、V。 - 用
Q K^T计算所有 pairwise dot products。 - 用
softmax得到 attention weights。 - 乘以
V得到 contextual embeddings。
这就是 tunable self-attention 的核心。
十六、课堂问答:AK、AQ、AV 是否相关
有学生问:
AK, AQ, AV 之间是否有关系?老师回答:
Independent.它们是相互独立的矩阵。
十七、课堂问答:矩阵大小与参数数量
有学生问,如果 embedding dimension 是 50,这些矩阵有多少参数。
老师回答,如果输入 embedding 长度是 50,并且希望输出仍然是 50,那么矩阵大小是:
50 x 50参数数量是:
2,500也就是说,这些矩阵的大小主要由 embedding dimension 决定。
十八、课堂问答:三个矩阵到底在学习什么
有学生问:
这三个矩阵分别试图学习什么?老师回答:
We don't know.模型只是被赋予了把输入转换成潜在有用表示的能力。
这些变换是否有用、具体学到什么,要通过训练和任务表现来判断。
实际效果上,这种设计显著有用,因此 transformer 才采用它。
老师总结了深度学习中的一个常见做法:
想提升模型容量时,可以在中间向量上加入 matrix multiplication。也就是把某个中间 vector 通过矩阵变成另一个 vector。
如果再接一个小的 ReLU,通常还能进一步增加表达能力。
十九、课堂问答:为什么最后用 V 而不是原始 X
有学生问,简化版 self-attention 最后是乘原始 X,为什么现在最后乘的是 V。
老师回答,原先的三个 copy 被当作相同输入。
现在既然目标是让每条路径都更有表达能力,就没有必要只改前两条路径。
三条路径都可以通过不同矩阵转换:
KQV
因此最后用于 weighted average 的也不再是原始 X,而是经过 AV 转换后的 V。
二十、课堂问答:Tunable 不是 Fine-Tuning
有学生把这个过程称为 fine-tuning。
老师特别纠正:
这里不是 fine-tuning,而是让 self-attention tunable。意思是模型内部增加了更多可学习 weights。
当整个模型训练时,这些矩阵会和其他权重一样,通过:
backpropagation被更新。
增加参数永远带来 overfitting 风险,因此需要关注 validation set 等常规训练诊断。
但这里增加参数的目的非常明确:
给 self-attention layer 增加学习能力。简化版 self-attention 只能做 dot products,而 tunable self-attention 可以从数据中学到更适合任务的变换。
二十一、原始论文公式:Attention Is All You Need
老师展示了原始 transformer 论文:
Attention Is All You Need其中著名公式是:
Attention(Q, K, V) = softmax(Q K^T / sqrt(d_k)) V课堂推导中暂时忽略了:
sqrt(d_k)老师解释,加入这个缩放项是为了避免 dot product 数值过大。
如果 softmax 的输入中某些数特别大,其他数字会被压到接近 0,影响 gradient flow。
因此除以 sqrt(d_k) 可以让数值更稳定。
这是一个技术细节,但对训练很重要。
除了这个缩放项之外,课堂推导得到的就是原始 transformer 公式的主体:
softmax(Q K^T) V老师建议学生之后阅读论文,并对照课堂中 iPad 的矩阵推导和幻灯片中非矩阵化解释,两种理解方式相互补充。
二十二、Tunable Self-Attention 让 Multi-Head 真正有效
上一讲提到 multi-head attention,但如果 self-attention 内部没有参数,那么多个 heads 的输入相同、计算相同、输出也会相同。
这样多个 heads 就没有意义。
引入 tunable self-attention 后,每个 attention head 都有自己的三组矩阵:
AK, AQ, AV因此不同 heads 会学出不同参数,输出也会不同。
这就是 multi-head attention 真正有用的原因。
二十三、课堂问答:A 只是记号
有学生再次问 AK、AQ、AV 之间是否有实际关系,还是只是 notation。
老师回答,A 只是记号。
因为结果矩阵要叫:
Q, K, V所以老师用 A 加下标表示前面的可学习变换矩阵。
二十四、课堂问答:矩阵是否总是方阵
有学生问这些矩阵是否是 square matrices。
老师回答,很多实现会保留维度。
例如输入 embedding 长度是 10,输出也保持 10,就使用:
10 x 10的矩阵。
但 V 的维度可能会有更技术性的处理。
例如输入长度是 100,并且有 5 个 attention heads:
K可能做100 -> 100Q可能做100 -> 100V可能做100 -> 20
因为多个 heads 的 V 输出最终会 concatenate 回整体的 100 维。
老师说明,这里可以进一步展开,但课堂中只保留主直觉:
这些矩阵通常用于把输入 embedding 转换成某个维度的表示。二十五、矩阵初始化与每个 Head 的参数
有学生确认:
AQ, AK, AV 的数值是否一开始是随机的,然后训练出来?老师回答:
Exactly.这些矩阵中的 values 是通过 optimization 学到的 weights,优化方法可以是:
SGD或类似的 gradient-based optimizer。
每个 attention head 都有自己的一组三个矩阵。
如果有 10 个 attention heads,则会学习:
10 x 3 = 30 matrices二十六、课堂问答:不同 Attention Heads 学什么 Pattern
有学生问,不同 attention heads 是否对应不同类别的 attention。
老师回答,可以这样理解。
一个句子中可能存在很多种 pattern:
- word meaning,例如
bank、station、train等语义关系。 - grammar。
- tense。
- tone。
- 其他语言结构。
事先并不知道需要多少 pattern。
这类似于 CNN 中不知道需要多少 filters 来检测:
- vertical line
- horizontal line
- semicircle
- quarter circle
因此模型设计中给足 capacity,让它通过训练学习自己需要的 patterns。
二十七、第二个复杂点:Residual Connection
补全 tunable self-attention 后,老师引入第二个复杂点:
residual connectionself-attention 输入是:
W1, W2, ..., W6经过处理后会得到一些中间输出向量。
因为 transformer 特意保持输入和输出的向量长度一致,所以可以把原始输入和变换后的输出逐元素相加。
这就是:
residual connection二十八、Residual Connection 的直觉
老师用“保险策略”解释 residual connection。
如果把输入送入一个 neural network,它会被转换成新的表示。
但后续层只能看到转换后的表示,看不到原始输入。
如果转换结果并不好,后续网络就失去了原始信息。
因此可以把:
- transformed representation
- original input
一起传下去。
一种方式是 concatenate,但这样会让向量越来越长,不符合 transformer 需要保持 same size 的设计。
更简单的方式是:
element-wise addition例如:
- 原始
W1是100维。 - 变换后的
W1也是100维。 - 两者逐元素相加后仍然是
100维。
这样既保留了原始输入的信息,又不改变向量长度。
二十九、Residual Connection 与 Gradient Flow
residual connection 不只是 transformer 的技巧。
它还会显著改善:
gradient flow during backpropagation老师提到,计算机视觉中学过的:
ResNet全称就是:
Residual Net这是较早系统化使用 residual connection 的网络。
因此,residual connection 广泛用于很多 deep neural architectures,不是 transformer 独有。
三十、第三个复杂点:Layer Normalization
第三个复杂点是:
layer normalization做完 residual connection 后,还会对向量做 normalization,然后再继续向后流动。
老师回顾整学期一直强调的原则:
进入 neural network 的数值最好保持在狭窄、稳定的范围内。例子包括:
- 图像像素除以
255,把 pixel values 放到0到1。 - 连续变量用 mean 和 standard deviation 做 standardization。
对于连续变量,常见做法是:
(x - mean) / standard deviation这样数值大致落在:
-1 to +1神经网络训练中,如果数值过大,backprop 会变得困难。
三十一、课堂问答:Vanishing / Exploding Gradient
有学生问,layer normalization 是否用于避免 vanishing gradient。
老师回答,相关问题包括两类:
exploding gradientvanishing gradient
两者都不好。
layer normalization、batch normalization 等技术都用于让中间数值保持在较小范围,减少后续 gradient 问题。
三十二、Layer Normalization 的具体做法
对于 transformer 中的一组 embeddings,layer normalization 会计算每个 embedding 自身的:
- mean
- standard deviation
如果有 6 个 embeddings,就会有:
6个 means6个 standard deviations
计算维度是在每个 embedding 的 row 内部。
然后对每个 embedding 做:
subtract mean
divide by standard deviation也就是 standardize。
随后还会引入两个额外参数,用来重新缩放和移动数值。
老师没有展开这两个参数的维度细节,因为实现上会稍微复杂。
结果是输出一组 well-behaved、范围较小的数值。
三十三、完整 Transformer Encoder Block
把本节三个复杂点放在一起,得到更真实的 transformer encoder block:
- 输入 embeddings。
- 进入
multi-head attention。 - 每个 attention head 内部都有自己的
AK、AQ、AV。 - 做 residual connection。
- 做
layer normalization。 - 进入 feedforward layer。
- 对 feedforward layer 的输出再做 residual connection。
- 再做
layer normalization。 - 输出 contextual embeddings。
这对应原始 transformer 图中的:
add and norm其中:
add表示 residual connection。norm表示 layer normalization。
三十四、课堂问答:模型会学到 Bias / Toxic Patterns 吗
有学生问,multi-head attention 或整个模型是否可以捕捉到 bias、hate speech 等特征。
老师回答,模型不是在价值意义上“理解”或“判断”这些东西。
它只是捕捉训练数据中的 patterns。
如果训练数据中包含:
- biased content
- toxic content
- dangerous content
模型也会捕捉这些模式。
模型本身没有价值判断,不知道什么是好、什么是坏。
如何让模型 unlearn 或 mitigate 这些影响,是一个很大的课题,老师表示这本身可以是一整门课。
三十五、Transformer Block 可以堆叠
老师再次强调,完整 transformer block 输入输出维度一致,因此可以垂直堆叠。
也就是:
block -> block -> block -> ...GPT-3 大约有:
96个 transformer blocks 堆叠在一起。
三十六、训练时哪些参数会被优化
老师明确说明,在这个复杂流程中,以下参数都会通过 backpropagation 优化:
- standalone embeddings。
- positional embeddings。
- 每个 attention head 内的
AK、AQ、AV。 layer norm中的参数。- feedforward layer 中的 weights。
- 后续
ReLU层中的 weights。 - 最终
softmax层中的 weights。
整体上,它仍然只是:
一个包含大量参数的数学模型。训练过程仍然使用:
gradient descent或:
stochastic gradient descent三十七、课堂问答:参数数量是否依赖输入长度
有学生问,训练时是否要为 max number of inputs 中每个位置、每个可能 matrix cell 都计算权重。
老师回答,核心 weights 本身不依赖句子长度。
原因是每个 sentence 中的每个 embedding 都会乘以同一个矩阵,例如 AK。
AK 只需要知道:
embedding length不需要知道:
句子有多少词因此,transformer 的参数数量与句子 token 数不直接绑定。
它主要依赖:
- vocabulary size,因为 vocabulary 决定需要多少 token embeddings。
- embedding dimension。
- positional embedding 的最大长度假设。
如果要支持 1,000 token 长度,就需要相应长度的 positional embedding matrix。
老师举例,Google Gemini 1.5 Pro 可以处理大约 1 million token context window,这会让计算非常重,但并不因此改变模型参数数量。
三十八、课堂问答:权重是同时更新还是依次更新
有学生问,训练时哪些 weights 先被优化,是否按顺序进行。
老师回答,概念上它们是同时更新的。
训练时有一个 loss function,计算 loss 对所有参数的 gradient。
如果模型有 1 billion 个参数,gradient 就可以看作一个:
1-billion-long vector更新规则仍然是:
W_new = W_old - alpha * gradient实际计算中,由于 backpropagation 的实现,会从输出端往前传播 gradient。
但完成一次反向传播后,所有相关 weights 都会被更新。
三十九、课堂问答:不同 Heads 为什么会学得不同
有学生问,如果两个 attention heads 输入相同、输出形状相同,为什么它们不会学成一样。
老师回答:
Because the initialization is different.每个 head 中的 AK、AQ、AV 初始值通常是随机的,而且不同 heads 的初始值不同。
如果所有初始值完全相同,那么它们确实会保持相同变化,没有差异。
但实际训练中,随机初始化让不同 heads 从一开始就不同。
四十、课堂问答:Transformer 输入的是句子还是 Embeddings
有学生问,transformer 的输入是 sentence,还是每个词的 embedding 数组。
老师回答:
Transformer itself is expecting embeddings in.实际流程是:
- 原始 sentence 进入 tokenizer。
- tokenizer 把文本转换成 tokens。
- tokens 通常是 integers。
- embedding layer 把 integers 映射成 embeddings。
- embeddings 进入 transformer。
backpropagation 会一直传回 embedding layer,因此 embeddings 也是 trainable 的。
四十一、课堂问答:Attention Heads 是并行还是堆叠
有学生问,attention heads 是并行的,还是可以堆叠。
老师回答,通常是:
parallelized如果需要更强能力,可以堆叠整个 transformer block。
四十二、Transformer 的常见应用形态
老师总结,常见应用包括三类。
第一类是:
sequence classification例如输入一整句话,判断电影评论是 positive 还是 negative。
第二类是:
sequence labeling也就是每个词都得到一个 multiclass label。
上一节的 slot filling 就是这种任务。
第三类是:
sequence generation输入一个序列,让模型继续生成更多内容。
large language models 就属于这类。
本节已经知道如何做 sequence labeling,因为上一节用 transformer stack 搭了 slot filling Colab。
接下来老师讨论如何做 sequence classification。
四十三、Sequence Classification:从多个 Embeddings 到一个向量
当一个句子经过 encoder 后,会输出一组 contextual embeddings。
这里的 encoder 可以只有 1 个 transformer block,也可以有很多个 blocks;老师强调,具体堆叠多少层不影响这里的分类思路。
如果要做二分类,例如:
positive / negative更方便的做法是把整句话总结成一个 vector。
有了一个 vector 后,就可以接:
ReLUsigmoid
完成 binary classification。
问题是:
如何把多个 contextual embeddings 压缩成一个 vector?四十四、简单平均的缺点
一种直接方法是:
average pooling也就是把所有 token embeddings 逐元素平均。
有学生指出,这可能丢失 word order。
老师回答,position information 已经通过 positional encoding 进入表示中,所以不是简单地完全丢失顺序。
但平均会把丰富信息压缩成一个向量,因此会丢失 richness。
另一个学生指出,数值大的 embeddings 可能支配平均结果。
老师说这可能发生,但前面的 layer normalization 设计会尽量让数值保持在稳定范围。
真正核心问题仍然是:
averaging is going to lose some richness.四十五、CLS Token
更好的方法是加入一个人工 token:
CLS也称:
class token做法是:
- 对每个句子,在训练时加入一个人工的
CLStoken。 - 这个 token 和其他 tokens 一起训练。
- 训练结束后,它也有自己的 contextual embedding。
- 由于 self-attention 让它能关注句子中的所有词,它的 contextual embedding 可以捕捉整句话的信息。
- 做 classification 时,只取
CLS的 contextual embedding。 - 接
ReLU和sigmoid或softmax完成分类。
这比事后平均所有 embeddings 更优雅,因为“如何总结句子”这件事被交给了数据和 backprop 学习。
老师总结了一个 meta principle:
如果你发现自己在做 ad hoc 决策,例如手动平均,应当思考能否让模型从数据中学习更合适的方式。四十六、课堂问答:为什么 CLS 放在开头
有学生问,为什么把 CLS token 放在句子开头,而不是末尾。
老师回答,放在末尾理论上也可以。
但实际句子长度不同:
- 有短句。
- 有长句。
- 短句会 padding。
transformer 内部通常会忽略 padded tokens。
如果把 CLS 放在末尾,就需要额外 bookkeeping,确定哪些位置是 padding、哪个位置才是真正的最后一个 token。
把 CLS 放在开头更简单,因为位置固定。
四十七、课堂问答:Sequence Classification 的应用
有学生问,sequence classification 的实际应用是否包括 sentiment analysis。
老师回答,是的。
常见例子包括:
- sentiment analysis:判断 positive / negative。
- call center email routing:读取客户邮件并判断应该转给哪个部门。
这类问题本质上是:
输入是一段 natural language text,输出是一个 label。四十八、为什么需要 Self-Supervised Learning
如果任务输入是 natural language text,我们不必只依赖当前任务的小规模 labeled data。
老师用 call center email routing 举例:
假设要把英文邮件分到 10 个部门。
系统不应该只为了这个 call center 任务才学习英语。
更好的方式是先从大量英文文本中学习语言的一般知识,再把这种知识用于具体任务。
这引出:
self-supervised learning四十九、回顾 Transfer Learning 与 ResNet
老师回顾第 4 讲的 transfer learning 例子。
当时使用:
ResNet流程是:
- 使用已经训练好的 ResNet。
- 去掉最后的 classification head,使其变成 headless ResNet。
- 接上一个小 hidden layer 和 output layer。
- 用少量 handbags / shoes 图片训练新头部。
当时只用约 100 个样本就能构建不错的 handbags / shoes classifier。
原因是 neural networks 在训练过程中会自动学习:
representations五十、Representation Learning
老师从更一般角度解释 deep network。
一个输入经过很多 layers,每一层都在把 raw input 转换成某种新的表示。
这些中间表示称为:
representations训练 deep network 时,实际上学习了两类东西:
- 如何用很多不同方式表示输入。
- 最后的一个小模型,例如 linear regression 或 logistic regression。
最终层通常是:
- linear layer
- sigmoid
- softmax
因此,从结构上看,deep network 的优势很大程度来自前面各层学出的好 representations。
这些 representations 相当于自动 feature engineering。
五十一、Encoders 与可迁移知识
从这个角度看,每一层都像一个 encoder。
- 第一层编码输入。
- 前两层编码另一种表示。
- 前三层编码更高层表示。
深层网络包含很多 encoders。
关键问题是:
这些 representations 捕捉的是任务特定知识,还是输入数据的一般知识?答案是:它们通常捕捉了大量关于输入数据的一般知识。
因此可以被迁移到其他任务。
视觉例子中,一个 object classifier 可能学到:
- little patterns
- circles
- edges
- nose-like shapes
- face-like shapes
这些特征不仅可用于原任务,也能帮助其他任务。
例如 face detection network 可以被复用于:
emotion detection五十二、Pretrained Encoder 的一般用法
如果能获得一个对输入数据产生良好 representations 的 encoder,就可以:
- 用 encoder 把 raw input 转换成 useful representations。
- 把这些 representations 作为输入。
- 训练一个 regression / classification head。
这正是 handbags / shoes 例子中使用 headless ResNet 的方式。
一般 playbook 是:
- 找到一个基于相似 inputs、但可能是不同 outputs 训练好的 deep neural network。
- 截取其靠近输出层的 representation,例如 penultimate representation。
- Chop off the head。
- Attach your own output head。
- 可以只训练最后几层,也可以 fine-tune 整个模型。
由于不需要用当前任务少量数据从零学习 representations,因此 labeled data 需求显著降低。
老师指出,从某种意义上看,你的训练数据变成了:
pretrained model 用过的大量数据 + 你自己的少量 labeled examples课堂中这里也用约 200 个 examples 来说明:当前任务虽然只有少量标注数据,但模型已经借用了预训练阶段的大量数据。
五十三、文本预训练的核心问题:Label 从哪里来
对图像来说,ResNet 曾在 ImageNet 上训练。
ImageNet 有大约:
1 million images并且每张图片有:
1,000 categories因此 labels 很清楚。
如果要为 text data 构建通用模型,文本数据并不难获得:
- 可以 scrape the internet。
- 可以下载 Wikipedia。
真正的问题是:
对于一段文本,label 应该是什么?如果能回答这个问题,就可以在大量文本上预训练模型。
五十四、Self-Supervised Learning 与 Masking
一个优雅方法是:
self-supervised learning核心思想是:
从输入本身构造监督信号。常见做法之一是:
masking做法是:
- 取一段 input。
- 随机移除或遮住其中一小部分。
- 遮住后的输入作为新 input。
- 被移除的部分作为 fake label。
- 训练模型根据上下文填空。
老师用 donut 类比:
- 打孔后的 donut 是新 input。
- 被打掉的小圆块,即 munchkin,是 label。
这个类比说明,label 是从原始输入中自动构造出来的。
五十五、Masked Language Modeling 示例
老师举例:
The Sloan School's mission ...可以随机把一些词换成:
mask模型看到带缺口的句子后,需要预测被遮掉的实际词。
在填空过程中,模型必须学习大量语言和世界知识。
例如:
The capital of France is ___.如果模型能填出:
Paris说明它已经学到相关知识。
因此,学习 fill in the blanks 的过程,会迫使模型学到很好的 input representations。
五十六、Masked Self-Supervised Learning 是 Sequence Labeling
老师把 masked self-supervised learning 重新表述为:
sequence labeling problem流程是:
- 输入一个带
mask的 token sequence。 - 通过 transformer 得到每个位置的 embeddings。
- 对未被 mask 的位置,通常不关心输出。
- 对被 mask 的位置,要求模型预测原本的词。
- 用这些预测与 right answers 构造 loss。
- 用 backprop 训练模型。
这种方法可以在大量 unlabeled text 上训练,因为 labels 来自输入本身。
五十七、BERT
如果用这种方式在大规模英文文本上预训练 transformer encoder,就得到:
BERTBERT 是非常著名的 transformer 模型。
老师指出,Google 在 2019 年使用 BERT 升级搜索。
上一讲中的 Brazil visa 搜索例子,底层就使用了 BERT。
五十八、BERT 论文中的模型结构
老师展示 BERT 论文,并指出现在学生已经可以读懂其中结构描述。
BERT 的模型结构是:
multi-layer bidirectional transformer encoder论文用三个符号描述模型规模:
L:number of layers / transformer blocks。H:hidden size。A:number of attention heads。
老师提到课堂示例中的参数包括:
H = 768- feedforward hidden layer 约为 hidden size 的数倍,课堂中提到
4,096 - 一个 BERT 版本有
12个 transformer blocks。 - 另一个 BERT 版本有
24个 transformer blocks。
这里的重点不是记住具体数值,而是把论文参数与课堂中讲过的 transformer block、hidden size、attention heads 对应起来。
五十九、Bidirectional 与 Causal Transformer
老师解释:
bidirectional表示句子中的词可以关注句子里的所有其他词。
也就是:
all words are seen下一节会看到另一种:
causal transformer在 causal transformer 中,一个 token 只能关注它之前的词,不能看之后的词。
这与 large language models 的生成机制相关。
六十、BERT 与 CLS
前面讲过,用 CLS token 可以做 sequence classification。
BERT 在预训练时已经使用了 CLS 机制,因此使用 BERT 做 sequence classification 时,CLS token 是现成可用的。
这意味着:
不需要额外对 BERT 做结构手术。BERT 可以作为以下任务的良好起点:
- sequence classification
- sequence labeling
老师还提到,后来出现了许多 BERT 的变体与改进。
如果想使用相关资源,可以了解:
Sentence Transformers library里面包含很多 BERT-related code 和 resources。
六十一、标准 NLP 任务与 Hugging Face
对于 natural language 输入的 classification 或 labeling,可以使用 BERT 这类模型:
- 标注少量 examples。
- 接上合适的 final layers。
- 像 ResNet transfer learning 那样 fine-tune。
但如果问题属于标准 NLP 任务,很多时候甚至不需要自己 fine-tune。
因为已有模型已经针对这些标准任务预训练或微调过,可以 out of the box 使用。
老师提到最大的模型中心之一:
Hugging Face Hub课堂时老师检查到大约有:
520,000 models他还提到,前一年数量可能只有约 50,000,增长非常快。
六十二、Hugging Face 的内容组织
老师切到 Hugging Face Colab,并介绍 Hugging Face 提供的内容:
- pre-trained models
- datasets
- Spaces,用于展示 demo
- documentation
Hugging Face 会按 task 组织模型。
任务类型包括:
- computer vision tasks
- natural language tasks
- text classification
- feature extraction
- 其他大量任务
如果选择 text classification,可以看到大量可用模型。
课堂中老师提到,仅 text classification 就有约:
50,000 models可以按:
- most downloaded
- most liked
等方式选择模型作为 starting point。
六十三、Hugging Face Pipeline
老师说明,如果输入是 natural language text,第一步要问:
这个任务是不是 standard task?如果是标准任务:
do not reinvent the wheel可以直接使用 Hugging Face Transformers library 中的:
pipeline课堂中提到,transformers library 当年已经预装在 Colab 中,因此不需要额外安装。
pipeline 的作用是让用户不用自己训练模型,就能快速使用一类任务的现成模型。
六十四、Pipeline 示例:Sentiment Classification
老师使用一段客户投诉文本作为示例。
大意是:
- 写给 Amazon。
- 客户从 Germany 的商店订购了 Optimus Prime action figure。
- 打开包裹后发现收到的是 Megatron。
- 作为 Decepticons 的终身敌人,客户要求 exchange。
- 署名是 Bumblebee。
使用方式是:
pipeline("text-classification")然后把文本像调用函数一样传给 classifier。
模型输出:
negative概率约为:
90%老师指出,这样 sentiment classification 就被快速解决了。
课堂中老师运行 Colab 时提到拿到了 A100,并说明第一次使用 pipeline 时需要下载相关模型文件。
六十五、更多 Sentiment 示例
老师尝试了几条电影评论:
I hated the movie.结果是 negative。
If I said I loved the movie, I would be lying.结果也是 negative,说明模型能处理一定程度的反讽结构。
The movie left me speechless.模型给出 negative,但老师指出这句话可能两边都说得通,一个更好的分类器可能给出接近 50% 的概率。
Incredible.结果是 positive。
最后,老师加入了一句受 Douglas Adams 启发的句子:
Almost but not quite entirely unlike anything good I've seen.模型被这句话误导,预测为 positive。
这个例子说明,out-of-the-box pipeline 很方便,但并非总是完美。
六十六、Pipeline 示例:Named Entity Recognition
另一个例子是:
named entity extraction也称:
named entity recognition可以给模型一段文本,例如 Reuters news story,让它抽取:
- company names
- people names
- locations
过去这类系统常常需要手工构建复杂规则。
现在可以直接使用:
pipeline("ner")课堂示例中,模型识别出:
Amazon是ORGGermany是LOCBumblebee是 person
这些输出标签来自 NER 任务常见的标准标签体系,例如 ORG 表示 organization,LOC 表示 location。老师提醒,具体任务可能还有一些额外配置参数,可以查对应 documentation。
同时,模型把 Optimus Prime、Decepticons 等 transformer fiction 相关词识别成 miscellaneous 或类似类别,说明它也可能被特定语境影响。
老师说明,抽出的 entities 可以放入 structured data table 或 database,再用于传统 machine learning。
六十七、Pipeline 示例:Question Answering
老师还演示了 question answering。
可以给模型一段 passage,再提出问题。
例如问题是:
What does the customer want?模型回答:
an exchange of Megatron并给出答案在原文中的 start 与 end 位置。
老师指出,这与后续要讲的 causal transformer 和 large language models 相关。
同时,这也提供了一种对 LLM 输出做 QA 的方式:
- 让模型回答问题。
- 要求模型指出答案来自输入中的哪个位置。
- 检查模型引用的原文片段与回答是否匹配。
由于 LLM 可能 hallucinate,这种来源检查可以帮助验证输出。
老师表示,Colab 中还有其他问题示例,但课堂为了回到 PowerPoint,没有继续展开。
六十八、标准任务优先使用现成 Pipeline
老师总结:
如果任务是标准 NLP 任务,应该优先考虑:
Hugging Face pipelines许多任务可以 out of the box 完成,不需要自己从零训练或做大量 heavy lifting。
六十九、Transformer 不只用于文本
老师再次强调,transformers 已经被证明适用于很多非 NLP 领域,例如:
- speech recognition
- computer vision
- structured / tabular data
- multimodal data
关键 insight 是:
Transformer block 本身不需要为不同应用做结构修改。真正需要设计的是:
如何把输入 tokenize / encode 成 embeddings。一旦输入被转换成 embeddings,就可以送入同一个 transformer block。
七十、Vision Transformer
老师介绍:
Vision Transformer这是很有名的架构,也是较早把 transformer 用于 vision problems 的架构之一。
问题是:
图片如何 tokenized?对文本来说:
I love HODL很容易看出 tokens 是:
IloveHODL
但图片没有天然的词。
七十一、把图片切成 Patches
Vision Transformer 的做法是把图片切成小块。
课堂示例中,一张大图被切成:
9个小图块。
每个 patch 本质上由 RGB 数值表示,也就是三张数值表。
可以把这些数值:
- flatten 成一个长向量。
- 通过 dense layer / linear projection。
- 得到较短的 embedding。
老师强调:
linear projection在这里可以理解为:
run it through a dense layerdense layer 的 weights 可以被学习。
因此,每个 image patch 都会变成一个 embedding。
七十二、Vision Transformer 中的位置与分类
图像 patch 的位置也很重要。
如果不考虑位置,把图像块打乱后模型可能无法区分。
因此,Vision Transformer 也使用 positional embeddings。
课堂示例中有 9 个 patches,因此有 9 个位置:
0, 1, 2, 3, 4, 5, 6, 7, 8每个 patch embedding 加上对应的 position embedding。
如果要做分类,还可以加入:
CLS token然后把所有 embeddings 送入 transformer。
最后取 CLS 的 contextual embedding,接 softmax 输出类别,例如:
- bird
- ball
- car
老师强调,这种简单方法实际效果很好。
七十三、课堂问答:Vision Transformer 是否有 Vocabulary
有学生问,文本有固定 vocabulary,图像可能变化极多,是否需要类似 vocabulary。
老师回答,图像这里没有 vocabulary 的概念。
做法是:
- 给任意图片切成固定数量 patches。
- 每个 patch 通过 dense layer 变成 embedding。
- 得到固定数量 embeddings。
- 把这些 embeddings 送入 transformer。
因此,对于任意图片,都可以产生一组 patch embeddings。
七十四、Tab Transformer
老师接着介绍 structured / tabular data。
对于 tabular data,传统方法如:
XGBoost和 gradient boosting 通常效果很好。
老师不认为 transformers 或 deep learning 在 tabular problems 上一定比 XGBoost 有明显优势,因此建议两者都尝试。
但 transformer 也可以用于 tabular data。
较早的代表之一是:
Tab Transformer七十五、Tabular Data 如何变成 Embeddings
tabular data 通常包含:
- categorical features
- continuous features
对于 categorical variables,例如 gender 等,可以为每个类别创建 embedding。
老师指出:
categorical feature is just text因此可以像处理文本一样创建 embeddings。
对于 continuous features,例如 heart disease 示例中的:
- cholesterol
- blood pressure
可以把它们组合成一个普通数值 vector。
七十六、Tab Transformer 的流程
Tab Transformer 的基本流程是:
- 对每个 categorical feature 创建 embedding。
- 把 categorical embeddings 输入 transformer block。
- 得到 contextual representations。
- 将 transformer 输出与 continuous features concatenate。
- 接一个或多个 dense layers。
- 输出预测结果。
老师指出,Tab Transformer 内部使用的 transformer block 与前面讲的一样,不需要结构变化。
后续也有很多改进版本。
关键点是:
categorical variables can be very easily represented as embeddings.七十七、Transformer 的通用接口:Embeddings In, Contextual Embeddings Out
老师总结:
只要输入已经被转换成 embeddings,就可以使用同一个 transformer block。
Transformer stack 的接口可以理解为:
give me embeddings, I give you contextual embeddings它对输入原本来自文本、图像还是表格并不关心。
七十八、多模态 Transformer
由于 transformer 只关心 embeddings,因此它天然适合 multi-modal data。
例如某个任务同时有:
- picture
- text
- tabular data
可以分别处理:
- 文本转换成 language embeddings。
- 图片转换成 image embeddings。
- 表格数据转换成 tabular embeddings。
- 加入
CLS token。 - 送入若干 transformer blocks。
- 取 contextual
CLS token。 - 接
ReLU。 - 再接
sigmoid或softmax。 - 输出 label。
这解释了为什么现代多模态模型可以同时接收图片和问题,并输出答案。
老师举例:
Google Gemini 1.5 ProGPT-4 Vision
这些模型可以输入 images 与 questions,并返回 answers。
原因是每种 modality 都被 cast into embeddings。
一旦 embeddingized,transformer 就可以通过 attention 学习跨模态关系。
例如,它可以判断:
问题中的某个 word 与图片中的某个 patch 高度相关。七十九、本节结束
本节课在这里结束。
老师说明,时间已经到 break,并祝大家本周剩余时间顺利。
下一节会继续进入 causal transformer 与 large language models 相关内容。
八十、本节核心脉络
本节课可以压缩为以下主线:
- 上一节的 transformer encoder 已经能处理
slot filling,整体准确率约99%,non-Oslots 约93%。 - 简化版 self-attention 可以写成
softmax(X X^T) X,并能高效映射到 GPU。 - 真实 transformer 引入
Q、K、V,公式为softmax(Q K^T / sqrt(d_k)) V。 AK、AQ、AV是独立、可学习的矩阵,会通过 backprop 更新。- 每个 attention head 都有自己的三组矩阵,因此 multi-head attention 才能学出不同 patterns。
residual connection保留原始输入并改善 gradient flow。layer normalization让中间数值保持稳定,减少 gradient 问题。- 完整 transformer encoder block 包含 multi-head attention、add and norm、feedforward、add and norm。
CLS token用于 sequence classification,比简单平均所有 embeddings 更可学习。self-supervised learning通过 masking 从文本自身构造 labels。BERT是用 masked self-supervised learning 训练出的 bidirectional transformer encoder。- Hugging Face
pipeline可以 out of the box 完成 sentiment classification、NER、question answering 等标准 NLP 任务。 - Transformer 可用于 vision、tabular data 和 multimodal data,关键是把输入转换成 embeddings。
八十一、关键术语表
tunable self-attention
在 self-attention 内部加入可学习矩阵,使 attention 机制本身具有可训练参数。
Q
query representation,由 X * AQ 得到。
K
key representation,由 X * AK 得到。
V
value representation,由 X * AV 得到。
AK / AQ / AV
三组独立的可学习矩阵,用于把输入 embeddings 转换成 K、Q、V。
scaled dot-product attention
原始 transformer 中的 attention 公式:softmax(Q K^T / sqrt(d_k)) V。
multi-head attention
多个 attention heads 并行计算,每个 head 拥有自己的 AK、AQ、AV。
residual connection
将 layer 输入与 layer 输出相加,保留原始信息并改善 gradient flow。
layer normalization
对每个 embedding 内部做标准化,使中间数值保持稳定。
add and norm
Transformer 图中的模块,add 表示 residual connection,norm 表示 layer normalization。
CLS token
用于 sequence classification 的人工 class token,其 contextual embedding 表示整句话。
self-supervised learning
从输入自身构造监督信号的训练方法。
masking
遮住输入的一部分,让模型预测被遮住内容的 self-supervised learning 技术。
BERT
基于 masked self-supervised learning 训练的 multi-layer bidirectional transformer encoder。
Hugging Face pipeline
Hugging Face transformers library 中的高级接口,可直接调用预训练模型完成标准任务。
Vision Transformer
把图片切成 patches,将每个 patch 转换成 embedding,再用 transformer 处理的视觉模型。
Tab Transformer
把 tabular data 中的 categorical variables 转换成 embeddings,并用 transformer 处理的表格模型。
multimodal transformer
把文本、图像、表格等不同 modality 都转换成 embeddings 后统一输入 transformer 的模型。