开了梯度检查点,为什么 Transformers 把 use_cache 关了
区分训练时的激活重算与生成时的 KV cache。按模型实现关闭训练缓存,推理前检查生成配置与梯度模式,不把兼容性警告当训练失败。
语言模型微调启用了梯度检查点,日志出现:
`use_cache=True` is incompatible with gradient checkpointing.
Setting `use_cache=False`...
训练可能仍在继续。这条消息通常是在处理训练路径与缓存配置的冲突,不等于权重加载失败,也不说明磁盘上的模型缓存需要删除。
下面针对支持梯度检查点的自回归 Transformer 训练。旧的 Transformers 4.35.2 Llama 路径有上述模型级提示;4.57.1 中相应层基类也会在训练且开启检查点时关闭传入的缓存选项、清除相关 past 参数。不同模型的代码位置和提示文字可能不同,不能据此断言所有模型都同样处理。
两种机制的对象不同
梯度检查点减少前向保存的部分激活,在反向需要时重新计算这些区域,换取更低的激活存储需求。它不会减少全部模型参数或优化器状态,也会增加重算。
use_cache 在这里主要指自回归生成的 KV cache,复用先前 token 的注意力键和值,避免每次从头计算。它不是下载缓存、tokenizer 缓存或训练数据集缓存。
训练重算需要与原前向保持一致;让重算路径继续使用或修改之前的 past 状态,可能引入不一致。模型实现因此会对这组功能作兼容限制。不能仅为了消除警告,直接删除源码中的条件分支。
训练前明确关闭这条缓存路径
对已经加载、支持相应接口的 model,下面是设置示例:
model.train()
model.config.use_cache = False
model.gradient_checkpointing_enable()
如果由 Trainer 或其他训练框架管理梯度检查点,应使用该框架的配置,不重复配置互相覆盖的开关。显式前向还传了 use_cache=True 时,也要检查调用参数;仅修改 config 不保证所有实际调用都使用它。
不要把 torch.no_grad() 加到训练前向来消除冲突,那会改变自动求导。也不要为了恢复 KV cache,盲目关闭梯度检查点:如果原来依赖它控制显存,关闭后可能无法容纳同样的批次。
如果训练没有出现该警告,仍不能单凭日志静默断言缓存已关闭。读取实际模型配置、训练参数和调用路径;某些实现自动处理,另一些模型并不使用同一缓存接口。
单独推理时重新核对生成配置
完成微调后,普通自回归推理通常可以恢复 KV cache。对支持这些接口的模型,以下片段适用于独立纯推理;inputs 已由匹配 tokenizer 编码并置于正确设备:
import torch
model.gradient_checkpointing_disable()
model.eval()
model.config.use_cache = True
with torch.no_grad():
output_ids = model.generate(
**inputs,
max_new_tokens=64,
use_cache=True,
)
调用 generate() 时显式传 use_cache=True,避免另一个生成配置仍保留旧值。KV cache 本身也占显存,长上下文或多路并发需要估算容量;恢复缓存不是保证推理永不 OOM。
eval() 与禁用求导是独立设置。训练中间的验证生成应由框架按设计临时切换,并在返回训练时恢复需要的状态,不能把这段独立推理配置原样留在后续训练流程里。
普通 decoder-only 文本生成的返回序列还包括输入前缀,处理输出时可参考 generate 结果中的输入提示词。这与缓存是否启用属于不同问题。
验收训练配置时,确认实际梯度检查点已启用、梯度按方案产生、相同步骤显存处于可接受范围;验收推理时,再单独核对缓存设置、生成结果与内存。警告不再出现只是配置变化的一个信号,不能代替这两段行为检查。


