Coverage for  / home / jenkins / .local / lib / python3.10 / site-packages / hyper_parallel / components / quantization / ops / npu_hifloat8.py: 56%

89 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-10-25 05:45 +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"""A5 HiFloat8 current-quantization, MM, and GMM adapters.""" 

16 

17from functools import lru_cache 

18from typing import Any, Optional 

19 

20import torch # pylint: disable=forbidden-backend-import 

21 

22from hyper_parallel.components.quantization.tensor.hifloat8_tensor import ( 

23 HiFloat8Tensor, 

24) 

25 

26_A5_DEVICE_MARKERS = ("Ascend950", "Ascend910_95") 

27_SUPPORTED_LAYOUTS = ("NN", "NT", "TN") 

28 

29 

30class HiFloat8NpuOps: 

31 """Adapt the verified A5 HiFloat8 torch_npu operator contract.""" 

32 

33 def __init__(self, torch_npu_module: Any) -> None: 

34 """Validate logical dtype, required operators, and target device.""" 

35 

36 required_operators = ("npu_dynamic_quant", "npu_quant_matmul") 

37 missing = [ 

38 name 

39 for name in required_operators 

40 if not callable(getattr(torch_npu_module, name, None)) 

41 ] 

42 if getattr(torch_npu_module, "hifloat8", None) is None: 

43 missing.append("hifloat8") 

44 if missing: 

45 version = getattr(torch_npu_module, "__version__", "unknown") 

46 raise RuntimeError( 

47 "The active torch_npu stack does not provide the A5 HiFloat8 " 

48 f"operator contract; missing {missing}, torch_npu={version}." 

49 ) 

50 

51 npu_handle = getattr(torch_npu_module, "npu", None) 

52 device_name = ( 

53 npu_handle.get_device_name() 

54 if npu_handle is not None 

55 and hasattr(npu_handle, "get_device_name") 

56 else "" 

57 ) 

58 if not any(marker in device_name for marker in _A5_DEVICE_MARKERS): 

59 raise RuntimeError( 

60 "HiFloat8 is supported only on Ascend 950PR/950DT (A5), " 

61 f"but the active device is {device_name or 'unknown'}." 

62 ) 

63 self._torch_npu = torch_npu_module 

64 

65 @property 

66 def quant_dtype(self) -> Any: 

67 """Return the runtime's logical HiFloat8 dtype identifier.""" 

68 

69 return self._torch_npu.hifloat8 

70 

71 def dynamic_quant( 

72 self, 

73 tensor: torch.Tensor, 

74 *, 

75 dst_type_max: float, 

76 quant_mode: str = "pertensor", 

77 ) -> tuple[torch.Tensor, torch.Tensor]: 

78 """Quantize one FP16/BF16 Tensor with the selected current scale.""" 

79 

80 return self._torch_npu.npu_dynamic_quant( 

81 tensor, 

82 dst_type=self._torch_npu.hifloat8, 

83 quant_mode=quant_mode, 

84 dst_type_max=float(dst_type_max), 

85 ) 

86 

87 def quant_matmul( 

88 self, 

89 x1: torch.Tensor, 

90 x2: torch.Tensor, 

91 scale: torch.Tensor, 

92 *, 

93 pertoken_scale: torch.Tensor, 

94 output_dtype: torch.dtype, 

95 ) -> torch.Tensor: 

96 """Execute an A5 HiFloat8 MM with explicit logical input dtypes.""" 

97 

98 return self._torch_npu.npu_quant_matmul( 

99 x1, 

100 x2, 

101 scale, 

102 pertoken_scale=pertoken_scale, 

103 output_dtype=output_dtype, 

104 x1_dtype=self._torch_npu.hifloat8, 

105 x2_dtype=self._torch_npu.hifloat8, 

106 ) 

107 

108 def validate_grouped_matmul(self) -> None: 

109 """Fail when the runtime lacks the HiFloat8 GMM operator.""" 

110 

111 if not callable(getattr(self._torch_npu, "npu_grouped_matmul", None)): 

112 version = getattr(self._torch_npu, "__version__", "unknown") 

113 raise RuntimeError( 

114 "The active torch_npu stack does not provide " 

115 f"npu_grouped_matmul; torch_npu={version}." 

116 ) 

117 

118 def quant_grouped_matmul( 

119 self, 

120 x1: torch.Tensor, 

121 x2: torch.Tensor, 

122 x2_scale: torch.Tensor, 

123 *, 

124 x1_scale: torch.Tensor, 

125 group_list: torch.Tensor, 

126 group_type: int, 

127 group_list_type: int, 

128 output_dtype: torch.dtype, 

129 bias: Optional[list[torch.Tensor]] = None, 

130 ) -> torch.Tensor: 

131 """Execute the verified A5 HiFloat8 grouped matmul contract.""" 

132 

133 self.validate_grouped_matmul() 

134 return self._torch_npu.npu_grouped_matmul( 

135 [x1], 

136 [x2], 

137 bias=[] if bias is None else bias, 

138 scale=[x2_scale], 

139 per_token_scale=[x1_scale], 

140 group_list=group_list, 

141 group_type=group_type, 

142 output_dtype=output_dtype, 

143 group_list_type=group_list_type, 

144 x_dtype=self._torch_npu.hifloat8, 

145 weight_dtype=self._torch_npu.hifloat8, 

146 split_item=3, 

147 )[0] 

148 

149 

150@lru_cache(maxsize=1) 

151def _get_hifloat8_npu_ops() -> HiFloat8NpuOps: 

152 """Return the process-local A5 HiFloat8 operator adapter.""" 

153 

154 try: 

155 import torch_npu # pylint: disable=C0415 

156 except ImportError as exc: 

157 raise RuntimeError( 

158 "A5 HiFloat8 requires torch_npu, but it is not importable." 

159 ) from exc 

160 return HiFloat8NpuOps(torch_npu) 

161 

162 

163def validate_hifloat8_runtime() -> None: 

164 """Fail during model setup when the HiFloat8 runtime is unavailable.""" 

165 

166 _get_hifloat8_npu_ops() 

167 

168 

169def validate_hifloat8_gmm_runtime() -> None: 

170 """Fail during expert setup when the HiFloat8 GMM runtime is unavailable.""" 

171 

172 _get_hifloat8_npu_ops().validate_grouped_matmul() 

173 

174 

175def _left_operand( 

176 tensor: HiFloat8Tensor, 

177 *, 

178 transpose: bool, 

179) -> tuple[torch.Tensor, torch.Tensor]: 

180 """Select the Pangu-compatible left operand direction.""" 

181 

182 if transpose: 

183 if not tensor.is_colwise(): 

184 raise ValueError( 

185 "Transposed HiFloat8 left operand requires column-wise data." 

186 ) 

187 return tensor.col_data.transpose(-1, -2), tensor.col_scale 

188 if not tensor.is_rowwise(): 

189 raise ValueError( 

190 "Non-transposed HiFloat8 left operand requires row-wise data." 

191 ) 

192 return tensor.row_data, tensor.row_scale 

193 

194 

195def _right_operand( 

196 tensor: HiFloat8Tensor, 

197 *, 

198 transpose: bool, 

199) -> tuple[torch.Tensor, torch.Tensor]: 

200 """Select the Pangu-compatible right operand direction.""" 

201 

202 if transpose: 

203 if not tensor.is_rowwise(): 

204 raise ValueError( 

205 "Transposed HiFloat8 right operand requires row-wise data." 

206 ) 

207 return tensor.row_data.transpose(-1, -2), tensor.row_scale 

208 if not tensor.is_colwise(): 

209 raise ValueError( 

210 "Non-transposed HiFloat8 right operand requires column-wise data." 

211 ) 

212 return tensor.col_data, tensor.col_scale 

213 

214 

215def hifloat8_matmul( 

216 left: HiFloat8Tensor, 

217 right: HiFloat8Tensor, 

218 *, 

219 layout: str, 

220 output_dtype: Optional[torch.dtype] = None, 

221) -> torch.Tensor: 

222 """Multiply typed HiFloat8 operands and return a high-precision Tensor.""" 

223 

224 if not isinstance(left, HiFloat8Tensor) or not isinstance( 

225 right, 

226 HiFloat8Tensor, 

227 ): 

228 raise TypeError("hifloat8_matmul requires two HiFloat8Tensor operands.") 

229 if layout not in _SUPPORTED_LAYOUTS: 

230 raise ValueError( 

231 f"Unsupported HiFloat8 layout {layout!r}; " 

232 f"expected one of {_SUPPORTED_LAYOUTS}." 

233 ) 

234 

235 result_dtype = output_dtype or left.dtype 

236 left_data, left_scale = _left_operand( 

237 left, 

238 transpose=layout[0] == "T", 

239 ) 

240 right_data, right_scale = _right_operand( 

241 right, 

242 transpose=layout[1] == "T", 

243 ) 

244 return left.quantizer.npu_ops.quant_matmul( 

245 left_data, 

246 right_data, 

247 right_scale, 

248 pertoken_scale=left_scale, 

249 output_dtype=result_dtype, 

250 ) 

251 

252 

253def hifloat8_grouped_matmul( 

254 left: HiFloat8Tensor, 

255 right: HiFloat8Tensor, 

256 *, 

257 layout: str, 

258 group_list: torch.Tensor, 

259 group_type: int = 0, 

260 group_list_type: int = 0, 

261 output_dtype: Optional[torch.dtype] = None, 

262 bias: Optional[torch.Tensor] = None, 

263) -> torch.Tensor: 

264 """Multiply expert-grouped HiFloat8 operands on A5. 

265 

266 ``group_type=0`` splits the token/M axis for forward and dgrad, while 

267 ``group_type=2`` splits the contracting axis for wgrad. 

268 """ 

269 

270 if not isinstance(left, HiFloat8Tensor) or not isinstance( 

271 right, 

272 HiFloat8Tensor, 

273 ): 

274 raise TypeError( 

275 "hifloat8_grouped_matmul requires two HiFloat8Tensor operands." 

276 ) 

277 if layout not in _SUPPORTED_LAYOUTS: 

278 raise ValueError( 

279 f"Unsupported HiFloat8 GMM layout {layout!r}; " 

280 f"expected one of {_SUPPORTED_LAYOUTS}." 

281 ) 

282 if not isinstance(group_list, torch.Tensor) or group_list.ndim != 1: 

283 raise ValueError("HiFloat8 GMM group_list must be one-dimensional.") 

284 if group_list.dtype != torch.int64: 

285 raise TypeError("HiFloat8 GMM group_list must use torch.int64.") 

286 if group_type not in (0, 2): 

287 raise ValueError( 

288 f"HiFloat8 GMM group_type must be 0 or 2, got {group_type}." 

289 ) 

290 if group_list_type not in (0, 1): 

291 raise ValueError( 

292 "HiFloat8 GMM group_list_type must be 0 or 1, " 

293 f"got {group_list_type}." 

294 ) 

295 

296 left_data, left_scale = _left_operand( 

297 left, 

298 transpose=layout[0] == "T", 

299 ) 

300 right_data, right_scale = _right_operand( 

301 right, 

302 transpose=layout[1] == "T", 

303 ) 

304 if left_scale.dtype != torch.float32 or right_scale.dtype != torch.float32: 

305 raise TypeError("HiFloat8 GMM scales must use torch.float32.") 

306 return left.quantizer.npu_ops.quant_grouped_matmul( 

307 left_data, 

308 right_data, 

309 right_scale, 

310 x1_scale=left_scale, 

311 group_list=group_list, 

312 group_type=group_type, 

313 group_list_type=group_list_type, 

314 output_dtype=output_dtype or left.dtype, 

315 bias=None if bias is None else [bias], 

316 ) 

317 

318 

319__all__ = [ 

320 "HiFloat8NpuOps", 

321 "hifloat8_grouped_matmul", 

322 "hifloat8_matmul", 

323 "validate_hifloat8_gmm_runtime", 

324 "validate_hifloat8_runtime", 

325]