Coverage for / home / jenkins / .local / lib / python3.10 / site-packages / hyper_parallel / components / quantization / quantizers / mxfp8.py: 84%
43 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-10-25 05:45 +0800
« 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"""MXFP8 quantizer for NPU dynamic block quantization."""
17from typing import Optional
19import torch # pylint: disable=forbidden-backend-import
21from hyper_parallel.components.quantization.ops.npu_mxfp8 import (
22 MXFP8NpuOps,
23 _get_npu_ops,
24)
25from hyper_parallel.components.quantization.quantizers.base import Quantizer
26from hyper_parallel.components.quantization.tensor import (
27 MXFP8Tensor,
28 QuantizedTensor,
29)
32class MXFP8Quantizer(Quantizer):
33 """Build E4M3 data and E8M0 scales for MX block computation."""
35 def __init__(
36 self,
37 quant_dtype: Optional[torch.dtype] = None,
38 *,
39 npu_ops: Optional[MXFP8NpuOps] = None,
40 ) -> None:
41 """Create a quantizer with lazy NPU operator resolution."""
43 self.quant_dtype = quant_dtype or torch.float8_e4m3fn
44 self._npu_ops = npu_ops
46 @property
47 def npu_ops(self) -> MXFP8NpuOps:
48 """Return the injected or lazily resolved NPU operator adapter."""
50 if self._npu_ops is None:
51 self._npu_ops = _get_npu_ops()
52 return self._npu_ops
54 def quantize(
55 self,
56 tensor: torch.Tensor,
57 *,
58 group_list: Optional[torch.Tensor] = None,
59 group_list_type: int = 0,
60 rowwise: bool = False,
61 colwise: bool = False,
62 ) -> MXFP8Tensor:
63 """Quantize a tensor into the requested MXFP8 directions."""
65 if not isinstance(tensor, torch.Tensor) or isinstance(
66 tensor,
67 QuantizedTensor,
68 ):
69 raise TypeError(
70 "MXFP8Quantizer expects a high-precision torch.Tensor."
71 )
72 if tensor.ndim < 2:
73 raise ValueError(
74 "MXFP8Quantizer expects at least two dimensions, but got "
75 f"shape {tuple(tensor.shape)}."
76 )
77 if not rowwise and not colwise:
78 raise ValueError(
79 "MXFP8Quantizer requires rowwise=True or colwise=True."
80 )
81 if group_list_type not in (0, 1):
82 raise ValueError(
83 "MXFP8Quantizer group_list_type must be 0 or 1, "
84 f"but got {group_list_type}."
85 )
86 if group_list is not None and (
87 not isinstance(group_list, torch.Tensor) or group_list.ndim != 1
88 ):
89 raise ValueError(
90 "MXFP8Quantizer group_list must be a one-dimensional Tensor."
91 )
93 row_data = None
94 row_scale = None
95 col_data = None
96 col_scale = None
97 if group_list is not None:
98 if not colwise:
99 raise ValueError(
100 "Grouped MXFP8 quantization requires colwise=True."
101 )
102 quant_group_list = (
103 group_list
104 if group_list_type == 0
105 else torch.cumsum(group_list, dim=0)
106 )
107 if rowwise:
108 row_data, row_scale = self.npu_ops.dynamic_mx_quant(
109 tensor,
110 axis=-1,
111 quant_dtype=self.quant_dtype,
112 )
113 col_data, col_scale = self.npu_ops.grouped_dynamic_mx_quant(
114 tensor,
115 quant_group_list,
116 quant_dtype=self.quant_dtype,
117 )
118 elif rowwise and colwise:
119 (
120 row_data,
121 row_scale,
122 col_data,
123 col_scale,
124 ) = self.npu_ops.dynamic_mx_quant_dual_axis(
125 tensor,
126 quant_dtype=self.quant_dtype,
127 )
128 elif rowwise:
129 row_data, row_scale = self.npu_ops.dynamic_mx_quant(
130 tensor,
131 axis=-1,
132 quant_dtype=self.quant_dtype,
133 )
134 elif colwise:
135 col_data, col_scale = self.npu_ops.dynamic_mx_quant(
136 tensor,
137 axis=-2,
138 quant_dtype=self.quant_dtype,
139 )
140 return MXFP8Tensor(
141 shape=tensor.shape,
142 dtype=tensor.dtype,
143 quantizer=self,
144 row_data=row_data,
145 row_scale=row_scale,
146 col_data=col_data,
147 col_scale=col_scale,
148 device=tensor.device,
149 )