申请屏蔽:当前训练场景每次前向均会执行完整反向,_bwd_slots 中反向产生的通信句柄会在 producer backward pre-hook 中被一一 pop 并完成释放,每步结束仅保留固定空列表,不会随迭代累积,因此不存在内存泄漏。
申请屏蔽:当前训练场景中,前向 pre-hook 每执行一次 _push_output_layout,同一次模块前向的 post-hook 都会执行一次 _pop_output_layout;栈清空后还会删除模块上的对应属性,不会跨迭代累积,因此不存在内存泄漏。


基于Trainer流程,新增统一的上下文并行(CP)能力,支持 Colossal、Ulysses、混合并行、异步通信与负载均衡,适配 SDPA、FlexAttention、MLA/DSA 等注意力,并覆盖 Qwen3-MoE、Kimi K3/Kimi Linear 和 Qwen3.5 模型;其中 Kimi Delta Attention 与 Gated DeltaNet 支持 Ulysses 和状态 P2P 两种整层并行方案。中文版是这样,给出英文版本
Built on the Trainer workflow, a unified Context Parallelism (CP) capability is introduced, supporting Colossal, Ulysses, hybrid parallelism, asynchronous communication, and load balancing. It supports SDPA, FlexAttention, MLA/DSA, and other attention mechanisms across Qwen3-MoE, Kimi K3/Kimi Linear, and Qwen3.5. Kimi Delta Attention and Gated DeltaNet additionally support both full-layer Ulysses and state-P2P parallelism.


Introduced unified Context Parallelism (CP) support within the Trainer workflow, featuring Colossal, Ulysses, hybrid parallelism, asynchronous communication, and load balancing. It supports SDPA, FlexAttention, MLA/DSA, and models including Qwen3-MoE, Kimi K3/Kimi Linear, and Qwen3.5. Kimi Delta Attention and Gated DeltaNet additionally support two full-layer parallel execution modes: Ulysses and state P2P.


中文:新增分布式 torch.compile 支持,可通过 Trainer 对 Transformer 层进行编译,并与 TP、CP、EP、FSDP2 和 Activation Checkpoint 协同使用。
English: Added distributed torch.compile support for compiling Transformer layers through the Trainer, with integration for TP, CP, EP, FSDP2, and Activation Checkpoint. 还是这个版本吧,在更新下


中文:新增分布式 torch.compile 支持,可通过 Trainer 对 Transformer 层进行编译,并与多维并行和 Activation Checkpoint 协同使用。
English: Added distributed torch.compile support for compiling Transformer layers through the Trainer, with integration for multidimensional parallelism and Activation Checkpoint.


当前不支持 initial_state,不是因为底层前向不会计算,而是因为当前反向没有形成完整闭环。
initial_state 是什么
KDA 是带状态的序列计算:
H0 -- token 0 --> H1
H1 -- token 1 --> H2
...
HT-1 -- token T-1 --> HT
其中:
initial_state = H0final_state = HT
不传时相当于:
H0 = 0
传入时可以实现长序列分段:
output1, state1 = chunk_kda(segment1)
output2, state2 = chunk_kda(
segment2,
initial_state=state1,
)
第二段会继承第一段的历史状态。
底层前向其实支持
FLA-NPU 的 aclnnChunkKdaFwd 支持:
initial_state dtype: FP32
state_v_first=False:
[N, HV, K, V]
state_v_first=True:
[N, HV, V, K]
因此只从前向推理角度看,底层可以使用 initial_state。
当前反向为什么不支持
训练时不仅要计算前向结果,还要处理两种状态梯度。
假设:
output, final_state = chunk_kda(
...,
initial_state=initial_state,
)
反向需要:
dO = ∂loss/∂output
dHT = ∂loss/∂final_state
并应返回:
dH0 = ∂loss/∂initial_state
通常:
dht表示最终状态HT接收到的上游梯度。dh0表示反向计算得到的初始状态H0梯度。
完整梯度关系是:
loss
├── output ────────> dO
└── final_state ───> dHT
│
▼
Chunk KDA backward
│
├── dq/dk/dv/dg/dbeta
└── dH0
当前 FLA-NPU 融合反向明确拒绝:
initial_state
dht
dh0
底层代码检查的是:
initialStateOptional == nullptr &&
dhtOptional == nullptr &&
dh0OutOptional == nullptr
即使 initial_state 不求梯度,也不能简单忽略
例如:
initial_state.stop_gradient = True
虽然不需要返回 dh0,但 q/k/v 的梯度仍然受到 initial_state 影响。
因为前向输出包含类似:
output = q @ initial_state + 当前序列产生的结果
所以:
dq
dk
dv
的正确计算可能需要知道前向使用的 initial_state。
如果前向使用了非零状态,但反向仍按零状态计算,训练可以运行,却会得到错误梯度。
因此不能采用:
前向传 initial_state
反向假装 initial_state=None
当前 HP 做了什么
HP 在公共接口入口直接拒绝:
if initial_state is not None:
raise ValueError(...)
MindSpore C++ 前向 bridge 也固定给 ACLNN 传空值:
const std::optional<ms::Tensor> empty = std::nullopt;
MS_DISPATCH_ACLNN(
aclnnChunkKdaFwd,
...,
empty, // initial_state
...
);
如果 final_state 参与 loss,自动反向也会明确报错,见 custom_op_impl.py。
这样可以避免静默返回错误梯度。
三个接口应该区别处理
现在已经拆成三个接口后,可以进一步区分。
显式前向 npu_chunk_kda_fwd
它只负责前向,因此理论上可以先支持:
npu_chunk_kda_fwd(
...,
initial_state=state,
)
这适用于:
- 流式推理
- 分段推理
- 不需要自动微分的场景
目前它仍被公共校验统一禁止,是 HP 当前接入层的限制,不是底层前向限制。
自动微分 npu_chunk_kda
这个接口暂时必须禁止 initial_state,直到反向支持:
initial_state 输入
dht 输入
dh0 输出
显式反向 npu_chunk_kda_bwd
需要底层真正完成状态反向语义后才能开放相关参数:
npu_chunk_kda_bwd(
...,
initial_state=initial_state,
dht=d_final_state,
)
并返回:
dq, dk, dv, dbeta, dg, dh0, ...
完整支持需要补什么
需要完成以下链路:
npu_chunk_kda_fwd接收并传递initial_state。- C++ 前向 bridge 把它传给
aclnnChunkKdaFwd。 NpuChunkKdaDFunction.forward()保存initial_state。- 自动反向接收
dht。 - C++ 反向 bridge 把
initial_state和dht传给aclnnChunkKdaBwd。 - 反向算子输出
dh0。 DFunction.backward()将dh0返回到initial_state。- 验证分段执行与整段执行等价。
- 验证跨段反向梯度与 CPU reference 一致。
所以准确结论是:
FLA-NPU 前向支持
initial_state,但当前融合反向不支持initial_state/dht/dh0。HP 为防止出现“前向正确、反向错误”的训练结果,暂时在所有公共接口中统一拒绝。纯前向接口理论上可以先单独开放推理支持。


dim (3, 2) keepdim False
input [[[[-2.01 -1.337 ]
[ 0.7104 -0.369 ]]
[[-1.3 0.8057 ]
[ 0.6343 1.064 ]]]
[[[ 0.4368 -0.3354 ]
[-1.0625 -2.535 ]]
[[ 0.1842 -2.111 ]
[-1.488 -0.9604 ]]]
[[[-1.098 -1.1875 ]
[ 1.009 -0.918 ]]
[[ 1.352 -0.03836]
[ 0.567 -0.375 ]]]]
input_ord -inf
torch ouput tensor([[1.7061, 1.8701],
[1.4990, 1.6729],
[2.1055, 0.4133]], dtype=torch.float16)
ms output [[1.706 1.87 ]
[1.499 1.673 ]
[2.105 0.4133]]
torch ouput tensor([[1.7061, 1.8701],
[1.4990, 1.6729],
[2.1055, 0.4133]], dtype=torch.float16)


lightning_indexer:https://gitcode.com/cann/ops-transformer/tree/master/attention/lightning_indexer_v2
sparse_flash_attention:https://gitcode.com/cann/ops-transformer/tree/master/attention/sparse_flash_attention
sparse_flash_attention_grad:https://gitcode.com/cann/ops-transformer/tree/master/attention/sparse_flash_attention_grad
sparse_lightning_indexer_kl_loss_grad_metadata:https://gitcode.com/cann/ops-transformer/tree/master/attention/sparse_lightning_indexer_kl_loss_grad_metadata
sparse_lightning_indexer_kl_loss_grad:https://gitcode.com/cann/ops-transformer/tree/master/attention/sparse_lightning_indexer_kl_loss_grad
dense_lightning_indexer_softmax_lse_v2_metadata:https://gitcode.com/cann/ops-transformer/tree/master/attention/dense_lightning_indexer_softmax_lse_v2_metadata
dense_lightning_indexer_softmax_lse_v2:https://gitcode.com/cann/ops-transformer/tree/master/attention/dense_lightning_indexer_softmax_lse_v2
dense_lightning_indexer_kl_loss_grad_metadata:https://gitcode.com/cann/ops-transformer/tree/master/attention/dense_lightning_indexer_kl_loss_grad_metadata
dense_lightning_indexer_kl_loss_grad:https://gitcode.com/cann/ops-transformer/tree/master/attention/dense_lightning_indexer_kl_loss_grad


任务4:新流程 CP 多通信模式迁移设计方案
1. 结论
当前
refactor_hp/hyper_parallel/components/distributed中的 CP 实现,实际上只有一种通信算法:旧流程
hp/hyper_parallel/core/context_parallel/已经具备:迁移到新流程时,不能简单增加
sdpa_qkv_ulysses、sdpa_hf_hybrid_async等 wrapper。这样会把“网络调用方式 × attention primitive × CP 算法 × 同异步”做成笛卡尔积,注册表会快速膨胀。推荐把 CP 拆成两个正交层次:
最终组合关系是:
2. 当前实现与旧能力对比
当前新流程的关键问题不是缺少一个
all_to_all函数,而是:CP_WRAPPER_REGISTRY同时承担了模型识别和通信行为,职责耦合;_cp_sdpa_call固定执行 K/V all-gather;cp_mesh,没有 Hybrid 的子组拓扑;cp_utils.py直接调用torch.distributed,没有复用旧流程已有的 platform 可微和异步通信接口。3. 设计目标
3.1 必须满足
cp_size单独启用时保持当前默认行为:同步 K/V all-gather;Shard(sequence);new_group;3.2 第一版不做
co/ulysses维暴露成全局 ShardingPlan mesh 轴;ContextParallel类直接嵌入新 applier,避免新旧控制流再次耦合。4. 配置模型
4.1 Plan 级 CP 配置
新增 plan 级配置,算法选择不重复写入每个 attention spec:
class CPAlgorithm(str, Enum): ALL_GATHER = "all_gather" # 原 Pure Colossal ULYSSES = "ulysses" HYBRID = "hybrid" class CPSchedule(str, Enum): SYNC = "sync" ASYNC = "async" @dataclass(frozen=True) class ContextParallelConfig: algorithm: CPAlgorithm = CPAlgorithm.ALL_GATHER schedule: CPSchedule = CPSchedule.SYNC ulysses_degree: Optional[int] = None load_balance: bool = False async_fallback: Literal["error", "sync"] = "error"ShardingPlan新增:@dataclass class ShardingPlan: ... cp_config: Optional[ContextParallelConfig] = NoneShardingPlanner.plan新增:plan = planner.plan( model, mesh, tp_size=tp_size, cp_size=cp_size, cp_config=ContextParallelConfig( algorithm="hybrid", schedule="async", ulysses_degree=2, ), )兼容规则:
cp_size == 1:忽略 CP runtime;cp_size > 1且未传cp_config:生成all_gather + sync,保持当前新流程行为;algorithm,不再让ulysses_degree隐式决定模式;degree=1 -> all_gather,degree=cp -> ulysses,中间值 ->hybrid。4.2 Module 级 attention 描述
inner_target和inner_wrapper继续负责“目标位置”和“adapter 类型”。新增的字段只描述模块特有 layout 和异步 handoff:@dataclass class ModuleShardingSpec: ... inner_target: Optional[str] = None inner_wrapper: Optional[Union[str, Callable]] = None cp_seq_dim: int = 2 cp_head_dim: int = 1 cp_qkv_indices: Tuple[int, int, int] = (0, 1, 2) cp_qkv_kwarg_names: Tuple[str, ...] = () cp_handoff_targets: Dict[str, str] = field(default_factory=dict) _resolved_inner_wrapper: Optional[str] = None _resolved_cp_strategy: Optional[str] = Nonecp_handoff_targets的路径相对 attention boundary:ModuleShardingSpec( inner_target="self", inner_wrapper="sdpa_hf", cp_handoff_targets={ "q": "q_norm", "k": "k_norm", "v": "v_handoff", }, )handoff 必须是进入 attention primitive 前最后一个、输出直接作为 Q/K/V 使用的模块。若 projection 后还有 reshape、transpose、RoPE 或 QK-Norm,则不能把原始
q_proj/k_proj当成安全 handoff。5. 两级注册表
5.1 Attention Adapter 注册表
Adapter 只解决“怎样接入网络”,不决定 CP 算法:
CP_ADAPTER_REGISTRY = { "sdpa_qkv": SdpaQkvAdapter, "sdpa_hf": SdpaHfAdapter, "flex_qkv": FlexQkvAdapter, "flex_hf": FlexHfAdapter, }现有四个 wrapper 的迁移关系:
_wrap_sdpa_for_cp_wrap_hf_sdpa_for_cpF.scaled_dot_product_attention,把 primitive 调用交给 runtime_wrap_flex_attn_for_cp_wrap_hf_flex_for_cpflex_attention,把 primitive 调用交给 runtimeHF adapter 继续保留 misfire detection。一次 forward 没有拦截到目标 primitive 时立即报错。
5.2 CP Strategy 注册表
CP_STRATEGY_REGISTRY = { "all_gather": AllGatherCPStrategy, "ulysses": UlyssesCPStrategy, "hybrid": HybridCPStrategy, }统一接口建议为:
class CPStrategy: def prepare_qkv(self, q, k, v, runtime_ctx): """返回 attention 实际消费的 q/k/v 和本次调用状态。""" def restore_output(self, output, call_state): """把 attention 输出恢复为本地 sequence shard。""" def install_async_handoffs(self, target, handoff_spec, runtime_ctx): """异步模式下安装 producer hooks;同步模式为空操作。""" def causal_metadata(self, call_state): """返回全局 Q offset、Q/KV 长度等 mask 信息。"""Adapter 和 strategy 的组合伪代码:
def cp_aware_attention(q, k, v, primitive, kwargs): local_q, local_k, local_v, output_layout = unwrap_validate_dtensor(q, k, v) q2, k2, v2, state = strategy.prepare_qkv( local_q, local_k, local_v, runtime_ctx ) kwargs = mask_adapter.rewrite(kwargs, strategy.causal_metadata(state)) output = primitive(q2, k2, v2, **kwargs) output = strategy.restore_output(output, state) return rewrap_validate_output(output, output_layout)这样增加新算法时只增加 strategy;增加新网络调用方式时只增加 adapter。
5.3 旧注册表兼容
迁移期间保留
CP_WRAPPER_REGISTRY:sdpa_qkv/sdpa_hf/flex_qkv/flex_hf优先解析为新 adapter;fn(target, cp_mesh)调用;all_gather + sync,其他 strategy 必须报错,不能假装已经应用;inner_wrapper=Callable继续表示用户完全接管,框架不再叠加内置 strategy。6. 三种同步通信算法
以下统一以 BNSD
[B, N, S, D]为例;实际维度由cp_seq_dim/cp_head_dim指定。6.1 AllGather / Pure Colossal
输入:
前向:
反向:
当前
_AllGatherAlongDim.backward的all_reduce + chunk语义正确,但通信和显存开销较大。新 collective 层应优先使用reduce_scatter_tensor,后端不支持时再回退到all_reduce + chunk。6.2 Pure Ulysses
约束:本 rank 在 TP 切分后的 Q head 数和 KV head 数都能被
cp_size整除。前向:
反向中每个 all-to-all 的梯度都是方向相反的 all-to-all,不需要 reduce。
建议低层提供两个清晰接口:
二者使用自定义 autograd Function 或 platform 的可微
all_to_all_single,互为 backward。6.3 Hybrid
设:
从一维 CP mesh 派生内部二维拓扑:
该二维拓扑只在 CP runtime 内使用,模块边界仍只认识全局
cp轴。前向:
反向顺序:
Hybrid group 必须在 apply 阶段从
mesh["cp"]派生和缓存,forward 中只取 group handle。7. 异步调度设计
7.1 可重叠位置
Hybrid 第一版保持旧流程的“半异步”语义。K/V 在
cp_co上的 all-gather 暂不提前,避免两级 collective 的反向依赖和 stream 顺序变复杂。7.2 Handoff 安全规则
异步模式不能仅凭属性名看到
q_proj就自动启用。必须满足:cp_seq_dim/cp_head_dim一致;apply 阶段处理规则:
新 API 默认
error,防止用户以为已经获得 overlap;旧AsyncContextParallel兼容层可使用sync回退,保持旧行为。7.3 Runtime 状态
异步 handle 不能只放在一个覆盖式字典里。pipeline microbatch、activation checkpoint 重算和嵌套 forward 会同时存在多个调用。
每个已应用 attention 建立独立
CPRuntimeState:@dataclass class CPRuntimeState: forward_slots: Dict[str, Deque[AsyncSlot]] backward_slots: Dict[str, List[AsyncSlot]] invocation_id: int7.4 Autograd 语义
异步通信不能用“先异步裸 collective,稍后直接拿 output”的方式绕开 autograd。需要一个可微 wait 节点:
优先复用旧流程在
hyper_parallel.platform已有的接口:all_gather_single(..., async_op=True);all_to_all_single(..., async_op=True);differentiable_async_allgather_wait;differentiable_async_a2a_wait;reduce_scatter_single。不要在 components 中复制第二套 Torch-only async autograd 实现。
8. Causal mask
不同 strategy 的 Q 全局起点不同,mask 不能继续固定使用:
正确规则:
cp_rank * q_len0,保留标准is_causal=Truecp_corank 的连续大 chunkco_rank * q_len_after_a2a因此 strategy 应返回
CausalMetadata,adapter 只负责把它转换成 SDPA mask、Flex block mask 或后端 flash attention 参数。若原调用已经有
attn_mask:is_causal;第一版优先保证正确性;显式 SDPA mask 可能让 flash kernel 降级。后续可由 NPU/Flash adapter 使用原生 offset 参数恢复性能。
9. TP、GQA、MQA 与 layout 校验
9.1 TP + Ulysses
Ulysses 的整除检查必须使用 TP 后的本地 head 数:
等价的全局检查是 Q/KV head 数都能被
tp_size * ulysses_degree整除。9.2 GQA/MQA
第一版采用严格策略:
ulysses_degree;后续如需支持 KV heads 少于 Ulysses degree,可增加显式
kv_head_policy="repeat",并单独评估显存与通信开销。9.3 Layout
内置 primitive adapter 的默认 layout:
QKV 风格自定义 core attention 可以通过 spec 改为 BSHD:
ModuleShardingSpec( inner_wrapper="sdpa_qkv", cp_seq_dim=1, cp_head_dim=2, )进入通信前必须验证:
seq_dim != head_dim;cp_size % ulysses_degree == 0。10. production / validate 双模式
所有 strategy 都必须遵循当前 D-01'' 原则:
禁止 validate 依赖 DTensor
redistribute、production 使用手写 collective 的双路径实现,否则只能验证 placement,不能验证 kernel 级等价。TP layout 保存方式:
out_src重包装;cp_co/cp_ulyssesplacement 不离开 attention 区域。11. Planner 与 Applier 流程
11.1 Planner
def plan(..., cp_size=1, cp_config=None): cp_config = normalize_cp_config(cp_size, cp_config) validate_cp_config(model.config, tp_size, cp_size, cp_config) plan = infer_existing_sharding_plan(...) plan.cp_config = cp_config for attention_spec in plan: fill_default_cp_layout(attention_spec) merge_model_overrides(attention_spec) return planPlanner 负责静态检查:
11.2 Applier
def apply_phase_c(...): cp_mesh = get_cp_submesh(mesh) cp_topology = build_cp_topology(cp_mesh, plan.cp_config) for module, spec in attention_boundaries: adapter = resolve_cp_adapter(module, spec) strategy = resolve_cp_strategy(plan.cp_config) runtime = CPRuntime( topology=cp_topology, strategy=strategy, spec=spec, validate_mode=validate_mode, ) adapter.install(module, runtime)apply 阶段负责动态检查:
_resolved_inner_wrapper/_resolved_cp_strategy并记录日志。12. 文件修改规划
sharding_config.pyCPAlgorithm/CPSchedule/ContextParallelConfig;plan 级cp_config;spec 的 layout/handoff 字段sharding_planner.pycp_config;增加 mode/head/degree/load-balance 校验cp_collectives.py(新增)cp_strategy.py(新增)AllGatherCPStrategy/UlyssesCPStrategy/HybridCPStrategy、内部 topology、call statecp_adapters.py(新增)cp_utils.pyflex_cp_allgather做兼容导出sharding_applier.pyplatform/platform.pycomponents/distributed/__init__.pytests/components/distributed/13. 兼容性与错误策略
13.1 默认行为
planner.plan(model, mesh, cp_size=2)仍解析成:
现有 CP 用例无需改配置即可继续运行。
13.2 必须 fail-fast 的情况
cp_size % ulysses_degree != 0;cp_size;(1, cp_size);13.3 日志和可观测性
apply 后至少输出:
实际回退同步时,日志和
_resolved_cp_strategy必须反映真实执行方式。14. 分阶段迁移
M1:配置和分层,不改变当前数值路径
cp_config、adapter/strategy 两级抽象;AllGatherCPStrategy;M2:同步 Pure Ulysses
M3:同步 Hybrid
(cp_co, cp_ulysses);M4:异步模式
M5:原有扩展能力
15. 测试矩阵
15.1 单元测试
15.2 多进程数值测试
每个数值用例都与单卡完整序列参考比较:
15.3 异步性能验证
数值正确只证明“异步接口能运行”,不能证明发生了 overlap。NPU 集成测试还应检查 profiler timeline:
16. 用户侧最终形态
同步 Ulysses:
cp_config = ContextParallelConfig( algorithm="ulysses", schedule="sync", ) plan = planner.plan(model, mesh, cp_size=4, cp_config=cp_config)异步 all-gather:
cp_config = ContextParallelConfig( algorithm="all_gather", schedule="async", )Hybrid:
cp_config = ContextParallelConfig( algorithm="hybrid", schedule="async", ulysses_degree=2, )网络特殊信息仍通过 plan override 描述:
overrides = { "model.layers.0.self_attn": ModuleShardingSpec( inner_target="self", inner_wrapper="sdpa_hf", cp_seq_dim=2, cp_head_dim=1, cp_handoff_targets={ "q": "q_norm", "k": "k_norm", "v": "v_handoff", }, ), }算法配置属于 plan,网络结构差异属于 module spec。两者分离后,同一个模型适配不需要为每种 CP 通信模式重新写 wrapper。
17. 验收标准
任务4后续实现完成的最低标准:
cp_size>1默认路径与当前 all-gather 行为完全兼容;