Transformer:先理解信息怎样互相查询,再谈多模态融合
学术型精读 · 概念、公式、实验、源码与可验收练习
一句话总结
Transformer 用注意力直接建立序列位置之间的联系,训练时避免循环网络的逐位置递推;理解查询、键、值、掩码和残差,是读懂 ALMT 与 MulT 的前提。
论文究竟解决什么问题
这篇论文研究机器翻译:输入一种语言的词序列,输出另一种语言的词序列。旧方法通常先用循环网络编码,再逐步生成译文。循环结构让后一个位置依赖前一个位置的计算,训练很长的句子时难以把所有位置同时处理。作者提出只用注意力和逐位置前馈网络构建编码器、解码器,把跨位置的信息交互从递推改成直接查询。
这里的“并行”首先指训练中的序列计算,不表示原始模型能够一次生成全部译文。自回归解码仍然先生成第一个词,再利用已有词预测下一个词。论文结尾也把减少生成过程中的顺序依赖列为未来方向。因此,学习它时要把编码器并行、教师强制训练和实际推理的逐词生成分开理解。
Figure 1 是整篇论文的主线:左侧编码输入,右侧利用编码结果生成输出。编码器的自注意力处理源句内部关系;解码器的带掩码自注意力处理已经出现的目标词;中间的交叉注意力让目标词查询源句。三个模块都叫注意力,但查询来自哪里、可以看见哪些位置并不相同。
从一个具体句子理解查询、键和值
可以把查询理解成“当前位置要找什么”,键理解成“各位置提供怎样的索引”,值理解成“找到之后实际取回的内容”。例如处理“它很轻,但续航很短”时,评价词需要结合不同对象。模型不是查人工词典,而是用可学习线性映射把词表示投影成查询、键和值,再根据匹配程度加权组合信息。
设输入有十个词,每个词表示成五百一十二维向量。一个注意力头可以把它投影成十行六十四列的查询、键和值。查询乘键的转置得到十行十列的相关性表;每一行经过 softmax 后和为一,再乘值矩阵得到新的十行六十四列表示。输出长度等于查询长度,这一规律到跨模态注意力仍然成立。
除以键维数的平方根并非为了改变矩阵形状,而是控制点积随维度增长的尺度。若分数绝对值过大,softmax 会过早接近只选择一个位置,梯度变小。这个理由依赖作者讨论的近似方差分析,不表示缩放能够自动解决所有数值稳定问题;掩码与浮点精度仍然要正确处理。
多头注意力并不是把同一张注意力图复制八遍。每个头有不同的投影参数,可以学习不同关系,再把结果拼接并映射回模型维度。Figure 2 展示了这一结构。某些头在可视化中表现出语法或指代关联,但这些图是解释性观察,不能据此认定每个头都固定对应一个人类命名的语言功能。
顺序、非线性与残差分别做什么
纯注意力本身不自动知道第几个词先出现,因此原模型把正弦、余弦位置编码加到词嵌入上。不同频率提供不同变化尺度,使位置能够进入后续相关性计算。它不是把时间戳作为一个单独的整数输入,也不保证模型在任意超长序列上都能无损外推。Table 3 中学习式位置编码与正弦编码的结果很接近,不能把正弦形式神化。
逐位置前馈网络对每个位置分别使用同一套参数,先升维、经过 ReLU,再降维。注意力负责不同位置交换信息,前馈网络负责对当前位置收到的表示做非线性变换。前馈网络不再沿序列维度混合位置,因此不要把它误读成第二个全局注意力层。
原论文每个子层使用残差连接与层归一化,表达为先相加再归一化,即常说的后归一化。残差把原输入直接送到后面,减少每一层都重新学习完整表示的负担。现代代码常用先归一化,但这是架构变体;本篇公开仓库中的 v2 默认配置也与论文 v1 有差别,不能看到 Transformer 名字就假定所有实现一致。
解码器的未来位置掩码让预测第三个词时看不到第四个词。实现中通常在对应注意力分数加一个很大的负数,softmax 后该位置权重接近零。填充掩码则屏蔽没有真实内容的补齐位置。二者目的不同,特别是在变长视频、变长语音中,忘记填充掩码会使模型把补零模式当作信息。
架构与训练配置如何核对
基础模型包含六层编码器与六层解码器,模型维度五百一十二,八个头,前馈中间维度二千零四十八。必须区分层数、头数与维数:增加头数时,若总模型维度固定,每个头的维数会减少;增加层数则增加串联的变换次数。两种变化影响不同,参数量与计算量也不是同一个概念。
原文训练使用 Adam、自定义学习率预热和衰减、标签平滑、dropout 等配套设置。标签平滑使正确标签不再占据全部目标概率,其目标是改善泛化与置信度,不等于把训练标签随机打错。基础模型使用四千步预热;当前仓库 v2 的默认预热不同,复现时应明确调用哪一组配置。
原文使用八张 P100 训练,因此不能把论文的训练时间直接换算成单张笔记本显卡的承诺。初学者应先完成一个注意力层和一个小型序列任务,再决定是否训练完整翻译模型。理解基本算子不需要复现整套大规模翻译训练,也不需要为了读懂 ALMT 先取得相同的 BLEU。
实验究竟支持哪些结论
Table 2 的翻译比较支持 Transformer 在这些数据与训练设置下具有很强的性能和效率;Table 3 的消融则更适合判断设计选择。两张表的数据集划分不同:前者是最终翻译测试结果,后者报告开发集结果。不能把两张表中基础模型的数字差异理解成某个模块导致的性能变化。
需要特别标注版本内的不一致:正文 Section 6.1 的英法结果出现 41.0,而摘要与 Table 2 报告 41.8。本页采用 Table 2 的 41.8,并保留这一核查说明。读论文时遇到这种差异应保留定位信息,而不是自行选一个数字后假装不存在冲突。
Table 1 比较复杂度和信息路径。全自注意力的主要计算随序列长度平方增长,位置之间可以一步联系;循环网络路径随距离增长。这解释为什么注意力适合建模远距离关系,也解释长视频、长音频可能产生显存压力。“任意两点能直接联系”不代表模型总会学到正确联系,更不代表所有问题都比卷积便宜。
Figure 3、Figure 4、Figure 5 展示长距离联系、指代与结构相关的注意力可视化。它们可以帮助提出观察问题,但注意力权重不能直接证明因果贡献。真正验证某一模态或位置的作用,还需要遮挡、替换、消融及错误分析,尤其在情绪识别中不能仅凭一张热力图声称模型理解了情绪。
与细粒度、跨场景研究怎样连接
细粒度方向关心“什么时候、哪个局部、哪个模态提供区分线索”。你首先可以把查询定义为表情片段,键和值定义为对应的语音或文本序列,明确输出到底落在哪一个时间轴上。这样读 MulT 或 ALMT 时,就能看出它们在组织交互而非简单拼接特征。
跨场景方向还需要问:注意力可能关注背景、说话人或录音环境吗?答案是可能。原论文没有建立跨场景情绪泛化保证。若直接把注意力网络换进分类器后目标域变差,首先检查模型是否学到了源域特有的关联,而不是直接增加头数。保持模型不变、替换场景分布的受控实验,比堆叠模块更能识别原因。
作者在结尾提出拓展到图像、音频、视频以及局部注意力等方向,这些是原论文的后续展望,不是已经完成的实验。独立判断还应补充二次复杂度、固定上下文处理和生成阶段顺序依赖等边界。把“提出了可迁移的计算范式”与“已经解决所有模态问题”区分开,是这篇基础论文最重要的科研阅读训练。
公式逐步读:变量、运算与适用范围
原文式 (1):缩放点积注意力
Q 的行数是查询位置数,K 与 V 的行数必须相同;softmax 沿键位置进行。输出不是分类概率,而是经过加权的信息表示。
原文未编号定义:多头组合
每个头用自己的投影矩阵得到注意力输出。拼接发生在特征轴,不能在时间轴拼接后仍声称输出长度不变。
原文式 (2):逐位置前馈
对各位置独立执行同一非线性映射。基础模型先从五百一十二维升到二千零四十八维,再返回原维度以便残差相加。
原文未编号定义:位置编码
p 是位置,i 控制频率。位置编码与嵌入逐元素相加;它不是额外增加一个序列位置。
原文式 (3):学习率
s 是更新步数,w 是预热步数;开始线性上升,之后按步数平方根的倒数下降。不能把这里的步数误填为训练轮数。
实验读数:先固定协议,再比较数值
| 模型 | 英德 | 英法 |
|---|---|---|
| ConvS2S | 25.16 | 40.46 |
| MoE | 26.03 | 40.56 |
| Transformer base | 27.3 | 38.1 |
| Transformer big | 28.4 | 41.8 |
| 设置 | BLEU |
|---|---|
| 基础设置 | 25.8 |
| 单头 | 24.9 |
| 四头 | 25.5 |
| 十六头 | 25.8 |
| 三十二头 | 25.4 |
| 学习式位置编码 | 25.7 |
| 无 dropout | 24.6 |
计算流程图
flowchart LR A[Source tokens and positions] --> B[Encoder self attention] B --> C[Source representations] D[Previous target tokens] --> E[Causal self attention] E --> F[Cross attention queries] C --> F F --> G[Feed forward and vocabulary prediction]
沿图逐条检查箭头:每个箭头传递的是张量或监督信号,并不代表额外的数据集;训练目标旁的分支在部署时未必保留。建议先在纸上填入批大小、序列长度、通道数,再阅读下面的源码。一个模块即使名字相同,只要输入轴、掩码或输出使用方式改变,也不能直接视作同一个实验。
论文方法与固定版本源码对照
tensor2tensor/layers/common_attention.py:1646–1667
with tf.variable_scope(
name, default_name="dot_product_attention", values=[q, k, v]) as scope:
logits = tf.matmul(q, k, transpose_b=True) # [..., length_q, length_kv]
if bias is not None:
bias = common_layers.cast_like(bias, logits)
logits += bias
# If logits are fp16, upcast before softmax
logits = maybe_upcast(logits, activation_dtype, weight_dtype)
weights = tf.nn.softmax(logits, name="attention_weights")
if hard_attention_k > 0:
weights = harden_attention_weights(weights, hard_attention_k,
gumbel_noise_weight)
weights = common_layers.cast_like(weights, q)
if save_weights_to is not None:
save_weights_to[scope.name] = weights
save_weights_to[scope.name + "/logits"] = logits
# Drop out attention links for each head.
weights = common_layers.dropout_with_broadcast_dims(
weights, 1.0 - dropout_rate, broadcast_dims=dropout_broadcast_dims)
if common_layers.should_generate_summaries() and make_image_summary:
attention_image_summary(weights, image_shapes)
return tf.matmul(weights, v)这里先计算相关性,再加掩码偏置、softmax 和加权求和。查询的缩放可能在上游完成,因此不能仅凭这一局部函数看不到除法就断言代码漏掉缩放。
tensor2tensor/models/transformer.py:1772–1794
def transformer_base_v1():
"""Set of hyperparameters."""
hparams = common_hparams.basic_params1()
hparams.norm_type = "layer"
hparams.hidden_size = 512
hparams.batch_size = 4096
hparams.max_length = 256
hparams.clip_grad_norm = 0. # i.e. no gradient clipping
hparams.optimizer_adam_epsilon = 1e-9
hparams.learning_rate_schedule = "legacy"
hparams.learning_rate_decay_scheme = "noam"
hparams.learning_rate = 0.1
hparams.learning_rate_warmup_steps = 4000
hparams.initializer_gain = 1.0
hparams.num_hidden_layers = 6
hparams.initializer = "uniform_unit_scaling"
hparams.weight_decay = 0.0
hparams.optimizer_adam_beta1 = 0.9
hparams.optimizer_adam_beta2 = 0.98
hparams.num_sampled_classes = 0
hparams.label_smoothing = 0.1
hparams.shared_embedding_and_softmax_weights = True
hparams.symbol_modality_num_shards = 16这是 v1 参数配置所在区域。阅读时继续对照同文件 v2:归一化顺序与预热设置存在变更。复现实验必须保存实际解析后的完整配置。
代码核查固定在提交 bafdc1b67730430d38d6ab802cbd51f9d053ba2e。这里展示的是公开仓库的实际文件,不把重新写的教学代码冒充作者实现。仓库后续可能包含新版本、工程兼容选项和不同默认参数;本文只将已核实的语句对应到论文机制。下载权重成功、模型能够前向传播、复现论文最终指标是三个不同的验收层级。
从读懂到能够独立实现:可执行学习任务
第一步,用随机张量构造两个样本、三个查询、五个键、四维通道,手写一次注意力。验收:输出为两组三行四列;每行权重和接近一;屏蔽最后一个键后对应权重接近零。不要先引入完整 Transformer 类,否则很难知道错误发生在哪个轴。
第二步,固定查询与键,仅修改一个值向量,观察输出按对应权重变化;再固定键和值,只修改查询,观察关注分配变化。验收:在笔记中分别解释“选择依据改变”和“取回内容改变”。这一实验直接帮助理解多模态模块里为何必须说明查询来自哪种模态。
第三步,构造一个四词序列和上三角未来掩码。分别打印有掩码与无掩码的权重矩阵。验收:第一个查询只能看到第一个词;最后一个查询可看见全部非填充词;填充位置不会因为位置编码而获得有效权重。
第四步,完成一个最小分类器,只比较平均池化与一个自注意力层,其余特征、划分和优化器相同。记录参数量、显存峰值、每步时间、验证指标。验收不要求注意力一定获胜,而要求你能解释收益来自新增交互、更多参数还是偶然波动。
第五步,在真实情绪任务之前画出所有张量形状,写清文字长度、语音长度和视频长度。验收:能独立说明为什么跨注意力输出跟随查询时间轴,并指出原始 Transformer 的翻译结果不能作为情绪识别有效性的直接证据。
建立可检查的实验记录
开始第一轮实验前,建立四份小文件:数据清单记录样本编号、来源、标签与划分;配置文件记录预处理、随机种子、模型名称和冻结范围;结果表记录验证指标、选中轮次与最后测试指标;错误清单保存预测错误的样本编号及观察理由。这些文件比一张最高准确率截图更能说明你真正控制了实验条件,也能让后续细粒度或跨场景拓展沿用同一条证据链。
对视频、语音或多模态情绪数据,必须优先检查主体、会话和视频来源是否跨集合重复。同一原始视频切出的多个片段高度相关,随机按片段划分可能让模型记住说话人、背景或录制设备。跨场景问题至少要明确源域训练集、源域验证集和目标域测试集;若使用目标域标签选择提示词或超参数,就不应再把它描述为完全未见目标域的泛化结果。
为避免把实现错误误认为研究发现,先运行一个极小批次,打印输入输出形状、数值范围、有效长度以及损失是否有限。随后在少量训练样本上尝试拟合,验证模型确实能够更新指定参数。如果极小训练集都学不会,优先检查标签编码、掩码方向、归一化、学习率和冻结设置;此时直接扩大数据量通常只会延长排查时间,而不能证明模型本身不适合任务。
消融实验一次只改变一个关键因素,其他预处理、划分、优化预算和选择规则保持一致。第一轮以发现实现问题为目标,只用一个种子;确认代码与趋势合理之后,再增加多个种子并保留每次独立结果。均值用于概括趋势,标准差用于展示训练波动,但都不能替代对样本泄漏和评价口径的检查。不同论文中的最优数字不能在协议不明时直接相减。
解释实验失败时,先区分三层原因:实现层是否正确地执行了计算;优化层是否在给定预算内学到了信号;数据层是否提供了任务需要的信息。比如文本缺少反讽语调、静态图像看不到表情变化、音频包含录音噪声,这些问题不能仅靠增加网络深度解决。把失败样本分组后再提出修改,每项修改应能对应一个可观察的问题和一个预先规定的验证指标。
学习笔记采用“论文本身说了什么—源码实际做了什么—我在本地验证了什么”三栏记录。第一栏附页码或图表编号,第二栏附固定提交与行号,第三栏附命令、环境和输出。本文已完成原文及源码核对,未宣称在你的机器上重训原论文。下面的练习属于待执行计划;只有真正运行并保存结果后,才能把相应项目改为“已完成”。
短引语与阅读定位
原文短语 Attention Is All You Need
(标题):强调注意力作为主体结构,不应理解为数据、优化和监督都不重要。
原文短语 Scaled Dot-Product Attention
(Section 3.2.1):先读矩阵形状,再理解缩放与归一化。
原文短语 Multi-Head Attention
(Section 3.2.2):不同投影子空间的并行信息交互。
参考资料与核验边界
论文摘要与版本信息;完整论文 PDF;作者公开仓库固定版本。公式中标注“教学整理”的表达用于显式说明原文的计算步骤,不声称具有原文公式编号。所有实验数字均指原论文报告结果,不是本次新训练得到的结果。英文短引语合计不超过二十五个词。
自己的解释与验收记录
写出一条输入到输出的链路、一个关键公式的含义,以及你完成的最小检查。笔记仅保存在当前浏览器,可从主站「我的学习笔记」导出。