已合并
deprecate LinearA8W8quant #17110
lifei265创建于 2024年12月28日
deprecate LinearA8W8quant #17110
已合并
lifei265创建于 2024年12月28日
refs/pull/17110/head合入到master
2 个文件变更+42-1
@@ -47,7 +47,8 @@ class TestLinearA8W8Quant(TestCase):
47 47 
48 @unittest.skipIf(DEVICE_NAME == 'Ascend910A' or DEVICE_NAME == 'Ascend310P',48 @unittest.skipIf(DEVICE_NAME == 'Ascend910A' or DEVICE_NAME == 'Ascend310P',
49 "OP `QuantBatchMatmulV3` is not supported on 910A or 310P, skip this ut for this device type!")49 "OP `QuantBatchMatmulV3` is not supported on 910A or 310P, skip this ut for this device type!")
50- def test_npu_linear_quant_out_int32(self):50+ @unittest.expectedFailure
51+ def test_npu_linear_quant_out_int32_error(self):
51 x1 = torch.randint(-1, 1, (1, 5), dtype=torch.int8).npu()52 x1 = torch.randint(-1, 1, (1, 5), dtype=torch.int8).npu()
52 x2 = torch.randint(-1, 1, (127, 5), dtype=torch.int8).npu()53 x2 = torch.randint(-1, 1, (127, 5), dtype=torch.int8).npu()
53 scale = torch.randn(1, dtype=torch.float32).npu()54 scale = torch.randn(1, dtype=torch.float32).npu()
@@ -61,5 +62,22 @@ class TestLinearA8W8Quant(TestCase):
61 npu_out = model(x1)62 npu_out = model(x1)
62 self.assertRtolEqual(supported_output, npu_out, 0.001)63 self.assertRtolEqual(supported_output, npu_out, 0.001)
63 64 
65+ @unittest.skipIf(DEVICE_NAME == 'Ascend910A' or DEVICE_NAME == 'Ascend310P',
66+ "OP `QuantBatchMatmulV3` is not supported on 910A or 310P, skip this ut for this device type!")
67+ @unittest.expectedFailure
68+ def test_npu_linear_quant_scale_fp16_error(self):
69+ x1 = torch.randint(-1, 1, (1, 5), dtype=torch.int8).npu()
70+ x2 = torch.randint(-1, 1, (127, 5), dtype=torch.int8).npu()
71+ scale = torch.randn(1, dtype=torch.float16).npu()
72+ out_dtype = torch.int8
73+ supported_output = torch_npu.npu_quant_matmul(x1, x2.t(), scale, output_dtype=out_dtype)
74+ in_features = 5
75+ out_features = 127
76+ model = LinearA8W8Quant(in_features, out_features, bias=False, offset=False, pertoken_scale=False, output_dtype=out_dtype)
77+ model.weight.data = x2
78+ model.scale.data = scale
79+ npu_out = model(x1)
80+ self.assertRtolEqual(supported_output, npu_out, 0.001)
81+ 
64if __name__ == "__main__":82if __name__ == "__main__":
65 run_tests()83 run_tests()
@@ -1,8 +1,10 @@
1+import warnings
1import torch2import torch
2import torch.nn as nn3import torch.nn as nn
3from torch import Tensor4from torch import Tensor
4from torch.nn.parameter import Parameter5from torch.nn.parameter import Parameter
5import torch_npu6import torch_npu
7+from torch_npu.utils._error_code import ErrCode, ops_error
6 8 
7__all__ = ["LinearA8W8Quant"]9__all__ = ["LinearA8W8Quant"]
8 10 
@@ -60,6 +62,8 @@ class LinearA8W8Quant(nn.Module):
60 pertoken_scale: bool = False, device=None, dtype=None, output_dtype=None) -> None:62 pertoken_scale: bool = False, device=None, dtype=None, output_dtype=None) -> None:
61 63 
62 super(LinearA8W8Quant, self).__init__()64 super(LinearA8W8Quant, self).__init__()
65+ warnings.warn("torch_npu.contrib.module.LinearA8W8Quant is deprecated and will be removed in future version. "
66+ "Use torch_npu.contrib.module.LinearQuant instead.", FutureWarning)
63 self.in_features = in_features67 self.in_features = in_features
64 self.out_features = out_features68 self.out_features = out_features
65 self.weight = Parameter(torch.empty((out_features, in_features)), False)69 self.weight = Parameter(torch.empty((out_features, in_features)), False)
@@ -84,6 +88,25 @@ class LinearA8W8Quant(nn.Module):
84 scale_quant = self.scale88 scale_quant = self.scale
85 first_last_dim = self.weight.dim() - 189 first_last_dim = self.weight.dim() - 1
86 second_last_dim = self.weight.dim() - 290 second_last_dim = self.weight.dim() - 2
91+ if not ((linear_quant_input.dtype == torch.int32 and self.weight.dtype == torch.int32) or
92+ (linear_quant_input.dtype == torch.int8 and self.weight.dtype == torch.int8)):
93+ raise ValueError("input and weight should be both torch.int32 or both torch.int8 datatype, "
94+ f"but now input is {linear_quant_input.dtype}, weight is {self.weight.dtype}." + ops_error(ErrCode.TYPE))
95+ if self.scale.dtype not in [torch.int64, torch.float32, torch.bfloat16]:
96+ raise ValueError("scale should be torch.int64, torch.float32 or torch.bfloat16 datatype, "
97+ f"but now it is {self.scale.dtype}." + ops_error(ErrCode.TYPE))
98+ if self.offset is not None and self.offset.dtype is not torch.float32:
99+ raise ValueError("offset should be torch.float32 datatype, "
100+ f"but now it is {self.offset.dtype}." + ops_error(ErrCode.TYPE))
101+ if self.bias is not None and self.bias.dtype not in [torch.int32, torch.bfloat16, torch.float16, torch.float32]:
102+ raise ValueError("bias should be torch.int32, torch.bfloat16, torch.float16 or torch.float32 datatype, "
103+ f"but now it is {self.bias.dtype}." + ops_error(ErrCode.TYPE))
104+ if self.pertoken_scale is not None and self.pertoken_scale.dtype is not torch.float32:
105+ raise ValueError("pertoken_scale should be torch.float32 datatype, "
106+ f"but now it is {self.pertoken_scale.dtype}." + ops_error(ErrCode.TYPE))
107+ if self.output_dtype is not None and self.output_dtype not in [torch.int8, torch.float16, torch.bfloat16]:
108+ raise ValueError("output_dtype should be torch.int8, torch.float16 or torch.bfloat16, "
109+ f"but now it is {self.output_dtype}." + ops_error(ErrCode.TYPE))
87 is_check_dtype_ok = (self.scale.dtype == torch.float32 and 110 is_check_dtype_ok = (self.scale.dtype == torch.float32 and
88 self.output_dtype not in [torch.bfloat16, torch.int32])111 self.output_dtype not in [torch.bfloat16, torch.int32])
89 if self.pertoken_scale is None and is_check_dtype_ok:112 if self.pertoken_scale is None and is_check_dtype_ok: