main
py 428 lines 12.3 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 import torch
4
5 from vllm.utils.torch_utils import direct_register_custom_op
6
7
8 def mhc_pre_aiter(
9 residual: torch.Tensor,
10 fn: torch.Tensor,
11 hc_scale: torch.Tensor,
12 hc_base: torch.Tensor,
13 rms_eps: float,
14 hc_pre_eps: float,
15 hc_sinkhorn_eps: float,
16 hc_post_mult_value: float,
17 sinkhorn_repeat: int,
18 n_splits: int = 1,
19 norm_weight: torch.Tensor | None = None,
20 norm_eps: float = 0.0,
21 ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
22 """Forward pass for mHC pre block.
23
24 Args:
25 residual: shape (..., hc_mult, hidden_size), dtype torch.bfloat16
26 fn: shape (hc_mult3, hc_mult * hidden_size), dtype torch.float32
27 hc_scale: shape (3,), dtype torch.float32
28 hc_base: shape (hc_mult3,), dtype torch.float32
29 rms_eps: RMS normalization epsilon
30 hc_pre_eps: pre-mix epsilon
31 hc_sinkhorn_eps: sinkhorn epsilon
32 hc_post_mult_value: post-mix multiplier value
33 sinkhorn_repeat: number of sinkhorn iterations
34 n_splits: split-k factor;
35 norm_weight: optional RMSNorm weight fused into the pre kernel
36 norm_eps: epsilon for the fused RMSNorm when norm_weight is set
37
38 Returns:
39 post_mix: shape (..., hc_mult), dtype torch.float32
40 comb_mix: shape (..., hc_mult, hc_mult), dtype torch.float32
41 layer_input: shape (..., hidden_size), dtype torch.bfloat16
42
43 """
44 hidden_size = residual.shape[-1]
45 assert hidden_size % 256 == 0
46 from vllm._aiter_ops import rocm_aiter_ops
47
48 return rocm_aiter_ops.mhc_pre(
49 residual,
50 fn,
51 hc_scale,
52 hc_base,
53 rms_eps,
54 hc_pre_eps,
55 hc_sinkhorn_eps,
56 hc_post_mult_value,
57 sinkhorn_repeat,
58 norm_weight,
59 norm_eps,
60 )
61
62
63 def _mhc_pre_aiter_fake(
64 residual: torch.Tensor,
65 fn: torch.Tensor,
66 hc_scale: torch.Tensor,
67 hc_base: torch.Tensor,
68 rms_eps: float,
69 hc_pre_eps: float,
70 hc_sinkhorn_eps: float,
71 hc_post_mult_value: float,
72 sinkhorn_repeat: int,
73 n_splits: int = 1,
74 norm_weight: torch.Tensor | None = None,
75 norm_eps: float = 0.0,
76 ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
77 hc_mult = residual.shape[-2]
78 hidden_size = residual.shape[-1]
79 outer_shape = residual.shape[:-2]
80
81 # Create empty tensors with correct shapes for meta device / shape inference
82 post_mix = torch.empty(
83 *outer_shape,
84 hc_mult,
85 1,
86 dtype=torch.float32,
87 device=residual.device,
88 )
89 comb_mix = torch.empty(
90 *outer_shape,
91 hc_mult,
92 hc_mult,
93 dtype=torch.float32,
94 device=residual.device,
95 )
96 layer_input = torch.empty(
97 *outer_shape,
98 hidden_size,
99 dtype=torch.bfloat16,
100 device=residual.device,
101 )
102
103 return post_mix, comb_mix, layer_input
104
105
106 def mhc_pre_delayed_aiter(
107 residual: torch.Tensor,
108 fn: torch.Tensor,
109 hc_scale: torch.Tensor,
110 hc_base: torch.Tensor,
111 rms_eps: float,
112 hc_pre_eps: float,
113 hc_sinkhorn_eps: float,
114 hc_post_mult_value: float,
115 sinkhorn_repeat: int,
116 pre_mix: torch.Tensor | None = None,
117 sublayer_out: torch.Tensor | None = None,
118 post_layer_mix: torch.Tensor | None = None,
119 comb_res_mix: torch.Tensor | None = None,
120 residual_out: torch.Tensor | None = None,
121 ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]:
122 """MHC pre with the pre-mix carried in from the previous sublayer.
123
124 Matches ``mhc_pre_delayed_torch``: the stream collapse uses *pre_mix*
125 rather than the gate computed here, and that gate is returned as the
126 pre-mix for the next sublayer seam.
127
128 Args:
129 residual: shape (..., hc_mult, hidden_size), dtype torch.bfloat16
130 fn: shape (hc_mult3, hc_mult * hidden_size), dtype torch.float32
131 hc_scale: shape (3,), dtype torch.float32
132 hc_base: shape (hc_mult3,), dtype torch.float32
133 rms_eps: RMS normalization epsilon
134 hc_pre_eps: pre-mix epsilon
135 hc_sinkhorn_eps: sinkhorn epsilon
136 hc_post_mult_value: post-mix multiplier value
137 sinkhorn_repeat: number of sinkhorn iterations
138 pre_mix: shape (..., hc_mult) from the previous sublayer, or None at
139 model entry to select residual stream zero.
140 sublayer_out: attention or FFN output, shape (..., hidden_size). When
141 given with the two mixes below, the preceding post block is
142 applied here so AITER can fold it into the pre projection.
143 post_layer_mix: shape (..., hc_mult, 1), post gate for that block.
144 comb_res_mix: shape (..., hc_mult, hc_mult), residual comb for it.
145 residual_out: shape (..., hc_mult, hidden_size), written with the post
146 block's new residual. Required exactly when the post is folded in.
147
148 Returns:
149 post_mix: shape (..., hc_mult, 1), dtype torch.float32
150 comb_mix: shape (..., hc_mult, hc_mult), dtype torch.float32
151 layer_input: shape (..., hidden_size), dtype torch.bfloat16
152 next_pre_mix: shape (..., hc_mult), dtype torch.float32
153
154 """
155 hidden_size = residual.shape[-1]
156 assert hidden_size % 256 == 0
157 from vllm._aiter_ops import rocm_aiter_ops
158
159 return rocm_aiter_ops.mhc_pre_delayed(
160 residual,
161 fn,
162 hc_scale,
163 hc_base,
164 rms_eps,
165 hc_pre_eps,
166 hc_sinkhorn_eps,
167 hc_post_mult_value,
168 sinkhorn_repeat,
169 pre_mix,
170 sublayer_out,
171 post_layer_mix,
172 comb_res_mix,
173 residual_out,
174 )
175
176
177 def _mhc_pre_delayed_aiter_fake(
178 residual: torch.Tensor,
179 fn: torch.Tensor,
180 hc_scale: torch.Tensor,
181 hc_base: torch.Tensor,
182 rms_eps: float,
183 hc_pre_eps: float,
184 hc_sinkhorn_eps: float,
185 hc_post_mult_value: float,
186 sinkhorn_repeat: int,
187 pre_mix: torch.Tensor | None = None,
188 sublayer_out: torch.Tensor | None = None,
189 post_layer_mix: torch.Tensor | None = None,
190 comb_res_mix: torch.Tensor | None = None,
191 residual_out: torch.Tensor | None = None,
192 ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]:
193 hc_mult = residual.shape[-2]
194 hidden_size = residual.shape[-1]
195 outer_shape = residual.shape[:-2]
196 return (
197 torch.empty(
198 *outer_shape, hc_mult, 1, dtype=torch.float32, device=residual.device
199 ),
200 torch.empty(
201 *outer_shape, hc_mult, hc_mult, dtype=torch.float32, device=residual.device
202 ),
203 torch.empty(
204 *outer_shape, hidden_size, dtype=torch.bfloat16, device=residual.device
205 ),
206 torch.empty(*outer_shape, hc_mult, dtype=torch.float32, device=residual.device),
207 )
208
209
210 def mhc_fused_post_pre_delayed_rms_norm_aiter(
211 residual: torch.Tensor,
212 fn: torch.Tensor,
213 hc_scale: torch.Tensor,
214 hc_base: torch.Tensor,
215 rms_eps: float,
216 hc_pre_eps: float,
217 hc_sinkhorn_eps: float,
218 hc_post_mult_value: float,
219 sinkhorn_repeat: int,
220 pre_mix: torch.Tensor | None,
221 sublayer_out: torch.Tensor | None,
222 post_layer_mix: torch.Tensor | None,
223 comb_res_mix: torch.Tensor | None,
224 norm_weight: torch.Tensor,
225 norm_eps: float,
226 residual_out: torch.Tensor | None,
227 ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]:
228 """:func:`mhc_pre_delayed_aiter` with the RMSNorm of the collapse folded in:
229 ``layer_input`` comes back normalised with ``norm_weight`` / ``norm_eps``."""
230 from vllm._aiter_ops import rocm_aiter_ops
231
232 return rocm_aiter_ops.mhc_fused_post_pre_delayed_rms_norm(
233 residual,
234 fn,
235 hc_scale,
236 hc_base,
237 rms_eps,
238 hc_pre_eps,
239 hc_sinkhorn_eps,
240 hc_post_mult_value,
241 sinkhorn_repeat,
242 pre_mix,
243 sublayer_out,
244 post_layer_mix,
245 comb_res_mix,
246 norm_weight,
247 norm_eps,
248 residual_out,
249 )
250
251
252 def _mhc_fused_post_pre_delayed_rms_norm_aiter_fake(
253 residual: torch.Tensor,
254 fn: torch.Tensor,
255 hc_scale: torch.Tensor,
256 hc_base: torch.Tensor,
257 rms_eps: float,
258 hc_pre_eps: float,
259 hc_sinkhorn_eps: float,
260 hc_post_mult_value: float,
261 sinkhorn_repeat: int,
262 pre_mix: torch.Tensor | None,
263 sublayer_out: torch.Tensor | None,
264 post_layer_mix: torch.Tensor | None,
265 comb_res_mix: torch.Tensor | None,
266 norm_weight: torch.Tensor,
267 norm_eps: float,
268 residual_out: torch.Tensor | None,
269 ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]:
270 return _mhc_pre_delayed_aiter_fake(
271 residual,
272 fn,
273 hc_scale,
274 hc_base,
275 rms_eps,
276 hc_pre_eps,
277 hc_sinkhorn_eps,
278 hc_post_mult_value,
279 sinkhorn_repeat,
280 )
281
282
283 def mhc_post_aiter(
284 x: torch.Tensor,
285 residual: torch.Tensor,
286 post_layer_mix: torch.Tensor,
287 comb_res_mix: torch.Tensor,
288 ) -> torch.Tensor:
289 hidden_size = residual.shape[-1]
290
291 assert hidden_size % 256 == 0
292 from vllm._aiter_ops import rocm_aiter_ops
293
294 return rocm_aiter_ops.mhc_post(
295 x,
296 residual,
297 post_layer_mix,
298 comb_res_mix,
299 )
300
301
302 def _mhc_post_aiter_fake(
303 x: torch.Tensor,
304 residual: torch.Tensor,
305 post_layer_mix: torch.Tensor,
306 comb_res_mix: torch.Tensor,
307 ) -> torch.Tensor:
308 return torch.empty_like(residual)
309
310
311 def mhc_fused_post_pre_aiter(
312 x: torch.Tensor,
313 residual: torch.Tensor,
314 post_layer_mix: torch.Tensor,
315 comb_res_mix: torch.Tensor,
316 fn: torch.Tensor,
317 hc_scale: torch.Tensor,
318 hc_base: torch.Tensor,
319 rms_eps: float,
320 hc_pre_eps: float,
321 hc_sinkhorn_eps: float,
322 hc_post_mult_value: float,
323 sinkhorn_repeat: int,
324 n_splits: int = 1,
325 tile_n: int = 1,
326 norm_weight: torch.Tensor | None = None,
327 norm_eps: float = 0.0,
328 ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]:
329 """Fused mHC post + next mHC pre on ROCm via AITER.
330
331 Returns residual_cur, post_mix_cur, comb_mix_cur, layer_input_cur.
332 """
333 hidden_size = residual.shape[-1]
334 assert hidden_size % 256 == 0
335 from vllm._aiter_ops import rocm_aiter_ops
336
337 return rocm_aiter_ops.mhc_fused_post_pre(
338 x,
339 residual,
340 post_layer_mix,
341 comb_res_mix,
342 fn,
343 hc_scale,
344 hc_base,
345 rms_eps,
346 hc_pre_eps,
347 hc_sinkhorn_eps,
348 hc_post_mult_value,
349 sinkhorn_repeat,
350 norm_weight,
351 norm_eps,
352 )
353
354
355 def _mhc_fused_post_pre_aiter_fake(
356 x: torch.Tensor,
357 residual: torch.Tensor,
358 post_layer_mix: torch.Tensor,
359 comb_res_mix: torch.Tensor,
360 fn: torch.Tensor,
361 hc_scale: torch.Tensor,
362 hc_base: torch.Tensor,
363 rms_eps: float,
364 hc_pre_eps: float,
365 hc_sinkhorn_eps: float,
366 hc_post_mult_value: float,
367 sinkhorn_repeat: int,
368 n_splits: int = 1,
369 tile_n: int = 1,
370 norm_weight: torch.Tensor | None = None,
371 norm_eps: float = 0.0,
372 ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]:
373 hc_mult = residual.shape[-2]
374 hidden_size = residual.shape[-1]
375 outer_shape = residual.shape[:-2]
376 post_mix = torch.empty(
377 *outer_shape,
378 hc_mult,
379 1,
380 dtype=torch.float32,
381 device=residual.device,
382 )
383 comb_mix = torch.empty(
384 *outer_shape,
385 hc_mult,
386 hc_mult,
387 dtype=torch.float32,
388 device=residual.device,
389 )
390 layer_input = torch.empty(
391 *outer_shape,
392 hidden_size,
393 dtype=torch.bfloat16,
394 device=residual.device,
395 )
396 return torch.empty_like(residual), post_mix, comb_mix, layer_input
397
398
399 direct_register_custom_op(
400 op_name="mhc_pre_aiter",
401 op_func=mhc_pre_aiter,
402 mutates_args=[],
403 fake_impl=_mhc_pre_aiter_fake,
404 )
405 direct_register_custom_op(
406 op_name="mhc_pre_delayed_aiter",
407 op_func=mhc_pre_delayed_aiter,
408 mutates_args=["residual_out"],
409 fake_impl=_mhc_pre_delayed_aiter_fake,
410 )
411 direct_register_custom_op(
412 op_name="mhc_fused_post_pre_delayed_rms_norm_aiter",
413 op_func=mhc_fused_post_pre_delayed_rms_norm_aiter,
414 mutates_args=["residual_out"],
415 fake_impl=_mhc_fused_post_pre_delayed_rms_norm_aiter_fake,
416 )
417 direct_register_custom_op(
418 op_name="mhc_post_aiter",
419 op_func=mhc_post_aiter,
420 mutates_args=[],
421 fake_impl=_mhc_post_aiter_fake,
422 )
423 direct_register_custom_op(
424 op_name="mhc_fused_post_pre_aiter",
425 op_func=mhc_fused_post_pre_aiter,
426 mutates_args=[],
427 fake_impl=_mhc_fused_post_pre_aiter_fake,
428 )