
_load_rng_state after get_batch_samples may break training reproducibility when dataloader has random operations
快速结论:该问题发生在使用 Hugging Face Transformers Trainer 从 checkpoint 恢复训练时,如果 dataloader 中包含了随机操作(如数据增强、噪声注入等),当前的调用顺序 get_batch_samples() 先于 _load_rng_state() 会导致训练无法保持逐比特(bit-for-bit)复现。优先排查 _inner_training_loop 中 RNG 状态恢复与数据加载的执行顺序。
问题场景
在 Hugging Face Transformers 库的 Trainer 中,当用户从 checkpoint 恢复训练,并且 dataloader 包含随机操作(例如在 Dataset 的 __getitem__ 中应用随机噪声、数据增强或使用随机采样器)时,训练过程可能无法复现原始不间断运行的结果。
报错原文
该问题不产生显式报错,而是表现为训练结果在复现时出现偏差。核心问题描述为:
When `get_batch_samples` is called before `_load_rng_state`, the random operations within the dataloader consume the RNG state from the *current* execution stream, not the *restored* one.
This leads to two issues:
1. The data batch fetched is different from the one in the original, uninterrupted run.
2. The subsequent `_load_rng_state` call resets the RNG, but the `training_step` (e.g., with Dropout) then operates on this incorrect data, and uses an RNG state that is out of sync with the original run's state progression.
原因分析
在 Trainer 的 _inner_training_loop 中,当前实现为:先调用 get_batch_samples() 获取数据批次,再调用 _load_rng_state() 恢复随机数生成器(RNG)状态。这种顺序导致数据加载过程中消耗的是恢复前的 RNG 状态,因此获取到的数据批次与原始不间断运行不一致。随后恢复 RNG 状态虽然能影响模型训练步骤(如 Dropout),但模型操作的已是错误的数据,并且 RNG 状态与原始运行的状态推进不再同步。如果反过来,先恢复 RNG 状态(_load_rng_state()),再获取数据批次(get_batch_samples()),则数据加载和模型训练步骤都能使用正确的 RNG 状态,实现完全复现。
环境排查
- Python 版本(建议 >= 3.8)
- PyTorch 版本(建议 >= 1.10)
- Transformers 版本(建议 >= 4.x,具体视 issue 提交时间)
- CUDA 版本及 GPU 型号(如果使用 GPU 训练)
- 确认 dataloader 中是否包含随机操作(如数据增强、随机变换等)
解决步骤
- 手动调整调用顺序(可优先尝试):在
Trainer的_inner_training_loop中,将对_load_rng_state()的调用提前到get_batch_samples()之前。即:先恢复 RNG 状态,再获取数据批次。 - 验证复现性:使用 issue 中提供的实验脚本,分别测试两种顺序:
- Hypothesis A:
load_rng_state() -> get_batch_samples()(修复后) - Hypothesis B:
get_batch_samples() -> load_rng_state()(当前实现)
确认 Hypothesis A 能复现原始不间断运行的输出。
- Hypothesis A:
- 等待官方确认与 PR 合入:issue 中已有社区成员提出相同的修复建议(“Just swap the order”),但尚未得到官方核心维护者(如 @SunMarc)的确认。建议关注该 issue 的进展,或自行 Fork 并应用上述修改。
验证方法
运行 issue 中提供的实验脚本,比较以下三种输出的损失值或其他训练指标是否一致:
- 原始不间断运行(Golden standard)
- 使用修复后的顺序(
load_rng_state()先于get_batch_samples()) - 当前实现(
get_batch_samples()先于load_rng_state())
如果修复后的顺序输出与原始不间断运行完全一致,则说明问题已解决。



