资讯动态

Transformer核心原理详解:注意力机制、模型架构与训练推理实践

发布时间:2026/10/2 21:14:22 来源:尧图企业网站定制
很多做深度学习的朋友都问过我同一句话Transformer到底该怎么理解查了一堆资料看了不少教程要么停在“注意力机制”四个字就没了要么一头扎进论文公式里出不来总觉得隔着一层窗户纸。这篇文章我想用自己的方式把Transformer从整体设计思路、模型架构到里面的核心细节完整地讲一遍尽量让没有基础的朋友也能看懂让有基础的朋友也能挖到一些之前没留意的点。这篇内容适合这几类人看第一次接触Transformer想搭起完整知识框架的初学者、用现成库调模型但想知道内部到底怎么运转的工程开发者、准备面试需要把原理讲清楚的同学。我会先讲Transformer解决了什么问题再去拆解架构里每个模块的作用接着深入到训练和推理阶段的核心机制最后分享一些我在实际使用中踩过的坑和排查思路。1. 内容整体设计与思路拆解1.1 为什么说Transformer是“模型无关架构”的分水岭先聊一个经常被误读的概念——“模型无关架构”。这个词很多时候会让人困惑实际上它想表达的意思是Transformer作为一种基础架构并不绑定特定的下游任务。无论是做自然语言处理、计算机视觉还是语音识别它都能作为统一的骨干网络存在。这让它区别于为某个任务定制的模型设计。在Transformer之前自然语言处理领域的主流是RNN循环神经网络和它的变体LSTM、GRU。RNN的核心思路是按时间步顺序处理输入序列。说白了就是一个字一个字地读句子读到第n个词的时候模型“记忆”里保留的是从第1个词到第n-1个词的信息摘要。这个设计有一个天然的短板——顺序计算导致训练速度慢而且随着序列变长早期信息会被逐渐“遗忘”这就是长期依赖问题。Transformer完全推翻了这套逻辑。它一次性看到整个序列不再一个词一个词地按顺序读。这种设计也带来一个直接的好处训练可以完全并行化。用GPU跑神经网络的人都知道并行计算才是吞吐量的王道。同时它引入的注意力机制Attention Mechanism能够直接建模序列中任意两个位置之间的关系不管这两个位置隔了多远。这两点放在一起成了Transformer碾压RNN的决定性优势。我的理解里Transformer最大的贡献不是某一个具体的模块而是提供了一种全新的“建模思路”把序列数据看作一个全连接的图节点之间通过注意力机制动态计算关联权重再通过多层堆叠来逐步提取高层语义。这种思路后来被移植到图像领域有了ViT被移植到语音领域有了Whisper等模型都是因为它抓住了“关系建模”这个核心。1.2 这篇介绍的核心主线Transformer论文《Attention Is All You Need》其实讲得很简练全文只有七页正文加附录。但正是这种简洁让很多细节需要反复读才能品出来。我梳理了一条适合学习的主线先搞清楚要解决的问题如何高效建模序列数据中的长距离依赖再理解最核心的部件注意力机制是如何计算“谁和谁有关系、关系有多强”的然后看架构多头注意力、前馈网络、残差连接、层归一化、位置编码这些模块各自承担什么职责最后深入训练和推理的细节为什么用Adam优化器、为什么需要学习率预热、推理时的温度参数是怎么一回事按照这条线往下走Transformer就不再是一堆公式的堆砌而是一个各个环节都有明确设计目的的完整系统。我自己当年学的时候就是按这个顺序每一步都先问“它解决什么问题”等全部走完一遍后再回头看论文很多原本觉得突兀的设计也就都顺理成章了。2. 核心细节解析注意力机制与内部原理2.1 注意力机制从“查表”理解Query、Key、Value自注意力机制Self-Attention是Transformer的核心网上讲它的文章也最多但很多解释过于数学化。我换一个生活化的类比来帮助理解它本质上就是一次“检索”。想象你在一个巨大的图书馆里查资料。你手里有一张便签上面写着你想查的主题这张便签就是Query查询向量。图书馆里有无数本藏书每本书的书脊上都贴着标签这些标签就是Key键向量。你的目光在书架上扫过看到每本书的标签后会比较它和你手中便签上主题的匹配程度匹配度高的书你会抽出来看匹配度低的你扫一眼就略过了。而真正被抽出来的书的正文内容就是Value值向量。放在Transformer的场景里注意力的计算分三步。第一步为序列中的每个词生成三个向量Query、Key、Value。这三个向量都是通过原始词嵌入向量分别乘以三个不同的权重矩阵得到的。注意这三个权重矩阵是模型在训练中学习出来的它们决定了模型应该如何从“我要找什么”和“我有什么”这两个角度去表征每个词。第二步计算注意力分数。对于第i个词拿它的Query去和序列中所有词的Key做点积Dot Product得到一个数值。点积的结果可以理解为两个向量的相似度数值越大说明这两个词之间的关系越紧密。但直接使用点积结果有一个问题如果向量维度很大点积结果的方差也会很大导致softmax之后梯度极小。所以论文里除了一个缩放因子——向量维度的平方根√d_k这就是“缩放点积注意力”名称的由来。第三步对分数做softmax归一化得到和为1的权重分布然后用这个权重对所有的Value做加权求和。这个加权和就是第i个词经过注意力层之后的输出。这一步骤的含义是每个词的新表示取决于“它应该从哪些词那里获取多少信息”。用公式表示就是Attention(Q, K, V) softmax(QK^T / √d_k) V。很多人在理解时卡在一个问题上为什么Value和Key、Query长得一样原因在于自注意力Self-Attention里的“Self”——Q、K、V都来源于同一个输入序列。但它们经过不同的线性变换后实际上担任了不同的角色。Query负责“发出询问”Key负责“响应询问”Value负责“提供内容”。同一个词既要去询问别人也要被别人询问还要作为内容被别人提取所以它同时衍生出三个不同的角色向量。2.2 多头注意力机制一个注意力不够那就并行好几个多头注意力Multi-Head Attention这个名字听起来很复杂其实思想非常朴素既然一个注意力层只能从一种角度建模词与词之间的关系那我就并行运行好几个注意力层每个层使用不同的线性变换相当于让模型从多个“视角”去观察输入序列。用一个场景来类比几个人同时看一张照片有人注意人物的表情有人注意背景的环境光线有人注意物体之间的位置关系。每个人看到的重点不同但汇总起来就对照片有了更全面的理解。具体实现上论文里用了8个头。输入向量被分成8组或者通过不同的权重矩阵映射到8个子空间每组独立走一遍注意力的计算流程产生8个不同的输出。这8个输出会被拼接起来再经过一个线性层压缩回原始的维度。一个常见的误区是多头注意力是不是用来替代“单个注意力”的更强版本并不完全是。多头设计带来的一个实际好处是每个头可以专注于不同类型的关系。在实际训练好的模型里研究人员确实观察到不同的注意力头有不同的“专业分工”有的头关注语法依赖关系有的头关注指代消解关系比如“它”指代的是前文中的哪个名词有的头关注位置邻近关系。这种多视角的信息综合比单头注意力捕捉到的模式要丰富得多。但无脑增加头的数量也不行。当头的数量过多时每个头分到的维度太窄反而会降低模型容量而且训练开销也会线性增长。8到16个头是绝大多数模型配置里比较稳妥的选择。2.3 位置编码让模型“看见”顺序Transformer一次性处理整个序列这既是优点也带来了一个严重问题它自己完全感知不到词的先后顺序。句子“我打你”和“你打我”包含的词完全一样如果模型不知道顺序就无法区分这两句话的含义。RNN天然不存在这个问题因为它本来就是按顺序处理的。Transformer要想办法把位置信息“塞”进输入里于是就有了位置编码Positional Encoding。论文用的是基于正弦余弦函数的固定位置编码方案公式长这样PE(pos, 2i) sin(pos / 10000^(2i/d_model)) PE(pos, 2i1) cos(pos / 10000^(2i/d_model))这个公式看上去有点劝退我拆开来讲。pos代表词在句子里的位置从0开始数i代表位置编码向量里的维度下标d_model是嵌入维度。这个公式做的事情是为每个位置生成一组唯一但又有规律的值加到不是拼接词嵌入向量上模型就能通过这部分信息推断出词的相对位置。为什么选正弦和余弦函数论文给出了一个很巧妙的理由因为三角函数的性质位置posk的编码可以表示为位置pos编码的线性变换。这让模型更容易学到“相对位置”的概念——对于语言来说相对位置往往比绝对位置更重要。比如“猫在垫子上面”和“狗在沙发上面”模型需要知道的是“猫”和“垫子”紧挨着的这个相对关系而不是这俩词在整篇文档里的绝对序号。后来也有一些工作做了改进比如用可学习的位置编码、相对位置编码甚至旋转位置编码。但理解正弦余弦方案是理解后续所有位置编码变体的基础。2.4 前馈网络与残差连接非线性变换和深层训练的保障多头注意力算是Transformer架构里的“信息交互”环节但光有它还不够。每层注意力后面都会接一个前馈网络Feed-Forward NetworkFFN这是标准的全连接网络通常包含两层线性变换和中间一个激活函数最常用的是ReLU公式可以写成FFN(x) max(0, xW1 b1)W2 b2这个模块的作用是什么呢注意力机制本质上做的事情是“加权求和”这是一种线性操作多个线性操作的叠加仍然是线性的模型的表达能力就受限了。前馈网络的作用就是引入非线性变换让模型有更强的表达能力对上一层输出的特征做进一步加工。模型先通过注意力层收集信息再通过前馈网络加工信息这两个环节交替出现构成了Transformer每一层的基本结构。那残差连接又是解决什么问题很简单深度学习网络的层数越深越容易出现梯度消失训练就越不稳定。残差连接的做法是把层的输入和输出直接相加这样梯度可以沿着捷径路径直接回传相当于给梯度开了一条高速公路。Transformer每一层都使用了这个结构Add部分就是在做残差连接。层归一化Layer Normalization则是把每个样本的特征向量缩放到均值为0、方差为1的分布上让每层的输入保持在稳定的范围里加速收敛。这里有个容易忽略的细节层归一化和批归一化最大的区别在于批归一化是对同一个特征维度在所有样本上做归一化而层归一化是对单个样本的所有特征做归一化。Transformer选择层归一化是因为在序列任务中每个样本的序列长度可能不同而且训练和推理时batch size的波动会影响批归一化的稳定性层归一化则没有这个顾虑。3. 模型架构全景从Encoder到Decoder的完整流程3.1 Encoder双向输入的编码器是怎么工作的Encoder编码器是Transformer中负责读取输入序列、提取特征的部分由多个相同的层堆叠组成论文中默认是6层。每层内包含两个子层多头自注意力机制和前馈网络每个子层都搭配了残差连接和层归一化。关键是我刚才标注的“自”字。在Encoder的每层注意力中Q、K、V都来自同一个输入序列每个词都可以关注到整个输入序列中的所有词。这意味着Encoder建模的是“双向”上下文——对于第i个位置的词它的新表示同时结合了它前面和后面所有词的信息。这种双向信息对理解任务非常重要。拿“苹果”这个词举例如果它后面跟的是“很好吃”那它是水果如果后面跟的是“发布了新手机”那它是一家公司。Encoder能同时看到前后的信息自然能做出更准确的判断。Encoder还有一个容易被忽略的设计意图各层逐步抽象。越靠近输入层模型关注的是比较浅层的特征比如词的语义、相邻词的关系越靠近输出层模型关注的是更高层的语义信息比如整个句子的主旨意图。这种分层抽象的能力让Encoder输出的向量表示有丰富的层次信息直接喂给下游任务做微调就能有很好的效果。3.2 Decoder带掩码的自注意力和交叉注意力Decoder解码器的结构比Encoder稍复杂一些主要负责根据Encoder输出的信息一步步生成目标序列。每层也由多个子层组成但多了一个“带掩码的多头自注意力”模块还有一个“交叉注意力”模块。带掩码的多头自注意力是Decoder里第一个值得细品的地方。它在计算注意力分数时把未来位置的信息遮住了——具体做法是把未来对应位置的分数设为一个大的负数这样softmax之后权重趋近于0。为什么需要这么做因为在生成第i个词的时候模型不应该看到第i1个词及之后的内容。如果能看到未来的词那不叫生成叫作弊。训练时用Teacher Forcing策略可以一次性把所有位置的词都喂进去如果不加掩码模型就可以“偷看”后文来预测前文学到的能力在推理时完全派不上用场。所以带掩码的注意力是保证自回归生成正确性的关键。交叉注意力是Decoder的第二个子层。这里的Q来自Decoder自身上一层的输出而K和V来自Encoder的输出。它做的事情是让Decoder在生成目标序列时能够“查询”输入序列中哪些部分和当前的生成任务最相关。比如英译中的任务里翻译到某个中文词时模型可以动态地决定它应该重点关注英文源句中的哪个词。这个机制是“注意力”最直观的一种体现。Decoder层里还有一个细节值得注意交叉注意力层的输入K、V来自Encoder这意味着Decoder的层数和Encoder的层数需要匹配才能保证第n层Decoder拿到的是第n层Encoder的输出。论文图里虽然画得很直观但真正实现时这个对应关系很容易写错我在自己写代码时就踩过这个坑。3.3 完整的输入输出流程梳理把整个流程串联起来从输入到输出你可以把它理解成一条组装线。输入阶段原始token序列先经过词嵌入层映射成向量然后叠加上位置编码。之后这些带位置信息的向量进入Encoder经过6层交替的注意力与前馈网络每一步都带残差和归一化。Encoder的输出是一组向量表示每一个输入token对应一个向量这些向量被认为编码了输入序列的全部语义信息。Decoder侧它接收两个来源的信息一个是Encoder输出的“上下文表示”另一个是目标端已有的“已生成序列”。目标序列同样经过嵌入加位置编码然后先经过带掩码的自注意力处理已生成部分彼此之间的关系再经过交叉注意力从Encoder的输出中“汲取”输入序列的信息最后经过前馈网络。Decoder同样堆叠6层最后一层输出的向量经过一个线性层和softmax层得到下一个词的预测概率分布。推理的时候每生成一个词就把这个词拼到已生成的序列后面重新输入Decoder继续预测下一个词。这就是所谓自回归生成Autoregressive Generation的完整过程。3.4 训练时为什么要用Mask掩盖未来的词刚才在Decoder部分我提到了训练时怎么延续“不偷看”的要求。训练阶段如果用真实的目标句子一次性输入Decoder模型理论上可以根据第1个词直接“看到”第2、3、4个词的存在然后利用这些信息来预测第1个位置的词这显然不合理。因此训练时必须使用带掩码的注意力机制来强制模型只能依赖当前位置之前的信息进行预测。这个设计对训练效率也有重要影响。掩码让Transformer可以并行训练——一次前向传播就能计算所有位置的预测结果而不需要像RNN那样逐个时间步展开。并行计算正是Transformer能在大规模语料上训练的关键没有这个设计训练速度可能会慢一到两个数量级。关于掩码实现很多初学者会困惑“为什么不用0而是用负无穷”因为注意力分数经过softmax之后所有位置的概率和为1。如果把未来位置设为0softmax仍然会分配一点非零权重给它。设置为负无穷实际操作中通常用-1e9这样的极大负值softmax计算后这些位置的概率会趋近于0在数值上等于被完全屏蔽。4. 实操过程与核心环节实现训练细节与关键参数4.1 训练稳定性的关键学习率预热与Adam优化器Transformer训练时有一个非常讲究的细节学习率调度策略。论文里使用Adam优化器但搭配了一个特别的学习率方案——先在训练初期让学习率线性增长再按步数的倒数平方根衰减。用公式描述就是lr d_model^(-0.5) * min(step^(-0.5), step * warmup_steps^(-1.5))其中warmup_steps在论文中被设为4000。拆开看这个公式当step小于warmup_steps时学习率随训练步数线性增长当step超过warmup_steps后学习率按1/√step的速率衰减。为什么要这样设计深度学习训练的初学者常常认为学习率越大越快但Transformer这种深层架构初始化后的模型参数状态非常“脆弱”一开始就用大的学习率容易直接把训练带入损失震荡区域导致收敛困难。学习率预热相当于给模型一段“慢启动”时间让梯度更新从小步幅开始把参数调到比较合理的区域后再加大步幅。这和开车起步要先慢后快是一个道理直接踩油门容易打滑。我在复现Transformer时发现warmup_steps不是必须严格等于4000可以根据数据规模调整。小数据集上1000步预热就够了但不要完全去掉预热。去掉预热后很多情况下模型在前期几十步就出现损失激增然后陷入局部震荡很难恢复。4.2 训练时为什么需要Label SmoothingTransformer论文中除了基础架构还提出了一个在训练策略上的重要trick标签平滑Label Smoothing。它把one-hot的硬标签改为一个平滑分布比如正确的类别给0.9其余类别均分剩下0.1。这种做法被作者称为“困惑度可能会升高但提升准确率和BLEU分数”的操作。原因很简单。如果使用硬标签训练模型会被驱动到“对正确类别输出置信度为1其他所有类别为0”的极端状态。这会导致模型过度自信而且为了迎合这种极端目标内部表征会发散泛化能力下降。标签平滑则给模型留了一点“容错空间”让它不必追求绝对极端的输出训练更稳定。我当时也做过对比实验在机器翻译任务上用标签平滑BLEU分数普遍能提升0.5到1个点这个提升幅度在任务里已经非常可观。有一个细节值得注意标签平滑只在训练时使用推理阶段预测概率分布时仍然取argmax或做beam search不会再应用平滑操作。有些框架训练和推理用同一个参数配置稍不注意就会在推理时也加平滑导致概率分布严重失真。4.3 推理阶段的细节Beam Search与温度参数推理阶段训练好的Transformer模型如何生成预测结果最直接的方式是贪心解码Greedy Decoding每一步都选择概率最大的词作为下一个词。这种方式计算快但容易陷入局部最优——就像走迷宫每一步都选看起来最近的路结果可能走进死胡同。因此实际使用中常采用Beam Search束搜索维持多个候选序列同时扩展最终选择整体概率最高的序列。beam size束宽是这里最重要的超参数它决定同时维护多少条候选路径。beam size越大搜索越全面但计算量也成倍增加而且有过犹不及的风险——太大会导致译文偏向“保守”倾向于高频短语组合反而损失多样性。经验上翻译任务beam size取4到8比较合适。温度参数控制的是推理时对概率分布的“锐化”或“平滑”程度。将logits除以温度值后再做softmax当温度趋近于0时分布集中于最高概率的词生成结果更确定温度大于1时分布更均匀生成结果更多样。这个细节在文本生成类任务中显得很关键。如果你需要写代码、总结之类的确定性任务建议温度调低一些如果你在做创意写作或对话生成希望模型输出更“有想象力”可以把温度调高一些。4.4 显存优化与训练配置经验Transformer是显存消耗大户。以BERT-Base规模的模型为例batch size设为32、序列长度512时一张12GB显存的卡可能刚好放得下但稍微把序列长度加到1024就很容易爆显存。这里有几个行之有效的经验技巧。混合精度训练是我最推荐的优化手段。它用FP16存储中间激活值和梯度用FP32维护主权重副本显存占用相比纯FP32训练能下降约一半而且现代GPU对FP16计算有硬件加速训练速度往往也有提升。但要特别注意损失缩放Loss Scaling的设置避免FP16精度下梯度过小被“抹零”。梯度累积是在显存不足时常用的另一种策略。不增大单步的batch size而是分成几个小的micro-batch计算梯度累加后再统一更新参数。这里有个容易踩的坑梯度累积时需要把梯度除以累积步数否则等效学习率会被放大训练容易不稳定。序列长度也是影响显存的大户。注意力机制的显存和序列长度的平方成正比序列长度翻倍注意力部分显存占用变4倍。对超长文本可以尝试分块注意力Block Attention或者用Longformer这类稀疏注意力变体来降低开销。下面把我实际项目里一套比较稳定的训练配置放在这里作参考配置项推荐值说明优化器Adambetas(0.9, 0.98)论文标准配置学习率峰值5e-5 ~ 1e-4微调时建议用较低值从预训练权重开始Warmup步数总步数的5%-10%微调用从头训练可参考4000步Batch Size尽量大但别爆显存能用32就不用16梯度裁剪1.0防止梯度爆炸的最有效保险标签平滑0.1有分类或生成任务的建议开权重衰减0.01AdamW常用配置5. 细粒度原理解读为什么每一步都是这样设计的5.1 从反向传播的角度理解为什么要除以√d_k缩放因子√d_k这个细节很多人第一次看论文时会直接忽略觉得它只是个数值上的调整。但从反向传播角度想这个缩放是稳定训练的必要条件。当两个随机向量Q和K的每个维度都是从标准正态分布采样时它们的点积期望是0但方差是d_k。当d_k比较大时点积结果的标准差变得很大。比如d_k512时点积结果的量级可能到±20甚至更大。这么大的数值经过softmax后会变得极其接近one-hot——也就是概率分布几乎集中在某一个位置上其他位置接近0。softmax在输入很大时会产生极小的梯度因为这些接近0的位置的导数几乎为0主导位置的导数也趋近于饱和区。这会导致反向传播时梯度消失模型无法有效学习。除以√d_k后点积结果的方差被重新标定到1softmax的输入落在温和的区间梯度就能正常流动了。这个技巧放到今天来看仍然是Transformer训练成功的关键前提之一。也正因如此后来的很多实现在替代这个缩放因子时都会非常谨慎不会轻易改动。5.2 为什么Transformer的一个层里需要四种不同模块我再把Encoder单个层的结构重新组合来看多头注意力、残差连接、层归一化、前馈网络。这四个模块协同工作的方式可以类比成一个公司的生产流程。注意力机制是“信息收集”部门负责获取上下文信息残差连接是“物流系统”确保信息在整个流程中不丢失、不中断层归一化是“质检环节”保证每一批“产品”的质量都在合理范围内前馈网络是“加工车间”将收集来的信息做进一步的精细化处理。这四个部门缺一不可而且顺序也有讲究。先做注意力再做前馈网络的原因是要先“得到”信息然后才能“加工”信息。先做残差再做归一化则是为了保证梯度回传的通道足够通畅、参数更新的尺度足够稳定。这些设计看似随意但任何一步调换顺序训练效果都有明显的下降。5.3 从Transformer到ViT为什么图像也能用Transformer还有一点值得提的是Transformer的适用范围并不局限于文本。Vision TransformerViT的出现证明了一个很有意思的现象图像也可以被看成是一种“序列”。ViT的做法是把一张图片切分成固定大小的patch比如把224×224的图片切成16×16的patch得到196个patch每个patch展平后经过线性投影成一个向量。这些patch向量和文本token一样加上位置编码然后直接输入标准的Transformer Encoder。在ImageNet这种大规模数据集上ViT甚至能超过传统的CNN模型。这一现象说明Transformer的“注意力机制”本质上是在做“特征间关系”的建模。文本里词与词之间有关系图像里patch与patch之间也有关系——比如远处的天空patch和近处的建筑patch存在空间关联。只要能序列化理论上就能套Transformer架构。6. 常见问题与排查技巧实录6.1 训练时损失不降问题可能出在哪很多朋友第一次自己从头训练Transformer时会遇到一个非常挫败的现象loss降不下去甚至一直卡在一个水平来回震荡。结合我自己的排查经验最值得怀疑的几个点按优先级排序如下数据检查排在最前面。tokenizer和训练目标是否对齐比如解码器的输入和标签有没有错位一位很多实现里Decoder输入是目标序列去尾标签是目标序列去头如果这个对不齐模型会学到奇怪的映射loss会一直很高。如果用的是HuggingFace的Trainer建议先把代码里的数据管线和batch结构打印出来核对token ids这一步能发现大部分低级错误。其次检查损失函数。交叉熵损失在计算时要忽略填充位置的loss也就是进行padding mask。如果padding位置没有被正确mask掉模型就是在大量无意义的填充符上做预测损失会非常奇怪。然后是学习率问题。前面我提到过去掉warmup、上来就用大学习率很容易导致损失震荡。如果你发现前几百步训练loss像心电图一样狂跳先看看学习率曲线是不是合理。若以上都没问题最后要关注的是数值稳定性。LayerNorm里epsilon设太大会导致特征被过度平滑设太小可能在FP16精度下出现NaN。检查一下模型输出是不是出现了NaN或Inf如果是优先检查是否用了不稳定的初始化方式。6.2 生成内容单一重复如何调整解码策略如果你用训练好的Transformer模型做文本生成发现它老是在重复同一句话先别急着认为是模型训练得不够好先检查推理时的解码策略。如果你用的是贪心解码那重复几乎是必然的。贪心解码每一步只选概率最大的词一旦陷入某个重复回路就出不来了。改用Top-k采样只从概率最高的k个词里采样和Top-p采样累积概率达到p的候选词集合里采样能显著改善多样性。温度也值得调一调。温度过高会让输出变得杂乱无章过低则会让概率分布过度集中输出反而偏向高频词。一般来说创意写作温度可以设在0.7到0.9事实性回答设在0.1到0.3比较合适。如果是beam search导致的重复可以试试把beam size调小或者在损失函数里加一个“重复惩罚”项。6.3 显存不足的常用解决方案这个我在4.4节已经写了一些方法这里补充一个实际案例。有一次我用BERT做长文本分类序列长度512、batch size 16一张16GB的V100跑得还算流畅。但换到序列长度1024后直接爆显存减batch size到8还是不行。最后我做了两个改动把激活函数换成GELU的近似形式虽然说影响很小但更重要的是启用了gradient checkpointing——用计算换显存在前向传播时丢弃中间激活反向传播时重新计算。这一下就把峰值显存降低了约60%训练能跑了代价是训练时间多了大约30%。在显存拮据的情况下这是相当实用的权衡。6.4 常见问题速查表现象可能原因排查与解决方法训练loss居高不下数据对齐错误、padding mask忘记设置检查Decoder输入和标签错位打印batch核对训练loss震荡不止学习率过大、warmup缺失降低峰值学习率给学习率加预热或衰减推理输出全是重复内容解码策略不合适、温度过高或过低改用Top-k/Top-p采样调整温度参数显存直接OOMbatch size过大、序列过长混合精度、梯度累积、gradient checkpointing数值出现NaN或Inf学习率过大、FP16梯度溢出、初始化不当加梯度裁剪、检查Loss Scaling、检查初始化模型输出与输入语言无关交叉注意力维度不匹配或信息没有有效传递检查Encoder输出是否进入了Decoder的交叉注意力层下游任务效果不如预期预训练和微调数据分布差距大增加领域数据继续预训练或用领域语料做增量训练写在最后Transformer这套架构从2017年提出至今已经从一个纯NLP模型演变为整个深度学习领域的基础设施。我自己这几年的一个感觉是很多新模型说到底都是在Transformer骨架上做“局部装修”——改进注意力效率、调整归一化位置、更换位置编码方案。所以把Transformer本身理解透后面再学BERT、GPT、ViT这些模型的时候都能省下很多力气。如果你正在学习这条路线上我建议不要急着去追新出来的各种变体先把这篇里提到的核心机制自己推一遍最好能亲自动手写一个极简版的Transformer哪怕只有一个Encoder层、模型参数量很小跑通一次训练和推理。亲手写完一遍之后你再看任何讲到Transformer的资料都会有一种“原来如此”的踏实感跟单纯看别人讲完全不一样。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑