
部署过大模型的工程师大概都经历过这种纠结模型生成的回答语法通顺、语义连贯但你总觉得某些关键位置“不太稳”。实体名可能拼错数字可能对不上逻辑链条中间断了一环。传统自回归推理只做一次前向就给出答案遇到低置信度 token 时模型既没有机会回头修改也没有机制利用更深层的语义来校正早期误差。DeepMind 最近公开的一个研究方向把注意力放在了“推理时回灌深层激活”上思路很直接在推理阶段把深层已经编码好的激活反馈到更浅层重新计算难度较高的 token从而降低困惑度。它的意义不在于给出一个新训练 Loss而在于重新分配推理期计算的优先级。这篇文章不打算复述论文的每一处细节而是想拆解这条技术路线的原理、收益边界、工程落地方式以及最容易踩的坑。我会先讲清楚困惑度到底在衡量什么再解释深层激活回灌的核心机制然后给出一套可参考的概念性实现流程、评估方法和最佳实践。如果你正在做 LLM 应用落地、推理加速或者模型评测这篇文章值得花十分钟读完。1. 为什么一条“降低困惑度”的研究值得关注放在三年前如果有人说“推理时调整激活能降困惑度”很多人会认为这是学术圈的自娱自乐。但今天不一样。随着模型规模增大真正昂贵的不是训练而是推理。每次让模型重新生成一遍答案都要付出几十亿甚至上百亿参数的前向计算成本。业界常用的提高生成质量手段包括多次采样、自一致性投票、思维链、重排序本质上都是在“多算几遍”的基础上增加决策依据。问题在于这些方法的计算分配非常粗糙无论 token 是简单还是困难都被一视同仁地重新计算。DeepMind 这个方向真正值得关注的地方是它试图把推理期的额外计算集中到“最不确定”的位置上。一个模型在生成Paris这个 token 的时候可能已经非常确定但在生成一段逻辑推理的中间步骤时分布会明显平坦熵值很高。传统解码策略对这两种情况使用同样的计算资源显然浪费了。回灌深层激活的思路是在检测到高不确定性 token 之后利用深层的全局语义信息反向修正浅层表示让模型对困难位置的预测更“笃定”。这相当于给推理过程加了一个“局部放大器”。对 CSDN 读者来说这个方向至少有三层价值。第一它提供了一种不改变模型权重就能改善生成质量的新手段第二它把困惑度这个老指标重新拉回工程评测视野第三它让我们重新思考 token 级别的自回归生成究竟还有多少优化空间。无论 DeepMind 最终是否把这条路线落地成产品它背后的“按需分配推理计算”思想都会成为推理优化的长期趋势。2. 困惑度究竟在衡量什么困惑度PerplexityPPL是语言模型最经典的评估指标之一。它的基础数学定义是对一段文本计算每个 token 的平均负对数似然再取指数。公式可以写成PPL exp( - (1 / N) * sum(log P(token_i | context_i)) )其中 N 是 token 总数。通俗地说模型在预测下一个词时如果平均“犹豫程度”越低困惑度就越低。如果模型对每个位置都给出了接近 1 的预测概率PPL 就接近 1如果模型像抛硬币一样猜PPL 就会很高。但这里有一个老生常谈却容易被忽略的误区困惑度低不等于回答正确。一个模型可能对“中国的首都是北京”给出极高的置信度也可能对一句事实错误的话给出同样高的置信度。困惑度衡量的是模型内部的一致性是“模型觉得自己有多确定”而不是“事实是否正确”。不过这并不意味着 PPL 没有价值。实践中的合理用法是在同一个模型、同一组 prompt 下比较不同解码策略的 PPL。当 PPL 显著下降时说明新策略让模型在预测层面变得更稳定这通常会带来更少的语法断裂、实体错乱和逻辑跳跃。还有一个更细的观察PPL 不应该只看整体平均值。生成一段 200 token 的回答时可能前面 180 个 token 都很好只有最后 20 个 token 出现了漂移。整体 PPL 被大量高置信 token 稀释后看不出问题。更实用的做法是分区间计算 PPL或者按 token 的熵值做分层统计。这样可以把“局部困惑度高”的问题暴露出来。DeepMind 这次选择困惑度作为观察指标正是因为它是 token 级不确定性的直接反映能比较敏感地看出深层激活回灌是否真的改善了预测分布。3. DeepMind 的新思路推理时回灌深层激活要理解“回灌深层激活”先要看一眼标准的 Transformer 前向计算过程。输入 token 经过 Embedding 层后会依次穿过若干个 Transformer 层。每一层都会保留一份隐藏状态hidden state。最后一层的隐藏状态被映射为词表大小的 logits再通过 Softmax 得到下一个 token 的概率分布。在这个过程中存在一个天然的不对称现象浅层表示更多地编码局部语法和词法信息深层表示则更多地编码全局语义和跨 token 依赖关系。当你预测一个长句中的某个中间 token 时这个 token 的最终分布其实已经在深层表示里“见了更多上下文”只是常规解码器没有显式利用这一点去修正早期层的信息。回灌feedback要做的就是把深层已经编码好的激活反馈给浅层。一个典型流程是先做一次正常前向推理拿到每个 token 的预测概率。如果某个 token 的置信度低于阈值就提取该位置若干深层的隐藏状态通过简单的线性映射或残差加法注入到浅层对应位置。然后基于注入后的表示重新做一次局部前向计算得到修正后的预测分布。这个过程可以循环若干轮每轮都让浅层表示向深层语义靠拢。这里有一个直观类比写论文初稿时第一遍往往只求把内容铺出来语言粗糙逻辑松散。拿到整篇稿子后你会把整篇文章的脉络记在心里然后再回头看某一段写得不顺的地方用“整篇文章想表达什么”来重写这一段。回灌深层激活就是在模拟这个“回读修改”的过程只不过把“整篇文章的思想”编码成了深层激活向量。需要特别区分的是这个思路既不同于思维链CoT也不同于常见的自我修正Self-Correction。CoT 通过增加中间推理步骤来提升表现它的额外计算发生在 token 序列层面。自我修正是生成完整回答后再让模型审阅并修订。而回灌深层激活的额外计算发生在表示空间内部不增加 token 数量也不要求模型“说一句反思的话”而是直接调整内部 activation。这意味着它的计算开销更可控也更适合对延迟不敏感的离线推理场景。还要澄清一点回灌不是把网络结构改成循环网络。它的核心思想是“推理阶段人为构建反馈路径”而不是“训练时使用反馈连接”。这个设计上的差异很重要因为它意味着任何已训练好的 Transformer 模型理论上都可以在解码阶段套上这一层策略不需要重新训练也不需要微调。对于已经部署的模型来说这是一个很友好的优化方向。4. 核心技术机制拆解4.1 标准自回归解码的流程我们先明确基线。标准自回归解码每一步只做一次前向传播输入当前已有的 token 序列。经过全部 Transformer 层得到最后一层隐藏状态。映射到词表空间得到 logits。根据解码策略贪心、采样、束搜索选出下一个 token。拼接到序列末尾继续下一次迭代。这个流程的优点是简单、快。缺点也很明显模型只能“一条路走到黑”如果某个中间 token 选错了后续所有生成结果都会受到影响。KV Cache 的存在略微缓解了重复计算问题但并没有改变“只前向一次”的核心逻辑。4.2 深层激活回灌的关键环节在回灌流程中标准解码被替换成“检测—提取—注入—重算”四个阶段。第一阶段是低置信度检测。模型完成前向传播后会得到当前位置的概率分布。通常可以用最大概率、熵值或者 margin最大概率减次大概率来判断这个 token 是否值得回灌。低于阈值的 token 才进入回灌流程高置信度 token 直接解码避免不必要的计算浪费。第二阶段是深层激活提取。从最后一层或倒数若干层的隐藏状态中取出当前 token 位置的激活向量。这个向量包含了模型对全局上下文的整合信息是“回灌”的内容来源。选择哪一层作为信息源会影响效果太浅的层语义不足最后一层又可能过于贴近输出层。实际工程中往往需要尝试不同层组合。第三阶段是注入。把深层的激活向量注入到选定的浅层位置。注入方式可以是简单相加、拼接后经过线性投影或者通过一个小型 Gate 网络控制混合比例。从计算效率角度看简单加法代价最低从表达能力角度看带 Gate 的线性组合更灵活。第四阶段是局部重算。注入完成后从浅层开始重新执行后续若干层的前向计算得到新的 logits。这里不一定要重算全部层只重算从注入层到最后一层的路径即可这样可以控制计算量。重算后如果新分布的最大概率显著提高说明回灌有效如果变化不大就停止循环避免陷入无意义的反复。4.3 回灌与 Test-Time Compute 的关系业界把推理阶段的额外计算统称为 Test-Time Compute。近几年出现的多数方案比如 Best-of-N、自一致性、Tree Search本质上是“构建多个候选路径再从中挑一个”。这类方案的计算量通常成倍增长。回灌深层激活的不同之处在于它选择了另一个维度不增加路径数量而是在表示空间中迭代修正。它更接近数值优化中的“利用梯度信息修正当前解”只不过这里的“梯度”被替换成了深层激活。这样设计的好处是计算量的增长是线性的而且只在低置信度 token 上发生。假设一个回答有 200 个 token其中只有 20 个 token 低于置信度阈值回灌的额外成本就只集中在这 20 个位置上而不是翻倍重跑整个序列。这种“局部性”控制让它比 Best-of-N 更适合预算受限的场景。4.4 收益边界在哪里从原理上推断回灌深层激活最可能带来明显收益的场景是那些对局部 token 的精确性要求高、且上下文依赖强的任务。比如代码生成一个变量名在前面定义后面引用时模型应该把它写对错误 token 往往局部概率不高。长文档摘要、多跳问答、结构化数据生成也类似因为这些任务里的正确 token 高度依赖全局上下文。反过来如果一段文本就是简单的事实枚举模型本身的置信度已经很高那么回灌的空间就很有限。这个方向不是万能的它的价值上限取决于“模型浅层表示和深层表示之间存在多少信息差”。5. 概念性实现示例下面用一个最小示例来说明标准解码和回灌解码的流程差异。注意这段代码是概念性伪代码目的是展示核心逻辑不绑定任何具体深度学习框架。不同模型的层索引、隐藏状态接口、局部前向实现方式各不相同实际接入时需要替换成对应框架的 API。5.1 标准解码与回灌解码对比# 文件路径example_feedback_decode.py # 说明概念性伪代码用于展示推理时回灌深层激活的流程。 def standard_decode(model, input_ids, max_new_tokens): generated input_ids for _ in range(max_new_tokens): logits model(generated) next_id argmax(logits[:, -1, :]) generated concat(generated, next_id) return generated def feedback_decode(model, input_ids, max_new_tokens, shallow_layer2, deep_layer-1, confidence_threshold0.6): generated input_ids for _ in range(max_new_tokens): # 1. 正常前向同时拿到 logits 和全部层的隐藏状态 logits, all_hidden model.forward_with_hidden(generated) last_logits logits[:, -1, :] max_prob max(softmax(last_logits)) # 2. 置信度足够高时直接解码不做回灌 if max_prob confidence_threshold: next_id argmax(last_logits) generated concat(generated, next_id) continue # 3. 提取深层激活并注入到浅层 deep_activation all_hidden[deep_layer][:, -1, :] # 取最后一个 token 的深层激活 shallow_state all_hidden[shallow_layer][:, -1, :] # 浅层当前状态 updated_state combine_activation(shallow_state, deep_activation) # 4. 基于注入后的表示做一次局部前向重新计算 logits new_logits model.forward_from_layer(updated_state, start_layershallow_layer) next_id argmax(new_logits[:, -1, :]) generated concat(generated, next_id) return generated这段代码里有几个关键点。forward_with_hidden表示前向的同时返回所有层的隐藏状态这是获取深层激活的基础。combine_activation是注入函数实际实现中可以是简单的向量加法也可以是线性投影。forward_from_layer表示从某个浅层开始重新执行前向而不是从 Embedding 开始这样可以在修正浅层表示的同时避免重复计算前面的层。5.2 回灌循环控制逻辑一次回灌不一定就能解决问题。模型接收深层激活后新分布可能仍然不够确定。这时可以设计一个循环让回灌过程执行多轮直到满足停止条件。但必须设置轮数上限和退出条件否则会出现无意义的反复计算。# 文件路径feedback_loop.py # 说明回灌循环控制包含退出阈值和最大轮数限制。 def feedback_with_loop(model, shallow_state, deep_activation, max_rounds3, exit_confidence0.7): current_state shallow_state best_id None best_prob -1.0 for round_idx in range(max_rounds): # 将深层激活注入当前状态 updated_state combine_activation(current_state, deep_activation) new_logits model.forward_from_layer(updated_state, start_layer0) probs softmax(new_logits[:, -1, :]) candidate_id argmax(probs) candidate_prob max(probs) # 如果这一轮没有取得进步提前终止 if candidate_prob best_prob: break best_id candidate_id best_prob candidate_prob # 达到退出置信度提前结束 if best_prob exit_confidence: break # 用更新后的状态作为下一轮的浅层状态 current_state updated_state return best_id, best_prob这个循环有两个退出条件一是置信度超过exit_confidence说明回灌已经产生了稳定结果二是新分布概率不再增长说明继续迭代没有额外收益。这两种条件缺一不可。如果没有最大轮数限制模型可能在两个 token 之间反复横跳白白消耗计算资源。5.3 实验配置示例工程实现时可以把回灌相关的参数抽取成配置文件方便在不同任务上快速切换策略。以下是一个 YAML 配置示例字段都做了注释方便理解。# feedback_decode_config.yaml model: name: your-llm-model max_length: 2048 feedback: enabled: true shallow_layer: 2 # 回灌目标层也就是注入发生的位置 deep_layer: -1 # 深层激活来源层-1 表示最后一层 inject_mode: linear # simple_add / linear / concat 三种可选 exit_confidence: 0.7 # 置信度超过该值则停止回灌 max_feedback_rounds: 3 # 每个 token 最多回灌几轮 low_conf_threshold: 0.6 # 只有概率低于该值的 token 才触发回灌 eval: dataset: your_eval_set batch_size: 8 save_results: trueshallow_layer和deep_layer是回灌质量最重要的两个开关。如果浅层选得太靠前注入的信息会经过太多层传播效果可能被稀释如果选得太靠后注入前后差异不大回灌就失去了意义。inject_mode直接决定混合方式simple_add最省算力linear更稳concat表达力更强但需要额外的投影矩阵。建议先用simple_add跑通完整流程再逐步尝试其他模式。5.4 困惑度评估脚本完成一段生成后可以用下面的脚本计算困惑度用来对比标准解码和回灌解码的效果。脚本基于常见的 HuggingFace Transformers API 风格同样以示意为主。# 文件路径eval_perplexity.py import math import torch def compute_perplexity(model, tokenizer, text): encodings tokenizer(text, return_tensorspt) input_ids encodings.input_ids with torch.no_grad(): outputs model(input_ids, labelsinput_ids) loss outputs.loss ppl math.exp(loss.item()) return ppl def compare_decode_strategies(model, tokenizer, prompt): # standard_text standard_decode(model, tokenizer(prompt).input_ids, max_new_tokens128) # feedback_text feedback_decode(model, tokenizer(prompt).input_ids, max_new_tokens128) # 伪代码演示需要先运行上面的解码函数再计算 PPL # ppl_standard compute_perplexity(model, tokenizer, standard_text) # ppl_feedback compute_perplexity(model, tokenizer, feedback_text) # return ppl_standard, ppl_feedback pass评估的重点不是跑一次就下结论而是要在多个任务、多个领域的数据集上做统计对比。单独一个 prompt 的 PPL 波动很大不能说明问题。6. 运行结果与效果验证方式回灌深层激活是否有效不能只看 PPL 数字下降了就高兴。PPL 是一个总体指标它有可能被少数 token 的大幅改进拉低而大多数 token 并没有实质变化。更稳妥的验证方式是把评估拆成三个层次。第一层是分布层验证。计算标准解码和回灌解码各自的平均 PPL、PPL 中位数以及低置信 token 集合的平均 PPL。重点观察低置信 token 集合的 PPL 是否显著下降。如果整体 PPL 下降主要是低置信 token 贡献的说明回灌确实把算力用在了刀刃上如果整体 PPL 没变化只是低置信 token 的分布被强行改成了另一个低概率分布那说明注入方式可能需要调整。第二层是任务层验证。找一组自带标准答案的任务比如多跳问答、代码生成、数学推理。用准确率或匹配率来对比两种解码策略。这一步回答的核心问题是PPL 降低是否真的转化成了任务正确率的提升。如果 PPL 降了但任务准确率没变甚至下降了说明模型只是变得更“自信”但没有变得更“正确”这类回灌策略需要警惕。第三层是稳定性验证。同一个 prompt 用不同的随机种子生成多次看回灌策略的输出方差。如果回灌之后的输出在不同采样条件下结果差异很大说明它的修正路径不稳定工程上难以接受。判断成功的标准可以写成同一测试集下PPL 下降幅度是否一致。低置信 token 比例是否减少。下游任务指标是否同步改善。生成的文本是否出现语法或逻辑层面的新错误。如果运行失败第一步应该看的不是模型而是回灌配置。最常见的问题是deep_layer和shallow_layer选错导致注入维度和隐藏状态维度不匹配代码直接报错。其次是回灌阈值设置过高导致绝大多数 token 都进入回灌流程生成速度慢到不可用。这种情况下优先降低max_feedback_rounds或者调高low_conf_threshold。7. 常见误区与排查思路这个方向听起来简单但实践中容易被误解。以下几个误区值得单独说明。第一个误区回灌等于让模型无限循环。实际工程中每一层前向都需要真实计算无限循环意味着推理时间无限增长。必须设置明确的轮数上限和退出阈值。回灌的目标不是“算到天荒地老”而是用最少的额外计算获得最大的分布改进。第二个误区困惑度降低就一定代表回答质量提升。PPL 衡量的是模型内部置信度不能等同于事实验证。回灌能让模型更确定但确定的不一定是对的。所以评估时务必结合下游任务指标。第三个误区所有场景都适合回灌。对实时交互场景来说额外增加一次前向可能就超出了延迟预算。回灌更适合离线批量生成、RAG 后处理、知识库问答等延迟敏感度较低的场景。第四个误区回灌需要修改模型结构。实际上它只是在推理阶段调整计算流程模型权重无需变动。这决定了它可以作为现有推理系统的外挂模块不需要重新训练或微调。下面是一张常见问题排查表问题现象可能原因排查方式解决方案程序报维度不匹配深层激活与浅层状态维度不一致检查模型隐藏层维度配置在注入前加线性投影或改用concat模式并配置投影层生成速度大幅变慢触发回灌的 token 比例过高统计低置信 token 占比和回灌轮次调低low_conf_threshold或减少max_feedback_roundsPPL 下降但任务准确率不变回灌只增强了模型自信未改变正确分布分别统计正确/错误样本的 PPL 变化调整深层激活来源层尝试不同注入方式回灌前后预测完全一样深层激活信息没有有效注入打印注入前后激活向量的差异度检查注入函数是否生效尝试concat模式KV Cache 与局部重算冲突重算时未同步更新缓存查看推理引擎缓存机制在局部前向时暂时禁用或重建 KV Cache显存峰值翻倍需要同时保存全层激活检查显存监控曲线只保存需要回灌的层避免保留全部中间状态8. 工程落地与最佳实践回灌深层激活如果要进入生产环境不能只写一个能跑的 Python 脚本还要考虑性能、可观测性和回滚方案。以下几点是我认为工程落地时优先级最高的内容。第一场景选择要克制。不是所有请求都需要回灌。可以从用户请求中抽取特征比如是否包含多步指令、是否涉及长文本、是否属于高风险回答动态决定是否开启回灌。更精细的做法是对同一个请求先用标准解码生成记录每个 token 的最低概率只有当最低概率低于某个阈值时才对这部分内容进行二次回灌生成。这相当于把回灌设计成一个“按需触发的救援模块”。第二控制计算预算。合理设置low_conf_threshold和max_feedback_rounds。经验上low_conf_threshold设置在 0.4 到 0.7 之间比较常见太低会导致回灌几乎不触发太高会让每个 token 都进入回灌。max_feedback_rounds建议起步为 1效果不足时再逐步增加。每一步多一轮延迟就多一份不要一开始就把参数拉满。第三优化显存占用。回灌需要访问中间层激活这在推理引擎中并不总是零成本。如果模型有 32 层而我们只需要第 2 层和第 32 层的激活就应只对这两层做 hook不要保存全部 32 层的隐藏状态。使用 PyTorch 的register_forward_hook或类似机制可以精准提取目标层激活显著降低显存开销。第四注入方式优先从简单的开始。先实现simple_add验证方向是否可行再尝试linear或concat。一些研究表明深层激活中混杂的语义信息可能需要在注入前做归一化或缩放否则会破坏浅层的局部表示。你可以在combine_activation里加入一个缩放系数把深层激活乘以一个小于 1 的权重再相加通常比直接相加更稳定。第五日志和监控必须到位。生产环境至少记录以下字段触发回灌的 token 数量、每个 token 的回灌轮数、回灌前后的最大概率变化、PPL 变化幅度、额外延迟消耗。这些指标既能帮助你调参也能在出现问题时快速定位是不是回灌策略导致的异常。建议把回灌策略做成可配置开关线上可以通过配置中心动态切换而不是每次调整都要改代码发布。第六灰度发布和回滚。回灌虽然不改变模型权重但可能改变生成分布影响用户看到的回答。上线前先在一个小流量桶内运行比较开启和关闭回灌时的用户反馈、任务成功率、延迟分位数。一旦发现效果下降应该能立刻通过开关回滚到标准解码不要等到故障扩散再处理。这里尤其要遵循最小权限原则回灌只应在授权处理的数据上使用不能因为策略改变而越权访问或修改数据。第七与现有推理优化方案的关系。量化、投机采样、KV Cache 优化都属于通用加速手段回灌是在它们之上增加的一层策略。需要留意的是回灌的局部前向可能会绕过部分缓存逻辑导致量化模型下的数值表现和浮点模型不完全一致。上线前需要重新跑一遍评测确认量化没有放大回灌引入的偏差。9. 总结与后续学习方向DeepMind 这个研究方向真正有价值的地方不是“困惑度降低”这个结果本身而是它展示了推理阶段还有一块可以精细优化的计算空间。传统自回归解码把每次前向计算看成不可分割的原子操作回灌深层激活则把它拆成了“哪里不确定就修哪里”。这种 token 级别的按需计算和最近业界强调的推理加速、成本控制其实是一体两面的关系加速是减少不必要计算回灌是把节省下来的算力花在关键位置。如果你对这个方向感兴趣下一步可以做三件事。第一选择一个开源模型自己实现一个最小回灌流程先跑通代码再体验调参过程。第二整理一个多领域评测集包含代码、数学、摘要、问答等任务用本文第五节给出的评估脚本对比标准解码和回灌解码的效果差异。第三关注后续研究在停止策略和注入方式上的进展这两个细节目前还有很大的优化空间也是决定回灌能否从论文走向工程的关键。最后提醒一句不要把 PPL 当作万能指标。它适合做同一策略下的相对比较不适合跨模型或跨任务的绝对评价。真正负责任的落地方式是把 PPL 和下游任务指标、线上反馈、延迟成本放在一起综合判断。希望这篇文章能帮你把这条新的推理期优化路线理解得更清楚也让你在评估下一代模型和推理框架时多一个观察维度。