Transformer全链路解析:从输入处理到推理优化的完整指南

发布时间:2026/10/21 0:11:52
Transformer全链路解析:从输入处理到推理优化的完整指南
1. 从一次被问懵的经历说起前阵子有个刚入行的朋友问我“Transformer 到底怎么工作的我看了一堆文章每个部分单独讲都能懂但串起来就懵了。”我当时随口讲了几句 Attention 的公式结果他更懵了。后来我花了一个下午从输入怎么变成向量、Attention 到底在算什么、训练时梯度怎么流、推理时为什么能加速完整地给他捋了一遍他才算真正把这条链路打通。这件事让我意识到一个问题大部分讲 Transformer 的内容都是“切片式”的——单独讲 Self-Attention 的、单独讲位置编码的、单独讲训练技巧的但很少有人把输入处理、注意力计算、训练过程和推理优化这四个环节串成一条完整的线来讲。而恰恰是这条线才是理解 Transformer 的关键。这篇内容就是把我那次讲解的完整思路整理出来。不管你是刚接触深度学习的新手还是已经用过 BERT、GPT 系列模型但对其内部机制一知半解的开发者我都会用最直白的方式把这条链路从头到尾走一遍。你会看到数据怎么一步步流动、每一步为什么这么设计、训练和推理阶段有什么本质区别以及在实际操作中哪些地方最容易踩坑。2. 输入处理文字是怎么变成模型能吃的数字的2.1 从一句话到一串数字的完整流程Transformer 的输入是一段文本但模型只认数字。这中间的转换过程很多人觉得“不就是分词加 embedding 嘛”但细节远比想象中多。假设输入是“我爱深度学习”这句话。第一步是分词Tokenization。中文和英文的分词策略完全不同。英文通常用子词切分比如 BPE 或 WordPiece把“deep learning”切成“deep”和“learning”甚至可能切成“deep”、“learn”、“ing”。中文则更复杂可以按字切也可以按词切还可以用子词算法切。实际操作中大部分中文模型采用字级别或子词级别的混合策略。分词之后每个 token 会被映射成一个整数 ID。比如“我”对应 1024“爱”对应 2048以此类推。这些 ID 本身没有语义含义只是一个索引。接下来通过一个嵌入矩阵Embedding Matrix把每个 ID 转换成一个固定维度的向量。假设模型维度是 512那么每个 token 就变成一个 512 维的浮点数向量。但这里有个关键细节嵌入矩阵是随机初始化的它的值是在训练过程中学出来的。也就是说“我”这个 token 最终对应的向量是模型在大量语料上自己学到的语义表示。语义相近的词它们的向量在空间中距离会更近。这也是为什么 embedding 能捕捉语义关系的原因。2.2 位置编码为什么 Attention 需要额外的位置信息Transformer 和 RNN 最大的区别之一就是它没有循环结构。RNN 天然知道“第一个词”和“第二个词”的顺序因为它是按顺序处理的。但 Transformer 是并行处理所有 token 的如果不加额外信息它根本不知道哪个词在前、哪个词在后。所以需要位置编码Positional Encoding。最经典的做法是正弦余弦编码用不同频率的三角函数生成每个位置的编码向量然后直接加到 token 的 embedding 上。为什么用三角函数因为这种编码方式可以让模型通过线性变换推断出相对位置关系。比如位置 5 和位置 7 的关系可以通过位置 1 和位置 3 的关系推导出来。后来也出现了可学习的位置编码比如 BERT 用的就是这种把位置也当成一个可训练的 embedding。两种方式各有优劣正弦编码泛化性更好理论上可以处理比训练时更长的序列可学习编码更灵活但受限于训练时的最大长度。注意位置编码的维度必须和 token embedding 的维度一致否则没法直接相加。通常做法是 embedding 维度设为 512位置编码也是 512 维逐元素相加。2.3 输入层的实操要点与常见坑在实际操作中输入处理有几个容易出问题的地方。第一个坑是 padding 的处理。一个 batch 里的句子长度不一样短的句子需要补零对齐。但补零之后Attention 计算时这些零位置也会参与导致结果偏差。所以需要注意力掩码Attention Mask把 padding 位置的注意力分数设成负无穷这样 softmax 之后这些位置的权重就变成零了。第二个坑是分词器的选择。同一个预训练模型必须搭配对应的分词器。比如你用 BERT 的分词器去处理 GPT 的输入token ID 完全对不上embedding 查出来的向量毫无意义。这个错误看起来很低级但实际项目中经常有人犯。第三个坑是最大序列长度。每个模型都有最大输入长度限制比如 512 或 1024。超过这个长度的部分会被截断如果关键信息恰好在末尾模型就看不到了。处理长文本时要么分段处理要么用支持长序列的模型变体。3. Attention 机制Transformer 的核心引擎3.1 Self-Attention 到底在算什么Attention 的本质是一个加权求和的过程。每个 token 都会生成三个向量Query查询、Key键、Value值。这三个向量是通过三个不同的线性变换矩阵从输入 embedding 得到的。计算过程分三步算分数每个 Query 和所有 Key 做点积得到一个分数。这个分数表示当前 token 对其他 token 的“关注程度”。归一化把分数除以根号 d_kd_k 是 Key 的维度然后过 softmax。除以根号 d_k 是为了防止点积结果太大导致 softmax 梯度消失。加权求和用归一化后的分数对 Value 加权求和得到当前 token 的输出。用一句话概括每个 token 都在问“我应该关注哪些其他 token”然后根据关注程度把所有 token 的信息加权融合进来。为什么除以根号 d_k假设 Query 和 Key 的每个维度都是独立同分布的均值 0 方差 1那么点积结果的方差就是 d_k。当 d_k 很大时比如 512点积结果会很大softmax 之后会变得非常尖锐梯度几乎为零。除以根号 d_k 之后方差被拉回 1softmax 的分布更平滑梯度更健康。3.2 Multi-Head Attention为什么要多个头单个 Attention 头只能学到一种关注模式。比如它可能只关注语法关系或者只关注语义相似度。但语言中的关系是多维的——语法、语义、指代、位置等等。Multi-Head Attention就是让模型同时学多种关注模式。具体做法是把 Query、Key、Value 分别投影到多个低维子空间每个子空间独立做 Attention最后把结果拼接起来再投影一次。假设模型维度是 512用 8 个头每个头的维度就是 64。每个头在自己的 64 维空间里计算 Attention最后 8 个头的输出拼成 512 维。这样做的好处是不同的头可以关注不同的东西。有的头可能关注相邻词有的头可能关注句法结构有的头可能关注语义关联。实际可视化 Attention 权重时确实能看到不同头有明显的分工。3.3 Attention 计算中的实操细节与性能考量Attention 的计算复杂度是 O(n²·d)n 是序列长度d 是维度。当序列长度很大时计算量和内存占用会急剧上升。比如 n1024 时Attention 矩阵有 100 万个元素n4096 时就有 1600 万个元素。实际优化中有几个常用手段Flash Attention通过分块计算和重计算减少显存访问次数在不改变数学结果的前提下大幅提升速度。稀疏 Attention只计算部分位置的 Attention比如只关注局部窗口或固定模式。线性 Attention用核函数近似 softmax把复杂度降到 O(n·d²)。提示如果你在训练时遇到显存不足的问题优先检查是不是序列长度设得太大了。把长度从 1024 降到 512显存占用能降差不多四分之三。另外Attention 的 mask 操作也很关键。训练时要用因果 mask防止看到未来 token推理时也要用同样的 mask 保持一致性。如果训练和推理的 mask 方式不一致模型效果会明显下降。4. 训练过程模型是怎么学会这些参数的4.1 前向传播从输入到输出的完整链路训练的第一步是前向传播。输入经过 embedding 层和位置编码后进入编码器或解码器堆叠。每一层包含两个子层Multi-Head Attention 和前馈网络FFN。每个子层都有残差连接和层归一化。残差连接的作用是缓解梯度消失让梯度能直接流过网络。层归一化则是稳定训练过程让每层的输入分布保持相对稳定。这两个技术的组合使得 Transformer 可以堆叠几十甚至上百层。前馈网络通常是两层线性变换加一个激活函数ReLU 或 GELU。中间层的维度通常是模型维度的 4 倍比如模型维度 512FFN 中间层就是 2048。这个设计是为了增加模型的非线性表达能力。最终输出经过一个线性层映射到词表大小再经过 softmax 得到每个位置的概率分布。4.2 损失计算与反向传播梯度是怎么流的损失函数通常用交叉熵。对于语言模型任务就是预测下一个 token 的概率分布和真实 token 的交叉熵。损失越小说明模型预测越准。反向传播时梯度从损失函数开始逐层往回传。由于有残差连接梯度可以跳过某些层直接传到前面。但即便如此深层 Transformer 仍然可能遇到梯度消失或爆炸的问题。常用的解决方案包括梯度裁剪把梯度范数限制在一个阈值内防止爆炸。学习率预热训练初期用很小的学习率逐渐增加到设定值避免初期梯度太大导致训练不稳定。权重衰减对参数施加 L2 正则化防止过拟合。注意Transformer 的训练对学习率非常敏感。学习率太大损失会震荡甚至发散学习率太小收敛速度极慢。实际中通常用 Adam 优化器配合 warmup 和余弦退火策略。4.3 训练中的常见问题与调参经验训练 Transformer 时有几个高频问题损失不下降先检查数据有没有问题比如标签是不是错了、分词是不是有问题。然后检查学习率是不是太小或者梯度是不是被裁剪得太狠了。损失震荡通常是学习率太大或者 batch size 太小。可以尝试降低学习率或者增大 batch size。另外梯度累积也可以模拟大 batch 的效果。过拟合训练损失下降但验证损失上升。这时候可以增加 dropout、增大权重衰减、或者用更多数据。Transformer 的 dropout 通常加在 embedding 层、Attention 层和 FFN 层。训练速度慢检查是不是没有用混合精度训练AMP或者数据加载成了瓶颈。混合精度训练可以在几乎不损失精度的情况下提速 30% 到 50%。我自己的经验是训练一个小型 Transformer比如 6 层、512 维度在单卡上大概需要几个小时到一天具体取决于数据量和序列长度。如果是大型模型通常需要多卡分布式训练这时候通信开销会成为新的瓶颈。5. 推理过程训练好的模型怎么生成结果5.1 自回归生成一个 token 一个 token 地往外蹦推理阶段和训练阶段最大的区别是训练时所有 token 是并行处理的推理时只能一个一个生成。这是因为语言模型是自回归的——预测第 n 个 token 时只能看到前 n-1 个 token。具体流程是输入一个起始 token比如s模型输出第一个 token 的概率分布选一个 token 作为输出然后把这个 token 拼接到输入后面再预测下一个如此循环。这个过程叫自回归生成。每一步都要重新计算 Attention但前面已经计算过的 Key 和 Value 可以缓存起来不用重复计算。这就是KV Cache的核心思想。有了 KV Cache每步只需要计算新 token 的 Query然后和缓存的 Key、Value 做 Attention大大减少了计算量。5.2 KV Cache 的原理与显存占用分析KV Cache 的本质是用空间换时间。假设模型有 L 层每层有 h 个头每个头的维度是 d序列长度是 n那么 KV Cache 的显存占用大约是2 × L × h × d × n × 精度字节数以 GPT-3 级别的模型为例L96h96d128n2048用 FP16 精度KV Cache 大约占用 2×96×96×128×2048×2 字节算下来差不多 9.6 GB。这还只是 KV Cache不包括模型参数本身的显存。所以长序列推理时KV Cache 会成为显存瓶颈。优化手段包括量化 KV Cache用 INT8 甚至 INT4 存储显存占用直接降一半或四分之三。分页管理像操作系统管理内存一样管理 KV Cache按需分配减少碎片。滑动窗口只保留最近 n 个 token 的 KV超出的丢弃。5.3 推理加速的常用手段与效果对比除了 KV Cache还有几种常见的推理加速手段手段原理加速效果适用场景量化用低精度表示参数和激活值2-4 倍显存受限、对精度要求不极端蒸馏用大模型教小模型2-10 倍需要部署到边缘设备剪枝去掉不重要的参数或结构1.5-3 倍模型有明显冗余时批处理同时处理多个请求取决于 batch size服务端高并发场景投机采样用小模型草稿、大模型验证2-3 倍对生成质量要求高提示量化是最容易落地的加速手段。现在很多推理框架都支持一键量化精度损失通常在 1% 以内但速度提升非常明显。实际部署时通常会把多种手段组合使用。比如先量化到 INT8再用 KV Cache 优化最后配合批处理。这样一套组合拳下来推理成本能降一个数量级。6. 把四个环节串起来一条完整的数据流6.1 训练和推理的本质区别训练和推理最大的区别在于并行性和目标。训练时所有 token 并行处理目标是让损失最小化梯度能流过整个网络。推理时只能串行生成目标是快速、准确地产生输出。另一个区别是计算图。训练时需要保存中间激活值用于反向传播所以显存占用更大。推理时不需要反向传播可以只保留必要的中间结果显存占用更小。还有一个容易被忽略的区别是数值精度。训练时通常用 FP32 或混合精度推理时可以用 INT8 甚至 INT4。精度降低会带来一定的效果损失但换来的速度提升通常很划算。6.2 从输入到输出的完整链路回顾把整条链路串起来看输入处理文本 → 分词 → token ID → embedding → 加位置编码 → 得到输入向量。编码/解码输入向量经过多层 Transformer 块每层做 Multi-Head Attention 和前馈网络配合残差连接和层归一化。训练前向传播得到预测分布 → 计算交叉熵损失 → 反向传播计算梯度 → 优化器更新参数。推理自回归生成每步用 KV Cache 加速最终得到完整输出序列。这四个环节环环相扣。输入处理决定了模型能看到什么Attention 决定了模型怎么理解上下文训练决定了模型能学到什么推理决定了模型怎么把学到的东西用出来。6.3 实际项目中的经验总结在实际项目中我踩过的坑主要集中在几个地方输入长度和显存的关系序列长度翻倍Attention 的计算量和显存占用翻四倍。所以训练前一定要估算好显存别等到跑起来才发现 OOM。训练和推理的一致性训练时用的 mask、位置编码、分词方式推理时必须完全一致。任何不一致都会导致效果下降。KV Cache 的管理长序列推理时KV Cache 的显存占用可能比模型本身还大。提前规划好显存分配或者用分页管理方案。量化后的精度验证量化之后一定要在验证集上跑一遍确认精度损失在可接受范围内。有些任务对精度敏感量化后效果会明显下降。最后再分享一个小技巧如果你要深入理解 Transformer最好的方式不是看论文而是自己动手实现一个简化版。不用很大2 层、128 维度就够。把输入处理、Attention、训练循环、推理生成都写一遍跑通之后你对整个流程的理解会完全不一样。我当初就是这么干的写完之后再看那些论文很多之前模糊的地方一下子就清晰了。