1. 变革起点:为什么说Transformer是NLP的分水岭
做自然语言处理的人,对2017年那篇经典论文的发布时间记得很清楚。在那之前,整个NLP圈子被循环神经网络的统治笼罩了很久。无论是LSTM还是GRU,本质上都在做同一件事:让信息沿着时间步顺序一步一步传递。这种串联结构带来的问题非常致命——序列一长,梯度要么消失要么爆炸,前面的单词基本就“失忆”了。后来大家用门控机制、用注意力机制去补救,也只是在LSTM的外围打补丁,并没有从根上改变顺序依赖这个致命缺陷。
Transformer之所以被称作革命性架构,核心就在于它把“顺序处理”变成了“并行处理”。它第一次让模型可以同时看到一句话里所有词,并且用自注意力机制动态计算每个词和其他词之间的关联权重。这种设计的直接好处有两层:底层是解决了长距离依赖问题,词与词之间的距离不再影响信息传递;上层则是训练速度的质变,GPU的并行算力终于能真正被榨干。我至今记得第一次把LSTM换成Transformer跑机器翻译实验时的感受,训练时间和效果的双重改善,确实是降维打击。
那篇论文当时给出的BLEU值在WMT任务上刷新了纪录,但真正让整个行业狂热起来的,是后来的预训练语言模型浪潮。从GPT到BERT再到T5,几乎所有主流架构都建立在这个自注意力基础之上。可以这么说,现在你打开任何一篇NLP论文、任何一套开源代码库,绕不开的都是这套架构。所以这篇文章我会从原理到工程,把Transformer掰开揉碎讲清楚,特别会讲很多文档里不会写的实操细节和踩坑经验,适合正在入门深度学习NLP、准备做文本分类或生成任务、以及想深入理解大模型底层机制的同学阅读。
2. 架构全景拆解:编码器与解码器的协作逻辑
2.1 一次前向传播走完整个流程
先建立一个整体画面。一个标准的Transformer模型,如果做的是翻译这类序列到序列任务,由编码器和解码器两大部分组成。编码器负责把输入句子“读懂”,解码器则负责基于编码器的理解逐词生成目标语言。以“我 爱 学习”翻译成英文为例,输入会先经过词嵌入变成向量,然后带着位置信息进入编码器。编码器内部有6层堆叠结构,每层都有两个主要子层:多头自注意力层和全连接前馈网络层。每层之间还夹着残差连接和层归一化。
解码器结构类似,但多了一个关键的掩码多头注意力层。掩码的作用是保证生成第k个词的时候,模型只能看到前k-1个词,看不到后面的未来信息。这就是自回归生成的本质:一个词一个词地往右蹦。这个掩码机制实现起来非常微妙,新手做生成任务时如果忘了加或者加错位置,模型训练时Loss会迅速异常,但预测时又是一副什么都对不上来的样子。
流程走完后再看工程实现:所有输入句子会先被padding到同一长度,padding的部分靠注意力掩码让模型忽略。词嵌入维度d_model一般取512,全连接层的隐藏维度则是2048左右。这里有个长盛不衰的经典比例——前馈层的维度通常是嵌入维度的4倍。论文里是512对2048,后来很多大模型沿用这个比例,如果按bert_base的实际参数来看,隐藏层768配前馈层3072也是同一个倍数关系。
2.2 位置编码维度:唯一体现序列顺序的地方
自注意力机制本身不关心词的位置,它把句子当成一个无序的词袋来计算相似度。“我爱你”和“你爱我”在自注意力眼里,如果向量相同,计算出来的权重也完全相同。所以位置信息的注入是一个必要条件,不是锦上添花。
论文原文用的是三角函数的绝对位置编码,公式是PE(pos, 2i) = sin(pos/10000^(2i/d_model)),偶数维度用sin,奇数维度用cos。这个设计有个很有意思的性质:对任意固定的偏移k,PE(pos+k)可以表示成PE(pos)的线性函数。换句话说,模型能从位置编码中学习到相对位置关系,而不只是死记绝对位置。这个数学性质非常优雅,我一直觉得这是论文里被低估的一个亮点。
后来BERT用了可学习的位置嵌入,直接把位置索引映射成一个可训练的向量矩阵。实测下来,对于固定长度不太长的文本任务,两者的效果差距很小。但如果你做的是长文本处理工作,经常会遇到推理长度超过训练长度的场景,三角函数的绝对位置编码在超长外推上表现更稳定一些,因为它本质上是一种连续函数。这方面业界后来又有旋转位置编码和相对位置编码的变体,各有各的优劣,但理解原版的绝对位置编码是一切的基础。实际实现时还要注意拼接长度的问题:如果训练时最长没超过512,在线预测却来了个1000字的输入,需要有个预案,直接用截断还是扩展位置编码的周期,得提前想好。
3. 自注意力机制:整个架构的灵魂算子
3.1 从查询-键-值看注意力计算的本质
自注意力听起来玄乎,其实原理用一个比喻就能说透:想象你在一间会议室里做文档评审,当前关注的问题就是Query(查询),会议室里每个人头顶的标签是Key(键),而每个人的发言内容则是Value(值)。你需要做的事情是:拿当前问题,去挨个对比和每个人的标签匹配程度,再根据匹配度加权汇总所有人的发言内容。放到句子里,每个词都轮流当一次Query,去和其他所有词的Key做点积,得到匹配分数,经过softmax变成权重后,加权求和所有词的Value。整个过程看重的是一个词在当下语境中应该从其他词身上聚合多少信息。
公式只有一个:Attention(Q, K, V) = softmax(QK^T / √d_k) V。这里有两个细节必须扣清楚。第一,为什么除以√d_k?因为当向量维度d_k变大时,点积结果的方差会跟着变大,导致softmax进入饱和区,梯度变得非常小。除以√d_k相当于把方差调节回1左右,让softmax对输入变化保持敏感。第二,点积的优势在于可以用高度优化的矩阵乘法库来实现,速度极快,这也是Google选择点积注意力而非加性注意力的工程原因之一——虽然理论上精度差异不大,但点积能利用GPU矩阵计算的并行能力。
如果把Q、K、V的具体取值拉出来看,你会发现它们其实是输入X分别乘上三个不同的权重矩阵W_Q、W_K、W_V得到的。这三个矩阵都是可学习的参数,训练过程中会不断调整,找到什么样的Query更能匹配什么样的Key,以及最终应该抽取什么样的Value信息。我在实际调参时发现,注意力头的学习对初始化非常敏感,如果初始权重设置不合适,训练前期损失会出现长时间的下平台期,表现为Loss纹丝不动。
3.2 多头注意力:不同子空间的并行协作
与其用单个注意力操作去算全局关系,原文把整个计算拆成h个头(论文里h=8),每个头在维度为d_k = d_model/h的子空间内独立做注意力运算。这背后的直觉是:不同的头可以关注不同类型的依赖关系。我做过一个可视化实验,发现某些头学到的模式类似于语法关系依赖,某些头则能捕捉指代关系,还有一些头隐约对齐了同义释义间的语义关联。
有趣的地方在于,并不是每个头都那么“勤劳”。我在实际项目中有一个很深的体会——相当一部分注意力头的分布趋于均匀,几乎没什么信息量。BERT时代就有研究者做过注意力头重要性分析,通过剪枝实验发现去掉半数注意力头后模型性能几乎不掉。这项工作引出了大模型时代的一些节约资源思路。当然,这也给自己提了个醒:多头不是越多越好,盲目加头会让参数量膨胀,训练更慢且不一定带来收益提升。在实务里,头数选择要匹配序列长度和任务复杂度,对于短文本分类任务,用12个头的BERT规模是合适的,但如果是自己的小模型再堆8个头,效果反而不一定比4个头好。
多头实现完成后,所有头的输出会拼一起,经过一个输出投影矩阵WO做线性变换。这个WO同样参与训练,是整个结构里容易忽略但参数量占比不小的一块。计算参数量时别只盯着W_Q、W_K、W_V,WO矩阵在多头合并阶段的存在价值需要一并计入模型总参数估算。
3.3 为什么要残差连接和层归一化
有了多头注意力之后,架构里还叠加了两个标准组件:残差连接和层归一化。残差连接这里补的正是“恒等映射的路径”,让信息可以无损地从底层传到高层。原始数学表达是输出=LayerNorm(x + Sublayer(x))。这样做的前提是注意力子层的信息增益相对有限,保留原始x能使深层的梯度反传通道更顺畅。如果没有残差连接,20层以上的Transformer网络基本没法稳定训练。
层归一化则是对一个样本的所有特征维度做归一化,和BatchNorm的区别在于后者是跨样本统计均值方差。NLP任务每个样本的序列长度和幅值差异很大,BatchNorm在很多情况下并不能提供稳定收益,而LayerNorm在Transformer这条路上几乎是标配。训练时经常遇到的一种问题是训练和推理行为不一致,绝大多数都源于归一化层的运行统计量维护方式不对,这类问题在推理阶段表现为输出随机波动明显。所以自己写推理代码时,要格外注意是用训练阶段的归一化统计量,还是当前batch的统计量,两者不能混用。
前馈网络子层本身则由两个全连接层和一个ReLU激活函数组成:FFN(x) = max(0, xW1 + b1)W2 + b2。第一层把维度从d_model升到4倍大小,第二层再降回来。这其实是一种逐位置的特征变换,可以理解为对每个词向量做的非线性映射,让模型在更高维的空间里做语义转换。我个人的理解是:注意力负责“汇总信息”,也就是说网络通过注意力机制来决定关注什么;而FFN负责“加工信息”,也就是将注意力筛选出的信息做进一步变换。两个组件各司其职,缺一不可。
4. 为什么是Transformer:三大范式与注意力变体对比选型
4.1 三种架构范式的任务适用场景
Transformer论文本身就是Encoder-Decoder的完整结构,但后来的发展路径分化成了三大流派,选型时有很强的场景导向性。
第一种是Encoder-only架构,BERT引领的流派。因为编码器能双向看到完整句子,所以特别适合理解类任务,比如文本分类、命名实体识别、句子相似度计算。做这类任务时,把编码器输出的[CLS]向量或者所有token的池化向量接一个分类头就行。我在实际做舆情分类项目时,用中文BERT类模型加上简单的全连接分类层,基线上的效果就很能打。
第二种是Decoder-only架构,GPT系列的路线。它保留了掩码自注意力,只能从左往右单向生成,天然适合文本生成场景。最近几年大家发现,把模型规模做到足够大之后,Decoder-only模型在各种任务上表现出了很强的涌现能力,所以现在大模型赛道几乎全是这种结构。它的优势在于结构简洁,统一了预训练和微调的范式,而且更适合做零样本和少样本学习。
第三种是Encoder-Decoder架构,T5和BART代表的路线。它适合需要先理解再生成的场景,例如文本摘要、机器翻译、风格改写。相比纯粹的Decoder-only,这种结构能先对源文本做双向编码,再在解码阶段生成目标文本,所以对于“输入长度较长、输出对输入依赖很大”的任务,效果往往更好。
我在实际项目中的选型经验是:任务如果重判断不重表达,优先考虑Encoder-only;如果任务重创造性表达,比如写文章、写代码、做对话,Decoder-only是更合适的方向;如果输入输出都是整段文本且关联度高,比如摘要和翻译,Encoder-Decoder结构最能贴合需求。这套分类方法可以套用到很多实际项目的架构选型里。
4.2 多种注意力变体的核心改进思路
基础自注意力有个众所周知的问题:计算复杂度是O(n²),n是序列长度。序列一旦涨到几万甚至几十万token,算力需求会让人绝望。为了解决这个痛点,业界出现了大量变体。
Sparse Attention的思路是把全连接的注意力矩阵稀疏化,让每个token只关注邻近区域或特定的全局锚点token,代表是Longformer和BigBird。Local Attention则把序列切成固定窗口,每个token只能看窗口内的内容,复杂度降为O(n),但对超长距离的依赖捕捉能力变弱。Linformer则通过低秩投影把注意力矩阵压缩到固定低维空间,把复杂度降到O(n),前提条件是注意力矩阵具有低秩特性。
另外还有一类思路是把线性化和核方法引入注意力计算,用核函数近似替代softmax的指数运算,实现真正的线性复杂度,代表是Performer。我在做长文本任务时试过其中几种方案,总体感受是省了显存却牺牲了一点精度,尤其对长距离语义建模的影响较为明显。所以如果你处理的文本长度在2048以内,老老实实使用全量自注意力通常是最稳妥的选择;只有明确超长序列是必须解决的核心痛点时,才值得引入稀疏或线性变体。
4.3 大模型时代的Transformer架构演进
把视野拉回到现在的大模型,你会发现很多商业产品和开源模型虽然在工程技术上走了很远,底层仍然能辨认出Transformer的骨架。比如Gated Attention在注意力计算里加入了门控机制,和LSTM里的门控逻辑有异曲同工之妙;RetNet引入了线性递归和分块递归的表征模式,对长序列推理更友好;RWKV把注意力和RNN的优点做了结合,用线性attention代替标准自注意力,在推理成本上大幅降低。
这些探索性进展说明Transformer并不是一个封闭的终点,而是在持续进化的主干道。但我的判断是:短期内全量注意力、多头机制、残差归一化这些内核式贡献仍然不会缺席任何下一代架构,毕竟它们解决的是语义建模和信息传播的基本问题。理解原始Transformer的结构,是理解未来一切变体的第一块积木。如果你刚接触这块,建议不要急着追各种花哨变体,先把经典的Encoder-Decoder逐层实现一遍,自然而然就会对上面的演进逻辑有更深的体会。
5. 模型训练与推理的工程落地要点
5.1 数据处理和词表构建的隐藏门道
聊完架构再看实操。Transformer第一步处理的不是向量而是原始文本,这中间词表构建和数据管道设计的讲究非常多。常见的分词策略主要有三种:Word级别分词简单直接,但词表动辄几十万,而且对未登录词的表示十分棘手;Character级别词表小,但序列长度会变长,信息密度偏低,效果也不好;现在的主流是Subword分词,比如BPE和SentencePiece,它们能在“词”和“字符”之间找到平衡。BPE的做法是统计频繁共现的子串逐步合并成新的子词单元,这样既能覆盖绝大多数常见词,又能在遇到生词时退化为子词甚至字符级表示。
词表大小选择也直接影响模型参数量和训练速度。我做过一组对比实验,词表从3万扩到6万后,模型参数增加了将近1个亿,占用显存随之大幅上升,但下游任务的效果提升微乎其微。如果做中文任务,词表大小在2万到5万之间是比较合理的区间,再往上增加边际收益就很有限了。这里要注意一个细节:不管用哪种分词方式,都需要给词表添加特殊token,常见的有[PAD]、[CLS]、[SEP]、[MASK]以及[UNK]等。它们的索引通常固定在最前面,训练时统一处理,千万别漏了,不然后续填充和掩码都会出错。
5.2 训练过程中的参数配置与稳定化技巧
训练Transformer模型和训练传统神经网络的最大区别在于对超参数的敏感性。模型维度、层数、学习率、批大小、Dropout率、训练步数,这些参数互相影响,牵一发而动全身。对于想要在单卡上训一个小规模Transformer的新手,通常是6层编码器、6层解码器、d_model=512、8头注意力、FFN维度2048的配置起步,这正好是论文的base版本规模。
学习率方面,论文采用了一个很精妙的warmup策略:先线性增长,再按步数的平方根倒数递减。公式是lr = d_model^(-0.5) * min(step^(-0.5), step * warmup_steps^(-1.5))。Warmup的步数通常设为4000到8000步之间。这个设计的原因非常直观:训练初期模型权重还很随机,过大的学习率会让Loss剧烈震荡;先用小学习率让模型找到一个相对稳定的方向,再加大学习率加速收敛,最后逐步衰减保证稳定收敛。我建议这个策略可以原封不动保留,尤其是想做机器翻译这类任务时,能极大避免Loss爆炸的问题。
优化器方面Adam是标配,但为了防止梯度出现极端值,论文还额外加了梯度裁剪,通常clip到1.0左右。正则化主要靠Dropout,论文中dropout率设为0.1,这个取值在绝大多数任务上都经得验证。实际测试时,如果你发现训练集上表现很好但验证集表现不佳,那么增加Dropout率或者加大训练数据是最直观的两条路;如果训练集Loss都降不下去,先查学习率和优化器设置,别急着改模型结构。
5.3 损失函数与推理生成策略
Transformer在训练时用的是交叉熵损失函数,目标就是最大化下一个token的条件概率,在具体实现里往往还叠加了标签平滑这个技巧。标签平滑的做法是:把原来的硬标签(0或1)改成软标签,给错误类别的概率留出一小点份额,比如0.1。这个trick能防止模型过度自信,缓解过拟合,我会在做文本分类和生成任务时都加上,尤其在训练数据量较小时,标签平滑对泛化效果的帮助是非常明显的。
推理阶段和训练阶段的行为完全不同。训练时解码器看到的是完整的金标序列(并且配合mask遮挡未来位置),而推理时只能一个个词地自回归生成。这时解码策略境界差异就体现出来了:贪心搜索只取概率最大的词,速度快但容易陷入重复和局部最优;Beam Search在当前词基础上保留概率最高的前K条候选路径(K通常取3到8),在翻译、摘要类任务上效果较好,但参数量大的生成模型上容易产生过于保守的重复文本;采样策略则从概率分布中随机选择,配合温度参数可以将分布拉平或集中,用于对话和故事生成时效果更自然。我自己的经验是:摘要任务用Beam Search配上长度惩罚,效果最稳;聊天和续写则用采样的温度调节,T值越大文本越发散,T值越小越发确定性,常用区间是0.7到1.0。
5.4 损失函数之外的评估维度
很多新手上手Transformer时习惯只看Loss,但是Loss下降并不代表任务做得好。以机器翻译为例,Loss降到0.5以下,翻译结果可能依然狗屁不通。这时候需要一套更符合人类感知的评估指标。BLEU是机器翻译最常用的指标,它基于n-gram精确率来计算生成文本和参考文本的重合度,对语序的惩罚比较重。ROUGE则被广泛用于摘要任务,它更看重召回率,也就是参考摘要中有多少内容被生成出来了。
这些指标虽然重要,但我强烈建议核心任务上还是做一些人工评估。我出过多次“BLEU高分但读起来别扭”的情况,原因是生成了大量高频词堆砌,或者句子结构虽对但语义偏掉。做产品化项目时,最好建立一个小规模的人工评测集,定期把模型输出拿出来打分,比只看自动指标可靠得多。这也是从做实验走向做产品时最关键的意识转换。
6. 常见问题排查与实战踩坑记录
6.1 训练Loss不下降或者梯度爆炸
这个问题出现的频率极高。先判断是不是数据问题:检查数据预处理是否出错,比如标签错位、padding_index和pad的位置混杂;再判断是不是代码问题,比如注意力掩码构造错误,训练时把未来的token也暴露给了模型,导致Loss异常低或者不收敛;最后查模型本身的初始化是否合理。
梯度爆炸一般表现为Loss突然变成NaN。常见诱因是学习率过大,初始化方式不当,或者在长度很长的序列上出现了极端数值。排查时先在训练循环里加入梯度值打印,观察梯度范数的变化轨迹。如果梯度范数持续在非常高的量级,说明学习率需要下调,或者需要加强梯度裁剪的力度。还有一种隐蔽的情况:混合精度训练时Loss出现NaN,多半和loss scaling策略有关。如果开启自动混合精度后发现不稳定,先试着一个纯FP32的跑通基线,再来排查精度层面的问题。
6.2 注意力可视化结果之我见
把注意力矩阵热力图画出来是一项很有价值的Debug工作。画图前需要把多头注意力的权重导出,然后用热力图库展示。我在项目里发现新手常犯的错误是直接把所有头画在一起复盘,视觉上一团浆糊,根本看不出区别。正确做法是每个头单独画一张图,或者把头和头并排展示。这样才能观察出哪些头在对角线附近集中(通常表示该头过多关注当前位置本身),哪些头形成了清晰的句法关联模式。
对角线集中本身不一定是问题,但如果所有头都集中在对角线上,就说明注意力退化成了逐词的恒等变换,模型没有学到跨词的交互语义。这个情况往往和训练不充分、数据量太小或者块大小设置不合理有关。另外一个观察方向是看padding位置的注意力权重,理想的注意力图在padding区域附近几乎不分配任何权重。如果你发现Padding区拿到了大量注意权重,大概率是注意力掩码没有正确传播到所有层。
6.3 显存溢出与推理速度的优化方向
Transformer对显存的消耗来自两处:一处是模型参数本身及其对应的优化器状态,另一处是中间激活值。以训练为例,如果使用Adam优化器,每个参数需要额外的动量参数和方差参数副本,加上模型参数自身,整体显存开销至少是参数量乘以4,再加上梯度就更多,所以我一般会在项目初期用模型的显存占用量反推允许的batchsize上限。遇到显存溢出时优先检查batchsize、序列长度这两个最容易膨胀的点。
如果这两样都调整到位仍然存不下,再考虑梯度累积、混合精度训练等方案。梯度累积不增加显存但会拖慢单步速度,混合精度则是“免费的午餐”。用一个简单的黄金经验做个总结:先估算模型参数总量,乘以一定的经验系数,再配上序列长度和批量大小,就能大致算出显存的处理器水平需求,避免到训练的时候才傻眼。推理阶段的优化思路则不太一样,可以用KV Cache针对Decoder部分缓存注意力计算的键值对来加速,这是所有生成模型提升吞吐量的标配方案,工程实施上的细节也值得好好钻研。
7. 使用Transformer进行下游任务微调的实际经验
预训练模型在通用语料上学会了语言的基本规律,但这些知识泛而广,并不精确匹配某个业务场景。微调就是把预训练模型迁移到特定任务上的过程。以常见的文本分类为例,在BERT类模型顶上接一个分类头,把句子送进去取[CLS]向量,再过一层线性层和softmax,用任务数据重新训练。
微调时有三点经验值得特别提及。第一是学习率设置:因为预训练模型已经学到了足够好的表征,微调的学习率不能太大,常见的有效学习率在2e-5到5e-5之间,大的学习率会破坏预训练阶段学到的特征;第二是层冻结策略:如果任务数据和预训练语料差异很大,或者数据量很少,可以尝试从底层开始逐层解冻,先只训顶层,再慢慢扩展,这样能有效抑制过拟合;第三是数据增强:与任务无关的轻微噪声增强(比如同义词替换、随机token掩码)在小数据集上可以明显提升微调效果。
到底应该全量微调还是只调部分参数?如果算力充足、任务数据也比较充分,全量微调当然是最佳选项。但真实业务场景常常是数据稀缺的,这时候冻结大部分层,只微调最后几层甚至只需在最后加一个轻量的适配器层,效果也不会差太多。近年很多高效的参数微调方法登场后,全量微调的“不可替代性”进一步下降,尤其是在大模型时代,用很小资源快速适配任务的需求远大于从头训练一个模型的需求。我自己在实际做项目时,小数据量的任务常常只调整很有限的参数,效果已经足够,没必要为了“稳妥”把全部参数都扔进去跑一遍。
8. 我在工程现场的一些个人心得
最后聊几句偏个人向的东西。很多人在接触Transformer时,第一反应是去抠论文公式,然后把架构图背下来。这确实重要,但真正的理解必须建立在亲手实现和跑通实验的基础上。我自己做过的路径是:用开源框架接口直接调现成的Transformer模型,再去读源码里每一个张量维度的变换过程,最后自己从头实现一遍简化版。这个过程走下来,你对这个架构的控制力完全不一样——出问题时你能直接推测是哪一层的形状或者数据流出了问题。
调试Transformer时,强烈建议保存一套完整的断点信息机制,在关键层之间记录张量的均值、方差、最小值和最大值。正常训练的Transformer,激活值的均值和方差应该在一个相对稳定的区间。一旦发现某个张量数值异常暴涨,几乎可以断定梯度或者前向传播过程出现了数值问题。这个方法比直接盯着Loss曲线更早发现问题,尤其是在堆叠深层结构时帮助特别大。
模型除了“调出来”之外,“用起来”还有一套学问。同样一个预训练模型,输入侧是否需要额外构造特征、输出侧是否需要约束解码空间,这些决策在实际业务里甚至比模型的架构选择更影响用户体验。以在线QA系统为例,完全基于标准Transformer的生成结果有时会出现答非所问、内容空洞的问题,可一旦加上了基于业务逻辑的结果过滤和后处理规则,交付物立刻有质的提升。这提醒我们,工程落地的核心永远不是单点模型的性能,而是模型和系统的配合。
Transformer这套架构的设计启发性极强:把顺序信息从硬约束变为软偏好、把全局交互从昂贵操作变为并行可行的矩阵运算,这些思想层面的贡献已经远远超出了NLP本身的领域范围。如果你正准备认真入坑NLP,我的建议是用心把这一套原理解透、动手把一种实现跑通。有了这块基石之后,无论后续面对的是庞大参数的大模型、多模态前端的融合模型,还是层出不穷的新注意力变体,你都不会感到陌生,因为它们都是在同一套核心思想上搭建出来的。