Coverage for  / home / jenkins / .local / lib / python3.10 / site-packages / hyper_multicore / modules / mega_mhc / function.py: 73%

59 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-11-15 05:03 +0800

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"""Functional entry point for the BF16 HyperMegaMhc scheduler kernel.""" 

16 

17from __future__ import annotations 

18 

19from functools import lru_cache 

20from typing import Any 

21 

22import torch 

23 

24from hyper_multicore._core_spec import get_device_core_spec 

25from hyper_multicore.modules.mega_mhc_grad.common import MegaMhcGradCache 

26from hyper_multicore.modules.mega_mhc_grad.function import hyper_mega_mhc_grad 

27from hyper_multicore.torch import ops as multicore_ops 

28 

29from ..mega_mhc_common import ( 

30 MHC_SINKHORN_ITERS, 

31 MegaMhcOutputs, 

32 validate_mega_mhc_core_spec, 

33 validate_mega_mhc_native_inputs, 

34 validate_mega_mhc_token_count, 

35) 

36from .graph import DEFAULT_TOKEN_TILE 

37from .plan import MegaMhcPlan, build_mega_mhc_plan 

38 

39 

40@lru_cache(maxsize=16) 

41def _get_cached_plan( 

42 token_count: int, 

43 hidden_size: int, 

44 device_index: int, 

45 num_cube_cores: int, 

46 token_tile: int, 

47) -> MegaMhcPlan: 

48 """Reuse immutable RuntimeConfig tensors for recurring static shapes.""" 

49 return build_mega_mhc_plan( 

50 token_count, 

51 hidden_size, 

52 torch.device("npu", device_index), 

53 num_cube_cores, 

54 token_tile, 

55 ) 

56 

57 

58def _restore_forward_outputs( 

59 outputs: tuple[torch.Tensor, ...], 

60 leading_shape: tuple[int, ...], 

61 hidden_size: int, 

62) -> tuple[MegaMhcOutputs, MegaMhcGradCache]: 

63 """Restore public dimensions and retain the native-layout backward cache.""" 

64 ( 

65 new_residual, 

66 next_pre, 

67 next_post, 

68 next_res, 

69 block_input, 

70 hc_before_norm, 

71 inv_rms, 

72 sum_out, 

73 norm_out, 

74 mixed_input, 

75 rms_rstd, 

76 ) = outputs 

77 public_outputs = ( 

78 new_residual.reshape(*leading_shape, 4, hidden_size), 

79 next_pre.reshape(*leading_shape, 4), 

80 next_post.reshape(*leading_shape, 4), 

81 next_res.reshape(*leading_shape, 4, 4), 

82 block_input.reshape(*leading_shape, hidden_size), 

83 ) 

84 cache = MegaMhcGradCache( 

85 new_residual=new_residual, 

86 hc_before_norm=hc_before_norm, 

87 inv_rms=inv_rms, 

88 sum_out=sum_out, 

89 norm_out=norm_out, 

90 mixed_input=mixed_input, 

91 rms_rstd=rms_rstd, 

92 ) 

93 return public_outputs, cache 

94 

95 

96def _hyper_mega_mhc_forward( 

97 previous_output: torch.Tensor, 

98 residual: torch.Tensor, 

99 previous_pre_mix: torch.Tensor, 

100 previous_post_mix: torch.Tensor, 

101 previous_residual_mix: torch.Tensor, 

102 phi: torch.Tensor, 

103 alpha: torch.Tensor, 

104 bias: torch.Tensor, 

105 norm_weight: torch.Tensor, 

106 *, 

107 hc_eps: float = 1e-6, 

108 norm_eps: float = 1e-6, 

109 num_iters: int = MHC_SINKHORN_ITERS, 

110 need_backward: bool = True, 

111 token_tile: int = DEFAULT_TOKEN_TILE, 

112) -> tuple[MegaMhcOutputs, MegaMhcGradCache]: 

113 """Run one shifted boundary and retain the native backward cache. 

114 

115 Args: 

116 previous_output: Previous block output. 

117 residual: Previous residual streams. 

118 previous_pre_mix: Previous pre-mix coefficients. 

119 previous_post_mix: Previous post-mix coefficients. 

120 previous_residual_mix: Previous residual-mix coefficients. 

121 phi: Projection weights. 

122 alpha: Mapping scale parameters. 

123 bias: Mapping bias parameters. 

124 norm_weight: Shifted RMSNorm weight. 

125 hc_eps: Sinkhorn numerical-stability epsilon. 

126 norm_eps: RMS normalization epsilon. 

127 num_iters: Sinkhorn iteration count. 

128 need_backward: Whether to retain native backward caches. 

129 token_tile: Number of tokens assigned to each logical task. 

130 """ 

131 validate_mega_mhc_native_inputs( 

132 previous_output, 

133 residual, 

134 previous_pre_mix, 

135 previous_post_mix, 

136 previous_residual_mix, 

137 phi, 

138 alpha, 

139 bias, 

140 norm_weight, 

141 num_iters=num_iters, 

142 need_backward=need_backward, 

143 token_tile=token_tile, 

144 ) 

145 leading_shape = residual.shape[:-2] 

146 hidden_size = residual.shape[-1] 

147 token_count = residual.numel() // (4 * hidden_size) 

148 device_index = residual.device.index 

149 if device_index is None: 

150 device_index = torch.npu.current_device() 

151 core_spec = get_device_core_spec(device_index) 

152 validate_mega_mhc_core_spec(core_spec) 

153 num_cube_cores, num_vector_cores = core_spec.num_cube_cores, core_spec.num_vector_cores 

154 if need_backward: 

155 validate_mega_mhc_token_count(token_count, num_vector_cores) 

156 plan = _get_cached_plan( 

157 token_count, 

158 hidden_size, 

159 device_index, 

160 num_cube_cores, 

161 token_tile, 

162 ) 

163 events = torch.zeros(plan.event_capacity * 4, dtype=torch.uint8, device=residual.device) 

164 options = {} 

165 if plan.runtime.is_active: 

166 options["diagnostics"] = plan.runtime 

167 outputs = multicore_ops.hyper_mega_mhc( 

168 previous_output.reshape(1, token_count, hidden_size).contiguous(), 

169 residual.reshape(1, token_count, 4, hidden_size).contiguous(), 

170 previous_pre_mix.reshape(1, token_count, 4).contiguous(), 

171 previous_post_mix.reshape(1, token_count, 4).contiguous(), 

172 previous_residual_mix.reshape(1, token_count, 4, 4).contiguous(), 

173 phi.contiguous(), 

174 alpha.contiguous(), 

175 bias.contiguous(), 

176 norm_weight.contiguous(), 

177 plan.runtime.runtime_config, 

178 events, 

179 events, 

180 hc_eps=hc_eps, 

181 norm_eps=norm_eps, 

182 num_iters=num_iters, 

183 need_backward=need_backward, 

184 **options, 

185 ) 

186 return _restore_forward_outputs(outputs, leading_shape, hidden_size) 

187 

188 

189class _HyperMegaMhcFunction(torch.autograd.Function): 

190 """Connect the fused forward and backward NPU operators to autograd.""" 

191 

192 @staticmethod 

193 def forward( 

194 ctx: Any, 

195 previous_output: torch.Tensor, 

196 residual: torch.Tensor, 

197 previous_pre_mix: torch.Tensor, 

198 previous_post_mix: torch.Tensor, 

199 previous_residual_mix: torch.Tensor, 

200 phi: torch.Tensor, 

201 alpha: torch.Tensor, 

202 bias: torch.Tensor, 

203 norm_weight: torch.Tensor, 

204 hc_eps: float, 

205 norm_eps: float, 

206 num_iters: int, 

207 token_tile: int, 

208 ) -> MegaMhcOutputs: 

209 """Launch HyperMegaMhc and save its explicit native cache. 

210 

211 Args: 

212 ctx: Autograd context retaining only the state required for backward. 

213 previous_output: Previous block output tensor. 

214 residual: Residual streams supplied to the current block. 

215 previous_pre_mix: Previous block's input mixing coefficients. 

216 previous_post_mix: Previous block's output mixing coefficients. 

217 previous_residual_mix: Previous block's residual mixing matrix. 

218 phi: Projection weight used to generate mixing coefficients. 

219 alpha: Scaling parameters for the projected mixing coefficients. 

220 bias: Bias parameters for the projected mixing coefficients. 

221 norm_weight: RMS normalization weight. 

222 hc_eps: Numerical epsilon used by mixing coefficient normalization. 

223 norm_eps: Numerical epsilon used by RMS normalization. 

224 num_iters: Number of Sinkhorn normalization iterations. 

225 token_tile: Number of token rows assigned to a task tile. 

226 """ 

227 outputs, cache = _hyper_mega_mhc_forward( 

228 previous_output, 

229 residual, 

230 previous_pre_mix, 

231 previous_post_mix, 

232 previous_residual_mix, 

233 phi, 

234 alpha, 

235 bias, 

236 norm_weight, 

237 hc_eps=hc_eps, 

238 norm_eps=norm_eps, 

239 num_iters=num_iters, 

240 need_backward=True, 

241 token_tile=token_tile, 

242 ) 

243 ctx.save_for_backward( 

244 previous_output, 

245 residual, 

246 previous_pre_mix, 

247 previous_post_mix, 

248 previous_residual_mix, 

249 phi, 

250 alpha, 

251 bias, 

252 norm_weight, 

253 cache.new_residual, 

254 cache.hc_before_norm, 

255 cache.inv_rms, 

256 cache.sum_out, 

257 cache.norm_out, 

258 cache.mixed_input, 

259 cache.rms_rstd, 

260 ) 

261 ctx.hc_eps = hc_eps 

262 ctx.token_tile = token_tile 

263 return outputs 

264 

265 @staticmethod 

266 def backward(ctx: Any, *grad_outputs: torch.Tensor) -> tuple[torch.Tensor | None, ...]: 

267 """Differentiate the boundary with HyperMegaMhcGrad. 

268 

269 Args: 

270 ctx: Autograd context retaining only the state required for backward. 

271 grad_outputs: Upstream gradients for the differentiable forward results. 

272 """ 

273 ( 

274 previous_output, 

275 residual, 

276 previous_pre_mix, 

277 previous_post_mix, 

278 previous_residual_mix, 

279 phi, 

280 alpha, 

281 bias, 

282 norm_weight, 

283 new_residual, 

284 hc_before_norm, 

285 inv_rms, 

286 sum_out, 

287 norm_out, 

288 mixed_input, 

289 rms_rstd, 

290 ) = ctx.saved_tensors 

291 cache = MegaMhcGradCache( 

292 new_residual=new_residual, 

293 hc_before_norm=hc_before_norm, 

294 inv_rms=inv_rms, 

295 sum_out=sum_out, 

296 norm_out=norm_out, 

297 mixed_input=mixed_input, 

298 rms_rstd=rms_rstd, 

299 ) 

300 gradients = hyper_mega_mhc_grad( 

301 *grad_outputs, 

302 previous_output, 

303 residual, 

304 previous_pre_mix, 

305 previous_post_mix, 

306 previous_residual_mix, 

307 phi, 

308 alpha, 

309 bias, 

310 norm_weight, 

311 cache, 

312 hc_eps=ctx.hc_eps, 

313 token_tile=ctx.token_tile, 

314 ) 

315 return (*gradients, None, None, None, None) 

316 

317 

318def hyper_mega_mhc( 

319 previous_output: torch.Tensor, 

320 residual: torch.Tensor, 

321 previous_pre_mix: torch.Tensor, 

322 previous_post_mix: torch.Tensor, 

323 previous_residual_mix: torch.Tensor, 

324 phi: torch.Tensor, 

325 alpha: torch.Tensor, 

326 bias: torch.Tensor, 

327 norm_weight: torch.Tensor, 

328 *, 

329 hc_eps: float = 1e-6, 

330 norm_eps: float = 1e-6, 

331 num_iters: int = MHC_SINKHORN_ITERS, 

332 need_backward: bool = True, 

333 token_tile: int = DEFAULT_TOKEN_TILE, 

334) -> MegaMhcOutputs: 

335 """Run the fused shifted boundary with its matching autograd backward.""" 

336 differentiable_inputs = ( 

337 previous_output, 

338 residual, 

339 previous_pre_mix, 

340 previous_post_mix, 

341 previous_residual_mix, 

342 phi, 

343 alpha, 

344 bias, 

345 norm_weight, 

346 ) 

347 if need_backward and torch.is_grad_enabled() and any( 

348 isinstance(value, torch.Tensor) and value.requires_grad for value in differentiable_inputs 

349 ): 

350 return _HyperMegaMhcFunction.apply( 

351 *differentiable_inputs, 

352 hc_eps, 

353 norm_eps, 

354 num_iters, 

355 token_tile, 

356 ) 

357 outputs, _ = _hyper_mega_mhc_forward( 

358 *differentiable_inputs, 

359 hc_eps=hc_eps, 

360 norm_eps=norm_eps, 

361 num_iters=num_iters, 

362 need_backward=False, 

363 token_tile=token_tile, 

364 ) 

365 return outputs