已合并
【r1.9.0-beta1】【bugfix】增加softmax_out排布转换,以支持dsa一阶段tnd排布使用FA的tnd排布 #8288
【r1.9.0-beta1】【bugfix】增加softmax_out排布转换,以支持dsa一阶段tnd排布使用FA的tnd排布 #8288
已合并
wei_zhuoyi创建于 5月22日
共 2 个文件变更+135-37
@@ -30,8 +30,8 @@ from mindformers.parallel_core.transformer_config import MLATransformerConfig
30from mindformers.parallel_core.training_graph.transformer.dsa.dsa_indexer_loss import DSAIndexerLoss30from mindformers.parallel_core.training_graph.transformer.dsa.dsa_indexer_loss import DSAIndexerLoss
31from mindformers.parallel_core.training_graph.device_matrix import layout31from mindformers.parallel_core.training_graph.device_matrix import layout
32from mindformers.parallel_core.training_graph.communication import get_dp_cp_tp_id32from mindformers.parallel_core.training_graph.communication import get_dp_cp_tp_id
33-from mindformers.parallel_core.training_graph.transformer.mask_generate import CausalEODMaskGenerate
34from mindformers.parallel_core.training_graph.transformer.dsa.utils import adjust_bsnd_input, adjust_tnd_input33from mindformers.parallel_core.training_graph.transformer.dsa.utils import adjust_bsnd_input, adjust_tnd_input
34+from mindformers.parallel_core.training_graph.transformer.softmax_convert import SoftmaxConverter
35 35 
36 36 
37@dataclass37@dataclass
@@ -130,12 +130,11 @@ class DSAttention(nn.Cell):
130 head_num=self.head_num,130 head_num=self.head_num,
131 scale_value=self.softmax_scale,131 scale_value=self.softmax_scale,
132 inner_precise=0,132 inner_precise=0,
133- input_layout="BSND",133+ input_layout=self.input_layout,
134- sparse_mode=config.sparse_mode if not self.is_tnd else 0134+ sparse_mode=config.sparse_mode
135 )135 )
136- self.eod_mask_generator = CausalEODMaskGenerate(config)136+ self.softmax_converter = SoftmaxConverter(config)
137- self.softmax_transpose = aclnn_ops.Transpose()137+ self.slice = aclnn_ops.StridedSlice().add_prim_attr("self_define_shard", True)
138- self.slice = aclnn_ops.StridedSlice().add_prim_attr("self_define_shard", True)
139 if _get_parallel_mode() in (ParallelMode.SEMI_AUTO_PARALLEL,):138 if _get_parallel_mode() in (ParallelMode.SEMI_AUTO_PARALLEL,):
140 self.shard()139 self.shard()
141 140 
@@ -196,17 +195,6 @@ class DSAttention(nn.Cell):
196 max_logits = self.reduce_max(softmax_max, (0, 1, 2))195 max_logits = self.reduce_max(softmax_max, (0, 1, 2))
197 self.assign(self.max_logits_val, self.maximum(self.max_logits_val, max_logits))196 self.assign(self.max_logits_val, self.maximum(self.max_logits_val, max_logits))
198 else:197 else:
199- # During dense warmup stage, common FlashAttention will be applied instead of SparseFlashAttention
200- if self.is_tnd:
201- t, n, _ = query.shape
202- b, s = t // self.seq_length, self.seq_length
203- attention_mask = self.eod_mask_generator(self.reshape(actual_seq_qlen, (b, -1)))
204- query = self.reshape(query, (b, s, n, -1))
205- key = self.reshape(key, (b, s, n, -1))
206- value = self.reshape(value, (b, s, n, -1))
207- actual_seq_qlen = None
208- actual_seq_kvlen = None
209- 
210 softmax_max, softmax_sum, _, attention_output = self.dense_flash_attention(198 softmax_max, softmax_sum, _, attention_output = self.dense_flash_attention(
211 query, key, value,199 query, key, value,
212 None, None, None,200 None, None, None,
@@ -219,15 +207,14 @@ class DSAttention(nn.Cell):
219 step = (1,) * len(softmax_max.shape)207 step = (1,) * len(softmax_max.shape)
220 softmax_max = self.slice(softmax_max, begin, (*softmax_shape, 1), step)208 softmax_max = self.slice(softmax_max, begin, (*softmax_shape, 1), step)
221 softmax_sum = self.slice(softmax_sum, begin, (*softmax_shape, 1), step)209 softmax_sum = self.slice(softmax_sum, begin, (*softmax_shape, 1), step)
222- if self.track_max_attention_logit:
223- max_logits = self.reduce_max(softmax_max, (0, 2, 3))
224- self.assign(self.max_logits_val, self.maximum(self.max_logits_val, max_logits))
225 if self.is_tnd:210 if self.is_tnd:
226- # [b, s, n, d] -> [t, n, d]211+ softmax_max, softmax_sum = self.softmax_converter(softmax_max, softmax_sum, actual_seq_qlen)
227- attention_output = self.reshape(attention_output, (t, n, -1))212+ if self.track_max_attention_logit:
228- # [b, n, s, 1] -> [n, b, s, 1] -> [n, t, 1]213+ if self.is_tnd:
229- softmax_max = self.reshape(self.softmax_transpose(softmax_max, (1, 0, 2, 3)), (n, t, 1))214+ max_logits = self.reduce_max(softmax_max, (1, 2))
230- softmax_sum = self.reshape(self.softmax_transpose(softmax_sum, (1, 0, 2, 3)), (n, t, 1))215+ else:
216+ max_logits = self.reduce_max(softmax_max, (0, 2, 3))
217+ self.assign(self.max_logits_val, self.maximum(self.max_logits_val, max_logits))
231 218 
232 return attention_output, softmax_max, softmax_sum219 return attention_output, softmax_max, softmax_sum
233 220 
@@ -238,35 +225,42 @@ class DSAttention(nn.Cell):
238 q_shard = layout("dp_cp_tp", "None", "None")225 q_shard = layout("dp_cp_tp", "None", "None")
239 kv_shard = layout("dp", "None", "None")226 kv_shard = layout("dp", "None", "None")
240 idx_shard = layout("dp_cp_tp", "None", "None")227 idx_shard = layout("dp_cp_tp", "None", "None")
241- attn_shard = layout("dp_cp_tp", "None", "None")
242- softmax_shard = layout("None", "dp_cp_tp", "None")
243 sfa_shard = (q_shard, kv_shard, kv_shard, idx_shard, q_shard, kv_shard, layout("dp"), layout("dp"))228 sfa_shard = (q_shard, kv_shard, kv_shard, idx_shard, q_shard, kv_shard, layout("dp"), layout("dp"))
229+ fa_shard = (
230+ layout("dp_cp", "tp", "None"),
231+ layout("dp", "tp", "None"),
232+ layout("dp", "tp", "None"),
233+ layout("None", "None"),
234+ layout("dp"), layout("dp")
235+ )
244 else:236 else:
245 q_shard = layout("dp", "cp_tp", "None", "None")237 q_shard = layout("dp", "cp_tp", "None", "None")
246 kv_shard = layout("dp", "None", "None", "None")238 kv_shard = layout("dp", "None", "None", "None")
247 idx_shard = layout("dp", "cp_tp", "None", "None")239 idx_shard = layout("dp", "cp_tp", "None", "None")
248- attn_shard = layout("dp", "cp_tp", "None", "None")
249- softmax_shard = layout("dp", "None", "cp_tp", "None")
250 sfa_shard = (q_shard, kv_shard, kv_shard, idx_shard, q_shard, kv_shard)240 sfa_shard = (q_shard, kv_shard, kv_shard, idx_shard, q_shard, kv_shard)
251- self.split_q.shard((q_shard,))
252- self.split_k.shard((kv_shard,))
253- if self.sparse_loss:
254- self.sparse_flash_attention.shard(sfa_shard, (attn_shard, softmax_shard, softmax_shard))
255- else:
256 fa_shard = (241 fa_shard = (
257 layout("dp", "cp", "tp", "None"),242 layout("dp", "cp", "tp", "None"),
258 layout("dp", "None", "tp", "None"),243 layout("dp", "None", "tp", "None"),
259 layout("dp", "None", "tp", "None"),244 layout("dp", "None", "tp", "None"),
260 layout("None", "None") if self.mask_compression else layout("dp", "None", "cp", "None"),245 layout("None", "None") if self.mask_compression else layout("dp", "None", "cp", "None"),
261 )246 )
262- softmax_shard = layout("dp", "tp", "cp", "None")247+ self.split_q.shard((q_shard,))
263- attn_shard = layout("dp", "cp", "tp", "None")248+ self.split_k.shard((kv_shard,))
249+ if self.sparse_loss:
250+ attn_shard = layout("dp_cp_tp", "None", "None") if self.is_tnd else layout("dp", "cp_tp", "None", "None")
251+ softmax_shard = layout("None", "dp_cp_tp", "None") if self.is_tnd else layout("dp", "None", "cp_tp", "None")
252+ self.sparse_flash_attention.shard(sfa_shard, (attn_shard, softmax_shard, softmax_shard))
253+ else:
254+ softmax_shard = layout("dp_cp", "tp", "None") if self.is_tnd else layout("dp", "tp", "cp", "None")
255+ attn_shard = layout("dp_cp", "tp", "None") if self.is_tnd else layout("dp", "cp", "tp", "None")
264 self.dense_flash_attention.shard(fa_shard, (softmax_shard, softmax_shard, layout("None"), attn_shard))256 self.dense_flash_attention.shard(fa_shard, (softmax_shard, softmax_shard, layout("None"), attn_shard))
265 self.slice.shard((softmax_shard,), (softmax_shard,))257 self.slice.shard((softmax_shard,), (softmax_shard,))
266- self.softmax_transpose.shard((layout("dp", "tp", "cp", "None"),))258+ 
267 if self.track_max_attention_logit:259 if self.track_max_attention_logit:
268 if self.sparse_loss:260 if self.sparse_loss:
269 softmax_shard = layout("None", "dp_cp", "tp") if self.is_tnd else layout("dp", "None", "cp", "tp")261 softmax_shard = layout("None", "dp_cp", "tp") if self.is_tnd else layout("dp", "None", "cp", "tp")
262+ else:
263+ softmax_shard = layout("tp", "dp_cp", "None") if self.is_tnd else layout("dp", "tp", "cp", "None")
270 self.assign.shard((layout("tp"), layout("tp")), (layout("tp"),))264 self.assign.shard((layout("tp"), layout("tp")), (layout("tp"),))
271 self.maximum.shard((layout("tp"), layout("tp")), (layout("tp"),))265 self.maximum.shard((layout("tp"), layout("tp")), (layout("tp"),))
272 self.reduce_max.shard((softmax_shard,), (layout("tp"),))266 self.reduce_max.shard((softmax_shard,), (layout("tp"),))
@@ -0,0 +1,104 @@
1+# Copyright 2026 Huawei Technologies Co., Ltd
2+#
3+# Licensed under the Apache License, Version 2.0 (the "License");
4+# you may not use this file except in compliance with the License.
5+# You may obtain a copy of the License at
6+#
7+# http://www.apache.org/licenses/LICENSE-2.0
8+#
9+# Unless required by applicable law or agreed to in writing, software
10+# distributed under the License is distributed on an "AS IS" BASIS,
11+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+# See the License for the specific language governing permissions and
13+# limitations under the License.
14+# ============================================================================
15+"""Convert Softmax_out Layout"""
16+from mindspore import nn, ops
17+from mindspore.ops import auto_generate as aclnn_ops
18+from mindspore import dtype as mstype
19+ 
20+from mindformers.parallel_core.training_graph.communication import get_dp_cp_tp_id
21+from mindformers.parallel_core.training_graph.device_matrix import layout
22+from mindformers.parallel_core.transformer_config import TransformerConfig
23+ 
24+ 
25+class SoftmaxConverter(nn.Cell):
26+ """convert softmax_max and softmax_sum layout of FlashAttentionScore in TND layout"""
27+ def __init__(self, config: TransformerConfig):
28+ super().__init__()
29+ if not config.input_layout != "TND":
30+ raise ValueError("Only softmax_out in TND layout need to be converted!")
31+ self.seq_length = config.seq_length
32+ self.head_num = config.num_attention_heads
33+ self.is_dryrun = config.is_dryrun
34+ self.tp = config.tensor_model_parallel_size
35+ self.cp = config.context_parallel_size
36+ self.cp_id = get_dp_cp_tp_id(config)[1]
37+ 
38+ self.cast = aclnn_ops.Cast()
39+ self.reshape = aclnn_ops.Reshape()
40+ self.slice = aclnn_ops.StridedSlice().add_prim_attr("self_define_shard", True)
41+ self.clamp = aclnn_ops.ClampScalar()
42+ self.roll = aclnn_ops.Roll(1)
43+ self.repeat_scalar = aclnn_ops.RepeatInterleaveInt()
44+ self.arange = aclnn_ops.Arange()
45+ self.mod = aclnn_ops.FmodScalar()
46+ self.repeat_interleave = aclnn_ops.RepeatInterleaveTensor()
47+ self.equal = aclnn_ops.Equal()
48+ self.select = aclnn_ops.MaskedSelect()
49+ self.stack = aclnn_ops.StackExt()
50+ self.softmax_transpose = aclnn_ops.Transpose()
51+ infer_dtype = lambda *args: (args[0], args[1])
52+ self.convert_softmax = ops.Morph(
53+ self._convert_softmax,
54+ self.infer_shape, infer_dtype
55+ ).add_prim_attr("self_define_shard", True)
56+ self.shard()
57+ 
58+ def infer_shape(self, *args):
59+ t, n, _ = args[0]
60+ out_shape = [n, t, 1]
61+ return out_shape, out_shape
62+ 
63+ def _convert_softmax(self, softmax_max, softmax_sum, actual_seq_len):
64+ """convert softmax layout"""
65+ t, n, _ = softmax_max.shape
66+ softmax_max = self.reshape(softmax_max, (-1,))
67+ softmax_sum = self.reshape(softmax_sum, (-1,))
68+ partial_num_head = self.head_num // self.tp
69+ offset_q = t * self.cp_id
70+ actual_seq_qlen = self.cast(self.clamp(actual_seq_len - offset_q, 0, t), mstype.int32)
71+ prev_seq_qlen = self.roll(actual_seq_qlen)
72+ prev_seq_qlen[0] = 0
73+ interleave_seq_qlen = actual_seq_qlen - prev_seq_qlen
74+ interleave_seq_qlen = self.repeat_scalar(interleave_seq_qlen, partial_num_head)
75+ base = self.mod(self.arange(0, interleave_seq_qlen.shape[0], 1), partial_num_head)
76+ interleave_seq_qlen = self.repeat_interleave(base, interleave_seq_qlen)
77+ softmax_maxs = []
78+ softmax_sums = []
79+ for i in range(partial_num_head):
80+ head_mask = self.equal(interleave_seq_qlen, i)
81+ softmax_maxs.append(self.select(softmax_max, head_mask))
82+ softmax_sums.append(self.select(softmax_sum, head_mask))
83+ softmax_max = self.reshape(self.stack(softmax_maxs), (n, t, 1))
84+ softmax_sum = self.reshape(self.stack(softmax_sums), (n, t, 1))
85+ return softmax_max, softmax_sum
86+ 
87+ def construct(self, softmax_max, softmax_sum, actual_seq_len):
88+ if self.is_dryrun:
89+ softmax_max = self.softmax_transpose(softmax_max, (1, 0, 2))
90+ softmax_sum = self.softmax_transpose(softmax_sum, (1, 0, 2))
91+ return softmax_max, softmax_sum
92+ if softmax_max.shape[-1] != 1:
93+ softmax_shape = softmax_max.shape[:-1]
94+ softmax_max = self.slice(softmax_max, (0, 0, 0), (*softmax_shape, 1), (1, 1, 1))
95+ softmax_sum = self.slice(softmax_sum, (0, 0, 0), (*softmax_shape, 1), (1, 1, 1))
96+ return self.convert_softmax(softmax_max, softmax_sum, actual_seq_len)
97+ 
98+ def shard(self):
99+ self.slice.shard((layout("dp_cp", "tp", "None"),), (layout("dp_cp", "tp", "None"),))
100+ self.convert_softmax.shard(
101+ (layout("dp_cp", "tp", "None"), layout("dp_cp", "tp", "None"), layout("dp")),
102+ (layout("tp", "dp_cp", "None"), layout("tp", "dp_cp", "None"))
103+ )
104+ self.softmax_transpose.shard((layout("dp_cp", "tp", "None"),))