| @@ -4,7 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | |产品 | 是否支持 | | 5 | |产品 | 是否支持 | |
| 6 | |:-------------------------|:----------:| | 6 | |:-------------------------|:----------:| |
| 7 | -| <term>Ascend 950PR/Ascend 950DT</term> | x | | 7 | +| <term>Ascend 950PR/Ascend 950DT</term> | √ | |
| 8 | | <term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term> | √ | | 8 | | <term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term> | √ | |
| 9 | | <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term> | √ | | 9 | | <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term> | √ | |
| 10 | | <term>Atlas 200I/500 A2 推理产品</term> | × | | 10 | | <term>Atlas 200I/500 A2 推理产品</term> | × | |
| @@ -6,7 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | |产品 | 是否支持 | | 7 | |产品 | 是否支持 | |
| 8 | |:-------------------------|:----------:| | 8 | |:-------------------------|:----------:| |
| 9 | -| <term>Ascend 950PR/Ascend 950DT</term> | x | | 9 | +| <term>Ascend 950PR/Ascend 950DT</term> | √ | |
| 10 | | <term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term> | √ | | 10 | | <term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term> | √ | |
| 11 | | <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term> | √ | | 11 | | <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term> | √ | |
| 12 | | <term>Atlas 200I/500 A2 推理产品</term> | × | | 12 | | <term>Atlas 200I/500 A2 推理产品</term> | × | |
| @@ -164,7 +164,7 @@ aclnnStatus aclnnApplyAdamWQuant( | |||
| 164 | <td class="tg-0pky">absmaxMRef(aclTensor*)</td> | 164 | <td class="tg-0pky">absmaxMRef(aclTensor*)</td> |
| 165 | <td class="tg-0pky">输入/输出</td> | 165 | <td class="tg-0pky">输入/输出</td> |
| 166 | <td class="tg-0pky">每blockSize(256)个vRef对应一个最大值,用于对mRef索引选择qmapM中的值乘以对应的absmaxMRef进行反量化。再通过更新后的mRef每blockSize(256)个选择出一个最大值,作为absmaxMRef的输出。</td> | 166 | <td class="tg-0pky">每blockSize(256)个vRef对应一个最大值,用于对mRef索引选择qmapM中的值乘以对应的absmaxMRef进行反量化。再通过更新后的mRef每blockSize(256)个选择出一个最大值,作为absmaxMRef的输出。</td> |
| 167 | - <td class="tg-0pky">shape要求为“absmaxMRef.size = mRef.size/blockSize”。</td> | 167 | + <td class="tg-0pky">shape要求为“absmaxMRef.size = ceil(mRef.size/blockSize)”。</td> |
| 168 | <td class="tg-0pky">FLOAT32</td> | 168 | <td class="tg-0pky">FLOAT32</td> |
| 169 | <td class="tg-0pky">ND</td> | 169 | <td class="tg-0pky">ND</td> |
| 170 | <td class="tg-0pky">1</td> | 170 | <td class="tg-0pky">1</td> |
| @@ -174,7 +174,7 @@ aclnnStatus aclnnApplyAdamWQuant( | |||
| 174 | <td class="tg-0pky">absmaxVRef(aclTensor*)</td> | 174 | <td class="tg-0pky">absmaxVRef(aclTensor*)</td> |
| 175 | <td class="tg-0pky">输入/输出</td> | 175 | <td class="tg-0pky">输入/输出</td> |
| 176 | <td class="tg-0pky">每blockSize(256)个vRef对应一个最大值,用于对vRef索引选择qmapV中的值乘以对应的absmaxVRef进行反量化。再通过更新后的vRef每blockSize(256)个选择出一个最大值,作为absmaxVRef的输出。</td> | 176 | <td class="tg-0pky">每blockSize(256)个vRef对应一个最大值,用于对vRef索引选择qmapV中的值乘以对应的absmaxVRef进行反量化。再通过更新后的vRef每blockSize(256)个选择出一个最大值,作为absmaxVRef的输出。</td> |
| 177 | - <td class="tg-0pky">shape要求为“absmaxVRef.size = vRef.size/blockSize”。</td> | 177 | + <td class="tg-0pky">shape要求为“absmaxVRef.size = ceil(vRef.size/blockSize)”。</td> |
| 178 | <td class="tg-0pky">FLOAT32</td> | 178 | <td class="tg-0pky">FLOAT32</td> |
| 179 | <td class="tg-0pky">ND</td> | 179 | <td class="tg-0pky">ND</td> |
| 180 | <td class="tg-0pky">1</td> | 180 | <td class="tg-0pky">1</td> |
| @@ -373,8 +373,8 @@ aclnnStatus aclnnApplyAdamWQuant( | |||
| 373 | - varRef.shape = grad.shape | 373 | - varRef.shape = grad.shape |
| 374 | - varRef.shape = mRef.shape | 374 | - varRef.shape = mRef.shape |
| 375 | - varRef.shape = vRef.shape | 375 | - varRef.shape = vRef.shape |
| 376 | - - varRef.size/blockSize = absmaxMRef.size | 376 | + - ceil(varRef.size/blockSize) = absmaxMRef.size |
| 377 | - - varRef.size/blockSize = absmaxVRef.size | 377 | + - ceil(varRef.size/blockSize) = absmaxVRef.size |
| 378 | 378 | ||
| 379 | 确定性计算: | 379 | 确定性计算: |
| 380 | 380 | ||
| @@ -1,12 +1,15 @@ | |||
| 1 | # ---------------------------------------------------------------------------- | 1 | # ---------------------------------------------------------------------------- |
| 2 | -# Copyright (c) 2025 Huawei Technologies Co., Ltd. | 2 | +# Copyright (c) 2025-2026 Huawei Technologies Co., Ltd. |
| 3 | -# This program is free software, you can redistribute it and/or modify it under the terms and conditions of | 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"). | 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. | 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, | 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. | 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. | 8 | # See LICENSE in the root of the software repository for the full text of the License. |
| 9 | # ---------------------------------------------------------------------------- | 9 | # ---------------------------------------------------------------------------- |
| 10 | -message(STATUS "=== Debug: start ops.optim.apply_adam_w_quant.op_host.CMakeLists.txt ") | 10 | +set(SUPPORT_COMPUTE_UNIT "ascend910b" "ascend910_93" "ascend950") |
| 11 | - | 11 | +# 910b/910_93 走 arch22 通用 tiling,950 走 arch35 regbase tiling。 |
| 12 | -add_modules_sources(HOSTNAME ${OPHOST_NAME} MODE PRIVATE DIR ${CMAKE_CURRENT_SOURCE_DIR} OPTYPE apply_adam_w_quant ACLNNTYPE aclnn) | 12 | +set(SUPPORT_TILING_DIR "arch22" "arch22" "arch35") |
| 13 | +add_modules_sources(HOSTNAME ${OPHOST_NAME} MODE PRIVATE DIR ${CMAKE_CURRENT_SOURCE_DIR} | ||
| 14 | + OPTYPE apply_adam_w_quant ACLNNTYPE aclnn | ||
| 15 | + COMPUTE_UNIT ${SUPPORT_COMPUTE_UNIT} TILING_DIR ${SUPPORT_TILING_DIR}) | ||
| @@ -1,5 +1,5 @@ | |||
| 1 | /** | 1 | /** |
| 2 | - * Copyright (c) 2025 Huawei Technologies Co., Ltd. | 2 | + * Copyright (c) 2025-2026 Huawei Technologies Co., Ltd. |
| 3 | * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | 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"). | 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. | 5 | * Please refer to the License for details. You may not use this file except in compliance with the License. |
| @@ -116,6 +116,20 @@ public: | |||
| 116 | this->Attr("block_size").AttrType(OPTIONAL).Int(BLOCKSIZE); | 116 | this->Attr("block_size").AttrType(OPTIONAL).Int(BLOCKSIZE); |
| 117 | this->AICore().AddConfig("ascend910b"); | 117 | this->AICore().AddConfig("ascend910b"); |
| 118 | this->AICore().AddConfig("ascend910_93"); | 118 | this->AICore().AddConfig("ascend910_93"); |
| 119 | + | ||
| 120 | + // arch35(Ascend950)regbase 出包配置:契约与 A2 完全一致(9 入/5 出、fp32/fp16/bf16), | ||
| 121 | + // 仅走 regbase 编译路径;opFile/opInterface 名与 A2 相同,由 op_kernel CMake 的 | ||
| 122 | + // COMPUTE_UNITS 路由区分根 kernel(A2)与 arch35/ kernel(A5)。 | ||
| 123 | + OpAICoreConfig aicoreConfig950; | ||
| 124 | + aicoreConfig950.DynamicCompileStaticFlag(true) | ||
| 125 | + .DynamicFormatFlag(false) | ||
| 126 | + .DynamicRankSupportFlag(true) | ||
| 127 | + .DynamicShapeSupportFlag(true) | ||
| 128 | + .NeedCheckSupportFlag(false) | ||
| 129 | + .PrecisionReduceFlag(true) | ||
| 130 | + .ExtendCfgInfo("opFile.value", "apply_adam_w_quant") | ||
| 131 | + .ExtendCfgInfo("opInterface.value", "apply_adam_w_quant"); | ||
| 132 | + this->AICore().AddConfig("ascend950", aicoreConfig950); | ||
| 119 | } | 133 | } |
| 120 | }; | 134 | }; |
| 121 | 135 | ||
| @@ -304,4 +304,4 @@ static ge::graphStatus TilingPrepare4ApplyAdamWQuant(gert::TilingParseContext* c | |||
| 304 | IMPL_OP_OPTILING(ApplyAdamWQuant) | 304 | IMPL_OP_OPTILING(ApplyAdamWQuant) |
| 305 | .Tiling(Tiling4ApplyAdamWQuant) | 305 | .Tiling(Tiling4ApplyAdamWQuant) |
| 306 | .TilingParse<Tiling4ApplyAdamWQuantCompileInfo>(TilingPrepare4ApplyAdamWQuant); | 306 | .TilingParse<Tiling4ApplyAdamWQuantCompileInfo>(TilingPrepare4ApplyAdamWQuant); |
| 307 | -} // namespace optiling | 307 | +} // namespace optiling |
| @@ -0,0 +1,352 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 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 | + * NOTE: Portions of this code were AI-generated and have been | ||
| 11 | + * technically reviewed for functional accuracy and security | ||
| 12 | + */ | ||
| 13 | + | ||
| 14 | +/*! | ||
| 15 | + * \file apply_adam_w_quant_tiling_arch35.cpp | ||
| 16 | + * \brief ApplyAdamWQuant regbase (Ascend950) tiling implementation. | ||
| 17 | + * | ||
| 18 | + * 与 A2 tiling 完全同算法(blockwise-256 分核 + UB 切分),仅出包路径不同:regbase 走 | ||
| 19 | + * RawTilingData 直写裸 buffer。核数/UB 由 PlatformAscendC 运行时取(arch35 自适应)。 | ||
| 20 | + */ | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + | ||
| 30 | + | ||
| 31 | + | ||
| 32 | +using namespace ge; | ||
| 33 | + | ||
| 34 | +namespace optiling { | ||
| 35 | +namespace { | ||
| 36 | +constexpr size_t INDEX_IN_VAR = 0; | ||
| 37 | +constexpr size_t INDEX_IN_GRAD = 1; | ||
| 38 | +constexpr size_t INDEX_IN_M = 2; | ||
| 39 | +constexpr size_t INDEX_IN_V = 3; | ||
| 40 | +constexpr size_t INDEX_IN_QMAP_M = 4; | ||
| 41 | +constexpr size_t INDEX_IN_QMAP_V = 5; | ||
| 42 | +constexpr size_t INDEX_IN_ABSMAX_M = 6; | ||
| 43 | +constexpr size_t INDEX_IN_ABSMAX_V = 7; | ||
| 44 | +constexpr size_t INDEX_IN_STEP = 8; | ||
| 45 | + | ||
| 46 | +constexpr size_t INDEX_ATTR_LR = 0; | ||
| 47 | +constexpr size_t INDEX_ATTR_BETA1 = 1; | ||
| 48 | +constexpr size_t INDEX_ATTR_BETA2 = 2; | ||
| 49 | +constexpr size_t INDEX_ATTR_WEIGHT_DECAY = 3; | ||
| 50 | +constexpr size_t INDEX_ATTR_EPS = 4; | ||
| 51 | +constexpr size_t INDEX_ATTR_GNORM_SCALE = 5; | ||
| 52 | +constexpr size_t INDEX_ATTR_BLOCK_SIZE = 7; | ||
| 53 | + | ||
| 54 | +constexpr uint64_t TILINGKEY_DATA_VAR_FLOAT = 100; | ||
| 55 | +constexpr uint64_t TILINGKEY_DATA_VAR_FLOAT16 = 200; | ||
| 56 | +constexpr uint64_t TILINGKEY_DATA_VAR_BFLOAT16 = 300; | ||
| 57 | +constexpr uint64_t QMAP_SIZE = 256; | ||
| 58 | +constexpr uint64_t SIZE_OF_FLOAT = 4; | ||
| 59 | +constexpr uint64_t SIZE_OF_FLOAT16 = 2; | ||
| 60 | +constexpr uint64_t PER_BLOCK_OF_MAX_NUM = 1; | ||
| 61 | +constexpr uint64_t ONE_BLOCK_NEED_BUF = 10; | ||
| 62 | +constexpr uint64_t NUM_OF_QMAP = 2; | ||
| 63 | +constexpr int64_t BLOCKSIZE = 256; | ||
| 64 | + | ||
| 65 | +inline uint64_t CeilDiv(uint64_t a, uint64_t b) { return (b == 0 ? 0 : ((a + b - 1) / b)); } | ||
| 66 | + | ||
| 67 | +inline bool IsSameShape(const gert::Shape& shape1, const gert::Shape& shape2) | ||
| 68 | +{ | ||
| 69 | + size_t dimNum = shape1.GetDimNum(); | ||
| 70 | + if (shape2.GetDimNum() != dimNum) { | ||
| 71 | + return false; | ||
| 72 | + } | ||
| 73 | + for (size_t i = 0; i < dimNum; ++i) { | ||
| 74 | + if (shape1.GetDim(i) != shape2.GetDim(i)) { | ||
| 75 | + return false; | ||
| 76 | + } | ||
| 77 | + } | ||
| 78 | + return true; | ||
| 79 | +} | ||
| 80 | +} // namespace | ||
| 81 | + | ||
| 82 | +ge::graphStatus ApplyAdamWQuantRegbaseTiling::GetAttributes() | ||
| 83 | +{ | ||
| 84 | + auto* attrs = tilingContext_->GetAttrs(); | ||
| 85 | + OP_CHECK_NULL_WITH_CONTEXT(tilingContext_, attrs); | ||
| 86 | + | ||
| 87 | + auto* attrLr = attrs->GetAttrPointer<float>(INDEX_ATTR_LR); | ||
| 88 | + OP_CHECK_NULL_WITH_CONTEXT(tilingContext_, attrLr); | ||
| 89 | + lr_ = *attrLr; | ||
| 90 | + | ||
| 91 | + auto* attrBeta1 = attrs->GetAttrPointer<float>(INDEX_ATTR_BETA1); | ||
| 92 | + OP_CHECK_NULL_WITH_CONTEXT(tilingContext_, attrBeta1); | ||
| 93 | + beta1_ = *attrBeta1; | ||
| 94 | + | ||
| 95 | + auto* attrBeta2 = attrs->GetAttrPointer<float>(INDEX_ATTR_BETA2); | ||
| 96 | + OP_CHECK_NULL_WITH_CONTEXT(tilingContext_, attrBeta2); | ||
| 97 | + beta2_ = *attrBeta2; | ||
| 98 | + | ||
| 99 | + auto* attrWeightDecay = attrs->GetAttrPointer<float>(INDEX_ATTR_WEIGHT_DECAY); | ||
| 100 | + OP_CHECK_NULL_WITH_CONTEXT(tilingContext_, attrWeightDecay); | ||
| 101 | + weightDecay_ = *attrWeightDecay; | ||
| 102 | + | ||
| 103 | + auto* attrEps = attrs->GetAttrPointer<float>(INDEX_ATTR_EPS); | ||
| 104 | + OP_CHECK_NULL_WITH_CONTEXT(tilingContext_, attrEps); | ||
| 105 | + eps_ = *attrEps; | ||
| 106 | + | ||
| 107 | + auto* attrGnormScale = attrs->GetAttrPointer<float>(INDEX_ATTR_GNORM_SCALE); | ||
| 108 | + OP_CHECK_NULL_WITH_CONTEXT(tilingContext_, attrGnormScale); | ||
| 109 | + gnormScale_ = *attrGnormScale; | ||
| 110 | + | ||
| 111 | + auto* attrBlockSize = attrs->GetAttrPointer<int64_t>(INDEX_ATTR_BLOCK_SIZE); | ||
| 112 | + OP_CHECK_NULL_WITH_CONTEXT(tilingContext_, attrBlockSize); | ||
| 113 | + blockSize_ = *attrBlockSize; | ||
| 114 | + OP_CHECK_IF(blockSize_ != BLOCKSIZE, | ||
| 115 | + OP_LOGE_FOR_INVALID_VALUE_WITH_REASON(tilingContext_->GetNodeName(), "parameter", "invalid", | ||
| 116 | + "attr block_size should be 256, please check."), | ||
| 117 | + return ge::GRAPH_FAILED); | ||
| 118 | + return ge::GRAPH_SUCCESS; | ||
| 119 | +} | ||
| 120 | + | ||
| 121 | +ge::graphStatus ApplyAdamWQuantRegbaseTiling::CheckInputShape() | ||
| 122 | +{ | ||
| 123 | + auto varShapePtr = tilingContext_->GetInputShape(INDEX_IN_VAR); | ||
| 124 | + OP_CHECK_NULL_WITH_CONTEXT(tilingContext_, varShapePtr); | ||
| 125 | + auto gradShapePtr = tilingContext_->GetInputShape(INDEX_IN_GRAD); | ||
| 126 | + OP_CHECK_NULL_WITH_CONTEXT(tilingContext_, gradShapePtr); | ||
| 127 | + auto mShapePtr = tilingContext_->GetInputShape(INDEX_IN_M); | ||
| 128 | + OP_CHECK_NULL_WITH_CONTEXT(tilingContext_, mShapePtr); | ||
| 129 | + auto vShapePtr = tilingContext_->GetInputShape(INDEX_IN_V); | ||
| 130 | + OP_CHECK_NULL_WITH_CONTEXT(tilingContext_, vShapePtr); | ||
| 131 | + auto qmapMShapePtr = tilingContext_->GetInputShape(INDEX_IN_QMAP_M); | ||
| 132 | + OP_CHECK_NULL_WITH_CONTEXT(tilingContext_, qmapMShapePtr); | ||
| 133 | + auto qmapVShapePtr = tilingContext_->GetInputShape(INDEX_IN_QMAP_V); | ||
| 134 | + OP_CHECK_NULL_WITH_CONTEXT(tilingContext_, qmapVShapePtr); | ||
| 135 | + auto absmaxMShapePtr = tilingContext_->GetInputShape(INDEX_IN_ABSMAX_M); | ||
| 136 | + OP_CHECK_NULL_WITH_CONTEXT(tilingContext_, absmaxMShapePtr); | ||
| 137 | + auto absmaxVShapePtr = tilingContext_->GetInputShape(INDEX_IN_ABSMAX_V); | ||
| 138 | + OP_CHECK_NULL_WITH_CONTEXT(tilingContext_, absmaxVShapePtr); | ||
| 139 | + auto stepShapePtr = tilingContext_->GetInputShape(INDEX_IN_STEP); | ||
| 140 | + OP_CHECK_NULL_WITH_CONTEXT(tilingContext_, stepShapePtr); | ||
| 141 | + | ||
| 142 | + const gert::Shape& varShape = varShapePtr->GetStorageShape(); | ||
| 143 | + const gert::Shape& gradShape = gradShapePtr->GetStorageShape(); | ||
| 144 | + const gert::Shape& mShape = mShapePtr->GetStorageShape(); | ||
| 145 | + const gert::Shape& vShape = vShapePtr->GetStorageShape(); | ||
| 146 | + const gert::Shape& qmapMShape = qmapMShapePtr->GetStorageShape(); | ||
| 147 | + const gert::Shape& qmapVShape = qmapVShapePtr->GetStorageShape(); | ||
| 148 | + const gert::Shape& absmaxMShape = absmaxMShapePtr->GetStorageShape(); | ||
| 149 | + const gert::Shape& absmaxVShape = absmaxVShapePtr->GetStorageShape(); | ||
| 150 | + const gert::Shape& stepShape = stepShapePtr->GetStorageShape(); | ||
| 151 | + | ||
| 152 | + bool isDiffShape = !IsSameShape(varShape, gradShape) || !IsSameShape(varShape, mShape) || | ||
| 153 | + !IsSameShape(varShape, vShape); | ||
| 154 | + bool isQmapDiffShape = !IsSameShape(qmapMShape, qmapVShape) || | ||
| 155 | + static_cast<uint64_t>(qmapMShape.GetShapeSize()) != QMAP_SIZE; | ||
| 156 | + uint64_t expectedAbsmaxSize = CeilDiv(static_cast<uint64_t>(varShape.GetShapeSize()), | ||
| 157 | + static_cast<uint64_t>(blockSize_)); | ||
| 158 | + bool isAbsmaxDiffShape = static_cast<uint64_t>(absmaxMShape.GetShapeSize()) != expectedAbsmaxSize || | ||
| 159 | + static_cast<uint64_t>(absmaxVShape.GetShapeSize()) != expectedAbsmaxSize; | ||
| 160 | + OP_CHECK_IF(isDiffShape, | ||
| 161 | + OP_LOGE_FOR_INVALID_VALUE_WITH_REASON(tilingContext_->GetNodeName(), "parameter", "invalid", | ||
| 162 | + "var,grad,m,v should have same shape, please check."), | ||
| 163 | + return ge::GRAPH_FAILED); | ||
| 164 | + OP_CHECK_IF( | ||
| 165 | + isQmapDiffShape, | ||
| 166 | + OP_LOGE_FOR_INVALID_VALUE_WITH_REASON(tilingContext_->GetNodeName(), "parameter", "invalid", | ||
| 167 | + "qmapM and qmapV should be same shape,shape is [256], please check."), | ||
| 168 | + return ge::GRAPH_FAILED); | ||
| 169 | + OP_CHECK_IF(isAbsmaxDiffShape, | ||
| 170 | + OP_LOGE_FOR_INVALID_VALUE_WITH_REASON( | ||
| 171 | + tilingContext_->GetNodeName(), "parameter", "invalid", | ||
| 172 | + "absmaxM and absmaxV should each contain ceil(var size / block_size) elements, please check."), | ||
| 173 | + return ge::GRAPH_FAILED); | ||
| 174 | + OP_CHECK_IF(stepShape.GetDimNum() != 1 || stepShape.GetDim(0) != 1, | ||
| 175 | + OP_LOGE_FOR_INVALID_VALUE_WITH_REASON(tilingContext_->GetNodeName(), "parameter", "invalid", | ||
| 176 | + "step should have only one element, please check."), | ||
| 177 | + return ge::GRAPH_FAILED); | ||
| 178 | + return ge::GRAPH_SUCCESS; | ||
| 179 | +} | ||
| 180 | + | ||
| 181 | +ge::graphStatus ApplyAdamWQuantRegbaseTiling::DetermineTilingKey() | ||
| 182 | +{ | ||
| 183 | + auto dtypePtr = tilingContext_->GetInputDesc(INDEX_IN_VAR); | ||
| 184 | + OP_CHECK_NULL_WITH_CONTEXT(tilingContext_, dtypePtr); | ||
| 185 | + auto dtype = dtypePtr->GetDataType(); | ||
| 186 | + if (dtype == ge::DataType::DT_FLOAT) { | ||
| 187 | + tilingKey_ = TILINGKEY_DATA_VAR_FLOAT; | ||
| 188 | + } else if (dtype == ge::DataType::DT_FLOAT16) { | ||
| 189 | + tilingKey_ = TILINGKEY_DATA_VAR_FLOAT16; | ||
| 190 | + } else if (dtype == ge::DataType::DT_BF16) { | ||
| 191 | + tilingKey_ = TILINGKEY_DATA_VAR_BFLOAT16; | ||
| 192 | + } else { | ||
| 193 | + OP_LOGE_FOR_INVALID_VALUE_WITH_REASON(tilingContext_->GetNodeName(), "parameter", "invalid", | ||
| 194 | + "var dtype should be float/float16/bfloat16, please check."); | ||
| 195 | + return ge::GRAPH_FAILED; | ||
| 196 | + } | ||
| 197 | + return ge::GRAPH_SUCCESS; | ||
| 198 | +} | ||
| 199 | + | ||
| 200 | +ge::graphStatus ApplyAdamWQuantRegbaseTiling::DoTiling() | ||
| 201 | +{ | ||
| 202 | + auto platformInfoPtr = tilingContext_->GetPlatformInfo(); | ||
| 203 | + OP_CHECK_NULL_WITH_CONTEXT(tilingContext_, platformInfoPtr); | ||
| 204 | + const auto ascendcPlatform = platform_ascendc::PlatformAscendC(platformInfoPtr); | ||
| 205 | + uint64_t aivNum = ascendcPlatform.GetCoreNumAiv(); | ||
| 206 | + OP_CHECK_IF(aivNum == 0, | ||
| 207 | + OP_LOGE_FOR_INVALID_VALUE_WITH_REASON(tilingContext_->GetNodeName(), "parameter", "invalid", | ||
| 208 | + "aivNum can not be 0, please check."), | ||
| 209 | + return ge::GRAPH_FAILED); | ||
| 210 | + uint64_t maxUbSize = 0; | ||
| 211 | + ascendcPlatform.GetCoreMemSize(platform_ascendc::CoreMemType::UB, maxUbSize); | ||
| 212 | + OP_CHECK_IF(maxUbSize == 0, | ||
| 213 | + OP_LOGE_FOR_INVALID_VALUE_WITH_REASON(tilingContext_->GetNodeName(), "parameter", "invalid", | ||
| 214 | + "ub size can not be 0, please check."), | ||
| 215 | + return ge::GRAPH_FAILED); | ||
| 216 | + | ||
| 217 | + auto shapePtr = tilingContext_->GetInputShape(INDEX_IN_VAR); | ||
| 218 | + OP_CHECK_NULL_WITH_CONTEXT(tilingContext_, shapePtr); | ||
| 219 | + | ||
| 220 | + uint64_t oneBlockSize = static_cast<uint64_t>(blockSize_) * | ||
| 221 | + (SIZE_OF_FLOAT * ONE_BLOCK_NEED_BUF + SIZE_OF_FLOAT16 + SIZE_OF_FLOAT) + | ||
| 222 | + (PER_BLOCK_OF_MAX_NUM + PER_BLOCK_OF_MAX_NUM) * SIZE_OF_FLOAT; | ||
| 223 | + OP_CHECK_IF(oneBlockSize == 0, | ||
| 224 | + OP_LOGE_FOR_INVALID_VALUE_WITH_REASON(tilingContext_->GetNodeName(), "parameter", "invalid", | ||
| 225 | + "one core max size can not be 0, please check."), | ||
| 226 | + return ge::GRAPH_FAILED); | ||
| 227 | + uint64_t reservedQmap = QMAP_SIZE * SIZE_OF_FLOAT * NUM_OF_QMAP; | ||
| 228 | + OP_CHECK_IF(maxUbSize <= reservedQmap, | ||
| 229 | + OP_LOGE_FOR_INVALID_VALUE_WITH_REASON(tilingContext_->GetNodeName(), "parameter", "invalid", | ||
| 230 | + "ub size too small for qmap, please check."), | ||
| 231 | + return ge::GRAPH_FAILED); | ||
| 232 | + perCoreDoBlockNum_ = (maxUbSize - reservedQmap) / oneBlockSize; | ||
| 233 | + OP_CHECK_IF(perCoreDoBlockNum_ == 0, | ||
| 234 | + OP_LOGE_FOR_INVALID_VALUE_WITH_REASON(tilingContext_->GetNodeName(), "parameter", "invalid", | ||
| 235 | + "one core do block num can not be 0, please check."), | ||
| 236 | + return ge::GRAPH_FAILED); | ||
| 237 | + | ||
| 238 | + uint64_t totalDataNum = static_cast<uint64_t>(shapePtr->GetStorageShape().GetShapeSize()); | ||
| 239 | + uint64_t blockNum = CeilDiv(totalDataNum, static_cast<uint64_t>(blockSize_)); | ||
| 240 | + uint64_t totalUseNumCore = CeilDiv(blockNum, perCoreDoBlockNum_); | ||
| 241 | + OP_CHECK_IF(totalUseNumCore == 0, | ||
| 242 | + OP_LOGE_FOR_INVALID_VALUE_WITH_REASON(tilingContext_->GetNodeName(), "parameter", "invalid", | ||
| 243 | + "total use num core can not be 0, please check."), | ||
| 244 | + return ge::GRAPH_FAILED); | ||
| 245 | + lastCoreLastBlock_ = blockNum - (totalUseNumCore - 1) * perCoreDoBlockNum_; | ||
| 246 | + lastBlockSize_ = totalDataNum - (blockNum - 1) * static_cast<uint64_t>(blockSize_); | ||
| 247 | + useNumCore_ = CeilDiv(totalUseNumCore, CeilDiv(totalUseNumCore, aivNum)); | ||
| 248 | + OP_CHECK_IF(useNumCore_ == 0, | ||
| 249 | + OP_LOGE_FOR_INVALID_VALUE_WITH_REASON(tilingContext_->GetNodeName(), "parameter", "invalid", | ||
| 250 | + "use_num_core can't be 0."), | ||
| 251 | + return ge::GRAPH_FAILED); | ||
| 252 | + | ||
| 253 | + lastPreCoreRowWork_ = totalUseNumCore / useNumCore_; | ||
| 254 | + notLastCoreNum_ = totalUseNumCore - lastPreCoreRowWork_ * useNumCore_; | ||
| 255 | + notLastPreCoreRowWork_ = lastPreCoreRowWork_ + 1; | ||
| 256 | + return ge::GRAPH_SUCCESS; | ||
| 257 | +} | ||
| 258 | + | ||
| 259 | +ge::graphStatus ApplyAdamWQuantRegbaseTiling::SetTilingData() | ||
| 260 | +{ | ||
| 261 | + auto* rawTilingData = tilingContext_->GetRawTilingData(); | ||
| 262 | + OP_CHECK_NULL_WITH_CONTEXT(tilingContext_, rawTilingData); | ||
| 263 | + OP_CHECK_NULL_WITH_CONTEXT(tilingContext_, rawTilingData->GetData()); | ||
| 264 | + OP_CHECK_IF(rawTilingData->GetCapacity() < sizeof(ApplyAdamWQuantRegbaseTilingData), | ||
| 265 | + OP_LOGE_FOR_INVALID_VALUE_WITH_REASON( | ||
| 266 | + tilingContext_->GetNodeName(), "parameter", "invalid", | ||
| 267 | + "tiling data capacity is less than ApplyAdamWQuantRegbaseTilingData size."), | ||
| 268 | + return ge::GRAPH_FAILED); | ||
| 269 | + | ||
| 270 | + ApplyAdamWQuantRegbaseTilingData tiling; | ||
| 271 | + tiling.use_num_core = useNumCore_; | ||
| 272 | + tiling.last_pre_core_row_work = lastPreCoreRowWork_; | ||
| 273 | + tiling.not_last_core_num = notLastCoreNum_; | ||
| 274 | + tiling.not_last_pre_core_row_work = notLastPreCoreRowWork_; | ||
| 275 | + tiling.last_core_last_block = lastCoreLastBlock_; | ||
| 276 | + tiling.lr = lr_; | ||
| 277 | + tiling.beta1 = beta1_; | ||
| 278 | + tiling.beta2 = beta2_; | ||
| 279 | + tiling.weight_decay = weightDecay_; | ||
| 280 | + tiling.eps = eps_; | ||
| 281 | + tiling.gnorm_scale = gnormScale_; | ||
| 282 | + tiling.block_size = blockSize_; | ||
| 283 | + tiling.one_core_do_block_num_per_row = perCoreDoBlockNum_; | ||
| 284 | + tiling.tiling_key = tilingKey_; | ||
| 285 | + tiling.last_block_size = lastBlockSize_; | ||
| 286 | + | ||
| 287 | + auto ret = memcpy_s(rawTilingData->GetData(), rawTilingData->GetCapacity(), &tiling, | ||
| 288 | + sizeof(ApplyAdamWQuantRegbaseTilingData)); | ||
| 289 | + OP_CHECK_IF(ret != EOK, | ||
| 290 | + OP_LOGE_FOR_INVALID_VALUE_WITH_REASON(tilingContext_->GetNodeName(), "memcpy_s", | ||
| 291 | + std::to_string(ret).c_str(), "copy tiling data failed"), | ||
| 292 | + return ge::GRAPH_FAILED); | ||
| 293 | + rawTilingData->SetDataSize(sizeof(ApplyAdamWQuantRegbaseTilingData)); | ||
| 294 | + | ||
| 295 | + tilingContext_->SetBlockDim(static_cast<uint32_t>(useNumCore_)); | ||
| 296 | + tilingContext_->SetTilingKey(tilingKey_); | ||
| 297 | + size_t* workspaces = tilingContext_->GetWorkspaceSizes(1); | ||
| 298 | + OP_CHECK_NULL_WITH_CONTEXT(tilingContext_, workspaces); | ||
| 299 | + workspaces[0] = 0U; | ||
| 300 | + return ge::GRAPH_SUCCESS; | ||
| 301 | +} | ||
| 302 | + | ||
| 303 | +ge::graphStatus ApplyAdamWQuantRegbaseTiling::RunTiling() | ||
| 304 | +{ | ||
| 305 | + OP_CHECK_IF( | ||
| 306 | + tilingContext_ == nullptr, | ||
| 307 | + OP_LOGE_FOR_INVALID_VALUE_WITH_REASON("ApplyAdamWQuant", "parameter", "invalid", "tiling context is null"), | ||
| 308 | + return ge::GRAPH_FAILED); | ||
| 309 | + OP_CHECK_IF(GetAttributes() != ge::GRAPH_SUCCESS, | ||
| 310 | + OP_LOGE_FOR_INVALID_VALUE_WITH_REASON(tilingContext_->GetNodeName(), "parameter", "invalid", | ||
| 311 | + "GetAttributes failed."), | ||
| 312 | + return ge::GRAPH_FAILED); | ||
| 313 | + OP_CHECK_IF(CheckInputShape() != ge::GRAPH_SUCCESS, | ||
| 314 | + OP_LOGE_FOR_INVALID_VALUE_WITH_REASON(tilingContext_->GetNodeName(), "parameter", "invalid", | ||
| 315 | + "input shape check failed."), | ||
| 316 | + return ge::GRAPH_FAILED); | ||
| 317 | + OP_CHECK_IF(DetermineTilingKey() != ge::GRAPH_SUCCESS, | ||
| 318 | + OP_LOGE_FOR_INVALID_VALUE_WITH_REASON(tilingContext_->GetNodeName(), "parameter", "invalid", | ||
| 319 | + "determine tiling key failed."), | ||
| 320 | + return ge::GRAPH_FAILED); | ||
| 321 | + OP_CHECK_IF(DoTiling() != ge::GRAPH_SUCCESS, | ||
| 322 | + OP_LOGE_FOR_INVALID_VALUE_WITH_REASON(tilingContext_->GetNodeName(), "parameter", "invalid", | ||
| 323 | + "DoTiling failed."), | ||
| 324 | + return ge::GRAPH_FAILED); | ||
| 325 | + return SetTilingData(); | ||
| 326 | +} | ||
| 327 | + | ||
| 328 | +ge::graphStatus Tiling4ApplyAdamWQuant(gert::TilingContext* context) | ||
| 329 | +{ | ||
| 330 | + if (context == nullptr) { | ||
| 331 | + OP_LOGE_FOR_INVALID_VALUE_WITH_REASON("Tiling4ApplyAdamWQuant", "parameter", "invalid", | ||
| 332 | + "Tiling context is null"); | ||
| 333 | + return ge::GRAPH_FAILED; | ||
| 334 | + } | ||
| 335 | + OP_LOGD(context, "Tiling4ApplyAdamWQuant running begin"); | ||
| 336 | + ApplyAdamWQuantRegbaseTiling regbaseTiling(context); | ||
| 337 | + return regbaseTiling.RunTiling(); | ||
| 338 | +} | ||
| 339 | + | ||
| 340 | +static ge::graphStatus TilingPrepare4ApplyAdamWQuant(gert::TilingParseContext* context) | ||
| 341 | +{ | ||
| 342 | + OP_LOGD(context, "TilingPrepare4ApplyAdamWQuant enter."); | ||
| 343 | + auto compileInfo = context->GetCompiledInfo<ApplyAdamWQuantRegbaseCompileInfo>(); | ||
| 344 | + OP_CHECK_NULL_WITH_CONTEXT(context, compileInfo); | ||
| 345 | + OP_LOGD(context, "TilingPrepare4ApplyAdamWQuant exit."); | ||
| 346 | + return ge::GRAPH_SUCCESS; | ||
| 347 | +} | ||
| 348 | + | ||
| 349 | +IMPL_OP_OPTILING(ApplyAdamWQuant) | ||
| 350 | + .Tiling(Tiling4ApplyAdamWQuant) | ||
| 351 | + .TilingParse<ApplyAdamWQuantRegbaseCompileInfo>(TilingPrepare4ApplyAdamWQuant); | ||
| 352 | +} // namespace optiling | ||
| @@ -0,0 +1,63 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 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 | + * NOTE: Portions of this code were AI-generated and have been | ||
| 11 | + * technically reviewed for functional accuracy and security | ||
| 12 | + */ | ||
| 13 | + | ||
| 14 | +/*! | ||
| 15 | + * \file apply_adam_w_quant_tiling_arch35.h | ||
| 16 | + * \brief ApplyAdamWQuant regbase (arch35 / Ascend950) tiling class declaration. | ||
| 17 | + */ | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | +namespace optiling { | ||
| 25 | +struct ApplyAdamWQuantRegbaseCompileInfo {}; | ||
| 26 | + | ||
| 27 | +class ApplyAdamWQuantRegbaseTiling { | ||
| 28 | +public: | ||
| 29 | + explicit ApplyAdamWQuantRegbaseTiling(gert::TilingContext* context) : tilingContext_(context) {} | ||
| 30 | + | ||
| 31 | + ge::graphStatus RunTiling(); | ||
| 32 | + | ||
| 33 | +protected: | ||
| 34 | + ge::graphStatus GetAttributes(); | ||
| 35 | + ge::graphStatus CheckInputShape(); | ||
| 36 | + ge::graphStatus DetermineTilingKey(); | ||
| 37 | + ge::graphStatus DoTiling(); | ||
| 38 | + ge::graphStatus SetTilingData(); | ||
| 39 | + | ||
| 40 | +private: | ||
| 41 | + gert::TilingContext* tilingContext_ = nullptr; | ||
| 42 | + | ||
| 43 | + // attrs | ||
| 44 | + float lr_ = 0.0f; | ||
| 45 | + float beta1_ = 0.0f; | ||
| 46 | + float beta2_ = 0.0f; | ||
| 47 | + float weightDecay_ = 0.0f; | ||
| 48 | + float eps_ = 0.0f; | ||
| 49 | + float gnormScale_ = 0.0f; | ||
| 50 | + int64_t blockSize_ = 0; | ||
| 51 | + | ||
| 52 | + // tiling result | ||
| 53 | + uint64_t tilingKey_ = 0; | ||
| 54 | + uint64_t useNumCore_ = 0; | ||
| 55 | + uint64_t lastPreCoreRowWork_ = 0; | ||
| 56 | + uint64_t notLastCoreNum_ = 0; | ||
| 57 | + uint64_t notLastPreCoreRowWork_ = 0; | ||
| 58 | + uint64_t lastCoreLastBlock_ = 0; | ||
| 59 | + uint64_t lastBlockSize_ = 0; | ||
| 60 | + uint64_t perCoreDoBlockNum_ = 0; | ||
| 61 | +}; | ||
| 62 | +} // namespace optiling | ||
| 63 | + | ||
| @@ -0,0 +1,572 @@ | |||
| 1 | +{ | ||
| 2 | + "op_type": "ApplyAdamWQuant", | ||
| 3 | + "op_list": [ | ||
| 4 | + { | ||
| 5 | + "bin_filename": "ApplyAdamWQuant_d9384f4e", | ||
| 6 | + "inputs": [ | ||
| 7 | + { | ||
| 8 | + "name": "var", | ||
| 9 | + "index": 0, | ||
| 10 | + "dtype": "float32", | ||
| 11 | + "format": "ND", | ||
| 12 | + "paramType": "required", | ||
| 13 | + "shape": [ | ||
| 14 | + -2 | ||
| 15 | + ] | ||
| 16 | + }, | ||
| 17 | + { | ||
| 18 | + "name": "grad", | ||
| 19 | + "index": 1, | ||
| 20 | + "dtype": "float32", | ||
| 21 | + "format": "ND", | ||
| 22 | + "paramType": "required", | ||
| 23 | + "shape": [ | ||
| 24 | + -2 | ||
| 25 | + ] | ||
| 26 | + }, | ||
| 27 | + { | ||
| 28 | + "name": "m", | ||
| 29 | + "index": 2, | ||
| 30 | + "dtype": "uint8", | ||
| 31 | + "format": "ND", | ||
| 32 | + "paramType": "required", | ||
| 33 | + "shape": [ | ||
| 34 | + -2 | ||
| 35 | + ] | ||
| 36 | + }, | ||
| 37 | + { | ||
| 38 | + "name": "v", | ||
| 39 | + "index": 3, | ||
| 40 | + "dtype": "uint8", | ||
| 41 | + "format": "ND", | ||
| 42 | + "paramType": "required", | ||
| 43 | + "shape": [ | ||
| 44 | + -2 | ||
| 45 | + ] | ||
| 46 | + }, | ||
| 47 | + { | ||
| 48 | + "name": "qmap_m", | ||
| 49 | + "index": 4, | ||
| 50 | + "dtype": "float32", | ||
| 51 | + "format": "ND", | ||
| 52 | + "paramType": "required", | ||
| 53 | + "shape": [ | ||
| 54 | + -2 | ||
| 55 | + ] | ||
| 56 | + }, | ||
| 57 | + { | ||
| 58 | + "name": "qmap_v", | ||
| 59 | + "index": 5, | ||
| 60 | + "dtype": "float32", | ||
| 61 | + "format": "ND", | ||
| 62 | + "paramType": "required", | ||
| 63 | + "shape": [ | ||
| 64 | + -2 | ||
| 65 | + ] | ||
| 66 | + }, | ||
| 67 | + { | ||
| 68 | + "name": "absmax_m", | ||
| 69 | + "index": 6, | ||
| 70 | + "dtype": "float32", | ||
| 71 | + "format": "ND", | ||
| 72 | + "paramType": "required", | ||
| 73 | + "shape": [ | ||
| 74 | + -2 | ||
| 75 | + ] | ||
| 76 | + }, | ||
| 77 | + { | ||
| 78 | + "name": "absmax_v", | ||
| 79 | + "index": 7, | ||
| 80 | + "dtype": "float32", | ||
| 81 | + "format": "ND", | ||
| 82 | + "paramType": "required", | ||
| 83 | + "shape": [ | ||
| 84 | + -2 | ||
| 85 | + ] | ||
| 86 | + }, | ||
| 87 | + { | ||
| 88 | + "name": "step", | ||
| 89 | + "index": 8, | ||
| 90 | + "dtype": "int64", | ||
| 91 | + "format": "ND", | ||
| 92 | + "paramType": "required", | ||
| 93 | + "shape": [ | ||
| 94 | + -2 | ||
| 95 | + ] | ||
| 96 | + } | ||
| 97 | + ], | ||
| 98 | + "outputs": [ | ||
| 99 | + { | ||
| 100 | + "name": "var", | ||
| 101 | + "index": 0, | ||
| 102 | + "dtype": "float32", | ||
| 103 | + "format": "ND", | ||
| 104 | + "paramType": "required", | ||
| 105 | + "shape": [ | ||
| 106 | + -2 | ||
| 107 | + ] | ||
| 108 | + }, | ||
| 109 | + { | ||
| 110 | + "name": "m", | ||
| 111 | + "index": 1, | ||
| 112 | + "dtype": "uint8", | ||
| 113 | + "format": "ND", | ||
| 114 | + "paramType": "required", | ||
| 115 | + "shape": [ | ||
| 116 | + -2 | ||
| 117 | + ] | ||
| 118 | + }, | ||
| 119 | + { | ||
| 120 | + "name": "v", | ||
| 121 | + "index": 2, | ||
| 122 | + "dtype": "uint8", | ||
| 123 | + "format": "ND", | ||
| 124 | + "paramType": "required", | ||
| 125 | + "shape": [ | ||
| 126 | + -2 | ||
| 127 | + ] | ||
| 128 | + }, | ||
| 129 | + { | ||
| 130 | + "name": "absmax_m", | ||
| 131 | + "index": 3, | ||
| 132 | + "dtype": "float32", | ||
| 133 | + "format": "ND", | ||
| 134 | + "paramType": "required", | ||
| 135 | + "shape": [ | ||
| 136 | + -2 | ||
| 137 | + ] | ||
| 138 | + }, | ||
| 139 | + { | ||
| 140 | + "name": "absmax_v", | ||
| 141 | + "index": 4, | ||
| 142 | + "dtype": "float32", | ||
| 143 | + "format": "ND", | ||
| 144 | + "paramType": "required", | ||
| 145 | + "shape": [ | ||
| 146 | + -2 | ||
| 147 | + ] | ||
| 148 | + } | ||
| 149 | + ], | ||
| 150 | + "attrs": [ | ||
| 151 | + { | ||
| 152 | + "name": "lr", | ||
| 153 | + "dtype": "float", | ||
| 154 | + "value": 0.1 | ||
| 155 | + }, | ||
| 156 | + { | ||
| 157 | + "name": "beta1", | ||
| 158 | + "dtype": "float", | ||
| 159 | + "value": 0.1 | ||
| 160 | + }, | ||
| 161 | + { | ||
| 162 | + "name": "beta2", | ||
| 163 | + "dtype": "float", | ||
| 164 | + "value": 0.1 | ||
| 165 | + }, | ||
| 166 | + { | ||
| 167 | + "name": "weight_decay", | ||
| 168 | + "dtype": "float", | ||
| 169 | + "value": 0.1 | ||
| 170 | + }, | ||
| 171 | + { | ||
| 172 | + "name": "eps", | ||
| 173 | + "dtype": "float", | ||
| 174 | + "value": 0.1 | ||
| 175 | + }, | ||
| 176 | + { | ||
| 177 | + "name": "gnorm_scale", | ||
| 178 | + "dtype": "float", | ||
| 179 | + "value": 0.1 | ||
| 180 | + }, | ||
| 181 | + { | ||
| 182 | + "name": "quant_mode", | ||
| 183 | + "dtype": "string", | ||
| 184 | + "value": null | ||
| 185 | + }, | ||
| 186 | + { | ||
| 187 | + "name": "block_size", | ||
| 188 | + "dtype": "int64", | ||
| 189 | + "value": 256 | ||
| 190 | + } | ||
| 191 | + ] | ||
| 192 | + }, | ||
| 193 | + { | ||
| 194 | + "bin_filename": "ApplyAdamWQuant_896fb64e", | ||
| 195 | + "inputs": [ | ||
| 196 | + { | ||
| 197 | + "name": "var", | ||
| 198 | + "index": 0, | ||
| 199 | + "dtype": "float16", | ||
| 200 | + "format": "ND", | ||
| 201 | + "paramType": "required", | ||
| 202 | + "shape": [ | ||
| 203 | + -2 | ||
| 204 | + ] | ||
| 205 | + }, | ||
| 206 | + { | ||
| 207 | + "name": "grad", | ||
| 208 | + "index": 1, | ||
| 209 | + "dtype": "float16", | ||
| 210 | + "format": "ND", | ||
| 211 | + "paramType": "required", | ||
| 212 | + "shape": [ | ||
| 213 | + -2 | ||
| 214 | + ] | ||
| 215 | + }, | ||
| 216 | + { | ||
| 217 | + "name": "m", | ||
| 218 | + "index": 2, | ||
| 219 | + "dtype": "uint8", | ||
| 220 | + "format": "ND", | ||
| 221 | + "paramType": "required", | ||
| 222 | + "shape": [ | ||
| 223 | + -2 | ||
| 224 | + ] | ||
| 225 | + }, | ||
| 226 | + { | ||
| 227 | + "name": "v", | ||
| 228 | + "index": 3, | ||
| 229 | + "dtype": "uint8", | ||
| 230 | + "format": "ND", | ||
| 231 | + "paramType": "required", | ||
| 232 | + "shape": [ | ||
| 233 | + -2 | ||
| 234 | + ] | ||
| 235 | + }, | ||
| 236 | + { | ||
| 237 | + "name": "qmap_m", | ||
| 238 | + "index": 4, | ||
| 239 | + "dtype": "float32", | ||
| 240 | + "format": "ND", | ||
| 241 | + "paramType": "required", | ||
| 242 | + "shape": [ | ||
| 243 | + -2 | ||
| 244 | + ] | ||
| 245 | + }, | ||
| 246 | + { | ||
| 247 | + "name": "qmap_v", | ||
| 248 | + "index": 5, | ||
| 249 | + "dtype": "float32", | ||
| 250 | + "format": "ND", | ||
| 251 | + "paramType": "required", | ||
| 252 | + "shape": [ | ||
| 253 | + -2 | ||
| 254 | + ] | ||
| 255 | + }, | ||
| 256 | + { | ||
| 257 | + "name": "absmax_m", | ||
| 258 | + "index": 6, | ||
| 259 | + "dtype": "float32", | ||
| 260 | + "format": "ND", | ||
| 261 | + "paramType": "required", | ||
| 262 | + "shape": [ | ||
| 263 | + -2 | ||
| 264 | + ] | ||
| 265 | + }, | ||
| 266 | + { | ||
| 267 | + "name": "absmax_v", | ||
| 268 | + "index": 7, | ||
| 269 | + "dtype": "float32", | ||
| 270 | + "format": "ND", | ||
| 271 | + "paramType": "required", | ||
| 272 | + "shape": [ | ||
| 273 | + -2 | ||
| 274 | + ] | ||
| 275 | + }, | ||
| 276 | + { | ||
| 277 | + "name": "step", | ||
| 278 | + "index": 8, | ||
| 279 | + "dtype": "int64", | ||
| 280 | + "format": "ND", | ||
| 281 | + "paramType": "required", | ||
| 282 | + "shape": [ | ||
| 283 | + -2 | ||
| 284 | + ] | ||
| 285 | + } | ||
| 286 | + ], | ||
| 287 | + "outputs": [ | ||
| 288 | + { | ||
| 289 | + "name": "var", | ||
| 290 | + "index": 0, | ||
| 291 | + "dtype": "float16", | ||
| 292 | + "format": "ND", | ||
| 293 | + "paramType": "required", | ||
| 294 | + "shape": [ | ||
| 295 | + -2 | ||
| 296 | + ] | ||
| 297 | + }, | ||
| 298 | + { | ||
| 299 | + "name": "m", | ||
| 300 | + "index": 1, | ||
| 301 | + "dtype": "uint8", | ||
| 302 | + "format": "ND", | ||
| 303 | + "paramType": "required", | ||
| 304 | + "shape": [ | ||
| 305 | + -2 | ||
| 306 | + ] | ||
| 307 | + }, | ||
| 308 | + { | ||
| 309 | + "name": "v", | ||
| 310 | + "index": 2, | ||
| 311 | + "dtype": "uint8", | ||
| 312 | + "format": "ND", | ||
| 313 | + "paramType": "required", | ||
| 314 | + "shape": [ | ||
| 315 | + -2 | ||
| 316 | + ] | ||
| 317 | + }, | ||
| 318 | + { | ||
| 319 | + "name": "absmax_m", | ||
| 320 | + "index": 3, | ||
| 321 | + "dtype": "float32", | ||
| 322 | + "format": "ND", | ||
| 323 | + "paramType": "required", | ||
| 324 | + "shape": [ | ||
| 325 | + -2 | ||
| 326 | + ] | ||
| 327 | + }, | ||
| 328 | + { | ||
| 329 | + "name": "absmax_v", | ||
| 330 | + "index": 4, | ||
| 331 | + "dtype": "float32", | ||
| 332 | + "format": "ND", | ||
| 333 | + "paramType": "required", | ||
| 334 | + "shape": [ | ||
| 335 | + -2 | ||
| 336 | + ] | ||
| 337 | + } | ||
| 338 | + ], | ||
| 339 | + "attrs": [ | ||
| 340 | + { | ||
| 341 | + "name": "lr", | ||
| 342 | + "dtype": "float", | ||
| 343 | + "value": 0.1 | ||
| 344 | + }, | ||
| 345 | + { | ||
| 346 | + "name": "beta1", | ||
| 347 | + "dtype": "float", | ||
| 348 | + "value": 0.1 | ||
| 349 | + }, | ||
| 350 | + { | ||
| 351 | + "name": "beta2", | ||
| 352 | + "dtype": "float", | ||
| 353 | + "value": 0.1 | ||
| 354 | + }, | ||
| 355 | + { | ||
| 356 | + "name": "weight_decay", | ||
| 357 | + "dtype": "float", | ||
| 358 | + "value": 0.1 | ||
| 359 | + }, | ||
| 360 | + { | ||
| 361 | + "name": "eps", | ||
| 362 | + "dtype": "float", | ||
| 363 | + "value": 0.1 | ||
| 364 | + }, | ||
| 365 | + { | ||
| 366 | + "name": "gnorm_scale", | ||
| 367 | + "dtype": "float", | ||
| 368 | + "value": 0.1 | ||
| 369 | + }, | ||
| 370 | + { | ||
| 371 | + "name": "quant_mode", | ||
| 372 | + "dtype": "string", | ||
| 373 | + "value": null | ||
| 374 | + }, | ||
| 375 | + { | ||
| 376 | + "name": "block_size", | ||
| 377 | + "dtype": "int64", | ||
| 378 | + "value": 256 | ||
| 379 | + } | ||
| 380 | + ] | ||
| 381 | + }, | ||
| 382 | + { | ||
| 383 | + "bin_filename": "ApplyAdamWQuant_b14a102b", | ||
| 384 | + "inputs": [ | ||
| 385 | + { | ||
| 386 | + "name": "var", | ||
| 387 | + "index": 0, | ||
| 388 | + "dtype": "bfloat16", | ||
| 389 | + "format": "ND", | ||
| 390 | + "paramType": "required", | ||
| 391 | + "shape": [ | ||
| 392 | + -2 | ||
| 393 | + ] | ||
| 394 | + }, | ||
| 395 | + { | ||
| 396 | + "name": "grad", | ||
| 397 | + "index": 1, | ||
| 398 | + "dtype": "bfloat16", | ||
| 399 | + "format": "ND", | ||
| 400 | + "paramType": "required", | ||
| 401 | + "shape": [ | ||
| 402 | + -2 | ||
| 403 | + ] | ||
| 404 | + }, | ||
| 405 | + { | ||
| 406 | + "name": "m", | ||
| 407 | + "index": 2, | ||
| 408 | + "dtype": "uint8", | ||
| 409 | + "format": "ND", | ||
| 410 | + "paramType": "required", | ||
| 411 | + "shape": [ | ||
| 412 | + -2 | ||
| 413 | + ] | ||
| 414 | + }, | ||
| 415 | + { | ||
| 416 | + "name": "v", | ||
| 417 | + "index": 3, | ||
| 418 | + "dtype": "uint8", | ||
| 419 | + "format": "ND", | ||
| 420 | + "paramType": "required", | ||
| 421 | + "shape": [ | ||
| 422 | + -2 | ||
| 423 | + ] | ||
| 424 | + }, | ||
| 425 | + { | ||
| 426 | + "name": "qmap_m", | ||
| 427 | + "index": 4, | ||
| 428 | + "dtype": "float32", | ||
| 429 | + "format": "ND", | ||
| 430 | + "paramType": "required", | ||
| 431 | + "shape": [ | ||
| 432 | + -2 | ||
| 433 | + ] | ||
| 434 | + }, | ||
| 435 | + { | ||
| 436 | + "name": "qmap_v", | ||
| 437 | + "index": 5, | ||
| 438 | + "dtype": "float32", | ||
| 439 | + "format": "ND", | ||
| 440 | + "paramType": "required", | ||
| 441 | + "shape": [ | ||
| 442 | + -2 | ||
| 443 | + ] | ||
| 444 | + }, | ||
| 445 | + { | ||
| 446 | + "name": "absmax_m", | ||
| 447 | + "index": 6, | ||
| 448 | + "dtype": "float32", | ||
| 449 | + "format": "ND", | ||
| 450 | + "paramType": "required", | ||
| 451 | + "shape": [ | ||
| 452 | + -2 | ||
| 453 | + ] | ||
| 454 | + }, | ||
| 455 | + { | ||
| 456 | + "name": "absmax_v", | ||
| 457 | + "index": 7, | ||
| 458 | + "dtype": "float32", | ||
| 459 | + "format": "ND", | ||
| 460 | + "paramType": "required", | ||
| 461 | + "shape": [ | ||
| 462 | + -2 | ||
| 463 | + ] | ||
| 464 | + }, | ||
| 465 | + { | ||
| 466 | + "name": "step", | ||
| 467 | + "index": 8, | ||
| 468 | + "dtype": "int64", | ||
| 469 | + "format": "ND", | ||
| 470 | + "paramType": "required", | ||
| 471 | + "shape": [ | ||
| 472 | + -2 | ||
| 473 | + ] | ||
| 474 | + } | ||
| 475 | + ], | ||
| 476 | + "outputs": [ | ||
| 477 | + { | ||
| 478 | + "name": "var", | ||
| 479 | + "index": 0, | ||
| 480 | + "dtype": "bfloat16", | ||
| 481 | + "format": "ND", | ||
| 482 | + "paramType": "required", | ||
| 483 | + "shape": [ | ||
| 484 | + -2 | ||
| 485 | + ] | ||
| 486 | + }, | ||
| 487 | + { | ||
| 488 | + "name": "m", | ||
| 489 | + "index": 1, | ||
| 490 | + "dtype": "uint8", | ||
| 491 | + "format": "ND", | ||
| 492 | + "paramType": "required", | ||
| 493 | + "shape": [ | ||
| 494 | + -2 | ||
| 495 | + ] | ||
| 496 | + }, | ||
| 497 | + { | ||
| 498 | + "name": "v", | ||
| 499 | + "index": 2, | ||
| 500 | + "dtype": "uint8", | ||
| 501 | + "format": "ND", | ||
| 502 | + "paramType": "required", | ||
| 503 | + "shape": [ | ||
| 504 | + -2 | ||
| 505 | + ] | ||
| 506 | + }, | ||
| 507 | + { | ||
| 508 | + "name": "absmax_m", | ||
| 509 | + "index": 3, | ||
| 510 | + "dtype": "float32", | ||
| 511 | + "format": "ND", | ||
| 512 | + "paramType": "required", | ||
| 513 | + "shape": [ | ||
| 514 | + -2 | ||
| 515 | + ] | ||
| 516 | + }, | ||
| 517 | + { | ||
| 518 | + "name": "absmax_v", | ||
| 519 | + "index": 4, | ||
| 520 | + "dtype": "float32", | ||
| 521 | + "format": "ND", | ||
| 522 | + "paramType": "required", | ||
| 523 | + "shape": [ | ||
| 524 | + -2 | ||
| 525 | + ] | ||
| 526 | + } | ||
| 527 | + ], | ||
| 528 | + "attrs": [ | ||
| 529 | + { | ||
| 530 | + "name": "lr", | ||
| 531 | + "dtype": "float", | ||
| 532 | + "value": 0.1 | ||
| 533 | + }, | ||
| 534 | + { | ||
| 535 | + "name": "beta1", | ||
| 536 | + "dtype": "float", | ||
| 537 | + "value": 0.1 | ||
| 538 | + }, | ||
| 539 | + { | ||
| 540 | + "name": "beta2", | ||
| 541 | + "dtype": "float", | ||
| 542 | + "value": 0.1 | ||
| 543 | + }, | ||
| 544 | + { | ||
| 545 | + "name": "weight_decay", | ||
| 546 | + "dtype": "float", | ||
| 547 | + "value": 0.1 | ||
| 548 | + }, | ||
| 549 | + { | ||
| 550 | + "name": "eps", | ||
| 551 | + "dtype": "float", | ||
| 552 | + "value": 0.1 | ||
| 553 | + }, | ||
| 554 | + { | ||
| 555 | + "name": "gnorm_scale", | ||
| 556 | + "dtype": "float", | ||
| 557 | + "value": 0.1 | ||
| 558 | + }, | ||
| 559 | + { | ||
| 560 | + "name": "quant_mode", | ||
| 561 | + "dtype": "string", | ||
| 562 | + "value": null | ||
| 563 | + }, | ||
| 564 | + { | ||
| 565 | + "name": "block_size", | ||
| 566 | + "dtype": "int64", | ||
| 567 | + "value": 256 | ||
| 568 | + } | ||
| 569 | + ] | ||
| 570 | + } | ||
| 571 | + ] | ||
| 572 | +} | ||
| @@ -1,9 +1,9 @@ | |||
| 1 | # ---------------------------------------------------------------------------- | 1 | # ---------------------------------------------------------------------------- |
| 2 | # Copyright (c) 2026 Huawei Technologies Co., Ltd. | 2 | # Copyright (c) 2026 Huawei Technologies Co., Ltd. |
| 3 | -# This program is free software, you can redistribute it and/or modify it under the terms and conditions of | 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"). | 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. | 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, | 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. | 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. | 8 | # See LICENSE in the root of the software repository for the full text of the License. |
| 9 | # ---------------------------------------------------------------------------- | 9 | # ---------------------------------------------------------------------------- |
| @@ -12,3 +12,8 @@ | |||
| 12 | add_kernel_sources( | 12 | add_kernel_sources( |
| 13 | COMPUTE_UNITS ascend910b ascend910_93 | 13 | COMPUTE_UNITS ascend910b ascend910_93 |
| 14 | ) | 14 | ) |
| 15 | +add_kernel_sources( | ||
| 16 | + KERNEL_SRC arch35/apply_adam_w_quant.cpp | ||
| 17 | + COMPUTE_UNITS ascend950 | ||
| 18 | + AUTO_SYNC false | ||
| 19 | +) | ||
| @@ -0,0 +1,55 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 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 | + * NOTE: Portions of this code were AI-generated and have been | ||
| 11 | + * technically reviewed for functional accuracy and security | ||
| 12 | + */ | ||
| 13 | + | ||
| 14 | +/*! | ||
| 15 | + * \file apply_adam_w_quant.cpp | ||
| 16 | + * \brief ApplyAdamWQuant arch35 (Ascend950 / DAV_3510) kernel entry. | ||
| 17 | + * | ||
| 18 | + * arch35 移植:计算逻辑与 A2 完全一致(blockwise-256 量化 AdamW),复用同族 A2 的 | ||
| 19 | + * 手写 TPipe/TBuf + 高层 Vec API 计算头(base/fp32/fp16),仅 tiling 数据从 framework | ||
| 20 | + * GET_TILING_DATA 换成 regbase 的 plain-POD GET_TILING_DATA_WITH_STRUCT。dtype 分发沿用 | ||
| 21 | + * A2 的 TilingKey:fp32=100 / fp16=200 / bf16=300。kernel 入口风格对齐 norm/deep_norm。 | ||
| 22 | + */ | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + | ||
| 28 | +using namespace ApplyAdamWQuantNS; | ||
| 29 | + | ||
| 30 | +extern "C" __global__ __aicore__ void apply_adam_w_quant(GM_ADDR var, GM_ADDR grad, GM_ADDR m, GM_ADDR v, | ||
| 31 | + GM_ADDR qmap_m, GM_ADDR qmap_v, GM_ADDR absmax_m, | ||
| 32 | + GM_ADDR absmax_v, GM_ADDR step, GM_ADDR var_ref, GM_ADDR m_ref, | ||
| 33 | + GM_ADDR v_ref, GM_ADDR absmax_m_ref, GM_ADDR absmax_v_ref, | ||
| 34 | + GM_ADDR workspace, GM_ADDR tiling) | ||
| 35 | +{ | ||
| 36 | + KERNEL_TASK_TYPE_DEFAULT(KERNEL_TYPE_AIV_ONLY); | ||
| 37 | + REGISTER_TILING_DEFAULT(ApplyAdamWQuantRegbaseTilingData); | ||
| 38 | + GET_TILING_DATA_WITH_STRUCT(ApplyAdamWQuantRegbaseTilingData, tiling_data_in, tiling); | ||
| 39 | + if (TILING_KEY_IS(100)) { | ||
这个分发链没有兜底分支,tiling key 不是 100/200/300 时 kernel 什么都不做就正常返回,输出保持为未初始化的 GM 内容,从外面看就是「算子跑成功了但结果不对」。tiling 侧虽然已经限死了三种 dtype,但两边一旦改歪就是这种最难查的表现。建议补一个 else,至少在 CPU 调试态下 assert 或打一条日志。 ![]() ![]() | |||
| 40 | + ApplyAdamWQuant<float, int64_t> op; | ||
| 41 | + op.Init(var, grad, m, v, qmap_m, qmap_v, absmax_m, absmax_v, step, var_ref, m_ref, v_ref, absmax_m_ref, | ||
| 42 | + absmax_v_ref, &tiling_data_in); | ||
| 43 | + op.Process(); | ||
| 44 | + } else if (TILING_KEY_IS(200)) { | ||
| 45 | + ApplyAdamWQuant16<float, int64_t, half> op; | ||
| 46 | + op.Init(var, grad, m, v, qmap_m, qmap_v, absmax_m, absmax_v, step, var_ref, m_ref, v_ref, absmax_m_ref, | ||
| 47 | + absmax_v_ref, &tiling_data_in); | ||
| 48 | + op.Process(); | ||
| 49 | + } else if (TILING_KEY_IS(300)) { | ||
| 50 | + ApplyAdamWQuant16<float, int64_t, bfloat16_t> op; | ||
| 51 | + op.Init(var, grad, m, v, qmap_m, qmap_v, absmax_m, absmax_v, step, var_ref, m_ref, v_ref, absmax_m_ref, | ||
| 52 | + absmax_v_ref, &tiling_data_in); | ||
| 53 | + op.Process(); | ||
| 54 | + } | ||
| 55 | +} | ||
| @@ -0,0 +1,146 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 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 apply_adam_w_quant_base.h | ||
| 13 | + * \brief | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | +namespace ApplyAdamWQuantNS { | ||
| 22 | +using namespace AscendC; | ||
| 23 | + | ||
| 24 | +constexpr int32_t Q_MAP_SIZE = 256; | ||
| 25 | +constexpr uint32_t CALC_BUF_NUM = 6; | ||
| 26 | +constexpr uint32_t PER_UINT8_8BITS = 8; | ||
| 27 | +constexpr uint32_t REPEAT_NUM = 64; | ||
| 28 | +constexpr uint32_t REPEAT_7_TIMES = 7; | ||
| 29 | +constexpr uint32_t REPEAT_NUM_128 = 128; | ||
| 30 | +constexpr uint32_t STRIDE_8 = 8; | ||
| 31 | +constexpr uint32_t PER_4NUM_ONEMAX = 4; | ||
| 32 | +constexpr uint32_t BROADCAST_DIM2 = 2; | ||
| 33 | +constexpr uint32_t BROADCAST_AXIS1 = 1; | ||
| 34 | + | ||
| 35 | +template <typename T> | ||
| 36 | +__aicore__ inline void DataCopyIn(const AscendC::LocalTensor<T>& dst, const AscendC::GlobalTensor<T>& src, | ||
| 37 | + uint32_t count) | ||
| 38 | +{ | ||
| 39 | + AscendC::DataCopyExtParams copyParams{1, static_cast<uint32_t>(count * sizeof(T)), 0, 0, 0}; | ||
| 40 | + AscendC::DataCopyPadExtParams<T> padParams{false, 0, 0, 0}; | ||
| 41 | + AscendC::DataCopyPad(dst, src, copyParams, padParams); | ||
| 42 | +} | ||
| 43 | + | ||
| 44 | +template <typename T> | ||
| 45 | +__aicore__ inline void DataCopyOut(const AscendC::GlobalTensor<T>& dst, const AscendC::LocalTensor<T>& src, | ||
| 46 | + uint32_t count) | ||
| 47 | +{ | ||
| 48 | + AscendC::DataCopyExtParams copyParams{1, static_cast<uint32_t>(count * sizeof(T)), 0, 0, 0}; | ||
| 49 | + | ||
| 50 | + AscendC::DataCopyPad(dst, src, copyParams); | ||
| 51 | +} | ||
| 52 | + | ||
| 53 | +template <typename T, typename T1> | ||
| 54 | +__aicore__ inline void CastF16ToFp32(const AscendC::LocalTensor<T>& dst, const AscendC::LocalTensor<T1>& src, | ||
| 55 | + uint32_t count) | ||
| 56 | +{ | ||
| 57 | + AscendC::Cast(dst, src, AscendC::RoundMode::CAST_NONE, count); | ||
| 58 | +} | ||
| 59 | + | ||
| 60 | +template <typename T, typename T1> | ||
| 61 | +__aicore__ inline void CastFp32ToF16(const AscendC::LocalTensor<T>& dst, const AscendC::LocalTensor<T1>& src, | ||
| 62 | + uint32_t count) | ||
| 63 | +{ | ||
| 64 | + if constexpr (AscendC::IsSameType<T, half>::value) { | ||
| 65 | + Cast(dst, src, AscendC::RoundMode::CAST_NONE, count); | ||
| 66 | + } else { // bf16 | ||
| 67 | + Cast(dst, src, AscendC::RoundMode::CAST_RINT, count); | ||
| 68 | + } | ||
| 69 | +} | ||
| 70 | + | ||
| 71 | +template <AscendC::HardEvent hardEvent> | ||
| 72 | +__aicore__ inline void PipeSync() | ||
| 73 | +{ | ||
| 74 | + int32_t eventID = static_cast<int32_t>(GetTPipePtr()->FetchEventID(hardEvent)); | ||
| 75 | + AscendC::SetFlag<hardEvent>(eventID); | ||
| 76 | + AscendC::WaitFlag<hardEvent>(eventID); | ||
| 77 | +} | ||
| 78 | + | ||
| 79 | +__aicore__ inline float PowS(const AscendC::LocalTensor<float>& dst, float srcScalar, | ||
| 80 | + const AscendC::LocalTensor<float>& src) | ||
| 81 | +{ | ||
| 82 | + AscendC::Power<float>(dst, srcScalar, src); | ||
| 83 | + PipeSync<AscendC::HardEvent::V_S>(); | ||
| 84 | + float ret = dst.GetValue(0); | ||
| 85 | + AscendC::PipeBarrier<PIPE_ALL>(); | ||
| 86 | + return ret; | ||
| 87 | +} | ||
| 88 | + | ||
| 89 | +// RegBase VF:AdamW 状态/参数逐元素更新(fp32 寄存器计算 body)。 | ||
| 90 | +// fp32 与 fp16 路径共用——两者进入本函数时 m/v/grad/var 均为 fp32 UB tile。 | ||
| 91 | +// 由 UB 层 UpdateStateAndParam(Fp32) 经 asc_vf_call 调用,替代原 tile-API Muls/Mul/Add/Sqrt/Adds/Div 链。 | ||
| 92 | +// grad' = grad * gnormScale | ||
| 93 | +// m_out = m * beta1 + grad' * (1 - beta1) | ||
| 94 | +// v_out = v * beta2 + grad'^2 * (1 - beta2) | ||
| 95 | +// var_out= (var + (m_out * stepSize) / (sqrt(v_out) + eps*correction2)) * wdFactor | ||
| 96 | +// wdFactor = (weight_decay>0) ? (1 - lr*weight_decay) : 1.0f(乘 1.0 为 no-op,等价于原分支跳过) | ||
| 97 | +template <typename T> | ||
| 98 | +__simd_vf__ inline void AdamWQuantUpdateVF(__ubuf__ T* dqStateMAddr, __ubuf__ T* dqStateVAddr, __ubuf__ T* varAddr, | ||
这个 VF 函数全仓没有任何调用点,fp32.h 的 UpdateStateAndParamFp32 和 fp16.h 的 UpdateStateAndParam 用的都是 Muls/Mul/Add/Sqrt/Adds/Div 这条 tile-API 链,恰恰是上面注释里说「已被替代」的那条。所以现在是 45 行死代码加一段与事实相反的注释,后面接手的人很容易以为计算走的是 VF 路径。要么真的把 UB 层切到 asc_vf_call 走这个 VF body(arch35 上这才是推荐写法,同目录的 adam_apply_one_assign、inplace_apply_centered_rms_prop 都是这么做的),要么把它和注释一起删掉。 ![]() ![]() | |||
| 99 | + __ubuf__ T* gradAddr, float gnormScale, float beta1, float oneMinusBeta1, | ||
| 100 | + float beta2, float oneMinusBeta2, float epsCorr, float stepSize, | ||
| 101 | + float wdFactor, uint32_t count, uint32_t oneRepeatSize, uint16_t repeatTimes) | ||
| 102 | +{ | ||
| 103 | + using namespace AscendC::Reg; | ||
| 104 | + RegTensor<T> regM, regV, regGrad, regVar, regTmp; | ||
| 105 | + MaskReg mask; | ||
| 106 | + AddrReg aReg; | ||
| 107 | + uint32_t remain = count; | ||
| 108 | + for (uint16_t i = 0; i < repeatTimes; ++i) { | ||
| 109 | + aReg = CreateAddrReg<T>(i, oneRepeatSize); | ||
| 110 | + mask = UpdateMask<T>(remain); | ||
| 111 | + | ||
| 112 | + LoadAlign(regM, dqStateMAddr, aReg); | ||
| 113 | + LoadAlign(regV, dqStateVAddr, aReg); | ||
| 114 | + LoadAlign(regVar, varAddr, aReg); | ||
| 115 | + LoadAlign(regGrad, gradAddr, aReg); | ||
| 116 | + | ||
| 117 | + // grad = grad * gnormScale | ||
| 118 | + Muls(regGrad, regGrad, gnormScale, mask); | ||
| 119 | + // m = m*beta1 + grad*(1-beta1) | ||
| 120 | + Muls(regM, regM, beta1, mask); | ||
| 121 | + Muls(regTmp, regGrad, oneMinusBeta1, mask); | ||
| 122 | + Add(regM, regM, regTmp, mask); | ||
| 123 | + // v = v*beta2 + grad^2*(1-beta2) | ||
| 124 | + Muls(regV, regV, beta2, mask); | ||
| 125 | + Mul(regGrad, regGrad, regGrad, mask); // grad^2 | ||
| 126 | + Muls(regTmp, regGrad, oneMinusBeta2, mask); | ||
| 127 | + Add(regV, regV, regTmp, mask); | ||
| 128 | + // denom = sqrt(v) + eps*correction2 | ||
| 129 | + Sqrt(regTmp, regV, mask); | ||
| 130 | + Adds(regTmp, regTmp, epsCorr, mask); | ||
| 131 | + // var = var + (m*stepSize)/denom(regGrad 复用为 m*stepSize,对齐原 tmpVar1 别名 grad 缓存) | ||
| 132 | + Muls(regGrad, regM, stepSize, mask); | ||
| 133 | + Div(regGrad, regGrad, regTmp, mask); | ||
| 134 | + Add(regVar, regVar, regGrad, mask); | ||
| 135 | + // var = var * wdFactor(无 weight_decay 时 wdFactor=1) | ||
| 136 | + Muls(regVar, regVar, wdFactor, mask); | ||
| 137 | + | ||
| 138 | + StoreAlign(dqStateMAddr, regM, aReg, mask); | ||
| 139 | + StoreAlign(dqStateVAddr, regV, aReg, mask); | ||
| 140 | + StoreAlign(varAddr, regVar, aReg, mask); | ||
| 141 | + } | ||
| 142 | +} | ||
| 143 | + | ||
| 144 | +} // namespace ApplyAdamWQuantNS | ||
| 145 | + | ||
| 146 | + | ||
| @@ -0,0 +1,718 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 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 apply_adam_w_quant_fp16.h | ||
| 13 | + * \brief | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | +namespace ApplyAdamWQuantNS { | ||
| 21 | +using namespace AscendC; | ||
| 22 | + | ||
| 23 | +using namespace ApplyAdamWQuantNS; | ||
| 24 | + | ||
| 25 | +template <typename T, typename U, typename T_VAR_GRAD> | ||
| 26 | +class ApplyAdamWQuant16 { | ||
| 27 | +public: | ||
| 28 | + __aicore__ inline ApplyAdamWQuant16(){}; | ||
| 29 | + __aicore__ inline void Init(GM_ADDR var, GM_ADDR grad, GM_ADDR m, GM_ADDR v, GM_ADDR qmap_m, GM_ADDR qmap_v, | ||
| 30 | + GM_ADDR absmax_m, GM_ADDR absmax_v, GM_ADDR step, GM_ADDR var_ref, GM_ADDR m_ref, | ||
| 31 | + GM_ADDR v_ref, GM_ADDR absmax_m_ref, GM_ADDR absmax_v_ref, | ||
| 32 | + const ApplyAdamWQuantRegbaseTilingData* tilingData) | ||
| 33 | + { | ||
| 34 | + this->blockIdx = AscendC::GetBlockIdx(); | ||
| 35 | + ParseTilingData(tilingData); | ||
| 36 | + if (this->blockIdx < notLastCoreNum) { | ||
| 37 | + gmOffset = this->blockIdx * notLastPreCoreRowWork * blockSize * oneCoreDoBlockNumPerRow; | ||
| 38 | + absmaxOffset = this->blockIdx * notLastPreCoreRowWork * oneCoreDoBlockNumPerRow; | ||
| 39 | + } else { | ||
| 40 | + gmOffset = (notLastCoreNum * notLastPreCoreRowWork + | ||
| 41 | + (this->blockIdx - notLastCoreNum) * lastPreCoreRowWork) * | ||
| 42 | + blockSize * oneCoreDoBlockNumPerRow; | ||
| 43 | + absmaxOffset = (notLastCoreNum * notLastPreCoreRowWork + | ||
| 44 | + (this->blockIdx - notLastCoreNum) * lastPreCoreRowWork) * | ||
| 45 | + oneCoreDoBlockNumPerRow; | ||
| 46 | + } | ||
| 47 | + this->singleBlockNum = oneCoreDoBlockNumPerRow; | ||
| 48 | + this->singleSize = blockSize * oneCoreDoBlockNumPerRow; | ||
| 49 | + varGm.SetGlobalBuffer((__gm__ T_VAR_GRAD*)var + gmOffset); | ||
| 50 | + gradGm.SetGlobalBuffer((__gm__ T_VAR_GRAD*)grad + gmOffset); | ||
| 51 | + stateMGm.SetGlobalBuffer((__gm__ uint8_t*)m + gmOffset); | ||
| 52 | + stateVGm.SetGlobalBuffer((__gm__ uint8_t*)v + gmOffset); | ||
| 53 | + qMapMGm.SetGlobalBuffer((__gm__ T*)qmap_m); | ||
| 54 | + qMapVGm.SetGlobalBuffer((__gm__ T*)qmap_v); | ||
| 55 | + absMaxMGm.SetGlobalBuffer((__gm__ T*)absmax_m + absmaxOffset); | ||
| 56 | + absMaxVGm.SetGlobalBuffer((__gm__ T*)absmax_v + absmaxOffset); | ||
| 57 | + stepGm.SetGlobalBuffer((__gm__ U*)step, 1); | ||
| 58 | + varRefGm.SetGlobalBuffer((__gm__ T_VAR_GRAD*)var_ref + gmOffset); | ||
| 59 | + stateMRefGm.SetGlobalBuffer((__gm__ uint8_t*)m_ref + gmOffset); | ||
| 60 | + stateVRefGm.SetGlobalBuffer((__gm__ uint8_t*)v_ref + gmOffset); | ||
| 61 | + absMaxMRefGm.SetGlobalBuffer((__gm__ T*)absmax_m_ref + absmaxOffset); | ||
| 62 | + absMaxVRefGm.SetGlobalBuffer((__gm__ T*)absmax_v_ref + absmaxOffset); | ||
| 63 | + step_ = static_cast<float>(stepGm.GetValue(0)); | ||
| 64 | + | ||
| 65 | + pipe.InitBuffer(varBuf, singleSize * sizeof(T_VAR_GRAD)); | ||
| 66 | + pipe.InitBuffer(gradBuf, singleSize * sizeof(T_VAR_GRAD)); | ||
| 67 | + pipe.InitBuffer(varFp32Buf, singleSize * sizeof(T)); | ||
| 68 | + pipe.InitBuffer(gradFp32Buf, singleSize * sizeof(T)); | ||
| 69 | + pipe.InitBuffer(stateMBuf, singleSize * sizeof(T)); | ||
| 70 | + pipe.InitBuffer(stateVBuf, singleSize * sizeof(T)); | ||
| 71 | + pipe.InitBuffer(qMapMBuf, Q_MAP_SIZE * sizeof(T)); | ||
| 72 | + pipe.InitBuffer(qMapVBuf, Q_MAP_SIZE * sizeof(T)); | ||
| 73 | + pipe.InitBuffer(absMaxMBuf, oneCoreDoBlockNumPerRow * sizeof(T)); | ||
| 74 | + pipe.InitBuffer(absMaxVBuf, oneCoreDoBlockNumPerRow * sizeof(T)); | ||
| 75 | + pipe.InitBuffer(calcBuf, CALC_BUF_NUM * singleSize * sizeof(float)); | ||
| 76 | + | ||
| 77 | + this->qMapM = qMapMBuf.Get<T>(); | ||
| 78 | + this->qMapV = qMapVBuf.Get<T>(); | ||
| 79 | + this->stateM = stateMBuf.Get<uint8_t>(); | ||
| 80 | + this->stateV = stateVBuf.Get<uint8_t>(); | ||
| 81 | + this->absMaxM = absMaxMBuf.Get<T>(); | ||
| 82 | + this->absMaxV = absMaxVBuf.Get<T>(); | ||
| 83 | + this->var = varBuf.Get<T_VAR_GRAD>(); | ||
| 84 | + this->grad = gradBuf.Get<T_VAR_GRAD>(); | ||
| 85 | + this->varFp32 = varFp32Buf.Get<T>(); | ||
| 86 | + this->gradFp32 = gradFp32Buf.Get<T>(); | ||
| 87 | + | ||
| 88 | + step_ += 1; | ||
| 89 | + uint32_t count = AscendC::ONE_BLK_SIZE / sizeof(float); | ||
| 90 | + AscendC::LocalTensor<float> stepTensor = calcBuf.GetWithOffset<float>(count, 0); | ||
| 91 | + AscendC::LocalTensor<float> resTensor = calcBuf.GetWithOffset<float>(count, AscendC::ONE_BLK_SIZE); | ||
| 92 | + AscendC::Duplicate<float>(stepTensor, step_, AscendC::ONE_BLK_SIZE / sizeof(float)); | ||
| 93 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 94 | + | ||
| 95 | + float correction1 = 1 - PowS(resTensor, beta1, stepTensor); | ||
| 96 | + this->correction2 = sqrt(1 - PowS(resTensor, beta2, stepTensor)); | ||
| 97 | + this->stepSize = -lr * this->correction2 / correction1; | ||
| 98 | + } | ||
| 99 | + | ||
| 100 | + __aicore__ inline void Process() | ||
| 101 | + { | ||
| 102 | + DataCopyIn<T>(qMapM, qMapMGm, Q_MAP_SIZE); | ||
| 103 | + DataCopyIn<T>(qMapV, qMapVGm, Q_MAP_SIZE); | ||
| 104 | + | ||
| 105 | + int64_t perCoreRowWork = lastPreCoreRowWork; | ||
| 106 | + if (this->blockIdx < notLastCoreNum) { | ||
| 107 | + perCoreRowWork += 1; | ||
| 108 | + } | ||
| 109 | + uint64_t blockOffset = 0; | ||
| 110 | + uint64_t absMaxBlockOffset = 0; | ||
| 111 | + for (int64_t n = 0; n < perCoreRowWork; n++) { | ||
| 112 | + bool isLastRow = static_cast<uint64_t>(this->blockIdx + 1) == useNumCore && n + 1 == perCoreRowWork; | ||
| 113 | + singleBlockNum = isLastRow ? lastCoreLastBlock : oneCoreDoBlockNumPerRow; | ||
| 114 | + singleSize = blockSize * singleBlockNum; | ||
| 115 | + uint32_t validSize = isLastRow ? singleSize - blockSize + lastBlockSize : singleSize; | ||
| 116 | + | ||
| 117 | + DataCopyIn<uint8_t>(stateM, stateMGm[blockOffset], validSize); | ||
| 118 | + DataCopyIn<uint8_t>(stateV, stateVGm[blockOffset], validSize); | ||
| 119 | + | ||
| 120 | + DataCopyIn<T>(absMaxM, absMaxMGm[absMaxBlockOffset], singleBlockNum); | ||
| 121 | + DataCopyIn<T>(absMaxV, absMaxVGm[absMaxBlockOffset], singleBlockNum); | ||
| 122 | + | ||
| 123 | + PipeSync<AscendC::HardEvent::MTE2_V>(); | ||
| 124 | + | ||
| 125 | + DeQuant(stateM, qMapM, absMaxM, calcBuf, singleBlockNum, validSize); | ||
| 126 | + DeQuant(stateV, qMapV, absMaxV, calcBuf, singleBlockNum, validSize); | ||
| 127 | + DataCopyIn<T_VAR_GRAD>(var, varGm[blockOffset], validSize); | ||
| 128 | + DataCopyIn<T_VAR_GRAD>(grad, gradGm[blockOffset], validSize); | ||
| 129 | + PipeSync<AscendC::HardEvent::MTE2_V>(); | ||
| 130 | + CastF16ToFp32<T, T_VAR_GRAD>(varFp32, var, validSize); | ||
| 131 | + CastF16ToFp32<T, T_VAR_GRAD>(gradFp32, grad, validSize); | ||
| 132 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 133 | + UpdateStateAndParam(stateM.template ReinterpretCast<T>(), stateV.template ReinterpretCast<T>(), gradFp32, | ||
| 134 | + varFp32, validSize); | ||
| 135 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 136 | + CastFp32ToF16<T_VAR_GRAD, T>(var, varFp32, validSize); | ||
| 137 | + PipeSync<AscendC::HardEvent::V_MTE3>(); | ||
| 138 | + DataCopyOut<T_VAR_GRAD>(varRefGm[blockOffset], var, validSize); | ||
| 139 | + QuantM(stateM.template ReinterpretCast<T>(), qMapM, stateM, absMaxM, gradFp32, calcBuf, singleBlockNum); | ||
| 140 | + QuantV(stateV.template ReinterpretCast<T>(), qMapV, stateV, absMaxV, calcBuf, singleBlockNum); | ||
| 141 | + PipeSync<AscendC::HardEvent::V_MTE3>(); | ||
| 142 | + | ||
| 143 | + DataCopyOut<T>(absMaxMRefGm[absMaxBlockOffset], absMaxM, singleBlockNum); | ||
| 144 | + DataCopyOut<T>(absMaxVRefGm[absMaxBlockOffset], absMaxV, singleBlockNum); | ||
| 145 | + | ||
| 146 | + DataCopyOut<uint8_t>(stateMRefGm[blockOffset], stateM, validSize); | ||
| 147 | + DataCopyOut<uint8_t>(stateVRefGm[blockOffset], stateV, validSize); | ||
| 148 | + | ||
| 149 | + PipeSync<AscendC::HardEvent::MTE3_MTE2>(); | ||
| 150 | + blockOffset += singleSize; | ||
| 151 | + absMaxBlockOffset += singleBlockNum; | ||
| 152 | + } | ||
| 153 | + } | ||
| 154 | + | ||
| 155 | +private: | ||
| 156 | + __aicore__ inline void ParseTilingData(const ApplyAdamWQuantRegbaseTilingData* tilingData) | ||
| 157 | + { | ||
| 158 | + useNumCore = tilingData->use_num_core; | ||
| 159 | + lastPreCoreRowWork = tilingData->last_pre_core_row_work; | ||
| 160 | + notLastCoreNum = tilingData->not_last_core_num; | ||
| 161 | + notLastPreCoreRowWork = tilingData->not_last_pre_core_row_work; | ||
| 162 | + lastCoreLastBlock = tilingData->last_core_last_block; | ||
| 163 | + lastBlockSize = tilingData->last_block_size; | ||
| 164 | + oneCoreDoBlockNumPerRow = tilingData->one_core_do_block_num_per_row; | ||
| 165 | + | ||
| 166 | + lr = tilingData->lr; | ||
| 167 | + beta1 = tilingData->beta1; | ||
| 168 | + beta2 = tilingData->beta2; | ||
| 169 | + weightDecay = tilingData->weight_decay; | ||
| 170 | + eps = tilingData->eps; | ||
| 171 | + gnormScale = tilingData->gnorm_scale; | ||
| 172 | + blockSize = tilingData->block_size; | ||
| 173 | + } | ||
| 174 | + | ||
| 175 | + __aicore__ inline void BinarySearch(const AscendC::LocalTensor<T>& normState, const AscendC::LocalTensor<T>& qMap, | ||
| 176 | + AscendC::LocalTensor<uint8_t>& qState, AscendC::TBuf<>& calcBuf, | ||
| 177 | + int32_t singleBlockNum) | ||
| 178 | + { | ||
| 179 | + uint32_t offset = 0; | ||
| 180 | + AscendC::LocalTensor<int32_t> lowerPivot = calcBuf.GetWithOffset<int32_t>(singleSize, offset); | ||
| 181 | + offset += singleSize * sizeof(int32_t); | ||
| 182 | + AscendC::LocalTensor<int32_t> upperPivot = calcBuf.GetWithOffset<int32_t>(singleSize, offset); | ||
| 183 | + offset += singleSize * sizeof(int32_t); | ||
| 184 | + AscendC::LocalTensor<int32_t> pivot = calcBuf.GetWithOffset<int32_t>(singleSize, offset); | ||
| 185 | + offset += singleSize * sizeof(int32_t); | ||
| 186 | + AscendC::LocalTensor<int32_t> gatherOffset = calcBuf.GetWithOffset<int32_t>(singleSize, offset); | ||
| 187 | + offset += singleSize * sizeof(int32_t); | ||
| 188 | + AscendC::LocalTensor<T> stateTmp = calcBuf.GetWithOffset<T>(singleSize, offset); | ||
| 189 | + offset += singleSize * sizeof(T); | ||
| 190 | + AscendC::LocalTensor<uint8_t> higgerMask = calcBuf.GetWithOffset<uint8_t>(singleSize / PER_UINT8_8BITS, offset); | ||
| 191 | + | ||
| 192 | + AscendC::Duplicate<int32_t>(lowerPivot, 0, singleSize); | ||
| 193 | + AscendC::Duplicate<int32_t>(upperPivot, Q_MAP_SIZE - 1, singleSize); | ||
| 194 | + AscendC::Duplicate<int32_t>(pivot, (Q_MAP_SIZE - 1) >> 1, singleSize); | ||
| 195 | + | ||
| 196 | + T midValue = qMap.GetValue((Q_MAP_SIZE - 1) >> 1); | ||
| 197 | + | ||
| 198 | + PipeSync<AscendC::HardEvent::S_V>(); | ||
| 199 | + | ||
| 200 | + AscendC::Duplicate<T>(stateTmp, midValue, singleSize); | ||
| 201 | + | ||
| 202 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 203 | + AscendC::Compare<T, uint8_t>(higgerMask, normState, stateTmp, AscendC::CMPMODE::GT, singleSize); | ||
| 204 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 205 | + | ||
| 206 | + AscendC::Select<float, uint8_t>( | ||
| 207 | + lowerPivot.template ReinterpretCast<float>(), higgerMask, pivot.template ReinterpretCast<float>(), | ||
| 208 | + lowerPivot.template ReinterpretCast<float>(), AscendC::SELMODE::VSEL_TENSOR_TENSOR_MODE, REPEAT_NUM, | ||
| 209 | + singleSize / REPEAT_NUM, {1, 1, 1, 8, 8, 8}); | ||
| 210 | + AscendC::Select<float, uint8_t>( | ||
| 211 | + upperPivot.template ReinterpretCast<float>(), higgerMask, upperPivot.template ReinterpretCast<float>(), | ||
| 212 | + pivot.template ReinterpretCast<float>(), AscendC::SELMODE::VSEL_TENSOR_TENSOR_MODE, REPEAT_NUM, | ||
| 213 | + singleSize / REPEAT_NUM, {1, 1, 1, 8, 8, 8}); | ||
| 214 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 215 | + | ||
| 216 | + for (int32_t i = 0; i < REPEAT_7_TIMES; ++i) { | ||
| 217 | + AscendC::Add<int32_t>(pivot, lowerPivot, upperPivot, singleSize); | ||
| 218 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 219 | + AscendC::ShiftRight<int32_t>(pivot, pivot, 1, singleSize); | ||
| 220 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 221 | + | ||
| 222 | + AscendC::Muls<int32_t>(gatherOffset, pivot, sizeof(T), singleSize); | ||
| 223 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 224 | + | ||
| 225 | + for (int i = 0; i < singleSize / Q_MAP_SIZE; i++) { | ||
| 226 | + AscendC::Gather<T>(stateTmp[i * Q_MAP_SIZE], qMap, | ||
| 227 | + gatherOffset.template ReinterpretCast<uint32_t>()[i * Q_MAP_SIZE], 0, Q_MAP_SIZE); | ||
| 228 | + } | ||
| 229 | + | ||
| 230 | + AscendC::Gather<T>(stateTmp, qMap, gatherOffset.template ReinterpretCast<uint32_t>(), 0, singleSize); | ||
| 231 | + | ||
| 232 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 233 | + | ||
| 234 | + AscendC::Compare<T, uint8_t>(higgerMask, normState, stateTmp, AscendC::CMPMODE::GT, singleSize); | ||
| 235 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 236 | + | ||
| 237 | + AscendC::Select<float, uint8_t>( | ||
| 238 | + lowerPivot.template ReinterpretCast<float>(), higgerMask, pivot.template ReinterpretCast<float>(), | ||
| 239 | + lowerPivot.template ReinterpretCast<float>(), AscendC::SELMODE::VSEL_TENSOR_TENSOR_MODE, REPEAT_NUM, | ||
| 240 | + singleSize / REPEAT_NUM, {1, 1, 1, 8, 8, 8}); | ||
| 241 | + | ||
| 242 | + AscendC::Select<float, uint8_t>( | ||
| 243 | + upperPivot.template ReinterpretCast<float>(), higgerMask, upperPivot.template ReinterpretCast<float>(), | ||
| 244 | + pivot.template ReinterpretCast<float>(), AscendC::SELMODE::VSEL_TENSOR_TENSOR_MODE, REPEAT_NUM, | ||
| 245 | + singleSize / REPEAT_NUM, {1, 1, 1, 8, 8, 8}); | ||
| 246 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 247 | + } | ||
| 248 | + | ||
| 249 | + AscendC::LocalTensor<T> lowerState = stateTmp; | ||
| 250 | + AscendC::LocalTensor<T> upperState = pivot.template ReinterpretCast<T>(); | ||
| 251 | + | ||
| 252 | + AscendC::Muls<int32_t>(gatherOffset, lowerPivot, sizeof(T), singleSize); | ||
| 253 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 254 | + | ||
| 255 | + for (int i = 0; i < singleSize / Q_MAP_SIZE; i++) { | ||
| 256 | + AscendC::Gather<T>(lowerState[i * Q_MAP_SIZE], qMap, | ||
| 257 | + gatherOffset.template ReinterpretCast<uint32_t>()[i * Q_MAP_SIZE], 0, Q_MAP_SIZE); | ||
| 258 | + } | ||
| 259 | + | ||
| 260 | + AscendC::Gather<T>(lowerState, qMap, gatherOffset.template ReinterpretCast<uint32_t>(), 0, singleSize); | ||
| 261 | + | ||
| 262 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 263 | + AscendC::Sub<T>(lowerState, normState, lowerState, singleSize); | ||
| 264 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 265 | + AscendC::Abs<T>(lowerState, lowerState, singleSize); | ||
| 266 | + | ||
| 267 | + AscendC::Muls<int32_t>(gatherOffset, upperPivot, sizeof(T), singleSize); | ||
| 268 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 269 | + | ||
| 270 | + for (int i = 0; i < singleSize / Q_MAP_SIZE; i++) { | ||
| 271 | + AscendC::Gather<T>(upperState[i * Q_MAP_SIZE], qMap, | ||
| 272 | + gatherOffset.template ReinterpretCast<uint32_t>()[i * Q_MAP_SIZE], 0, Q_MAP_SIZE); | ||
| 273 | + } | ||
| 274 | + | ||
| 275 | + AscendC::Gather<T>(upperState, qMap, gatherOffset.template ReinterpretCast<uint32_t>(), 0, singleSize); | ||
| 276 | + | ||
| 277 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 278 | + AscendC::Sub<T>(upperState, normState, upperState, singleSize); | ||
| 279 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 280 | + AscendC::Abs<T>(upperState, upperState, singleSize); | ||
| 281 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 282 | + | ||
| 283 | + AscendC::Compare<T, uint8_t>(higgerMask, lowerState, upperState, AscendC::CMPMODE::LE, singleSize); | ||
| 284 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 285 | + | ||
| 286 | + AscendC::Select<float, uint8_t>( | ||
| 287 | + pivot.template ReinterpretCast<float>(), higgerMask, lowerPivot.template ReinterpretCast<float>(), | ||
| 288 | + upperPivot.template ReinterpretCast<float>(), AscendC::SELMODE::VSEL_TENSOR_TENSOR_MODE, REPEAT_NUM, | ||
| 289 | + singleSize / REPEAT_NUM, {1, 1, 1, 8, 8, 8}); | ||
| 290 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 291 | + AscendC::Cast<int16_t, int32_t>(stateTmp.template ReinterpretCast<int16_t>(), pivot, | ||
| 292 | + AscendC::RoundMode::CAST_NONE, singleSize); | ||
| 293 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 294 | + AscendC::Cast<half, int16_t>(pivot.template ReinterpretCast<half>(), | ||
| 295 | + stateTmp.template ReinterpretCast<int16_t>(), AscendC::RoundMode::CAST_NONE, | ||
| 296 | + singleSize); | ||
| 297 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 298 | + AscendC::Cast<uint8_t, half>(qState, pivot.template ReinterpretCast<half>(), AscendC::RoundMode::CAST_NONE, | ||
| 299 | + singleSize); | ||
| 300 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 301 | + } | ||
| 302 | + | ||
| 303 | + __aicore__ inline void BinarySearchScaled(const AscendC::LocalTensor<T>& state, const AscendC::LocalTensor<T>& qMap, | ||
| 304 | + const AscendC::LocalTensor<T>& absMax, | ||
| 305 | + AscendC::LocalTensor<uint8_t>& qState, AscendC::TBuf<>& calcBuf, | ||
| 306 | + int32_t singleBlockNum) | ||
| 307 | + { | ||
| 308 | + uint32_t offset = 0; | ||
| 309 | + AscendC::LocalTensor<int32_t> lowerPivot = calcBuf.GetWithOffset<int32_t>(singleSize, offset); | ||
| 310 | + offset += singleSize * sizeof(int32_t); | ||
| 311 | + AscendC::LocalTensor<int32_t> upperPivot = calcBuf.GetWithOffset<int32_t>(singleSize, offset); | ||
| 312 | + offset += singleSize * sizeof(int32_t); | ||
| 313 | + AscendC::LocalTensor<int32_t> pivot = calcBuf.GetWithOffset<int32_t>(singleSize, offset); | ||
| 314 | + offset += singleSize * sizeof(int32_t); | ||
| 315 | + AscendC::LocalTensor<int32_t> gatherOffset = calcBuf.GetWithOffset<int32_t>(singleSize, offset); | ||
| 316 | + offset += singleSize * sizeof(int32_t); | ||
| 317 | + AscendC::LocalTensor<T> stateTmp = calcBuf.GetWithOffset<T>(singleSize, offset); | ||
| 318 | + offset += singleSize * sizeof(T); | ||
| 319 | + AscendC::LocalTensor<uint8_t> higgerMask = calcBuf.GetWithOffset<uint8_t>(singleSize / PER_UINT8_8BITS, offset); | ||
| 320 | + AscendC::LocalTensor<T> absMaxBrcb = gatherOffset.template ReinterpretCast<T>(); | ||
| 321 | + | ||
| 322 | + uint32_t srcShape[2] = {static_cast<uint32_t>(singleBlockNum), 1}; | ||
| 323 | + uint32_t dstShape[2] = {static_cast<uint32_t>(singleBlockNum), blockSize}; | ||
| 324 | + | ||
| 325 | + AscendC::Duplicate<int32_t>(lowerPivot, 0, singleSize); | ||
| 326 | + AscendC::Duplicate<int32_t>(upperPivot, Q_MAP_SIZE - 1, singleSize); | ||
| 327 | + AscendC::Duplicate<int32_t>(pivot, (Q_MAP_SIZE - 1) >> 1, singleSize); | ||
| 328 | + | ||
| 329 | + T midValue = qMap.GetValue((Q_MAP_SIZE - 1) >> 1); | ||
| 330 | + | ||
| 331 | + PipeSync<AscendC::HardEvent::S_V>(); | ||
| 332 | + | ||
| 333 | + AscendC::Duplicate<T>(stateTmp, midValue, singleSize); | ||
| 334 | + AscendC::Broadcast<T, BROADCAST_DIM2, BROADCAST_AXIS1>(absMaxBrcb, absMax, dstShape, srcShape); | ||
| 335 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 336 | + AscendC::Mul<T>(stateTmp, stateTmp, absMaxBrcb, singleSize); | ||
| 337 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 338 | + AscendC::Compare<T, uint8_t>(higgerMask, state, stateTmp, AscendC::CMPMODE::GT, singleSize); | ||
| 339 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 340 | + | ||
| 341 | + AscendC::Select<float, uint8_t>( | ||
| 342 | + lowerPivot.template ReinterpretCast<float>(), higgerMask, pivot.template ReinterpretCast<float>(), | ||
| 343 | + lowerPivot.template ReinterpretCast<float>(), AscendC::SELMODE::VSEL_TENSOR_TENSOR_MODE, REPEAT_NUM, | ||
| 344 | + singleSize / REPEAT_NUM, {1, 1, 1, 8, 8, 8}); | ||
| 345 | + AscendC::Select<float, uint8_t>( | ||
| 346 | + upperPivot.template ReinterpretCast<float>(), higgerMask, upperPivot.template ReinterpretCast<float>(), | ||
| 347 | + pivot.template ReinterpretCast<float>(), AscendC::SELMODE::VSEL_TENSOR_TENSOR_MODE, REPEAT_NUM, | ||
| 348 | + singleSize / REPEAT_NUM, {1, 1, 1, 8, 8, 8}); | ||
| 349 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 350 | + | ||
| 351 | + for (int32_t i = 0; i < REPEAT_7_TIMES; ++i) { | ||
| 352 | + AscendC::Add<int32_t>(pivot, lowerPivot, upperPivot, singleSize); | ||
| 353 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 354 | + AscendC::ShiftRight<int32_t>(pivot, pivot, 1, singleSize); | ||
| 355 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 356 | + | ||
| 357 | + AscendC::Muls<int32_t>(gatherOffset, pivot, sizeof(T), singleSize); | ||
| 358 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 359 | + | ||
| 360 | + for (int i = 0; i < singleSize / Q_MAP_SIZE; i++) { | ||
| 361 | + AscendC::Gather<T>(stateTmp[i * Q_MAP_SIZE], qMap, | ||
| 362 | + gatherOffset.template ReinterpretCast<uint32_t>()[i * Q_MAP_SIZE], 0, Q_MAP_SIZE); | ||
| 363 | + } | ||
| 364 | + | ||
| 365 | + AscendC::Gather<T>(stateTmp, qMap, gatherOffset.template ReinterpretCast<uint32_t>(), 0, singleSize); | ||
| 366 | + | ||
| 367 | + AscendC::Broadcast<T, BROADCAST_DIM2, BROADCAST_AXIS1>(absMaxBrcb, absMax, dstShape, srcShape); | ||
| 368 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 369 | + AscendC::Mul<T>(stateTmp, stateTmp, absMaxBrcb, singleSize); | ||
| 370 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 371 | + | ||
| 372 | + AscendC::Compare<T, uint8_t>(higgerMask, state, stateTmp, AscendC::CMPMODE::GT, singleSize); | ||
| 373 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 374 | + | ||
| 375 | + AscendC::Select<float, uint8_t>( | ||
| 376 | + lowerPivot.template ReinterpretCast<float>(), higgerMask, pivot.template ReinterpretCast<float>(), | ||
| 377 | + lowerPivot.template ReinterpretCast<float>(), AscendC::SELMODE::VSEL_TENSOR_TENSOR_MODE, REPEAT_NUM, | ||
| 378 | + singleSize / REPEAT_NUM, {1, 1, 1, 8, 8, 8}); | ||
| 379 | + | ||
| 380 | + AscendC::Select<float, uint8_t>( | ||
| 381 | + upperPivot.template ReinterpretCast<float>(), higgerMask, upperPivot.template ReinterpretCast<float>(), | ||
| 382 | + pivot.template ReinterpretCast<float>(), AscendC::SELMODE::VSEL_TENSOR_TENSOR_MODE, REPEAT_NUM, | ||
| 383 | + singleSize / REPEAT_NUM, {1, 1, 1, 8, 8, 8}); | ||
| 384 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 385 | + } | ||
| 386 | + | ||
| 387 | + AscendC::LocalTensor<T> lowerState = stateTmp; | ||
| 388 | + AscendC::LocalTensor<T> upperState = pivot.template ReinterpretCast<T>(); | ||
| 389 | + | ||
| 390 | + AscendC::Muls<int32_t>(gatherOffset, lowerPivot, sizeof(T), singleSize); | ||
| 391 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 392 | + | ||
| 393 | + for (int i = 0; i < singleSize / Q_MAP_SIZE; i++) { | ||
| 394 | + AscendC::Gather<T>(lowerState[i * Q_MAP_SIZE], qMap, | ||
| 395 | + gatherOffset.template ReinterpretCast<uint32_t>()[i * Q_MAP_SIZE], 0, Q_MAP_SIZE); | ||
| 396 | + } | ||
| 397 | + | ||
| 398 | + AscendC::Gather<T>(lowerState, qMap, gatherOffset.template ReinterpretCast<uint32_t>(), 0, singleSize); | ||
| 399 | + | ||
| 400 | + AscendC::Broadcast<T, BROADCAST_DIM2, BROADCAST_AXIS1>(absMaxBrcb, absMax, dstShape, srcShape); | ||
| 401 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 402 | + AscendC::Mul<T>(lowerState, lowerState, absMaxBrcb, singleSize); | ||
| 403 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 404 | + AscendC::Sub<T>(lowerState, state, lowerState, singleSize); | ||
| 405 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 406 | + AscendC::Abs<T>(lowerState, lowerState, singleSize); | ||
| 407 | + | ||
| 408 | + AscendC::Muls<int32_t>(gatherOffset, upperPivot, sizeof(T), singleSize); | ||
| 409 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 410 | + | ||
| 411 | + for (int i = 0; i < singleSize / Q_MAP_SIZE; i++) { | ||
| 412 | + AscendC::Gather<T>(upperState[i * Q_MAP_SIZE], qMap, | ||
| 413 | + gatherOffset.template ReinterpretCast<uint32_t>()[i * Q_MAP_SIZE], 0, Q_MAP_SIZE); | ||
| 414 | + } | ||
| 415 | + | ||
| 416 | + AscendC::Gather<T>(upperState, qMap, gatherOffset.template ReinterpretCast<uint32_t>(), 0, singleSize); | ||
| 417 | + | ||
| 418 | + AscendC::Broadcast<T, BROADCAST_DIM2, BROADCAST_AXIS1>(absMaxBrcb, absMax, dstShape, srcShape); | ||
| 419 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 420 | + AscendC::Mul<T>(upperState, upperState, absMaxBrcb, singleSize); | ||
| 421 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 422 | + AscendC::Sub<T>(upperState, state, upperState, singleSize); | ||
| 423 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 424 | + AscendC::Abs<T>(upperState, upperState, singleSize); | ||
| 425 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 426 | + | ||
| 427 | + AscendC::Compare<T, uint8_t>(higgerMask, lowerState, upperState, AscendC::CMPMODE::LE, singleSize); | ||
| 428 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 429 | + | ||
| 430 | + AscendC::Select<float, uint8_t>( | ||
| 431 | + pivot.template ReinterpretCast<float>(), higgerMask, lowerPivot.template ReinterpretCast<float>(), | ||
| 432 | + upperPivot.template ReinterpretCast<float>(), AscendC::SELMODE::VSEL_TENSOR_TENSOR_MODE, REPEAT_NUM, | ||
| 433 | + singleSize / REPEAT_NUM, {1, 1, 1, 8, 8, 8}); | ||
| 434 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 435 | + AscendC::Cast<int16_t, int32_t>(stateTmp.template ReinterpretCast<int16_t>(), pivot, | ||
| 436 | + AscendC::RoundMode::CAST_NONE, singleSize); | ||
| 437 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 438 | + AscendC::Cast<half, int16_t>(pivot.template ReinterpretCast<half>(), | ||
| 439 | + stateTmp.template ReinterpretCast<int16_t>(), AscendC::RoundMode::CAST_NONE, | ||
| 440 | + singleSize); | ||
| 441 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 442 | + AscendC::Cast<uint8_t, half>(qState, pivot.template ReinterpretCast<half>(), AscendC::RoundMode::CAST_NONE, | ||
| 443 | + singleSize); | ||
| 444 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 445 | + } | ||
| 446 | + | ||
| 447 | + __aicore__ inline void CheckSign(const AscendC::LocalTensor<T>& normState, const AscendC::LocalTensor<T>& qMap, | ||
| 448 | + AscendC::LocalTensor<uint8_t>& qState, AscendC::TBuf<>& calcBuf, | ||
| 449 | + int32_t singleBlockNum) | ||
| 450 | + { | ||
| 451 | + // Match golden exactly: if normalized state and selected qmap have opposite | ||
| 452 | + // signs, move the code by one step toward the normalized state's sign. | ||
| 453 | + // Use int16 arithmetic (A2-style) to avoid float rounding in index conversion. | ||
| 454 | + uint32_t offset = 0; | ||
| 455 | + AscendC::LocalTensor<int32_t> gatherOffset = calcBuf.GetWithOffset<int32_t>(singleSize, offset); | ||
| 456 | + offset += singleSize * sizeof(int32_t); | ||
| 457 | + AscendC::LocalTensor<T> dq = calcBuf.GetWithOffset<T>(singleSize, offset); | ||
| 458 | + offset += singleSize * sizeof(T); | ||
| 459 | + AscendC::LocalTensor<int16_t> idxI = calcBuf.GetWithOffset<int16_t>(singleSize, offset); | ||
| 460 | + offset += singleSize * sizeof(int16_t); | ||
| 461 | + AscendC::LocalTensor<T> zero = calcBuf.GetWithOffset<T>(singleSize, offset); | ||
| 462 | + offset += singleSize * sizeof(T); | ||
| 463 | + AscendC::LocalTensor<int16_t> adjustedI = calcBuf.GetWithOffset<int16_t>(singleSize, offset); | ||
| 464 | + offset += singleSize * sizeof(int16_t); | ||
| 465 | + const int32_t maskBytes = singleSize / PER_UINT8_8BITS; | ||
| 466 | + AscendC::LocalTensor<uint8_t> normPosMask = calcBuf.GetWithOffset<uint8_t>(maskBytes, offset); | ||
| 467 | + offset += maskBytes; | ||
| 468 | + AscendC::LocalTensor<uint8_t> normNegMask = calcBuf.GetWithOffset<uint8_t>(maskBytes, offset); | ||
| 469 | + offset += maskBytes; | ||
| 470 | + AscendC::LocalTensor<uint8_t> qPosMask = calcBuf.GetWithOffset<uint8_t>(maskBytes, offset); | ||
| 471 | + offset += maskBytes; | ||
| 472 | + AscendC::LocalTensor<uint8_t> qNegMask = calcBuf.GetWithOffset<uint8_t>(maskBytes, offset); | ||
| 473 | + AscendC::LocalTensor<half> halfBuf = gatherOffset.template ReinterpretCast<half>(); | ||
| 474 | + | ||
| 475 | + const int32_t selRepeat = singleSize / REPEAT_NUM_128; | ||
| 476 | + | ||
| 477 | + // idxI = int16(qState) — exact since values are 0-255 | ||
| 478 | + AscendC::Cast<half, uint8_t>(halfBuf, qState, AscendC::RoundMode::CAST_NONE, singleSize); | ||
| 479 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 480 | + AscendC::Cast<int16_t, half>(idxI, halfBuf, AscendC::RoundMode::CAST_RINT, singleSize); | ||
| 481 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 482 | + | ||
| 483 | + // dq = qMap[idxI] | ||
| 484 | + AscendC::Cast<int32_t, int16_t>(gatherOffset, idxI, AscendC::RoundMode::CAST_NONE, singleSize); | ||
| 485 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 486 | + AscendC::Muls<int32_t>(gatherOffset, gatherOffset, sizeof(T), singleSize); | ||
| 487 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 488 | + AscendC::Gather<T>(dq, qMap, gatherOffset.template ReinterpretCast<uint32_t>(), 0, singleSize); | ||
| 489 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 490 | + | ||
| 491 | + AscendC::Duplicate<T>(zero, static_cast<T>(0.0f), singleSize); | ||
| 492 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 493 | + AscendC::Compare<T, uint8_t>(normPosMask, normState, zero, AscendC::CMPMODE::GT, singleSize); | ||
| 494 | + AscendC::Compare<T, uint8_t>(normNegMask, normState, zero, AscendC::CMPMODE::LT, singleSize); | ||
| 495 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 496 | + AscendC::Compare<T, uint8_t>(qPosMask, dq, zero, AscendC::CMPMODE::GT, singleSize); | ||
| 497 | + AscendC::Compare<T, uint8_t>(qNegMask, dq, zero, AscendC::CMPMODE::LT, singleSize); | ||
| 498 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 499 | + AscendC::And(normPosMask, normPosMask, qNegMask, maskBytes); | ||
| 500 | + AscendC::And(normNegMask, normNegMask, qPosMask, maskBytes); | ||
| 501 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 502 | + | ||
| 503 | + // Adjust idxI by ±1 in int16 space (avoids float rounding) | ||
| 504 | + AscendC::Adds<int16_t>(adjustedI, idxI, static_cast<int16_t>(1), singleSize); | ||
| 505 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 506 | + AscendC::Select<int16_t, uint8_t>(idxI, normPosMask, adjustedI, idxI, AscendC::SELMODE::VSEL_TENSOR_TENSOR_MODE, | ||
| 507 | + REPEAT_NUM_128, selRepeat, {1, 1, 1, 8, 8, 8}); | ||
| 508 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 509 | + AscendC::Adds<int16_t>(adjustedI, idxI, static_cast<int16_t>(-1), singleSize); | ||
| 510 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 511 | + AscendC::Select<int16_t, uint8_t>(idxI, normNegMask, adjustedI, idxI, AscendC::SELMODE::VSEL_TENSOR_TENSOR_MODE, | ||
| 512 | + REPEAT_NUM_128, selRepeat, {1, 1, 1, 8, 8, 8}); | ||
| 513 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 514 | + | ||
| 515 | + // Clamp to [0, 255] | ||
| 516 | + AscendC::Maxs<int16_t>(idxI, idxI, static_cast<int16_t>(0), singleSize); | ||
| 517 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 518 | + AscendC::Mins<int16_t>(idxI, idxI, static_cast<int16_t>(Q_MAP_SIZE - 1), singleSize); | ||
| 519 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 520 | + | ||
| 521 | + // int16 → half → uint8 (exact, no rounding) | ||
| 522 | + AscendC::Cast<half, int16_t>(halfBuf, idxI, AscendC::RoundMode::CAST_NONE, singleSize); | ||
| 523 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 524 | + AscendC::Cast<uint8_t, half>(qState, halfBuf, AscendC::RoundMode::CAST_NONE, singleSize); | ||
| 525 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 526 | + } | ||
| 527 | + | ||
| 528 | + __aicore__ inline void Normlize(const AscendC::LocalTensor<T>& state, const AscendC::LocalTensor<T>& absMax, | ||
| 529 | + AscendC::TBuf<>& calcBuf, int32_t singleBlockNum) | ||
| 530 | + { | ||
| 531 | + AscendC::LocalTensor<T> absState = calcBuf.GetWithOffset<T>(singleSize, 0); | ||
| 532 | + AscendC::LocalTensor<T> absMaxTmp = calcBuf.GetWithOffset<T>(singleSize, singleSize * sizeof(T)); | ||
| 533 | + AscendC::LocalTensor<T> absMaxBrcb = calcBuf.GetWithOffset<T>(singleSize, 2 * singleSize * sizeof(T)); | ||
| 534 | + | ||
| 535 | + AscendC::Abs<T>(absState, state, singleSize); | ||
| 536 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 537 | + | ||
| 538 | + uint32_t mask = AscendC::ONE_REPEAT_BYTE_SIZE / sizeof(T); | ||
| 539 | + uint32_t repeat = singleSize / mask; | ||
| 540 | + AscendC::BlockReduceMax<T>(absMaxTmp, absState, repeat, mask, 1, 1, STRIDE_8); | ||
| 541 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 542 | + AscendC::WholeReduceMax<T>(absMax, absMaxTmp, blockSize / (AscendC::ONE_BLK_SIZE / sizeof(T)), singleBlockNum, | ||
| 543 | + 1, 1, PER_4NUM_ONEMAX, AscendC::ReduceOrder::ORDER_ONLY_VALUE); | ||
| 544 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 545 | + | ||
| 546 | + uint32_t srcShape[2] = {static_cast<uint32_t>(singleBlockNum), 1}; | ||
| 547 | + uint32_t dstShape[2] = {static_cast<uint32_t>(singleBlockNum), blockSize}; | ||
| 548 | + AscendC::Broadcast<T, BROADCAST_DIM2, BROADCAST_AXIS1>(absMaxBrcb, absMax, dstShape, srcShape); | ||
| 549 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 550 | + AscendC::Div<T>(state, state, absMaxBrcb, singleSize); | ||
| 551 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 552 | + } | ||
| 553 | + | ||
| 554 | + __aicore__ inline void CalcAbsMax(const AscendC::LocalTensor<T>& state, const AscendC::LocalTensor<T>& absMax, | ||
| 555 | + AscendC::TBuf<>& calcBuf, int32_t singleBlockNum) | ||
| 556 | + { | ||
| 557 | + AscendC::LocalTensor<T> absState = calcBuf.GetWithOffset<T>(singleSize, 0); | ||
| 558 | + AscendC::LocalTensor<T> absMaxTmp = calcBuf.GetWithOffset<T>(singleSize, singleSize * sizeof(T)); | ||
| 559 | + | ||
| 560 | + AscendC::Abs<T>(absState, state, singleSize); | ||
| 561 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 562 | + | ||
| 563 | + uint32_t mask = AscendC::ONE_REPEAT_BYTE_SIZE / sizeof(T); | ||
| 564 | + uint32_t repeat = singleSize / mask; | ||
| 565 | + AscendC::BlockReduceMax<T>(absMaxTmp, absState, repeat, mask, 1, 1, STRIDE_8); | ||
| 566 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 567 | + AscendC::WholeReduceMax<T>(absMax, absMaxTmp, blockSize / (AscendC::ONE_BLK_SIZE / sizeof(T)), singleBlockNum, | ||
| 568 | + 1, 1, PER_4NUM_ONEMAX, AscendC::ReduceOrder::ORDER_ONLY_VALUE); | ||
| 569 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 570 | + } | ||
| 571 | + | ||
| 572 | + __aicore__ inline void QuantM(const AscendC::LocalTensor<T>& state, const AscendC::LocalTensor<T>& qMap, | ||
| 573 | + AscendC::LocalTensor<uint8_t>& qState, const AscendC::LocalTensor<T>& absMax, | ||
| 574 | + AscendC::LocalTensor<T>& normStateTmp, AscendC::TBuf<>& calcBuf, | ||
| 575 | + int32_t singleBlockNum) | ||
| 576 | + { | ||
| 577 | + Normlize(state, absMax, calcBuf, singleBlockNum); | ||
| 578 | + | ||
| 579 | + AscendC::Adds<T>(normStateTmp, state, static_cast<T>(0.0f), singleSize); | ||
| 580 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 581 | + | ||
| 582 | + BinarySearch(state, qMap, qState, calcBuf, singleBlockNum); | ||
| 583 | + | ||
| 584 | + CheckSign(normStateTmp, qMap, qState, calcBuf, singleBlockNum); | ||
| 585 | + } | ||
| 586 | + | ||
| 587 | + __aicore__ inline void QuantV(const AscendC::LocalTensor<T>& state, const AscendC::LocalTensor<T>& qMap, | ||
| 588 | + AscendC::LocalTensor<uint8_t>& qState, const AscendC::LocalTensor<T>& absMax, | ||
| 589 | + AscendC::TBuf<>& calcBuf, int32_t singleBlockNum) | ||
| 590 | + { | ||
| 591 | + Normlize(state, absMax, calcBuf, singleBlockNum); | ||
| 592 | + BinarySearch(state, qMap, qState, calcBuf, singleBlockNum); | ||
| 593 | + } | ||
| 594 | + | ||
| 595 | + __aicore__ inline void DeQuant(const AscendC::LocalTensor<uint8_t>& state, const AscendC::LocalTensor<T>& qMap, | ||
| 596 | + AscendC::LocalTensor<T>& absMax, AscendC::TBuf<>& calcBuf, int32_t singleBlockNum, | ||
| 597 | + uint32_t validSize) | ||
| 598 | + { | ||
| 599 | + uint32_t offset = 0; | ||
| 600 | + AscendC::LocalTensor<T> dqState = calcBuf.GetWithOffset<T>(singleSize, offset); | ||
| 601 | + offset += singleSize * sizeof(T); | ||
| 602 | + AscendC::LocalTensor<int32_t> gatherOffset = calcBuf.GetWithOffset<int32_t>(singleSize, offset); | ||
| 603 | + offset += singleSize * sizeof(int32_t); | ||
| 604 | + AscendC::LocalTensor<T> absMaxBrcb = calcBuf.GetWithOffset<T>(singleSize, offset); | ||
| 605 | + | ||
| 606 | + AscendC::Cast<half, uint8_t>(gatherOffset[singleSize >> 1].template ReinterpretCast<half>(), state, | ||
| 607 | + AscendC::RoundMode::CAST_NONE, singleSize); | ||
| 608 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 609 | + AscendC::Cast<int32_t, half>(gatherOffset, gatherOffset[singleSize >> 1].template ReinterpretCast<half>(), | ||
| 610 | + AscendC::RoundMode::CAST_RINT, singleSize); | ||
| 611 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 612 | + AscendC::Muls<int32_t>(gatherOffset, gatherOffset, sizeof(T), singleSize); | ||
| 613 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 614 | + | ||
| 615 | + for (int i = 0; i < singleSize / Q_MAP_SIZE; i++) { | ||
| 616 | + AscendC::Gather<T>(dqState[i * Q_MAP_SIZE], qMap, | ||
| 617 | + gatherOffset.template ReinterpretCast<uint32_t>()[i * Q_MAP_SIZE], 0, Q_MAP_SIZE); | ||
| 618 | + } | ||
| 619 | + | ||
| 620 | + AscendC::Gather<T>(dqState, qMap, gatherOffset.template ReinterpretCast<uint32_t>(), 0, singleSize); | ||
| 621 | + | ||
| 622 | + uint32_t srcShape[2] = {static_cast<uint32_t>(singleBlockNum), 1}; | ||
| 623 | + uint32_t dstShape[2] = {static_cast<uint32_t>(singleBlockNum), blockSize}; | ||
| 624 | + AscendC::Broadcast<T, BROADCAST_DIM2, BROADCAST_AXIS1>(absMaxBrcb, absMax, dstShape, srcShape); | ||
| 625 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 626 | + if (validSize < static_cast<uint32_t>(singleSize)) { | ||
| 627 | + AscendC::Duplicate<T>(state.template ReinterpretCast<T>(), static_cast<T>(0), singleSize); | ||
| 628 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 629 | + } | ||
| 630 | + AscendC::Mul<T>(state.template ReinterpretCast<T>(), dqState, absMaxBrcb, validSize); | ||
| 631 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 632 | + } | ||
| 633 | + | ||
| 634 | + __aicore__ inline void UpdateStateAndParam(const AscendC::LocalTensor<T>& dqStateM, | ||
| 635 | + const AscendC::LocalTensor<T>& dqStateV, | ||
| 636 | + const AscendC::LocalTensor<T>& grad, const AscendC::LocalTensor<T>& var, | ||
| 637 | + uint32_t validSize) | ||
| 638 | + { | ||
| 639 | + constexpr uint32_t oneRepeatSize = AscendC::GetVecLen() / sizeof(T); | ||
| 640 | + uint16_t repeatTimes = AscendC::CeilDivision(validSize, oneRepeatSize); | ||
| 641 | + float weightDecayFactor = weightDecay > 0.0f ? 1.0f - lr * weightDecay : 1.0f; | ||
| 642 | + asc_vf_call<AdamWQuantUpdateVF<T>>((__ubuf__ T*)dqStateM.GetPhyAddr(), (__ubuf__ T*)dqStateV.GetPhyAddr(), | ||
| 643 | + (__ubuf__ T*)var.GetPhyAddr(), (__ubuf__ T*)grad.GetPhyAddr(), gnormScale, | ||
| 644 | + beta1, 1.0f - beta1, beta2, 1.0f - beta2, eps * correction2, stepSize, | ||
| 645 | + weightDecayFactor, validSize, oneRepeatSize, repeatTimes); | ||
| 646 | + } | ||
| 647 | + | ||
| 648 | +private: | ||
| 649 | + TPipe pipe; | ||
| 650 | + | ||
| 651 | + AscendC::TBuf<AscendC::QuePosition::VECCALC> varBuf; | ||
| 652 | + AscendC::TBuf<AscendC::QuePosition::VECCALC> gradBuf; | ||
| 653 | + AscendC::TBuf<AscendC::QuePosition::VECCALC> varFp32Buf; | ||
| 654 | + AscendC::TBuf<AscendC::QuePosition::VECCALC> gradFp32Buf; | ||
| 655 | + AscendC::TBuf<AscendC::QuePosition::VECCALC> stateMBuf; | ||
| 656 | + AscendC::TBuf<AscendC::QuePosition::VECCALC> stateVBuf; | ||
| 657 | + AscendC::TBuf<AscendC::QuePosition::VECCALC> qMapMBuf; | ||
| 658 | + AscendC::TBuf<AscendC::QuePosition::VECCALC> qMapVBuf; | ||
| 659 | + AscendC::TBuf<AscendC::QuePosition::VECCALC> absMaxMBuf; | ||
| 660 | + AscendC::TBuf<AscendC::QuePosition::VECCALC> absMaxVBuf; | ||
| 661 | + AscendC::TBuf<AscendC::QuePosition::VECCALC> calcBuf; | ||
| 662 | + | ||
| 663 | + AscendC::GlobalTensor<T_VAR_GRAD> varGm; | ||
| 664 | + AscendC::GlobalTensor<T_VAR_GRAD> varRefGm; | ||
| 665 | + AscendC::GlobalTensor<T_VAR_GRAD> gradGm; | ||
| 666 | + AscendC::GlobalTensor<uint8_t> stateMGm; | ||
| 667 | + AscendC::GlobalTensor<uint8_t> stateMRefGm; | ||
| 668 | + AscendC::GlobalTensor<uint8_t> stateVGm; | ||
| 669 | + AscendC::GlobalTensor<uint8_t> stateVRefGm; | ||
| 670 | + AscendC::GlobalTensor<T> qMapMGm; | ||
| 671 | + | ||
| 672 | + AscendC::GlobalTensor<T> qMapVGm; | ||
| 673 | + AscendC::GlobalTensor<T> absMaxMGm; | ||
| 674 | + AscendC::GlobalTensor<T> absMaxMRefGm; | ||
| 675 | + AscendC::GlobalTensor<T> absMaxVGm; | ||
| 676 | + AscendC::GlobalTensor<T> absMaxVRefGm; | ||
| 677 | + AscendC::GlobalTensor<U> stepGm; | ||
| 678 | + | ||
| 679 | + AscendC::LocalTensor<T> qMapM; | ||
| 680 | + AscendC::LocalTensor<T> qMapV; | ||
| 681 | + AscendC::LocalTensor<uint8_t> stateM; | ||
| 682 | + AscendC::LocalTensor<uint8_t> stateV; | ||
| 683 | + AscendC::LocalTensor<T> absMaxM; | ||
| 684 | + AscendC::LocalTensor<T> absMaxV; | ||
| 685 | + AscendC::LocalTensor<T_VAR_GRAD> var; | ||
| 686 | + AscendC::LocalTensor<T_VAR_GRAD> grad; | ||
| 687 | + AscendC::LocalTensor<T> varFp32; | ||
| 688 | + AscendC::LocalTensor<T> gradFp32; | ||
| 689 | + | ||
| 690 | + int32_t blockIdx; | ||
| 691 | + float step_ = 0; | ||
| 692 | + | ||
| 693 | + int32_t singleBlockNum; | ||
| 694 | + int32_t singleSize; | ||
| 695 | + | ||
| 696 | + uint64_t useNumCore = 0; | ||
| 697 | + uint64_t lastPreCoreRowWork = 0; | ||
| 698 | + uint64_t notLastCoreNum = 0; | ||
| 699 | + uint64_t notLastPreCoreRowWork = 0; | ||
| 700 | + uint64_t lastCoreLastBlock = 0; | ||
| 701 | + uint64_t lastBlockSize = 0; | ||
| 702 | + int64_t oneCoreDoBlockNumPerRow = 0; | ||
| 703 | + | ||
| 704 | + float stepSize; | ||
| 705 | + float correction2; | ||
| 706 | + float lr; | ||
| 707 | + float beta1; | ||
| 708 | + float beta2; | ||
| 709 | + float weightDecay; | ||
| 710 | + float eps; | ||
| 711 | + float gnormScale; | ||
| 712 | + uint32_t blockSize; | ||
| 713 | + | ||
| 714 | + uint64_t gmOffset = 0; | ||
| 715 | + uint64_t absmaxOffset = 0; | ||
| 716 | +}; | ||
| 717 | +} // namespace ApplyAdamWQuantNS | ||
| 718 | + | ||
| @@ -0,0 +1,711 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 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 apply_adam_w_quant_fp32.h | ||
| 13 | + * \brief | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | +namespace ApplyAdamWQuantNS { | ||
| 21 | +using namespace AscendC; | ||
| 22 | + | ||
| 23 | +using namespace ApplyAdamWQuantNS; | ||
| 24 | + | ||
| 25 | +template <typename T, typename U> | ||
| 26 | +class ApplyAdamWQuant { | ||
| 27 | +public: | ||
| 28 | + __aicore__ inline ApplyAdamWQuant(){}; | ||
| 29 | + __aicore__ inline void Init(GM_ADDR var, GM_ADDR grad, GM_ADDR m, GM_ADDR v, GM_ADDR qmap_m, GM_ADDR qmap_v, | ||
| 30 | + GM_ADDR absmax_m, GM_ADDR absmax_v, GM_ADDR step, GM_ADDR var_ref, GM_ADDR m_ref, | ||
| 31 | + GM_ADDR v_ref, GM_ADDR absmax_m_ref, GM_ADDR absmax_v_ref, | ||
| 32 | + const ApplyAdamWQuantRegbaseTilingData* tilingData) | ||
| 33 | + { | ||
| 34 | + this->blockIdx = AscendC::GetBlockIdx(); | ||
| 35 | + ParseTilingDataFp32(tilingData); | ||
| 36 | + | ||
| 37 | + if (this->blockIdx < notLastCoreNum) { | ||
| 38 | + gmOffset = this->blockIdx * notLastPreCoreRowWork * blockSize * oneCoreDoBlockNumPerRow; | ||
| 39 | + absmaxOffset = this->blockIdx * notLastPreCoreRowWork * oneCoreDoBlockNumPerRow; | ||
| 40 | + } else { | ||
| 41 | + gmOffset = (notLastCoreNum * notLastPreCoreRowWork + | ||
| 42 | + (this->blockIdx - notLastCoreNum) * lastPreCoreRowWork) * | ||
| 43 | + blockSize * oneCoreDoBlockNumPerRow; | ||
| 44 | + absmaxOffset = (notLastCoreNum * notLastPreCoreRowWork + | ||
| 45 | + (this->blockIdx - notLastCoreNum) * lastPreCoreRowWork) * | ||
| 46 | + oneCoreDoBlockNumPerRow; | ||
| 47 | + } | ||
| 48 | + this->singleBlockNum = oneCoreDoBlockNumPerRow; | ||
| 49 | + this->singleSize = blockSize * oneCoreDoBlockNumPerRow; | ||
| 50 | + varGm.SetGlobalBuffer((__gm__ T*)var + gmOffset); | ||
| 51 | + gradGm.SetGlobalBuffer((__gm__ T*)grad + gmOffset); | ||
| 52 | + stateMGm.SetGlobalBuffer((__gm__ uint8_t*)m + gmOffset); | ||
| 53 | + stateVGm.SetGlobalBuffer((__gm__ uint8_t*)v + gmOffset); | ||
| 54 | + qMapMGm.SetGlobalBuffer((__gm__ T*)qmap_m); | ||
| 55 | + qMapVGm.SetGlobalBuffer((__gm__ T*)qmap_v); | ||
| 56 | + absMaxMGm.SetGlobalBuffer((__gm__ T*)absmax_m + absmaxOffset); | ||
| 57 | + absMaxVGm.SetGlobalBuffer((__gm__ T*)absmax_v + absmaxOffset); | ||
| 58 | + stepGm.SetGlobalBuffer((__gm__ U*)step, 1); | ||
| 59 | + varRefGm.SetGlobalBuffer((__gm__ T*)var_ref + gmOffset); | ||
| 60 | + stateMRefGm.SetGlobalBuffer((__gm__ uint8_t*)m_ref + gmOffset); | ||
| 61 | + stateVRefGm.SetGlobalBuffer((__gm__ uint8_t*)v_ref + gmOffset); | ||
| 62 | + absMaxMRefGm.SetGlobalBuffer((__gm__ T*)absmax_m_ref + absmaxOffset); | ||
| 63 | + absMaxVRefGm.SetGlobalBuffer((__gm__ T*)absmax_v_ref + absmaxOffset); | ||
| 64 | + step_ = static_cast<float>(stepGm.GetValue(0)); | ||
| 65 | + | ||
| 66 | + pipe.InitBuffer(varBuf, singleSize * sizeof(T)); | ||
| 67 | + pipe.InitBuffer(gradBuf, singleSize * sizeof(T)); | ||
| 68 | + pipe.InitBuffer(stateMBuf, singleSize * sizeof(T)); | ||
| 69 | + pipe.InitBuffer(stateVBuf, singleSize * sizeof(T)); | ||
| 70 | + pipe.InitBuffer(qMapMBuf, Q_MAP_SIZE * sizeof(T)); | ||
| 71 | + pipe.InitBuffer(qMapVBuf, Q_MAP_SIZE * sizeof(T)); | ||
| 72 | + pipe.InitBuffer(absMaxMBuf, oneCoreDoBlockNumPerRow * sizeof(T)); | ||
| 73 | + pipe.InitBuffer(absMaxVBuf, oneCoreDoBlockNumPerRow * sizeof(T)); | ||
| 74 | + pipe.InitBuffer(calcBuf, CALC_BUF_NUM * singleSize * sizeof(float)); | ||
| 75 | + | ||
| 76 | + this->qMapM = qMapMBuf.Get<T>(); | ||
| 77 | + this->qMapV = qMapVBuf.Get<T>(); | ||
| 78 | + this->stateM = stateMBuf.Get<uint8_t>(); | ||
| 79 | + this->stateV = stateVBuf.Get<uint8_t>(); | ||
| 80 | + this->absMaxM = absMaxMBuf.Get<T>(); | ||
| 81 | + this->absMaxV = absMaxVBuf.Get<T>(); | ||
| 82 | + this->var = varBuf.Get<T>(); | ||
| 83 | + this->grad = gradBuf.Get<T>(); | ||
| 84 | + | ||
| 85 | + step_ += 1; | ||
| 86 | + uint32_t count = AscendC::ONE_BLK_SIZE / sizeof(float); | ||
| 87 | + AscendC::LocalTensor<float> stepTensor = calcBuf.GetWithOffset<float>(count, 0); | ||
| 88 | + AscendC::LocalTensor<float> resTensor = calcBuf.GetWithOffset<float>(count, AscendC::ONE_BLK_SIZE); | ||
| 89 | + AscendC::Duplicate<float>(stepTensor, step_, AscendC::ONE_BLK_SIZE / sizeof(float)); | ||
| 90 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 91 | + | ||
| 92 | + float correction1 = 1 - PowS(resTensor, beta1, stepTensor); | ||
| 93 | + this->correction2 = sqrt(1 - PowS(resTensor, beta2, stepTensor)); | ||
| 94 | + this->stepSize = -lr * this->correction2 / correction1; | ||
| 95 | + } | ||
| 96 | + __aicore__ inline void Process() | ||
| 97 | + { | ||
| 98 | + DataCopyIn<T>(qMapM, qMapMGm, Q_MAP_SIZE); | ||
| 99 | + DataCopyIn<T>(qMapV, qMapVGm, Q_MAP_SIZE); | ||
| 100 | + | ||
| 101 | + int64_t perCoreRowWork = lastPreCoreRowWork; | ||
| 102 | + if (this->blockIdx < notLastCoreNum) { | ||
| 103 | + perCoreRowWork += 1; | ||
| 104 | + } | ||
| 105 | + uint64_t blockOffset = 0; | ||
| 106 | + uint64_t absMaxBlockOffset = 0; | ||
| 107 | + for (int64_t n = 0; n < perCoreRowWork; n++) { | ||
| 108 | + bool isLastRow = static_cast<uint64_t>(this->blockIdx + 1) == useNumCore && n + 1 == perCoreRowWork; | ||
| 109 | + singleBlockNum = isLastRow ? lastCoreLastBlock : oneCoreDoBlockNumPerRow; | ||
| 110 | + singleSize = blockSize * singleBlockNum; | ||
| 111 | + uint32_t validSize = isLastRow ? singleSize - blockSize + lastBlockSize : singleSize; | ||
| 112 | + | ||
| 113 | + DataCopyIn<uint8_t>(stateM, stateMGm[blockOffset], validSize); | ||
| 114 | + DataCopyIn<uint8_t>(stateV, stateVGm[blockOffset], validSize); | ||
| 115 | + | ||
| 116 | + DataCopyIn<T>(absMaxM, absMaxMGm[absMaxBlockOffset], singleBlockNum); | ||
| 117 | + DataCopyIn<T>(absMaxV, absMaxVGm[absMaxBlockOffset], singleBlockNum); | ||
| 118 | + | ||
| 119 | + PipeSync<AscendC::HardEvent::MTE2_V>(); | ||
| 120 | + | ||
| 121 | + DeQuantFp32(stateM, qMapM, absMaxM, calcBuf, singleBlockNum, validSize); | ||
| 122 | + DeQuantFp32(stateV, qMapV, absMaxV, calcBuf, singleBlockNum, validSize); | ||
| 123 | + | ||
| 124 | + DataCopyIn<T>(var, varGm[blockOffset], validSize); | ||
| 125 | + DataCopyIn<T>(grad, gradGm[blockOffset], validSize); | ||
| 126 | + | ||
| 127 | + PipeSync<AscendC::HardEvent::MTE2_V>(); | ||
| 128 | + | ||
| 129 | + UpdateStateAndParamFp32(stateM.template ReinterpretCast<T>(), stateV.template ReinterpretCast<T>(), grad, | ||
| 130 | + var, validSize); | ||
| 131 | + PipeSync<AscendC::HardEvent::V_MTE3>(); | ||
| 132 | + | ||
| 133 | + DataCopyOut<T>(varRefGm[blockOffset], var, validSize); | ||
| 134 | + | ||
| 135 | + QuantMFp32(stateM.template ReinterpretCast<T>(), qMapM, stateM, absMaxM, grad, calcBuf, singleBlockNum); | ||
| 136 | + QuantVFp32(stateV.template ReinterpretCast<T>(), qMapV, stateV, absMaxV, calcBuf, singleBlockNum); | ||
| 137 | + PipeSync<AscendC::HardEvent::V_MTE3>(); | ||
| 138 | + | ||
| 139 | + DataCopyOut<T>(absMaxMRefGm[absMaxBlockOffset], absMaxM, singleBlockNum); | ||
| 140 | + DataCopyOut<T>(absMaxVRefGm[absMaxBlockOffset], absMaxV, singleBlockNum); | ||
| 141 | + DataCopyOut<uint8_t>(stateMRefGm[blockOffset], stateM, validSize); | ||
| 142 | + DataCopyOut<uint8_t>(stateVRefGm[blockOffset], stateV, validSize); | ||
| 143 | + PipeSync<AscendC::HardEvent::MTE3_MTE2>(); | ||
| 144 | + | ||
| 145 | + blockOffset += singleSize; | ||
| 146 | + absMaxBlockOffset += singleBlockNum; | ||
| 147 | + } | ||
| 148 | + } | ||
| 149 | + | ||
| 150 | +private: | ||
| 151 | + __aicore__ inline void ParseTilingDataFp32(const ApplyAdamWQuantRegbaseTilingData* tilingData) | ||
| 152 | + { | ||
| 153 | + useNumCore = tilingData->use_num_core; | ||
| 154 | + lastPreCoreRowWork = tilingData->last_pre_core_row_work; | ||
| 155 | + notLastCoreNum = tilingData->not_last_core_num; | ||
| 156 | + notLastPreCoreRowWork = tilingData->not_last_pre_core_row_work; | ||
| 157 | + lastCoreLastBlock = tilingData->last_core_last_block; | ||
| 158 | + lastBlockSize = tilingData->last_block_size; | ||
| 159 | + oneCoreDoBlockNumPerRow = tilingData->one_core_do_block_num_per_row; | ||
| 160 | + | ||
| 161 | + lr = tilingData->lr; | ||
| 162 | + beta1 = tilingData->beta1; | ||
| 163 | + beta2 = tilingData->beta2; | ||
| 164 | + weightDecay = tilingData->weight_decay; | ||
| 165 | + eps = tilingData->eps; | ||
| 166 | + gnormScale = tilingData->gnorm_scale; | ||
| 167 | + blockSize = tilingData->block_size; | ||
| 168 | + } | ||
| 169 | + | ||
| 170 | + __aicore__ inline void BinarySearchFp32(const AscendC::LocalTensor<T>& normState, | ||
| 171 | + const AscendC::LocalTensor<T>& qMap, AscendC::LocalTensor<uint8_t>& qState, | ||
| 172 | + AscendC::TBuf<>& calcBuf, int32_t singleBlockNum) | ||
| 173 | + { | ||
| 174 | + uint32_t offset = 0; | ||
| 175 | + AscendC::LocalTensor<int32_t> lowerPivot = calcBuf.GetWithOffset<int32_t>(singleSize, offset); | ||
| 176 | + offset += singleSize * sizeof(int32_t); | ||
| 177 | + AscendC::LocalTensor<int32_t> upperPivot = calcBuf.GetWithOffset<int32_t>(singleSize, offset); | ||
| 178 | + offset += singleSize * sizeof(int32_t); | ||
| 179 | + AscendC::LocalTensor<int32_t> pivot = calcBuf.GetWithOffset<int32_t>(singleSize, offset); | ||
| 180 | + offset += singleSize * sizeof(int32_t); | ||
| 181 | + AscendC::LocalTensor<int32_t> gatherOffset = calcBuf.GetWithOffset<int32_t>(singleSize, offset); | ||
| 182 | + offset += singleSize * sizeof(int32_t); | ||
| 183 | + AscendC::LocalTensor<T> stateTmp = calcBuf.GetWithOffset<T>(singleSize, offset); | ||
| 184 | + offset += singleSize * sizeof(T); | ||
| 185 | + AscendC::LocalTensor<uint8_t> higgerMask = calcBuf.GetWithOffset<uint8_t>(singleSize / PER_UINT8_8BITS, offset); | ||
| 186 | + | ||
| 187 | + AscendC::Duplicate<int32_t>(lowerPivot, 0, singleSize); | ||
| 188 | + AscendC::Duplicate<int32_t>(upperPivot, Q_MAP_SIZE - 1, singleSize); | ||
| 189 | + AscendC::Duplicate<int32_t>(pivot, (Q_MAP_SIZE - 1) >> 1, singleSize); | ||
| 190 | + | ||
| 191 | + T midValue = qMap.GetValue((Q_MAP_SIZE - 1) >> 1); | ||
| 192 | + | ||
| 193 | + PipeSync<AscendC::HardEvent::S_V>(); | ||
| 194 | + | ||
| 195 | + AscendC::Duplicate<T>(stateTmp, midValue, singleSize); | ||
| 196 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 197 | + AscendC::Compare<T, uint8_t>(higgerMask, normState, stateTmp, AscendC::CMPMODE::GT, singleSize); | ||
| 198 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 199 | + AscendC::Select<float, uint8_t>( | ||
| 200 | + lowerPivot.template ReinterpretCast<float>(), higgerMask, pivot.template ReinterpretCast<float>(), | ||
| 201 | + lowerPivot.template ReinterpretCast<float>(), AscendC::SELMODE::VSEL_TENSOR_TENSOR_MODE, REPEAT_NUM, | ||
| 202 | + singleSize / REPEAT_NUM, {1, 1, 1, 8, 8, 8}); | ||
| 203 | + AscendC::Select<float, uint8_t>( | ||
| 204 | + upperPivot.template ReinterpretCast<float>(), higgerMask, upperPivot.template ReinterpretCast<float>(), | ||
| 205 | + pivot.template ReinterpretCast<float>(), AscendC::SELMODE::VSEL_TENSOR_TENSOR_MODE, REPEAT_NUM, | ||
| 206 | + singleSize / REPEAT_NUM, {1, 1, 1, 8, 8, 8}); | ||
| 207 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 208 | + | ||
| 209 | + for (int32_t i = 0; i < REPEAT_7_TIMES; ++i) { | ||
| 210 | + AscendC::Add<int32_t>(pivot, lowerPivot, upperPivot, singleSize); | ||
| 211 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 212 | + AscendC::ShiftRight<int32_t>(pivot, pivot, 1, singleSize); | ||
| 213 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 214 | + | ||
| 215 | + AscendC::Muls<int32_t>(gatherOffset, pivot, sizeof(T), singleSize); | ||
| 216 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 217 | + | ||
| 218 | + | ||
| 219 | + for (int i = 0; i < singleSize / Q_MAP_SIZE; i++) { | ||
| 220 | + AscendC::Gather<T>(stateTmp[i * Q_MAP_SIZE], qMap, | ||
| 221 | + gatherOffset.template ReinterpretCast<uint32_t>()[i * Q_MAP_SIZE], 0, Q_MAP_SIZE); | ||
| 222 | + } | ||
| 223 | + | ||
| 224 | + AscendC::Gather<T>(stateTmp, qMap, gatherOffset.template ReinterpretCast<uint32_t>(), 0, singleSize); | ||
| 225 | + | ||
| 226 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 227 | + | ||
| 228 | + AscendC::Compare<T, uint8_t>(higgerMask, normState, stateTmp, AscendC::CMPMODE::GT, singleSize); | ||
| 229 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 230 | + | ||
| 231 | + AscendC::Select<float, uint8_t>( | ||
| 232 | + lowerPivot.template ReinterpretCast<float>(), higgerMask, pivot.template ReinterpretCast<float>(), | ||
| 233 | + lowerPivot.template ReinterpretCast<float>(), AscendC::SELMODE::VSEL_TENSOR_TENSOR_MODE, REPEAT_NUM, | ||
| 234 | + singleSize / REPEAT_NUM, {1, 1, 1, 8, 8, 8}); | ||
| 235 | + | ||
| 236 | + AscendC::Select<float, uint8_t>( | ||
| 237 | + upperPivot.template ReinterpretCast<float>(), higgerMask, upperPivot.template ReinterpretCast<float>(), | ||
| 238 | + pivot.template ReinterpretCast<float>(), AscendC::SELMODE::VSEL_TENSOR_TENSOR_MODE, REPEAT_NUM, | ||
| 239 | + singleSize / REPEAT_NUM, {1, 1, 1, 8, 8, 8}); | ||
| 240 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 241 | + } | ||
| 242 | + | ||
| 243 | + AscendC::LocalTensor<T> lowerState = stateTmp; | ||
| 244 | + AscendC::LocalTensor<T> upperState = pivot.template ReinterpretCast<T>(); | ||
| 245 | + | ||
| 246 | + AscendC::Muls<int32_t>(gatherOffset, lowerPivot, sizeof(T), singleSize); | ||
| 247 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 248 | + | ||
| 249 | + for (int i = 0; i < singleSize / Q_MAP_SIZE; i++) { | ||
| 250 | + AscendC::Gather<T>(lowerState[i * Q_MAP_SIZE], qMap, | ||
| 251 | + gatherOffset.template ReinterpretCast<uint32_t>()[i * Q_MAP_SIZE], 0, Q_MAP_SIZE); | ||
| 252 | + } | ||
| 253 | + | ||
| 254 | + AscendC::Gather<T>(lowerState, qMap, gatherOffset.template ReinterpretCast<uint32_t>(), 0, singleSize); | ||
| 255 | + | ||
| 256 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 257 | + AscendC::Sub<T>(lowerState, normState, lowerState, singleSize); | ||
| 258 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 259 | + AscendC::Abs<T>(lowerState, lowerState, singleSize); | ||
| 260 | + | ||
| 261 | + AscendC::Muls<int32_t>(gatherOffset, upperPivot, sizeof(T), singleSize); | ||
| 262 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 263 | + | ||
| 264 | + | ||
| 265 | + for (int i = 0; i < singleSize / Q_MAP_SIZE; i++) { | ||
| 266 | + AscendC::Gather<T>(upperState[i * Q_MAP_SIZE], qMap, | ||
| 267 | + gatherOffset.template ReinterpretCast<uint32_t>()[i * Q_MAP_SIZE], 0, Q_MAP_SIZE); | ||
| 268 | + } | ||
| 269 | + | ||
| 270 | + AscendC::Gather<T>(upperState, qMap, gatherOffset.template ReinterpretCast<uint32_t>(), 0, singleSize); | ||
| 271 | + | ||
| 272 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 273 | + AscendC::Sub<T>(upperState, normState, upperState, singleSize); | ||
| 274 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 275 | + AscendC::Abs<T>(upperState, upperState, singleSize); | ||
| 276 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 277 | + | ||
| 278 | + AscendC::Compare<T, uint8_t>(higgerMask, lowerState, upperState, AscendC::CMPMODE::LE, singleSize); | ||
| 279 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 280 | + | ||
| 281 | + AscendC::Select<float, uint8_t>( | ||
| 282 | + pivot.template ReinterpretCast<float>(), higgerMask, lowerPivot.template ReinterpretCast<float>(), | ||
| 283 | + upperPivot.template ReinterpretCast<float>(), AscendC::SELMODE::VSEL_TENSOR_TENSOR_MODE, REPEAT_NUM, | ||
| 284 | + singleSize / REPEAT_NUM, {1, 1, 1, 8, 8, 8}); | ||
| 285 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 286 | + AscendC::Cast<int16_t, int32_t>(stateTmp.template ReinterpretCast<int16_t>(), pivot, | ||
| 287 | + AscendC::RoundMode::CAST_NONE, singleSize); | ||
| 288 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 289 | + AscendC::Cast<half, int16_t>(pivot.template ReinterpretCast<half>(), | ||
| 290 | + stateTmp.template ReinterpretCast<int16_t>(), AscendC::RoundMode::CAST_NONE, | ||
| 291 | + singleSize); | ||
| 292 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 293 | + AscendC::Cast<uint8_t, half>(qState, pivot.template ReinterpretCast<half>(), AscendC::RoundMode::CAST_NONE, | ||
| 294 | + singleSize); | ||
| 295 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 296 | + } | ||
| 297 | + | ||
| 298 | + __aicore__ inline void BinarySearchScaledFp32(const AscendC::LocalTensor<T>& state, | ||
| 299 | + const AscendC::LocalTensor<T>& qMap, | ||
| 300 | + const AscendC::LocalTensor<T>& absMax, | ||
| 301 | + AscendC::LocalTensor<uint8_t>& qState, AscendC::TBuf<>& calcBuf, | ||
| 302 | + int32_t singleBlockNum) | ||
| 303 | + { | ||
| 304 | + uint32_t offset = 0; | ||
| 305 | + AscendC::LocalTensor<int32_t> lowerPivot = calcBuf.GetWithOffset<int32_t>(singleSize, offset); | ||
| 306 | + offset += singleSize * sizeof(int32_t); | ||
| 307 | + AscendC::LocalTensor<int32_t> upperPivot = calcBuf.GetWithOffset<int32_t>(singleSize, offset); | ||
| 308 | + offset += singleSize * sizeof(int32_t); | ||
| 309 | + AscendC::LocalTensor<int32_t> pivot = calcBuf.GetWithOffset<int32_t>(singleSize, offset); | ||
| 310 | + offset += singleSize * sizeof(int32_t); | ||
| 311 | + AscendC::LocalTensor<int32_t> gatherOffset = calcBuf.GetWithOffset<int32_t>(singleSize, offset); | ||
| 312 | + offset += singleSize * sizeof(int32_t); | ||
| 313 | + AscendC::LocalTensor<T> stateTmp = calcBuf.GetWithOffset<T>(singleSize, offset); | ||
| 314 | + offset += singleSize * sizeof(T); | ||
| 315 | + AscendC::LocalTensor<uint8_t> higgerMask = calcBuf.GetWithOffset<uint8_t>(singleSize / PER_UINT8_8BITS, offset); | ||
| 316 | + AscendC::LocalTensor<T> absMaxBrcb = gatherOffset.template ReinterpretCast<T>(); | ||
| 317 | + | ||
| 318 | + uint32_t srcShape[2] = {static_cast<uint32_t>(singleBlockNum), 1}; | ||
| 319 | + uint32_t dstShape[2] = {static_cast<uint32_t>(singleBlockNum), blockSize}; | ||
| 320 | + | ||
| 321 | + AscendC::Duplicate<int32_t>(lowerPivot, 0, singleSize); | ||
| 322 | + AscendC::Duplicate<int32_t>(upperPivot, Q_MAP_SIZE - 1, singleSize); | ||
| 323 | + AscendC::Duplicate<int32_t>(pivot, (Q_MAP_SIZE - 1) >> 1, singleSize); | ||
| 324 | + | ||
| 325 | + T midValue = qMap.GetValue((Q_MAP_SIZE - 1) >> 1); | ||
| 326 | + | ||
| 327 | + PipeSync<AscendC::HardEvent::S_V>(); | ||
| 328 | + | ||
| 329 | + AscendC::Duplicate<T>(stateTmp, midValue, singleSize); | ||
| 330 | + AscendC::Broadcast<T, BROADCAST_DIM2, BROADCAST_AXIS1>(absMaxBrcb, absMax, dstShape, srcShape); | ||
| 331 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 332 | + AscendC::Mul<T>(stateTmp, stateTmp, absMaxBrcb, singleSize); | ||
| 333 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 334 | + AscendC::Compare<T, uint8_t>(higgerMask, state, stateTmp, AscendC::CMPMODE::GT, singleSize); | ||
| 335 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 336 | + | ||
| 337 | + AscendC::Select<float, uint8_t>( | ||
| 338 | + lowerPivot.template ReinterpretCast<float>(), higgerMask, pivot.template ReinterpretCast<float>(), | ||
| 339 | + lowerPivot.template ReinterpretCast<float>(), AscendC::SELMODE::VSEL_TENSOR_TENSOR_MODE, REPEAT_NUM, | ||
| 340 | + singleSize / REPEAT_NUM, {1, 1, 1, 8, 8, 8}); | ||
| 341 | + AscendC::Select<float, uint8_t>( | ||
| 342 | + upperPivot.template ReinterpretCast<float>(), higgerMask, upperPivot.template ReinterpretCast<float>(), | ||
| 343 | + pivot.template ReinterpretCast<float>(), AscendC::SELMODE::VSEL_TENSOR_TENSOR_MODE, REPEAT_NUM, | ||
| 344 | + singleSize / REPEAT_NUM, {1, 1, 1, 8, 8, 8}); | ||
| 345 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 346 | + | ||
| 347 | + for (int32_t i = 0; i < REPEAT_7_TIMES; ++i) { | ||
| 348 | + AscendC::Add<int32_t>(pivot, lowerPivot, upperPivot, singleSize); | ||
| 349 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 350 | + AscendC::ShiftRight<int32_t>(pivot, pivot, 1, singleSize); | ||
| 351 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 352 | + | ||
| 353 | + AscendC::Muls<int32_t>(gatherOffset, pivot, sizeof(T), singleSize); | ||
| 354 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 355 | + | ||
| 356 | + | ||
| 357 | + for (int i = 0; i < singleSize / Q_MAP_SIZE; i++) { | ||
| 358 | + AscendC::Gather<T>(stateTmp[i * Q_MAP_SIZE], qMap, | ||
| 359 | + gatherOffset.template ReinterpretCast<uint32_t>()[i * Q_MAP_SIZE], 0, Q_MAP_SIZE); | ||
| 360 | + } | ||
| 361 | + | ||
| 362 | + AscendC::Gather<T>(stateTmp, qMap, gatherOffset.template ReinterpretCast<uint32_t>(), 0, singleSize); | ||
| 363 | + | ||
| 364 | + AscendC::Broadcast<T, BROADCAST_DIM2, BROADCAST_AXIS1>(absMaxBrcb, absMax, dstShape, srcShape); | ||
| 365 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 366 | + AscendC::Mul<T>(stateTmp, stateTmp, absMaxBrcb, singleSize); | ||
| 367 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 368 | + | ||
| 369 | + AscendC::Compare<T, uint8_t>(higgerMask, state, stateTmp, AscendC::CMPMODE::GT, singleSize); | ||
| 370 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 371 | + | ||
| 372 | + AscendC::Select<float, uint8_t>( | ||
| 373 | + lowerPivot.template ReinterpretCast<float>(), higgerMask, pivot.template ReinterpretCast<float>(), | ||
| 374 | + lowerPivot.template ReinterpretCast<float>(), AscendC::SELMODE::VSEL_TENSOR_TENSOR_MODE, REPEAT_NUM, | ||
| 375 | + singleSize / REPEAT_NUM, {1, 1, 1, 8, 8, 8}); | ||
| 376 | + | ||
| 377 | + AscendC::Select<float, uint8_t>( | ||
| 378 | + upperPivot.template ReinterpretCast<float>(), higgerMask, upperPivot.template ReinterpretCast<float>(), | ||
| 379 | + pivot.template ReinterpretCast<float>(), AscendC::SELMODE::VSEL_TENSOR_TENSOR_MODE, REPEAT_NUM, | ||
| 380 | + singleSize / REPEAT_NUM, {1, 1, 1, 8, 8, 8}); | ||
| 381 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 382 | + } | ||
| 383 | + | ||
| 384 | + AscendC::LocalTensor<T> lowerState = stateTmp; | ||
| 385 | + AscendC::LocalTensor<T> upperState = pivot.template ReinterpretCast<T>(); | ||
| 386 | + | ||
| 387 | + AscendC::Muls<int32_t>(gatherOffset, lowerPivot, sizeof(T), singleSize); | ||
| 388 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 389 | + | ||
| 390 | + for (int i = 0; i < singleSize / Q_MAP_SIZE; i++) { | ||
| 391 | + AscendC::Gather<T>(lowerState[i * Q_MAP_SIZE], qMap, | ||
| 392 | + gatherOffset.template ReinterpretCast<uint32_t>()[i * Q_MAP_SIZE], 0, Q_MAP_SIZE); | ||
| 393 | + } | ||
| 394 | + | ||
| 395 | + AscendC::Gather<T>(lowerState, qMap, gatherOffset.template ReinterpretCast<uint32_t>(), 0, singleSize); | ||
| 396 | + | ||
| 397 | + AscendC::Broadcast<T, BROADCAST_DIM2, BROADCAST_AXIS1>(absMaxBrcb, absMax, dstShape, srcShape); | ||
| 398 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 399 | + AscendC::Mul<T>(lowerState, lowerState, absMaxBrcb, singleSize); | ||
| 400 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 401 | + AscendC::Sub<T>(lowerState, state, lowerState, singleSize); | ||
| 402 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 403 | + AscendC::Abs<T>(lowerState, lowerState, singleSize); | ||
| 404 | + | ||
| 405 | + AscendC::Muls<int32_t>(gatherOffset, upperPivot, sizeof(T), singleSize); | ||
| 406 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 407 | + | ||
| 408 | + | ||
| 409 | + for (int i = 0; i < singleSize / Q_MAP_SIZE; i++) { | ||
| 410 | + AscendC::Gather<T>(upperState[i * Q_MAP_SIZE], qMap, | ||
| 411 | + gatherOffset.template ReinterpretCast<uint32_t>()[i * Q_MAP_SIZE], 0, Q_MAP_SIZE); | ||
| 412 | + } | ||
| 413 | + | ||
| 414 | + AscendC::Gather<T>(upperState, qMap, gatherOffset.template ReinterpretCast<uint32_t>(), 0, singleSize); | ||
| 415 | + | ||
| 416 | + AscendC::Broadcast<T, BROADCAST_DIM2, BROADCAST_AXIS1>(absMaxBrcb, absMax, dstShape, srcShape); | ||
| 417 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 418 | + AscendC::Mul<T>(upperState, upperState, absMaxBrcb, singleSize); | ||
| 419 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 420 | + AscendC::Sub<T>(upperState, state, upperState, singleSize); | ||
| 421 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 422 | + AscendC::Abs<T>(upperState, upperState, singleSize); | ||
| 423 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 424 | + | ||
| 425 | + AscendC::Compare<T, uint8_t>(higgerMask, lowerState, upperState, AscendC::CMPMODE::LE, singleSize); | ||
| 426 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 427 | + | ||
| 428 | + AscendC::Select<float, uint8_t>( | ||
| 429 | + pivot.template ReinterpretCast<float>(), higgerMask, lowerPivot.template ReinterpretCast<float>(), | ||
| 430 | + upperPivot.template ReinterpretCast<float>(), AscendC::SELMODE::VSEL_TENSOR_TENSOR_MODE, REPEAT_NUM, | ||
| 431 | + singleSize / REPEAT_NUM, {1, 1, 1, 8, 8, 8}); | ||
| 432 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 433 | + AscendC::Cast<int16_t, int32_t>(stateTmp.template ReinterpretCast<int16_t>(), pivot, | ||
| 434 | + AscendC::RoundMode::CAST_NONE, singleSize); | ||
| 435 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 436 | + AscendC::Cast<half, int16_t>(pivot.template ReinterpretCast<half>(), | ||
| 437 | + stateTmp.template ReinterpretCast<int16_t>(), AscendC::RoundMode::CAST_NONE, | ||
| 438 | + singleSize); | ||
| 439 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 440 | + AscendC::Cast<uint8_t, half>(qState, pivot.template ReinterpretCast<half>(), AscendC::RoundMode::CAST_NONE, | ||
| 441 | + singleSize); | ||
| 442 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 443 | + } | ||
| 444 | + | ||
| 445 | + __aicore__ inline void CheckSignFp32(const AscendC::LocalTensor<T>& normState, const AscendC::LocalTensor<T>& qMap, | ||
| 446 | + AscendC::LocalTensor<uint8_t>& qState, AscendC::TBuf<>& calcBuf, | ||
| 447 | + int32_t singleBlockNum) | ||
| 448 | + { | ||
| 449 | + // Match golden exactly: if normalized state and selected qmap have opposite | ||
| 450 | + // signs, move the code by one step toward the normalized state's sign. | ||
| 451 | + // Use int16 arithmetic (A2-style) to avoid float rounding in index conversion. | ||
| 452 | + uint32_t offset = 0; | ||
| 453 | + AscendC::LocalTensor<int32_t> gatherOffset = calcBuf.GetWithOffset<int32_t>(singleSize, offset); | ||
| 454 | + offset += singleSize * sizeof(int32_t); | ||
| 455 | + AscendC::LocalTensor<T> dq = calcBuf.GetWithOffset<T>(singleSize, offset); | ||
| 456 | + offset += singleSize * sizeof(T); | ||
| 457 | + AscendC::LocalTensor<int16_t> idxI = calcBuf.GetWithOffset<int16_t>(singleSize, offset); | ||
| 458 | + offset += singleSize * sizeof(int16_t); | ||
| 459 | + AscendC::LocalTensor<T> zero = calcBuf.GetWithOffset<T>(singleSize, offset); | ||
| 460 | + offset += singleSize * sizeof(T); | ||
| 461 | + AscendC::LocalTensor<int16_t> adjustedI = calcBuf.GetWithOffset<int16_t>(singleSize, offset); | ||
| 462 | + offset += singleSize * sizeof(int16_t); | ||
| 463 | + const int32_t maskBytes = singleSize / PER_UINT8_8BITS; | ||
| 464 | + AscendC::LocalTensor<uint8_t> normPosMask = calcBuf.GetWithOffset<uint8_t>(maskBytes, offset); | ||
| 465 | + offset += maskBytes; | ||
| 466 | + AscendC::LocalTensor<uint8_t> normNegMask = calcBuf.GetWithOffset<uint8_t>(maskBytes, offset); | ||
| 467 | + offset += maskBytes; | ||
| 468 | + AscendC::LocalTensor<uint8_t> qPosMask = calcBuf.GetWithOffset<uint8_t>(maskBytes, offset); | ||
| 469 | + offset += maskBytes; | ||
| 470 | + AscendC::LocalTensor<uint8_t> qNegMask = calcBuf.GetWithOffset<uint8_t>(maskBytes, offset); | ||
| 471 | + AscendC::LocalTensor<half> halfBuf = gatherOffset.template ReinterpretCast<half>(); | ||
| 472 | + | ||
| 473 | + const int32_t selRepeat = singleSize / REPEAT_NUM_128; | ||
| 474 | + | ||
| 475 | + // idxI = int16(qState) — exact since values are 0-255 | ||
| 476 | + AscendC::Cast<half, uint8_t>(halfBuf, qState, AscendC::RoundMode::CAST_NONE, singleSize); | ||
| 477 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 478 | + AscendC::Cast<int16_t, half>(idxI, halfBuf, AscendC::RoundMode::CAST_RINT, singleSize); | ||
| 479 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 480 | + | ||
| 481 | + // dq = qMap[idxI] | ||
| 482 | + AscendC::Cast<int32_t, int16_t>(gatherOffset, idxI, AscendC::RoundMode::CAST_NONE, singleSize); | ||
| 483 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 484 | + AscendC::Muls<int32_t>(gatherOffset, gatherOffset, sizeof(T), singleSize); | ||
| 485 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 486 | + AscendC::Gather<T>(dq, qMap, gatherOffset.template ReinterpretCast<uint32_t>(), 0, singleSize); | ||
| 487 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 488 | + | ||
| 489 | + AscendC::Duplicate<T>(zero, static_cast<T>(0.0f), singleSize); | ||
| 490 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 491 | + AscendC::Compare<T, uint8_t>(normPosMask, normState, zero, AscendC::CMPMODE::GT, singleSize); | ||
| 492 | + AscendC::Compare<T, uint8_t>(normNegMask, normState, zero, AscendC::CMPMODE::LT, singleSize); | ||
| 493 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 494 | + AscendC::Compare<T, uint8_t>(qPosMask, dq, zero, AscendC::CMPMODE::GT, singleSize); | ||
| 495 | + AscendC::Compare<T, uint8_t>(qNegMask, dq, zero, AscendC::CMPMODE::LT, singleSize); | ||
| 496 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 497 | + AscendC::And(normPosMask, normPosMask, qNegMask, maskBytes); | ||
| 498 | + AscendC::And(normNegMask, normNegMask, qPosMask, maskBytes); | ||
| 499 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 500 | + | ||
| 501 | + // Adjust idxI by ±1 in int16 space (avoids float rounding) | ||
| 502 | + AscendC::Adds<int16_t>(adjustedI, idxI, static_cast<int16_t>(1), singleSize); | ||
| 503 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 504 | + AscendC::Select<int16_t, uint8_t>(idxI, normPosMask, adjustedI, idxI, AscendC::SELMODE::VSEL_TENSOR_TENSOR_MODE, | ||
| 505 | + REPEAT_NUM_128, selRepeat, {1, 1, 1, 8, 8, 8}); | ||
| 506 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 507 | + AscendC::Adds<int16_t>(adjustedI, idxI, static_cast<int16_t>(-1), singleSize); | ||
| 508 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 509 | + AscendC::Select<int16_t, uint8_t>(idxI, normNegMask, adjustedI, idxI, AscendC::SELMODE::VSEL_TENSOR_TENSOR_MODE, | ||
| 510 | + REPEAT_NUM_128, selRepeat, {1, 1, 1, 8, 8, 8}); | ||
| 511 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 512 | + | ||
| 513 | + // Clamp to [0, 255] | ||
| 514 | + AscendC::Maxs<int16_t>(idxI, idxI, static_cast<int16_t>(0), singleSize); | ||
| 515 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 516 | + AscendC::Mins<int16_t>(idxI, idxI, static_cast<int16_t>(Q_MAP_SIZE - 1), singleSize); | ||
| 517 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 518 | + | ||
| 519 | + // int16 → half → uint8 (exact, no rounding) | ||
| 520 | + AscendC::Cast<half, int16_t>(halfBuf, idxI, AscendC::RoundMode::CAST_NONE, singleSize); | ||
| 521 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 522 | + AscendC::Cast<uint8_t, half>(qState, halfBuf, AscendC::RoundMode::CAST_NONE, singleSize); | ||
| 523 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 524 | + } | ||
| 525 | + | ||
| 526 | + __aicore__ inline void NormlizeFp32(const AscendC::LocalTensor<T>& state, const AscendC::LocalTensor<T>& absMax, | ||
| 527 | + AscendC::TBuf<>& calcBuf, int32_t singleBlockNum) | ||
| 528 | + { | ||
| 529 | + AscendC::LocalTensor<T> absState = calcBuf.GetWithOffset<T>(singleSize, 0); | ||
| 530 | + AscendC::LocalTensor<T> absMaxTmp = calcBuf.GetWithOffset<T>(singleSize, singleSize * sizeof(T)); | ||
| 531 | + AscendC::LocalTensor<T> absMaxBrcb = calcBuf.GetWithOffset<T>(singleSize, 2 * singleSize * sizeof(T)); | ||
| 532 | + | ||
| 533 | + AscendC::Abs<T>(absState, state, singleSize); | ||
| 534 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 535 | + | ||
| 536 | + uint32_t mask = AscendC::ONE_REPEAT_BYTE_SIZE / sizeof(T); | ||
| 537 | + uint32_t repeat = singleSize / mask; | ||
| 538 | + AscendC::BlockReduceMax<T>(absMaxTmp, absState, repeat, mask, 1, 1, STRIDE_8); | ||
| 539 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 540 | + AscendC::WholeReduceMax<T>(absMax, absMaxTmp, blockSize / (AscendC::ONE_BLK_SIZE / sizeof(T)), singleBlockNum, | ||
| 541 | + 1, 1, PER_4NUM_ONEMAX, AscendC::ReduceOrder::ORDER_ONLY_VALUE); | ||
| 542 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 543 | + | ||
| 544 | + uint32_t srcShape[2] = {static_cast<uint32_t>(singleBlockNum), 1}; | ||
| 545 | + uint32_t dstShape[2] = {static_cast<uint32_t>(singleBlockNum), blockSize}; | ||
| 546 | + AscendC::Broadcast<T, BROADCAST_DIM2, BROADCAST_AXIS1>(absMaxBrcb, absMax, dstShape, srcShape); | ||
| 547 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 548 | + AscendC::Div<T>(state, state, absMaxBrcb, singleSize); | ||
这里按 absmax 归一化没有做零保护,而本 PR 新增的 golden 里 _quantize_state 明确写了 denom = where(absmax == 0, 1, absmax)。整个 256 元素的 block 全为零时(首步 m 全零、稀疏梯度都会出现),kernel 这边会 inf 或 nan,随后进二分搜索得到的量化码完全是垃圾,golden 那边得到的是 0,两边直接对不上。fp16.h 的 Normlize 同一处也一样。建议按 golden 的写法先把 absmax 为 0 的位置换成 1 再除。 ![]() ![]() | |||
| 549 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 550 | + } | ||
| 551 | + | ||
| 552 | + __aicore__ inline void CalcAbsMaxFp32(const AscendC::LocalTensor<T>& state, const AscendC::LocalTensor<T>& absMax, | ||
| 553 | + AscendC::TBuf<>& calcBuf, int32_t singleBlockNum) | ||
| 554 | + { | ||
| 555 | + AscendC::LocalTensor<T> absState = calcBuf.GetWithOffset<T>(singleSize, 0); | ||
| 556 | + AscendC::LocalTensor<T> absMaxTmp = calcBuf.GetWithOffset<T>(singleSize, singleSize * sizeof(T)); | ||
| 557 | + | ||
| 558 | + AscendC::Abs<T>(absState, state, singleSize); | ||
| 559 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 560 | + | ||
| 561 | + uint32_t mask = AscendC::ONE_REPEAT_BYTE_SIZE / sizeof(T); | ||
| 562 | + uint32_t repeat = singleSize / mask; | ||
| 563 | + AscendC::BlockReduceMax<T>(absMaxTmp, absState, repeat, mask, 1, 1, STRIDE_8); | ||
| 564 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 565 | + AscendC::WholeReduceMax<T>(absMax, absMaxTmp, blockSize / (AscendC::ONE_BLK_SIZE / sizeof(T)), singleBlockNum, | ||
| 566 | + 1, 1, PER_4NUM_ONEMAX, AscendC::ReduceOrder::ORDER_ONLY_VALUE); | ||
| 567 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 568 | + } | ||
| 569 | + | ||
| 570 | + __aicore__ inline void QuantMFp32(const AscendC::LocalTensor<T>& state, const AscendC::LocalTensor<T>& qMap, | ||
| 571 | + AscendC::LocalTensor<uint8_t>& qState, const AscendC::LocalTensor<T>& absMax, | ||
| 572 | + AscendC::LocalTensor<T>& normStateTmp, AscendC::TBuf<>& calcBuf, | ||
| 573 | + int32_t singleBlockNum) | ||
| 574 | + { | ||
| 575 | + NormlizeFp32(state, absMax, calcBuf, singleBlockNum); | ||
| 576 | + | ||
| 577 | + AscendC::Adds<T>(normStateTmp, state, static_cast<T>(0.0f), singleSize); | ||
| 578 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 579 | + | ||
| 580 | + BinarySearchFp32(state, qMap, qState, calcBuf, singleBlockNum); | ||
| 581 | + | ||
| 582 | + CheckSignFp32(normStateTmp, qMap, qState, calcBuf, singleBlockNum); | ||
| 583 | + } | ||
| 584 | + | ||
| 585 | + __aicore__ inline void QuantVFp32(const AscendC::LocalTensor<T>& state, const AscendC::LocalTensor<T>& qMap, | ||
| 586 | + AscendC::LocalTensor<uint8_t>& qState, const AscendC::LocalTensor<T>& absMax, | ||
| 587 | + AscendC::TBuf<>& calcBuf, int32_t singleBlockNum) | ||
| 588 | + { | ||
| 589 | + NormlizeFp32(state, absMax, calcBuf, singleBlockNum); | ||
| 590 | + BinarySearchFp32(state, qMap, qState, calcBuf, singleBlockNum); | ||
| 591 | + } | ||
| 592 | + | ||
| 593 | + __aicore__ inline void DeQuantFp32(const AscendC::LocalTensor<uint8_t>& state, const AscendC::LocalTensor<T>& qMap, | ||
| 594 | + AscendC::LocalTensor<T>& absMax, AscendC::TBuf<>& calcBuf, | ||
| 595 | + int32_t singleBlockNum, uint32_t validSize) | ||
| 596 | + { | ||
| 597 | + uint32_t offset = 0; | ||
| 598 | + AscendC::LocalTensor<T> dqState = calcBuf.GetWithOffset<T>(singleSize, offset); | ||
| 599 | + offset += singleSize * sizeof(T); | ||
| 600 | + AscendC::LocalTensor<int32_t> gatherOffset = calcBuf.GetWithOffset<int32_t>(singleSize, offset); | ||
| 601 | + offset += singleSize * sizeof(int32_t); | ||
| 602 | + AscendC::LocalTensor<T> absMaxBrcb = calcBuf.GetWithOffset<T>(singleSize, offset); | ||
| 603 | + | ||
| 604 | + AscendC::Cast<half, uint8_t>(gatherOffset[singleSize >> 1].template ReinterpretCast<half>(), state, | ||
| 605 | + AscendC::RoundMode::CAST_NONE, singleSize); | ||
| 606 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 607 | + AscendC::Cast<int32_t, half>(gatherOffset, gatherOffset[singleSize >> 1].template ReinterpretCast<half>(), | ||
| 608 | + AscendC::RoundMode::CAST_RINT, singleSize); | ||
| 609 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 610 | + AscendC::Muls<int32_t>(gatherOffset, gatherOffset, sizeof(T), singleSize); | ||
| 611 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 612 | + | ||
| 613 | + for (int i = 0; i < singleSize / Q_MAP_SIZE; i++) { | ||
| 614 | + AscendC::Gather<T>(dqState[i * Q_MAP_SIZE], qMap, | ||
| 615 | + gatherOffset.template ReinterpretCast<uint32_t>()[i * Q_MAP_SIZE], 0, Q_MAP_SIZE); | ||
| 616 | + } | ||
| 617 | + | ||
| 618 | + AscendC::Gather<T>(dqState, qMap, gatherOffset.template ReinterpretCast<uint32_t>(), 0, singleSize); | ||
| 619 | + | ||
| 620 | + | ||
| 621 | + uint32_t srcShape[2] = {static_cast<uint32_t>(singleBlockNum), 1}; | ||
| 622 | + uint32_t dstShape[2] = {static_cast<uint32_t>(singleBlockNum), blockSize}; | ||
| 623 | + AscendC::Broadcast<T, BROADCAST_DIM2, BROADCAST_AXIS1>(absMaxBrcb, absMax, dstShape, srcShape); | ||
| 624 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 625 | + if (validSize < static_cast<uint32_t>(singleSize)) { | ||
| 626 | + AscendC::Duplicate<T>(state.template ReinterpretCast<T>(), static_cast<T>(0), singleSize); | ||
| 627 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 628 | + } | ||
| 629 | + AscendC::Mul<T>(state.template ReinterpretCast<T>(), dqState, absMaxBrcb, validSize); | ||
| 630 | + AscendC::PipeBarrier<PIPE_V>(); | ||
| 631 | + } | ||
| 632 | + | ||
| 633 | + __aicore__ inline void UpdateStateAndParamFp32(const AscendC::LocalTensor<T>& dqStateM, | ||
| 634 | + const AscendC::LocalTensor<T>& dqStateV, | ||
| 635 | + AscendC::LocalTensor<T>& grad, AscendC::LocalTensor<T>& var, | ||
| 636 | + uint32_t validSize) | ||
| 637 | + { | ||
| 638 | + constexpr uint32_t oneRepeatSize = AscendC::GetVecLen() / sizeof(T); | ||
| 639 | + uint16_t repeatTimes = AscendC::CeilDivision(validSize, oneRepeatSize); | ||
| 640 | + float weightDecayFactor = weightDecay > 0.0f ? 1.0f - lr * weightDecay : 1.0f; | ||
| 641 | + asc_vf_call<AdamWQuantUpdateVF<T>>((__ubuf__ T*)dqStateM.GetPhyAddr(), (__ubuf__ T*)dqStateV.GetPhyAddr(), | ||
| 642 | + (__ubuf__ T*)var.GetPhyAddr(), (__ubuf__ T*)grad.GetPhyAddr(), gnormScale, | ||
| 643 | + beta1, 1.0f - beta1, beta2, 1.0f - beta2, eps * correction2, stepSize, | ||
| 644 | + weightDecayFactor, validSize, oneRepeatSize, repeatTimes); | ||
| 645 | + } | ||
| 646 | + | ||
| 647 | +private: | ||
| 648 | + TPipe pipe; | ||
TPipe 放在算子类内部是有明确代价的,实测 scalar 耗时会多出一成七左右,规范里要求在 kernel 入口创建、类里只存指针。apply_adam_w_quant.cpp 那个入口现在没有创建 TPipe,建议把 pipe 提到入口,Init 改成收一个 TPipe*。fp16.h 同样。文件头注释写着「kernel 入口风格对齐 norm/deep_norm」,但 deep_norm 是在入口建 pipe 的。 ![]() ![]() | |||
| 649 | + | ||
| 650 | + AscendC::TBuf<AscendC::QuePosition::VECCALC> varBuf; | ||
| 651 | + AscendC::TBuf<AscendC::QuePosition::VECCALC> gradBuf; | ||
| 652 | + AscendC::TBuf<AscendC::QuePosition::VECCALC> stateMBuf; | ||
| 653 | + AscendC::TBuf<AscendC::QuePosition::VECCALC> stateVBuf; | ||
| 654 | + AscendC::TBuf<AscendC::QuePosition::VECCALC> qMapMBuf; | ||
| 655 | + AscendC::TBuf<AscendC::QuePosition::VECCALC> qMapVBuf; | ||
| 656 | + AscendC::TBuf<AscendC::QuePosition::VECCALC> absMaxMBuf; | ||
| 657 | + AscendC::TBuf<AscendC::QuePosition::VECCALC> absMaxVBuf; | ||
| 658 | + AscendC::TBuf<AscendC::QuePosition::VECCALC> calcBuf; | ||
| 659 | + | ||
| 660 | + AscendC::GlobalTensor<T> varGm; | ||
| 661 | + AscendC::GlobalTensor<T> varRefGm; | ||
| 662 | + AscendC::GlobalTensor<T> gradGm; | ||
| 663 | + AscendC::GlobalTensor<uint8_t> stateMGm; | ||
| 664 | + AscendC::GlobalTensor<uint8_t> stateMRefGm; | ||
| 665 | + AscendC::GlobalTensor<uint8_t> stateVGm; | ||
| 666 | + AscendC::GlobalTensor<uint8_t> stateVRefGm; | ||
| 667 | + AscendC::GlobalTensor<T> qMapMGm; | ||
| 668 | + AscendC::GlobalTensor<T> qMapVGm; | ||
| 669 | + AscendC::GlobalTensor<T> absMaxMGm; | ||
| 670 | + AscendC::GlobalTensor<T> absMaxMRefGm; | ||
| 671 | + AscendC::GlobalTensor<T> absMaxVGm; | ||
| 672 | + AscendC::GlobalTensor<T> absMaxVRefGm; | ||
| 673 | + AscendC::GlobalTensor<U> stepGm; | ||
| 674 | + | ||
| 675 | + AscendC::LocalTensor<T> qMapM; | ||
| 676 | + AscendC::LocalTensor<T> qMapV; | ||
| 677 | + AscendC::LocalTensor<uint8_t> stateM; | ||
| 678 | + AscendC::LocalTensor<uint8_t> stateV; | ||
| 679 | + AscendC::LocalTensor<T> absMaxM; | ||
| 680 | + AscendC::LocalTensor<T> absMaxV; | ||
| 681 | + AscendC::LocalTensor<T> var; | ||
| 682 | + AscendC::LocalTensor<T> grad; | ||
| 683 | + | ||
| 684 | + int32_t blockIdx; | ||
| 685 | + float step_ = 0; | ||
| 686 | + | ||
| 687 | + int32_t singleBlockNum; | ||
| 688 | + int32_t singleSize; | ||
| 689 | + uint64_t useNumCore = 0; | ||
| 690 | + uint64_t lastPreCoreRowWork = 0; | ||
| 691 | + uint64_t notLastCoreNum = 0; | ||
| 692 | + uint64_t notLastPreCoreRowWork = 0; | ||
| 693 | + uint64_t lastCoreLastBlock = 0; | ||
| 694 | + uint64_t lastBlockSize = 0; | ||
| 695 | + int64_t oneCoreDoBlockNumPerRow = 0; | ||
| 696 | + | ||
| 697 | + float stepSize; | ||
| 698 | + float correction2; | ||
| 699 | + float lr; | ||
| 700 | + float beta1; | ||
| 701 | + float beta2; | ||
| 702 | + float weightDecay; | ||
| 703 | + float eps; | ||
| 704 | + float gnormScale; | ||
| 705 | + uint32_t blockSize; | ||
| 706 | + | ||
| 707 | + uint64_t gmOffset = 0; | ||
| 708 | + uint64_t absmaxOffset = 0; | ||
| 709 | +}; | ||
| 710 | +} // namespace ApplyAdamWQuantNS | ||
| 711 | + | ||
| @@ -0,0 +1,47 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 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 | + * NOTE: Portions of this code were AI-generated and have been | ||
| 11 | + * technically reviewed for functional accuracy and security | ||
| 12 | + */ | ||
| 13 | + | ||
| 14 | +/*! | ||
| 15 | + * \file apply_adam_w_quant_tiling_data.h | ||
| 16 | + * \brief ApplyAdamWQuant arch35 (Ascend950) plain tiling-data struct. | ||
| 17 | + * | ||
| 18 | + * arch35 走 regbase 出包路径(host GetTilingData<T> 直写裸 buffer + kernel | ||
| 19 | + * GET_TILING_DATA_WITH_STRUCT 直读),故用 plain POD,字段名/顺序/类型与 A2 的 | ||
| 20 | + * framework 版 ApplyAdamWQuantTilingData 一一对应,使 arch35 的计算头(从 A2 拷贝) | ||
| 21 | + * 无需改动成员访问即可复用。参考 deep_norm/apply_adam_w_v2 的 arch35 tiling_data 布局。 | ||
| 22 | + */ | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + | ||
| 29 | +struct ApplyAdamWQuantRegbaseTilingData { | ||
| 30 | + uint64_t use_num_core = 0; // 总共使用的核数 | ||
基础命名风格问题,请遵守华为编程规范 ![]() ![]() | |||
| 31 | + uint64_t last_pre_core_row_work = 0; // 尾核一个核循环的个数 | ||
| 32 | + uint64_t not_last_core_num = 0; // 非尾核的个数 | ||
| 33 | + uint64_t not_last_pre_core_row_work = 0; // 非尾核一个核循环的个数 | ||
| 34 | + uint64_t last_core_last_block = 0; // 最后一个核最后一次循环的 block 个数 | ||
| 35 | + float lr = 0.0f; | ||
| 36 | + float beta1 = 0.0f; | ||
| 37 | + float beta2 = 0.0f; | ||
| 38 | + float weight_decay = 0.0f; | ||
| 39 | + float eps = 0.0f; | ||
| 40 | + float gnorm_scale = 0.0f; | ||
| 41 | + int64_t block_size = 0; | ||
| 42 | + uint64_t one_core_do_block_num_per_row = 0; | ||
| 43 | + uint64_t tiling_key = 0; | ||
不要把tilingKey放到tilingData中 ![]() ![]() | |||
| 44 | + uint64_t last_block_size = 0; // 最后一个量化 block 的有效元素数 | ||
| 45 | +}; | ||
| 46 | + | ||
| 47 | + | ||
| @@ -0,0 +1,139 @@ | |||
| 1 | +#!/usr/bin/env python3 | ||
| 2 | +# -*- coding: UTF-8 -*- | ||
| 3 | +# Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 4 | +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 5 | +# CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 6 | +# Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 7 | +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 8 | +# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 9 | +# See LICENSE in the root of the software repository for the full text of the License. | ||
| 10 | + | ||
| 11 | +"""Torch CPU golden for ApplyAdamWQuant. | ||
| 12 | + | ||
| 13 | +NumPy is used only for TTK array conversion and input sanitization. The golden | ||
| 14 | +math itself is expressed with Torch tensor operations. | ||
| 15 | +""" | ||
| 16 | + | ||
| 17 | +import numpy as np | ||
| 18 | +import torch | ||
| 19 | + | ||
| 20 | +BLOCK = 256 | ||
| 21 | + | ||
| 22 | +__spec__ = {"apply_adam_w_quant": "ApplyAdamWQuantTestSpec"} | ||
| 23 | +__golden__ = {"kernel": {"apply_adam_w_quant": "apply_adam_w_quant_golden"}} | ||
| 24 | + | ||
| 25 | + | ||
| 26 | +def _to_f32(x): | ||
| 27 | + return torch.as_tensor(np.asarray(x).astype(np.float32), dtype=torch.float32) | ||
| 28 | + | ||
| 29 | + | ||
| 30 | +def _quantize_state(state, qmap, absmax): | ||
| 31 | + one = torch.tensor(1.0, dtype=torch.float32) | ||
| 32 | + denom = torch.where(absmax == 0, one, absmax) | ||
| 33 | + normalized = state / denom | ||
| 34 | + distances = torch.abs(normalized[:, None] - qmap[None, :]) | ||
| 35 | + indices = torch.argmin(distances, dim=1).to(torch.int64) | ||
| 36 | + if bool(torch.any(qmap < 0)): | ||
| 37 | + quantized = qmap[indices] | ||
| 38 | + flip = normalized * quantized < 0 | ||
| 39 | + adjusted = indices.clone() | ||
| 40 | + adjusted = torch.where(flip & (normalized > 0), adjusted + 1, adjusted) | ||
| 41 | + adjusted = torch.where(flip & (normalized < 0), adjusted - 1, adjusted) | ||
| 42 | + indices = torch.clamp(adjusted, 0, qmap.numel() - 1) | ||
| 43 | + return indices | ||
| 44 | + | ||
| 45 | + | ||
| 46 | +def apply_adam_w_quant_golden( | ||
| 47 | + var, grad, m, v, qmap_m, qmap_v, absmax_m, absmax_v, step, **kwargs | ||
| 48 | +): | ||
| 49 | + lr = torch.tensor(float(kwargs.get("lr", 0.001)), dtype=torch.float32) | ||
| 50 | + beta1 = torch.tensor(float(kwargs.get("beta1", 0.9)), dtype=torch.float32) | ||
| 51 | + beta2 = torch.tensor(float(kwargs.get("beta2", 0.999)), dtype=torch.float32) | ||
| 52 | + weight_decay = torch.tensor( | ||
| 53 | + float(kwargs.get("weight_decay", 1.0)), dtype=torch.float32 | ||
| 54 | + ) | ||
| 55 | + eps = torch.tensor(float(kwargs.get("eps", 1e-8)), dtype=torch.float32) | ||
| 56 | + gnorm_scale = torch.tensor( | ||
| 57 | + float(kwargs.get("gnorm_scale", 1.0)), dtype=torch.float32 | ||
| 58 | + ) | ||
| 59 | + block_size = int(kwargs.get("block_size", BLOCK)) | ||
| 60 | + | ||
| 61 | + out_dtype = np.asarray(var).dtype | ||
| 62 | + one = torch.tensor(1.0, dtype=torch.float32) | ||
| 63 | + step_v = _to_f32(step).reshape(-1)[0] + one | ||
| 64 | + bias_c1 = one - torch.pow(beta1, step_v) | ||
| 65 | + bias_c2_sqrt = torch.sqrt(one - torch.pow(beta2, step_v)) | ||
| 66 | + step_size = -lr * bias_c2_sqrt / bias_c1 | ||
| 67 | + one_minus_beta1 = one - beta1 | ||
| 68 | + one_minus_beta2 = one - beta2 | ||
| 69 | + weight_decay_factor = one - lr * weight_decay | ||
| 70 | + | ||
| 71 | + var_f = _to_f32(var).reshape(-1).clone() | ||
| 72 | + grad_f = _to_f32(grad).reshape(-1) | ||
| 73 | + m_codes = torch.as_tensor(np.asarray(m).reshape(-1).copy(), dtype=torch.int64) | ||
| 74 | + v_codes = torch.as_tensor(np.asarray(v).reshape(-1).copy(), dtype=torch.int64) | ||
| 75 | + qmap_m_t = _to_f32(qmap_m).reshape(-1) | ||
| 76 | + qmap_v_t = _to_f32(qmap_v).reshape(-1) | ||
| 77 | + absmax_m_t = _to_f32(absmax_m).reshape(-1) | ||
| 78 | + absmax_v_t = _to_f32(absmax_v).reshape(-1) | ||
| 79 | + new_am = torch.zeros_like(absmax_m_t, dtype=torch.float32) | ||
| 80 | + new_av = torch.zeros_like(absmax_v_t, dtype=torch.float32) | ||
| 81 | + | ||
| 82 | + n = var_f.numel() | ||
| 83 | + num_blocks = (n + block_size - 1) // block_size | ||
| 84 | + for block_idx in range(num_blocks): | ||
| 85 | + start = block_idx * block_size | ||
| 86 | + end = min((block_idx + 1) * block_size, n) | ||
| 87 | + param = var_f[start:end] | ||
| 88 | + grad_block = grad_f[start:end] * gnorm_scale | ||
| 89 | + s1 = qmap_m_t[m_codes[start:end]] * absmax_m_t[block_idx] | ||
| 90 | + s2 = qmap_v_t[v_codes[start:end]] * absmax_v_t[block_idx] | ||
| 91 | + s1_update = s1 * beta1 + one_minus_beta1 * grad_block | ||
| 92 | + s2_update = s2 * beta2 + one_minus_beta2 * (grad_block * grad_block) | ||
| 93 | + denom = torch.sqrt(s2_update) + eps * bias_c2_sqrt | ||
| 94 | + param = param + step_size * s1_update / denom | ||
| 95 | + if float(weight_decay) > 0.0: | ||
| 96 | + param = param * weight_decay_factor | ||
| 97 | + | ||
| 98 | + abs_m = torch.max(torch.abs(s1_update)) | ||
| 99 | + abs_v = torch.max(s2_update) | ||
| 100 | + var_f[start:end] = param | ||
| 101 | + m_codes[start:end] = _quantize_state(s1_update, qmap_m_t, abs_m) | ||
| 102 | + v_codes[start:end] = _quantize_state(s2_update, qmap_v_t, abs_v) | ||
| 103 | + new_am[block_idx] = abs_m | ||
| 104 | + new_av[block_idx] = abs_v | ||
| 105 | + | ||
| 106 | + var_out = var_f.reshape(np.asarray(var).shape).numpy().astype(out_dtype, copy=False) | ||
| 107 | + return [ | ||
| 108 | + var_out, | ||
| 109 | + m_codes.numpy() | ||
| 110 | + .astype(np.asarray(m).dtype, copy=False) | ||
| 111 | + .reshape(np.asarray(m).shape), | ||
| 112 | + v_codes.numpy() | ||
| 113 | + .astype(np.asarray(v).dtype, copy=False) | ||
| 114 | + .reshape(np.asarray(v).shape), | ||
| 115 | + new_am.numpy() | ||
| 116 | + .astype(np.float32, copy=False) | ||
| 117 | + .reshape(np.asarray(absmax_m).shape), | ||
| 118 | + new_av.numpy() | ||
| 119 | + .astype(np.float32, copy=False) | ||
| 120 | + .reshape(np.asarray(absmax_v).shape), | ||
| 121 | + ] | ||
| 122 | + | ||
| 123 | + | ||
| 124 | +def customize_inputs( | ||
| 125 | + var, grad, m, v, qmap_m, qmap_v, absmax_m, absmax_v, step, **kwargs | ||
| 126 | +): | ||
| 127 | + qmap_m = np.linspace(-1.0, 1.0, 256, dtype=np.float32) | ||
| 128 | + qmap_v = np.linspace(0.0, 1.0, 256, dtype=np.float32) | ||
| 129 | + m = np.clip(m, 0, 255).astype(np.uint8) | ||
| 130 | + v = np.clip(v, 0, 255).astype(np.uint8) | ||
| 131 | + absmax_m = np.abs(absmax_m).astype(np.float32) + 0.1 | ||
| 132 | + absmax_v = np.abs(absmax_v).astype(np.float32) + 0.1 | ||
| 133 | + step = np.maximum(np.asarray(step), 1) | ||
| 134 | + return var, grad, m, v, qmap_m, qmap_v, absmax_m, absmax_v, step | ||
| 135 | + | ||
| 136 | + | ||
| 137 | +class ApplyAdamWQuantTestSpec: | ||
| 138 | + golden = apply_adam_w_quant_golden | ||
| 139 | + customize_inputs = customize_inputs | ||


新写代码都有tilingkey中冗余dtype信息问题,请排查整改后再检视