尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Transformer预测流程全解析:从Embedding到概率输出的LLM核心机制

Transformer预测流程全解析:从Embedding到概率输出的LLM核心机制 1. 从“猜词游戏”到“概率大师”理解LLM预测的本质当你和ChatGPT聊天或者让Claude帮你写代码时你有没有想过这个“聪明”的模型本质上是在玩一个极其复杂的“猜词游戏”它每次只输出一个词Token然后基于你输入的所有词和它自己已经输出的词去猜下一个最可能出现的词是什么。这个看似简单的“猜下一个”动作背后却是一套名为Transformer的精密架构在支撑。今天我们不谈空洞的理论就从最直观的“预测”行为出发亲手拆解一遍Transformer是如何完成这个核心任务的。你会发现从你输入“今天天气”开始到模型输出“不错”为止中间经历了一场由Embedding词嵌入、Self-Attention自注意力和Feed-Forward Network前馈网络协同完成的、基于概率的复杂计算风暴。理解了这个流程你就能明白为什么大语言模型LLM时而惊艳时而“胡言乱语”以及我们该如何更好地与它协作。2. 预测流程全景图Transformer的“三步走”策略在深入细节之前我们先建立一个宏观认知。Transformer模型预测下一个Token并不是一个黑箱魔法而是一个清晰、可重复的三阶段流程。我们可以把它想象成一个高效的信息处理工厂。第一阶段输入编码与上下文感知。这是准备原料的阶段。你的文本输入比如“今天天气真”被切分成一个个Token然后转换成计算机能理解的数字向量即Embedding。但这还不够模型还需要知道每个词在句子中的位置位置编码以及在整个输入序列中哪些词和哪些词关系更密切。这一步的核心就是Self-Attention机制它让模型能够“纵观全局”理解“今天”和“天气”之间的紧密关联而不是孤立地看待每个词。第二阶段特征深化与非线性变换。经过Self-Attention处理后的向量已经包含了丰富的上下文信息但还不够“深刻”。前馈神经网络FFN就像一个强大的特征提取器它对每个位置的向量进行独立的、复杂的非线性变换进一步挖掘和组合特征为最终的决策提供更强大的表征能力。你可以把它理解为对初步加工过的原料进行精炼和提纯。第三阶段概率映射与决策输出。这是最终出结果的阶段。经过层层处理得到的最终向量会被送入一个线性层通常称为LM Head映射到一个巨大的词汇表上计算出一个概率分布。这个分布就代表了模型认为下一个Token是词汇表中每一个词的可能性。最后通过一个采样策略如贪婪搜索、核采样等从这个概率分布中选出一个词作为输出。模型输出这个词后会把它作为新的输入的一部分继续预测再下一个词如此循环直到生成完整的回答。这个“编码-深化-决策”的三步流程在模型的每一个解码层对于纯解码器模型如GPT系列或解码器部分对于编码器-解码器模型中都会循环进行。接下来我们就深入到每一个步骤的“车间”里看看具体是如何运作的。2.1 第一阶段从文本到向量——Embedding与位置编码一切始于将人类语言转化为机器语言。假设我们的输入是“今天天气真”。首先模型通过一个分词器Tokenizer将其切分成Token例如[“今”, “天”, “天”, “气”, “真”]。每个Token都会被分配一个唯一的ID。Embedding查找模型内部维护着一个巨大的查找表称为Embedding矩阵。其维度是[词汇表大小V, 隐藏层维度d_model]。例如词汇表有5万个词隐藏层维度是768那么这个矩阵就是50000x768。我们根据每个Token的ID从这个矩阵中取出对应的一个768维的行向量。这个向量就是该Token的初始数学表示。它已经蕴含了该Token的语义信息通过模型在海量数据上训练学习得到“天气”的向量和“下雨”的向量在空间上会比和“苹果”的向量更接近。注意同一个汉字在不同语境下可能是不同的Token。例如“银行”和“一行代码”中的“行”在高质量的分词器中很可能被分成不同的Token拥有不同的ID和Embedding这有助于模型区分多义词。位置编码的不可或缺性然而上面的过程丢失了至关重要的顺序信息。“天气今天真”和“今天天气真”的Embedding序列看起来可能一样如果分词结果相同但语义完全不同。Transformer不像RNN那样天然具有顺序处理能力因此必须显式地注入位置信息。这是通过位置编码实现的。位置编码的实现最经典的是使用正弦和余弦函数来生成位置编码向量PE(pos, 2i) sin(pos / 10000^(2i/d_model))和PE(pos, 2i1) cos(pos / 10000^(2i/d_model))。其中pos是Token在序列中的位置012...i是向量维度的索引。这样生成的编码对于每个位置都是独一无二的并且模型能够轻松学会相对位置关系因为正弦函数具有sin(posk)可表示为sin(pos)和cos(pos)的线性组合的性质。最终Token的Embedding向量和其位置编码向量会相加得到既包含语义又包含位置信息的综合向量作为后续处理的输入。实操心得在实际看代码或理解模型时你会经常看到token_embeddings position_embeddings这个操作。这就是信息融合的关键一步。有些现代模型如RoPE旋转位置编码采用了更优雅的融合方式但核心目标不变让模型知道“谁在哪儿”。2.2 第二阶段的核心Self-Attention——模型如何“分配注意力”这是Transformer的灵魂也是它相比过去RNN、LSTM模型取得突破的关键。Self-Attention机制让模型能够在处理序列中任何一个Token时“直接看到”序列中所有其他Token的信息并动态决定关注谁、关注多少。1. 创建Query, Key, Value对于输入序列中的每一个Token的融合向量假设维度是d_model我们通过三个不同的线性变换矩阵W_Q,W_K,W_V分别将其投影到三个新的空间得到Query查询、Key键、Value值向量。它们的维度通常是d_kKey的维度。为什么需要三个可以这样类比Query代表当前Token发出的“询问”“我应该关注谁”Key代表序列中每个Token的“身份标签”用于匹配Query。Value代表每个Token真正要提供的“信息内容”。2. 计算注意力分数接下来我们用当前Token的Query向量去和序列中所有Token包括它自己的Key向量做点积。点积的结果越大说明两者的相关性越高。例如在处理“真”这个Token时它的Query与“天气”的Key点积分数可能很高而与“今”的Key点积分数可能较低。这样就得到了一系列原始分数。3. 缩放与归一化原始点积分数可能会随着向量维度d_k增大而变得非常大导致Softmax函数进入梯度极小的区域。因此需要将分数除以sqrt(d_k)进行缩放。然后对缩放后的分数应用Softmax函数将其转化为一个概率分布所有分数之和为1。这个分布就是“注意力权重”。它清晰地告诉我们对于当前Token而言序列中每个Token的“重要程度”是多少。4. 加权求和输出最后我们用这个注意力权重对各个Token的Value向量进行加权求和。权重高的Value向量对最终结果的贡献就大。这个加权求和的结果就是当前Token经过Self-Attention处理后的新向量。它不再仅仅是自身的原始信息而是融合了全局上下文信息后的“增强版”表示。多头注意力为了增强模型的容量使其能够同时关注来自不同表示子空间的信息Transformer采用了“多头注意力”。简单说就是把上面的过程并行做很多次例如12次或16次即12或16个头每次使用不同的W_Q, W_K, W_V矩阵从而得到多个不同的上下文增强向量。最后把这些向量的结果拼接起来再通过一个线性层W_O投影回d_model维度。为什么Self-Attention如此强大因为它解决了长距离依赖问题。在RNN中信息需要一步步传递距离越远越容易衰减或遗忘。而Self-Attention让任意两个位置Token的直接“通信”成为可能无论它们相隔多远计算复杂度都是常数级的不考虑序列长度对计算资源的线性增长。这使得模型能够更好地把握全局语义。2.3 第二阶段补充前馈网络与残差连接经过Self-Attention层后我们得到了包含丰富上下文信息的向量。接下来它们会进入一个前馈神经网络。这个FFN对序列中每个位置的向量进行独立、相同的处理。它通常由两个线性变换和一个激活函数如ReLU或GELU组成FFN(x) W_2 * GELU(W_1 * x b_1) b_2。其中中间层的维度通常会扩大例如d_model768中间层维度d_ff3072然后再投影回来。它的作用是对Self-Attention提取的特征进行非线性变换和组合增强模型的表达能力。残差连接与层归一化这是训练深度网络Transformer通常有数十层稳定性的关键技巧。在Self-Attention层和FFN层都采用了“残差连接”结构。即该层的输出是LayerOutput LayerNorm(x Sublayer(x))。其中Sublayer可以是Self-Attention或FFN。x是输入。x Sublayer(x)就是残差连接它确保梯度可以更直接地回传缓解梯度消失问题。LayerNorm层归一化则对相加后的向量进行归一化使其数值分布稳定加速训练。一个解码层的完整流程因此在一个标准的Transformer解码层例如GPT中的一层里信息流动是这样的输入向量x。多头自注意力层attn_output LayerNorm(x Attention(x))。前馈网络层output LayerNorm(attn_output FFN(attn_output))。输出output作为下一层的输入。这样的层堆叠起来比如24层、48层每一层都在上一层的“理解”基础上进行更深层次的上下文融合和特征提取。3. 从向量到词汇最终的概率决策层经过所有Transformer层的深度处理后我们得到了序列中最后一个位置即我们正在预测的下一个Token的位置的输出向量。这个向量维度是d_model它浓缩了整个输入序列和已生成序列的全部复杂信息。现在我们需要将它“翻译”回人类语言。线性投影LM Head这一步通过一个简单的线性层没有激活函数实现。这个线性层的权重矩阵形状是[d_model, vocab_size]。它将d_model维的向量映射到vocab_size维词汇表大小的向量上。这个映射操作可以理解为为词汇表中的每一个候选Token计算一个“得分”logit。Softmax转换为概率得到的vocab_size维的得分向量数值范围可能很大且正负不定。我们对其应用Softmax函数P(token_i) exp(logit_i) / sum(exp(logit_j)) for j in vocab。这个操作将所有得分归一化转化为一个概率分布。分布中每个位置的值就代表了模型预测下一个Token是该位置对应词汇的概率。例如概率分布可能在“不错”这个词上概率最高比如0.6在“很好”上次之0.3在“糟糕”上概率很低0.001。采样策略得到了概率分布如何选择最终的输出Token呢这里有几种常见策略贪婪搜索直接选择概率最高的那个Token。简单高效但容易导致生成结果重复、单调。随机采样完全按照概率分布随机选取。结果多样但不稳定可能产生不合逻辑的词。核采样这是目前主流方法。它先对概率分布进行排序然后只保留概率累积和达到某个阈值如0.9或0.95的最高概率Token集合在这个集合内重新归一化概率并随机采样。这样既避免了选择低概率的奇怪Token又引入了随机性使生成结果在连贯性和多样性之间取得平衡。温度调节在Softmax之前将logits除以一个温度参数T。T1是标准情况T1会使概率分布更平缓增加多样性T1会使概率分布更尖锐增加确定性更像贪婪搜索。模型输出选中的Token例如“不错”后会把这个Token的ID加入到输入序列的末尾然后整个流程重新开始预测再下一个Token如此循环往复直到生成结束符或达到最大长度。4. 训练与推理的差异为什么预测时看不到未来理解Transformer预测流程必须分清两个模式训练和推理。训练阶段Teacher Forcing在这个阶段模型拥有“标准答案”。我们给模型输入一个完整的句子例如“今天天气真不错”但会使用一种叫“掩码”的技巧。在计算Self-Attention时我们会使用一个注意力掩码矩阵确保每个Token在计算注意力时只能“看到”它自己以及它之前的Token而不能“看到”它之后的Token。这就是所谓的“因果掩码”或“解码器掩码”。模型的任务是基于已知的前文去预测下一个Token。损失函数就是比较模型预测的概率分布和真实的下一个Token“标准答案”之间的差异通常用交叉熵损失。通过海量数据的训练模型逐渐学会如何根据前文生成合理的后文。推理/生成阶段这就是我们日常使用的模式。此时没有“标准答案”。模型从给定的提示Prompt开始每次只生成一个Token并将其追加到输入中然后预测下一个循环进行。这个过程是自回归的。每一步的预测都严格依赖于已有的全部Token完全模拟了训练时的条件。这就是为什么模型在生成时不能“偷看”未来的原因——它在训练时就没学过这么做它的架构因果掩码也物理上禁止了这么做。一个关键技巧KV缓存在自回归生成过程中每次预测新Token时输入的序列都在变长增加了一个刚生成的Token。如果每次都从头计算所有Token的Key和Value向量计算量会随着生成长度平方级增长极其低效。因此在实际推理中会使用KV缓存。即在计算第t步时我们已经缓存了前t-1个Token的Key和Value向量。当计算第t个Token的Self-Attention时只需要计算当前新Token的Q、K、V然后将其K、V加入缓存再用当前Token的Q去和缓存中所有K计算注意力即可。这大大提升了长文本生成的效率。5. 常见问题与实战排查指南理解了原理在实际应用或学习过程中你可能会遇到一些典型问题。下面这个表格整理了一些常见现象、可能原因和排查思路。现象可能原因排查思路与解决方法生成内容重复、循环1. 采样温度过低接近贪婪搜索。2. 重复惩罚参数设置不当或未启用。3. 模型在训练数据中见过大量重复模式。1.调高温度参数如从0.7调到0.9或1.0。2.启用并调整重复惩罚如repetition_penalty1.1惩罚已出现过的Token。3. 尝试核采样并降低top_p值如0.9限制候选集。生成内容无关、胡言乱语1. 采样温度过高随机性太强。2. 输入Prompt不清晰或存在歧义。3. 模型本身在特定领域知识不足或训练不充分。1.降低温度参数增加生成确定性。2.优化Prompt提供更明确的任务指令和上下文。3. 尝试使用更专业的领域模型或在Prompt中提供少量示例Few-shot。生成突然中断或输出结束符1. 达到了预设的最大生成长度。2. 模型输出了结束符如endoftext生成速度非常慢1. 模型参数量大硬件资源GPU显存不足。2. 未启用KV缓存导致计算复杂度随序列长度平方增长。3. 使用高精度计算如FP32而硬件更适合FP16/BF16。1. 考虑使用模型量化如GPTQ, AWQ来减小模型体积和内存占用。2. 确保推理框架如vLLM, Hugging Facetransformers的KV缓存已启用。3. 使用混合精度推理AMP在保持精度同时提升速度。对于长Prompt模型似乎“忘记”了开头的内容1. 这是Transformer架构的固有问题注意力机制会逐渐稀释远处Token的信息。2. 位置编码在超长序列下外推能力可能不足。1. 这是当前LLM的核心挑战之一。可尝试使用具有长上下文优化的模型如支持128K、1M上下文。2. 在Prompt设计上将最关键的信息放在靠近结尾的位置或在中途进行关键信息重述。Token数量与字符/单词数对不上1. 分词器Tokenizer的分词方式不同。例如英文子词切分如“playing”-“play”“ing”中文按字或词切分。2. 特殊Token如开始、结束、填充Token占用了额度。1. 这是正常现象。使用模型对应的Tokenizer对文本进行编码查看具体的Token ID列表以理解其分词规则。2. 在计算API调用成本或上下文窗口时务必以Token数为准而非字符数。实操心得调试生成效果当你对生成结果不满意时一个系统性的调试流程是先调Prompt再调参数最后考虑换模型。Prompt工程是第一位的。确保你的指令清晰、具体必要时提供角色设定和输出格式示例。一个模糊的Prompt再好的模型和参数也救不了。参数调整有顺序通常先调整temperature(温度) 和top_p(核采样参数)这两个对生成风格影响最大。如果遇到重复再考虑repetition_penalty。max_new_tokens根据需求设置。理解模型的局限性没有哪个模型是万能的。通用模型在专业领域必然不如领域模型。如果经过多次Prompt优化和参数调整仍无法达到要求就该考虑寻找或微调一个更垂直的模型了。6. 超越基础现代LLM预测流程的演进与优化最初的Transformer架构为LLM的预测能力奠定了基础但工业界和学术界一直在对其进行优化以解决效率、长度和性能问题。1. 效率优化注意力机制的变体原始的Self-Attention计算量和内存占用随序列长度呈平方级增长这限制了模型处理长文本的能力。因此涌现了许多高效注意力变体FlashAttention通过精妙的IO感知算法在GPU上重组计算顺序大幅减少对高带宽内存的访问从而极大提升注意力计算速度并降低内存占用已成为当前训练和推理的标配。稀疏注意力/局部注意力如Longformer、BigBird让每个Token只关注局部窗口和少量全局Token将计算复杂度从O(n²)降至O(n)从而处理极长序列。MQA多查询注意力与GQA分组查询注意力这是推理效率优化的关键。在标准的MHA中每个头都有一组独立的K、V向量缓存开销大。MQA让所有头共享同一组K、VGQA是折中方案将头分成若干组组内共享K、V。这两种方式能显著减少KV缓存的内存占用提升推理吞吐量对生成质量影响很小被Llama 2/3等模型广泛采用。2. 长度外推与位置编码进化传统正弦位置编码在训练长度之外泛化能力差。新的方案致力于提升模型的长上下文能力RoPE旋转位置编码这是当前主流用于LLaMA、GPT NeoX等。它通过旋转矩阵将绝对位置信息注入到Token向量的每一对维度上不仅保持了相对位置关系还具有良好的长度外推性。理论上可以在训练时用较短序列推理时处理更长的序列。ALiBi注意力线性偏置直接在注意力分数上添加一个与相对距离成负比的偏置项惩罚远距离的注意力。这种方法训练出来的模型其长度外推能力非常出色。NTK-aware Scaled RoPE等动态插值方法为了在不重新训练的情况下让基于RoPE的模型适应更长的上下文人们提出了在推理时动态调整RoPE基频的方法这相当于对位置编码进行“拉伸”使其能覆盖更长的位置索引在实践中取得了不错的效果。3. 推理加速技术为了让LLM更快地生成除了优化注意力还有以下系统级优化量化将模型权重和激活值从高精度如FP16转换为低精度如INT8、INT4甚至更低。这能大幅减少模型内存占用和带宽需求提升推理速度。GPTQ、AWQ、GGUF等是常见的后训练量化方法。推测解码用一个小的“草稿模型”快速生成多个候选Token然后用原始大模型并行验证这些候选Token一次性接受多个正确的Token。这能将生成速度提升数倍。Medusa、Eagle等是其中的代表。操作符融合与内核优化将模型中的多个连续操作如LayerNorm的归一化计算融合成一个CUDA内核执行减少内核启动开销和内存读写次数。理解这些演进能帮助你在选择模型、部署服务和进行优化时做出更明智的决策。例如如果你需要处理超长文档就应该关注采用了FlashAttention和高效位置编码如RoPE外推的模型如果你追求极致的推理速度那么支持MQA/GQA和4bit量化的模型会是首选。7. 从原理到实践动手观察预测流程理论说了这么多最好的理解方式就是动手观察。这里提供一个极简的概念性代码片段帮助你串联起整个流程使用PyTorch和Hugging Face Transformers库示意。import torch from transformers import AutoTokenizer, AutoModelForCausalLM # 1. 加载模型和分词器 model_name gpt2 # 以一个小模型为例 tokenizer AutoTokenizer.from_pretrained(model_name) model AutoModelForCausalLM.from_pretrained(model_name) model.eval() # 切换到评估模式 # 2. 准备输入 prompt 今天天气真 inputs tokenizer(prompt, return_tensorspt) # 返回PyTorch张量 input_ids inputs[input_ids] # tokenizer会自动添加必要的特殊Token如开始符 # 3. 模型前向传播推理 with torch.no_grad(): # 禁用梯度计算节省内存 outputs model(input_ids) # outputs.logits 的形状是 [batch_size, sequence_length, vocab_size] # 4. 提取下一个Token的预测 # 我们关心序列最后一个位置-1的logits因为它基于所有上文预测下一个词 next_token_logits outputs.logits[:, -1, :] # 形状 [1, vocab_size] # 5. 应用采样策略这里用贪婪搜索作为示例 next_token_id torch.argmax(next_token_logits, dim-1) # 选择概率最大的Token ID # 6. 解码成文本 next_token tokenizer.decode(next_token_id) print(f输入: {prompt}) print(f模型预测的下一个Token是: {next_token}) # 7. 查看概率分布可选 probs torch.nn.functional.softmax(next_token_logits, dim-1) top_k_probs, top_k_ids torch.topk(probs, k5) # 查看Top-5可能的结果 print(\nTop-5 候选Token及其概率:) for i in range(5): token_str tokenizer.decode(top_k_ids[0, i]) print(f {token_str}: {top_k_probs[0, i]:.4f})运行这段代码你会看到模型对于“今天天气真”这个Prompt输出了它认为概率最高的下一个Token例如“不错”并列出其他可能的候选。你可以尝试更换不同的Prompt观察模型预测的变化。更进一步你可以深入模型的每一层提取注意力权重可视化模型到底在关注哪些词这将让你对Self-Attention有最直观的感受。踩坑提醒在实际部署中直接使用model.generate()接口会更方便它内部封装了完整的自回归生成循环、KV缓存、采样策略等复杂逻辑。上述代码仅用于教学演示最核心的单步预测过程。另外对于大模型务必注意显存管理使用.to(‘cuda’)将模型移至GPU并在不需要时及时清理缓存torch.cuda.empty_cache()。通过这样从宏观到微观从理论到代码的拆解Transformer如何预测下一个Token的神秘面纱就被彻底揭开了。它不是一个魔法黑盒而是一系列精心设计的数学运算和工程优化的结晶。理解了这个流程你就能更理性地使用LLM更有效地进行Prompt工程并在模型出现“奇怪”行为时有一个清晰的排查方向。这或许就是从一个使用者迈向一个理解者的关键一步。
返回列表