已合并
GroupedDynamicBlockQuant op-plugin #3932
yin-peng创建于 2025年12月29日
GroupedDynamicBlockQuant op-plugin #3932
已合并
共 5 个文件变更+163-1
| @@ -7156,6 +7156,9 @@ custom: | |||
| 7156 | op_api: all_version | 7156 | op_api: all_version |
| 7157 | exposed: all_version | 7157 | exposed: all_version |
| 7158 | 7158 | ||
| 7159 | + - func: npu_grouped_dynamic_block_quant(Tensor x, Tensor group_list, *, float min_scale=0.0, str round_mode="rint", int dst_type=291, int row_block_size=1, int col_block_size=128, int group_list_type=0) -> (Tensor, Tensor) | ||
| 7160 | + op_api: [v2.1, newest] | ||
| 7161 | + | ||
| 7159 | - func: npu_recurrent_gated_delta_rule(Tensor query, Tensor key, Tensor value, Tensor(a!) state, *, Tensor? beta=None, float? scale=None, Tensor? actual_seq_lengths=None, Tensor? ssm_state_indices=None, Tensor? num_accepted_tokens=None, Tensor? g=None, Tensor? gk=None) -> Tensor | 7162 | - func: npu_recurrent_gated_delta_rule(Tensor query, Tensor key, Tensor value, Tensor(a!) state, *, Tensor? beta=None, float? scale=None, Tensor? actual_seq_lengths=None, Tensor? ssm_state_indices=None, Tensor? num_accepted_tokens=None, Tensor? g=None, Tensor? gk=None) -> Tensor |
| 7160 | op_api: all_version | 7163 | op_api: all_version |
| 7161 | exposed: all_version | 7164 | exposed: all_version |
| @@ -4890,4 +4890,25 @@ has_side_effect(torch.ops.npu.save_npugraph_tensor.default) | |||
| 4890 | 4890 | ||
| 4891 | 4891 | ||
| 4892 | def save_npugraph_tensor_meta(self, *, save_path=None): | 4892 | def save_npugraph_tensor_meta(self, *, save_path=None): |
| 4893 | - return | 4893 | + return |
| 4894 | + | ||
| 4895 | + | ||
| 4896 | + | ||
Z meta缺少测试用例,在test_faketensor.py中添加 ![]() ![]() | |||
| 4897 | +def npu_dynamic_block_quant_meta(x, group_list, *, min_scale=0.0, round_mode="rint", dst_type=torch.float8_e5m2, row_block_size=1, col_block_size=128, group_list_type=0): | ||
| 4898 | + dtype = TORCH_DTYPE_ENUM_VALUE_TO_SCALAR_TYPE_MAP.get(dst_type, torch.float8_e5m2) | ||
| 4899 | + y = torch.empty(x.shape, dtype=dtype, device=x.device) | ||
| 4900 | + scale_shape = list(x.shape) | ||
| 4901 | + | ||
| 4902 | + if len(scale_shape) == 2: | ||
| 4903 | + scale_shape[0] = scale_shape[0] / row_block_size + group_list.shape[0] | ||
| 4904 | + scale_shape[1] = math.ceil(scale_shape[1] / col_block_size) | ||
| 4905 | + elif len(scale_shape) == 3: | ||
| 4906 | + scale_shape[1] = scale_shape[1] / row_block_size + group_list.shape[0] | ||
| 4907 | + scale_shape[2] = math.ceil(scale_shape[2] / col_block_size) | ||
| 4908 | + else: | ||
| 4909 | + raise RuntimeError(f"Expected x to have 2 or 3 dimensions, but got {x.dim()}.") | ||
| 4910 | + | ||
| 4911 | + scale_shape = torch.Size(scale_shape) | ||
| 4912 | + | ||
| 4913 | + scale = torch.empty(scale_shape, dtype=torch.float32, device=x.device) | ||
| 4914 | + return y, scale | ||
| @@ -4690,6 +4690,9 @@ | |||
| 4690 | "func: npu_dynamic_block_quant(Tensor x, *, float min_scale=0.0, str round_mode=\"rint\", int dst_type=1, int row_block_size=1, int col_block_size=128) -> (Tensor y, Tensor scale)": { | 4690 | "func: npu_dynamic_block_quant(Tensor x, *, float min_scale=0.0, str round_mode=\"rint\", int dst_type=1, int row_block_size=1, int col_block_size=128) -> (Tensor y, Tensor scale)": { |
| 4691 | "version": ["all_version"] | 4691 | "version": ["all_version"] |
| 4692 | }, | 4692 | }, |
| 4693 | + "func: npu_grouped_dynamic_block_quant(Tensor x, Tensor group_list, *, float min_scale=0.0, str round_mode=\"rint\", int dst_type=291, int row_block_size=1, int col_block_size=128, int group_list_type=0) -> (Tensor, Tensor)": { | ||
| 4694 | + "version": ["all_version"] | ||
| 4695 | + }, | ||
| 4693 | "func: fused_linear_online_max_sum(Tensor input, Tensor weight, Tensor target, int vocab_start_index, int vocab_end_index, bool return_logits=False) -> (Tensor, Tensor, Tensor, Tensor, Tensor, Tensor)": { | 4696 | "func: fused_linear_online_max_sum(Tensor input, Tensor weight, Tensor target, int vocab_start_index, int vocab_end_index, bool return_logits=False) -> (Tensor, Tensor, Tensor, Tensor, Tensor, Tensor)": { |
| 4694 | "version": ["all_version"] | 4697 | "version": ["all_version"] |
| 4695 | }, | 4698 | }, |
| @@ -0,0 +1,56 @@ | |||
| 1 | +import math | ||
| 2 | +import unittest | ||
| 3 | +import copy | ||
| 4 | +import struct | ||
| 5 | +from struct import pack, unpack | ||
| 6 | +import numpy as np | ||
| 7 | +import torch | ||
| 8 | +import torch_npu | ||
| 9 | +from torch_npu.testing.testcase import TestCase, run_tests | ||
| 10 | +from torch_npu.testing.common_utils import SupportedDevices | ||
| 11 | +from torch.testing import assert_close | ||
| 12 | + | ||
| 13 | +class TestGroupedDynamicBlockQuant(TestCase): | ||
| 14 | + def custom_op_exec(self, input_tensor, group_list_tensor, min_scale=0.0, round_mode="rint", dst_type=291, row_block_size=1, col_block_size=128, group_list_type=0): | ||
| 15 | + return torch_npu.npu_grouped_dynamic_block_quant(input_tensor, | ||
| 16 | + group_list_tensor, | ||
| 17 | + min_scale=min_scale, | ||
| 18 | + round_mode=round_mode, | ||
| 19 | + dst_type=dst_type, | ||
| 20 | + row_block_size=row_block_size, | ||
| 21 | + col_block_size=col_block_size, | ||
| 22 | + group_list_type=group_list_type) | ||
| 23 | + | ||
| 24 | + def supported_op_exec(self, input_tensor): | ||
| 25 | + if torch.all(torch.eq(input_tensor, 0.0)) and input_tensor.shape == torch.Size([1, 2]): | ||
| 26 | + device = input_tensor.device | ||
| 27 | + y = torch.tensor([[0, 0]], dtype=torch.float8_e5m2, device=device) | ||
| 28 | + scale = torch.tensor([[0.0], [0.0]], dtype=torch.float, device=device) | ||
| 29 | + | ||
| 30 | + return y, scale | ||
| 31 | + | ||
| 32 | + def generate_input(self, input, group_list, input_dtype="float16"): | ||
| 33 | + input_data_type = torch.float16 if input_dtype == "float16" else torch.bfloat16 | ||
| 34 | + input_value = 0.0 | ||
| 35 | + input_tensor = torch.full(input, input_value, dtype=input_data_type) | ||
| 36 | + group_list_data_type = torch.int32 | ||
| 37 | + group_list_value = 1 | ||
| 38 | + group_list_tensor = torch.full(group_list, group_list_value, dtype=group_list_data_type) | ||
| 39 | + | ||
| 40 | + return input_tensor, group_list_tensor | ||
| 41 | + | ||
| 42 | + | ||
| 43 | + def test_npu_grouped_dynamic_block_quant(self, device="npu"): | ||
| 44 | + input_tensor, group_list_tensor = self.generate_input(input=[1, 2], group_list=[1], input_dtype="float16") | ||
| 45 | + input_tensor = input_tensor.to(device) | ||
| 46 | + group_list_tensor = group_list_tensor.to(device) | ||
| 47 | + supported_output = self.supported_op_exec(input_tensor.clone()) | ||
| 48 | + custom_output = self.custom_op_exec(input_tensor.clone(), group_list_tensor.clone(), 0.0, "rint", 291, 1, 128, 0) | ||
| 49 | + y = custom_output[0].view([1, 2]).view(torch.uint8) | ||
| 50 | + scale = custom_output[1].view([2, 1]) | ||
| 51 | + | ||
| 52 | + assert torch.all(y == supported_output[0].view(torch.uint8)) | ||
| 53 | + assert_close(supported_output[1], scale, atol=0.01, rtol=0.001) | ||
| 54 | + | ||
| 55 | +if __name__ == "__main__": | ||
| 56 | + run_tests() | ||


逻辑运算与副作用: 函数参数 'int64_t group_list_type' 在函数体内未被使用,可能是冗余参数或遗漏了实现。如果 group_list_type 应该用于确定 group_list 的处理方式(例如,是标量还是张量),那么当前代码忽略了它。
问题类型: 逻辑运算与副作用 文件路径:
op_plugin/ops/opapi/GroupedDynamicBlockQuantNpuOpApi.cpp行号: 33 问题代码:int64_t group_list_type)修改建议:
此评论由代码审查工具自动生成