已合并
【9.2.0beta2】【cherry-pick】DequantSituQuant和SituMxQuant算子 #8958
east_yang创建于 8月20日
【9.2.0beta2】【cherry-pick】DequantSituQuant和SituMxQuant算子 #8958
已合并
共 63 个文件变更+9752-0
| @@ -113,10 +113,12 @@ | |||
| 113 | | [aclnnDeformableConv2d](../../conv/deformable_conv2d/docs/aclnnDeformableConv2d.md) | 实现卷积功能,支持2D卷积,同时支持可变形卷积、分组卷积。 | 默认确定性实现 | 默认确定性实现 | | 113 | | [aclnnDeformableConv2d](../../conv/deformable_conv2d/docs/aclnnDeformableConv2d.md) | 实现卷积功能,支持2D卷积,同时支持可变形卷积、分组卷积。 | 默认确定性实现 | 默认确定性实现 | |
| 114 | | [aclnnDeformableConv2dBackward](../../conv/convolution_backward/docs/aclnnDeformableConv2dBackward.md) | 实现卷积反向功能,支持2D卷积反向,同时支持可变形卷积、分组卷积反向。 | - | 默认确定性实现 | | 114 | | [aclnnDeformableConv2dBackward](../../conv/convolution_backward/docs/aclnnDeformableConv2dBackward.md) | 实现卷积反向功能,支持2D卷积反向,同时支持可变形卷积、分组卷积反向。 | - | 默认确定性实现 | |
| 115 | | [aclnnDequantBias](../../quant/dequant_bias/docs/aclnnDequantBias.md) | 对输入x反量化操作,将输入的int32的数据转化为FLOAT16/BFLOAT16输出。 | 默认确定性实现 | - | | 115 | | [aclnnDequantBias](../../quant/dequant_bias/docs/aclnnDequantBias.md) | 对输入x反量化操作,将输入的int32的数据转化为FLOAT16/BFLOAT16输出。 | 默认确定性实现 | - | |
| 116 | +| [aclnnDequantSituQuant](../../quant/dequant_situ_quant/docs/aclnnDequantSituQuant.md) | 在Situ激活函数前后添加dequant和quant操作,实现x的DequantSituQuant计算。 | 默认确定性实现 | - | | ||
| 116 | | [aclnnDequantSwigluQuant](../../quant/dequant_swiglu_quant/docs/aclnnDequantSwigluQuant.md) | 在Swish门控线性单元激活函数前后添加dequant和quant操作,实现x的DequantSwigluQuant计算。 | 默认确定性实现 | 默认确定性实现 | | 117 | | [aclnnDequantSwigluQuant](../../quant/dequant_swiglu_quant/docs/aclnnDequantSwigluQuant.md) | 在Swish门控线性单元激活函数前后添加dequant和quant操作,实现x的DequantSwigluQuant计算。 | 默认确定性实现 | 默认确定性实现 | |
| 117 | | [aclnnDequantSwigluQuantV2](../../quant/dequant_swiglu_quant/docs/aclnnDequantSwigluQuantV2.md) | 在Swish门控线性单元激活函数前后添加dequant和quant操作,实现x的DequantSwigluQuant计算。 | 默认确定性实现 | 默认确定性实现 | | 118 | | [aclnnDequantSwigluQuantV2](../../quant/dequant_swiglu_quant/docs/aclnnDequantSwigluQuantV2.md) | 在Swish门控线性单元激活函数前后添加dequant和quant操作,实现x的DequantSwigluQuant计算。 | 默认确定性实现 | 默认确定性实现 | |
| 118 | | [aclnnSwigluGroup](../../activation/swiglu_group/docs/aclnnSwigluGroup.md) | 执行SwiGLU激活,实现x的SwiGlu计算,输出与x相同数据类型的激活结果。 | - | 默认确定性实现 | | 119 | | [aclnnSwigluGroup](../../activation/swiglu_group/docs/aclnnSwigluGroup.md) | 执行SwiGLU激活,实现x的SwiGlu计算,输出与x相同数据类型的激活结果。 | - | 默认确定性实现 | |
| 119 | | [aclnnSwigluMxQuant](../../quant/swiglu_mx_quant/docs/aclnnSwigluMxQuant.md) | 在Swish门控线性单元激活函数后添加DynamicMxQuant操作,实现x的SwigluMxQuant计算。 | - | 默认确定性实现 | | 120 | | [aclnnSwigluMxQuant](../../quant/swiglu_mx_quant/docs/aclnnSwigluMxQuant.md) | 在Swish门控线性单元激活函数后添加DynamicMxQuant操作,实现x的SwigluMxQuant计算。 | - | 默认确定性实现 | |
| 121 | +| [aclnnSituMxQuant](../../quant/situ_mx_quant/docs/aclnnSituMxQuant.md) | 将Situ激活函数与动态MX量化融合,实现x的SituMxQuant计算。 | - | 默认确定性实现 | | ||
| 120 | | [aclnnSwigluMxQuantWithDualAxis](../../quant/swiglu_mx_quant_with_dual_axis/docs/aclnnSwigluMxQuantWithDualAxis.md) | 在Swish门控线性单元激活函数后添加GroupDynamicMxQuant操作,根据传入的分组索引的起始值,对swiglu后的数据进行分组的-1轴和-2轴同时动态量化。 | - | 默认确定性实现 | | 122 | | [aclnnSwigluMxQuantWithDualAxis](../../quant/swiglu_mx_quant_with_dual_axis/docs/aclnnSwigluMxQuantWithDualAxis.md) | 在Swish门控线性单元激活函数后添加GroupDynamicMxQuant操作,根据传入的分组索引的起始值,对swiglu后的数据进行分组的-1轴和-2轴同时动态量化。 | - | 默认确定性实现 | |
| 121 | | [aclnnSwigluBackwardMxQuantWithDualAxis](../../quant/swiglu_backward_mx_quant_with_dual_axis/docs/aclnnSwigluBackwardMxQuantWithDualAxis.md) | 在Swish门控线性单元激活的反向计算函数后添加GroupDynamicMxQuant操作,根据传入的分组索引的起始值,对swiglu后的数据进行分组的-1轴和-2轴同时动态量化。 | - | 默认确定性实现 | | 123 | | [aclnnSwigluBackwardMxQuantWithDualAxis](../../quant/swiglu_backward_mx_quant_with_dual_axis/docs/aclnnSwigluBackwardMxQuantWithDualAxis.md) | 在Swish门控线性单元激活的反向计算函数后添加GroupDynamicMxQuant操作,根据传入的分组索引的起始值,对swiglu后的数据进行分组的-1轴和-2轴同时动态量化。 | - | 默认确定性实现 | |
| 122 | | [aclnnGroupedDynamicMxQuant](../../quant/grouped_dynamic_mx_quant/docs/aclnnGroupedDynamicMxQuant.md) | 根据传入的分组索引的起始值,对传入的数据进行分组的float8的动态量化。 | - | 默认确定性实现 | | 124 | | [aclnnGroupedDynamicMxQuant](../../quant/grouped_dynamic_mx_quant/docs/aclnnGroupedDynamicMxQuant.md) | 根据传入的分组索引的起始值,对传入的数据进行分组的float8的动态量化。 | - | 默认确定性实现 | |
| @@ -4448,6 +4448,16 @@ | |||
| 4448 | <td>AI Core</td> | 4448 | <td>AI Core</td> |
| 4449 | <td>对输入x反量化操作,将输入的int32的数据转化为FLOAT16/BFLOAT16输出。</td> | 4449 | <td>对输入x反量化操作,将输入的int32的数据转化为FLOAT16/BFLOAT16输出。</td> |
| 4450 | </tr> | 4450 | </tr> |
| 4451 | + <tr> | ||
| 4452 | + <td>quant</td> | ||
| 4453 | + <td><a href="../../quant/dequant_situ_quant/README.md">dequant_situ_quant</a></td> | ||
| 4454 | + <td>✓</td> | ||
| 4455 | + <td>✓</td> | ||
| 4456 | + <td>✓</td> | ||
| 4457 | + <td>✓</td> | ||
| 4458 | + <td>AI Core</td> | ||
| 4459 | + <td>在Situ激活函数前后添加dequant和quant操作,实现x的DequantSituQuant计算。</td> | ||
| 4460 | + </tr> | ||
| 4451 | <tr> | 4461 | <tr> |
| 4452 | <td>quant</td> | 4462 | <td>quant</td> |
| 4453 | <td><a href="../../quant/dequant_swiglu_quant/README.md">dequant_swiglu_quant</a></td> | 4463 | <td><a href="../../quant/dequant_swiglu_quant/README.md">dequant_swiglu_quant</a></td> |
| @@ -4728,6 +4738,16 @@ | |||
| 4728 | <td>AI Core</td> | 4738 | <td>AI Core</td> |
| 4729 | <td>在SwiGlu激活函数后添加mx_quant操作,实现输入x的SwigluMxQuant计算,支持FP8或FP4量化输出。</td> | 4739 | <td>在SwiGlu激活函数后添加mx_quant操作,实现输入x的SwigluMxQuant计算,支持FP8或FP4量化输出。</td> |
| 4730 | </tr> | 4740 | </tr> |
| 4741 | + <tr> | ||
| 4742 | + <td>quant</td> | ||
| 4743 | + <td><a href="../../quant/situ_mx_quant/README.md">situ_mx_quant</a></td> | ||
| 4744 | + <td>✓</td> | ||
| 4745 | + <td>✓</td> | ||
| 4746 | + <td>✓</td> | ||
| 4747 | + <td>✓</td> | ||
| 4748 | + <td>AI Core</td> | ||
| 4749 | + <td>将Situ激活函数与动态MX量化融合,实现输入x的SituMxQuant计算,支持FP8量化输出。</td> | ||
| 4750 | + </tr> | ||
| 4731 | <tr> | 4751 | <tr> |
| 4732 | <td>quant</td> | 4752 | <td>quant</td> |
| 4733 | <td><a href="../../quant/swiglu_mx_quant_with_dual_axis/README.md">swiglu_mx_quant_with_dual_axis</a></td> | 4753 | <td><a href="../../quant/swiglu_mx_quant_with_dual_axis/README.md">swiglu_mx_quant_with_dual_axis</a></td> |
| @@ -36,3 +36,5 @@ | |||
| 36 | |[flat_quant](../../quant/flat_quant/docs/torchapi_flat_quant.md)| 为矩阵x依次进行两次克罗内克积小矩阵乘法,然后针对矩阵乘的结果进行量化处理。 |默认支持确定性计算|默认支持确定性计算| | 36 | |[flat_quant](../../quant/flat_quant/docs/torchapi_flat_quant.md)| 为矩阵x依次进行两次克罗内克积小矩阵乘法,然后针对矩阵乘的结果进行量化处理。 |默认支持确定性计算|默认支持确定性计算| |
| 37 | |[matmul_emu_split_weight](../../matmul/matmul_emu_split_weight/docs/torchapi_matmul_emu_split_weight.md)| 使用双路BF16 GEMM融合模拟FP32精度矩阵乘法。离线将FP32权重拆分为高位BF16与低位残差BF16,推理阶段执行两次BF16 GEMM并做线性组合,激活值全程保持BF16,两路矩阵乘均运行在Cube上。 |-|默认支持确定性计算| | 37 | |[matmul_emu_split_weight](../../matmul/matmul_emu_split_weight/docs/torchapi_matmul_emu_split_weight.md)| 使用双路BF16 GEMM融合模拟FP32精度矩阵乘法。离线将FP32权重拆分为高位BF16与低位残差BF16,推理阶段执行两次BF16 GEMM并做线性组合,激活值全程保持BF16,两路矩阵乘均运行在Cube上。 |-|默认支持确定性计算| |
| 38 | |[mx_to_block_mx_quant](../../quant/mx_to_block_mx_quant/docs/torchapi_mx_to_block_mx_quant.md)| 将调用 npu_dynamic_mx_quant 量化得到的 FLOAT4 的 Tensor 结合 FLOAT8_E8M0 缩放系数,转换为 FLOAT8 分块量化格式,同时输出 -1 轴和 -2 轴方向的量化尺度。|-| 默认确定性实现 | | 38 | |[mx_to_block_mx_quant](../../quant/mx_to_block_mx_quant/docs/torchapi_mx_to_block_mx_quant.md)| 将调用 npu_dynamic_mx_quant 量化得到的 FLOAT4 的 Tensor 结合 FLOAT8_E8M0 缩放系数,转换为 FLOAT8 分块量化格式,同时输出 -1 轴和 -2 轴方向的量化尺度。|-| 默认确定性实现 | |
| 39 | +|[dequant_situ_quant](../../quant/dequant_situ_quant/docs/torchapi_dequant_situ_quant.md)|在Situ激活函数前后添加dequant和quant操作,实现x的DequantSituQuant计算。|默认支持确定性计算|-| | ||
| 40 | +|[situ_mx_quant](../../quant/situ_mx_quant/docs/torchapi_situ_mx_quant.md)|将Situ激活函数与动态MX量化融合,实现x的SituMxQuant计算,支持FP8量化输出。|-|默认支持确定性计算| | ||
| @@ -0,0 +1,20 @@ | |||
| 1 | +# ---------------------------------------------------------------------------- | ||
| 2 | +# Copyright (c) 2025 Huawei Technologies Co., Ltd. | ||
| 3 | +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | +# CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | +# Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | +# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | +# See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | +# ---------------------------------------------------------------------------- | ||
| 10 | + | ||
| 11 | +file(GLOB CURRENT_DIRS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*) | ||
| 12 | +if(NOT ENABLE_TEST AND NOT BENCHMARK) | ||
| 13 | + list(REMOVE_ITEM CURRENT_DIRS tests) | ||
| 14 | +endif() | ||
| 15 | +list(REMOVE_ITEM CURRENT_DIRS examples) | ||
| 16 | +foreach(SUB_DIR ${CURRENT_DIRS}) | ||
| 17 | + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SUB_DIR}/CMakeLists.txt") | ||
| 18 | + add_subdirectory(${SUB_DIR}) | ||
| 19 | + endif() | ||
| 20 | +endforeach() | ||
| @@ -0,0 +1,204 @@ | |||
| 1 | +# DequantSituQuant | ||
| 2 | + | ||
| 3 | +## 产品支持情况 | ||
| 4 | + | ||
| 5 | +| 产品 | 是否支持 | | ||
| 6 | +| :----------------------------------------------------------- | :------: | | ||
| 7 | +| <term>Ascend 950PR/Ascend 950DT</term> | × | | ||
| 8 | +| <term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term> | √ | | ||
| 9 | +| <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term> | √ | | ||
| 10 | +| <term>Atlas 200I/500 A2 推理产品</term> | × | | ||
| 11 | +| <term>Atlas 推理系列产品</term> | × | | ||
| 12 | +| <term>Atlas 训练系列产品</term> | × | | ||
| 13 | + | ||
| 14 | +## 功能说明 | ||
| 15 | + | ||
| 16 | +- 算子功能:在Situ激活函数前后添加dequant和quant操作,实现x的DequantSituQuant计算。 | ||
| 17 | + | ||
| 18 | +- 计算公式: | ||
| 19 | + | ||
| 20 | + 1. 根据输入数据类型x的不同,反量化路径不同: | ||
| 21 | + | ||
| 22 | + - INT8路径: | ||
| 23 | + | ||
| 24 | + $$ | ||
| 25 | + dequantOut_i = cast\_to\_float(x_i) \times weight\_scale_i + bias_i | ||
| 26 | + $$ | ||
| 27 | + | ||
| 28 | + - INT32路径: | ||
| 29 | + | ||
| 30 | + $$ | ||
| 31 | + dequantOut_i = cast\_to\_float(x_i) \times weight\_scale_i \times activation\_scale_i + bias_i | ||
| 32 | + $$ | ||
| 33 | + | ||
| 34 | + - BF16/FLOAT16路径(预反量化): | ||
| 35 | + | ||
| 36 | + $$ | ||
| 37 | + dequantOut_i = cast\_to\_float(x_i) | ||
| 38 | + $$ | ||
| 39 | + | ||
| 40 | + 2. Situ激活: | ||
| 41 | + | ||
| 42 | + $$ | ||
| 43 | + situ_a = \beta \times \tanh(gate / \beta) \times sigmoid(gate) | ||
| 44 | + $$ | ||
| 45 | + | ||
| 46 | + 当linear_beta > 0时: | ||
| 47 | + | ||
| 48 | + $$ | ||
| 49 | + up = linear\_beta \times \tanh(up / linear\_beta) | ||
| 50 | + $$ | ||
| 51 | + | ||
| 52 | + $$ | ||
| 53 | + situOut = situ_a \times up | ||
| 54 | + $$ | ||
| 55 | + | ||
| 56 | + 其中,当activate_left为true时,gate取dequantOut的前半部分,up取后半部分;当activate_left为false时,gate取dequantOut的后半部分,up取前半部分。 | ||
| 57 | + | ||
| 58 | + 3. 量化: | ||
| 59 | + | ||
| 60 | + - static模式: | ||
| 61 | + | ||
| 62 | + $$ | ||
| 63 | + out_i = trunc(situOut_i / quant\_scale_i + quant\_offset_i) | ||
| 64 | + $$ | ||
| 65 | + | ||
| 66 | + - dynamic模式: | ||
| 67 | + | ||
| 68 | + $$ | ||
| 69 | + scale_i = absmax(situOut_i) / 127 | ||
| 70 | + $$ | ||
| 71 | + | ||
| 72 | + $$ | ||
| 73 | + out_i = trunc(situOut_i / scale_i) | ||
| 74 | + $$ | ||
| 75 | + | ||
| 76 | +## 参数说明 | ||
| 77 | + | ||
| 78 | +<table style="undefined;table-layout: fixed; width: 951px"><colgroup> | ||
| 79 | + <col style="width: 121px"> | ||
| 80 | + <col style="width: 144px"> | ||
| 81 | + <col style="width: 313px"> | ||
| 82 | + <col style="width: 257px"> | ||
| 83 | + <col style="width: 116px"> | ||
| 84 | + </colgroup> | ||
| 85 | + <thead> | ||
| 86 | + <tr> | ||
| 87 | + <th>参数名</th> | ||
| 88 | + <th>输入/输出/属性</th> | ||
| 89 | + <th>描述</th> | ||
| 90 | + <th>数据类型</th> | ||
| 91 | + <th>数据格式</th> | ||
| 92 | + </tr></thead> | ||
| 93 | + <tbody> | ||
| 94 | + <tr> | ||
| 95 | + <td>x</td> | ||
| 96 | + <td>输入</td> | ||
| 97 | + <td>输入待处理的数据,公式中的x。输入不支持包含±inf或nan。</td> | ||
| 98 | + <td>INT8、INT32、BFLOAT16、FLOAT16</td> | ||
| 99 | + <td>ND</td> | ||
| 100 | + </tr> | ||
| 101 | + <tr> | ||
| 102 | + <td>weight_scale</td> | ||
| 103 | + <td>输入</td> | ||
| 104 | + <td>反量化的weight scale,公式中的weight_scale。输入不支持包含±inf或nan。</td> | ||
| 105 | + <td>FLOAT</td> | ||
| 106 | + <td>ND</td> | ||
| 107 | + </tr> | ||
| 108 | + <tr> | ||
| 109 | + <td>activation_scale</td> | ||
| 110 | + <td>输入</td> | ||
| 111 | + <td>反量化的activation scale,公式中的activation_scale。输入不支持包含±inf或nan。</td> | ||
| 112 | + <td>FLOAT</td> | ||
| 113 | + <td>ND</td> | ||
| 114 | + </tr> | ||
| 115 | + <tr> | ||
| 116 | + <td>bias</td> | ||
| 117 | + <td>输入</td> | ||
| 118 | + <td>反量化的bias,公式中的bias。输入不支持包含±inf或nan。</td> | ||
| 119 | + <td>FLOAT</td> | ||
| 120 | + <td>ND</td> | ||
| 121 | + </tr> | ||
| 122 | + <tr> | ||
| 123 | + <td>quant_scale</td> | ||
| 124 | + <td>输入</td> | ||
| 125 | + <td>量化的scale,公式中的quant_scale。输入不支持包含±inf或nan。</td> | ||
| 126 | + <td>FLOAT</td> | ||
| 127 | + <td>ND</td> | ||
| 128 | + </tr> | ||
| 129 | + <tr> | ||
| 130 | + <td>quant_offset</td> | ||
| 131 | + <td>输入</td> | ||
| 132 | + <td>量化的offset,公式中的quant_offset。输入不支持包含±inf或nan。</td> | ||
| 133 | + <td>FLOAT</td> | ||
| 134 | + <td>ND</td> | ||
| 135 | + </tr> | ||
| 136 | + <tr> | ||
| 137 | + <td>group_index</td> | ||
| 138 | + <td>输入</td> | ||
| 139 | + <td>MoE分组需要的group_index。输入不支持包含±inf或nan。</td> | ||
| 140 | + <td>INT64</td> | ||
| 141 | + <td>ND</td> | ||
| 142 | + </tr> | ||
| 143 | + <tr> | ||
| 144 | + <td>beta</td> | ||
| 145 | + <td>属性</td> | ||
| 146 | + <td>Situ激活的beta参数,公式中的β。不能为0。默认4.0。</td> | ||
| 147 | + <td>FLOAT</td> | ||
| 148 | + <td>-</td> | ||
| 149 | + </tr> | ||
| 150 | + <tr> | ||
| 151 | + <td>linear_beta</td> | ||
| 152 | + <td>属性</td> | ||
| 153 | + <td>Situ激活的linear_beta参数,公式中的linear_beta。当值≤0时不启用。默认25.0。</td> | ||
| 154 | + <td>FLOAT</td> | ||
| 155 | + <td>-</td> | ||
| 156 | + </tr> | ||
| 157 | + <tr> | ||
| 158 | + <td>activate_left</td> | ||
| 159 | + <td>属性</td> | ||
| 160 | + <td>表示gate取dequantOut的前半部分还是后半部分,公式中的activate_left。默认true。</td> | ||
| 161 | + <td>BOOL</td> | ||
| 162 | + <td>-</td> | ||
| 163 | + </tr> | ||
| 164 | + <tr> | ||
| 165 | + <td>quant_type</td> | ||
| 166 | + <td>属性</td> | ||
| 167 | + <td>表示量化模式,对应公式中的static/dynamic模式。支持"static"和"dynamic"。默认"dynamic"。</td> | ||
| 168 | + <td>STRING</td> | ||
| 169 | + <td>-</td> | ||
| 170 | + </tr> | ||
| 171 | + <tr> | ||
| 172 | + <td>y</td> | ||
| 173 | + <td>输出</td> | ||
| 174 | + <td>量化后的输出,公式中的out。</td> | ||
| 175 | + <td>INT8</td> | ||
| 176 | + <td>ND</td> | ||
| 177 | + </tr> | ||
| 178 | + <tr> | ||
| 179 | + <td>y_scale</td> | ||
| 180 | + <td>输出</td> | ||
| 181 | + <td>动态量化的scale,公式中的scale(仅dynamic模式有意义)。</td> | ||
| 182 | + <td>FLOAT</td> | ||
| 183 | + <td>ND</td> | ||
| 184 | + </tr> | ||
| 185 | + </tbody></table> | ||
| 186 | + | ||
| 187 | +## 约束说明 | ||
| 188 | + | ||
| 189 | +- x的最后一维需要是2的倍数。 | ||
| 190 | +- 当x的数据类型为INT8时,x维度≥2维;当x的数据类型为INT32/BF16/FLOAT16时,x维度为2维。 | ||
| 191 | +- beta参数不能为0。 | ||
| 192 | +- INT8路径:必须提供weight_scale,禁止activation_scale和group_index。 | ||
| 193 | +- INT32:必须提供weight_scale和activation_scale,禁止quant_scale和quant_offset。 | ||
| 194 | +- BFLOAT16/FLOAT16:所有可选输入均不使用(预反量化模式)。 | ||
| 195 | +- 当quant_type为static时,quant_scale必须提供。 | ||
| 196 | +- 当quant_type为dynamic时,quant_scale可选(作为smoothScale使用)。 | ||
| 197 | +- 算子支持的输入张量的内存大小有上限,校验公式:weight_scale张量内存大小+bias张量内存大小+quant_scale张量内存大小+quant_offset张量内存大小 + (activation_scale张量内存大小 + y_scale张量内存大小)/40 + x张量最后一维H内存大小 * 10 < 192KB。 | ||
| 198 | + | ||
| 199 | +## 调用说明 | ||
| 200 | + | ||
| 201 | +| 调用方式 | 调用样例 | 说明 | | ||
| 202 | +|--------------|------------------------------------------------------------------------|----------------------------------------------------------------| | ||
| 203 | +| aclnn调用 | [test_aclnn_dequant_situ_quant](./examples/test_aclnn_dequant_situ_quant.cpp) | 通过[aclnnDequantSituQuant](./docs/aclnnDequantSituQuant.md)接口方式调用DequantSituQuant算子。 | | ||
| 204 | +| 图模式调用 | - | 通过[算子IR](./op_graph/dequant_situ_quant_proto.h)构图方式调用DequantSituQuant算子。 | | ||
| @@ -0,0 +1,573 @@ | |||
| 1 | +# aclnnDequantSituQuant | ||
| 2 | + | ||
| 3 | +## 产品支持情况 | ||
| 4 | + | ||
| 5 | +<!-- npu="950" id1 --> | ||
| 6 | +- <term>Ascend 950PR/Ascend 950DT</term>:不支持 | ||
| 7 | +<!-- end id1 --> | ||
| 8 | +<!-- npu="A3" id2 --> | ||
| 9 | +- <term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term>:支持 | ||
| 10 | +<!-- end id2 --> | ||
| 11 | +<!-- npu="910b" id3 --> | ||
| 12 | +- <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term>:支持 | ||
| 13 | +<!-- end id3 --> | ||
| 14 | +<!-- npu="310b" id4 --> | ||
| 15 | +- <term>Atlas 200I/500 A2 推理产品</term>:不支持 | ||
| 16 | +<!-- end id4 --> | ||
| 17 | +<!-- npu="310p" id5 --> | ||
| 18 | +- <term>Atlas 推理系列产品</term>:不支持 | ||
| 19 | +<!-- end id5 --> | ||
| 20 | +<!-- npu="910" id6 --> | ||
| 21 | +- <term>Atlas 训练系列产品</term>:不支持 | ||
| 22 | +<!-- end id6 --> | ||
| 23 | + | ||
| 24 | +## 功能说明 | ||
| 25 | + | ||
| 26 | +- 接口功能:在Situ激活函数前后添加dequant和quant操作,实现x的DequantSituQuant计算。 | ||
| 27 | + | ||
| 28 | +- 计算公式: | ||
| 29 | + | ||
| 30 | +1. 根据输入数据类型x的不同,反量化路径不同: | ||
| 31 | + | ||
| 32 | +- INT8路径 | ||
| 33 | + | ||
| 34 | + $$ | ||
| 35 | + dequantOut_i = cast\_to\_float(x_i) \times weight\_scale_i + bias_i | ||
| 36 | + $$ | ||
| 37 | + | ||
| 38 | +- INT32路径 | ||
| 39 | + | ||
| 40 | + $$ | ||
| 41 | + dequantOut_i = cast\_to\_float(x_i) \times weight\_scale_i \times activation\_scale_i + bias_i | ||
| 42 | + $$ | ||
| 43 | + | ||
| 44 | +- BF16/FLOAT16路径(预反量化) | ||
| 45 | + | ||
| 46 | + $$ | ||
| 47 | + dequantOut_i = cast\_to\_float(x_i) | ||
| 48 | + $$ | ||
| 49 | + | ||
| 50 | +1. Situ激活 | ||
| 51 | + | ||
| 52 | +$$ | ||
| 53 | +situ_a = \beta \times \tanh(gate / \beta) \times sigmoid(gate) | ||
| 54 | +$$ | ||
| 55 | + | ||
| 56 | +当linear_beta > 0时: | ||
| 57 | + | ||
| 58 | +$$ | ||
| 59 | +up = linear\_beta \times \tanh(up / linear\_beta) | ||
| 60 | +$$ | ||
| 61 | + | ||
| 62 | +$$ | ||
| 63 | +situOut = situ_a \times up | ||
| 64 | +$$ | ||
| 65 | + | ||
| 66 | + 其中,当activate_left为true时,gate取dequantOut的前半部分,up取后半部分;当activate_left为false时,gate取dequantOut的后半部分,up取前半部分。 | ||
| 67 | + | ||
| 68 | +2. 量化 | ||
| 69 | + | ||
| 70 | +- quant_type = static | ||
| 71 | + | ||
| 72 | + $$ | ||
| 73 | + y_i = trunc(situOut_i / quant\_scale_i + quant\_offset_i) | ||
| 74 | + $$ | ||
| 75 | + | ||
| 76 | +- quant_type = dynamic | ||
| 77 | + | ||
| 78 | + $$ | ||
| 79 | + scale_i = absmax(situOut_i) / 127 | ||
| 80 | + $$ | ||
| 81 | + | ||
| 82 | + $$ | ||
| 83 | + y_i = trunc(situOut_i / scale_i) | ||
| 84 | + $$ | ||
| 85 | + | ||
| 86 | +## 函数原型 | ||
| 87 | + | ||
| 88 | +每个算子分为[两段式接口](../../../docs/zh/context/two_phase_api.md),必须先调用"aclnnDequantSituQuantGetWorkspaceSize"接口获取计算所需workspace大小以及包含了算子计算流程的执行器,再调用"aclnnDequantSituQuant"接口执行计算。 | ||
| 89 | + | ||
| 90 | +```Cpp | ||
| 91 | +aclnnStatus aclnnDequantSituQuantGetWorkspaceSize( | ||
| 92 | + const aclTensor* x, | ||
| 93 | + const aclTensor* weightScaleOptional, | ||
| 94 | + const aclTensor* activationScaleOptional, | ||
| 95 | + const aclTensor* biasOptional, | ||
| 96 | + const aclTensor* quantScaleOptional, | ||
| 97 | + const aclTensor* quantOffsetOptional, | ||
| 98 | + const aclTensor* groupIndexOptional, | ||
| 99 | + float beta, | ||
| 100 | + float linearBeta, | ||
| @@ -0,0 +1,350 @@ | |||
| 1 | +# dequant_situ_quant | ||
| 2 | + | ||
| 3 | +## 产品支持情况 | ||
| 4 | + | ||
| 5 | +<!-- npu="950" id1 --> | ||
| 6 | +- <term>Ascend 950PR/Ascend 950DT</term>:不支持 | ||
| 7 | +<!-- end id1 --> | ||
| 8 | +<!-- npu="A3" id2 --> | ||
| 9 | +- <term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term>:支持 | ||
| 10 | +<!-- end id2 --> | ||
| 11 | +<!-- npu="910b" id3 --> | ||
| 12 | +- <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term>:支持 | ||
| 13 | +<!-- end id3 --> | ||
| 14 | +<!-- npu="310b" id4 --> | ||
| 15 | +- <term>Atlas 200I/500 A2 推理产品</term>:不支持 | ||
| 16 | +<!-- end id4 --> | ||
| 17 | +<!-- npu="310p" id5 --> | ||
| 18 | +- <term>Atlas 推理系列产品</term>:不支持 | ||
| 19 | +<!-- end id5 --> | ||
| 20 | +<!-- npu="910" id6 --> | ||
| 21 | +- <term>Atlas 训练系列产品</term>:不支持 | ||
| 22 | +<!-- end id6 --> | ||
| 23 | + | ||
| 24 | +## 功能说明 | ||
| 25 | + | ||
| 26 | +- 接口功能:对输入x执行反量化(Dequant)、Situ激活函数和量化(Quant)的融合计算。底层封装aclnnDequantSituQuant。 | ||
| 27 | + | ||
| 28 | +- 计算公式: | ||
| 29 | + | ||
| 30 | + 1. 根据输入数据类型x的不同,反量化路径不同: | ||
| 31 | + | ||
| 32 | + - INT8路径: | ||
| 33 | + | ||
| 34 | + $$ | ||
| 35 | + dequantOut_i = cast\_to\_float(x_i) \times weight\_scale_i + bias_i | ||
| 36 | + $$ | ||
| 37 | + | ||
| 38 | + - INT32路径: | ||
| 39 | + | ||
| 40 | + $$ | ||
| 41 | + dequantOut_i = cast\_to\_float(x_i) \times weight\_scale_i \times activation\_scale_i + bias_i | ||
| 42 | + $$ | ||
| 43 | + | ||
| 44 | + - BFLOAT16/FLOAT16路径(预反量化): | ||
| 45 | + | ||
| 46 | + $$ | ||
| 47 | + dequantOut_i = cast\_to\_float(x_i) | ||
| 48 | + $$ | ||
| 49 | + 2. Situ激活: | ||
| 50 | + | ||
| 51 | + $$ | ||
| 52 | + situ_a = \beta \times \tanh(gate / \beta) \times sigmoid(gate) | ||
| 53 | + $$ | ||
| 54 | + | ||
| 55 | + 当linear_beta > 0时: | ||
| 56 | + | ||
| 57 | + $$ | ||
| 58 | + up = linear\_beta \times \tanh(up / linear\_beta) | ||
| 59 | + $$ | ||
| 60 | + | ||
| 61 | + $$ | ||
| 62 | + situOut = situ_a \times up | ||
| 63 | + $$ | ||
| 64 | + | ||
| 65 | + 其中,当activate_left为true时,gate取dequantOut的前半部分,up取后半部分;当activate_left为false时,gate取dequantOut的后半部分,up取前半部分。 | ||
| 66 | + 3. 量化: | ||
| 67 | + | ||
| 68 | + - static模式: | ||
| 69 | + | ||
| 70 | + $$ | ||
| 71 | + y_i = trunc(situOut_i / quant\_scale_i + quant\_offset_i) | ||
| 72 | + $$ | ||
| 73 | + | ||
| 74 | + - dynamic模式: | ||
| 75 | + | ||
| 76 | + $$ | ||
| 77 | + scale_i = absmax(situOut_i) / 127 | ||
| 78 | + $$ | ||
| 79 | + | ||
| 80 | + $$ | ||
| 81 | + y_i = trunc(situOut_i / scale_i) | ||
| 82 | + $$ | ||
| 83 | + | ||
| 84 | +## 函数原型 | ||
| 85 | + | ||
| 86 | +```python | ||
| 87 | +cann_ops_nn.dequant_situ_quant( | ||
| 88 | + x, | ||
| 89 | + *, | ||
| 90 | + weight_scale=None, | ||
| 91 | + activation_scale=None, | ||
| 92 | + bias=None, | ||
| 93 | + quant_scale=None, | ||
| 94 | + quant_offset=None, | ||
| 95 | + group_index=None, | ||
| 96 | + beta=4.0, | ||
| 97 | + linear_beta=25.0, | ||
| 98 | + activate_left=True, | ||
| 99 | + quant_type="dynamic", | ||
| 100 | +) -> (Tensor, Tensor) | ||
| 101 | +``` | ||
| 102 | + | ||
| 103 | +## 参数说明 | ||
| 104 | + | ||
| 105 | +<table style="undefined;table-layout: fixed; width:1625px"><colgroup> | ||
| 106 | +<col style="width: 147px"> | ||
| 107 | +<col style="width: 132px"> | ||
| 108 | +<col style="width: 132px"> | ||
| 109 | +<col style="width: 480px"> | ||
| 110 | +<col style="width: 330px"> | ||
| 111 | +<col style="width: 280px"> | ||
| 112 | +</colgroup> | ||
| 113 | +<thead> | ||
| 114 | +<tr> | ||
| 115 | + <th>参数名</th> | ||
| 116 | + <th>参数类型</th> | ||
| 117 | + <th>可选/必选</th> | ||
| 118 | + <th>描述</th> | ||
| 119 | + <th>数据类型</th> | ||
| 120 | + <th>维度(shape)</th> | ||
| 121 | +</tr> | ||
| 122 | +</thead> | ||
| 123 | +<tbody> | ||
| 124 | + <tr> | ||
| 125 | + <td>x</td> | ||
| 126 | + <td>Tensor</td> | ||
| 127 | + <td>必选</td> | ||
| 128 | + <td>输入数据,对应公式中的x。不支持非连续,数据格式支持ND。</td> | ||
| 129 | + <td>int8、int32、bfloat16、float16</td> | ||
| 130 | + <td>INT8: 2-8维;其他: 2维,最后一维为2H</td> | ||
| 131 | + </tr> | ||
| 132 | + <tr> | ||
| 133 | + <td>weight_scale</td> | ||
| 134 | + <td>Tensor</td> | ||
| 135 | + <td>可选</td> | ||
| 136 | + <td>反量化weight scale,对应公式中的weight_scale。不支持非连续,数据格式支持ND。</td> | ||
| 137 | + <td>float32</td> | ||
| 138 | + <td>1维,shape为(2H,)或(1,)</td> | ||
| 139 | + </tr> | ||
| 140 | + <tr> | ||
| 141 | + <td>activation_scale</td> | ||
| 142 | + <td>Tensor</td> | ||
| 143 | + <td>可选</td> | ||
| 144 | + <td>反量化activation scale,对应公式中的activation_scale。不支持非连续,数据格式支持ND。</td> | ||
| 145 | + <td>float32</td> | ||
| 146 | + <td>1维,shape为(1,)</td> | ||
| 147 | + </tr> | ||
| 148 | + <tr> | ||
| 149 | + <td>bias</td> | ||
| 150 | + <td>Tensor</td> | ||
| 151 | + <td>可选</td> | ||
| 152 | + <td>反量化bias,对应公式中的bias。不支持非连续,数据格式支持ND。</td> | ||
| 153 | + <td>float32</td> | ||
| 154 | + <td>1维,shape为(2H,)或(1,)</td> | ||
| 155 | + </tr> | ||
| 156 | + <tr> | ||
| 157 | + <td>quant_scale</td> | ||
| 158 | + <td>Tensor</td> | ||
| 159 | + <td>可选</td> | ||
| 160 | + <td>量化scale,对应公式中的quant_scale。不支持非连续,数据格式支持ND。</td> | ||
| 161 | + <td>float32</td> | ||
| 162 | + <td>1维,shape为(H,)或(1,)</td> | ||
| 163 | + </tr> | ||
| 164 | + <tr> | ||
| 165 | + <td>quant_offset</td> | ||
| 166 | + <td>Tensor</td> | ||
| 167 | + <td>可选</td> | ||
| 168 | + <td>量化offset,对应公式中的quant_offset。不支持非连续,数据格式支持ND。</td> | ||
| 169 | + <td>float32</td> | ||
| 170 | + <td>1维,shape为(H,)或(1,)</td> | ||
| 171 | + </tr> | ||
| 172 | + <tr> | ||
| 173 | + <td>group_index</td> | ||
| 174 | + <td>Tensor</td> | ||
| 175 | + <td>可选</td> | ||
| 176 | + <td>MoE group索引。不支持非连续,数据格式支持ND。</td> | ||
| 177 | + <td>int64</td> | ||
| 178 | + <td>1维,shape为(K,)</td> | ||
| 179 | + </tr> | ||
| 180 | + <tr> | ||
| 181 | + <td>beta</td> | ||
| 182 | + <td>float</td> | ||
| 183 | + <td>可选</td> | ||
| 184 | + <td>Situ激活的beta参数,对应公式中的β。默认4.0。</td> | ||
| 185 | + <td>-</td> | ||
| 186 | + <td>-</td> | ||
| 187 | + </tr> | ||
| 188 | + <tr> | ||
| 189 | + <td>linear_beta</td> | ||
| 190 | + <td>float</td> | ||
| 191 | + <td>可选</td> | ||
| 192 | + <td>Situ激活的linear_beta参数,对应公式中的linear_beta。默认25.0。</td> | ||
| 193 | + <td>-</td> | ||
| 194 | + <td>-</td> | ||
| 195 | + </tr> | ||
| 196 | + <tr> | ||
| 197 | + <td>activate_left</td> | ||
| 198 | + <td>bool</td> | ||
| 199 | + <td>可选</td> | ||
| 200 | + <td>表示gate取dequantOut的前半部分还是后半部分,对应公式中的activate_left。默认true。</td> | ||
| 201 | + <td>-</td> | ||
| 202 | + <td>-</td> | ||
| 203 | + </tr> | ||
| 204 | + <tr> | ||
| 205 | + <td>quant_type</td> | ||
| 206 | + <td>str</td> | ||
| 207 | + <td>可选</td> | ||
| 208 | + <td>量化模式,对应公式中的static/dynamic模式。支持"static"和"dynamic"。默认"dynamic"。</td> | ||
| 209 | + <td>-</td> | ||
| 210 | + <td>-</td> | ||
| 211 | + </tr> | ||
| 212 | +</tbody> | ||
| 213 | +</table> | ||
| 214 | + | ||
| 215 | +## 返回值说明 | ||
| 216 | + | ||
| 217 | +<table style="undefined;table-layout: fixed; width:1625px"><colgroup> | ||
| 218 | +<col style="width: 147px"> | ||
| 219 | +<col style="width: 132px"> | ||
| 220 | +<col style="width: 132px"> | ||
| 221 | +<col style="width: 480px"> | ||
| 222 | +<col style="width: 330px"> | ||
| 223 | +<col style="width: 280px"> | ||
| 224 | +</colgroup> | ||
| 225 | +<thead> | ||
| 226 | +<tr> | ||
| 227 | + <th>输出名</th> | ||
| 228 | + <th>输出类型</th> | ||
| 229 | + <th>可选/必选</th> | ||
| 230 | + <th>描述</th> | ||
| 231 | + <th>数据类型</th> | ||
| 232 | + <th>维度(shape)</th> | ||
| 233 | +</tr> | ||
| 234 | +</thead> | ||
| 235 | +<tbody> | ||
| 236 | + <tr> | ||
| 237 | + <td>y</td> | ||
| 238 | + <td>Tensor</td> | ||
| 239 | + <td>必选</td> | ||
| 240 | + <td>量化输出,对应公式中的y。不支持非连续,数据格式支持ND。</td> | ||
| 241 | + <td>int8</td> | ||
| 242 | + <td>INT8: x.shape[:-1]+[H];其他: [M, H]</td> | ||
| 243 | + </tr> | ||
| 244 | + <tr> | ||
| 245 | + <td>y_scale</td> | ||
| 246 | + <td>Tensor</td> | ||
| 247 | + <td>必选</td> | ||
| 248 | + <td>动态量化scale,对应公式中的scale(仅dynamic模式有意义)。不支持非连续,数据格式支持ND。</td> | ||
| 249 | + <td>float32</td> | ||
| 250 | + <td>INT8: x.shape[:-1];其他: [M]</td> | ||
| 251 | + </tr> | ||
| 252 | +</tbody> | ||
| 253 | +</table> | ||
| 254 | + | ||
| 255 | +其中H = x.shape[-1] / 2。 | ||
| 256 | + | ||
| 257 | +## 约束说明 | ||
| 258 | + | ||
| 259 | +- x及可选Tensor均需为NPU Tensor;可选Tensor可以传None。 | ||
| 260 | +- x的最后一维必须为偶数。当x的数据类型为INT8时,维度≥2维;当x的数据类型为INT32/BF16/FLOAT16时,维度为2维。 | ||
| 261 | +- beta参数不能为0。 | ||
| 262 | +- 当quant_type为"static"时,quant_scale必须提供。 | ||
| 263 | +- 支持空Tensor(当x.size(0) == 0时直接返回空输出)。 | ||
| 264 | +- 关于quant_type的约束说明如下: | ||
| 265 | + | ||
| 266 | + | quant_type | 含义 | quant_scale | quant_offset | | ||
| 267 | + | ---- | ---- | ---- | ---- | | ||
| 268 | + | "static" | 静态量化 | 必选 | 可选 | | ||
| 269 | + | "dynamic" | 动态量化 | 可选(作为smoothScale) | 不生效 | | ||
| 270 | + | ||
| 271 | +- 各数据类型的输入约束如下: | ||
| 272 | + | ||
| 273 | + | x数据类型 | 必选输入 | 可选输入 | 禁止输入 | | ||
| 274 | + | ---- | ---- | ---- | ---- | | ||
| 275 | + | INT8 | x, weight_scale | bias, quant_scale, quant_offset | activation_scale, group_index | | ||
| 276 | + | INT32 | x, weight_scale, activation_scale | bias, group_index | quant_scale, quant_offset | | ||
| 277 | + | BF16 | x | — | weight_scale, activation_scale, bias, quant_scale, quant_offset, group_index | | ||
| 278 | + | FLOAT16 | x | — | weight_scale, activation_scale, bias, quant_scale, quant_offset, group_index | | ||
| 279 | + | ||
| 280 | +- 该接口支持训练、推理场景下使用。 | ||
| 281 | +- 该接口支持单算子模式和TorchAir图模式调用。 | ||
| 282 | + | ||
| 283 | +## 确定性计算 | ||
| 284 | + | ||
| 285 | +默认支持确定性计算。 | ||
| 286 | + | ||
| 287 | +## 调用示例 | ||
| 288 | + | ||
| 289 | +- 单算子模式调用(eager) | ||
| 290 | + | ||
| 291 | + ```python | ||
| 292 | + import torch | ||
| 293 | + import torch_npu | ||
| 294 | + import cann_ops_nn | ||
| 295 | + | ||
| 296 | + # INT8, dynamic量化 | ||
| 297 | + x = torch.randint(-127, 127, (16, 64), dtype=torch.int8).npu() | ||
| 298 | + weight_scale = torch.full((64,), 0.1, dtype=torch.float32).npu() | ||
| 299 | + | ||
| 300 | + y, y_scale = cann_ops_nn.dequant_situ_quant( | ||
| 301 | + x, weight_scale=weight_scale, | ||
| 302 | + beta=4.0, linear_beta=25.0, activate_left=True, quant_type="dynamic", | ||
| 303 | + ) | ||
| 304 | + print("y:============", y.shape, y.cpu()) | ||
| 305 | + print("y_scale:============", y_scale.shape, y_scale.cpu()) | ||
| 306 | + | ||
| 307 | + # BF16, 预反量化 | ||
| 308 | + x_bf16 = torch.randn(32, 128, dtype=torch.bfloat16).npu() | ||
| 309 | + y_bf16, y_scale_bf16 = cann_ops_nn.dequant_situ_quant( | ||
| 310 | + x_bf16, beta=4.0, linear_beta=25.0, activate_left=True, quant_type="dynamic", | ||
| 311 | + ) | ||
| 312 | + print("y_bf16:============", y_bf16.shape, y_bf16.cpu()) | ||
| 313 | + ``` | ||
| 314 | + | ||
| 315 | +- 图模式(torchair)调用 | ||
| 316 | + | ||
| 317 | + ```python | ||
| 318 | + import torch | ||
| 319 | + import torch_npu | ||
| 320 | + import torchair | ||
| 321 | + import cann_ops_nn | ||
| 322 | + | ||
| 323 | + | ||
| 324 | + class NetModel(torch.nn.Module): | ||
| 325 | + def __init__(self): | ||
| 326 | + super().__init__() | ||
| 327 | + | ||
| 328 | + def forward(self, x, weight_scale, quant_scale): | ||
| 329 | + return cann_ops_nn.dequant_situ_quant( | ||
| 330 | + x, weight_scale=weight_scale, quant_scale=quant_scale, | ||
| 331 | + beta=4.0, linear_beta=25.0, activate_left=True, quant_type="static", | ||
| 332 | + ) | ||
| 333 | + | ||
| 334 | + | ||
| 335 | + def dequant_situ_quant_test(): | ||
| 336 | + x = torch.randint(-127, 127, (16, 64), dtype=torch.int8).npu() | ||
| 337 | + weight_scale = torch.full((64,), 0.1, dtype=torch.float32).npu() | ||
| 338 | + quant_scale = torch.tensor([1.0], dtype=torch.float32).npu() | ||
| 339 | + model = NetModel() | ||
| 340 | + config = torchair.CompilerConfig() | ||
| 341 | + npu_backend = torchair.get_npu_backend(compiler_config=config) | ||
| 342 | + model = torch.compile(model, backend=npu_backend, dynamic=True, fullgraph=True) | ||
| 343 | + y, y_scale = model(x, weight_scale, quant_scale) | ||
| 344 | + print("y:============", y.shape, y.cpu()) | ||
| 345 | + print("y_scale:============", y_scale.shape, y_scale.cpu()) | ||
| 346 | + | ||
| 347 | + | ||
| 348 | + if __name__ == "__main__": | ||
| 349 | + dequant_situ_quant_test() | ||
| 350 | + ``` | ||
| @@ -0,0 +1,451 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2025 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +#include <iostream> | ||
| 12 | +#include <vector> | ||
| 13 | +#include <cmath> | ||
| 14 | +#include <cstring> | ||
| 15 | +#include <algorithm> | ||
| 16 | +#include "acl/acl.h" | ||
| 17 | +#include "aclnnop/aclnn_dequant_situ_quant.h" | ||
| 18 | + | ||
| 19 | +#define CHECK_RET(cond, return_expr) \ | ||
| 20 | + do { \ | ||
| 21 | + if (!(cond)) { \ | ||
| 22 | + return_expr; \ | ||
| 23 | + } \ | ||
| 24 | + } while (0) | ||
| 25 | + | ||
| 26 | +#define LOG_PRINT(message, ...) \ | ||
| 27 | + do { \ | ||
| 28 | + printf(message, ##__VA_ARGS__); \ | ||
| 29 | + } while (0) | ||
| 30 | + | ||
| 31 | +int64_t GetShapeSize(const std::vector<int64_t>& shape) | ||
| 32 | +{ | ||
| 33 | + int64_t shapeSize = 1; | ||
| 34 | + for (auto i : shape) { | ||
| 35 | + shapeSize *= i; | ||
| 36 | + } | ||
| 37 | + return shapeSize; | ||
| 38 | +} | ||
| 39 | + | ||
| 40 | +template <typename T> | ||
| 41 | +int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, | ||
| 42 | + aclDataType dataType, aclTensor** tensor) | ||
| 43 | +{ | ||
| 44 | + auto size = GetShapeSize(shape) * sizeof(T); | ||
| 45 | + auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 46 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); | ||
| 47 | + ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 48 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); | ||
| 49 | + | ||
| 50 | + std::vector<int64_t> strides(shape.size(), 1); | ||
| 51 | + for (int64_t i = shape.size() - 2; i >= 0; i--) { | ||
| 52 | + strides[i] = shape[i + 1] * strides[i + 1]; | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, | ||
| 56 | + shape.data(), shape.size(), *deviceAddr); | ||
| 57 | + return 0; | ||
| 58 | +} | ||
| 59 | + | ||
| 60 | +// Truncate towards zero (matching kernel's CAST_TRUNC for fp16→int8) | ||
| 61 | +int8_t TruncToInt8(float val) | ||
| 62 | +{ | ||
| 63 | + int32_t intVal = static_cast<int32_t>(val); // truncation towards zero | ||
| 64 | + intVal = std::max(-128, std::min(127, intVal)); | ||
| 65 | + return static_cast<int8_t>(intVal); | ||
| 66 | +} | ||
| 67 | + | ||
| 68 | +// CPU reference: DequantSituQuant static mode | ||
| 69 | +void CpuStaticQuant(const std::vector<int8_t>& x, const std::vector<float>& dequantScale, | ||
| 70 | + const std::vector<float>& quantScale, const std::vector<float>& quantOffset, int64_t rowLen, | ||
| 71 | + int64_t inDimy, int64_t outDimy, double beta, double linearBeta, bool activateLeft, | ||
| 72 | + std::vector<int8_t>& yOut) | ||
| 73 | +{ | ||
| 74 | + for (int64_t r = 0; r < rowLen; r++) { | ||
| 75 | + for (int64_t c = 0; c < outDimy; c++) { | ||
| 76 | + int64_t gateIdx = r * inDimy + (activateLeft ? c : c + outDimy); | ||
| 77 | + int64_t upIdx = r * inDimy + (activateLeft ? c + outDimy : c); | ||
| 78 | + | ||
| 79 | + float gate = static_cast<float>(x[gateIdx]) * dequantScale[gateIdx % dequantScale.size()]; | ||
| 80 | + float up = static_cast<float>(x[upIdx]) * dequantScale[upIdx % dequantScale.size()]; | ||
| 81 | + | ||
| 82 | + float invBeta = 1.0f / static_cast<float>(beta); | ||
| 83 | + float tanhResult = std::tanh(gate * invBeta) * static_cast<float>(beta); | ||
| 84 | + float sigmoidResult = 1.0f / (1.0f + std::exp(-gate)); | ||
| 85 | + float situA = tanhResult * sigmoidResult; | ||
| 86 | + | ||
| 87 | + if (linearBeta > 0.0) { | ||
| 88 | + float invLb = 1.0f / static_cast<float>(linearBeta); | ||
| 89 | + up = std::tanh(up * invLb) * static_cast<float>(linearBeta); | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | + float situOut = situA * up; | ||
| 93 | + | ||
| 94 | + float qs = quantScale.size() == 1 ? quantScale[0] : quantScale[c]; | ||
| 95 | + float qo = quantOffset.empty() ? 0.0f : (quantOffset.size() == 1 ? quantOffset[0] : quantOffset[c]); | ||
| 96 | + float quantized = situOut / qs + qo; | ||
| 97 | + | ||
| 98 | + yOut[r * outDimy + c] = TruncToInt8(quantized); | ||
| 99 | + } | ||
| 100 | + } | ||
| 101 | +} | ||
| 102 | + | ||
| 103 | +// CPU reference: DequantSituQuant dynamic mode | ||
| 104 | +void CpuDynamicQuant(const std::vector<int8_t>& x, const std::vector<float>& dequantScale, int64_t rowLen, | ||
| 105 | + int64_t inDimy, int64_t outDimy, double beta, double linearBeta, bool activateLeft, | ||
| 106 | + std::vector<int8_t>& yOut, std::vector<float>& yScaleOut) | ||
| 107 | +{ | ||
| 108 | + std::vector<float> situOutBuf(rowLen * outDimy, 0.0f); | ||
| 109 | + | ||
| 110 | + for (int64_t r = 0; r < rowLen; r++) { | ||
| 111 | + for (int64_t c = 0; c < outDimy; c++) { | ||
| 112 | + int64_t gateIdx = r * inDimy + (activateLeft ? c : c + outDimy); | ||
| 113 | + int64_t upIdx = r * inDimy + (activateLeft ? c + outDimy : c); | ||
| 114 | + | ||
| 115 | + float gate = static_cast<float>(x[gateIdx]) * dequantScale[gateIdx % dequantScale.size()]; | ||
| 116 | + float up = static_cast<float>(x[upIdx]) * dequantScale[upIdx % dequantScale.size()]; | ||
| 117 | + | ||
| 118 | + float invBeta = 1.0f / static_cast<float>(beta); | ||
| 119 | + float tanhResult = std::tanh(gate * invBeta) * static_cast<float>(beta); | ||
| 120 | + float sigmoidResult = 1.0f / (1.0f + std::exp(-gate)); | ||
| 121 | + float situA = tanhResult * sigmoidResult; | ||
| 122 | + | ||
| 123 | + if (linearBeta > 0.0) { | ||
| 124 | + float invLb = 1.0f / static_cast<float>(linearBeta); | ||
| 125 | + up = std::tanh(up * invLb) * static_cast<float>(linearBeta); | ||
| 126 | + } | ||
| 127 | + | ||
| 128 | + situOutBuf[r * outDimy + c] = situA * up; | ||
| 129 | + } | ||
| 130 | + | ||
| 131 | + float absMax = 0.0f; | ||
| 132 | + for (int64_t c = 0; c < outDimy; c++) { | ||
| 133 | + absMax = std::max(absMax, std::abs(situOutBuf[r * outDimy + c])); | ||
| 134 | + } | ||
| 135 | + float scale = absMax / 127.0f; | ||
| 136 | + if (scale == 0.0f) | ||
| 137 | + scale = 1.0f; | ||
| 138 | + float invScale = 1.0f / scale; | ||
| 139 | + yScaleOut[r] = scale; | ||
| 140 | + | ||
| 141 | + for (int64_t c = 0; c < outDimy; c++) { | ||
| 142 | + yOut[r * outDimy + c] = TruncToInt8(situOutBuf[r * outDimy + c] * invScale); | ||
| 143 | + } | ||
| 144 | + } | ||
| 145 | +} | ||
| 146 | + | ||
| 147 | +// ============ Test 1: static quant, scalar quant_scale, no bias ============ | ||
| 148 | +int TestStaticQuantScalar(int32_t deviceId, aclrtStream stream) | ||
| 149 | +{ | ||
| 150 | + LOG_PRINT("\n========== Test 1: Static Quant (scalar scale, no bias) ==========\n"); | ||
| 151 | + | ||
| 152 | + int64_t rowLen = 16; | ||
| 153 | + int64_t inDimy = 64; | ||
| 154 | + int64_t outDimy = 32; | ||
| 155 | + double beta = 1.0; | ||
| 156 | + double linearBeta = 0.0; | ||
| 157 | + bool activateLeft = false; | ||
| 158 | + | ||
| 159 | + std::vector<int64_t> xShape = {rowLen, inDimy}; | ||
| 160 | + std::vector<int64_t> dequantScaleShape = {inDimy}; | ||
| 161 | + std::vector<int64_t> quantScaleShape = {1}; | ||
| 162 | + std::vector<int64_t> quantOffsetShape = {1}; | ||
| 163 | + std::vector<int64_t> yShape = {rowLen, outDimy}; | ||
| 164 | + std::vector<int64_t> yScaleOutShape = {rowLen}; | ||
| 165 | + | ||
| 166 | + auto xSize = GetShapeSize(xShape); | ||
| 167 | + auto dsSize = GetShapeSize(dequantScaleShape); | ||
| 168 | + auto qsSize = GetShapeSize(quantScaleShape); | ||
| 169 | + auto qoSize = GetShapeSize(quantOffsetShape); | ||
| 170 | + auto ySize = GetShapeSize(yShape); | ||
| 171 | + auto yScaleSize = GetShapeSize(yScaleOutShape); | ||
| 172 | + | ||
| 173 | + std::vector<int8_t> xHostData(xSize); | ||
| 174 | + for (int64_t i = 0; i < xSize; i++) { | ||
| 175 | + xHostData[i] = static_cast<int8_t>((i * 7 + 3) % 100); | ||
| 176 | + } | ||
| 177 | + std::vector<float> dequantScaleHostData(dsSize, 0.1f); | ||
| 178 | + std::vector<float> quantScaleHostData(qsSize, 1.0f); | ||
| 179 | + std::vector<float> quantOffsetHostData(qoSize, 0.0f); | ||
| 180 | + std::vector<int8_t> yHostData(ySize, 0); | ||
| 181 | + std::vector<float> yScaleOutHostData(yScaleSize, 0.0f); | ||
| 182 | + | ||
| 183 | + void* xDeviceAddr = nullptr; | ||
| 184 | + void* dsDeviceAddr = nullptr; | ||
| 185 | + void* qsDeviceAddr = nullptr; | ||
| 186 | + void* qoDeviceAddr = nullptr; | ||
| 187 | + void* yDeviceAddr = nullptr; | ||
| 188 | + void* yScaleDeviceAddr = nullptr; | ||
| 189 | + aclTensor* x = nullptr; | ||
| 190 | + aclTensor* dequantScale = nullptr; | ||
| 191 | + aclTensor* quantScale = nullptr; | ||
| 192 | + aclTensor* quantOffset = nullptr; | ||
| 193 | + aclTensor* y = nullptr; | ||
| 194 | + aclTensor* yScaleOut = nullptr; | ||
| 195 | + | ||
| 196 | + auto ret = CreateAclTensor(xHostData, xShape, &xDeviceAddr, aclDataType::ACL_INT8, &x); | ||
| 197 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 198 | + ret = CreateAclTensor(dequantScaleHostData, dequantScaleShape, &dsDeviceAddr, aclDataType::ACL_FLOAT, | ||
| 199 | + &dequantScale); | ||
| 200 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 201 | + ret = CreateAclTensor(quantScaleHostData, quantScaleShape, &qsDeviceAddr, aclDataType::ACL_FLOAT, &quantScale); | ||
| 202 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 203 | + ret = CreateAclTensor(quantOffsetHostData, quantOffsetShape, &qoDeviceAddr, aclDataType::ACL_FLOAT, &quantOffset); | ||
| 204 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 205 | + ret = CreateAclTensor(yHostData, yShape, &yDeviceAddr, aclDataType::ACL_INT8, &y); | ||
| 206 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 207 | + ret = CreateAclTensor(yScaleOutHostData, yScaleOutShape, &yScaleDeviceAddr, aclDataType::ACL_FLOAT, &yScaleOut); | ||
| 208 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 209 | + | ||
| 210 | + uint64_t workspaceSize = 0; | ||
| 211 | + aclOpExecutor* executor; | ||
| 212 | + ret = aclnnDequantSituQuantGetWorkspaceSize(x, dequantScale, nullptr, nullptr, quantScale, quantOffset, nullptr, | ||
| 213 | + beta, linearBeta, activateLeft, const_cast<char*>("static"), y, | ||
| 214 | + yScaleOut, &workspaceSize, &executor); | ||
| 215 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("GetWorkspaceSize failed. ERROR: %d\n", ret); return ret); | ||
| 216 | + | ||
| 217 | + void* workspaceAddr = nullptr; | ||
| 218 | + if (workspaceSize > 0) { | ||
| 219 | + ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 220 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | ||
| 221 | + } | ||
| 222 | + | ||
| 223 | + ret = aclnnDequantSituQuant(workspaceAddr, workspaceSize, executor, stream); | ||
| 224 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnDequantSituQuant failed. ERROR: %d\n", ret); return ret); | ||
| 225 | + | ||
| 226 | + ret = aclrtSynchronizeStream(stream); | ||
| 227 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 228 | + | ||
| 229 | + std::vector<int8_t> npuYResult(ySize, 0); | ||
| 230 | + ret = aclrtMemcpy(npuYResult.data(), npuYResult.size() * sizeof(int8_t), yDeviceAddr, ySize * sizeof(int8_t), | ||
| 231 | + ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 232 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy y result failed. ERROR: %d\n", ret); return ret); | ||
| 233 | + | ||
| 234 | + std::vector<int8_t> cpuYResult(ySize, 0); | ||
| 235 | + CpuStaticQuant(xHostData, dequantScaleHostData, quantScaleHostData, quantOffsetHostData, rowLen, inDimy, outDimy, | ||
| 236 | + beta, linearBeta, activateLeft, cpuYResult); | ||
| 237 | + | ||
| 238 | + int64_t matchCount = 0; | ||
| 239 | + int64_t closeCount = 0; | ||
| 240 | + int64_t mismatchCount = 0; | ||
| 241 | + int maxDiff = 0; | ||
| 242 | + for (int64_t i = 0; i < ySize; i++) { | ||
| 243 | + int diff = std::abs(static_cast<int>(npuYResult[i]) - static_cast<int>(cpuYResult[i])); | ||
| 244 | + if (diff == 0) | ||
| 245 | + matchCount++; | ||
| 246 | + if (diff <= 1) | ||
| 247 | + closeCount++; | ||
| 248 | + else | ||
| 249 | + mismatchCount++; | ||
| 250 | + maxDiff = std::max(maxDiff, diff); | ||
| 251 | + } | ||
| 252 | + | ||
| 253 | + LOG_PRINT("Static quant: total=%ld, exact_match=%ld, within_1=%ld, mismatch=%ld, max_diff=%d\n", ySize, matchCount, | ||
| 254 | + closeCount, mismatchCount, maxDiff); | ||
| 255 | + LOG_PRINT("NPU y (first 16): "); | ||
| 256 | + for (int64_t i = 0; i < std::min<int64_t>(16, ySize); i++) | ||
| 257 | + LOG_PRINT("%d ", npuYResult[i]); | ||
| 258 | + LOG_PRINT("\nCPU y (first 16): "); | ||
| 259 | + for (int64_t i = 0; i < std::min<int64_t>(16, ySize); i++) | ||
| 260 | + LOG_PRINT("%d ", cpuYResult[i]); | ||
| 261 | + LOG_PRINT("\n"); | ||
| 262 | + | ||
| 263 | + aclDestroyTensor(x); | ||
| 264 | + aclDestroyTensor(dequantScale); | ||
| 265 | + aclDestroyTensor(quantScale); | ||
| 266 | + aclDestroyTensor(quantOffset); | ||
| 267 | + aclDestroyTensor(y); | ||
| 268 | + aclDestroyTensor(yScaleOut); | ||
| 269 | + aclrtFree(xDeviceAddr); | ||
| 270 | + aclrtFree(dsDeviceAddr); | ||
| 271 | + aclrtFree(qsDeviceAddr); | ||
| 272 | + aclrtFree(qoDeviceAddr); | ||
| 273 | + aclrtFree(yDeviceAddr); | ||
| 274 | + aclrtFree(yScaleDeviceAddr); | ||
| 275 | + if (workspaceSize > 0) | ||
| 276 | + aclrtFree(workspaceAddr); | ||
| 277 | + | ||
| 278 | + bool passed = (maxDiff <= 2); | ||
| 279 | + LOG_PRINT("Test 1 %s (max_diff=%d, tolerance=2)\n", passed ? "PASSED" : "FAILED", maxDiff); | ||
| 280 | + return passed ? 0 : 1; | ||
| 281 | +} | ||
| 282 | + | ||
| 283 | +// ============ Test 2: dynamic quant, no bias, no smooth ============ | ||
| 284 | +int TestDynamicQuant(int32_t deviceId, aclrtStream stream) | ||
| 285 | +{ | ||
| 286 | + LOG_PRINT("\n========== Test 2: Dynamic Quant (no bias, no smooth) ==========\n"); | ||
| 287 | + | ||
| 288 | + int64_t rowLen = 32; | ||
| 289 | + int64_t inDimy = 128; | ||
| 290 | + int64_t outDimy = 64; | ||
| 291 | + double beta = 1.0; | ||
| 292 | + double linearBeta = 0.0; | ||
| 293 | + bool activateLeft = false; | ||
| 294 | + | ||
| 295 | + std::vector<int64_t> xShape = {rowLen, inDimy}; | ||
| 296 | + std::vector<int64_t> dequantScaleShape = {inDimy}; | ||
| 297 | + std::vector<int64_t> yShape = {rowLen, outDimy}; | ||
| 298 | + std::vector<int64_t> yScaleOutShape = {rowLen}; | ||
| 299 | + | ||
| 300 | + auto xSize = GetShapeSize(xShape); | ||
| 301 | + auto dsSize = GetShapeSize(dequantScaleShape); | ||
| 302 | + auto ySize = GetShapeSize(yShape); | ||
| 303 | + auto yScaleSize = GetShapeSize(yScaleOutShape); | ||
| 304 | + | ||
| 305 | + std::vector<int8_t> xHostData(xSize); | ||
| 306 | + for (int64_t i = 0; i < xSize; i++) { | ||
| 307 | + xHostData[i] = static_cast<int8_t>((i * 7 + 3) % 100); | ||
| 308 | + } | ||
| 309 | + std::vector<float> dequantScaleHostData(dsSize, 0.1f); | ||
| 310 | + std::vector<int8_t> yHostData(ySize, 0); | ||
| 311 | + std::vector<float> yScaleOutHostData(yScaleSize, 0.0f); | ||
| 312 | + | ||
| 313 | + void* xDeviceAddr = nullptr; | ||
| 314 | + void* dsDeviceAddr = nullptr; | ||
| 315 | + void* yDeviceAddr = nullptr; | ||
| 316 | + void* yScaleDeviceAddr = nullptr; | ||
| 317 | + aclTensor* x = nullptr; | ||
| 318 | + aclTensor* dequantScale = nullptr; | ||
| 319 | + aclTensor* y = nullptr; | ||
| 320 | + aclTensor* yScaleOut = nullptr; | ||
| 321 | + | ||
| 322 | + auto ret = CreateAclTensor(xHostData, xShape, &xDeviceAddr, aclDataType::ACL_INT8, &x); | ||
| 323 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 324 | + ret = CreateAclTensor(dequantScaleHostData, dequantScaleShape, &dsDeviceAddr, aclDataType::ACL_FLOAT, | ||
| 325 | + &dequantScale); | ||
| 326 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 327 | + ret = CreateAclTensor(yHostData, yShape, &yDeviceAddr, aclDataType::ACL_INT8, &y); | ||
| 328 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 329 | + ret = CreateAclTensor(yScaleOutHostData, yScaleOutShape, &yScaleDeviceAddr, aclDataType::ACL_FLOAT, &yScaleOut); | ||
| 330 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 331 | + | ||
| 332 | + uint64_t workspaceSize = 0; | ||
| 333 | + aclOpExecutor* executor; | ||
| 334 | + ret = aclnnDequantSituQuantGetWorkspaceSize(x, dequantScale, nullptr, nullptr, nullptr, nullptr, nullptr, beta, | ||
| 335 | + linearBeta, activateLeft, const_cast<char*>("dynamic"), y, yScaleOut, | ||
| 336 | + &workspaceSize, &executor); | ||
| 337 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("GetWorkspaceSize failed. ERROR: %d\n", ret); return ret); | ||
| 338 | + | ||
| 339 | + void* workspaceAddr = nullptr; | ||
| 340 | + if (workspaceSize > 0) { | ||
| 341 | + ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 342 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | ||
| 343 | + } | ||
| 344 | + | ||
| 345 | + ret = aclnnDequantSituQuant(workspaceAddr, workspaceSize, executor, stream); | ||
| 346 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnDequantSituQuant failed. ERROR: %d\n", ret); return ret); | ||
| 347 | + | ||
| 348 | + ret = aclrtSynchronizeStream(stream); | ||
| 349 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 350 | + | ||
| 351 | + std::vector<int8_t> npuYResult(ySize, 0); | ||
| 352 | + ret = aclrtMemcpy(npuYResult.data(), npuYResult.size() * sizeof(int8_t), yDeviceAddr, ySize * sizeof(int8_t), | ||
| 353 | + ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 354 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy y result failed. ERROR: %d\n", ret); return ret); | ||
| 355 | + | ||
| 356 | + std::vector<float> npuScaleResult(yScaleSize, 0.0f); | ||
| 357 | + ret = aclrtMemcpy(npuScaleResult.data(), npuScaleResult.size() * sizeof(float), yScaleDeviceAddr, | ||
| 358 | + yScaleSize * sizeof(float), ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 359 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy scale result failed. ERROR: %d\n", ret); return ret); | ||
| 360 | + | ||
| 361 | + std::vector<int8_t> cpuYResult(ySize, 0); | ||
| 362 | + std::vector<float> cpuScaleResult(yScaleSize, 0.0f); | ||
| 363 | + CpuDynamicQuant(xHostData, dequantScaleHostData, rowLen, inDimy, outDimy, beta, linearBeta, activateLeft, | ||
| 364 | + cpuYResult, cpuScaleResult); | ||
| 365 | + | ||
| 366 | + int64_t matchCount = 0; | ||
| 367 | + int64_t closeCount = 0; | ||
| 368 | + int maxDiff = 0; | ||
| 369 | + for (int64_t i = 0; i < ySize; i++) { | ||
| 370 | + int diff = std::abs(static_cast<int>(npuYResult[i]) - static_cast<int>(cpuYResult[i])); | ||
| 371 | + if (diff == 0) | ||
| 372 | + matchCount++; | ||
| 373 | + if (diff <= 1) | ||
| 374 | + closeCount++; | ||
| 375 | + maxDiff = std::max(maxDiff, diff); | ||
| 376 | + } | ||
| 377 | + | ||
| 378 | + int64_t scaleMatch = 0; | ||
| 379 | + float maxScaleDiff = 0.0f; | ||
| 380 | + for (int64_t i = 0; i < yScaleSize; i++) { | ||
| 381 | + float diff = std::abs(npuScaleResult[i] - cpuScaleResult[i]); | ||
| 382 | + if (diff < 1e-3f) | ||
| 383 | + scaleMatch++; | ||
| 384 | + maxScaleDiff = std::max(maxScaleDiff, diff); | ||
| 385 | + } | ||
| 386 | + | ||
| 387 | + LOG_PRINT("Dynamic quant y: total=%ld, exact_match=%ld, within_1=%ld, max_diff=%d\n", ySize, matchCount, closeCount, | ||
| 388 | + maxDiff); | ||
| 389 | + LOG_PRINT("Dynamic quant scale: total=%ld, match=%ld, max_diff=%f\n", yScaleSize, scaleMatch, maxScaleDiff); | ||
| 390 | + LOG_PRINT("NPU y (first 16): "); | ||
| 391 | + for (int64_t i = 0; i < std::min<int64_t>(16, ySize); i++) | ||
| 392 | + LOG_PRINT("%d ", npuYResult[i]); | ||
| 393 | + LOG_PRINT("\nCPU y (first 16): "); | ||
| 394 | + for (int64_t i = 0; i < std::min<int64_t>(16, ySize); i++) | ||
| 395 | + LOG_PRINT("%d ", cpuYResult[i]); | ||
| 396 | + LOG_PRINT("\n"); | ||
| 397 | + LOG_PRINT("NPU scale (first 5): "); | ||
| 398 | + for (int64_t i = 0; i < std::min<int64_t>(5, yScaleSize); i++) | ||
| 399 | + LOG_PRINT("%f ", npuScaleResult[i]); | ||
| 400 | + LOG_PRINT("\nCPU scale (first 5): "); | ||
| 401 | + for (int64_t i = 0; i < std::min<int64_t>(5, yScaleSize); i++) | ||
| 402 | + LOG_PRINT("%f ", cpuScaleResult[i]); | ||
| 403 | + LOG_PRINT("\n"); | ||
| 404 | + | ||
| 405 | + aclDestroyTensor(x); | ||
| 406 | + aclDestroyTensor(dequantScale); | ||
| 407 | + aclDestroyTensor(y); | ||
| 408 | + aclDestroyTensor(yScaleOut); | ||
| 409 | + aclrtFree(xDeviceAddr); | ||
| 410 | + aclrtFree(dsDeviceAddr); | ||
| 411 | + aclrtFree(yDeviceAddr); | ||
| 412 | + aclrtFree(yScaleDeviceAddr); | ||
| 413 | + if (workspaceSize > 0) | ||
| 414 | + aclrtFree(workspaceAddr); | ||
| 415 | + | ||
| 416 | + bool passed = (maxDiff <= 2) && (maxScaleDiff < 1e-2f); | ||
| 417 | + LOG_PRINT("Test 2 %s (max_y_diff=%d, max_scale_diff=%f)\n", passed ? "PASSED" : "FAILED", maxDiff, maxScaleDiff); | ||
| 418 | + return passed ? 0 : 1; | ||
| 419 | +} | ||
| 420 | + | ||
| 421 | +int main() | ||
| 422 | +{ | ||
| 423 | + LOG_PRINT("=== DequantSituQuant Precision Test ===\n"); | ||
| 424 | + | ||
| 425 | + int32_t deviceId = 0; | ||
| 426 | + aclrtStream stream; | ||
| 427 | + auto ret = aclInit(nullptr); | ||
| 428 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); | ||
| 429 | + ret = aclrtSetDevice(deviceId); | ||
| 430 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); | ||
| 431 | + ret = aclrtCreateStream(&stream); | ||
| 432 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); | ||
| 433 | + | ||
| 434 | + int ret1 = TestStaticQuantScalar(deviceId, stream); | ||
| 435 | + int ret2 = TestDynamicQuant(deviceId, stream); | ||
| 436 | + | ||
| 437 | + LOG_PRINT("\n=== Summary ===\n"); | ||
| 438 | + LOG_PRINT("Test 1 (Static Quant): %s\n", ret1 == 0 ? "PASSED" : "FAILED"); | ||
| 439 | + LOG_PRINT("Test 2 (Dynamic Quant): %s\n", ret2 == 0 ? "PASSED" : "FAILED"); | ||
| 440 | + | ||
| 441 | + aclrtDestroyStream(stream); | ||
| 442 | + aclrtResetDevice(deviceId); | ||
| 443 | + aclFinalize(); | ||
| 444 | + | ||
| 445 | + if (ret1 == 0 && ret2 == 0) { | ||
| 446 | + LOG_PRINT("\nAll tests PASSED!\n"); | ||
| 447 | + } else { | ||
| 448 | + LOG_PRINT("\nSome tests FAILED!\n"); | ||
| 449 | + } | ||
| 450 | + return (ret1 == 0 && ret2 == 0) ? 0 : 1; | ||
| 451 | +} | ||
| @@ -0,0 +1,11 @@ | |||
| 1 | +# ---------------------------------------------------------------------------- | ||
| 2 | +# Copyright (c) 2025 Huawei Technologies Co., Ltd. | ||
| 3 | +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | +# CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | +# Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | +# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | +# See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | +# ---------------------------------------------------------------------------- | ||
| 10 | + | ||
| 11 | +add_graph_plugin_sources() | ||
| @@ -0,0 +1,76 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2025 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +/*! | ||
| 12 | + * \file dequant_situ_quant_proto.h | ||
| 13 | + * \brief | ||
| 14 | + */ | ||
| 15 | +#ifndef OPS_QUANT_DEQUANT_SITU_QUANT_PROTO_H_ | ||
| 16 | +#define OPS_QUANT_DEQUANT_SITU_QUANT_PROTO_H_ | ||
| 17 | +#include "graph/operator_reg.h" | ||
| 18 | + | ||
| 19 | +namespace ge { | ||
| 20 | + | ||
| 21 | +/** | ||
| 22 | +* @brief Combine Dequant + Situ + Quant. | ||
| 23 | + | ||
| 24 | +* @par Inputs: | ||
| 25 | +* Seven inputs: | ||
| 26 | +* @li x: Required tensor. INT8 for per-channel dequant path; INT32 for MoE grouped-matmul accumulator; | ||
| 27 | +* BF16 for pre-dequantized path; FLOAT16 for pre-dequantized path. Shape is (N..., H) for INT8 | ||
| 28 | +* (dim > 1, H even) or [rows, width] for INT32/BF16/FLOAT16. | ||
| 29 | +* @li weight_scale: Optional FP32. Per-channel or per-expert dequantization scale. Required for INT32 x. | ||
| 30 | +* @li activation_scale: Optional FP32. Per-row dequantization scale (one value per row). Required for INT32 x. | ||
| 31 | +* @li bias: Optional FP32. Dequantization bias, same shape as weight_scale. | ||
| 32 | +* @li quant_scale: Optional FP32. Static quant scale or dynamic smooth scale. | ||
| 33 | +* @li quant_offset: Optional FP32. Static quant offset. | ||
| 34 | +* @li group_index: Optional INT64 [experts]. Per-expert consecutive routed row counts for MoE. | ||
| 35 | + | ||
| 36 | +* @par Outputs: | ||
| 37 | +* @li y: INT8 tensor. Last dim is x last dim / 2. | ||
| 38 | +* @li y_scale: FP32 tensor. Per-row dynamic quant scale (meaningless for static mode). | ||
| 39 | + | ||
| 40 | +* @par Attributes: | ||
| 41 | +* @li beta: Float. The beta parameter for Situ activation. Default is 4.0. | ||
| 42 | +* @li linear_beta: Float. The linear_beta parameter for Situ activation. When value <= 0, the linear_beta | ||
| 43 | +* transformation is not applied. Default is 25.0. | ||
| 44 | +* @li activate_left: Bool. Whether gate is the left half (true) or right half (false). Default is true. | ||
| 45 | +* @li quant_type: String. The quant type to use: 'static' or 'dynamic', default is 'dynamic'. | ||
| 46 | + | ||
| 47 | +* @attention Constraints: | ||
| 48 | +* @li The last dimension of x must be even. | ||
| 49 | +* @li INT8 path: weight_scale required, activation_scale/group_index must be absent, x dim > 1. | ||
| 50 | +* @li INT32 path: weight_scale and activation_scale required, quant_scale/quant_offset must be absent, | ||
| 51 | +* x rank == 2, quant_type must be dynamic. | ||
| 52 | +* @li BF16 path: weight_scale/activation_scale/bias/group_index must be absent, x rank == 2, | ||
| 53 | +* quant_type must be dynamic. | ||
| 54 | +* @li FLOAT16 path: weight_scale/activation_scale/bias/group_index must be absent, x rank == 2, | ||
| 55 | +* quant_type must be dynamic. | ||
| 56 | +* @li When quant_type is 'static', quant_scale must be provided. | ||
| 57 | +* @li When quant_type is 'dynamic', quant_scale is optional (used as smoothScale). | ||
| 58 | +*/ | ||
| 59 | +REG_OP(DequantSituQuant) | ||
| 60 | + .INPUT(x, TensorType({DT_INT8, DT_INT32, DT_BF16, DT_FLOAT16})) | ||
| 61 | + .OPTIONAL_INPUT(weight_scale, TensorType({DT_FLOAT, DT_FLOAT, DT_FLOAT, DT_FLOAT})) | ||
| 62 | + .OPTIONAL_INPUT(activation_scale, TensorType({DT_FLOAT, DT_FLOAT, DT_FLOAT, DT_FLOAT})) | ||
| 63 | + .OPTIONAL_INPUT(bias, TensorType({DT_FLOAT, DT_FLOAT, DT_FLOAT, DT_FLOAT})) | ||
| 64 | + .OPTIONAL_INPUT(quant_scale, TensorType({DT_FLOAT, DT_FLOAT, DT_FLOAT, DT_FLOAT})) | ||
| 65 | + .OPTIONAL_INPUT(quant_offset, TensorType({DT_FLOAT, DT_FLOAT, DT_FLOAT, DT_FLOAT})) | ||
| 66 | + .OPTIONAL_INPUT(group_index, TensorType({DT_INT64, DT_INT64, DT_INT64, DT_INT64})) | ||
| 67 | + .OUTPUT(y, TensorType({DT_INT8, DT_INT8, DT_INT8, DT_INT8})) | ||
| 68 | + .OUTPUT(y_scale, TensorType({DT_FLOAT, DT_FLOAT, DT_FLOAT, DT_FLOAT})) | ||
| 69 | + .ATTR(beta, Float, 4.0) | ||
| 70 | + .ATTR(linear_beta, Float, 25.0) | ||
| 71 | + .ATTR(activate_left, Bool, true) | ||
| 72 | + .ATTR(quant_type, String, "dynamic") | ||
| 73 | + .OP_END_FACTORY_REG(DequantSituQuant) | ||
| 74 | +} // namespace ge | ||
| 75 | + | ||
| 76 | +#endif // OPS_QUANT_DEQUANT_SITU_QUANT_PROTO_H_ | ||
| @@ -0,0 +1,11 @@ | |||
| 1 | +# ---------------------------------------------------------------------------- | ||
| 2 | +# Copyright (c) 2025 Huawei Technologies Co., Ltd. | ||
| 3 | +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | +# CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | +# Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | +# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | +# See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | +# ---------------------------------------------------------------------------- | ||
| 10 | + | ||
| 11 | +add_modules_sources(HOSTNAME ${OPHOST_NAME} MODE PRIVATE DIR ${CMAKE_CURRENT_SOURCE_DIR} OPTYPE dequant_situ_quant ACLNNTYPE aclnn) | ||
| @@ -0,0 +1,81 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2025 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +/*! | ||
| 12 | + * \file dequant_situ_quant_def.cpp | ||
| 13 | + * \brief | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | +#include <cstdint> | ||
| 17 | +#include "register/op_def_registry.h" | ||
| 18 | + | ||
| 19 | +namespace ops { | ||
| 20 | +class DequantSituQuant : public OpDef { | ||
| 21 | +public: | ||
| 22 | + explicit DequantSituQuant(const char* name) : OpDef(name) | ||
| 23 | + { | ||
| 24 | + this->Input("x") | ||
| 25 | + .ParamType(REQUIRED) | ||
| 26 | + .DataType({ge::DT_INT8, ge::DT_INT32, ge::DT_BF16, ge::DT_FLOAT16}) | ||
| 27 | + .Format({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND}) | ||
| 28 | + .UnknownShapeFormat({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND}); | ||
| 29 | + this->Input("weight_scale") | ||
| 30 | + .ParamType(OPTIONAL) | ||
| 31 | + .DataType({ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT}) | ||
| 32 | + .Format({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND}) | ||
| 33 | + .UnknownShapeFormat({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND}); | ||
| 34 | + this->Input("activation_scale") | ||
| 35 | + .ParamType(OPTIONAL) | ||
| 36 | + .DataType({ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT}) | ||
| 37 | + .Format({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND}) | ||
| 38 | + .UnknownShapeFormat({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND}); | ||
| 39 | + this->Input("bias") | ||
| 40 | + .ParamType(OPTIONAL) | ||
| 41 | + .DataType({ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT}) | ||
| 42 | + .Format({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND}) | ||
| 43 | + .UnknownShapeFormat({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND}); | ||
| 44 | + this->Input("quant_scale") | ||
| 45 | + .ParamType(OPTIONAL) | ||
| 46 | + .DataType({ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT}) | ||
| 47 | + .Format({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND}) | ||
| 48 | + .UnknownShapeFormat({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND}); | ||
| 49 | + this->Input("quant_offset") | ||
| 50 | + .ParamType(OPTIONAL) | ||
| 51 | + .DataType({ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT}) | ||
| 52 | + .Format({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND}) | ||
| 53 | + .UnknownShapeFormat({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND}); | ||
| 54 | + this->Input("group_index") | ||
| 55 | + .ParamType(OPTIONAL) | ||
| 56 | + .DataType({ge::DT_INT64, ge::DT_INT64, ge::DT_INT64, ge::DT_INT64}) | ||
| 57 | + .Format({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND}) | ||
| 58 | + .UnknownShapeFormat({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND}); | ||
| 59 | + this->Output("y") | ||
| 60 | + .ParamType(REQUIRED) | ||
| 61 | + .DataType({ge::DT_INT8, ge::DT_INT8, ge::DT_INT8, ge::DT_INT8}) | ||
| 62 | + .Format({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND}) | ||
| 63 | + .UnknownShapeFormat({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND}); | ||
| 64 | + this->Output("y_scale") | ||
| 65 | + .ParamType(REQUIRED) | ||
| 66 | + .DataType({ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT, ge::DT_FLOAT}) | ||
| 67 | + .Format({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND}) | ||
| 68 | + .UnknownShapeFormat({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND}); | ||
| 69 | + | ||
| 70 | + this->Attr("beta").AttrType(OPTIONAL).Float(4.0); | ||
| 71 | + this->Attr("linear_beta").AttrType(OPTIONAL).Float(25.0); | ||
| 72 | + this->Attr("activate_left").AttrType(OPTIONAL).Bool(true); | ||
| 73 | + this->Attr("quant_type").AttrType(OPTIONAL).String("dynamic"); | ||
| 74 | + | ||
| 75 | + this->AICore().AddConfig("ascend910b"); | ||
| 76 | + this->AICore().AddConfig("ascend910_93"); | ||
| 77 | + } | ||
| 78 | +}; | ||
| 79 | + | ||
| 80 | +OP_ADD(DequantSituQuant); | ||
| 81 | +} // namespace ops | ||
| @@ -0,0 +1,90 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2025 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +/*! | ||
| 12 | + * \file dequant_situ_quant_infershape.cpp | ||
| 13 | + * \brief | ||
| 14 | + */ | ||
| 15 | +#include "register/op_impl_registry.h" | ||
| 16 | +#include "graph/utils/type_utils.h" | ||
| 17 | +#include "util/shape_util.h" | ||
| 18 | +#include "log/log.h" | ||
| 19 | +#include "util/math_util.h" | ||
| 20 | + | ||
| 21 | +using namespace ge; | ||
| 22 | +namespace ops { | ||
| 23 | +constexpr size_t INPUT_IDX_X = 0; | ||
| 24 | +constexpr size_t OUTPUT_IDX_Y = 0; | ||
| 25 | +constexpr size_t OUTPUT_IDX_Y_SCALE = 1; | ||
| 26 | +constexpr int64_t CONST_UNKNOW_SHAPE = -1; | ||
| 27 | +constexpr int64_t NUM_TWO = 2; | ||
| 28 | + | ||
| 29 | +graphStatus InferShape4DequantSituQuant(gert::InferShapeContext* context) | ||
| 30 | +{ | ||
| 31 | + OP_LOGD(context, "Begin to do InferShape4DequantSituQuant."); | ||
| 32 | + | ||
| 33 | + const gert::Shape* xShape = context->GetInputShape(INPUT_IDX_X); | ||
| 34 | + OP_CHECK_NULL_WITH_CONTEXT(context, xShape); | ||
| 35 | + gert::Shape* yShape = context->GetOutputShape(OUTPUT_IDX_Y); | ||
| 36 | + OP_CHECK_NULL_WITH_CONTEXT(context, yShape); | ||
| 37 | + gert::Shape* yScaleShape = context->GetOutputShape(OUTPUT_IDX_Y_SCALE); | ||
| 38 | + OP_CHECK_NULL_WITH_CONTEXT(context, yScaleShape); | ||
| 39 | + | ||
| 40 | + *yShape = *xShape; | ||
| 41 | + OP_CHECK_IF(Ops::Base::IsUnknownRank(*xShape), | ||
| 42 | + OP_LOGD(context, "End to do InferShape4DequantSituQuant, inputx is [-2]."), return GRAPH_SUCCESS); | ||
| 43 | + | ||
| 44 | + int64_t xShapeRank = static_cast<int64_t>(xShape->GetDimNum()); | ||
| 45 | + | ||
| 46 | + auto inputDesc = context->GetInputDesc(INPUT_IDX_X); | ||
| 47 | + OP_CHECK_NULL_WITH_CONTEXT(context, inputDesc); | ||
| 48 | + ge::DataType xDataType = inputDesc->GetDataType(); | ||
| 49 | + | ||
| 50 | + bool isInt8 = (xDataType == ge::DT_INT8); | ||
| 51 | + if (isInt8) { | ||
| 52 | + OP_CHECK_IF(xShapeRank <= 1, OP_LOGE(context, "x shape rank must > 1 for int8, but is %ld", xShapeRank), | ||
| 53 | + return ge::GRAPH_FAILED); | ||
| 54 | + } else { | ||
| 55 | + OP_CHECK_IF(xShapeRank != 2, | ||
| 56 | + OP_LOGE(context, "x shape rank must be 2 for int32/bfloat16/float16, but is %ld", xShapeRank), | ||
| 57 | + return ge::GRAPH_FAILED); | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + int64_t lastDim = xShape->GetDim(xShapeRank - 1); | ||
| 61 | + int64_t outLastDim = lastDim == CONST_UNKNOW_SHAPE ? CONST_UNKNOW_SHAPE : lastDim / NUM_TWO; | ||
| 62 | + OP_CHECK_IF((lastDim != CONST_UNKNOW_SHAPE) && (lastDim % NUM_TWO != 0), | ||
| 63 | + OP_LOGE(context, "The last dim of x must be even number, but is %ld", lastDim), | ||
| 64 | + return ge::GRAPH_FAILED); | ||
| 65 | + | ||
| 66 | + yShape->SetDim(xShapeRank - 1, outLastDim); | ||
| 67 | + | ||
| 68 | + *yScaleShape = *yShape; | ||
| 69 | + if (isInt8) { | ||
| 70 | + yScaleShape->SetDimNum(xShapeRank - 1); | ||
| 71 | + } else { | ||
| 72 | + yScaleShape->SetDimNum(1); | ||
| 73 | + yScaleShape->SetDim(0, xShape->GetDim(0)); | ||
| 74 | + } | ||
| 75 | + | ||
| 76 | + OP_LOGD(context, "End to do InferShape4DequantSituQuant"); | ||
| 77 | + return GRAPH_SUCCESS; | ||
| 78 | +} | ||
| 79 | + | ||
| 80 | +graphStatus InferDtype4DequantSituQuant(gert::InferDataTypeContext* context) | ||
| 81 | +{ | ||
| 82 | + OP_LOGD(context, "InferDtype4DequantSituQuant enter"); | ||
| 83 | + context->SetOutputDataType(OUTPUT_IDX_Y, DT_INT8); | ||
| 84 | + context->SetOutputDataType(OUTPUT_IDX_Y_SCALE, DT_FLOAT); | ||
| 85 | + OP_LOGD(context, "InferDtype4DequantSituQuant end"); | ||
| 86 | + return GRAPH_SUCCESS; | ||
| 87 | +} | ||
| 88 | + | ||
| 89 | +IMPL_OP_INFERSHAPE(DequantSituQuant).InferShape(InferShape4DequantSituQuant).InferDataType(InferDtype4DequantSituQuant); | ||
| 90 | +} // namespace ops | ||
| @@ -0,0 +1,686 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2025 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +/*! | ||
| 12 | + * \file dequant_situ_quant_tiling.cpp | ||
| 13 | + * \brief | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | +#include <cmath> | ||
| 17 | +#include <cstdint> | ||
| 18 | +#include <algorithm> | ||
| 19 | +#include <limits> | ||
| 20 | +#include <string> | ||
| 21 | +#include "tiling/tiling_api.h" | ||
| 22 | +#include "dequant_situ_quant_tiling.h" | ||
| 23 | +#include "op_host/tiling_util.h" | ||
| 24 | +#include "op_host/tiling_templates_registry.h" | ||
| 25 | + | ||
| 26 | +#define CHECK_FAIL(cont, cond, ...) \ | ||
| 27 | + do { \ | ||
| 28 | + if (cond) { \ | ||
| 29 | + OP_LOGE(cont->GetNodeName(), ##__VA_ARGS__); \ | ||
| 30 | + return ge::GRAPH_FAILED; \ | ||
| 31 | + } \ | ||
| 32 | + } while (0) | ||
| 33 | + | ||
| 34 | +namespace optiling { | ||
| 35 | +using Ops::NN::Optiling::TilingBaseClass; | ||
| 36 | +using Ops::NN::Optiling::TilingRegistry; | ||
| 37 | + | ||
| 38 | +constexpr uint32_t UB_RESERVED_BUFF = 1024; | ||
| 39 | +constexpr uint32_t ALIGN_UINT_IN_CACHE_32B = 32; | ||
| 40 | +constexpr uint32_t PACK_UINT_IN_CACHE_512B = 512; | ||
| 41 | +constexpr uint32_t DEFAULT_BUFFER_NUM = 2; | ||
| 42 | +constexpr uint32_t MAX_CORE_NUMBER = 64; | ||
| 43 | +constexpr uint32_t PERFORMANCE_COL_LEN = 1536; | ||
| 44 | +constexpr uint32_t PERFORMANCE_ROW_LEN = 128; | ||
| 45 | +constexpr uint32_t MIN_CORE = 12; | ||
| 46 | +constexpr uint64_t USER_WORKSPACE = 16777216; // 16 * 1024 * 1024 | ||
| 47 | +constexpr uint64_t BLOCK_BYTES = 32; | ||
| 48 | + | ||
| 49 | +constexpr size_t INDEX_IN_X = 0; | ||
| 50 | +constexpr size_t INDEX_IN_WEIGHT_SCALE = 1; | ||
| 51 | +constexpr size_t INDEX_IN_ACTIVATION_SCALE = 2; | ||
| 52 | +constexpr size_t INDEX_IN_BIAS = 3; | ||
| 53 | +constexpr size_t INDEX_IN_QUANT_SCALE = 4; | ||
| 54 | +constexpr size_t INDEX_IN_QUANT_OFFSET = 5; | ||
| 55 | +constexpr size_t INDEX_IN_GROUP_INDEX = 6; | ||
| 56 | +constexpr int64_t NUM_TWO = 2; | ||
| 57 | +constexpr int64_t QUANT_TYPE_STATIC = 0; | ||
| 58 | +constexpr int64_t QUANT_TYPE_DYNAMIC = 1; | ||
| 59 | + | ||
| 60 | +void DequantSituQuantTiling::Reset() | ||
| 61 | +{ | ||
| 62 | + opName = nullptr; | ||
| 63 | + totalCore = 0; | ||
| 64 | + totalUsedCoreNum = 0; | ||
| 65 | + inputDTypeLen = 1; | ||
| 66 | + ubMinBlockLen = 32; | ||
| 67 | + cacheLineLen = 512; | ||
| 68 | + maxTileLen = 0; | ||
| 69 | + optBaseRowLen = 0; | ||
| 70 | + optBaseColLen = 0; | ||
| 71 | + workspaceSize_ = 0; | ||
| 72 | + hasDequantBias = false; | ||
| 73 | + hasQuantScale = false; | ||
| 74 | + hasQuantOffset = false; | ||
| 75 | + quantIsOne = false; | ||
| 76 | + activateLeft = 0; | ||
| 77 | + quantType = 0; | ||
| 78 | + beta = 4.0f; | ||
| 79 | + linearBeta = 25.0f; | ||
| 80 | + quantScaleShapeSize = 0; | ||
| 81 | + inDimx = 0; | ||
| 82 | + inDimy = 0; | ||
| 83 | + outDimy = 0; | ||
| 84 | + xDtype_ = ge::DT_INT8; | ||
| 85 | + isPreDequantized_ = false; | ||
| 86 | + hasWeightScale_ = false; | ||
| 87 | + hasActivationScale_ = false; | ||
| 88 | + hasGroupIndex_ = false; | ||
| 89 | + expertNum_ = 1; | ||
| 90 | +} | ||
| 91 | + | ||
| 92 | +bool DequantSituQuantTiling::IsCapable() | ||
| 93 | +{ | ||
| 94 | + if (Ops::NN::OpTiling::IsRegbaseSocVersion(context_)) { | ||
| 95 | + return false; | ||
| 96 | + } | ||
| 97 | + return true; | ||
| 98 | +} | ||
| 99 | + | ||
| 100 | +ge::graphStatus DequantSituQuantTiling::GetPlatformInfo() | ||
| @@ -0,0 +1,150 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2025 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +/*! | ||
| 12 | + * \file dequant_situ_quant_tiling.h | ||
| 13 | + * \brief | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | +#ifndef DEQUANT_SITU_QUANT_TILING_H | ||
| 17 | +#define DEQUANT_SITU_QUANT_TILING_H | ||
| 18 | + | ||
| 19 | +#include <vector> | ||
| 20 | +#include <iostream> | ||
| 21 | +#include "register/op_impl_registry.h" | ||
| 22 | +#include "util/math_util.h" | ||
| 23 | +#include "log/log.h" | ||
| 24 | +#include "tiling/platform/platform_ascendc.h" | ||
| 25 | +#include "platform/platform_infos_def.h" | ||
| 26 | +#include "register/tilingdata_base.h" | ||
| 27 | +#include "tiling/tiling_api.h" | ||
| 28 | +#include "../op_graph/dequant_situ_quant_proto.h" | ||
| 29 | +#include "op_host/tiling_base.h" | ||
| 30 | +#include "op_host/tiling_templates_registry.h" | ||
| 31 | + | ||
| 32 | +using namespace Ops::NN::Optiling; | ||
| 33 | +namespace optiling { | ||
| 34 | + | ||
| 35 | +BEGIN_TILING_DATA_DEF(DequantSituQuantTilingData) | ||
| 36 | +TILING_DATA_FIELD_DEF(uint32_t, is32BAligned); | ||
| 37 | +TILING_DATA_FIELD_DEF(uint32_t, isDoubleBuffer); | ||
| 38 | +TILING_DATA_FIELD_DEF(uint64_t, rowLen); | ||
| 39 | +TILING_DATA_FIELD_DEF(uint64_t, colLen); | ||
| 40 | +TILING_DATA_FIELD_DEF(uint32_t, baseRowLen); | ||
| 41 | +TILING_DATA_FIELD_DEF(uint32_t, baseColLen); | ||
| 42 | +TILING_DATA_FIELD_DEF(uint32_t, activateLeft); | ||
| 43 | +TILING_DATA_FIELD_DEF(uint32_t, dequantBiasIsEmpty); | ||
| 44 | +TILING_DATA_FIELD_DEF(uint32_t, quantScaleIsEmpty); | ||
| 45 | +TILING_DATA_FIELD_DEF(uint32_t, quantOffsetIsEmpty); | ||
| 46 | +TILING_DATA_FIELD_DEF(uint32_t, quantIsOne); | ||
| 47 | +TILING_DATA_FIELD_DEF(uint32_t, usedCoreNum); | ||
| 48 | +TILING_DATA_FIELD_DEF(int64_t, quantType); | ||
| 49 | +TILING_DATA_FIELD_DEF(float, beta); | ||
| 50 | +TILING_DATA_FIELD_DEF(float, linearBeta); | ||
| 51 | +TILING_DATA_FIELD_DEF(uint32_t, expertNum); | ||
| 52 | +TILING_DATA_FIELD_DEF(uint32_t, hasGroupIndex); | ||
| 53 | +TILING_DATA_FIELD_DEF(uint32_t, hasActivationScale); | ||
| 54 | +TILING_DATA_FIELD_DEF(uint32_t, isPreDequantized); | ||
| 55 | +TILING_DATA_FIELD_DEF(uint32_t, inputWidth); | ||
| 56 | +TILING_DATA_FIELD_DEF(uint32_t, outputWidth); | ||
| 57 | +END_TILING_DATA_DEF; | ||
| 58 | + | ||
| 59 | +REGISTER_TILING_DATA_CLASS(DequantSituQuant, DequantSituQuantTilingData) | ||
| 60 | + | ||
| 61 | +struct DequantSituQuantCompileInfo { | ||
| 62 | + uint64_t coreNum = 0; | ||
| 63 | + uint64_t ubSize = 0; | ||
| 64 | +}; | ||
| 65 | + | ||
| 66 | +constexpr int64_t DSQ_STATIC_QUANT_ONE = 10000; | ||
| 67 | +constexpr int64_t DSQ_STATIC_QUANT_VEC = 10001; | ||
| 68 | +constexpr int64_t DSQ_STATIC_QUANT_ONE_BIAS = 10002; | ||
| 69 | +constexpr int64_t DSQ_STATIC_QUANT_VEC_BIAS = 10003; | ||
| 70 | +constexpr int64_t DSQ_DYNAMIC_QUANT_NO_SMOOTH = 20000; | ||
| 71 | +constexpr int64_t DSQ_DYNAMIC_QUANT_SMOOTH = 20001; | ||
| 72 | +constexpr int64_t DSQ_DYNAMIC_QUANT_NO_SMOOTH_BIAS = 20002; | ||
| 73 | +constexpr int64_t DSQ_DYNAMIC_QUANT_SMOOTH_BIAS = 20003; | ||
| 74 | +constexpr int64_t DSQ_INT32_DYNAMIC = 30000; | ||
| 75 | +constexpr int64_t DSQ_BF16_DYNAMIC = 40000; | ||
| 76 | +constexpr int64_t DSQ_FP16_DYNAMIC = 50000; | ||
| 77 | + | ||
| 78 | +class DequantSituQuantTiling : public Ops::NN::Optiling::TilingBaseClass { | ||
| 79 | +public: | ||
| 80 | + explicit DequantSituQuantTiling(gert::TilingContext* cont) : TilingBaseClass(cont) { Reset(); } | ||
| 81 | + ~DequantSituQuantTiling() override = default; | ||
| 82 | + | ||
| 83 | + void Reset(gert::TilingContext* cont) override | ||
| 84 | + { | ||
| 85 | + TilingBaseClass::Reset(cont); | ||
| 86 | + Reset(); | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | +protected: | ||
| 90 | + bool IsCapable() override; | ||
| 91 | + ge::graphStatus GetPlatformInfo() override; | ||
| 92 | + ge::graphStatus GetShapeAttrsInfo() override; | ||
| 93 | + ge::graphStatus DoOpTiling() override; | ||
| 94 | + ge::graphStatus DoLibApiTiling() override; | ||
| 95 | + uint64_t GetTilingKey() const override; | ||
| 96 | + ge::graphStatus GetWorkspaceSize() override; | ||
| 97 | + ge::graphStatus PostTiling() override; | ||
| 98 | + void Reset(); | ||
| 99 | + | ||
| 100 | +private: | ||
| 101 | + void ShowTilingData(); | ||
| 102 | + ge::graphStatus GetShapeAttrsInfoInner(); | ||
| 103 | + ge::graphStatus CheckInputShapes(); | ||
| 104 | + ge::graphStatus CheckInputShapesInt8(int64_t dimNum, int64_t inDimy, int64_t outDimy); | ||
| 105 | + ge::graphStatus CheckInputShapesInt32(int64_t inDimy, int64_t outDimy); | ||
| 106 | + ge::graphStatus CheckInputShapesBF16(); | ||
| 107 | + bool SetAttrs(const gert::RuntimeAttrs* attrs); | ||
| 108 | + bool CalcTiling(const uint32_t totalCores, const uint64_t ubSize); | ||
| 109 | + bool CalcUbMaxTileLen(const uint64_t ubSize, uint32_t& maxTileLen); | ||
| 110 | + bool CalcOptBaseShape(uint32_t maxTileLen); | ||
| 111 | + ge::graphStatus ValidateInt32Contract(); | ||
| 112 | + | ||
| 113 | + const char* opName = ""; | ||
| 114 | + uint32_t totalCore = 0; | ||
| 115 | + uint32_t totalUsedCoreNum = 0; | ||
| 116 | + uint32_t inputDTypeLen = 1; | ||
| 117 | + uint32_t ubMinBlockLen = 32; | ||
| 118 | + uint32_t cacheLineLen = 512; | ||
| 119 | + uint32_t maxTileLen = 0; | ||
| 120 | + uint32_t optBaseRowLen = 0; | ||
| 121 | + uint32_t optBaseColLen = 0; | ||
| 122 | + uint64_t workspaceSize_ = 0; | ||
| 123 | + | ||
| 124 | + bool hasDequantBias = false; | ||
| 125 | + bool hasQuantScale = false; | ||
| 126 | + bool hasQuantOffset = false; | ||
| 127 | + bool quantIsOne = false; | ||
| 128 | + uint32_t activateLeft = 0; | ||
| 129 | + int64_t quantType = 0; | ||
| 130 | + float beta = 4.0f; | ||
| 131 | + float linearBeta = 25.0f; | ||
| 132 | + uint64_t quantScaleShapeSize = 0; | ||
| 133 | + | ||
| 134 | + int64_t inDimx = 0; | ||
| 135 | + int64_t inDimy = 0; | ||
| 136 | + int64_t outDimy = 0; | ||
| 137 | + | ||
| 138 | + ge::DataType xDtype_ = ge::DT_INT8; | ||
| 139 | + bool isPreDequantized_ = false; | ||
| 140 | + bool hasWeightScale_ = false; | ||
| 141 | + bool hasActivationScale_ = false; | ||
| 142 | + bool hasGroupIndex_ = false; | ||
| 143 | + uint32_t expertNum_ = 1; | ||
| 144 | + | ||
| 145 | + DequantSituQuantTilingData tilingData; | ||
| 146 | + platform_ascendc::SocVersion socVersion = platform_ascendc::SocVersion::ASCEND910B; | ||
| 147 | +}; | ||
| 148 | + | ||
| 149 | +} // namespace optiling | ||
| 150 | +#endif // DEQUANT_SITU_QUANT_TILING_H | ||
| @@ -0,0 +1,113 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2025 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +/*! | ||
| 12 | + * \file dequant_situ_quant.cpp | ||
| 13 | + * \brief Kernel entry point for DequantSituQuant operator. | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | +#include "kernel_operator.h" | ||
| 17 | +#include "kernel_tiling/kernel_tiling.h" | ||
| 18 | +#include "dequant_situ_quant.h" | ||
| 19 | + | ||
| 20 | +using namespace AscendC; | ||
| 21 | + | ||
| 22 | +#define DSQ_STATIC_QUANT_ONE 10000 | ||
| 23 | +#define DSQ_STATIC_QUANT_VEC 10001 | ||
| 24 | +#define DSQ_STATIC_QUANT_ONE_BIAS 10002 | ||
| 25 | +#define DSQ_STATIC_QUANT_VEC_BIAS 10003 | ||
| 26 | +#define DSQ_DYNAMIC_QUANT_NO_SMOOTH 20000 | ||
| 27 | +#define DSQ_DYNAMIC_QUANT_SMOOTH 20001 | ||
| 28 | +#define DSQ_DYNAMIC_QUANT_NO_SMOOTH_BIAS 20002 | ||
| 29 | +#define DSQ_DYNAMIC_QUANT_SMOOTH_BIAS 20003 | ||
| 30 | +#define DSQ_INT32_DYNAMIC 30000 | ||
| 31 | +#define DSQ_BF16_DYNAMIC 40000 | ||
| 32 | +#define DSQ_FP16_DYNAMIC 50000 | ||
| 33 | + | ||
| 34 | +extern "C" __global__ __aicore__ void dequant_situ_quant(GM_ADDR xGM, GM_ADDR weightScaleGM, GM_ADDR activationScaleGM, | ||
| 35 | + GM_ADDR biasGM, GM_ADDR quantScaleGM, GM_ADDR quantOffsetGM, | ||
| 36 | + GM_ADDR groupIndexGM, GM_ADDR yGM, GM_ADDR yScaleGM, | ||
| 37 | + GM_ADDR workspace, GM_ADDR tiling) | ||
| 38 | +{ | ||
| 39 | +#if (ORIG_DTYPE_X == DT_INT8) | ||
| 40 | + if (workspace == nullptr) { | ||
| 41 | + return; | ||
| 42 | + } | ||
| 43 | + GM_ADDR userspace = GetUserWorkspace(workspace); | ||
| 44 | + if (userspace == nullptr) { | ||
| 45 | + return; | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + TPipe pipe; | ||
| 49 | + GET_TILING_DATA_WITH_STRUCT(DequantSituQuantTilingData, tilingDataIn, tiling); | ||
| 50 | + const DequantSituQuantTilingData* __restrict__ tilingData = &tilingDataIn; | ||
| 51 | + | ||
| 52 | + if (TILING_KEY_IS(DSQ_STATIC_QUANT_ONE)) { | ||
| 53 | + DequantSituQuantOps::DequantSituQuantKernel<false> op(&pipe); | ||
| 54 | + op.Init(xGM, weightScaleGM, biasGM, quantScaleGM, quantOffsetGM, yGM, yScaleGM, userspace, tilingData); | ||
| 55 | + op.Process(); | ||
| 56 | + } else if (TILING_KEY_IS(DSQ_STATIC_QUANT_VEC)) { | ||
| 57 | + DequantSituQuantOps::DequantSituQuantKernel<false> op(&pipe); | ||
| 58 | + op.Init(xGM, weightScaleGM, biasGM, quantScaleGM, quantOffsetGM, yGM, yScaleGM, userspace, tilingData); | ||
| 59 | + op.Process(); | ||
| 60 | + } else if (TILING_KEY_IS(DSQ_STATIC_QUANT_ONE_BIAS)) { | ||
| 61 | + DequantSituQuantOps::DequantSituQuantKernel<true> op(&pipe); | ||
| 62 | + op.Init(xGM, weightScaleGM, biasGM, quantScaleGM, quantOffsetGM, yGM, yScaleGM, userspace, tilingData); | ||
| 63 | + op.Process(); | ||
| 64 | + } else if (TILING_KEY_IS(DSQ_STATIC_QUANT_VEC_BIAS)) { | ||
| 65 | + DequantSituQuantOps::DequantSituQuantKernel<true> op(&pipe); | ||
| 66 | + op.Init(xGM, weightScaleGM, biasGM, quantScaleGM, quantOffsetGM, yGM, yScaleGM, userspace, tilingData); | ||
| 67 | + op.Process(); | ||
| 68 | + } else if (TILING_KEY_IS(DSQ_DYNAMIC_QUANT_NO_SMOOTH)) { | ||
| 69 | + DequantSituQuantOps::DequantSituQuantKernel<false> op(&pipe); | ||
| 70 | + op.Init(xGM, weightScaleGM, biasGM, quantScaleGM, quantOffsetGM, yGM, yScaleGM, userspace, tilingData); | ||
| 71 | + op.Process(); | ||
| 72 | + } else if (TILING_KEY_IS(DSQ_DYNAMIC_QUANT_SMOOTH)) { | ||
| 73 | + DequantSituQuantOps::DequantSituQuantKernel<false> op(&pipe); | ||
| 74 | + op.Init(xGM, weightScaleGM, biasGM, quantScaleGM, quantOffsetGM, yGM, yScaleGM, userspace, tilingData); | ||
| 75 | + op.Process(); | ||
| 76 | + } else if (TILING_KEY_IS(DSQ_DYNAMIC_QUANT_NO_SMOOTH_BIAS)) { | ||
| 77 | + DequantSituQuantOps::DequantSituQuantKernel<true> op(&pipe); | ||
| 78 | + op.Init(xGM, weightScaleGM, biasGM, quantScaleGM, quantOffsetGM, yGM, yScaleGM, userspace, tilingData); | ||
| 79 | + op.Process(); | ||
| 80 | + } else if (TILING_KEY_IS(DSQ_DYNAMIC_QUANT_SMOOTH_BIAS)) { | ||
| 81 | + DequantSituQuantOps::DequantSituQuantKernel<true> op(&pipe); | ||
| 82 | + op.Init(xGM, weightScaleGM, biasGM, quantScaleGM, quantOffsetGM, yGM, yScaleGM, userspace, tilingData); | ||
| 83 | + op.Process(); | ||
| 84 | + } | ||
| 85 | +#elif (ORIG_DTYPE_X == DT_INT32) | ||
| 86 | + if (TILING_KEY_IS(DSQ_INT32_DYNAMIC)) { | ||
| 87 | + TPipe pipe; | ||
| 88 | + GET_TILING_DATA_WITH_STRUCT(DequantSituQuantTilingData, tilingDataIn, tiling); | ||
| 89 | + const DequantSituQuantTilingData* __restrict__ tilingData = &tilingDataIn; | ||
| 90 | + DequantSituQuantOps::DequantSituQuantK3Kernel<int32_t> op(&pipe); | ||
| 91 | + op.Init(xGM, weightScaleGM, activationScaleGM, biasGM, groupIndexGM, yGM, yScaleGM, tilingData); | ||
| 92 | + op.Process(); | ||
| 93 | + } | ||
| 94 | +#elif (ORIG_DTYPE_X == DT_BF16) | ||
| 95 | + if (TILING_KEY_IS(DSQ_BF16_DYNAMIC)) { | ||
| 96 | + TPipe pipe; | ||
| 97 | + GET_TILING_DATA_WITH_STRUCT(DequantSituQuantTilingData, tilingDataIn, tiling); | ||
| 98 | + const DequantSituQuantTilingData* __restrict__ tilingData = &tilingDataIn; | ||
| 99 | + DequantSituQuantOps::DequantSituQuantK3Kernel<bfloat16_t> op(&pipe); | ||
| 100 | + op.Init(xGM, weightScaleGM, activationScaleGM, biasGM, groupIndexGM, yGM, yScaleGM, tilingData); | ||
| 101 | + op.Process(); | ||
| 102 | + } | ||
| 103 | +#elif (ORIG_DTYPE_X == DT_FLOAT16) | ||
| 104 | + if (TILING_KEY_IS(DSQ_FP16_DYNAMIC)) { | ||
| 105 | + TPipe pipe; | ||
| 106 | + GET_TILING_DATA_WITH_STRUCT(DequantSituQuantTilingData, tilingDataIn, tiling); | ||
| 107 | + const DequantSituQuantTilingData* __restrict__ tilingData = &tilingDataIn; | ||
| 108 | + DequantSituQuantOps::DequantSituQuantK3Kernel<half> op(&pipe); | ||
| 109 | + op.Init(xGM, weightScaleGM, activationScaleGM, biasGM, groupIndexGM, yGM, yScaleGM, tilingData); | ||
| 110 | + op.Process(); | ||
| 111 | + } | ||
| 112 | +#endif | ||
| 113 | +} | ||
| @@ -0,0 +1,18 @@ | |||
| 1 | +# ---------------------------------------------------------------------------- | ||
| 2 | +# Copyright (c) 2025 Huawei Technologies Co., Ltd. | ||
| 3 | +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | +# CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | +# Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | +# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | +# See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | +# ---------------------------------------------------------------------------- | ||
| 10 | + | ||
| 11 | +file(GLOB CURRENT_DIRS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*) | ||
| 12 | +if(ENABLE_TEST) | ||
| 13 | + foreach(SUB_DIR ${CURRENT_DIRS}) | ||
| 14 | + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SUB_DIR}/CMakeLists.txt") | ||
| 15 | + add_subdirectory(${SUB_DIR}) | ||
| 16 | + endif() | ||
| 17 | + endforeach() | ||
| 18 | +endif() | ||
| @@ -0,0 +1,16 @@ | |||
| 1 | +# ---------------------------------------------------------------------------- | ||
| 2 | +# Copyright (c) 2025 Huawei Technologies Co., Ltd. | ||
| 3 | +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | +# CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | +# Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | +# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | +# See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | +# ---------------------------------------------------------------------------- | ||
| 10 | + | ||
| 11 | +file(GLOB CURRENT_DIRS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*) | ||
| 12 | +foreach(SUB_DIR ${CURRENT_DIRS}) | ||
| 13 | + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SUB_DIR}/CMakeLists.txt") | ||
| 14 | + add_subdirectory(${SUB_DIR}) | ||
| 15 | + endif() | ||
| 16 | +endforeach() | ||
| @@ -0,0 +1,19 @@ | |||
| 1 | +# ---------------------------------------------------------------------------- | ||
| 2 | +# Copyright (c) 2025 Huawei Technologies Co., Ltd. | ||
| 3 | +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | +# CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | +# Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | +# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | +# See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | +# ---------------------------------------------------------------------------- | ||
| 10 | + | ||
| 11 | +file(GLOB CURRENT_DIRS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*) | ||
| 12 | +if(UT_TEST_ALL OR OP_HOST_UT) | ||
| 13 | + add_modules_ut_sources(HOSTNAME ${OP_TILING_MODULE_NAME} MODE PRIVATE DIR ${CMAKE_CURRENT_SOURCE_DIR}) | ||
| 14 | + add_modules_ut_sources(HOSTNAME ${OP_INFERSHAPE_MODULE_NAME} MODE PRIVATE DIR ${CMAKE_CURRENT_SOURCE_DIR}) | ||
| 15 | +endif() | ||
| 16 | + | ||
| 17 | +if(UT_TEST_ALL OR OP_API_UT) | ||
| 18 | + add_modules_ut_sources(HOSTNAME ${OP_API_MODULE_NAME} MODE PRIVATE DIR ${CMAKE_CURRENT_SOURCE_DIR}) | ||
| 19 | +endif() | ||