拓冰建站拓冰建站
首页 / 资讯中心 / 正文

TorchTitan 静默数据损坏(SDC)检测实战:基于确定性重放的 `sdc_replayer` 全解析

TorchTitan 静默数据损坏SDC检测实战基于确定性重放的sdc_replayer全解析【免费下载链接】torchtitanA PyTorch native platform for training generative AI models项目地址: https://gitcode.com/GitHub_Trending/to/torchtitan导读静默数据损坏Silent Data Corruption, SDC是指硬件或软件错误悄然篡改数据却不产生任何显式报错最终表现为训练 loss 曲线异常、模型质量劣化甚至隐性训练失败。TorchTitan 通过**确定性重放deterministic replay**机制检测此类问题在受检的优化器步骤中重放完全确定性的前向/反向计算并比对所有可观测状态一旦出现偏差即在所有 rank 上抛出SDCReplayMismatch异常。本文以 silent_data_corruption.md 为主线结合 sdc_replayer.py 与 trainer.py 的源码实现完整讲解该特性的启用方式、重放边界、签名构成、限制与失败上报机制帮助你把它直接落地到自己的训练配置中。SDC 重放检测的原理与定位SDC 重放属于多种 SDC 检测策略之一。与之并列的替代方案还包括冗余硬件上的影子计算shadow computation在额外硬件上重复执行计算并交叉验证成本高且依赖冗余资源算法级校验algorithm-level checks例如带校验和的矩阵乘法属于算子内嵌检查。TorchTitan 选择的重放方案则不同它牺牲受检步骤的额外前向/反向时间换取一个训练过程中的、与硬件无关的完整性检查。其核心前提是执行必须完全确定同一输入、同一状态下的前向/反向必须产出完全一致的可观测结果任何差异都只能由静默数据损坏引起。实现上该特性默认关闭config.sdc_replayer默认为None不会给训练引入任何额外开销。从 sdc_replayer.py 的模块文档可以看到其完整生命周期快照执行前状态Python/CPU/加速器 RNG、注册的模块 buffer、调用方持有的标量并记录哪些参数进入时没有梯度执行一次前向/反向记录参考签名reference signatureloss、梯度、buffer、RNG 推进、标量状态恢复快照并重放num_replays次将每次签名与参考签名比对一旦出现任何分歧在所有 rank 上抛出SDCReplayMismatch否则仅提交最后一次执行的结果。配置方式无 CLI 标志纯编程式启用SDC 重放没有 CLI 标志必须在 config/recipe 中通过赋值配置对象来启用。config.sdc_replayer默认是None即禁用重放。这一点在 trainer.py 中有明确注释该字段被tyro.conf.Suppress标注从 tyro CLI 解析中隐藏只能编程式赋值。最小启用配置如下来自原文档可直接放入 config_registry 函数from torchtitan.observability.sdc_replayer import SDCReplayer config.debug.deterministic True config.sdc_replayer SDCReplayer.Config( num_steps1, # optimizer steps checked after each (re)start; -1 checks every step num_replays1, # re-executions compared against the reference )配置参数详解参数默认值含义与取值范围num_steps1从 trainer 启动起、并在每次 checkpoint 加载后重新计数需要检查多少个优化器步骤。-1表示检查每一步默认值1只检查每次重启动后的第一步。校验规则必须为-1或至少为1否则抛出ValueErrornum_replays1受检前向/反向相对初始参考执行被重放并比对的次数。必须至少为1更大值可以捕捉单次重放容易漏掉的间歇性损坏两个参数都定义在 sdc_replayer.py 的SDCReplayer.Configdataclass 中并在__post_init__里做合法性校验num_steps非-1时必须 1num_replays必须 1。为什么默认只检查重启动后的第一步因为训练刚恢复或刚初始化时损坏最可能来自一次错误的 checkpoint 恢复或参数初始化。restart 语义通过reset_schedule()实现——trainer 在每次 checkpoint 加载后load_state_dict都会调用它重置计数trainer.py因此 after each (re)start 的语义被精确落实。启用前置条件重放要求同时满足以下条件trainer.py 的_validate_sdc_replay会在配置解析阶段强制执行debug.deterministic True使用尽可能确定的算法见 configs.pydebug.deterministic_warn_only False不能只对非确定性算子发出警告而不报错configs.py使用torch.hash_tensorSDCReplayer.__init__会在构造时通过_validate_hash_support探测当前设备上torch.hash_tensor的可用性sdc_replayer.py。另外还有一条硬性组合限制CUDA graphs 开启时num_replays必须为1否则配置校验直接抛错ValueError: SDC replay supports at most one replay when CUDA graphs are enabled: set sdc_replayer.num_replays1 or training.disable_cuda_graphsTrue.一个真实的启用示例graph_trainer/llama3/config_registry.py 展示了在实验性 recipe 中的实际用法——直接赋值config.sdc_replayer SDCReplayer.Config()即可使用两个参数的默认值。重放边界什么被重放什么不被重放仅重放受检步骤的第一个前向/反向一个受检优化器步骤中只有第一个前向/反向调用即一个梯度累积组被重放在流水线并行PP下这个一个梯度累积组等价于一个完整的 pipeline schedule包含所有 pipeline microbatch。训练循环中的对应逻辑在 trainer.py仅当fwd_bwd_index 0时才走self.sdc_replayer.run_fwd_bwd(...)其余累积组直接执行、不检查。为什么后面的累积组不检查这是成本选择而非引擎限制重放引擎可以检查任何前向/反向 callable而后续累积组与第一组走的是相同的计算与通信路径继续检查只会把受检步骤的开销成倍放大却覆盖不到新的代码路径。因此当某步有多个累积组时只有第一组受检。状态恢复与提交语义每次执行前都会恢复状态参考执行与中间执行的结果均被丢弃只提交最后一次执行产出的梯度、注册 buffer、RNG 推进、token 计数器和 loss。对应实现中_run_checked先capture()基线执行参考并clone()其签名然后循环num_replays次每次restore(baseline)后执行、比对签名最后返回最后一次的 losssdc_replayer.py。梯度值永不快照零梯度进入契约这是本特性一个非常关键的设计细节梯度值永远不会被快照。受检的前向/反向必须以无待处理梯度状态进入None或全零即zero_grad之后的状态restore 直接依据该契约重建入口状态进入时无梯度的参数恢复为None进入时是零张量的原地清零in-place zero从而保留其存储地址供 CUDA graphs 使用且受检步骤上不产生任何梯度大小的克隆或拷贝 kernelsdc_replayer.py。违反该契约会产生假性不匹配false mismatch。源码注释给出了两类典型误用sdc_replayer.py把非第一个梯度累积组路由进run_fwd_bwdrestore 会抹掉部分累加值导致重放与参考分歧requires_gradTrue的参数未纳入优化器trainer 的zero_grad不会清它的梯度后续受检步骤会带着累积梯度进入。这类参数应冻结为requires_gradFalse。执行后端与 scratch 状态的边界以下执行后端都可以参与重放eager 执行、torch.compile、CUDA graphs、symmetric-memory FSDP、distributed GEMM、async TP、DeepEP v2 与 HybridEP。GraphTrainer实验性图训练器也使用相同的重放边界见 graph_trainer 目录。引擎对执行后端内部的 scratch 状态没有要求只要一次前向/反向调用在返回前完成、后续调用在读取前覆盖这些状态即可。这类 scratch 状态既不被快照也不进入重放签名。签名构成与失败上报签名里有什么受检签名signature由_signature方法构建sdc_replayer.py包含loss本地参数梯度每个参数按其named_parameters名称逐一哈希None梯度记录为none模式占位注册的模块 buffer按模块名 buffer 名逐一哈希Nonebuffer 同样有占位模式Python 与 torch RNG 状态random.getstate()、torch.get_rng_state()以及每设备的加速器 RNG 状态如torch.cuda.get_rng_state_all()签名项形如rng:cpu、rng:accelerator:indextoken 计数器trainer 中唯一被重放前向/反向修改的标量ntokens_seen通过ScalarStateAccessor注册见 trainer.py。每个张量项都会记录其 shape、dtype、device 组成的 schema并以torch.hash_tensor生成设备端 digest全部聚合到 loss 所在设备上做批量比对。不匹配如何上报一旦比对发现分歧会在梯度裁剪、优化器、学习率调度器、checkpoint 保存之前在所有 rank 上抛出SDCReplayMismatchsdc_replayer.py。异常信息精确标识step全局优化器步骤local_step该步骤在当前检查调度中的 1 基位置调度在 checkpoint 加载后重启local_step也随之重置replay第几次重放发现的分歧rank最先发现分歧的 rank通过all_reduceall_gather_object在全体 rank 间汇总并选取第一个有分歧者见 sdc_replayer.pysignature第一个出现分歧的签名条目名如loss、gradient:i:name、buffer:i:name、state:python_rng等。例如SDC replay mismatch: step42, local_step1, replay1, rank3, signaturegradient:0:layers.0.attn.q_proj.weight成本模型受检步骤的预期成本为1 num_replays次前向/反向执行1 次参考 num_replays次重放。未受检步骤不计算重放签名零额外开销。当前限制CUDA graphs 与多次重放不兼容CUDA graphs 目前要求sdc_replayer.num_replays1。若需要更多次重放则要恢复 graph 持有的梯度与可选 buffer 存储且不改变其被捕获的地址——当前实现做不到因此在配置校验阶段直接禁止trainer.py。从 cudagraph.py 可以看到CUDA graph 包装器会根据sdc_num_steps/sdc_num_replays计算预热与受检步骤数将重放纳入 graph 捕获调度。XOR 校验和的碰撞面当前重放使用现有的基于 XOR 的torch.hash_tensor模式sdc_replayer.py。该校验和与顺序无关因此置换permutation会碰撞张量元素重排后哈希不变部分重复值损坏也可能碰撞。源码中明确标注这一局限并说明复杂张量如 RoPE 缓存按实部/虚部拆分后继承同样的限制选用该哈希是因为它跨张量应用简单、对重放足够快。这意味着重放检测是大概率发现损坏的强信号而非数学上完备的校验。集成到训练循环调用链速览把以上机制串起来SDC 重放在 trainer 中的完整调用链为配置校验JobConfig.__post_init__→_validate_sdc_replaytrainer.py构造SDCReplayer(config.sdc_replayer, modulesself.model_parts, deviceself.device, scalar_state{...})trainer.py同时校验torch.hash_tensor可用性CUDA graph 集成若未禁用 CUDA graphswrap_with_cuda_graph接收sdc_num_steps/sdc_num_replaystrainer.py训练步每个优化器步的fwd_bwd_index 0时调用run_fwd_bwd(fwd_bwd, stepself.step)调度判定num_steps -1 or local_step num_stepssdc_replayer.py调度重置load_state_dict加载 checkpoint 后调用reset_schedule()trainer.py使恢复后的第一步重新受检。注意SDC 重放状态是进程本地、不进 checkpoint的其检查调度在每次 checkpoint 加载后自动重启trainer.py 的注释明确了这一点。总结与推荐用法日常训练保持config.sdc_replayer None默认零开销关键恢复点在 checkpoint 恢复后启用默认配置SDCReplayer.Config()用最小成本验证恢复是否正确——这正是默认num_steps1的设计意图容错要求高、怀疑间歇性损坏调大num_replays如2~3以捕捉单次重放易漏的偶发损坏同时注意 CUDA graphs 下必须保持num_replays1极致校验num_steps-1让每一步的第一累积组都受检代价是每步执行1 num_replays次前向/反向。SDC 重放并不能替代硬件层面的可靠性与算法级校验但它以极低的接入成本纯配置、无代码改动为大规模分布式训练提供了训练过程中可随时开启的确定性完整性防线——尤其适合在跨节点、长周期训练中作为体检手段把静默损坏暴露在梯度裁剪之前避免污染优化器状态与最终 checkpoint。【免费下载链接】torchtitanA PyTorch native platform for training generative AI models项目地址: https://gitcode.com/GitHub_Trending/to/torchtitan创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门