MIT深度学习课程第七讲:Transformer Encoder 与 Self-Attention
本节课进入 transformer。
老师先说明,transformer 最初是为 machine translation 设计的,例如:
- English 到 German
- German 到 French
- 其他语言之间的翻译
但它后来被证明是一种非常有效的深度神经网络架构,适用范围远远超过翻译任务。
现在,很多问题一旦进入建模阶段,往往会优先尝试 transformer,因为它在大量任务上都能取得很强的效果。
一、Transformer 的应用范围
老师列举了 transformer 已经产生重要影响的方向:
machine translation- Google Search
- information retrieval
- speech recognition
- text-to-speech
- computer vision
- reinforcement learning
- generative AI
- large language models
- multimodal models
- 特定领域系统,例如
AlphaFold
其中,AlphaFold 这类 protein-folding AI 也运行在 transformer stack 上。
老师强调,transformer 是一种非常灵活的架构,不只是自然语言处理中的单一模型。
二、用信息检索作为动机案例
本节课使用 search,更广义地说是 information retrieval,作为引入 transformer 的动机。
这类任务中,用户可能输入或说出自然语言查询,系统需要准确理解用户想要什么。
老师给出的例子包括:
Find me all flights from Boston to LaGuardia tomorrow morning.也可以更具体:
Tell me all the flights that are leaving from Boston and going to LaGuardia tomorrow morning between 8:00 and 9:00.这类问题不同于开放式生成任务,例如:
Write me a limerick about deep learning.开放式生成可能有很多合理答案,但航班查询、合同检索、客户行为分析等任务通常要求很高的准确性。
老师还列举了其他类似查询:
- how many customers abandon their shopping cart
- find all contracts that are up for renewal next month
- tell me all customers who ended a call center call yesterday and were not pleased with the transaction
本节课主要聚焦 travel-related query。
三、自然语言查询到结构化查询
历史上,这类系统常见的处理流程是:
- 接收 natural language query。
- 解析查询文本。
- 抽取关键实体。
- 把抽取出的实体重新组装成 structured query。
- 用 structured query 查询数据库。
- 格式化查询结果并返回给用户。
这里的 structured query 可以是 SQL,也可以是其他结构化查询形式。
老师使用 SQL 作为例子,是因为它更容易被理解。
对于航班查询:
Find me all flights from Boston to LaGuardia tomorrow morning.系统需要自动抽取出与 travel 相关的实体,例如:
BOSLGAtomorrow morningflights
问题的核心变成:
如何从自然语言查询中自动抽取 travel-related entities?四、ATIS 数据集与 Slot Filling
本节使用的数据集是:
Airline Travel Information Systems Data Set通常简称为:
ATIS这个数据集中包含数千条旅行查询。研究人员已经人工检查每一条查询,并给查询中的每个词标注它属于哪一种 travel entity,或者标注为不关心的类别。
这些被标注的 entity 类别称为:
slots因此,这个任务也可以称为:
slot filling五、Slot 标注示例
老师用下面这类句子说明标注方式:
I want to fly from Boston at 7:00 AM and arrive at 11 in the morning.其中:
Iwanttoflyfrom
这些词本身不对应需要抽取的具体 travel entity,因此标注为:
OO 表示:
other也就是当前任务中不关心的类别。
当句子中出现:
Boston它在这个上下文中表示出发城市,因此会被标注为:
B-fromloc.city_name其中:
fromloc表示 departure location。city_name表示城市名。B表示这个实体从当前 token 开始。
对于:
7:00 AM它由两个 token 组成,共同表示 departure time。
因此会使用 B 和 I 的标注方式:
7:00是 departure time 的开始,标为B-...AM是同一个实体的一部分,标为I-...
这里:
B表示BeginningI表示Intermediate或 inside/in the middle
对于后面的到达时间:
11可以标为B-arrive_timemorning可以标为arrive_time.period
这个例子说明,slot filling 的本质是:
给句子中的每个 token 分配一个与任务相关的标签。六、123 种 Slot 类型
在本节课的设置中,每个词会被分类到 123 种可能标签之一。
这些标签覆盖多种旅行相关信息,例如:
- aircraft code
- airline code
- airline name
- airport code
- airport name
- arrival date
- relative date
- round trip / one way
- 与 today 相关的相对时间
老师特别指出,像 tomorrow morning 这样的表达是相对于 today 的,因此系统不仅需要处理绝对时间,也要处理相对时间。
七、课堂问答:Boston 的上下文标签
有学生问:
如果句子里出现 from Boston,标注时是否需要结合 from Boston 的上下文?老师回答:
因为数据集是人工标注的,人类标注者会阅读完整句子,然后判断 Boston 在当前句子中是 departure city 还是 arrival city。
在:
from Boston这个具体上下文中,Boston 会被标为 departure city。
但在另一条查询中,如果用户说的是飞往 Boston,那么 Boston 会得到不同的标签。
八、课堂问答:Compound Query
有学生问,如果查询是复合形式,例如:
give me flights from Boston at 7:00 AM and flights from Denver at 11:00 AM模型是否处理这种 compound query。
老师回答,本节使用的数据集和示例主要关注 single query,因为大多数用户会提出类似:
- give me a flight from here to there
- what is the cheapest flight from here to there
这样的单个查询。
九、任务形式:Word-to-Slot Multi-Class Classification
这个问题可以表述为:
word-to-slot multi-class classification也就是:
每个输入 token 都要被分类到一个 slot label。老师强调,这不是把整条 query 分类到 123 个类别之一。
相反,是查询中的每个词都要独立得到一个标签,但这个标签又必须依赖上下文。
在课堂示例中,输入句子包含 18 个词,因此模型输出也需要包含 18 个位置:
18 in, 18 out每个输出位置上都接一个:
123-way softmax也就是说,18 个输出 token 中,每一个都需要在 123 个 slot 类型中选择一个。
十、这个任务对模型提出的三个要求
老师总结,slot filling 对模型有三个关键要求。
第一,输出长度必须与输入长度相同:
same cardinality如果输入有 18 个 token,输出也应有 18 个 token。
第二,模型必须支持可变长度输入。
现实查询可能很短,也可能很长。模型需要处理这种长度变化,但每条输入内部仍然要求输出与输入等长。
第三,模型必须同时考虑:
- surrounding context
- word order
原因是:
from Boston to LaGuardia和:
from LaGuardia to Boston含义完全不同。
十一、为什么 Context Matters
老师回顾上一节课中 standalone embeddings 的局限。
例如 GloVe 这类 standalone / uncontextual embedding,会给每个词一个固定向量。
如果一个词有多个含义,这个固定向量会变成多个含义的某种平均。
老师用几个例子说明同一个词在不同上下文中的含义差异。
see
I will see you soon.
I will see this project to its end.
I see what you mean.bank
I went to the bank to apply for a loan.
I'm banking on the job.
I'm standing on the left bank.it
The animal didn't cross the street because it was too tired.
The animal didn't cross the street because it was too wide.第一句中的 it 指代 animal。
第二句中的 it 指代 street。
station
radio station
train station
being stationed somewhere
the International Space Station这些例子说明,单个词的含义不能只由词本身决定,必须结合上下文。
十二、Transformer 满足这三个要求
老师指出,transformer 架构非常优雅地满足了前面三个条件:
- 能考虑 context。
- 能考虑 order。
- 输出与输入长度相同。
transformer 这个名字的含义在这里也很直观:
如果 10 个东西进去,10 个东西出来。输出不是数量上的压缩,而是输入的每个元素都被转换成了新的表示。
输入的 10 个 token 仍然对应输出的 10 个 transformed token。
十三、2017 年 Transformer 与 Google Search
transformer 于 2017 年提出。
老师提到,Google 曾长期投入 machine translation 和 search。
当 transformer 出现后,Google 把一个名为 BERT 的模型引入搜索系统,并显著提升了搜索质量。
搜索系统通常已经高度优化,因此改进往往很小。但老师指出,BERT 引入 Google Search 后带来了明显的 quality jump。
老师举了一个搜索例子:
Brazil traveler to USA needs a visa理想结果应该是:
Brazilian traveler coming to the USA needs visa information.但旧系统可能返回:
US citizens going to Brazil need visa information.问题在于系统没有充分理解词序和关系。
引入 BERT 后,搜索结果能更准确地返回美国驻巴西使馆等相关页面。
老师称原始 transformer 论文中的架构图已经成为 deep learning community 中的 iconic picture,并说明后续课程会逐步理解这张图。
他还指出,原论文研究者最初主要聚焦 machine translation,并没有完全预料到这个架构后来会被广泛应用到几乎所有领域。
十四、课堂问答:是否可以先丢弃 O
有学生问:
是否可以先丢弃那些标为 O 的 token,只输出真正重要的实体?例如 18 个输入 token 中,只有 8 个与实体有关,那么能否输出更短结果。
老师回答,这是完全可以思考的一种方式。
它相当于建立一个 two-stage model:
- 第一阶段做
O/non-O分类。 - 第二阶段只处理
non-Otoken。
但老师也指出,即使用一个简单的 one-stage model,只要使用 transformer,也能得到非常好的准确率。后面 Colab 会展示这一点。
十五、Self-Attention:从 station 开始
老师接着回答第一个核心问题:
如何让一个词的表示考虑周围所有词的上下文?示例句子是:
The train slowly left the station.每个词先都有一个 standalone embedding:
w1, w2, w3, w4, w5, w6其中 station 对应 w6。
station 可能表示 radio station、train station、space station 等不同含义。
在当前句子中,它显然是:
train station因此,需要用句子里的其他词来调整 station 的 embedding。
十六、Attention Weight 的直觉
老师先做一个假设:
如果已经知道每个词对 station 应该有多大影响,应该怎样使用这些信息?这就是 attention 的直觉:
对不同词支付不同程度的注意力。在:
The train slowly left the station.中,为了理解 station,直觉上:
train权重应较高。slowly和left可能有一些帮助。the权重很低。station自己的原始 embedding 也应该保留较高权重。
老师手动给出了一组示意权重,例如:
train:约30%left:约8%slowly:约12%station自身:约40%the:很低
老师强调,这些数字只是为了说明概念,是手工写出来的,不是实际模型计算得到的。
十七、课堂问答:这些权重属于谁
有学生问,这些权重是为了理解整句话,还是只和 station 有关。
老师回答:
这些权重只和 station 有关。也就是说,这组权重描述的是每个词对 station 的 contextual embedding 有多大贡献。
对句子中的每个词,都要分别做类似计算,但权重会不同。
十八、课堂问答:此时是否理解 Word Order
有学生问,此时模型是否已经理解 order。
老师回答:
此时还没有处理 order,只是在处理 context。词序会在后面通过 positional encoding 处理。
另一个学生问,模型如何知道 left 在这里的重要性较低。
老师回答,这种能力不是人工指定的,而是通过训练学出来的。
课程会先赋予模型这种表达能力,具体权重如何形成由 training 决定。
十九、Weighted Average 得到 Contextual Embedding
如果已经有了每个词对 station 的权重,最简单的做法是:
weighted average也就是:
0.05 * w1 + 0.30 * w2 + ... + 0.40 * w6结果仍然是一个向量。
这个新向量就是:
contextual embedding of station老师用记号表示为:
w6_hat其中:
w6是station的 standalone embedding。w6_hat是结合上下文后的 contextual embedding。
形式化地说,s1,6 表示第 1 个词对第 6 个词的权重,s2,6 表示第 2 个词对第 6 个词的权重,以此类推。
于是:
w6_hat = s1,6 * w1 + s2,6 * w2 + ... + s6,6 * w6课堂问答:新词、新上下文与 Autocomplete
有学生问,像 Google 这样的系统如何理解新出现的词,或者一个已知词的新上下文。
老师回答,如果是已知词的新上下文,context 来自输入本身。查询进入系统时通常是一整句话,模型会把这句话作为当前输入的上下文。
如果是从未见过的新词,甚至没有对应的 standalone embedding,那么需要等后续课程讲 byte-pair encoding 后再解释。
学生又追问,这是否会直接影响 predictive search / autocomplete。
老师回答,autocomplete 使用的是稍有不同的机制。过去 Google 使用过复杂的 non-transformer 方案,现在很可能也有 transformer 版本,但老师并不了解其内部具体实现。学生提出的理解方式是合理的,但不能直接等同于课堂当前讲的 self-attention 流程。
二十、课堂问答:旧的 w6 是否保留
有学生问,算出 w6_hat 后,它是加入下一层,还是替换原来的 w6。
老师回答:
w6_hat replaces w6也就是说,w6 被替换为 contextual version。
随着表示流经 transformer,它会变得越来越 contextualized。
同样的逻辑会应用到句子中的每个词:
w1, w2, ..., w6都会变成:
w1_hat, w2_hat, ..., w6_hat二十一、权重从哪里来:Dot Product
接下来,老师回答核心问题:
attention weights 从哪里来?直觉是:
一个词的权重应与它和目标词的相关程度成正比。例如:
train与station很相关。the与station的相关性较弱。
衡量两个词相关性的一种方法是:
dot product也就是计算两个 standalone embeddings 的点积。
对于两个向量:
train_embedding
station_embedding它们的 dot product 可以写成:
|train| * |station| * cos(theta)其中 theta 是两个向量之间的夹角。
为了简化理解,可以假设两个向量长度都接近 1,那么 dot product 的主要因素就是:
cos(theta)二十二、Dot Product 的几何直觉
老师用角度解释 dot product 如何表示 relatedness。
如果两个向量方向非常接近:
theta ≈ 0
cos(theta) ≈ 1说明它们高度相关。
如果两个向量互相垂直:
theta = 90 degrees
cos(theta) = 0说明它们大致不相关。
如果两个向量方向相反:
theta = 180 degrees
cos(theta) = -1说明它们可以被看作 anti-related。
因此,dot product 可以用来捕捉 embedding 之间的 closeness 或 relatedness。
二十三、用 Softmax 把 Dot Products 变成权重
dot product 本身还不能直接作为 weighted average 的权重。
原因是权重需要满足两个条件:
- 非负。
- 加起来等于
1。
但 dot product 或 cosine 可能是负数。
因此,需要使用:
softmax做法是:
- 对每个 dot product 做 exponentiation。
- 用每个指数值除以所有指数值之和。
这会得到一组:
non-negative
sum to 1的权重。
老师用角括号表示 dot product,例如:
<w1, w6>再通过:
exp(<w1, w6>)和 softmax 归一化得到真正的 attention weight。
二十四、从 Standalone Embedding 到 Contextual Embedding
整体过程可以总结为:
- 输入一组
standalone embeddings。 - 用 dot product 衡量每个词与目标词的相关性。
- 用 softmax 把相关性分数转成 attention weights。
- 用 attention weights 对所有 embeddings 做 weighted average。
- 得到目标词的
contextual embedding。
在 station 示例中,train 对 station 有强相关性,因此会对 station 的 embedding 产生较强拉动。
如果句子中没有 radio,即使 radio station 也是常见含义,radio 在当前句子中也不会产生影响。
因此,当前句子会把 station 拉向 trains、platforms、departures、tickets 等 train station 相关语义区域。
老师也提醒,如果一句话里同时出现 radio station 和 train station 这类更复杂混合上下文,transformer 也可以处理;本节的例子只是为了说明主直觉。
这正是 context 的作用:
当前句子中出现了什么,就会影响当前词的 contextual embedding。老师称这个机制为:
self-attention这是 transformer 的关键构件。
二十五、课堂问答:词自身的权重
有学生问,目标词自身在自己的 contextual embedding 中应该如何理解。
老师回答,目标词自身的权重通常会比较高,因为一个向量与自身的 cosine 很接近 1。
但它不一定总是最高,因为向量长度并不一定都等于 1。
可以把它理解成:
先对上下文做一个平均,再把这个结果与原始 embedding 平均。实际计算中则是所有 token 一起按权重做 weighted average。
二十六、课堂问答:为什么保持输入输出数量相同
有学生问,为什么需要保持输入和输出数量相同。
老师回答,这样可以在通过 transformer stack 时尽量保留信息。
每个 token 都有自己的 contextual embedding,即使某个 token 最终可能标为 O,它在中间层仍可能为其他 token 提供上下文。
保持 cardinality 不变可以保留 optionality:
- 最后可以选择 aggregate。
- 可以选择 simplify。
- 可以选择 summarize。
- 也可以继续做 per-token classification。
二十七、课堂问答:Context Window
有学生问模型能处理多长的句子。
老师回答,这由:
context window或:
maximum length控制。
这是一个可以设置的参数,后面在 Colab 中会看到。
二十八、Multi-Head Attention 的动机
在单个 self-attention head 之后,老师引入:
multi-head attention一个 attention head 可以学习某一种 attention pattern。
但一个复杂句子中可能同时包含多种模式,例如:
- meaning
- grammar
- tense
- tone
- facts vs opinions
- 其他复杂语言模式
因此,不应该只有一种“注意”的方式。
多个 attention heads 可以让模型从不同角度学习不同 pattern。
老师把它类比为 convolutional neural network 中的多个 filters:
- 一个 filter 可能学到 line。
- 一个 filter 可能学到 curve。
- 其他 filters 学到其他视觉 pattern。
在 attention 中也是类似逻辑,只是模型通过训练自动学出不同模式,而不是人工指定。
二十九、原始 Transformer 论文中的 Attention 可视化
老师引用了原始 transformer 论文中的例子:
The law will never be perfect, but its application should be just.
This is what we are missing, in my opinion.在一个 attention head 中,perfect 的 contextual embedding 可能大量关注 law。
在另一个 attention head 中,perfect 可能主要关注它自身。
不同 attention heads 学到不同的注意模式。
老师也提醒,现实中解释 attention head 为什么这样关注通常很困难,不一定能清楚解释每个 head 的语义。
但经验上,多个 attention heads 往往能显著提升目标任务表现。
三十、课堂问答:Attention Head 是否类似 CNN Filter
有学生把 attention head 与 CNN filter 类比。
老师确认这是同一类直觉。
他补充说明,在课堂早期讲 CNN 时,用 1 和 0 设计 filter 只是为了演示 vertical line 或 horizontal line detection。
真实训练中,CNN filter 的参数同样不是人工指定的,而是随机初始化后通过 backpropagation 学出来。
attention head 也是如此。
三十一、课堂问答:如果只是 Dot Product,为什么不同 Head 会不同
有学生提出一个关键问题:
如果 self-attention 只是 embeddings 的 dot product,那么同样的 embeddings 应该得到同样结果,为什么多个 head 会不同?老师说这是一个很好的问题,并说明这要留到下一节课详细解释。
当前简化版 self-attention box 内部没有参数。
因此学生的问题等价于:
如果 self-attention 里面没有可学习参数,模型到底在学什么?下一节课会引入更完整的机制,例如可以学习的参数。
本节先保留这个问题。
三十二、Concatenate and Project
多个 attention heads 的输出需要合并。
假设有两个 heads:
- head 1 输出某个 token 的 contextual embedding:
w1_hat - head 2 输出同一个 token 的 contextual embedding:
z1
这两个向量都表示第 1 个词,但来自不同 attention head。
合并方式是:
concatenate也就是把两个向量接在一起,形成一个更长的向量。
如果原始向量长度是 100,两个 heads concat 后会变成 200。
但 transformer 需要保持每层输入输出的 vector length 不变。
因此 concat 后会经过一个:
dense layer把长向量投影回原始长度。
这一步称为:
concatenate and project如果有 20 个 attention heads,concat 后向量会变成原来的 20 倍,再通过 projection 回到原始维度。
三十三、Feed-Forward / ReLU 层
在 multi-head attention 之后,还会加入 dense / ReLU 层来引入 non-linearity。
老师说明,通常会使用一个带 ReLU 的 hidden layer,然后再用一个 linear layer 投影回原始维度。
如果输入向量长度是 100,实践中常见设置是:
hidden ReLU width ≈ 400也就是 hidden layer 约为输入维度的 4 倍。
随后再通过 dense layer 投影回 100。
这一步的目的包括:
- 增加 non-linearity。
- 保持输出维度与输入维度一致。
老师指出,许多设计最初看起来有些 ad hoc,并非来自严格理论推导,但有很强直觉基础。后来很多研究尝试改进 transformer 的各个细节,但原始架构本身非常 robust,很难被轻易超越。
三十四、当前 Transformer Block 的流程
到这里,老师总结当前结构。
输入可以是:
- random standalone embeddings
- pretrained embeddings,例如
GloVe
然后:
- embeddings 进入多个
self-attention heads。 - 每个 head 输出 contextual embeddings。
- 多个 heads 的输出被 concatenated。
- 通过 dense projection 回到原始维度。
- 经过
ReLU和 linear layer。 - 输出同样数量、同样长度的 contextual embeddings。
如果输入是 6 个向量,每个向量长度为 100,输出仍然是:
6 vectors, each 100 dimensions不同的是,输出向量的数值已经被上下文化。
老师用这种方式说明:
transformer block 是一个保持 shape 不变、但改变表示内容的 black box。三十五、目前已经解决两个要求
到这里为止,模型已经满足了三个要求中的两个:
- 通过 self-attention 考虑 context。
- 输出长度与输入长度相同。
但还有一个问题没有解决:
word order当前的 dot product self-attention 本质上作用于 set,而不是 sequence。
如果把句子:
The train slowly left the station.打乱成:
The station slowly left the train.只依赖 dot product 的 self-attention 无法区分它们的顺序差异。
因为它计算的是 token pair 之间的关系,而不包含位置。
三十六、Set 与 Sequence
老师指出,如果处理的问题本来不关心顺序,那么此时的 transformer 已经可以使用。
例如某些 structured / tabular data:
- blood pressure
- cholesterol level
- 其他医学或结构化特征
这些特征之间没有自然词序,但仍可用于预测 heart disease 之类目标。
因此,transformer 可以服务于:
- order 不重要的 set problem。
- order 重要的 sequence problem。
对于 sequence,需要额外加入位置相关信息。
三十七、Positional Encoding
为了解决 word order,老师引入:
positional encoding有很多方法可以给 transformer 提供位置信息。
本节课采用最简单且实践中效果不错的一种方式:
把每个位置也看作 categorical variable,并为每个位置学习一个 embedding。如果最大句长是 30,那么每个词的位置就是:
0, 1, 2, ..., 29这些位置编号可以像词一样拥有自己的 embedding。
做法是:
final input embedding = word embedding + position embedding三十八、Positional Encoding 数值示例
老师给出一个极简词表:
unknown
cat
mat
I
sit
love
the
you
on假设每个 word embedding 的维度只有 2。
老师提醒,上一节使用的 GloVe embeddings 大约是 100 维,作业中使用的 embeddings 还会更长;这里设置为 2 维只是为了方便演示计算。
例如:
cat = [0.5, 7.1]再假设最大句长是 10,位置编号为:
0, 1, 2, ..., 9每个位置也有一个 2 维 embedding。
例如 position 0 的 embedding 是:
[1.3, 3.9]对于句子:
Cat sat matcat 出现在 position 0。
因此:
cat word embedding = [0.5, 7.1]
position 0 embedding = [1.3, 3.9]
sum = [1.8, 11.0]于是,进入 transformer 的不是原始 cat embedding,而是:
[1.8, 11.0]如果句子变成:
Mat sat catcat 的 word embedding 仍然是 [0.5, 7.1],但它的位置变了,因此会加上不同的 position embedding。
这样,同一个词出现在不同位置时,进入模型的向量也不同。
三十九、Position Embedding 从哪里来
老师问:
这些 position embeddings 从哪里来?答案仍然是:
learned with backprop训练开始时,这些 position embeddings 可以是随机数。
随着模型训练,它们会通过 backpropagation 被不断更新。
四十、课堂问答:Position Embedding 是否每个句子不同
有学生问,position embedding 是否会随每个句子变化。
老师回答:
不是。position embedding table 是一张共享表。
例如任意输入句子中,只要某个 token 位于第 7 个位置,就使用第 7 个位置对应的 embedding。
它只与位置有关,不与具体句子有关。
四十一、课堂问答:同一个词重复出现
有学生问,如果同一个词在一个句子中出现多次怎么办。
老师用例子说明:
Cat cat cat三个 cat 的 word embedding 都相同:
[0.5, 7.1]但它们的位置不同:
- 第一个
cat加 position0embedding。 - 第二个
cat加 position1embedding。 - 第三个
cat加 position2embedding。
因此,三个最终向量不同。
这就是 position embedding 的作用。
四十二、课堂问答:Position Table 与 Word Table 是否绑定
有学生问,position embedding table 是否依赖于 standalone embedding table。
老师回答:
independentposition embedding table 只取决于最大输入长度假设。
它不关心词表里有哪些词。
word embedding table 和 position embedding table 是两张独立表,只是在输入 transformer 前被相加。
四十三、课堂问答:Malformed Sentence
有学生问,如果输入句子本身有错误,例如出现语法或缺词问题,输出是否会错。
老师回答,从严格的 arithmetic 角度看,错误输入会导致相应计算结果。
但 transformer 通常在大量数据上训练,因此对这类噪声可能相当 robust。
四十四、课堂问答:Filler Words
有学生问,如果输入来自语音转写,包含很多:
umuhlike
这类 filler words,是否需要过滤。
老师回答,后面会讨论 byte-pair encoding。
在那类 tokenization 中,模型会把 individual characters、word fragments 和 words 都作为可能的 tokens。
像 um、uh 这样的词会被映射成较小 token,并像其他 token 一样被处理。
四十五、课堂问答:语义与位置哪个更重要
有学生问,既然 word embedding 和 position embedding 只是相加,那么语义信息是否可能比位置信息更重要。
老师回答,事先无法知道在某个具体任务或句子中哪一部分更重要。
训练过程会通过大量文本数据学习这些 embedding 的合适值,使整体准确率尽可能高。
这里体现了人类直觉与 backprop 学习之间的张力:很多时候可以把设计交给训练过程,让模型自己学出有效参数。
四十六、课堂问答:实际输入 Transformer 的是什么
有学生问,最终进入 transformer 的是 sum vector,还是幻灯片右侧展示的矩阵。
老师回答,实际进入 transformer 的是相加后的向量。
幻灯片右侧的矩阵只是为了演示计算过程。
四十七、课堂问答:Token 与 Punctuation
有学生问,输入是否还会去掉 punctuation,是否支持 multi-sentence input,以及每个句子是否都有 positional embedding。
老师回答,本节目前从 tokens 开始讨论。
在本节的简单例子中,token 基本等同于 words,并假设做了简单 standardization。
但在 GPT-4 这类模型中,tokenization scheme 不同。
一个 token 可能是:
- word 的一部分
- individual character
- punctuation mark
因此,punctuation 是否被保留、如何被处理,取决于 tokenizer。
老师会在后续讲 byte-pair encoding 时回到这个问题。
课堂转写中这里出现了 doesn't support punctuation 的表述,但上下文是在说明 GPT 系列能够把 punctuation 作为 token 并在输出中保留完整标点,因此笔记按这个上下文理解为:GPT 类 tokenizer 可以处理 punctuation。
四十八、Transformer Encoder
到这里,三个要求都已经满足:
- 通过 self-attention 处理 surrounding context。
- 通过 positional encoding 处理 order。
- 通过 shape-preserving design 保持输出与输入等长。
这个结构称为:
transformer encoder老师展示了原始论文中的 encoder 图,并解释其中流程:
- 输入文本,例如
The cat sat on the mat。 - 文本被转换成 tokens。
- tokens 被转换成 input embeddings / standalone embeddings。
- 加上 position-dependent embeddings。
- 进入 transformer block。
- 经过
multi-head attention。 - 经过
add and norm。 - 经过
feed forward network。 - 再经过
add and norm。 - 输出 contextual representations。
其中:
add and norm会在下一节课解释。- residual connections 和 layer normalization 也会在下一节课解释。
四十九、Encoder 的关键接口:输入输出 Shape 一致
老师强调,encoder 最重要的特点之一是:
输入和输出的 size 一致。这里的 size 包括两层含义:
- token 数量相同。
- 每个 token 的 vector length 相同。
因为接口一致,所以可以把多个 transformer encoder blocks 堆叠起来:
encoder -> encoder -> encoder -> ...老师用 pancakes 比喻这种堆叠方式。
他提到:
GPT-3 has 96 transformer stacks.深度学习中,层数越多,模型通常能表示越复杂的模式;前提是有足够数据,避免过拟合。
五十、下一节课会补充的内容
本节课先使用简化版 self-attention解释 transformer 的主干直觉。
老师明确说明,下一节会继续讲:
- self-attention 内部到底有哪些 learnable parameters
- 如果当前简化版 self-attention 没有参数,模型到底在学什么
- residual connections
- layer normalization
add and norm
五十一、课堂问答:多个 Head 与多个 Block 的区别
有学生问,多个 transformer blocks 与多个 self-attention heads 有什么不同。
老师回答:
- 一个 transformer block 内部可以有多个 attention heads。
- 增加 heads 是“变宽”,可以在同一层中学习不同 attention patterns。
- 堆叠 blocks 是“变深”,可以逐层学习更高层次的 abstraction。
老师补充,GPT-3 和 GPT-4 这类模型通常有很多 attention heads。实践中既可以增加 heads 让模型更“宽”,也可以堆叠 blocks 让模型更“深”。
老师用 CNN 类比:
较深的卷积层可以把低层特征组合成更抽象的概念。
例如前一层已经看到很多 edges,后一层可能把这些 edges 和 circles 组合起来识别为 face。
transformer stack 也是类似逻辑:越往上,表示越抽象。
五十二、Colab:用 Transformer 做 Travel Slot Filling
接下来进入 Colab。
目标是把刚刚学到的 transformer encoder 应用到 travel slot problem。
老师先做常规准备,并说明课程团队把前面提到的 ATIS 数据集放到了 raw box 中,便于 Colab 直接读取。
数据集中包含:
- query column:自然语言输入。
- slot-filling column:每个 token 对应的 slot label。
- intent column:整条 query 的 intent label。
本节只使用:
query作为 input text。slot-filling作为 dependent variable / output。
intent column 暂时不使用。
随后,代码会分别从 training data 和 test data 中取出 query 与 slot-filling 两列,用于训练和测试。
老师展示的数据示例包括:
I want to fly from Boston at 8:38 AMI want to fly from Boston at 8:30 AM and arrive in Denver at 11:00 in the morningWhat kind of ground transportation is available in Denver?What's the airport at Orlando?How much does the limo service cost within Pittsburgh?
这些例子说明 ATIS 覆盖了较宽范围的旅行相关查询。
五十三、HODL Library
课程团队把 Keras 中与 transformer 相关的代码封装进一个小文件,称为:
HODL老师说明,称它为 library 有些夸张,本质上只是把一组代码放进一个文件,便于课堂使用。
Colab 中会从 HODL 导入:
TransformerEncoder以及:
PositionalEmbedding处理流程是:
- 对输入 query 做 vectorization。
- 对 token 做 positional embedding。
- 把结果送入 transformer encoder。
五十四、输入 Query 的 Vectorization
输入侧需要先对 query 做向量化。
老师演示时出现过 max_query_length is not defined,原因是没有按顺序运行所有 Colab cells;重新运行相关 cell 后继续。
在数据中,输入 queries 的 vocabulary 有:
888 tokens因为输出模式需要 integer tokens,而不是 multi-hot encoding,所以 vectorizer 会输出整数序列。
这些整数后续会进入 embedding layer。
Keras 会保留特殊 token:
- empty string 作为
pad token UNK作为 unknown token
老师提到,最常见的 token 中有:
tofromflightsBoston
其中 Boston 出现得尤其频繁。
五十五、输出 Slot 的 Vectorization
输出侧的 slot labels 也是一串 token,因此也需要做类似 STIE 的处理。
但这里有一个重要差异:
slot label 中的大小写和符号有具体含义。
例如:
B-fromloc.city_name其中:
B-._
都不能随意删除或改写。
如果使用默认 standardization,Keras 可能会:
- 去掉 punctuation。
- 改成 lowercase。
这会破坏标签含义。
因此,输出侧 vectorizer 要设置:
standardization=None也就是告诉 Keras:
不要对 slot labels 做默认标准化。五十六、为什么输出 Vocabulary 是 125
老师在讲概念时说有:
123 slots但在 Colab 中,输出 vocabulary 显示为:
125 tokens学生回答,差异来自特殊 token。
也就是说,除 123 个实际 slot labels 外,还包含类似:
- padding token
- unknown token
这样的额外 token。
因此代码中的 softmax 会面向 125 个输出 token。
五十七、Slot Filling 模型结构
老师用一个简单输入说明模型结构:
fly from Boston to Denver对应输出大致是:
O O B-fromloc.city_name O B-toloc.city_name模型流程是:
- 输入 token 序列。
- 生成 positional input embeddings。
- 输入 transformer。
- 得到 contextual embeddings。
- 通过
ReLU。 - 对每个 token 输出一个 softmax 分类。
如果输入有 5 个 token,transformer 输出仍有 5 个 contextual embeddings。
然后,每个输出位置都接一个:
123-way softmax在代码中,因为包含特殊 token,实际是:
125-way softmax模型中所有 layer 的权重都会通过:
backprop被优化。
五十八、课堂问答:PositionalEmbedding Layer 是否也要学习
有学生问,Colab 中 import 的 positional embedding 是否就是固定好的。
老师回答,它只是一个 layer。
就像 TextVectorization layer 一样,layer 本身是一段代码或空壳,需要在具体数据上建立 vocabulary 或学习权重。
PositionalEmbedding 中的 weights 仍然需要通过训练学习。
五十九、课堂问答:Transformer 输出之后的维度由谁决定
有学生问,图中黄色 vector layer 维度变化是否有特殊原因。
老师回答,这是 modeler 的选择。
transformer 的职责是输出高层次的 contextual embeddings。
接下来怎么使用这些 embeddings,取决于具体任务。
对于当前任务,可以:
- 如果 embedding 很长,先用
ReLU降维或调整表示。 - 加入 non-linearity。
- 最后接 softmax 做分类。
老师总结为:
When in doubt, throw in a bit of non-linearity.六十、模型超参数设置
本节 Colab 中,老师从零训练 embeddings,不使用 GloVe。
主要设定包括:
embedding_dim = 512
dense_dim = 64
num_heads = 5
max_query_length = 30含义分别是:
- 每个 embedding vector 长度为
512。 - transformer 内部 feed-forward / dense dimension 为
64。 - attention heads 数量为
5。 - 每条 query 的最大 token 长度为
30。
如果输入句子有 35 个 token:
last 5 tokens are truncated如果输入句子有 22 个 token:
pad with 8 pad tokens这样所有输入都变成长度 30。
六十一、PositionalEmbedding Layer 内部结构
老师强调,PositionalEmbedding layer 打包了两张不同的表:
- word embedding table
- position embedding table
它们是 distinct tables,只是被包装在同一个 layer 中。
在本节数据中:
word embedding table 的形状是:
888 tokens x 512 dimensionsposition embedding table 的形状是:
30 positions x 512 dimensions每个输入 token 会取一个 word embedding,再取对应 position 的 embedding,然后相加。
六十二、TransformerEncoder 的参数
TransformerEncoder 对象需要指定三个主要参数:
embedding dimension
dense dimension
number of attention heads在本节中分别是:
512645
经过 transformer encoder 后,输出仍是一组 contextual embeddings。
随后进入传统 DNN 部分:
ReLUlayer,128units。dropout。Denseoutput layer。softmaxactivation。
输出层大小为:
125也就是 125-way softmax。
六十三、参数数量与课后练习
模型 summary 中显示参数量约为:
5.3 million老师建议,在下一节课讲完完整 self-attention 内部参数后,可以手工计算 transformer 中的参数数量,检查是否与 summary 匹配。
这是一个 optional extra credit / personal edification。
老师还说明,可以通过 layer 的:
weights属性查看任意 layer 的权重。
例如查看 PositionalEmbedding layer,可以看到:
888 x 512的 token embedding table。30 x 512的 position embedding table。
训练前也可以查看这些初始权重。
六十四、本节结束位置
由于模型训练需要几分钟,而课堂时间已经接近结束,老师决定停在模型搭建与权重查看这里。
后续内容会在下一节课继续。
老师最后提醒:
如果本节某些细节还不完全清楚,不用担心,下一节课会继续展开,尤其会解释 self-attention 内部到底学习什么。
六十五、本节核心脉络
本节课的主线可以压缩为:
transformer最初用于 machine translation,但已经扩展到搜索、语音、视觉、强化学习、生成式 AI、多模态模型和 AlphaFold 等场景。- 使用 ATIS travel query 的
slot filling任务作为动机。 - Slot filling 要求对每个 input token 输出一个 slot label。
- 该任务要求模型同时满足 context、order 和 same input-output length。
self-attention用 dot product 和 softmax 为每个词计算 context weights。- weighted average 把 standalone embeddings 转换成 contextual embeddings。
multi-head attention允许模型学习多种 attention patterns。concatenate and project负责合并多个 heads,同时保持 vector length 不变。- Feed-forward / ReLU 层为 transformer block 引入 non-linearity。
positional encoding通过 position embeddings 注入词序信息。transformer encoder保持输入输出 shape 一致,因此可以堆叠成深层transformer stack。- Colab 中用
TransformerEncoder和PositionalEmbedding构建了 ATIS slot filling 模型。
六十六、关键术语表
transformer
一种保持输入输出数量对应、同时将输入表示转换为上下文化表示的深度学习架构。
slot filling
给输入句子中的每个 token 标注任务相关实体类别的序列标注任务。
O
other,表示当前 token 不属于任务关心的实体类别。
B
Beginning,表示某个多 token 实体的开始。
I
Intermediate / inside,表示某个多 token 实体的后续部分。
standalone embedding
不随上下文变化的词向量,例如传统 GloVe 表示。
contextual embedding
结合当前句子上下文后得到的词向量。
self-attention
用输入序列内部 token 之间的相关性来重新计算每个 token 表示的机制。
dot product
衡量两个向量相似度或相关性的基本运算。
softmax
把任意实数分数转换为非负且总和为 1 的权重分布。
attention head
一套 self-attention 机制,可以学习一种 attention pattern。
multi-head attention
并行使用多个 attention heads,再把结果合并的机制。
positional encoding
向 token embedding 中注入位置信息的方法。
transformer encoder
由 input embeddings、positional encodings、multi-head attention、feed-forward network、add and norm 等组件构成的 encoder block。
context window
模型一次能处理的最大 token 长度。