Open
Hyper-Parallel Chunk KDA 当前实现设计 #12
yide12Add on 2 days ago
yide12
2 days ago Comments:
2 days ago Comments:
任务 3 已完成,并通过真实 4 卡故障快恢验证。
- 已拉取 PR 1443:
156436bf4dbd3e951e312b77c8c9afb3f87c1207 - 已拉取 MindCluster,并源码构建、安装
mindio_ttp 26.2.0 - 环境:Python 3.10.22、torch 2.9.0、torch_npu 2.9.0.post6、CANN 9.2.0
- 场景:4 卡 HSDP,step 9 forward 阶段杀死 rank 1
- 恢复结果:Controller 返回 0;rank 1 PID
2604716 → 2606050,其他 rank PID 不变 - 恢复后训练到 step 12,与 baseline 的模型、优化器、调度器、RNG、游标精确一致
- UT:
39 passed, 18 subtests passed - ST:
1 passed
交付入口:
复现命令:
bash /home/wyd/error_recovery/test_recovery/setup_environment.sh
bash /home/wyd/error_recovery/test_recovery/run_task3.sh
边界:这是实际 MindIO、HCCL、NPU 训练及进程替换测试,但管理策略由测试 harness 驱动,不等同于生产 ClusterD/Kubernetes 或物理掉电验收。当前 PR 也比最新本地 master 少 19 个提交,合入后需要重新验证。


Hyper-Parallel Chunk KDA 当前实现设计
1. 文档目的与版本基线
本文档描述当前已经落地的 Chunk KDA 实现,而不是早期接入设想。重点说明:
newest_flash_linear_attention/70eb6ba8hyper_parallel_github/kda_r1.0/a26a38ddmf目录中的 KDA Ulysses 和实验性 state-scan 调用方2. 总体设计
HP 对外提供两层接口:
这种分层的原因是:
3. 组件职责划分
3.1 FLA-NPU
FLA-NPU 是 KDA 数学语义和底层算子能力的提供者,负责:
FLA-NPU 不负责 HP 公共 Python API,也不负责 MF 的并行通信策略。
3.2 Hyper-Parallel 公共 API 层
位置:
hyper_parallel/custom_ops/experimental/experimental_ops.pyhyper_parallel/custom_ops/experimental/chunk_kda_stages.pyhyper_parallel/custom_ops/experimental/__init__.py职责:
npu_chunk_kda。该层不实现 kernel,不创建通信组,不执行 collective。
3.3 HP MindSpore 路由与自动微分层
位置:
hyper_parallel/platform/mindspore/custom_ops/custom_ops.pyhyper_parallel/platform/mindspore/custom_ops/custom_op_impl.pyhyper_parallel/platform/mindspore/custom_ops/chunk_kda_autograd.py职责:
final_state的上游梯度传入 Dhu,并将dh0返回给initial_state。当前路由规则:
safe raw-gate 在无 state 时也选择 stage chain,是因为该路径与当前 FLA stage ABI 成对,并且规避了 MF Ulysses 工作负载中 fused backward 出现的非有限梯度。
3.4 HP C++ Bridge 层
位置:
chunk_kda_fwd.ccchunk_kda_bwd.ccchunk_kda_stages.ccchunk_kda_stage_dispatch.h职责:
aclnnChunkKdaFwdV2、aclnnChunkKdaBwd和九个 stage ACLNN。Bridge 是薄适配层,不重新实现 KDA 数学逻辑,也不隐式执行通信。
3.5 HP ContextParallel
HP 现有
ContextParallel负责 Ulysses 的 sequence/head all-to-all:npu_chunk_kda本身不知道 CP group,也不知道 all-to-all。3.6 MindFormers 调用方
MF 负责模型级和并行级编排:
ContextParallel挂到 KDA core 外层。kda_disable_recompute。a_log/dt_bias等 replicated 参数梯度归约。4. 总接口定义
npu_chunk_kda( q, k, v, g, beta, scale: float, chunk_size: int = 64, *, layout: str = "BNSD", output_final_state: bool = False, safe_gate: bool = False, lower_bound: float = -5.0, use_gate_in_kernel: bool = True, a_log=None, dt_bias=None, cu_seqlens=None, chunk_indices=None, initial_state=None, disable_recompute: bool = True, state_v_first: bool = False, epsilon: float = 1e-6, use_qk_l2norm_in_kernel: bool = False, use_beta_sigmoid_in_kernel: bool = False, allow_neg_eigval: bool = False, use_exp2: bool = True, ) -> tuple[Tensor, Optional[Tensor]]4.1 输入含义
q/kHk,末维为 KvHv,末维为 VgbetascaleK**-0.5layoutBNSD/BSND/NTD/TNDa_log/dt_biasdt_bias可为[Hv,K]或等价展平形式cu_seqlens/chunk_indicesinitial_statedisable_recomputeTrue保存反向 cache;False在反向重建 prepare 和 state relaystate_v_first[V,K];HP 内部规范化为 K-firstepsilonuse_qk_l2norm_in_kerneluse_beta_sigmoid_in_kernelallow_neg_eigvaluse_exp2True4.2 Layout
[B,Hk,T,K][B,Hv,T,V/K][B,Hv,T][B,T,Hk,K][B,T,Hv,V/K][B,T,Hv][Hk,T,K][Hv,T,V/K][Hv,T][T,Hk,K][T,Hv,V/K][T,Hv]Hv可大于Hk。stage-chain 自动微分会将 Q/K 复制到 value heads,反向时再将重复 head 梯度求和回原始Hk。4.3 返回值
attn_out为 token-major 业务输出,HP 在 stage chain 外恢复公共输出约定。output_final_state=False时,final_state=None。final_state可参与 loss,其梯度会传给 Dhu。initial_state,stage-chain backward 返回对应dh0。final_state参与 loss。4.4 当前训练交集
当前 stage-chain 状态/重算路径的已对齐配套组合为:
K=V=128。chunk_size=64。safe_gate=True。use_gate_in_kernel=True。use_exp2=True。a_log;BwdFinalize 配套 ABI 要求dt_bias,未传时 HP 构造零值。FLA 前向能力比这个交集更广,但不能由“前向可运行”推导“反向已验收”。
5. 显式 Stage 接口
Stage API 都是本地 Tensor 算子,没有隐式自动微分,也没有通信。
5.1 前向阶段
npu_chunk_kda_fwd_preparenpu_chunk_kda_fwd_prepare( q, k, v, g, beta, scale, chunk_size=64, *, layout="BNSD", a_log=None, dt_bias=None, cu_seqlens=None, chunk_indices=None, epsilon=1e-6, use_qk_l2norm_in_kernel=False, use_gate_in_kernel=False, use_beta_sigmoid_in_kernel=False, allow_neg_eigval=False, safe_gate=False, lower_bound=-5.0, use_exp2=True, backward_mode="save", ) -> tuple[13]作用:将本地 Q/K/V/g/beta 处理为 head-major cache。
固定返回顺序:
backward_mode只控制输出哪些 cache,不代表启用自动微分:noneforwardnone+ 2recomputenone+ 8..12savenpu_chunk_kda_pre_process_fwdnpu_chunk_kda_pre_process_fwd( k, w, u, *, gk, cu_seqlens, chunk_size=64 ) -> tuple[Tensor]返回 FP32 summary
[N,Hv,K,V+K],其中最后一维表示[E | M]:该 summary 用于 sequence-split CP 的跨 rank 状态扫描。
npu_chunk_kda_fwd_hnpu_chunk_kda_fwd_h( k, w, u, *, gk, initial_state=None, output_final_state=False, chunk_size=64, cu_seqlens=None, chunk_indices=None, use_exp2=True, state_v_first=False, ) -> tuple[Tensor, Tensor, Optional[Tensor]]作用:从调用方给定的边界
initial_state开始,完成本地 chunk 状态递推。返回:
h:[B,Nc,Hv,K,V],每个 chunk 的入口/递推状态。v_new: 更新后的 value relay。final_state: 本地序列终点状态。npu_chunk_kda_fwd_finalizenpu_chunk_kda_fwd_finalize( qg_scaled, aqk, v_new, h, *, output_layout="BSND", state_v_first=False, cu_seqlens=None, chunk_indices=None, ) -> Tensor作用:将 Q 侧 cache、局部 value 和 state relay 组合为最终 attention output。
5.2 反向阶段
npu_chunk_kda_bwd_preparenpu_chunk_kda_bwd_prepare( aqk, v_new, d_o, h, *, scale, layout="BNSD", chunk_size=64, state_v_first=False, cu_seqlens=None, chunk_indices=None, ) -> tuple[Tensor, Tensor, Tensor]返回:
该阶段先拆出与 output 直接相关的本地梯度,为后续状态反向和最终梯度汇总做准备。
npu_chunk_kda_pre_process_bwdnpu_chunk_kda_pre_process_bwd( q, k, w, d_o, dv, scale, chunk_size=64, *, gk, cu_seqlens=None, ) -> Tensor返回本地 backward affine summary
[Hv,K,V+K]。调用方按反时间顺序交换 summary,为每个 rank 构造终点状态梯度dht。npu_chunk_kda_bwd_dhunpu_chunk_kda_bwd_dhu( q, k, w, d_o, dv, scale, chunk_size=64, *, gk, h0=None, dht=None, cu_seqlens=None, chunk_indices=None, use_exp2=True, state_v_first=False, ) -> tuple[Tensor, Optional[Tensor], Tensor]返回:
dht是本 rank 终点边界梯度。dh是 chunk 状态梯度,始终使用 K-first。h0时才返回dh0。dv_scan是经状态反向累积后的 value 梯度。npu_chunk_kda_bwd_finalizenpu_chunk_kda_bwd_finalize( q, k, v, gk, raw_g, beta, a_log, dt_bias, akk, v_new, h, dh, dv_scan, d_aqk, dq_raw, *, scale, lower_bound=-5.0, chunk_size=64, safe_gate=True, use_gate_in_kernel=True, use_exp2=True, state_v_first=False, q_rstd=None, k_rstd=None, cu_seqlens=None, chunk_indices=None, use_beta_sigmoid_in_kernel=False, allow_neg_eigval=False, output_layout="BNSD", ) -> tuple[7]返回:
该阶段汇总块内梯度、state-scan 梯度和 gate/beta 链式求导,得到面向模型输入和参数的最终梯度。
5.3 Summary 合并阶段
npu_chunk_kda_merge_fwd_bwdnpu_chunk_kda_merge_fwd_bwd( state, summaries, pre_or_post_num_ranks: int, rank: int, *, forward: bool = True, state_v_first: bool = False, ) -> Tensor作用:对调用方已经 AllGather 得到的 summaries 进行 affine compose,原位更新
state。该接口不执行 AllGather;
rank、参与合并的数量和 summary 顺序均由调用方保证。6. 不同场景的数据流
6.1 单卡/普通训练
调用方只使用
npu_chunk_kda,不需要直接处理 stage cache。保存模式:
重算模式:
6.2 Ulysses Context Parallel
Ulysses 不拆 KDA 的状态递推。它通过 all-to-all 让每个 rank 拿到完整 sequence 和部分 heads,然后直接调用总接口。
反向数据流由 MindSpore autograd 经 HP
DFunction和ContextParallel的反向规则自动逆转。职责边界:
ContextParallel负责 all-to-all。npu_chunk_kda只计算 full-sequence/local-head KDA。6.3 Sequence-split state-scan CP:前向
每个 rank 保留一段按时间顺序排列的 token。KDA 状态需要从前一 rank 的终点传到后一 rank。
summary 表示本 rank 的 affine state map:
因此可先交换较小的 summary,再计算每个 rank 的边界
h0,而不需要 gather 全部 token cache。6.4 Sequence-split state-scan CP:反向
前向 summary 按 rank 0 到 rank N-1 的时间顺序组合;反向 summary 必须按相反顺序组合。
6.5 Packed/Variable-length
单卡 stage 通过
cu_seqlens/chunk_indices识别序列边界:但当前 MF sequence-split CP 未实现跨 rank packed ownership/reset 计划,所以不允许将“单卡 stage 支持 packed”等同于“多卡 state-scan CP 已支持 packed”。
7. 为什么不把 CP 通信放进 KDA 算子
8. 当前验证状态
8.1 已验证
8.2 已知未通过项
强 gate 衰减、BF16、T=65、常量
dht、loss 仅依赖final_state时:当前定位为 BF16
v_newrelay 误差经终态梯度点积的正负抵消放大。该失败用例保留,不 skip,不放宽阈值。因此目前不能宣称任意 final-state-only loss 都已完成精度验收。8.3 实验性 state-scan CP 边界
当前 MF
KdaStateScan仅支持:B=1。尚未完成:
9. 结论
当前 HP Chunk KDA 的实现原则是:
FLA-NPU 负责 kernel 和数学语义,HP 负责 API、layout、自动微分与本地 stage bridge,MF 负责模型与通信编排。这样既能保持普通训练的易用性,又不会将 HP 绑定到某一种 CP 通信算法。