已合并
AscendC实现KlDivLossGrad算子贡献 #5358
hqnzw创建于 5月28日
AscendC实现KlDivLossGrad算子贡献 #5358
已合并
共 24 个文件变更+2594-0
| @@ -0,0 +1,19 @@ | |||
| 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 | +file(GLOB CURRENT_DIRS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*) | ||
| 12 | +if(NOT ENABLE_TEST AND NOT BENCHMARK) | ||
| 13 | + list(REMOVE_ITEM CURRENT_DIRS tests) | ||
| 14 | +endif() | ||
| 15 | +foreach(SUB_DIR ${CURRENT_DIRS}) | ||
| 16 | + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SUB_DIR}/CMakeLists.txt") | ||
| 17 | + add_subdirectory(${SUB_DIR}) | ||
| 18 | + endif() | ||
| 19 | +endforeach() | ||
| @@ -0,0 +1,36 @@ | |||
| 1 | +# KlDivLossGrad | ||
| 2 | + | ||
| 3 | +## 产品支持情况 | ||
| 4 | + | ||
| 5 | +|产品 | 是否支持 | | ||
| 6 | +|:-------------------------|:----------:| | ||
| 7 | +| <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term> | √ | | ||
| 8 | + | ||
| 9 | +## 功能说明 | ||
| 10 | + | ||
| 11 | +算子功能:进行[aclnnKlDiv](https://gitcode.com/cann/ops-math/blob/master/math/kl_div_v2/docs/aclnnKlDiv.md) api的结果的反向计算。 | ||
| 12 | + | ||
| 13 | +## 参数说明 | ||
| 14 | + | ||
| 15 | +- gradOutput(aclTensor*, 计算输入):Device侧的aclTensor,[数据格式](../../../docs/zh/context/数据格式.md)支持ND。shape需要与self满足[broadcast关系](../../../docs/zh/context/broadcast关系.md)。支持[非连续的Tensor](../../../docs/zh/context/非连续的Tensor.md)。数据类型支持FLOAT、FLOAT16、BFLOAT16。 | ||
| 16 | +- self(aclTensor*, 计算输入):Device侧的aclTensor。[数据格式](../../../docs/zh/context/数据格式.md)支持ND。支持[非连续的Tensor](../../../docs/zh/context/非连续的Tensor.md)。数据类型支持FLOAT、FLOAT16、BFLOAT16。 | ||
| 17 | +- target(aclTensor*, 计算输入):Device侧的aclTensor,[数据格式](../../../docs/zh/context/数据格式.md)支持ND。shape需要与self满足[broadcast关系](../../../docs/zh/context/broadcast关系.md)。支持[非连续的Tensor](../../../docs/zh/context/非连续的Tensor.md)。数据类型支持FLOAT、FLOAT16、BFLOAT16。 | ||
| 18 | +- reduction(int64_t, 计算输入):Host侧的int64_t,[数据格式](../../../docs/zh/context/数据格式.md)支持ND。指定要应用到输出的缩减。支持0(‘none’)| 1(‘mean’)| 2(‘sum’)|3(‘batchmean’)。‘none’表示不应用减少,‘mean’表示输出的总和将除以输出中的元素数,‘sum’表示输出将被求和,‘batchmean’表示输出的总和将除以batch的个数。 | ||
| 19 | +- logTarget(bool, 计算输入):Host侧的BOOL类型,是否对target进行log空间转换。 | ||
| 20 | +- out(aclTensor*, 计算输出):Device侧的aclTensor。支持[非连续的Tensor](../../../docs/zh/context/非连续的Tensor.md)。数据类型支持FLOAT、FLOAT16、BFLOAT16。 | ||
| 21 | + | ||
| 22 | +## 约束说明 | ||
| 23 | + | ||
| 24 | +无。 | ||
| 25 | + | ||
| 26 | +## 调用说明 | ||
| 27 | + | ||
| 28 | +| 调用方式 | 样例代码 | 说明 | | ||
| 29 | +| ---------------- | --------------------------- | --------------------------------------------------- | | ||
| 30 | +| aclnn接口 | [test_aclnn_kl_div_loss_grad.cpp](examples/test_aclnn_kl_div_loss_grad.cpp) | 通过[aclnnKlDivBackward](docs/aclnnKlDivBackward.md)接口方式调用KlDivLossGrad算子。 | | ||
| 31 | + | ||
| 32 | +## 贡献说明 | ||
| 33 | + | ||
| 34 | +| 贡献者 | 贡献方 | 贡献算子 | 贡献时间 | 贡献内容 | | ||
| 35 | +| ---- | ---- | ---- | ---- | ---- | | ||
| 36 | +| 韩智惟 | 北京交通大学-赵宏智老师团队 | KlDivLossGrad | 2026/05/28 | KlDivLossGrad算子适配开源仓 | | ||
| @@ -0,0 +1,394 @@ | |||
| 1 | +# aclnnKlDivBackward | ||
| 2 | + | ||
| 3 | +## 产品支持情况 | ||
| 4 | + | ||
| 5 | +|产品 | 是否支持 | | ||
| 6 | +|:-------------------------|:----------:| | ||
| 7 | +| <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term> | √ | | ||
| 8 | + | ||
| 9 | +## 功能说明 | ||
| 10 | + | ||
| 11 | +进行[aclnnKlDiv](https://gitcode.com/cann/ops-math/blob/master/math/kl_div_v2/docs/aclnnKlDiv.md) api的结果的反向计算。 | ||
| 12 | + | ||
| 13 | +## 函数原型 | ||
| 14 | + | ||
| 15 | +每个算子分为[两段式接口](../../../../docs/zh/context/两段式接口.md),必须先调用“aclnnKlDivBackwardGetWorkspaceSize”接口获取计算所需workspace大小以及包含了算子计算流程的执行器,再调用“aclnnKlDivBackward”接口执行计算。 | ||
| 16 | + | ||
| 17 | +```Cpp | ||
| 18 | +aclnnStatus aclnnKlDivBackwardGetWorkspaceSize( | ||
| 19 | + const aclTensor* gradOutput, | ||
| 20 | + const aclTensor* self, | ||
| 21 | + const aclTensor* target, | ||
| 22 | + int64_t reduction, | ||
| 23 | + bool logTarget, | ||
| 24 | + aclTensor* out, | ||
| 25 | + uint64_t* workspaceSize, | ||
| 26 | + aclOpExecutor** executor) | ||
| 27 | +``` | ||
| 28 | + | ||
| 29 | +```Cpp | ||
| 30 | +aclnnStatus aclnnKlDivBackward( | ||
| 31 | + void* workspace, | ||
| 32 | + uint64_t workspaceSize, | ||
| 33 | + aclOpExecutor* executor, | ||
| 34 | + aclrtStream stream) | ||
| 35 | +``` | ||
| 36 | + | ||
| 37 | +## aclnnKlDivBackwardGetWorkspaceSize | ||
| 38 | + | ||
| 39 | +- **参数说明:** | ||
| 40 | + | ||
| 41 | + <table class="tg" style="undefined;table-layout: fixed; width: 1435px"><colgroup> | ||
| 42 | + <col style="width: 205px"> | ||
| 43 | + <col style="width: 120px"> | ||
| 44 | + <col style="width: 300px"> | ||
| 45 | + <col style="width: 300px"> | ||
| 46 | + <col style="width: 130px"> | ||
| 47 | + <col style="width: 115px"> | ||
| 48 | + <col style="width: 120px"> | ||
| 49 | + <col style="width: 145px"> | ||
| 50 | + </colgroup> | ||
| 51 | + <thead> | ||
| 52 | + <tr> | ||
| 53 | + <th class="tg-0pky">参数名</th> | ||
| 54 | + <th class="tg-0pky">输入/输出</th> | ||
| 55 | + <th class="tg-0pky">描述</th> | ||
| 56 | + <th class="tg-0pky">使用说明</th> | ||
| 57 | + <th class="tg-0pky">数据类型</th> | ||
| 58 | + <th class="tg-0pky">数据格式</th> | ||
| 59 | + <th class="tg-0pky">维度(shape)</th> | ||
| 60 | + <th class="tg-0pky">非连续Tensor</th> | ||
| 61 | + </tr></thead> | ||
| 62 | + <tbody> | ||
| 63 | + <tr> | ||
| 64 | + <td class="tg-0pky">gradOutput(aclTensor*)</td> | ||
| 65 | + <td class="tg-0pky">输入</td> | ||
| 66 | + <td class="tg-0pky">梯度反向输入。</td> | ||
| 67 | + <td class="tg-0pky">shape需要与self满足<a href="../../../../docs/zh/context/broadcast关系.md" target="_blank">broadcast</a>关系。</td> | ||
| 68 | + <td class="tg-0pky">FLOAT、FLOAT16、BFLOAT16</td> | ||
| 69 | + <td class="tg-0pky">ND</td> | ||
| 70 | + <td class="tg-0pky">1-8</td> | ||
| 71 | + <td class="tg-0pky">√</td> | ||
| 72 | + </tr> | ||
| 73 | + <tr> | ||
| 74 | + <td class="tg-0pky">self(aclTensor*)</td> | ||
| 75 | + <td class="tg-0pky">输入</td> | ||
| 76 | + <td class="tg-0pky">输入张量。</td> | ||
| 77 | + <td class="tg-0pky">-</td> | ||
| 78 | + <td class="tg-0pky">FLOAT、FLOAT16、BFLOAT16</td> | ||
| 79 | + <td class="tg-0pky">ND</td> | ||
| 80 | + <td class="tg-0pky">1-8</td> | ||
| 81 | + <td class="tg-0pky">√</td> | ||
| 82 | + </tr> | ||
| 83 | + <tr> | ||
| 84 | + <td class="tg-0pky">target(aclTensor*)</td> | ||
| 85 | + <td class="tg-0pky">输入</td> | ||
| 86 | + <td class="tg-0pky">真实的标签。</td> | ||
| 87 | + <td class="tg-0pky">shape需要与self满足<a href="../../../../docs/zh/context/broadcast关系.md" target="_blank">broadcast</a>关系。</td> | ||
| 88 | + <td class="tg-0pky">FLOAT、FLOAT16、BFLOAT16</td> | ||
| 89 | + <td class="tg-0pky">ND</td> | ||
| 90 | + <td class="tg-0pky">1-8</td> | ||
| 91 | + <td class="tg-0pky">√</td> | ||
| 92 | + </tr> | ||
| 93 | + <tr> | ||
| 94 | + <td class="tg-0pky">reduction(int64_t)</td> | ||
| 95 | + <td class="tg-0pky">输入</td> | ||
| 96 | + <td class="tg-0pky">指定要应用到输出的缩减。</td> | ||
| 97 | + <td class="tg-0pky">支持0(none)|1(mean)|2(sum)|3(batchmean)。<br>'none'表示不应用缩减。<br>'mean'表示输出的总和将除以输出中的元素数。<br>'sum'表示输出将被求和。<br>'batchmean'表示输出的总和将除以batch的个数。</td> | ||
| 98 | + <td class="tg-0pky">INT64</td> | ||
| 99 | + <td class="tg-0pky">-</td> | ||
| 100 | + <td class="tg-0pky">-</td> | ||
| 101 | + <td class="tg-0pky">-</td> | ||
| 102 | + </tr> | ||
| 103 | + <tr> | ||
| 104 | + <td class="tg-0pky">logTarget(bool)</td> | ||
| 105 | + <td class="tg-0pky">输入</td> | ||
| 106 | + <td class="tg-0pky">是否对target进行log空间转换。</td> | ||
| 107 | + <td class="tg-0pky">-</td> | ||
| 108 | + <td class="tg-0pky">BOOL</td> | ||
| 109 | + <td class="tg-0pky">-</td> | ||
| 110 | + <td class="tg-0pky">-</td> | ||
| 111 | + <td class="tg-0pky">√</td> | ||
| 112 | + </tr> | ||
| 113 | + <tr> | ||
| 114 | + <td class="tg-0pky">out(aclTensor*)</td> | ||
| 115 | + <td class="tg-0pky">输出</td> | ||
| 116 | + <td class="tg-0pky">输出的损失。</td> | ||
| 117 | + <td class="tg-0pky">-</td> | ||
| 118 | + <td class="tg-0pky">与self保持一致</td> | ||
| 119 | + <td class="tg-0pky">ND</td> | ||
| 120 | + <td class="tg-0pky">1-8</td> | ||
| 121 | + <td class="tg-0pky">√</td> | ||
| 122 | + </tr> | ||
| 123 | + <tr> | ||
| 124 | + <td class="tg-0pky">workspaceSize(uint64_t*)</td> | ||
| 125 | + <td class="tg-0pky">输出</td> | ||
| 126 | + <td class="tg-0pky">返回需要在Device侧申请的workspace大小。</td> | ||
| 127 | + <td class="tg-0pky">-</td> | ||
| 128 | + <td class="tg-0pky">-</td> | ||
| 129 | + <td class="tg-0pky">-</td> | ||
| 130 | + <td class="tg-0pky">-</td> | ||
| 131 | + <td class="tg-0pky">-</td> | ||
| 132 | + </tr> | ||
| 133 | + <tr> | ||
| 134 | + <td class="tg-0pky">executor(aclOpExecutor**)</td> | ||
| 135 | + <td class="tg-0pky">输出</td> | ||
| 136 | + <td class="tg-0pky">返回op执行器,包含了算子计算流程。</td> | ||
| 137 | + <td class="tg-0pky">-</td> | ||
| 138 | + <td class="tg-0pky">-</td> | ||
| 139 | + <td class="tg-0pky">-</td> | ||
| 140 | + <td class="tg-0pky">-</td> | ||
| 141 | + <td class="tg-0pky">-</td> | ||
| 142 | + </tr> | ||
| 143 | + </tbody></table> | ||
| 144 | + | ||
| 145 | +- **返回值:** | ||
| 146 | + | ||
| 147 | + aclnnStatus:返回状态码,具体参见[aclnn返回码](../../../../docs/zh/context/aclnn返回码.md)。 | ||
| 148 | + | ||
| 149 | + 第一段接口完成入参校验,出现以下场景时报错: | ||
| 150 | + | ||
| 151 | + <table class="tg" style="undefined;table-layout: fixed; width: 991px"><colgroup> | ||
| 152 | + <col style="width: 269px"> | ||
| 153 | + <col style="width: 90px"> | ||
| 154 | + <col style="width: 632px"> | ||
| 155 | + </colgroup> | ||
| 156 | + <thead> | ||
| 157 | + <tr> | ||
| 158 | + <th class="tg-0pky">返回值</th> | ||
| 159 | + <th class="tg-0pky">错误码</th> | ||
| 160 | + <th class="tg-0pky">描述</th> | ||
| 161 | + </tr></thead> | ||
| 162 | + <tbody> | ||
| 163 | + <tr> | ||
| 164 | + <td class="tg-0pky">ACLNN_ERR_PARAM_NULLPTR</td> | ||
| 165 | + <td class="tg-0pky">161001</td> | ||
| 166 | + <td class="tg-0pky">传入的gradOutput、self、target和out是空指针。</td> | ||
| 167 | + </tr> | ||
| 168 | + <tr> | ||
| 169 | + <td class="tg-0pky" rowspan="6">ACLNN_ERR_PARAM_INVALID</td> | ||
| 170 | + <td class="tg-0pky" rowspan="6">161002</td> | ||
| 171 | + <td class="tg-0pky">gradOutput、self、target和out的数据类型不在支持的范围内时。</td> | ||
| 172 | + </tr> | ||
| 173 | + <tr> | ||
| 174 | + <td class="tg-0pky">self、out的数据类型不一致。</td> | ||
| 175 | + </tr> | ||
| 176 | + <tr> | ||
| 177 | + <td class="tg-0pky">gradOutput的shape不能向self或者target做<a href="../../../../docs/zh/context/broadcast关系.md" target="_blank">broadcast</a>。</td> | ||
| 178 | + </tr> | ||
| 179 | + <tr> | ||
| 180 | + <td class="tg-0pky">target的shape和self的shape不满足<a href="../../../../docs/zh/context/broadcast关系.md" target="_blank">broadcast</a>关系。</td> | ||
| 181 | + </tr> | ||
| 182 | + <tr> | ||
| 183 | + <td class="tg-0lax">self的shape与out的shape不相同。</td> | ||
| 184 | + </tr> | ||
| 185 | + <tr> | ||
| 186 | + <td class="tg-0lax">gradOutput、self、target或者out维度大于8。</td> | ||
| 187 | + </tr> | ||
| 188 | + </tbody> | ||
| 189 | + </table> | ||
| 190 | + | ||
| 191 | +## aclnnKlDivBackward | ||
| 192 | + | ||
| 193 | +- **参数说明:** | ||
| 194 | + | ||
| 195 | + <table style="undefined;table-layout: fixed; width: 1244px"><colgroup> | ||
| 196 | + <col style="width: 200px"> | ||
| 197 | + <col style="width: 162px"> | ||
| 198 | + <col style="width: 882px"> | ||
| 199 | + </colgroup> | ||
| 200 | + <thead> | ||
| 201 | + <tr> | ||
| 202 | + <th>参数名</th> | ||
| 203 | + <th>输入/输出</th> | ||
| 204 | + <th>描述</th> | ||
| 205 | + </tr></thead> | ||
| 206 | + <tbody> | ||
| 207 | + <tr> | ||
| 208 | + <td>workspace</td> | ||
| 209 | + <td>输入</td> | ||
| 210 | + <td>在Device侧申请的workspace内存地址。</td> | ||
| 211 | + </tr> | ||
| 212 | + <tr> | ||
| 213 | + <td>workspaceSize</td> | ||
| 214 | + <td>输入</td> | ||
| 215 | + <td>在Device侧申请的workspace大小,由第一段接口aclnnKlDivBackwardGetWorkspaceSize获取。</td> | ||
| 216 | + </tr> | ||
| 217 | + <tr> | ||
| 218 | + <td>executor</td> | ||
| 219 | + <td>输入</td> | ||
| 220 | + <td>op执行器,包含了算子计算流程。</td> | ||
| 221 | + </tr> | ||
| 222 | + <tr> | ||
| 223 | + <td>stream</td> | ||
| 224 | + <td>输入</td> | ||
| 225 | + <td>指定执行任务的Stream。</td> | ||
| 226 | + </tr> | ||
| 227 | + </tbody> | ||
| 228 | + </table> | ||
| 229 | + | ||
| 230 | +- **返回值:** | ||
| 231 | + | ||
| 232 | + aclnnStatus:返回状态码,具体参见[aclnn返回码](../../../../docs/zh/context/aclnn返回码.md)。 | ||
| 233 | + | ||
| 234 | +## 约束说明 | ||
| 235 | + | ||
| 236 | +- 确定性计算: | ||
| 237 | + - aclnnKlDivBackward默认确定性实现。 | ||
| 238 | + | ||
| 239 | +## 调用示例 | ||
| 240 | + | ||
| 241 | +示例代码如下,仅供参考,具体编译和执行过程请参考[编译与运行样例](../../../../docs/zh/context/编译与运行样例.md)。 | ||
| 242 | + | ||
| 243 | +```Cpp | ||
| 244 | +#include <iostream> | ||
| 245 | +#include <vector> | ||
| 246 | +#include "acl/acl.h" | ||
| 247 | +#include "aclnnop/aclnn_kl_div_backward.h" | ||
| 248 | + | ||
| 249 | +#define CHECK_RET(cond, return_expr) \ | ||
| 250 | + do { \ | ||
| 251 | + if (!(cond)) { \ | ||
| 252 | + return_expr; \ | ||
| 253 | + } \ | ||
| 254 | + } while (0) | ||
| 255 | + | ||
| 256 | +#define LOG_PRINT(message, ...) \ | ||
| 257 | + do { \ | ||
| 258 | + printf(message, ##__VA_ARGS__); \ | ||
| 259 | + } while (0) | ||
| 260 | + | ||
| 261 | +int64_t GetShapeSize(const std::vector<int64_t>& shape) { | ||
| 262 | + int64_t shapeSize = 1; | ||
| 263 | + for (auto i : shape) { | ||
| 264 | + shapeSize *= i; | ||
| 265 | + } | ||
| 266 | + return shapeSize; | ||
| 267 | +} | ||
| 268 | + | ||
| 269 | +int Init(int32_t deviceId, aclrtStream* stream) { | ||
| 270 | + // 固定写法,资源初始化 | ||
| 271 | + auto ret = aclInit(nullptr); | ||
| 272 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); | ||
| 273 | + ret = aclrtSetDevice(deviceId); | ||
| 274 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); | ||
| 275 | + ret = aclrtCreateStream(stream); | ||
| 276 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); | ||
| 277 | + return 0; | ||
| 278 | +} | ||
| 279 | + | ||
| 280 | +template <typename T> | ||
| 281 | +int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, | ||
| 282 | + aclDataType dataType, aclTensor** tensor) { | ||
| 283 | + auto size = GetShapeSize(shape) * sizeof(T); | ||
| 284 | + // 调用aclrtMalloc申请device侧内存 | ||
| 285 | + auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 286 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); | ||
| 287 | + | ||
| 288 | + // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上 | ||
| 289 | + ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 290 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); | ||
| 291 | + | ||
| 292 | + // 计算连续tensor的strides | ||
| 293 | + std::vector<int64_t> strides(shape.size(), 1); | ||
| 294 | + for (int64_t i = shape.size() - 2; i >= 0; i--) { | ||
| 295 | + strides[i] = shape[i + 1] * strides[i + 1]; | ||
| 296 | + } | ||
| 297 | + | ||
| 298 | + // 调用aclCreateTensor接口创建aclTensor | ||
| 299 | + *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, | ||
| 300 | + shape.data(), shape.size(), *deviceAddr); | ||
| 301 | + return 0; | ||
| 302 | +} | ||
| 303 | + | ||
| 304 | +int main() { | ||
| 305 | + // 1. (固定写法)device/stream初始化,参考acl API手册 | ||
| 306 | + // 根据自己的实际device填写deviceId | ||
| 307 | + int32_t deviceId = 0; | ||
| 308 | + aclrtStream stream; | ||
| 309 | + auto ret = Init(deviceId, &stream); | ||
| 310 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | ||
| 311 | + | ||
| 312 | + // 2. 构造输入与输出,需要根据API的接口自定义构造 | ||
| 313 | + std::vector<int64_t> gradOutputShape = {2, 2}; | ||
| 314 | + std::vector<int64_t> selfShape = {2, 2}; | ||
| 315 | + std::vector<int64_t> targetShape = {2, 2}; | ||
| 316 | + std::vector<int64_t> outShape = {2, 2}; | ||
| 317 | + void* gradOutputDeviceAddr = nullptr; | ||
| 318 | + void* selfDeviceAddr = nullptr; | ||
| 319 | + void* targetDeviceAddr = nullptr; | ||
| 320 | + void* outDeviceAddr = nullptr; | ||
| 321 | + aclTensor* gradOutput = nullptr; | ||
| 322 | + aclTensor* self = nullptr; | ||
| 323 | + aclTensor* target = nullptr; | ||
| 324 | + aclTensor* out = nullptr; | ||
| 325 | + std::vector<float> gradOutputHostData = {2, 3, 5, 8}; | ||
| 326 | + std::vector<float> selfHostData = {2, 3, 5, 8}; | ||
| 327 | + std::vector<float> targetHostData = {2, 3, 5, 8}; | ||
| 328 | + std::vector<float> outHostData = {2, 3, 5, 8}; | ||
| 329 | + int64_t reduction = 0; | ||
| 330 | + bool logTarget = false; | ||
| 331 | + // 创建gradOutput aclTensor | ||
| 332 | + ret = CreateAclTensor(gradOutputHostData, gradOutputShape, &gradOutputDeviceAddr, aclDataType::ACL_FLOAT, &gradOutput); | ||
| 333 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 334 | + // 创建self aclTensor | ||
| 335 | + ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self); | ||
| 336 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 337 | + // 创建target aclTensor | ||
| 338 | + ret = CreateAclTensor(targetHostData, targetShape, &targetDeviceAddr, aclDataType::ACL_FLOAT, &target); | ||
| 339 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 340 | + // 创建out aclTensor | ||
| 341 | + ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out); | ||
| 342 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 343 | + | ||
| 344 | + // 3. 调用CANN算子库API | ||
| 345 | + uint64_t workspaceSize = 0; | ||
| 346 | + aclOpExecutor* executor; | ||
| 347 | + // 调用aclnnKlDivBackward第一段接口 | ||
| 348 | + ret = aclnnKlDivBackwardGetWorkspaceSize(gradOutput, self, target, reduction, logTarget, out, &workspaceSize, &executor); | ||
| 349 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnKlDivBackwardGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); | ||
| 350 | + // 根据第一段接口计算出的workspaceSize申请device内存 | ||
| 351 | + void* workspaceAddr = nullptr; | ||
| 352 | + if (workspaceSize > 0) { | ||
| 353 | + ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 354 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | ||
| 355 | + } | ||
| 356 | + // 调用aclnnKlDivBackward第二段接口 | ||
| 357 | + ret = aclnnKlDivBackward(workspaceAddr, workspaceSize, executor, stream); | ||
| 358 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnKlDivBackward failed. ERROR: %d\n", ret); return ret); | ||
| 359 | + | ||
| 360 | + // 4. (固定写法)同步等待任务执行结束 | ||
| 361 | + ret = aclrtSynchronizeStream(stream); | ||
| 362 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 363 | + | ||
| 364 | + // 5. 获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改 | ||
| 365 | + auto size = GetShapeSize(outShape); | ||
| 366 | + std::vector<float> resultData(size, 0); | ||
| 367 | + ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), | ||
| 368 | + outDeviceAddr, size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 369 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy resultData from device to host failed. ERROR: %d\n", ret); | ||
| 370 | + return ret); | ||
| 371 | + for (int64_t i = 0; i < size; i++) { | ||
| 372 | + LOG_PRINT("resultData[%ld] is: %f\n", i, resultData[i]); | ||
| 373 | + } | ||
| 374 | + | ||
| 375 | + // 6. 释放aclTensor,需要根据具体API的接口定义修改 | ||
| 376 | + aclDestroyTensor(gradOutput); | ||
| 377 | + aclDestroyTensor(self); | ||
| 378 | + aclDestroyTensor(target); | ||
| 379 | + aclDestroyTensor(out); | ||
| 380 | + | ||
| 381 | + // 7. 释放device资源,需要根据具体API的接口定义修改 | ||
| 382 | + aclrtFree(gradOutputDeviceAddr); | ||
| 383 | + aclrtFree(selfDeviceAddr); | ||
| 384 | + aclrtFree(targetDeviceAddr); | ||
| 385 | + aclrtFree(outDeviceAddr); | ||
| 386 | + if (workspaceSize > 0) { | ||
| 387 | + aclrtFree(workspaceAddr); | ||
| 388 | + } | ||
| 389 | + aclrtDestroyStream(stream); | ||
| 390 | + aclrtResetDevice(deviceId); | ||
| 391 | + aclFinalize(); | ||
| 392 | + return 0; | ||
| 393 | +} | ||
| 394 | +``` | ||
| @@ -0,0 +1,169 @@ | |||
| 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 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + do { \ | ||
| 18 | + if (!(cond)) { \ | ||
| 19 | + return_expr; \ | ||
| 20 | + } \ | ||
| 21 | + } while (0) | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + do { \ | ||
| 25 | + printf(message, ##__VA_ARGS__); \ | ||
| 26 | + } while (0) | ||
| 27 | + | ||
| 28 | +int64_t GetShapeSize(const std::vector<int64_t>& shape) | ||
| 29 | +{ | ||
| 30 | + int64_t shapeSize = 1; | ||
| 31 | + for (auto i : shape) { | ||
| 32 | + shapeSize *= i; | ||
| 33 | + } | ||
| 34 | + return shapeSize; | ||
| 35 | +} | ||
| 36 | + | ||
| 37 | +int Init(int32_t deviceId, aclrtStream* stream) | ||
| 38 | +{ | ||
| 39 | + // 固定写法,资源初始化 | ||
| 40 | + auto ret = aclInit(nullptr); | ||
| 41 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); | ||
| 42 | + ret = aclrtSetDevice(deviceId); | ||
| 43 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); | ||
| 44 | + ret = aclrtCreateStream(stream); | ||
| 45 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); | ||
| 46 | + return 0; | ||
| 47 | +} | ||
| 48 | + | ||
| 49 | +template <typename T> | ||
| 50 | +int CreateAclTensor( | ||
| 51 | + const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, aclDataType dataType, | ||
| 52 | + aclTensor** tensor) | ||
| 53 | +{ | ||
| 54 | + auto size = GetShapeSize(shape) * sizeof(T); | ||
| 55 | + // 调用aclrtMalloc申请device侧内存 | ||
| 56 | + auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 57 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); | ||
| 58 | + | ||
| 59 | + // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上 | ||
| 60 | + ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 61 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); | ||
| 62 | + | ||
| 63 | + // 计算连续tensor的strides | ||
| 64 | + std::vector<int64_t> strides(shape.size(), 1); | ||
| 65 | + for (int64_t i = shape.size() - 2; i >= 0; i--) { | ||
| 66 | + strides[i] = shape[i + 1] * strides[i + 1]; | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + // 调用aclCreateTensor接口创建aclTensor | ||
| 70 | + *tensor = aclCreateTensor( | ||
| 71 | + shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(), | ||
| 72 | + *deviceAddr); | ||
| 73 | + return 0; | ||
| 74 | +} | ||
| 75 | + | ||
| 76 | +int main() | ||
| 77 | +{ | ||
| 78 | + // 1. (固定写法)device/stream初始化,参考acl API手册 | ||
| 79 | + // 根据自己的实际device填写deviceId | ||
| 80 | + int32_t deviceId = 0; | ||
| 81 | + aclrtStream stream; | ||
| 82 | + auto ret = Init(deviceId, &stream); | ||
| 83 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | ||
| 84 | + | ||
| 85 | + // 2. 构造输入与输出,需要根据API的接口自定义构造 | ||
| 86 | + std::vector<int64_t> gradOutputShape = {2, 2}; | ||
| 87 | + std::vector<int64_t> selfShape = {2, 2}; | ||
| 88 | + std::vector<int64_t> targetShape = {2, 2}; | ||
| 89 | + std::vector<int64_t> outShape = {2, 2}; | ||
| 90 | + void* gradOutputDeviceAddr = nullptr; | ||
| 91 | + void* selfDeviceAddr = nullptr; | ||
| 92 | + void* targetDeviceAddr = nullptr; | ||
| 93 | + void* outDeviceAddr = nullptr; | ||
| 94 | + aclTensor* gradOutput = nullptr; | ||
| 95 | + aclTensor* self = nullptr; | ||
| 96 | + aclTensor* target = nullptr; | ||
| 97 | + aclTensor* out = nullptr; | ||
| 98 | + std::vector<float> gradOutputHostData = {2, 3, 5, 8}; | ||
| 99 | + std::vector<float> selfHostData = {2, 3, 5, 8}; | ||
| 100 | + std::vector<float> targetHostData = {2, 3, 5, 8}; | ||
| 101 | + std::vector<float> outHostData = {2, 3, 5, 8}; | ||
| 102 | + int64_t reduction = 0; | ||
| 103 | + bool logTarget = false; | ||
| 104 | + // 创建gradOutput aclTensor | ||
| 105 | + ret = CreateAclTensor( | ||
| 106 | + gradOutputHostData, gradOutputShape, &gradOutputDeviceAddr, aclDataType::ACL_FLOAT, &gradOutput); | ||
| 107 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 108 | + // 创建self aclTensor | ||
| 109 | + ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self); | ||
| 110 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 111 | + // 创建target aclTensor | ||
| 112 | + ret = CreateAclTensor(targetHostData, targetShape, &targetDeviceAddr, aclDataType::ACL_FLOAT, &target); | ||
| 113 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 114 | + // 创建out aclTensor | ||
| 115 | + ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out); | ||
| 116 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 117 | + | ||
| 118 | + // 3. 调用CANN算子库API | ||
| 119 | + uint64_t workspaceSize = 0; | ||
| 120 | + aclOpExecutor* executor; | ||
| 121 | + // 调用aclnnKlDivBackward第一段接口 | ||
| 122 | + ret = aclnnKlDivBackwardGetWorkspaceSize( | ||
| 123 | + gradOutput, self, target, reduction, logTarget, out, &workspaceSize, &executor); | ||
| 124 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnKlDivBackwardGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); | ||
| 125 | + // 根据第一段接口计算出的workspaceSize申请device内存 | ||
| 126 | + void* workspaceAddr = nullptr; | ||
| 127 | + if (workspaceSize > 0) { | ||
| 128 | + ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 129 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | ||
| 130 | + } | ||
| 131 | + // 调用aclnnKlDivBackward第二段接口 | ||
| 132 | + ret = aclnnKlDivBackward(workspaceAddr, workspaceSize, executor, stream); | ||
| 133 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnKlDivBackward failed. ERROR: %d\n", ret); return ret); | ||
| 134 | + | ||
| 135 | + // 4. (固定写法)同步等待任务执行结束 | ||
| 136 | + ret = aclrtSynchronizeStream(stream); | ||
| 137 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 138 | + | ||
| 139 | + // 5. 获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改 | ||
| 140 | + auto size = GetShapeSize(outShape); | ||
| 141 | + std::vector<float> resultData(size, 0); | ||
| 142 | + ret = aclrtMemcpy( | ||
| 143 | + resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr, size * sizeof(resultData[0]), | ||
| 144 | + ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 145 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy resultData from device to host failed. ERROR: %d\n", ret); | ||
| 146 | + return ret); | ||
| 147 | + for (int64_t i = 0; i < size; i++) { | ||
| 148 | + LOG_PRINT("resultData[%ld] is: %f\n", i, resultData[i]); | ||
| 149 | + } | ||
| 150 | + | ||
| 151 | + // 6. 释放aclTensor,需要根据具体API的接口定义修改 | ||
| 152 | + aclDestroyTensor(gradOutput); | ||
| 153 | + aclDestroyTensor(self); | ||
| 154 | + aclDestroyTensor(target); | ||
| 155 | + aclDestroyTensor(out); | ||
| 156 | + | ||
| 157 | + // 7. 释放device资源,需要根据具体API的接口定义修改 | ||
| 158 | + aclrtFree(gradOutputDeviceAddr); | ||
| 159 | + aclrtFree(selfDeviceAddr); | ||
| 160 | + aclrtFree(targetDeviceAddr); | ||
| 161 | + aclrtFree(outDeviceAddr); | ||
| 162 | + if (workspaceSize > 0) { | ||
| 163 | + aclrtFree(workspaceAddr); | ||
| 164 | + } | ||
| 165 | + aclrtDestroyStream(stream); | ||
| 166 | + aclrtResetDevice(deviceId); | ||
| 167 | + aclFinalize(); | ||
| 168 | + return 0; | ||
| 169 | +} | ||
| @@ -0,0 +1,11 @@ | |||
| 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 | +add_modules_sources(HOSTNAME ${OPHOST_NAME} MODE PRIVATE DIR ${CMAKE_CURRENT_SOURCE_DIR} OPTYPE kl_div_loss_grad ACLNNTYPE aclnn_exclude) | ||
| @@ -0,0 +1,35 @@ | |||
| 1 | +/** | ||
F | |||
| 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 kl_div_loss_grad.cpp | ||
| 13 | + * \brief | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + | ||
| 17 | +namespace ops { | ||
| 18 | +static const std::vector<ge::DataType> dataType = {ge::DT_BF16, ge::DT_FLOAT16, ge::DT_FLOAT}; | ||
| 19 | +static const std::vector<ge::Format> dataFormat = {ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND}; | ||
| 20 | +class KlDivLossGrad : public OpDef { | ||
| 21 | +public: | ||
| 22 | + explicit KlDivLossGrad(const char* name) : OpDef(name) | ||
| 23 | + { | ||
| 24 | + this->Input("grad").ParamType(REQUIRED).DataType(dataType).Format(dataFormat); | ||
| 25 | + this->Input("input").ParamType(REQUIRED).DataType(dataType).Format(dataFormat); | ||
| 26 | + this->Input("target").ParamType(REQUIRED).DataType(dataType).Format(dataFormat); | ||
| 27 | + this->Output("y").ParamType(REQUIRED).DataType(dataType).Format(dataFormat); | ||
| 28 | + this->Attr("reduction").AttrType(OPTIONAL).String("mean"); | ||
| 29 | + this->Attr("log_target").AttrType(OPTIONAL).Bool(false); | ||
| 30 | + | ||
| 31 | + this->AICore().AddConfig("ascend910b"); | ||
| 32 | + } | ||
| 33 | +}; | ||
| 34 | +OP_ADD(KlDivLossGrad); | ||
| 35 | +} // namespace ops | ||
| @@ -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 | + | ||
| 11 | +/*! | ||
| 12 | + * \file kl_div_loss_grad_infer.cpp | ||
| 13 | + * \brief | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | +using namespace ge; | ||
| 19 | + | ||
| 20 | +namespace ops { | ||
| 21 | +ge::graphStatus CopyShapeInput2OutputWithForKlDivLossGrad( | ||
| 22 | + gert::InferShapeContext* context, int64_t input_idx, int64_t output_idx) | ||
| 23 | +{ | ||
| 24 | + auto in_shape = context->GetInputShape(input_idx); | ||
| 25 | + OP_CHECK_NULL_WITH_CONTEXT(context, in_shape); | ||
| 26 | + auto out_shape = context->GetOutputShape(output_idx); | ||
| 27 | + OP_CHECK_NULL_WITH_CONTEXT(context, out_shape); | ||
| 28 | + *out_shape = *in_shape; | ||
| 29 | + return ge::GRAPH_SUCCESS; | ||
| 30 | +} | ||
| 31 | + | ||
| 32 | +static ge::graphStatus InferShape4InIdx1AndOutIdx0(gert::InferShapeContext* context) | ||
| 33 | +{ | ||
| 34 | + constexpr size_t input_index = 1; | ||
| 35 | + constexpr size_t output_index = 0; | ||
| 36 | + return CopyShapeInput2OutputWithForKlDivLossGrad(context, input_index, output_index); | ||
| 37 | +} | ||
| 38 | + | ||
| 39 | +graphStatus InferDtypeForKlDivLossGrad(gert::InferDataTypeContext* context) | ||
| 40 | +{ | ||
| 41 | + auto xDtype = context->GetInputDataType(0); | ||
| 42 | + context->SetOutputDataType(0, xDtype); | ||
| 43 | + return GRAPH_SUCCESS; | ||
| 44 | +} | ||
| 45 | + | ||
| 46 | +IMPL_OP_INFERSHAPE(KlDivLossGrad).InferShape(InferShape4InIdx1AndOutIdx0).InferDataType(InferDtypeForKlDivLossGrad); | ||
| 47 | +} // namespace ops | ||
| @@ -0,0 +1,282 @@ | |||
| 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 kl_div_loss_grad_tiling.cpp | ||
| 13 | + * \brief | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | +namespace optiling { | ||
| 25 | + | ||
| 26 | +struct KlDivLossGradCompileInfo {}; | ||
| 27 | + | ||
| 28 | +enum Reduction { | ||
| 29 | + NONE, | ||
| 30 | + MEAN, | ||
| 31 | + SUM, | ||
| 32 | + BATCHMEAN, | ||
| 33 | +}; | ||
| 34 | + | ||
| 35 | +static ge::graphStatus GetPlatformInfo(gert::TilingContext* context, uint64_t& ubSize, int64_t& coreNum) | ||
| 36 | +{ | ||
| 37 | + // 获取平台信息指针 | ||
| 38 | + fe::PlatFormInfos* platformInfoPtr = context->GetPlatformInfo(); | ||
| 39 | + OP_CHECK_NULL_WITH_CONTEXT(context, platformInfoPtr); | ||
| 40 | + | ||
| 41 | + // 创建AscendC平台对象 | ||
| 42 | + auto ascendcPlatform = platform_ascendc::PlatformAscendC(platformInfoPtr); | ||
| 43 | + | ||
| 44 | + // 获取AI Core数量 | ||
| 45 | + coreNum = ascendcPlatform.GetCoreNumAiv(); | ||
| 46 | + OP_CHECK_IF(coreNum == 0, OP_LOGE(context, "coreNum is 0"), return ge::GRAPH_FAILED); | ||
| 47 | + | ||
| 48 | + // 获取UB(统一缓冲区)大小 | ||
| 49 | + ascendcPlatform.GetCoreMemSize(platform_ascendc::CoreMemType::UB, ubSize); | ||
| 50 | + OP_CHECK_IF(ubSize == 0, OP_LOGE(context, "ubSize is 0"), return ge::GRAPH_FAILED); | ||
| 51 | + | ||
| 52 | + return ge::GRAPH_SUCCESS; | ||
| 53 | +} | ||
| 54 | + | ||
| 55 | +static ge::graphStatus GetShapeInfo( | ||
| 56 | + gert::TilingContext* context, int64_t& inputNum, int64_t& gradNum, int64_t& batchSize) | ||
| 57 | +{ | ||
| 58 | + // 获取输入grad的shape信息 | ||
| 59 | + auto inputGrad = context->GetInputShape(0); | ||
| 60 | + OP_CHECK_NULL_WITH_CONTEXT(context, inputGrad); | ||
| 61 | + | ||
| 62 | + // 如果输入shape是标量,转换为{1},否则保持原shape不变 | ||
| 63 | + auto inputShapeGrad = Ops::NN::OpTiling::EnsureNotScalar(inputGrad->GetStorageShape()); | ||
| 64 | + gradNum = inputShapeGrad.GetShapeSize(); | ||
| 65 | + | ||
| 66 | + // 获取输入input的shape信息 | ||
| 67 | + auto inputInput = context->GetInputShape(1); | ||
| 68 | + OP_CHECK_NULL_WITH_CONTEXT(context, inputInput); | ||
| 69 | + | ||
| 70 | + // 如果输入shape是标量,转换为{1},否则保持原shape不变 | ||
| 71 | + auto inputShapeInput = Ops::NN::OpTiling::EnsureNotScalar(inputInput->GetStorageShape()); | ||
| 72 | + | ||
| 73 | + // 获取shape的大小与batch大小(用于后续batchmean计算) | ||
| 74 | + inputNum = inputShapeInput.GetShapeSize(); | ||
| 75 | + batchSize = inputShapeInput.GetDim(0); | ||
| 76 | + | ||
| 77 | + return ge::GRAPH_SUCCESS; | ||
| 78 | +} | ||
| 79 | + | ||
| 80 | +static ge::graphStatus GetAndValidateDtype(gert::TilingContext* context, ge::DataType& inputType) | ||
| 81 | +{ | ||
| 82 | + const std::set<ge::DataType> supportedDtype = {ge::DT_FLOAT, ge::DT_FLOAT16, ge::DT_BF16}; | ||
| 83 | + auto inputDesc = context->GetInputDesc(0); | ||
| 84 | + OP_CHECK_NULL_WITH_CONTEXT(context, inputDesc); | ||
| 85 | + inputType = inputDesc->GetDataType(); | ||
| 86 | + | ||
| 87 | + OP_CHECK_IF( | ||
| 88 | + supportedDtype.count(inputType) == 0, | ||
| 89 | + OP_LOGE(context, "KlDivLossGrad: invalid dtype, only support float, fp16 and bf16"), return ge::GRAPH_FAILED); | ||
| 90 | + | ||
| 91 | + return ge::GRAPH_SUCCESS; | ||
| 92 | +} | ||
| 93 | + | ||
| 94 | +static ge::graphStatus ParseAttrs(gert::TilingContext* context, Reduction& reduction, bool& logTarget) | ||
| 95 | +{ | ||
| 96 | + const gert::RuntimeAttrs* attrs = context->GetAttrs(); | ||
| 97 | + OP_CHECK_NULL_WITH_CONTEXT(context, attrs); | ||
| 98 | + | ||
| 99 | + const char* reductionPtr = attrs->GetStr(0); | ||
| 100 | + OP_CHECK_NULL_WITH_CONTEXT(context, reductionPtr); | ||
| 101 | + | ||
| 102 | + const bool* logTargetPtr = attrs->GetBool(1); | ||
| 103 | + OP_CHECK_NULL_WITH_CONTEXT(context, logTargetPtr); | ||
| 104 | + logTarget = *logTargetPtr; | ||
| 105 | + | ||
| 106 | + // 解析reduction属性 | ||
| 107 | + if (std::strcmp(reductionPtr, "none") == 0) { | ||
| 108 | + reduction = NONE; | ||
| 109 | + } else if (std::strcmp(reductionPtr, "mean") == 0) { | ||
| 110 | + reduction = MEAN; | ||
| 111 | + } else if (std::strcmp(reductionPtr, "sum") == 0) { | ||
| 112 | + reduction = SUM; | ||
| 113 | + } else if (std::strcmp(reductionPtr, "batchmean") == 0) { | ||
| 114 | + reduction = BATCHMEAN; | ||
| 115 | + } else { | ||
| 116 | + OP_LOGE(context, "KlDivLossGrad: invalid reduction type: %s", reductionPtr); | ||
| 117 | + return ge::GRAPH_FAILED; | ||
| 118 | + } | ||
| 119 | + | ||
| 120 | + return ge::GRAPH_SUCCESS; | ||
| 121 | +} | ||
| 122 | + | ||
| 123 | +ge::graphStatus GetWorkspaceSize(gert::TilingContext* context) | ||
| 124 | +{ | ||
| 125 | + // 获取工作空间大小数组 | ||
| 126 | + size_t* currentWorkspace = context->GetWorkspaceSizes(1); | ||
| 127 | + OP_CHECK_NULL_WITH_CONTEXT(context, currentWorkspace); | ||
| 128 | + currentWorkspace[0] = 0; | ||
| 129 | + return ge::GRAPH_SUCCESS; | ||
| 130 | +} | ||
| 131 | + | ||
| 132 | +static ge::graphStatus ComputeTilingParams( | ||
| 133 | + gert::TilingContext* context, uint64_t ubSize, int64_t coreNum, int64_t inputNum, int64_t gradNum, | ||
| 134 | + ge::DataType inputType, Reduction reduction, int64_t batchSize, int64_t& bigCoreDataNum, int64_t& smallCoreDataNum, | ||
| 135 | + int64_t& tileDataNum, int64_t& bigCoreNum, float& coff, int64_t& usedCoreNum) | ||
| 136 | +{ | ||
| 137 | + int64_t ubBlockSize = Ops::Base::GetUbBlockSize(context); | ||
| 138 | + int64_t inputTypeLength = (inputType == ge::DT_FLOAT) ? 4 : 2; | ||
| 139 | + int64_t blockElemNum = ubBlockSize / inputTypeLength; | ||
| 140 | + | ||
| 141 | + int64_t ubTileNum; | ||
| 142 | + if (gradNum != 1) { | ||
| 143 | + ubTileNum = (inputTypeLength == 2) ? 12 : 6; | ||
| 144 | + } else { | ||
| 145 | + ubTileNum = (inputTypeLength == 2) ? 8 : 4; | ||
| 146 | + } | ||
| 147 | + int64_t ubBlockNum = Ops::Base::FloorDiv(ubSize, static_cast<uint64_t>(ubBlockSize)); | ||
| 148 | + int64_t tileBlockNum = Ops::Base::FloorDiv(ubBlockNum, ubTileNum); | ||
| 149 | + OP_CHECK_IF(tileBlockNum == 0, OP_LOGE(context, "tileBlockNum is 0"), return ge::GRAPH_FAILED); | ||
| 150 | + | ||
| 151 | + tileDataNum = tileBlockNum * blockElemNum; | ||
| 152 | + | ||
| 153 | + int64_t inputBlockNum = Ops::Base::CeilDiv(inputNum, blockElemNum); | ||
| 154 | + | ||
| 155 | + // 核切分:优先使用更多的核并行计算 | ||
| 156 | + int64_t maxCoreNum = Ops::Base::CeilDiv(inputBlockNum, tileBlockNum); | ||
| 157 | + usedCoreNum = std::max(std::min(coreNum, maxCoreNum), static_cast<int64_t>(1)); | ||
| 158 | + | ||
| 159 | + int64_t smallCoreBlockNum = Ops::Base::FloorDiv(inputBlockNum, usedCoreNum); | ||
| 160 | + bigCoreNum = inputBlockNum % usedCoreNum; | ||
| 161 | + | ||
| 162 | + smallCoreDataNum = smallCoreBlockNum * blockElemNum; | ||
| 163 | + bigCoreDataNum = smallCoreDataNum + blockElemNum; | ||
| 164 | + | ||
| 165 | + // 计算系数 | ||
| 166 | + coff = 1.0f; | ||
| 167 | + if (reduction == BATCHMEAN) { | ||
| 168 | + OP_CHECK_IF(batchSize == 0, OP_LOGE(context, "batchSize is 0"), return ge::GRAPH_FAILED); | ||
| 169 | + coff = 1.0f / batchSize; | ||
| 170 | + } else if (reduction == MEAN) { | ||
| 171 | + OP_CHECK_IF(inputNum == 0, OP_LOGE(context, "inputNum is 0"), return ge::GRAPH_FAILED); | ||
| 172 | + coff = 1.0f / inputNum; | ||
| 173 | + } | ||
| 174 | + | ||
| 175 | + return ge::GRAPH_SUCCESS; | ||
| 176 | +} | ||
| 177 | + | ||
| 178 | +static ge::graphStatus SetTilingInfo( | ||
| 179 | + gert::TilingContext* context, int64_t bigCoreDataNum, int64_t smallCoreDataNum, int64_t tileDataNum, | ||
| 180 | + int64_t bigCoreNum, float coff, int64_t usedCoreNum, bool logTarget, bool isScalarGrad) | ||
| 181 | +{ | ||
| 182 | + KlDivLossGradTilingData* tiling = context->GetTilingData<KlDivLossGradTilingData>(); | ||
| 183 | + OP_CHECK_NULL_WITH_CONTEXT(context, tiling); | ||
| 184 | + | ||
| 185 | + // 初始化tiling数据为0 | ||
| 186 | + OP_CHECK_IF( | ||
| 187 | + memset_s(tiling, sizeof(KlDivLossGradTilingData), 0, sizeof(KlDivLossGradTilingData)) != EOK, | ||
| 188 | + OP_LOGE(context, "set tiling data error"), return ge::GRAPH_FAILED); | ||
| 189 | + | ||
| 190 | + tiling->bigCoreDataNum = bigCoreDataNum; | ||
| 191 | + tiling->smallCoreDataNum = smallCoreDataNum; | ||
| 192 | + tiling->tileDataNum = tileDataNum; | ||
| 193 | + tiling->bigCoreNum = bigCoreNum; | ||
| 194 | + tiling->coff = coff; | ||
| 195 | + | ||
| 196 | + // 设置使用的AI Core数量 | ||
| 197 | + context->SetBlockDim(usedCoreNum); | ||
| 198 | + | ||
| 199 | + // 根据属性设置tiling key | ||
| 200 | + uint64_t tilingKey = GET_TPL_TILING_KEY(logTarget, isScalarGrad); | ||
| 201 | + context->SetTilingKey(tilingKey); | ||
| 202 | + | ||
| 203 | + return ge::GRAPH_SUCCESS; | ||
| 204 | +} | ||
| 205 | + | ||
| 206 | +static ge::graphStatus KlDivLossGradTilingComputeAndSet( | ||
| 207 | + gert::TilingContext* context, uint64_t ubSize, int64_t coreNum, int64_t inputNum, int64_t gradNum, | ||
| 208 | + ge::DataType inputType, Reduction reduction, int64_t batchSize, bool logTarget) | ||
| 209 | +{ | ||
| 210 | + // 计算Tiling切分信息 | ||
| 211 | + int64_t bigCoreDataNum; | ||
| 212 | + int64_t smallCoreDataNum; | ||
| 213 | + int64_t tileDataNum; | ||
| 214 | + int64_t bigCoreNum; | ||
| 215 | + float coff; | ||
| 216 | + int64_t usedCoreNum; | ||
| 217 | + OP_CHECK_IF( | ||
| 218 | + ComputeTilingParams( | ||
| 219 | + context, ubSize, coreNum, inputNum, gradNum, inputType, reduction, batchSize, bigCoreDataNum, | ||
| 220 | + smallCoreDataNum, tileDataNum, bigCoreNum, coff, usedCoreNum) != ge::GRAPH_SUCCESS, | ||
| 221 | + OP_LOGE(context, "ComputeTilingParams error"), return ge::GRAPH_FAILED); | ||
| 222 | + | ||
| 223 | + // 设置tiling信息 | ||
| 224 | + OP_CHECK_IF( | ||
| 225 | + SetTilingInfo( | ||
| 226 | + context, bigCoreDataNum, smallCoreDataNum, tileDataNum, bigCoreNum, coff, usedCoreNum, logTarget, | ||
| 227 | + (gradNum == 1)) != ge::GRAPH_SUCCESS, | ||
| 228 | + OP_LOGE(context, "SetTilingInfo error"), return ge::GRAPH_FAILED); | ||
| 229 | + | ||
| 230 | + return ge::GRAPH_SUCCESS; | ||
| 231 | +} | ||
| 232 | + | ||
| 233 | +static ge::graphStatus KlDivLossGradTilingFunc(gert::TilingContext* context) | ||
| 234 | +{ | ||
| 235 | + // 1、获取平台运行时信息 | ||
| 236 | + uint64_t ubSize; | ||
| 237 | + int64_t coreNum; | ||
| 238 | + OP_CHECK_IF( | ||
| 239 | + GetPlatformInfo(context, ubSize, coreNum) != ge::GRAPH_SUCCESS, OP_LOGE(context, "GetPlatformInfo error"), | ||
| 240 | + return ge::GRAPH_FAILED); | ||
| 241 | + | ||
| 242 | + // 2、获取shape信息 | ||
| 243 | + int64_t inputNum; | ||
| 244 | + int64_t gradNum; | ||
| 245 | + int64_t batchSize; | ||
| 246 | + OP_CHECK_IF( | ||
| 247 | + GetShapeInfo(context, inputNum, gradNum, batchSize) != ge::GRAPH_SUCCESS, | ||
| 248 | + OP_LOGE(context, "GetShapeInfo error"), return ge::GRAPH_FAILED); | ||
| 249 | + | ||
| 250 | + // 3、获取并校验数据类型 | ||
| 251 | + ge::DataType inputType; | ||
| 252 | + OP_CHECK_IF( | ||
| 253 | + GetAndValidateDtype(context, inputType) != ge::GRAPH_SUCCESS, OP_LOGE(context, "GetAndValidateDtype error"), | ||
| 254 | + return ge::GRAPH_FAILED); | ||
| 255 | + | ||
| 256 | + // 4、解析属性 | ||
| 257 | + Reduction reduction; | ||
| 258 | + bool logTarget; | ||
| 259 | + OP_CHECK_IF( | ||
| 260 | + ParseAttrs(context, reduction, logTarget) != ge::GRAPH_SUCCESS, OP_LOGE(context, "ParseAttrs error"), | ||
| 261 | + return ge::GRAPH_FAILED); | ||
| 262 | + | ||
| 263 | + // 5、获取WorkspaceSize信息 | ||
| 264 | + OP_CHECK_IF( | ||
| 265 | + GetWorkspaceSize(context) != ge::GRAPH_SUCCESS, OP_LOGE(context, "GetWorkspaceSize error"), | ||
| 266 | + return ge::GRAPH_FAILED); | ||
| 267 | + | ||
| 268 | + // 6、计算Tiling切分信息并设置 | ||
| 269 | + return KlDivLossGradTilingComputeAndSet( | ||
| 270 | + context, ubSize, coreNum, inputNum, gradNum, inputType, reduction, batchSize, logTarget); | ||
| 271 | +} | ||
| 272 | + | ||
| 273 | +static ge::graphStatus TilingParseForKlDivLossGrad([[maybe_unused]] gert::TilingParseContext* context) | ||
| 274 | +{ | ||
| 275 | + return ge::GRAPH_SUCCESS; | ||
| 276 | +} | ||
| 277 | + | ||
| 278 | +// tiling注册入口. | ||
| 279 | +IMPL_OP_OPTILING(KlDivLossGrad) | ||
| 280 | + .Tiling(KlDivLossGradTilingFunc) | ||
| 281 | + .TilingParse<KlDivLossGradCompileInfo>(TilingParseForKlDivLossGrad); | ||
| 282 | +} // namespace optiling | ||
| @@ -0,0 +1,266 @@ | |||
| 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 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + | ||
| 30 | +using namespace op; | ||
| 31 | + | ||
| 32 | +extern "C" { | ||
| 33 | + | ||
| 34 | + | ||
| 35 | +enum Reduction { None = 0, Mean = 1, Sum = 2, Batchmean = 3, End }; | ||
| 36 | + | ||
| 37 | +static const char* REDUCTION_NONE = "none"; | ||
| 38 | +static const char* REDUCTION_MEAN = "mean"; | ||
| 39 | +static const char* REDUCTION_SUM = "sum"; | ||
| 40 | +static const char* REDUCTION_BATCHMEAN = "batchmean"; | ||
| 41 | + | ||
| 42 | +static const std::initializer_list<op::DataType> ASCEND910B_DTYPE_SUPPORT_LIST = { | ||
| 43 | + op::DataType::DT_FLOAT, op::DataType::DT_FLOAT16, op::DataType::DT_BF16}; | ||
| 44 | + | ||
| 45 | +static const inline std::initializer_list<DataType>& GetSupportDtypeList() | ||
| 46 | +{ | ||
| 47 | + static const std::initializer_list<DataType> emptyDtypes = {}; | ||
| 48 | + if (GetCurrentPlatformInfo().GetCurNpuArch() == NpuArch::DAV_2201) { | ||
| 49 | + return ASCEND910B_DTYPE_SUPPORT_LIST; | ||
| 50 | + } | ||
| 51 | + return emptyDtypes; | ||
| 52 | +} | ||
| 53 | + | ||
| 54 | +static bool CheckDtypeValid( | ||
| 55 | + const aclTensor* gradOutput, const aclTensor* self, const aclTensor* target, const aclTensor* out) | ||
| 56 | +{ | ||
| 57 | + const auto& supportList = GetSupportDtypeList(); | ||
| 58 | + if (supportList.size() == 0) { | ||
| 59 | + OP_LOGE( | ||
| 60 | + ACLNN_ERR_PARAM_INVALID, "support for npuArch %u is not implemented", | ||
| 61 | + static_cast<uint32_t>(GetCurrentPlatformInfo().GetCurNpuArch())); | ||
| 62 | + return false; | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + OP_CHECK_RESULT_DTYPE_CAST_FAILED(self->GetDataType(), out->GetDataType(), return false); | ||
| 66 | + // 检查gradOutput的数据类型是否在支持列表内 | ||
| 67 | + OP_CHECK_DTYPE_NOT_SUPPORT(gradOutput, supportList, return false); | ||
| 68 | + // 检查self的数据类型是否在支持列表内 | ||
| 69 | + OP_CHECK_DTYPE_NOT_SUPPORT(self, supportList, return false); | ||
| 70 | + // 检查target的数据类型是否在支持列表内 | ||
| 71 | + OP_CHECK_DTYPE_NOT_SUPPORT(target, supportList, return false); | ||
| 72 | + // 检查out的数据类型是否在支持列表内 | ||
| 73 | + OP_CHECK_DTYPE_NOT_SUPPORT(out, supportList, return false); | ||
| 74 | + | ||
| 75 | + return true; | ||
| 76 | +} | ||
| 77 | + | ||
| 78 | +constexpr size_t MAX_DIM_LEN = 8; | ||
| 79 | + | ||
| 80 | +static bool CheckShape( | ||
| 81 | + const aclTensor* gradOutput, const aclTensor* self, const aclTensor* target, const aclTensor* out) | ||
| 82 | +{ | ||
| 83 | + OP_CHECK_MAX_DIM(gradOutput, MAX_DIM_LEN, return false); | ||
| 84 | + OP_CHECK_MAX_DIM(self, MAX_DIM_LEN, return false); | ||
| 85 | + OP_CHECK_MAX_DIM(target, MAX_DIM_LEN, return false); | ||
| 86 | + OP_CHECK_MAX_DIM(out, MAX_DIM_LEN, return false); | ||
| 87 | + | ||
| 88 | + op::Shape broadcastShape; | ||
| 89 | + op::Shape broadcastGradShape; | ||
| 90 | + OP_CHECK_BROADCAST_AND_INFER_SHAPE(self, target, broadcastShape, return false); | ||
| 91 | + if (!BroadcastInferShape(gradOutput->GetViewShape(), broadcastShape, broadcastGradShape) || | ||
| 92 | + broadcastShape != broadcastGradShape) { | ||
| 93 | + OP_LOGE( | ||
| 94 | + ACLNN_ERR_PARAM_INVALID, "Except shape of gradOutput must broadcast to %s, but current is %s.", | ||
| 95 | + op::ToString(broadcastShape).GetString(), op::ToString(gradOutput->GetViewShape()).GetString()); | ||
| 96 | + return false; | ||
| 97 | + } | ||
| 98 | + OP_CHECK_SHAPE_NOT_EQUAL(self, out, return false); | ||
| 99 | + | ||
| 100 | + return true; | ||
| 101 | +} | ||
| 102 | + | ||
| 103 | +static aclnnStatus CheckParams( | ||
| 104 | + const aclTensor* gradOutput, const aclTensor* self, const aclTensor* target, aclTensor* out) | ||
| 105 | +{ | ||
| 106 | + // 1. 检查参数是否为空指针 | ||
| 107 | + CHECK_RET(CheckNotNull4Tensor(gradOutput, self, target, out), ACLNN_ERR_PARAM_NULLPTR); | ||
| 108 | + | ||
| 109 | + // 2. 检查输入的数据类型是否在API支持的数据类型范围之内,需要根据api定义校验 | ||
| 110 | + CHECK_RET(CheckDtypeValid(gradOutput, self, target, out), ACLNN_ERR_PARAM_INVALID); | ||
| 111 | + | ||
| 112 | + // 3. 检查输入输出shape | ||
| 113 | + CHECK_RET(CheckShape(gradOutput, self, target, out), ACLNN_ERR_PARAM_INVALID); | ||
| 114 | + | ||
| 115 | + return ACLNN_SUCCESS; | ||
| 116 | +} | ||
| 117 | + | ||
| 118 | +static const char* GetReductionStr(int64_t reduction) | ||
| 119 | +{ | ||
| 120 | + if (reduction == None) { | ||
| 121 | + return REDUCTION_NONE; | ||
| 122 | + } else if (reduction == Mean) { | ||
| 123 | + return REDUCTION_MEAN; | ||
| 124 | + } else if (reduction == Sum) { | ||
| 125 | + return REDUCTION_SUM; | ||
| 126 | + } else if (reduction == Batchmean) { | ||
| 127 | + return REDUCTION_BATCHMEAN; | ||
| 128 | + } else { | ||
| 129 | + return REDUCTION_NONE; | ||
| 130 | + } | ||
| 131 | +} | ||
| 132 | + | ||
| 133 | +static const aclTensor* BroadcastTensor(const aclTensor* self, const op::Shape broadcastShape, aclOpExecutor* executor) | ||
| 134 | +{ | ||
| 135 | + // 如果self的shape与broadcast的不一致,进行BroadcastTo | ||
| 136 | + if (self->GetViewShape() != broadcastShape) { | ||
| 137 | + auto broadcastShapeIntArray = GetBroadcastShapeLossBackward(broadcastShape, executor); | ||
| 138 | + if (broadcastShapeIntArray != nullptr) { | ||
| 139 | + return l0op::BroadcastTo(self, broadcastShapeIntArray, executor); | ||
| 140 | + } | ||
| 141 | + } | ||
| 142 | + return self; | ||
| 143 | +} | ||
| 144 | + | ||
| 145 | +static const aclTensor* ReduceSumTensor(const aclTensor* grad, const op::Shape outShape, aclOpExecutor* executor) | ||
| 146 | +{ | ||
| 147 | + // 如果grad的shape与outShape不一致,进行ReduceSum | ||
| 148 | + if (grad->GetViewShape() != outShape) { | ||
| 149 | + size_t outDimNum = outShape.GetDimNum(); | ||
| 150 | + size_t gradDimNum = grad->GetViewShape().GetDimNum(); | ||
| 151 | + size_t startDim = gradDimNum - outDimNum; | ||
| 152 | + size_t dimIdx = startDim; | ||
| 153 | + std::vector<int64_t> appendDim; | ||
| 154 | + for (size_t i = 0; i < startDim; ++i) { | ||
| 155 | + appendDim.push_back(i); | ||
| 156 | + } | ||
| 157 | + for (size_t j = startDim; j < gradDimNum; ++j) { | ||
| 158 | + if (outShape[j - startDim] != (grad->GetViewShape())[j]) { | ||
| 159 | + appendDim.push_back(j); | ||
| 160 | + dimIdx++; | ||
| 161 | + } | ||
| 162 | + } | ||
| 163 | + auto axes = executor->AllocIntArray(appendDim.data(), dimIdx); | ||
| 164 | + auto out = l0op::ReduceSumOp(grad, axes, true, executor); | ||
| 165 | + CHECK_RET(out != nullptr, nullptr); | ||
| 166 | + auto outShapeIntArray = GetBroadcastShapeLossBackward(outShape, executor); | ||
| 167 | + return l0op::Reshape(out, outShapeIntArray, executor); | ||
| 168 | + } | ||
| 169 | + return grad; | ||
| 170 | +} | ||
| 171 | + | ||
| 172 | +aclnnStatus aclnnKlDivBackwardGetWorkspaceSize( | ||
| 173 | + const aclTensor* gradOutput, const aclTensor* self, const aclTensor* target, int64_t reduction, bool logTarget, | ||
| 174 | + aclTensor* out, uint64_t* workspaceSize, aclOpExecutor** executor) | ||
| 175 | +{ | ||
| 176 | + OP_CHECK_COMM_INPUT(workspaceSize, executor); | ||
| 177 | + | ||
| 178 | + L2_DFX_PHASE_1(aclnnKlDivBackward, DFX_IN(gradOutput, self, target, reduction, logTarget), DFX_OUT(out)); | ||
| 179 | + // 固定写法,创建OpExecutor | ||
| 180 | + auto uniqueExecutor = CREATE_EXECUTOR(); | ||
| 181 | + CHECK_RET(uniqueExecutor.get() != nullptr, ACLNN_ERR_INNER_CREATE_EXECUTOR); | ||
| 182 | + | ||
| 183 | + // 固定写法,参数检查 | ||
| 184 | + auto ret = CheckParams(gradOutput, self, target, out); | ||
| 185 | + CHECK_RET(ret == ACLNN_SUCCESS, ret); | ||
| 186 | + | ||
| 187 | + if (self->IsEmpty()) { | ||
| 188 | + // 根据实际支持情况补充 | ||
| 189 | + *workspaceSize = 0; | ||
| 190 | + uniqueExecutor.ReleaseTo(executor); | ||
| 191 | + return ACLNN_SUCCESS; | ||
| 192 | + } | ||
| 193 | + | ||
| 194 | + // 固定写法,将输入gradOutput转换成连续的tensor | ||
| 195 | + auto gradOutputContiguous = l0op::Contiguous(gradOutput, uniqueExecutor.get()); | ||
| 196 | + CHECK_RET(gradOutputContiguous != nullptr, ACLNN_ERR_INNER_NULLPTR); | ||
| 197 | + | ||
| 198 | + // 固定写法,将输入self转换成连续的tensor | ||
| 199 | + auto selfContiguous = l0op::Contiguous(self, uniqueExecutor.get()); | ||
| 200 | + CHECK_RET(selfContiguous != nullptr, ACLNN_ERR_INNER_NULLPTR); | ||
| 201 | + | ||
| 202 | + // 固定写法,将输入target转换成连续的tensor | ||
| 203 | + auto targetContiguous = l0op::Contiguous(target, uniqueExecutor.get()); | ||
| 204 | + CHECK_RET(targetContiguous != nullptr, ACLNN_ERR_INNER_NULLPTR); | ||
| 205 | + | ||
| 206 | + auto gradOutputCasted = gradOutputContiguous; | ||
| 207 | + auto selfCasted = selfContiguous; | ||
| 208 | + auto targetCasted = targetContiguous; | ||
| 209 | + if (!(gradOutput->GetDataType() == op::DataType::DT_FLOAT16 && self->GetDataType() == op::DataType::DT_FLOAT16 && | ||
| 210 | + target->GetDataType() == op::DataType::DT_FLOAT16)) { | ||
| 211 | + auto promoteType = op::DataType::DT_FLOAT; | ||
| 212 | + | ||
| 213 | + // 将输入gradoutput的数据类型转换成隐式数据类型,根据具体算子语义按需调用 | ||
| 214 | + gradOutputCasted = l0op::Cast(gradOutputContiguous, promoteType, uniqueExecutor.get()); | ||
| 215 | + CHECK_RET(gradOutputCasted != nullptr, ACLNN_ERR_INNER_NULLPTR); | ||
| 216 | + | ||
| 217 | + // 将输入self的数据类型转换成隐式数据类型,根据具体算子语义按需调用 | ||
| 218 | + selfCasted = l0op::Cast(selfContiguous, promoteType, uniqueExecutor.get()); | ||
| 219 | + CHECK_RET(selfCasted != nullptr, ACLNN_ERR_INNER_NULLPTR); | ||
| 220 | + | ||
| 221 | + // 将输入target的数据类型转换成隐式数据类型,根据具体算子语义按需调用 | ||
| 222 | + targetCasted = l0op::Cast(targetContiguous, promoteType, uniqueExecutor.get()); | ||
| 223 | + CHECK_RET(targetCasted != nullptr, ACLNN_ERR_INNER_NULLPTR); | ||
| 224 | + } | ||
| 225 | + | ||
| 226 | + op::Shape broadcastShape; | ||
| 227 | + BroadcastInferShape(target->GetViewShape(), self->GetViewShape(), broadcastShape); | ||
| 228 | + | ||
| 229 | + // 判断self是否需要进行broadcast | ||
| 230 | + auto selfBroadcast = BroadcastTensor(selfCasted, broadcastShape, uniqueExecutor.get()); | ||
| 231 | + CHECK_RET(selfBroadcast != nullptr, ACLNN_ERR_INNER_NULLPTR); | ||
| 232 | + | ||
| 233 | + // 进行计算 | ||
| 234 | + auto grad = l0op::KlDivLossGrad( | ||
| 235 | + gradOutputCasted, selfBroadcast, targetCasted, GetReductionStr(reduction), logTarget, uniqueExecutor.get()); | ||
| 236 | + CHECK_RET(grad != nullptr, ACLNN_ERR_INNER_NULLPTR); | ||
| 237 | + | ||
| 238 | + // 根据grad的shape是否与out的shape相同,判断是否需要reduce | ||
| 239 | + auto gradReduce = ReduceSumTensor(grad, out->GetViewShape(), uniqueExecutor.get()); | ||
| 240 | + CHECK_RET(gradReduce != nullptr, ACLNN_ERR_INNER_NULLPTR); | ||
| 241 | + | ||
| 242 | + // 固定写法,将计算结果转换成输出out的数据类型 | ||
| 243 | + auto castOut = l0op::Cast(gradReduce, out->GetDataType(), uniqueExecutor.get()); | ||
| 244 | + CHECK_RET(castOut != nullptr, ACLNN_ERR_INNER_NULLPTR); | ||
| 245 | + | ||
| 246 | + // 固定写法,将计算结果拷贝到输出out上,out可能是非连续的tensor | ||
| 247 | + auto viewCopyResult = l0op::ViewCopy(castOut, out, uniqueExecutor.get()); | ||
| 248 | + CHECK_RET(viewCopyResult != nullptr, ACLNN_ERR_INNER_NULLPTR); | ||
| 249 | + | ||
| 250 | + // 固定写法,获取计算过程中需要使用的workspace大小 | ||
| 251 | + *workspaceSize = uniqueExecutor->GetWorkspaceSize(); | ||
| 252 | + // 需要把 uniqueExecutor持有executor转移给executor | ||
| 253 | + uniqueExecutor.ReleaseTo(executor); | ||
| 254 | + return ACLNN_SUCCESS; | ||
| 255 | +} | ||
| 256 | + | ||
| 257 | +aclnnStatus aclnnKlDivBackward(void* workspace, uint64_t workspaceSize, aclOpExecutor* executor, aclrtStream stream) | ||
| 258 | +{ | ||
| 259 | + L2_DFX_PHASE_2(aclnnKlDivBackward); | ||
| 260 | + // 固定写法,调用框架能力,完成计算 | ||
| 261 | + return CommonOpExecutorRun(workspace, workspaceSize, executor, stream); | ||
| 262 | +} | ||
| 263 | + | ||
| 264 | + | ||
| 265 | +} | ||
| 266 | + | ||
| @@ -0,0 +1,39 @@ | |||
| 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 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | +extern "C" { | ||
| 19 | + | ||
| 20 | + | ||
| 21 | +/** | ||
| 22 | + * @brief aclnnKlDivBackward的第一段接口,根据具体的计算流程,计算workspace大小。 | ||
| 23 | + * @domain aclnn_ops_train | ||
| 24 | + */ | ||
| 25 | +ACLNN_API aclnnStatus aclnnKlDivBackwardGetWorkspaceSize( | ||
| 26 | + const aclTensor* gradOutput, const aclTensor* self, const aclTensor* target, int64_t reduction, bool logTarget, | ||
| 27 | + aclTensor* out, uint64_t* workspaceSize, aclOpExecutor** executor); | ||
| 28 | + | ||
| 29 | +/** | ||
| 30 | + * @brief aclnnKlDivBackward的第二段接口,用于执行计算。 | ||
| 31 | + */ | ||
| 32 | +ACLNN_API aclnnStatus | ||
| 33 | +aclnnKlDivBackward(void* workspace, uint64_t workspaceSize, aclOpExecutor* executor, aclrtStream stream); | ||
| 34 | + | ||
| 35 | + | ||
| 36 | +} | ||
| 37 | + | ||
| 38 | + | ||
| 39 | + | ||
| @@ -0,0 +1,66 @@ | |||
| 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 kl_div_loss_grad.cpp | ||
| 13 | + * \brief | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | +using namespace op; | ||
| 26 | + | ||
| 27 | +namespace l0op { | ||
| 28 | +OP_TYPE_REGISTER(KlDivLossGrad); | ||
| 29 | + | ||
| 30 | +static const std::initializer_list<op::DataType> AICORE_DTYPE_SUPPORT_LIST = { | ||
| 31 | + op::DataType::DT_FLOAT, op::DataType::DT_FLOAT16, op::DataType::DT_BF16}; | ||
| 32 | +// 根据芯片类型、dtype判断算子是否支持走aicore | ||
| 33 | +static bool IsAiCoreSupport(const aclTensor* self) | ||
| 34 | +{ | ||
| 35 | + // KlDivLossGrad只需要判断dtype | ||
| 36 | + return CheckType(self->GetDataType(), AICORE_DTYPE_SUPPORT_LIST); | ||
| 37 | +} | ||
| 38 | + | ||
| 39 | +// AICORE算子kernel | ||
| 40 | +static const aclTensor* KlDivLossGradAiCore( | ||
| 41 | + const aclTensor* gradOutput, const aclTensor* self, const aclTensor* target, const char* reduction, bool logTarget, | ||
| 42 | + aclTensor* out, aclOpExecutor* executor) | ||
| 43 | +{ | ||
| 44 | + L0_DFX(KlDivLossGradAiCore, gradOutput, self, target, reduction, logTarget); | ||
| 45 | + auto ret = ADD_TO_LAUNCHER_LIST_AICORE( | ||
| 46 | + KlDivLossGrad, OP_INPUT(gradOutput, self, target), OP_OUTPUT(out), OP_ATTR(reduction, logTarget)); | ||
| 47 | + OP_CHECK( | ||
| 48 | + ret == ACLNN_SUCCESS, | ||
| 49 | + OP_LOGE(ACLNN_ERR_INNER_NULLPTR, "KlDivLossGradAiCore ADD_TO_LAUNCHER_LIST_AICORE failed."), return nullptr); | ||
| 50 | + | ||
| 51 | + return out; | ||
| 52 | +} | ||
| 53 | + | ||
| 54 | +const aclTensor* KlDivLossGrad( | ||
| 55 | + const aclTensor* gradOutput, const aclTensor* self, const aclTensor* target, const char* reduction, bool logTarget, | ||
| 56 | + aclOpExecutor* executor) | ||
| 57 | +{ | ||
| 58 | + auto out = executor->AllocTensor(self->GetViewShape(), self->GetDataType(), self->GetStorageFormat()); | ||
| 59 | + if (IsAiCoreSupport(self)) { | ||
| 60 | + // 只走aicore | ||
| 61 | + return KlDivLossGradAiCore(gradOutput, self, target, reduction, logTarget, out, executor); | ||
| 62 | + } | ||
| 63 | + OP_LOGE(ACLNN_ERR_PARAM_INVALID, "KlDivLossGrad not supported: dtype=%d.", static_cast<int>(self->GetDataType())); | ||
| 64 | + return nullptr; | ||
| 65 | +} | ||
| 66 | +} // namespace l0op | ||
| @@ -0,0 +1,26 @@ | |||
| 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 kl_div_loss_grad.h | ||
| 13 | + * \brief | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | +namespace l0op { | ||
| 21 | +const aclTensor* KlDivLossGrad( | ||
| 22 | + const aclTensor* gradOutput, const aclTensor* self, const aclTensor* target, const char* reduction, bool logTarget, | ||
| 23 | + aclOpExecutor* executor); | ||
| 24 | +} | ||
| 25 | + | ||
| 26 | + | ||
| @@ -0,0 +1,59 @@ | |||
| 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 kl_div_loss_grad.cpp | ||
| 13 | + * \brief | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | +using namespace NsKlDivLossGrad; | ||
| 19 | + | ||
| 20 | +template <bool logTarget, bool broadcast> | ||
| 21 | +struct PolicySelector; | ||
| 22 | + | ||
| 23 | +template <> | ||
| 24 | +struct PolicySelector<false, false> { | ||
| 25 | + template <class T> | ||
| 26 | + using type = ComputeImpl<T>; | ||
| 27 | +}; | ||
| 28 | + | ||
| 29 | +template <> | ||
| 30 | +struct PolicySelector<true, false> { | ||
| 31 | + template <class T> | ||
| 32 | + using type = ComputeImplLog<T>; | ||
| 33 | +}; | ||
| 34 | + | ||
| 35 | +template <> | ||
| 36 | +struct PolicySelector<false, true> { | ||
| 37 | + template <class T> | ||
| 38 | + using type = ComputeImplBroadCast<T>; | ||
| 39 | +}; | ||
| 40 | + | ||
| 41 | +template <> | ||
| 42 | +struct PolicySelector<true, true> { | ||
| 43 | + template <class T> | ||
| 44 | + using type = ComputeImplBroadCastLog<T>; | ||
| 45 | +}; | ||
| 46 | + | ||
| 47 | +template <bool logTarget, bool broadcast> | ||
| 48 | +__global__ __aicore__ void kl_div_loss_grad( | ||
| 49 | + GM_ADDR grad, GM_ADDR input, GM_ADDR target, GM_ADDR y, GM_ADDR workspace, GM_ADDR tiling) | ||
| 50 | +{ | ||
| 51 | + REGISTER_TILING_DEFAULT(KlDivLossGradTilingData); | ||
| 52 | + GET_TILING_DATA_WITH_STRUCT(KlDivLossGradTilingData, tilingData, tiling); | ||
| 53 | + KernelKlDivLossGrad<DTYPE_GRAD, PolicySelector<logTarget, broadcast>::template type> op; | ||
| 54 | + AscendC::TPipe pipe; | ||
| 55 | + op.Init( | ||
| 56 | + grad, input, target, y, tilingData.bigCoreDataNum, tilingData.smallCoreDataNum, tilingData.tileDataNum, | ||
| 57 | + tilingData.bigCoreNum, tilingData.coff, &pipe); | ||
| 58 | + op.Process(); | ||
| 59 | +} | ||
| @@ -0,0 +1,214 @@ | |||
| 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 kl_div_loss_grad.h | ||
| 13 | + * \brief | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | +namespace NsKlDivLossGrad { | ||
| 24 | +template <class T, template <class> class Policy> | ||
| 25 | +class KernelKlDivLossGrad { | ||
| 26 | + using PolicyType = Policy<float>; | ||
| 27 | + | ||
| 28 | +public: | ||
| 29 | + __aicore__ inline KernelKlDivLossGrad() {} | ||
| 30 | + __aicore__ inline void Init( | ||
| 31 | + GM_ADDR grad, GM_ADDR input, GM_ADDR target, GM_ADDR y, uint32_t bigCoreDataNum, uint32_t smallCoreDataNum, | ||
| 32 | + uint32_t tileDataNum, uint32_t bigCoreNum, float coeff, AscendC::TPipe* pipe) | ||
| 33 | + { | ||
| 34 | + uint32_t globalBufferIndex = bigCoreDataNum * AscendC::GetBlockIdx(); | ||
| 35 | + if (AscendC::GetBlockIdx() < bigCoreNum) { | ||
| 36 | + this->coreDataNum = bigCoreDataNum; | ||
| 37 | + } else { | ||
| 38 | + this->coreDataNum = smallCoreDataNum; | ||
| 39 | + globalBufferIndex -= (bigCoreDataNum - smallCoreDataNum) * (AscendC::GetBlockIdx() - bigCoreNum); | ||
| 40 | + } | ||
| 41 | + if constexpr (!PolicyType::broadcast) { | ||
| 42 | + gradGm.SetGlobalBuffer((__gm__ T*)grad + globalBufferIndex, this->coreDataNum); | ||
| 43 | + } else { | ||
| 44 | + gradGm.SetGlobalBuffer((__gm__ T*)grad, 1); | ||
| 45 | + } | ||
| 46 | + targetGm.SetGlobalBuffer((__gm__ T*)target + globalBufferIndex, this->coreDataNum); | ||
| 47 | + yGm.SetGlobalBuffer((__gm__ T*)y + globalBufferIndex, this->coreDataNum); | ||
| 48 | + | ||
| 49 | + if constexpr (!PolicyType::broadcast) { | ||
| 50 | + pipe->InitBuffer(inQueGrad, 2, tileDataNum * sizeof(T)); | ||
| 51 | + if constexpr (!std::is_same_v<T, float>) { | ||
| 52 | + pipe->InitBuffer(gradBuf, tileDataNum * sizeof(float)); | ||
| 53 | + } | ||
| 54 | + } | ||
| 55 | + pipe->InitBuffer(inQueTarget, 2, tileDataNum * sizeof(T)); | ||
| 56 | + if constexpr (!std::is_same_v<T, float>) { | ||
| 57 | + pipe->InitBuffer(targetBuf, tileDataNum * sizeof(float)); | ||
| 58 | + } | ||
| 59 | + pipe->InitBuffer(outQueY, 2, tileDataNum * sizeof(T)); | ||
| 60 | + if constexpr (!std::is_same_v<T, float>) { | ||
| 61 | + pipe->InitBuffer(yBuf, tileDataNum * sizeof(float)); | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | + this->tileDataNum = tileDataNum; | ||
| 65 | + if constexpr (PolicyType::broadcast) { | ||
| 66 | + if constexpr (std::is_same_v<T, bfloat16_t>) { | ||
| 67 | + policy.grad = AscendC::ToFloat(gradGm.GetValue(0)); | ||
| 68 | + } else { | ||
| 69 | + policy.grad = static_cast<float>(gradGm.GetValue(0)); | ||
| 70 | + } | ||
| 71 | + } | ||
| 72 | + policy.negCoeff = -coeff; | ||
| 73 | + } | ||
| 74 | + __aicore__ inline void Process() | ||
| 75 | + { | ||
| 76 | + uint64_t coreDataNum = this->coreDataNum; | ||
| 77 | + uint64_t tileDataNum = this->tileDataNum; | ||
| 78 | + for (uint64_t offset = 0; offset < coreDataNum; offset += tileDataNum) { | ||
| 79 | + uint32_t processDataNum = AscendC::Std::min(tileDataNum, coreDataNum - offset); | ||
| 80 | + CopyIn(offset, processDataNum); | ||
| 81 | + Compute(processDataNum); | ||
| 82 | + CopyOut(offset, processDataNum); | ||
| 83 | + } | ||
| 84 | + } | ||
| 85 | + | ||
| 86 | +private: | ||
| 87 | + __aicore__ inline void CopyIn(uint32_t offset, uint32_t processDataNum) | ||
| 88 | + { | ||
| 89 | + AscendC::LocalTensor<T> targetLocal = inQueTarget.AllocTensor<T>(); | ||
| 90 | + AscendC::DataCopy(targetLocal, targetGm[offset], processDataNum); | ||
| 91 | + inQueTarget.EnQue(targetLocal); | ||
| 92 | + if constexpr (!PolicyType::broadcast) { | ||
| 93 | + AscendC::LocalTensor<T> gradLocal = inQueGrad.AllocTensor<T>(); | ||
| 94 | + AscendC::DataCopy(gradLocal, gradGm[offset], processDataNum); | ||
| 95 | + inQueGrad.EnQue(gradLocal); | ||
| 96 | + } | ||
| 97 | + } | ||
| 98 | + __aicore__ inline void Compute(uint32_t processDataNum) | ||
| 99 | + { | ||
| 100 | + AscendC::LocalTensor<T> yLocal = outQueY.AllocTensor<T>(); | ||
| 101 | + AscendC::LocalTensor<T> targetLocal = inQueTarget.DeQue<T>(); | ||
| 102 | + if constexpr (!std::is_same_v<T, float>) { | ||
| 103 | + AscendC::LocalTensor<float> targetFp32 = targetBuf.Get<float>(); | ||
| 104 | + AscendC::LocalTensor<float> yFp32 = yBuf.Get<float>(); | ||
| 105 | + AscendC::Cast(targetFp32, targetLocal, AscendC::RoundMode::CAST_NONE, processDataNum); | ||
| 106 | + if constexpr (!PolicyType::broadcast) { | ||
| 107 | + AscendC::LocalTensor<T> gradLocal = inQueGrad.DeQue<T>(); | ||
| 108 | + AscendC::LocalTensor<float> gradFp32 = gradBuf.Get<float>(); | ||
| 109 | + AscendC::Cast(gradFp32, gradLocal, AscendC::RoundMode::CAST_NONE, processDataNum); | ||
| 110 | + inQueGrad.FreeTensor(gradLocal); | ||
| 111 | + policy.compute(gradFp32, targetFp32, yFp32, processDataNum); | ||
| 112 | + } else { | ||
| 113 | + policy.compute(targetFp32, yFp32, processDataNum); | ||
| 114 | + } | ||
| 115 | + AscendC::Cast(yLocal, yFp32, AscendC::RoundMode::CAST_RINT, processDataNum); | ||
| 116 | + } else { | ||
| 117 | + if constexpr (!PolicyType::broadcast) { | ||
| 118 | + AscendC::LocalTensor<T> gradLocal = inQueGrad.DeQue<T>(); | ||
| 119 | + policy.compute(gradLocal, targetLocal, yLocal, processDataNum); | ||
| 120 | + inQueGrad.FreeTensor(gradLocal); | ||
| 121 | + } else { | ||
| 122 | + policy.compute(targetLocal, yLocal, processDataNum); | ||
| 123 | + } | ||
| 124 | + } | ||
| 125 | + outQueY.EnQue(yLocal); | ||
| 126 | + inQueTarget.FreeTensor(targetLocal); | ||
| 127 | + } | ||
| 128 | + __aicore__ inline void CopyOut(uint32_t offset, uint32_t processDataNum) | ||
| 129 | + { | ||
| 130 | + AscendC::LocalTensor<T> yLocal = outQueY.DeQue<T>(); | ||
| 131 | + AscendC::DataCopy(yGm[offset], yLocal, processDataNum); | ||
| 132 | + outQueY.FreeTensor(yLocal); | ||
| 133 | + } | ||
| 134 | + | ||
| 135 | +private: | ||
| 136 | + AscendC::TQue<AscendC::TPosition::VECIN, 1> inQueGrad, inQueTarget; | ||
| 137 | + AscendC::TQue<AscendC::TPosition::VECOUT, 1> outQueY; | ||
| 138 | + AscendC::TBuf<AscendC::TPosition::VECCALC> gradBuf, targetBuf, yBuf; | ||
| 139 | + AscendC::GlobalTensor<T> gradGm, targetGm; | ||
| 140 | + AscendC::GlobalTensor<T> yGm; | ||
| 141 | + | ||
| 142 | + uint32_t coreDataNum; | ||
| 143 | + uint32_t tileDataNum; | ||
| 144 | + | ||
| 145 | + PolicyType policy; | ||
| 146 | +}; | ||
| 147 | + | ||
| 148 | +template <class T> | ||
| 149 | +class ComputeImpl { | ||
| 150 | +public: | ||
| 151 | + static constexpr bool broadcast = false; | ||
| 152 | + | ||
| 153 | + __aicore__ inline void compute( | ||
| 154 | + const AscendC::LocalTensor<T>& grad, const AscendC::LocalTensor<T>& target, const AscendC::LocalTensor<T>& y, | ||
| 155 | + uint32_t processDataNum) const | ||
| 156 | + { | ||
| 157 | + AscendC::Mul(y, grad, target, processDataNum); | ||
| 158 | + AscendC::Muls(y, y, negCoeff, processDataNum); | ||
| 159 | + } | ||
| 160 | + | ||
| 161 | + T negCoeff; | ||
| 162 | +}; | ||
| 163 | + | ||
| 164 | +template <class T> | ||
| 165 | +class ComputeImplLog { | ||
| 166 | +public: | ||
| 167 | + static constexpr bool broadcast = false; | ||
| 168 | + | ||
| 169 | + __aicore__ inline void compute( | ||
| 170 | + const AscendC::LocalTensor<T>& grad, const AscendC::LocalTensor<T>& target, const AscendC::LocalTensor<T>& y, | ||
| 171 | + uint32_t processDataNum) const | ||
| 172 | + { | ||
| 173 | + AscendC::Exp(y, target, processDataNum); | ||
| 174 | + AscendC::Mul(target, y, grad, processDataNum); | ||
| 175 | + AscendC::Muls(y, target, negCoeff, processDataNum); | ||
| 176 | + } | ||
| 177 | + | ||
| 178 | + T negCoeff; | ||
| 179 | +}; | ||
| 180 | + | ||
| 181 | +template <class T> | ||
| 182 | +class ComputeImplBroadCast { | ||
| 183 | +public: | ||
| 184 | + static constexpr bool broadcast = true; | ||
| 185 | + | ||
| 186 | + __aicore__ inline void compute( | ||
| 187 | + const AscendC::LocalTensor<T>& target, const AscendC::LocalTensor<T>& y, uint32_t processDataNum) const | ||
| 188 | + { | ||
| 189 | + AscendC::Muls(y, target, grad, processDataNum); | ||
| 190 | + AscendC::Muls(y, y, negCoeff, processDataNum); | ||
| 191 | + } | ||
| 192 | + | ||
| 193 | + T grad; | ||
| 194 | + T negCoeff; | ||
| 195 | +}; | ||
| 196 | + | ||
| 197 | +template <class T> | ||
| 198 | +class ComputeImplBroadCastLog { | ||
| 199 | +public: | ||
| 200 | + static constexpr bool broadcast = true; | ||
| 201 | + | ||
| 202 | + __aicore__ inline void compute( | ||
| 203 | + const AscendC::LocalTensor<T>& target, const AscendC::LocalTensor<T>& y, uint32_t processDataNum) const | ||
| 204 | + { | ||
| 205 | + AscendC::Exp(y, target, processDataNum); | ||
| 206 | + AscendC::Muls(target, y, grad, processDataNum); | ||
| 207 | + AscendC::Muls(y, target, negCoeff, processDataNum); | ||
| 208 | + } | ||
| 209 | + | ||
| 210 | + T grad; | ||
| 211 | + T negCoeff; | ||
| 212 | +}; | ||
| 213 | +} // namespace NsKlDivLossGrad | ||
| 214 | + | ||
| @@ -0,0 +1,27 @@ | |||
| 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 kl_div_loss_grad_tiling_data.h | ||
| 13 | + * \brief tiling data struct | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | +struct KlDivLossGradTilingData { | ||
| 20 | + uint32_t bigCoreDataNum; | ||
| 21 | + uint32_t smallCoreDataNum; | ||
| 22 | + uint32_t tileDataNum; | ||
| 23 | + uint32_t bigCoreNum; | ||
| 24 | + float coff; | ||
| 25 | +}; | ||
| 26 | + | ||
| 27 | + | ||
| @@ -0,0 +1,27 @@ | |||
| 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 kl_div_loss_grad_tiling_key.h | ||
| 13 | + * \brief kl_div_loss_grad tiling key declare | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | +/* 模板参数 */ | ||
| 22 | +ASCENDC_TPL_ARGS_DECL(klDivLossGrad, ASCENDC_TPL_BOOL_DECL(logTarget, 0, 1), ASCENDC_TPL_BOOL_DECL(broadcast, 0, 1), ); | ||
| 23 | + | ||
| 24 | +/* 模板参数组合 */ | ||
| 25 | +ASCENDC_TPL_SEL(ASCENDC_TPL_ARGS_SEL(ASCENDC_TPL_BOOL_SEL(logTarget, 0, 1), ASCENDC_TPL_BOOL_SEL(broadcast, 0, 1)), ); | ||
| 26 | + | ||
| 27 | + | ||
| @@ -0,0 +1,18 @@ | |||
| 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 | +message(STATUS "=== Debug: start ops.loss.kl_div_loss_grad.tests.CMakeLists.txt ") | ||
| 12 | +file(GLOB CURRENT_DIRS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*) | ||
| 13 | +message(STATUS "=== Debug: CURRENT_DIRS =${CURRENT_DIRS} ") | ||
| 14 | +foreach(SUB_DIR ${CURRENT_DIRS}) | ||
| 15 | + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SUB_DIR}/CMakeLists.txt") | ||
| 16 | + add_subdirectory(${SUB_DIR}) | ||
| 17 | + endif() | ||
| 18 | +endforeach() | ||
| @@ -0,0 +1,18 @@ | |||
| 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 | +message(STATUS "=== Debug: start ops.loss.kl_div_loss_grad.tests.CMakeLists.txt ") | ||
| 12 | +file(GLOB CURRENT_DIRS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*) | ||
| 13 | +message(STATUS "=== Debug: CURRENT_DIRS =${CURRENT_DIRS} ") | ||
| 14 | +foreach(SUB_DIR ${CURRENT_DIRS}) | ||
| 15 | + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SUB_DIR}/CMakeLists.txt") | ||
| 16 | + add_subdirectory(${SUB_DIR}) | ||
| 17 | + endif() | ||
| 18 | +endforeach() | ||
| @@ -0,0 +1,12 @@ | |||
| 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 | +message(STATUS "=== Debug: target_sources add test_kl_div_loss_grad") | ||
| 12 | +add_modules_llt_sources(HOSTNAME ${OPTEST_NAME} MODE PRIVATE DIR ${CMAKE_CURRENT_SOURCE_DIR}) | ||
| @@ -0,0 +1,493 @@ | |||
| 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 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | +using namespace op; | ||
| 22 | +using namespace std; | ||
| 23 | + | ||
| 24 | +enum Reduction { None, Mean, Sum, BatchMean, END }; | ||
| 25 | + | ||
| 26 | +class kl_div_loss_backward_test : public testing::Test { | ||
| 27 | +protected: | ||
| 28 | + static void SetUpTestCase() { std::cout << "kl_div_loss_backward_test SetUp" << std::endl; } | ||
| 29 | + | ||
| 30 | + static void TearDownTestCase() { std::cout << "kl_div_loss_backward_test TearDown" << std::endl; } | ||
| 31 | +}; | ||
| 32 | + | ||
| 33 | +TEST_F(kl_div_loss_backward_test, aclnnKlDivBackward_01_float_none_broadcast) | ||
| 34 | +{ | ||
| 35 | + auto gradOutputDesc = TensorDesc({3, 1}, ACL_FLOAT, ACL_FORMAT_ND); | ||
| 36 | + auto selfDesc = TensorDesc({3, 5}, ACL_FLOAT, ACL_FORMAT_ND); | ||
| 37 | + auto targetDesc = TensorDesc({3, 5}, ACL_FLOAT, ACL_FORMAT_ND).ValueRange(0, 4); | ||
| 38 | + int64_t reduction = Reduction::None; | ||
| 39 | + bool logTarget = false; | ||
| 40 | + | ||
| 41 | + auto outDesc = TensorDesc({3, 5}, ACL_FLOAT, ACL_FORMAT_ND).Precision(0.0001, 0.0001); | ||
| 42 | + | ||
| 43 | + auto ut = OP_API_UT( | ||
| 44 | + aclnnKlDivBackward, INPUT(gradOutputDesc, selfDesc, targetDesc, reduction, logTarget), OUTPUT(outDesc)); | ||
| 45 | + | ||
| 46 | + uint64_t workspace_size = 0; | ||
| 47 | + aclnnStatus aclRet = ut.TestGetWorkspaceSize(&workspace_size); | ||
| 48 | + EXPECT_EQ(aclRet, ACL_SUCCESS); | ||
| 49 | + | ||
| 50 | + ut.TestPrecision(); | ||
| 51 | +} | ||
| 52 | + | ||
| 53 | +TEST_F(kl_div_loss_backward_test, aclnnKlDivBackward_02_float_nchw_mean) | ||
| 54 | +{ | ||
| 55 | + auto gradOutputDesc = TensorDesc({3, 5, 2, 4}, ACL_FLOAT, ACL_FORMAT_NCHW); | ||
| 56 | + auto selfDesc = TensorDesc({3, 5, 2, 4}, ACL_FLOAT, ACL_FORMAT_NCHW).ValueRange(-1, 1); | ||
| 57 | + auto targetDesc = TensorDesc({3, 5, 2, 4}, ACL_FLOAT, ACL_FORMAT_NCHW).ValueRange(-1, 1); | ||
| 58 | + int64_t reduction = Reduction::Mean; | ||
| 59 | + bool logTarget = false; | ||
| 60 | + | ||
| 61 | + auto outDesc = TensorDesc({3, 5, 2, 4}, ACL_FLOAT, ACL_FORMAT_NCHW).Precision(0.0001, 0.0001); | ||
| 62 | + | ||
| 63 | + auto ut = OP_API_UT( | ||
| 64 | + aclnnKlDivBackward, INPUT(gradOutputDesc, selfDesc, targetDesc, reduction, logTarget), OUTPUT(outDesc)); | ||
| 65 | + | ||
| 66 | + uint64_t workspace_size = 0; | ||
| 67 | + aclnnStatus aclRet = ut.TestGetWorkspaceSize(&workspace_size); | ||
| 68 | + EXPECT_EQ(aclRet, ACL_SUCCESS); | ||
| 69 | + | ||
| 70 | + ut.TestPrecision(); | ||
| 71 | +} | ||
| 72 | + | ||
| 73 | +TEST_F(kl_div_loss_backward_test, aclnnKlDivBackward_03_float16_ncdhw_sum) | ||
| 74 | +{ | ||
| 75 | + auto gradOutputDesc = TensorDesc({1, 2, 3, 4, 5}, ACL_FLOAT16, ACL_FORMAT_NCDHW); | ||
| 76 | + auto selfDesc = TensorDesc({1, 2, 3, 4, 5}, ACL_FLOAT16, ACL_FORMAT_NCDHW).ValueRange(-1, 1); | ||
| 77 | + auto targetDesc = TensorDesc({1, 2, 3, 4, 5}, ACL_FLOAT16, ACL_FORMAT_NCDHW).ValueRange(-1, 1); | ||
| 78 | + int64_t reduction = Reduction::Sum; | ||
| 79 | + bool logTarget = false; | ||
| 80 | + | ||
| 81 | + auto outDesc = TensorDesc({1, 2, 3, 4, 5}, ACL_FLOAT16, ACL_FORMAT_NCDHW).Precision(0.0001, 0.0001); | ||
| 82 | + | ||
| 83 | + auto ut = OP_API_UT( | ||
| 84 | + aclnnKlDivBackward, INPUT(gradOutputDesc, selfDesc, targetDesc, reduction, logTarget), OUTPUT(outDesc)); | ||
| 85 | + | ||
| 86 | + uint64_t workspace_size = 0; | ||
| 87 | + aclnnStatus aclRet = ut.TestGetWorkspaceSize(&workspace_size); | ||
| 88 | + EXPECT_EQ(aclRet, ACL_SUCCESS); | ||
| 89 | + | ||
| 90 | + ut.TestPrecision(); | ||
| 91 | +} | ||
| 92 | + | ||
| 93 | +TEST_F(kl_div_loss_backward_test, aclnnKlDivBackward_04_float_hwcn_batchmean) | ||
| 94 | +{ | ||
| 95 | + auto gradOutputDesc = TensorDesc({3, 5, 4, 6}, ACL_FLOAT, ACL_FORMAT_HWCN); | ||
| 96 | + auto selfDesc = TensorDesc({3, 5, 4, 6}, ACL_FLOAT, ACL_FORMAT_HWCN).ValueRange(-1, 1); | ||
| 97 | + auto targetDesc = TensorDesc({3, 5, 4, 6}, ACL_FLOAT, ACL_FORMAT_HWCN).ValueRange(-1, 1); | ||
| 98 | + int64_t reduction = Reduction::BatchMean; | ||
| 99 | + bool logTarget = false; | ||
| 100 | + | ||
| 101 | + auto outDesc = TensorDesc({3, 5, 4, 6}, ACL_FLOAT, ACL_FORMAT_HWCN).Precision(0.0001, 0.0001); | ||
| 102 | + | ||
| 103 | + auto ut = OP_API_UT( | ||
| 104 | + aclnnKlDivBackward, INPUT(gradOutputDesc, selfDesc, targetDesc, reduction, logTarget), OUTPUT(outDesc)); | ||
| 105 | + | ||
| 106 | + uint64_t workspace_size = 0; | ||
| 107 | + aclnnStatus aclRet = ut.TestGetWorkspaceSize(&workspace_size); | ||
| 108 | + EXPECT_EQ(aclRet, ACL_SUCCESS); | ||
| 109 | + | ||
| 110 | + ut.TestPrecision(); | ||
| 111 | +} | ||
| 112 | + | ||
| 113 | +TEST_F(kl_div_loss_backward_test, aclnnKlDivBackward_05_float_none_logtarget_true) | ||
| 114 | +{ | ||
| 115 | + auto gradOutputDesc = TensorDesc({3, 5, 4, 6}, ACL_FLOAT, ACL_FORMAT_ND); | ||
| 116 | + auto selfDesc = TensorDesc({3, 5, 4, 6}, ACL_FLOAT, ACL_FORMAT_ND).ValueRange(-1, 1); | ||
| 117 | + auto targetDesc = TensorDesc({3, 5, 4, 6}, ACL_FLOAT, ACL_FORMAT_ND).ValueRange(-1, 1); | ||
| 118 | + int64_t reduction = Reduction::None; | ||
| 119 | + bool logTarget = true; | ||
| 120 | + | ||
| 121 | + auto outDesc = TensorDesc({3, 5, 4, 6}, ACL_FLOAT, ACL_FORMAT_ND).Precision(0.0001, 0.0001); | ||
| 122 | + | ||
| 123 | + auto ut = OP_API_UT( | ||
| 124 | + aclnnKlDivBackward, INPUT(gradOutputDesc, selfDesc, targetDesc, reduction, logTarget), OUTPUT(outDesc)); | ||
| 125 | + | ||
| 126 | + uint64_t workspace_size = 0; | ||
| 127 | + aclnnStatus aclRet = ut.TestGetWorkspaceSize(&workspace_size); | ||
| 128 | + EXPECT_EQ(aclRet, ACL_SUCCESS); | ||
| 129 | + | ||
| 130 | + ut.TestPrecision(); | ||
| 131 | +} | ||
| 132 | + | ||
| 133 | +TEST_F(kl_div_loss_backward_test, aclnnKlDivBackward_06_float16_to_float_logtarget_true) | ||
| 134 | +{ | ||
| 135 | + auto gradOutputDesc = TensorDesc({3, 5, 4, 6}, ACL_FLOAT16, ACL_FORMAT_ND); | ||
| 136 | + auto selfDesc = TensorDesc({3, 5, 4, 6}, ACL_FLOAT, ACL_FORMAT_ND).ValueRange(-1, 1); | ||
| 137 | + auto targetDesc = TensorDesc({3, 5, 4, 6}, ACL_FLOAT16, ACL_FORMAT_ND).ValueRange(-1, 1); | ||
| 138 | + int64_t reduction = Reduction::None; | ||
| 139 | + bool logTarget = true; | ||
| 140 | + | ||
| 141 | + auto outDesc = TensorDesc({3, 5, 4, 6}, ACL_FLOAT, ACL_FORMAT_ND).Precision(0.0001, 0.0001); | ||
| 142 | + | ||
| 143 | + auto ut = OP_API_UT( | ||
| 144 | + aclnnKlDivBackward, INPUT(gradOutputDesc, selfDesc, targetDesc, reduction, logTarget), OUTPUT(outDesc)); | ||
| 145 | + | ||
| 146 | + uint64_t workspace_size = 0; | ||
| 147 | + aclnnStatus aclRet = ut.TestGetWorkspaceSize(&workspace_size); | ||
| 148 | + EXPECT_EQ(aclRet, ACL_SUCCESS); | ||
| 149 | + | ||
| 150 | + ut.TestPrecision(); | ||
| 151 | +} | ||
| 152 | + | ||
| 153 | +TEST_F(kl_div_loss_backward_test, aclnnKlDivBackward_07_float_nhwc_logtarget_true) | ||
| 154 | +{ | ||
| 155 | + auto gradOutputDesc = TensorDesc({3, 1, 2, 5}, ACL_FLOAT, ACL_FORMAT_NHWC).ValueRange(-1, 1); | ||
| 156 | + auto selfDesc = TensorDesc({3, 1, 2, 5}, ACL_FLOAT, ACL_FORMAT_NHWC).ValueRange(-1, 1); | ||
| 157 | + auto targetDesc = TensorDesc({3, 1, 2, 5}, ACL_FLOAT, ACL_FORMAT_NHWC).ValueRange(-1, 1); | ||
| 158 | + int64_t reduction = Reduction::None; | ||
| 159 | + bool logTarget = true; | ||
| 160 | + | ||
| 161 | + auto outDesc = TensorDesc({3, 1, 2, 5}, ACL_FLOAT, ACL_FORMAT_NHWC).Precision(0.0001, 0.0001); | ||
| 162 | + | ||
| 163 | + auto ut = OP_API_UT( | ||
| 164 | + aclnnKlDivBackward, INPUT(gradOutputDesc, selfDesc, targetDesc, reduction, logTarget), OUTPUT(outDesc)); | ||
| 165 | + | ||
| 166 | + uint64_t workspace_size = 0; | ||
| 167 | + aclnnStatus aclRet = ut.TestGetWorkspaceSize(&workspace_size); | ||
| 168 | + EXPECT_EQ(aclRet, ACL_SUCCESS); | ||
| 169 | + | ||
| 170 | + ut.TestPrecision(); | ||
| 171 | +} | ||
| 172 | + | ||
| 173 | +TEST_F(kl_div_loss_backward_test, aclnnKlDivBackward_08_float_ndhwc_logtarget_true) | ||
| 174 | +{ | ||
| 175 | + auto gradOutputDesc = TensorDesc({3, 1, 2, 5, 4}, ACL_FLOAT, ACL_FORMAT_NDHWC).ValueRange(-1, 1); | ||
| 176 | + auto selfDesc = TensorDesc({3, 1, 2, 5, 4}, ACL_FLOAT, ACL_FORMAT_NDHWC).ValueRange(-1, 1); | ||
| 177 | + auto targetDesc = TensorDesc({3, 1, 2, 5, 4}, ACL_FLOAT, ACL_FORMAT_NDHWC).ValueRange(-1, 1); | ||
| 178 | + int64_t reduction = Reduction::None; | ||
| 179 | + bool logTarget = true; | ||
| 180 | + | ||
| 181 | + auto outDesc = TensorDesc({3, 1, 2, 5, 4}, ACL_FLOAT, ACL_FORMAT_NDHWC).Precision(0.0001, 0.0001); | ||
| 182 | + | ||
| 183 | + auto ut = OP_API_UT( | ||
| 184 | + aclnnKlDivBackward, INPUT(gradOutputDesc, selfDesc, targetDesc, reduction, logTarget), OUTPUT(outDesc)); | ||
| 185 | + | ||
| 186 | + uint64_t workspace_size = 0; | ||
| 187 | + aclnnStatus aclRet = ut.TestGetWorkspaceSize(&workspace_size); | ||
| 188 | + EXPECT_EQ(aclRet, ACL_SUCCESS); | ||
| 189 | + | ||
| 190 | + ut.TestPrecision(); | ||
| 191 | +} | ||
| 192 | + | ||
| 193 | +TEST_F(kl_div_loss_backward_test, aclnnKlDivBackward_09_empty_tensor) | ||
| 194 | +{ | ||
| 195 | + auto gradOutputDesc = TensorDesc({3, 1, 0, 5}, ACL_FLOAT, ACL_FORMAT_ND).ValueRange(-1, 1); | ||
| 196 | + auto selfDesc = TensorDesc({3, 1, 0, 5}, ACL_FLOAT, ACL_FORMAT_ND).ValueRange(-1, 1); | ||
| 197 | + auto targetDesc = TensorDesc({3, 1, 0, 5}, ACL_FLOAT, ACL_FORMAT_ND).ValueRange(-1, 1); | ||
| 198 | + int64_t reduction = Reduction::None; | ||
| 199 | + bool logTarget = true; | ||
| 200 | + | ||
| 201 | + auto outDesc = TensorDesc({3, 1, 0, 5}, ACL_FLOAT, ACL_FORMAT_ND).Precision(0.0001, 0.0001); | ||
| 202 | + | ||
| 203 | + auto ut = OP_API_UT( | ||
| 204 | + aclnnKlDivBackward, INPUT(gradOutputDesc, selfDesc, targetDesc, reduction, logTarget), OUTPUT(outDesc)); | ||
| 205 | + | ||
| 206 | + uint64_t workspace_size = 0; | ||
| 207 | + aclnnStatus aclRet = ut.TestGetWorkspaceSize(&workspace_size); | ||
| 208 | + EXPECT_EQ(aclRet, ACL_SUCCESS); | ||
| 209 | + | ||
| 210 | + ut.TestPrecision(); | ||
| 211 | +} | ||
| 212 | + | ||
| 213 | +TEST_F(kl_div_loss_backward_test, aclnnKlDivBackward_10_onedim_tensor_logtarget_true) | ||
| 214 | +{ | ||
| 215 | + auto gradOutputDesc = TensorDesc({3}, ACL_FLOAT, ACL_FORMAT_ND).ValueRange(-1, 1); | ||
| 216 | + auto selfDesc = TensorDesc({3}, ACL_FLOAT, ACL_FORMAT_ND).ValueRange(-1, 1); | ||
| 217 | + auto targetDesc = TensorDesc({3}, ACL_FLOAT, ACL_FORMAT_ND).ValueRange(-1, 1); | ||
| 218 | + int64_t reduction = Reduction::None; | ||
| 219 | + bool logTarget = true; | ||
| 220 | + | ||
| 221 | + auto outDesc = TensorDesc({3}, ACL_FLOAT, ACL_FORMAT_ND).Precision(0.0001, 0.0001); | ||
| 222 | + | ||
| 223 | + auto ut = OP_API_UT( | ||
| 224 | + aclnnKlDivBackward, INPUT(gradOutputDesc, selfDesc, targetDesc, reduction, logTarget), OUTPUT(outDesc)); | ||
| 225 | + | ||
| 226 | + uint64_t workspace_size = 0; | ||
| 227 | + aclnnStatus aclRet = ut.TestGetWorkspaceSize(&workspace_size); | ||
| 228 | + EXPECT_EQ(aclRet, ACL_SUCCESS); | ||
| 229 | + | ||
| 230 | + ut.TestPrecision(); | ||
| 231 | +} | ||
| 232 | + | ||
| 233 | +TEST_F(kl_div_loss_backward_test, aclnnKlDivBackward_11_threedim_tensor_broadcast) | ||
| 234 | +{ | ||
| 235 | + auto gradOutputDesc = TensorDesc({3, 4, 1}, ACL_FLOAT, ACL_FORMAT_ND).ValueRange(-1, 1); | ||
| 236 | + auto selfDesc = TensorDesc({3, 4, 6}, ACL_FLOAT, ACL_FORMAT_ND).ValueRange(-1, 1); | ||
| 237 | + auto targetDesc = TensorDesc({3, 4, 6}, ACL_FLOAT, ACL_FORMAT_ND).ValueRange(-1, 1); | ||
| 238 | + int64_t reduction = Reduction::None; | ||
| 239 | + bool logTarget = true; | ||
| 240 | + | ||
| 241 | + auto outDesc = TensorDesc({3, 4, 6}, ACL_FLOAT, ACL_FORMAT_ND).Precision(0.0001, 0.0001); | ||
| 242 | + | ||
| 243 | + auto ut = OP_API_UT( | ||
| 244 | + aclnnKlDivBackward, INPUT(gradOutputDesc, selfDesc, targetDesc, reduction, logTarget), OUTPUT(outDesc)); | ||
| 245 | + | ||
| 246 | + uint64_t workspace_size = 0; | ||
| 247 | + aclnnStatus aclRet = ut.TestGetWorkspaceSize(&workspace_size); | ||
| 248 | + EXPECT_EQ(aclRet, ACL_SUCCESS); | ||
| 249 | + | ||
| 250 | + ut.TestPrecision(); | ||
| 251 | +} | ||
| 252 | + | ||
| 253 | +TEST_F(kl_div_loss_backward_test, aclnnKlDivBackward_12_fivedim_tensor_logtarget_true) | ||
| 254 | +{ | ||
| 255 | + auto gradOutputDesc = TensorDesc({3, 4, 6, 2, 3}, ACL_FLOAT, ACL_FORMAT_ND).ValueRange(-1, 1); | ||
| 256 | + auto selfDesc = TensorDesc({3, 4, 6, 2, 3}, ACL_FLOAT, ACL_FORMAT_ND).ValueRange(-1, 1); | ||
| 257 | + auto targetDesc = TensorDesc({3, 4, 6, 2, 3}, ACL_FLOAT, ACL_FORMAT_ND).ValueRange(-1, 1); | ||
| 258 | + int64_t reduction = Reduction::None; | ||
| 259 | + bool logTarget = true; | ||
| 260 | + | ||
| 261 | + auto outDesc = TensorDesc({3, 4, 6, 2, 3}, ACL_FLOAT, ACL_FORMAT_ND).Precision(0.0001, 0.0001); | ||
| 262 | + | ||
| 263 | + auto ut = OP_API_UT( | ||
| 264 | + aclnnKlDivBackward, INPUT(gradOutputDesc, selfDesc, targetDesc, reduction, logTarget), OUTPUT(outDesc)); | ||
| 265 | + | ||
| 266 | + uint64_t workspace_size = 0; | ||
| 267 | + aclnnStatus aclRet = ut.TestGetWorkspaceSize(&workspace_size); | ||
| 268 | + EXPECT_EQ(aclRet, ACL_SUCCESS); | ||
| 269 | + | ||
| 270 | + ut.TestPrecision(); | ||
| 271 | +} | ||
| 272 | + | ||
| 273 | +TEST_F(kl_div_loss_backward_test, aclnnKlDivBackward_13_dtype_promote_float16_to_float) | ||
| 274 | +{ | ||
| 275 | + auto gradOutputDesc = TensorDesc({3, 4, 1, 2, 3}, ACL_FLOAT16, ACL_FORMAT_ND).ValueRange(-1, 1); | ||
| 276 | + auto selfDesc = TensorDesc({3, 4, 1, 2, 3}, ACL_FLOAT, ACL_FORMAT_ND).ValueRange(-1, 1); | ||
| 277 | + auto targetDesc = TensorDesc({3, 4, 1, 2, 3}, ACL_FLOAT16, ACL_FORMAT_ND).ValueRange(-1, 1); | ||
| 278 | + int64_t reduction = Reduction::None; | ||
| 279 | + bool logTarget = true; | ||
| 280 | + | ||
| 281 | + auto outDesc = TensorDesc({3, 4, 1, 2, 3}, ACL_FLOAT, ACL_FORMAT_ND).Precision(0.0001, 0.0001); | ||
| 282 | + | ||
| 283 | + auto ut = OP_API_UT( | ||
| 284 | + aclnnKlDivBackward, INPUT(gradOutputDesc, selfDesc, targetDesc, reduction, logTarget), OUTPUT(outDesc)); | ||
| 285 | + | ||
| 286 | + uint64_t workspace_size = 0; | ||
| 287 | + aclnnStatus aclRet = ut.TestGetWorkspaceSize(&workspace_size); | ||
| 288 | + EXPECT_EQ(aclRet, ACL_SUCCESS); | ||
| 289 | + | ||
| 290 | + ut.TestPrecision(); | ||
| 291 | +} | ||
| 292 | + | ||
| 293 | +TEST_F(kl_div_loss_backward_test, aclnnKlDivBackward_14_reduction_error) | ||
| 294 | +{ | ||
| 295 | + auto gradOutputDesc = TensorDesc({3, 5, 4, 6}, ACL_FLOAT, ACL_FORMAT_ND); | ||
| 296 | + auto selfDesc = TensorDesc({3, 5, 4, 6}, ACL_FLOAT, ACL_FORMAT_ND).ValueRange(-1, 1); | ||
| 297 | + auto targetDesc = TensorDesc({3, 5, 4, 6}, ACL_FLOAT, ACL_FORMAT_ND).ValueRange(-1, 1); | ||
| 298 | + int64_t reduction = Reduction::END; | ||
| 299 | + bool logTarget = false; | ||
| 300 | + | ||
| 301 | + auto outDesc = TensorDesc({3, 5, 4, 6}, ACL_FLOAT, ACL_FORMAT_ND).Precision(0.0001, 0.0001); | ||
| 302 | + | ||
| 303 | + auto ut = OP_API_UT( | ||
| 304 | + aclnnKlDivBackward, INPUT(gradOutputDesc, selfDesc, targetDesc, reduction, logTarget), OUTPUT(outDesc)); | ||
| 305 | + | ||
| 306 | + uint64_t workspace_size = 0; | ||
| 307 | + aclnnStatus aclRet = ut.TestGetWorkspaceSize(&workspace_size); | ||
| 308 | + EXPECT_EQ(aclRet, ACLNN_ERR_PARAM_INVALID); | ||
| 309 | +} | ||
| 310 | + | ||
| 311 | +TEST_F(kl_div_loss_backward_test, aclnnKlDivBackward_15_input_out_nullptr) | ||
| 312 | +{ | ||
| 313 | + auto tensorDesc = TensorDesc({10, 3, 5, 24}, ACL_FLOAT, ACL_FORMAT_ND).ValueRange(-1, 1); | ||
| 314 | + int64_t reduction = Reduction::None; | ||
| 315 | + bool logTarget = true; | ||
| 316 | + | ||
| 317 | + auto ut_grad = OP_API_UT( | ||
| 318 | + aclnnKlDivBackward, INPUT((aclTensor*)nullptr, tensorDesc, tensorDesc, reduction, logTarget), | ||
| 319 | + OUTPUT(tensorDesc)); | ||
| 320 | + uint64_t workspace_size = 0; | ||
| 321 | + aclnnStatus aclRet = ut_grad.TestGetWorkspaceSize(&workspace_size); | ||
| 322 | + EXPECT_EQ(aclRet, ACLNN_ERR_PARAM_NULLPTR); | ||
| 323 | + | ||
| 324 | + auto ut_self = OP_API_UT( | ||
| 325 | + aclnnKlDivBackward, INPUT(tensorDesc, (aclTensor*)nullptr, tensorDesc, reduction, logTarget), | ||
| 326 | + OUTPUT(tensorDesc)); | ||
| 327 | + aclRet = ut_self.TestGetWorkspaceSize(&workspace_size); | ||
| 328 | + EXPECT_EQ(aclRet, ACLNN_ERR_PARAM_NULLPTR); | ||
| 329 | + | ||
| 330 | + auto ut_tar = OP_API_UT( | ||
| 331 | + aclnnKlDivBackward, INPUT(tensorDesc, tensorDesc, (aclTensor*)nullptr, reduction, logTarget), | ||
| 332 | + OUTPUT(tensorDesc)); | ||
| 333 | + aclRet = ut_tar.TestGetWorkspaceSize(&workspace_size); | ||
| 334 | + EXPECT_EQ(aclRet, ACLNN_ERR_PARAM_NULLPTR); | ||
| 335 | + | ||
| 336 | + auto ut_o = OP_API_UT( | ||
| 337 | + aclnnKlDivBackward, INPUT(tensorDesc, tensorDesc, tensorDesc, reduction, logTarget), | ||
| 338 | + OUTPUT((aclTensor*)nullptr)); | ||
| 339 | + aclRet = ut_o.TestGetWorkspaceSize(&workspace_size); | ||
| 340 | + EXPECT_EQ(aclRet, ACLNN_ERR_PARAM_NULLPTR); | ||
| 341 | +} | ||
| 342 | + | ||
| 343 | +TEST_F(kl_div_loss_backward_test, aclnnKlDivBackward_16_input_error_shape_len) | ||
| 344 | +{ | ||
| 345 | + auto tensorDesc9 = TensorDesc({10, 24, 3, 5, 10, 22, 42, 30, 24}, ACL_FLOAT, ACL_FORMAT_ND).ValueRange(-1, 1); | ||
| 346 | + auto tensorDesc4 = TensorDesc({3, 1, 0, 5}, ACL_FLOAT, ACL_FORMAT_ND).ValueRange(-1, 1); | ||
| 347 | + int64_t reduction = Reduction::None; | ||
| 348 | + bool logTarget = true; | ||
| 349 | + | ||
| 350 | + auto ut_grad = OP_API_UT( | ||
| 351 | + aclnnKlDivBackward, INPUT(tensorDesc9, tensorDesc4, tensorDesc4, reduction, logTarget), OUTPUT(tensorDesc4)); | ||
| 352 | + uint64_t workspace_size = 0; | ||
| 353 | + aclnnStatus aclRet = ut_grad.TestGetWorkspaceSize(&workspace_size); | ||
| 354 | + EXPECT_EQ(aclRet, ACLNN_ERR_PARAM_INVALID); | ||
| 355 | + | ||
| 356 | + auto ut_self = OP_API_UT( | ||
| 357 | + aclnnKlDivBackward, INPUT(tensorDesc4, tensorDesc9, tensorDesc4, reduction, logTarget), OUTPUT(tensorDesc4)); | ||
| 358 | + aclRet = ut_self.TestGetWorkspaceSize(&workspace_size); | ||
| 359 | + EXPECT_EQ(aclRet, ACLNN_ERR_PARAM_INVALID); | ||
| 360 | + | ||
| 361 | + auto ut_tar = OP_API_UT( | ||
| 362 | + aclnnKlDivBackward, INPUT(tensorDesc4, tensorDesc4, tensorDesc9, reduction, logTarget), OUTPUT(tensorDesc4)); | ||
| 363 | + aclRet = ut_tar.TestGetWorkspaceSize(&workspace_size); | ||
| 364 | + EXPECT_EQ(aclRet, ACLNN_ERR_PARAM_INVALID); | ||
| 365 | +} | ||
| 366 | + | ||
| 367 | +TEST_F(kl_div_loss_backward_test, aclnnKlDivBackward_17_error_input_dtype) | ||
| 368 | +{ | ||
| 369 | + auto gradOutputDesc = TensorDesc({3, 4, 1, 1}, ACL_INT32, ACL_FORMAT_ND).ValueRange(-1, 1); | ||
| 370 | + auto selfDesc = TensorDesc({3, 4, 6, 3}, ACL_FLOAT, ACL_FORMAT_ND).ValueRange(-1, 1); | ||
| 371 | + auto targetDesc = TensorDesc({3, 4, 6, 1}, ACL_FLOAT16, ACL_FORMAT_ND).ValueRange(-1, 1); | ||
| 372 | + int64_t reduction = Reduction::None; | ||
| 373 | + bool logTarget = true; | ||
| 374 | + | ||
| 375 | + auto outDesc = TensorDesc({3, 4, 6, 3}, ACL_FLOAT, ACL_FORMAT_ND).Precision(0.0001, 0.0001); | ||
| 376 | + | ||
| 377 | + auto ut = OP_API_UT( | ||
| 378 | + aclnnKlDivBackward, INPUT(gradOutputDesc, selfDesc, targetDesc, reduction, logTarget), OUTPUT(outDesc)); | ||
| 379 | + uint64_t workspace_size = 0; | ||
| 380 | + aclnnStatus aclRet = ut.TestGetWorkspaceSize(&workspace_size); | ||
| 381 | + EXPECT_EQ(aclRet, ACLNN_ERR_PARAM_INVALID); | ||
| 382 | +} | ||
| 383 | + | ||
| 384 | +TEST_F(kl_div_loss_backward_test, aclnnKlDivBackward_18_target_not_broadcast) | ||
| 385 | +{ | ||
| 386 | + auto gradOutputDesc = TensorDesc({3, 4, 1, 1}, ACL_FLOAT16, ACL_FORMAT_ND).ValueRange(-1, 1); | ||
| 387 | + auto selfDesc = TensorDesc({3, 4, 6, 3}, ACL_FLOAT, ACL_FORMAT_ND).ValueRange(-1, 1); | ||
| 388 | + auto targetDesc = TensorDesc({3, 4, 6, 4}, ACL_FLOAT16, ACL_FORMAT_ND).ValueRange(-1, 1); | ||
| 389 | + int64_t reduction = Reduction::None; | ||
| 390 | + bool logTarget = true; | ||
| 391 | + | ||
| 392 | + auto outDesc = TensorDesc({3, 4, 6, 3}, ACL_FLOAT, ACL_FORMAT_ND).Precision(0.0001, 0.0001); | ||
| 393 | + | ||
| 394 | + auto ut = OP_API_UT( | ||
| 395 | + aclnnKlDivBackward, INPUT(gradOutputDesc, selfDesc, targetDesc, reduction, logTarget), OUTPUT(outDesc)); | ||
| 396 | + uint64_t workspace_size = 0; | ||
| 397 | + aclnnStatus aclRet = ut.TestGetWorkspaceSize(&workspace_size); | ||
| 398 | + EXPECT_EQ(aclRet, ACLNN_ERR_PARAM_INVALID); | ||
| 399 | +} | ||
| 400 | + | ||
| 401 | +TEST_F(kl_div_loss_backward_test, aclnnKlDivBackward_19_out_shape_not_equal_self) | ||
| 402 | +{ | ||
| 403 | + auto gradOutputDesc = TensorDesc({3, 4, 1, 1}, ACL_FLOAT16, ACL_FORMAT_ND).ValueRange(-1, 1); | ||
| 404 | + auto selfDesc = TensorDesc({3, 4, 6, 3}, ACL_FLOAT, ACL_FORMAT_ND).ValueRange(-1, 1); | ||
| 405 | + auto targetDesc = TensorDesc({3, 4, 6, 1}, ACL_FLOAT16, ACL_FORMAT_ND).ValueRange(-1, 1); | ||
| 406 | + int64_t reduction = Reduction::None; | ||
| 407 | + bool logTarget = true; | ||
| 408 | + | ||
| 409 | + auto outDesc = TensorDesc({3, 4, 6, 5}, ACL_FLOAT, ACL_FORMAT_ND).Precision(0.0001, 0.0001); | ||
| 410 | + | ||
| 411 | + auto ut = OP_API_UT( | ||
| 412 | + aclnnKlDivBackward, INPUT(gradOutputDesc, selfDesc, targetDesc, reduction, logTarget), OUTPUT(outDesc)); | ||
| 413 | + uint64_t workspace_size = 0; | ||
| 414 | + aclnnStatus aclRet = ut.TestGetWorkspaceSize(&workspace_size); | ||
| 415 | + EXPECT_EQ(aclRet, ACLNN_ERR_PARAM_INVALID); | ||
| 416 | +} | ||
| 417 | + | ||
| 418 | +TEST_F(kl_div_loss_backward_test, aclnnKlDivBackward_20_self_not_equal_broadcast_shape) | ||
| 419 | +{ | ||
| 420 | + auto gradOutputDesc = TensorDesc({3, 4, 1, 3}, ACL_FLOAT16, ACL_FORMAT_ND).ValueRange(-1, 1); | ||
| 421 | + auto selfDesc = TensorDesc({3, 4, 6, 1}, ACL_FLOAT, ACL_FORMAT_ND).ValueRange(-1, 1); | ||
| 422 | + auto targetDesc = TensorDesc({3, 4, 6, 1}, ACL_FLOAT16, ACL_FORMAT_ND).ValueRange(-1, 1); | ||
| 423 | + int64_t reduction = Reduction::None; | ||
| 424 | + bool logTarget = true; | ||
| 425 | + | ||
| 426 | + auto outDesc = TensorDesc({3, 4, 6, 1}, ACL_FLOAT, ACL_FORMAT_ND).Precision(0.0001, 0.0001); | ||
| 427 | + | ||
| 428 | + auto ut = OP_API_UT( | ||
| 429 | + aclnnKlDivBackward, INPUT(gradOutputDesc, selfDesc, targetDesc, reduction, logTarget), OUTPUT(outDesc)); | ||
| 430 | + uint64_t workspace_size = 0; | ||
| 431 | + aclnnStatus aclRet = ut.TestGetWorkspaceSize(&workspace_size); | ||
| 432 | + EXPECT_EQ(aclRet, ACLNN_ERR_PARAM_INVALID); | ||
| 433 | +} | ||
| 434 | + | ||
| 435 | +TEST_F(kl_div_loss_backward_test, aclnnKlDivBackward_21_broadcast_grad_1d) | ||
| 436 | +{ | ||
| 437 | + auto gradOutputDesc = TensorDesc({3, 1}, ACL_FLOAT, ACL_FORMAT_ND); | ||
| 438 | + auto selfDesc = TensorDesc({3, 1}, ACL_FLOAT, ACL_FORMAT_ND); | ||
| 439 | + auto targetDesc = TensorDesc({3, 5}, ACL_FLOAT, ACL_FORMAT_ND).ValueRange(0, 4); | ||
| 440 | + int64_t reduction = Reduction::None; | ||
| 441 | + bool logTarget = false; | ||
| 442 | + | ||
| 443 | + auto outDesc = TensorDesc({3, 1}, ACL_FLOAT, ACL_FORMAT_ND).Precision(0.0001, 0.0001); | ||
| 444 | + | ||
| 445 | + auto ut = OP_API_UT( | ||
| 446 | + aclnnKlDivBackward, INPUT(gradOutputDesc, selfDesc, targetDesc, reduction, logTarget), OUTPUT(outDesc)); | ||
| 447 | + | ||
| 448 | + uint64_t workspace_size = 0; | ||
| 449 | + aclnnStatus aclRet = ut.TestGetWorkspaceSize(&workspace_size); | ||
| 450 | + EXPECT_EQ(aclRet, ACL_SUCCESS); | ||
| 451 | + | ||
| 452 | + ut.TestPrecision(); | ||
| 453 | +} | ||
| 454 | + | ||
| 455 | +TEST_F(kl_div_loss_backward_test, aclnnKlDivBackward_22_broadcast_target_1d) | ||
| 456 | +{ | ||
| 457 | + auto gradOutputDesc = TensorDesc({3, 1}, ACL_FLOAT, ACL_FORMAT_ND); | ||
| 458 | + auto selfDesc = TensorDesc({3, 5}, ACL_FLOAT, ACL_FORMAT_ND); | ||
| 459 | + auto targetDesc = TensorDesc({3, 1}, ACL_FLOAT, ACL_FORMAT_ND).ValueRange(0, 4); | ||
| 460 | + int64_t reduction = Reduction::None; | ||
| 461 | + bool logTarget = false; | ||
| 462 | + | ||
| 463 | + auto outDesc = TensorDesc({3, 5}, ACL_FLOAT, ACL_FORMAT_ND).Precision(0.0001, 0.0001); | ||
| 464 | + | ||
| 465 | + auto ut = OP_API_UT( | ||
| 466 | + aclnnKlDivBackward, INPUT(gradOutputDesc, selfDesc, targetDesc, reduction, logTarget), OUTPUT(outDesc)); | ||
| 467 | + | ||
| 468 | + uint64_t workspace_size = 0; | ||
| 469 | + aclnnStatus aclRet = ut.TestGetWorkspaceSize(&workspace_size); | ||
| 470 | + EXPECT_EQ(aclRet, ACL_SUCCESS); | ||
| 471 | + | ||
| 472 | + ut.TestPrecision(); | ||
| 473 | +} | ||
| 474 | + | ||
| 475 | +TEST_F(kl_div_loss_backward_test, aclnnKlDivBackward_23_broadcast_mixed_rank) | ||
| 476 | +{ | ||
| 477 | + auto gradOutputDesc = TensorDesc({3, 1, 1}, ACL_FLOAT, ACL_FORMAT_ND); | ||
| 478 | + auto selfDesc = TensorDesc({3, 5, 1}, ACL_FLOAT, ACL_FORMAT_ND); | ||
| 479 | + auto targetDesc = TensorDesc({6, 3, 1, 7}, ACL_FLOAT, ACL_FORMAT_ND).ValueRange(0, 4); | ||
| 480 | + int64_t reduction = Reduction::None; | ||
| 481 | + bool logTarget = false; | ||
| 482 | + | ||
| 483 | + auto outDesc = TensorDesc({3, 5, 1}, ACL_FLOAT, ACL_FORMAT_ND).Precision(0.0001, 0.0001); | ||
| 484 | + | ||
| 485 | + auto ut = OP_API_UT( | ||
| 486 | + aclnnKlDivBackward, INPUT(gradOutputDesc, selfDesc, targetDesc, reduction, logTarget), OUTPUT(outDesc)); | ||
| 487 | + | ||
| 488 | + uint64_t workspace_size = 0; | ||
| 489 | + aclnnStatus aclRet = ut.TestGetWorkspaceSize(&workspace_size); | ||
| 490 | + EXPECT_EQ(aclRet, ACL_SUCCESS); | ||
| 491 | + | ||
| 492 | + ut.TestPrecision(); | ||
| 493 | +} | ||
| @@ -0,0 +1,15 @@ | |||
| 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 | +file(GLOB CURRENT_DIRS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*) | ||
| 12 | +if(UT_TEST_ALL OR OP_HOST_UT) | ||
| 13 | + add_modules_ut_sources(HOSTNAME ${OP_TILING_MODULE_NAME} MODE PRIVATE DIR ${CMAKE_CURRENT_SOURCE_DIR}) | ||
| 14 | + add_modules_ut_sources(HOSTNAME ${OP_INFERSHAPE_MODULE_NAME} MODE PRIVATE DIR ${CMAKE_CURRENT_SOURCE_DIR}) | ||
| 15 | +endif() | ||
| @@ -0,0 +1,222 @@ | |||
| 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 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | +using namespace ut_util; | ||
| 25 | +using namespace std; | ||
| 26 | +using namespace ge; | ||
| 27 | + | ||
| 28 | +class KlDivLossGradTiling : public testing::Test { | ||
| 29 | +protected: | ||
| 30 | + static void SetUpTestCase() { cout << "KlDivLossGradTiling SetUp" << endl; } | ||
| 31 | + | ||
| 32 | + static void TearDownTestCase() { cout << "KlDivLossGradTiling TearDown " << endl; } | ||
| 33 | +}; | ||
| 34 | + | ||
| 35 | +TEST_F(KlDivLossGradTiling, kl_div_loss_grad_float32_success) | ||
| 36 | +{ | ||
| 37 | + gert::StorageShape x1Shape = {{1, 2, 8, 16}, {1, 2, 8, 16}}; | ||
| 38 | + gert::StorageShape x2Shape = {{1, 2, 8, 16}, {1, 2, 8, 16}}; | ||
| 39 | + gert::StorageShape x3Shape = {{1, 2, 8, 16}, {1, 2, 8, 16}}; | ||
| 40 | + gert::StorageShape yShape = {{1, 2, 8, 16}, {1, 2, 8, 16}}; | ||
| 41 | + string compileInfoString = R"({ | ||
| 42 | + "hardware_info": {"BT_SIZE": 0, "load3d_constraints": "1", | ||
| 43 | + "Intrinsic_fix_pipe_l0c2out": false, "Intrinsic_data_move_l12ub": true, "Intrinsic_data_move_l0c2ub": true, "Intrinsic_data_move_out2l1_nd2nz": false, | ||
| 44 | + "UB_SIZE": 196608, "L2_SIZE": 33554432, "L1_SIZE": 524288, | ||
| 45 | + "L0A_SIZE": 65536, "L0B_SIZE": 65536, "L0C_SIZE": 131072, | ||
| 46 | + "CORE_NUM": 48} | ||
| 47 | + })"; | ||
| 48 | + map<string, string> socInfos; | ||
| 49 | + map<string, string> aicoreSpec; | ||
| 50 | + map<string, string> intrinsics; | ||
| 51 | + GetPlatFormInfos(compileInfoString.c_str(), socInfos, aicoreSpec, intrinsics); | ||
| 52 | + | ||
| 53 | + fe::PlatFormInfos platformInfo; | ||
| 54 | + platformInfo.Init(); | ||
| 55 | + | ||
| 56 | + struct KlDivLossGradTilingCompileInfo {}; | ||
| 57 | + KlDivLossGradTilingCompileInfo compileInfo; | ||
| 58 | + | ||
| 59 | + std::string opType("KlDivLossGrad"); | ||
| 60 | + auto tilingFunc = gert::OpImplRegistry::GetInstance().GetOpImpl(opType.c_str())->tiling; | ||
| 61 | + | ||
| 62 | + auto kernelHolder = | ||
| 63 | + gert::KernelRunContextFaker() | ||
| 64 | + .KernelIONum(3, 1) | ||
| 65 | + .Inputs({const_cast<char*>(compileInfoString.c_str()), reinterpret_cast<void*>(&platformInfo)}) | ||
| 66 | + .Outputs({&compileInfo}) | ||
| 67 | + .Build(); | ||
| 68 | + kernelHolder.GetContext<gert::TilingParseContext>()->GetPlatformInfo()->SetPlatformRes("SoCInfo", socInfos); | ||
| 69 | + kernelHolder.GetContext<gert::TilingParseContext>()->GetPlatformInfo()->SetPlatformRes("AICoreSpec", aicoreSpec); | ||
| 70 | + kernelHolder.GetContext<gert::TilingParseContext>()->GetPlatformInfo()->SetCoreNumByCoreType("AICore"); | ||
| 71 | + kernelHolder.GetContext<gert::TilingParseContext>()->GetPlatformInfo()->SetPlatformRes( | ||
| 72 | + "AICoreintrinsicDtypeMap", intrinsics); | ||
| 73 | + | ||
| 74 | + auto param = gert::TilingData::CreateCap(4096); | ||
| 75 | + auto workspaceSizeHoler = gert::ContinuousVector::Create<size_t>(4096); | ||
| 76 | + auto wsSize = reinterpret_cast<gert::ContinuousVector*>(workspaceSizeHoler.get()); | ||
| 77 | + ASSERT_NE(param, nullptr); | ||
| 78 | + auto holder = gert::TilingContextFaker() | ||
| 79 | + .SetOpType("KlDivLossGrad") | ||
| 80 | + .NodeIoNum(3, 1) | ||
| 81 | + .IrInstanceNum({1, 1}) | ||
| 82 | + .InputShapes({&x1Shape, &x2Shape, &x3Shape}) | ||
| 83 | + .OutputShapes({&yShape}) | ||
| 84 | + .CompileInfo(&compileInfo) | ||
| 85 | + .PlatformInfo(reinterpret_cast<char*>(&platformInfo)) | ||
| 86 | + .NodeInputTd(0, ge::DT_FLOAT, ge::FORMAT_ND, ge::FORMAT_ND) | ||
| 87 | + .NodeInputTd(1, ge::DT_FLOAT, ge::FORMAT_ND, ge::FORMAT_ND) | ||
| 88 | + .NodeInputTd(2, ge::DT_FLOAT, ge::FORMAT_ND, ge::FORMAT_ND) | ||
| 89 | + .NodeOutputTd(0, ge::DT_FLOAT, ge::FORMAT_ND, ge::FORMAT_ND) | ||
| 90 | + .TilingData(param.get()) | ||
| 91 | + .Workspace(wsSize) | ||
| 92 | + .Build(); | ||
| 93 | + gert::TilingContext* tilingContext = holder.GetContext<gert::TilingContext>(); | ||
| 94 | + ASSERT_NE(tilingContext, nullptr); | ||
| 95 | + EXPECT_EQ(tilingFunc(tilingContext), ge::GRAPH_SUCCESS); | ||
| 96 | +} | ||
| 97 | + | ||
| 98 | +TEST_F(KlDivLossGradTiling, kl_div_loss_grad_float16_success) | ||
| 99 | +{ | ||
| 100 | + gert::StorageShape x1Shape = {{1, 2, 8, 16}, {1, 2, 8, 16}}; | ||
| 101 | + gert::StorageShape x2Shape = {{1, 2, 8, 16}, {1, 2, 8, 16}}; | ||
| 102 | + gert::StorageShape x3Shape = {{1, 2, 8, 16}, {1, 2, 8, 16}}; | ||
| 103 | + gert::StorageShape yShape = {{1, 2, 8, 16}, {1, 2, 8, 16}}; | ||
| 104 | + string compileInfoString = R"({ | ||
| 105 | + "hardware_info": {"BT_SIZE": 0, "load3d_constraints": "1", | ||
| 106 | + "Intrinsic_fix_pipe_l0c2out": false, "Intrinsic_data_move_l12ub": true, "Intrinsic_data_move_l0c2ub": true, "Intrinsic_data_move_out2l1_nd2nz": false, | ||
| 107 | + "UB_SIZE": 196608, "L2_SIZE": 33554432, "L1_SIZE": 524288, | ||
| 108 | + "L0A_SIZE": 65536, "L0B_SIZE": 65536, "L0C_SIZE": 131072, | ||
| 109 | + "CORE_NUM": 48} | ||
| 110 | + })"; | ||
| 111 | + map<string, string> socInfos; | ||
| 112 | + map<string, string> aicoreSpec; | ||
| 113 | + map<string, string> intrinsics; | ||
| 114 | + GetPlatFormInfos(compileInfoString.c_str(), socInfos, aicoreSpec, intrinsics); | ||
| 115 | + | ||
| 116 | + fe::PlatFormInfos platformInfo; | ||
| 117 | + platformInfo.Init(); | ||
| 118 | + | ||
| 119 | + struct KlDivLossGradTilingCompileInfo {}; | ||
| 120 | + KlDivLossGradTilingCompileInfo compileInfo; | ||
| 121 | + | ||
| 122 | + std::string opType("KlDivLossGrad"); | ||
| 123 | + auto tilingFunc = gert::OpImplRegistry::GetInstance().GetOpImpl(opType.c_str())->tiling; | ||
| 124 | + | ||
| 125 | + auto kernelHolder = | ||
| 126 | + gert::KernelRunContextFaker() | ||
| 127 | + .KernelIONum(3, 1) | ||
| 128 | + .Inputs({const_cast<char*>(compileInfoString.c_str()), reinterpret_cast<void*>(&platformInfo)}) | ||
| 129 | + .Outputs({&compileInfo}) | ||
| 130 | + .Build(); | ||
| 131 | + kernelHolder.GetContext<gert::TilingParseContext>()->GetPlatformInfo()->SetPlatformRes("SoCInfo", socInfos); | ||
| 132 | + kernelHolder.GetContext<gert::TilingParseContext>()->GetPlatformInfo()->SetPlatformRes("AICoreSpec", aicoreSpec); | ||
| 133 | + kernelHolder.GetContext<gert::TilingParseContext>()->GetPlatformInfo()->SetCoreNumByCoreType("AICore"); | ||
| 134 | + kernelHolder.GetContext<gert::TilingParseContext>()->GetPlatformInfo()->SetPlatformRes( | ||
| 135 | + "AICoreintrinsicDtypeMap", intrinsics); | ||
| 136 | + | ||
| 137 | + auto param = gert::TilingData::CreateCap(4096); | ||
| 138 | + auto workspaceSizeHoler = gert::ContinuousVector::Create<size_t>(4096); | ||
| 139 | + auto wsSize = reinterpret_cast<gert::ContinuousVector*>(workspaceSizeHoler.get()); | ||
| 140 | + ASSERT_NE(param, nullptr); | ||
| 141 | + auto holder = gert::TilingContextFaker() | ||
| 142 | + .SetOpType("KlDivLossGrad") | ||
| 143 | + .NodeIoNum(3, 1) | ||
| 144 | + .IrInstanceNum({1, 1}) | ||
| 145 | + .InputShapes({&x1Shape, &x2Shape, &x3Shape}) | ||
| 146 | + .OutputShapes({&yShape}) | ||
| 147 | + .CompileInfo(&compileInfo) | ||
| 148 | + .PlatformInfo(reinterpret_cast<char*>(&platformInfo)) | ||
| 149 | + .NodeInputTd(0, ge::DT_FLOAT16, ge::FORMAT_ND, ge::FORMAT_ND) | ||
| 150 | + .NodeInputTd(1, ge::DT_FLOAT16, ge::FORMAT_ND, ge::FORMAT_ND) | ||
| 151 | + .NodeInputTd(2, ge::DT_FLOAT16, ge::FORMAT_ND, ge::FORMAT_ND) | ||
| 152 | + .NodeOutputTd(0, ge::DT_FLOAT16, ge::FORMAT_ND, ge::FORMAT_ND) | ||
| 153 | + .TilingData(param.get()) | ||
| 154 | + .Workspace(wsSize) | ||
| 155 | + .Build(); | ||
| 156 | + gert::TilingContext* tilingContext = holder.GetContext<gert::TilingContext>(); | ||
| 157 | + ASSERT_NE(tilingContext, nullptr); | ||
| 158 | + EXPECT_EQ(tilingFunc(tilingContext), ge::GRAPH_SUCCESS); | ||
| 159 | +} | ||
| 160 | + | ||
| 161 | +TEST_F(KlDivLossGradTiling, kl_div_loss_grad_bf16_success) | ||
| 162 | +{ | ||
| 163 | + gert::StorageShape x1Shape = {{1, 2, 8, 16}, {1, 2, 8, 16}}; | ||
| 164 | + gert::StorageShape x2Shape = {{1, 2, 8, 16}, {1, 2, 8, 16}}; | ||
| 165 | + gert::StorageShape x3Shape = {{1, 2, 8, 16}, {1, 2, 8, 16}}; | ||
| 166 | + gert::StorageShape yShape = {{1, 2, 8, 16}, {1, 2, 8, 16}}; | ||
| 167 | + string compileInfoString = R"({ | ||
| 168 | + "hardware_info": {"BT_SIZE": 0, "load3d_constraints": "1", | ||
| 169 | + "Intrinsic_fix_pipe_l0c2out": false, "Intrinsic_data_move_l12ub": true, "Intrinsic_data_move_l0c2ub": true, "Intrinsic_data_move_out2l1_nd2nz": false, | ||
| 170 | + "UB_SIZE": 196608, "L2_SIZE": 33554432, "L1_SIZE": 524288, | ||
| 171 | + "L0A_SIZE": 65536, "L0B_SIZE": 65536, "L0C_SIZE": 131072, | ||
| 172 | + "CORE_NUM": 48} | ||
| 173 | + })"; | ||
| 174 | + map<string, string> socInfos; | ||
| 175 | + map<string, string> aicoreSpec; | ||
| 176 | + map<string, string> intrinsics; | ||
| 177 | + GetPlatFormInfos(compileInfoString.c_str(), socInfos, aicoreSpec, intrinsics); | ||
| 178 | + | ||
| 179 | + fe::PlatFormInfos platformInfo; | ||
| 180 | + platformInfo.Init(); | ||
| 181 | + | ||
| 182 | + struct KlDivLossGradTilingCompileInfo {}; | ||
| 183 | + KlDivLossGradTilingCompileInfo compileInfo; | ||
| 184 | + | ||
| 185 | + std::string opType("KlDivLossGrad"); | ||
| 186 | + auto tilingFunc = gert::OpImplRegistry::GetInstance().GetOpImpl(opType.c_str())->tiling; | ||
| 187 | + | ||
| 188 | + auto kernelHolder = | ||
| 189 | + gert::KernelRunContextFaker() | ||
| 190 | + .KernelIONum(3, 1) | ||
| 191 | + .Inputs({const_cast<char*>(compileInfoString.c_str()), reinterpret_cast<void*>(&platformInfo)}) | ||
| 192 | + .Outputs({&compileInfo}) | ||
| 193 | + .Build(); | ||
| 194 | + kernelHolder.GetContext<gert::TilingParseContext>()->GetPlatformInfo()->SetPlatformRes("SoCInfo", socInfos); | ||
| 195 | + kernelHolder.GetContext<gert::TilingParseContext>()->GetPlatformInfo()->SetPlatformRes("AICoreSpec", aicoreSpec); | ||
| 196 | + kernelHolder.GetContext<gert::TilingParseContext>()->GetPlatformInfo()->SetCoreNumByCoreType("AICore"); | ||
| 197 | + kernelHolder.GetContext<gert::TilingParseContext>()->GetPlatformInfo()->SetPlatformRes( | ||
| 198 | + "AICoreintrinsicDtypeMap", intrinsics); | ||
| 199 | + | ||
| 200 | + auto param = gert::TilingData::CreateCap(4096); | ||
| 201 | + auto workspaceSizeHoler = gert::ContinuousVector::Create<size_t>(4096); | ||
| 202 | + auto wsSize = reinterpret_cast<gert::ContinuousVector*>(workspaceSizeHoler.get()); | ||
| 203 | + ASSERT_NE(param, nullptr); | ||
| 204 | + auto holder = gert::TilingContextFaker() | ||
| 205 | + .SetOpType("KlDivLossGrad") | ||
| 206 | + .NodeIoNum(3, 1) | ||
| 207 | + .IrInstanceNum({1, 1}) | ||
| 208 | + .InputShapes({&x1Shape, &x2Shape, &x3Shape}) | ||
| 209 | + .OutputShapes({&yShape}) | ||
| 210 | + .CompileInfo(&compileInfo) | ||
| 211 | + .PlatformInfo(reinterpret_cast<char*>(&platformInfo)) | ||
| 212 | + .NodeInputTd(0, ge::DT_BF16, ge::FORMAT_ND, ge::FORMAT_ND) | ||
| 213 | + .NodeInputTd(1, ge::DT_BF16, ge::FORMAT_ND, ge::FORMAT_ND) | ||
| 214 | + .NodeInputTd(2, ge::DT_BF16, ge::FORMAT_ND, ge::FORMAT_ND) | ||
| 215 | + .NodeOutputTd(0, ge::DT_BF16, ge::FORMAT_ND, ge::FORMAT_ND) | ||
| 216 | + .TilingData(param.get()) | ||
| 217 | + .Workspace(wsSize) | ||
| 218 | + .Build(); | ||
| 219 | + gert::TilingContext* tilingContext = holder.GetContext<gert::TilingContext>(); | ||
| 220 | + ASSERT_NE(tilingContext, nullptr); | ||
| 221 | + EXPECT_EQ(tilingFunc(tilingContext), ge::GRAPH_SUCCESS); | ||
| 222 | +} | ||
| @@ -0,0 +1,30 @@ | |||
| 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 | +if ((UT_TEST_ALL OR OP_KERNEL_UT) AND NOT UT_DONE) | ||
| 13 | + # 需要将Tiling依赖的文件添加到CMakeLists.txt中 | ||
| 14 | + # set(elewise_common_tiling_files | ||
| 15 | + # ${CANN_ROOT}/ops/built-in/op_tiling/runtime/elewise_tiling.cc | ||
| 16 | + # ) | ||
| 17 | + # 算子自己的tiling文件路径 | ||
| 18 | + set(kl_div_loss_grad_tiling_files | ||
| 19 | + ${CMAKE_CURRENT_SOURCE_DIR}/../../../op_host/kl_div_loss_grad_tiling.cpp | ||
| 20 | + ${CMAKE_CURRENT_SOURCE_DIR}/../../../op_host/kl_div_loss_grad_infershape.cpp | ||
| 21 | + # ${elewise_common_tiling_files} | ||
| 22 | + ) | ||
| 23 | + # 使用AddOpTestCase | ||
| 24 | + # param1:算子名称,以kernel方式命名 | ||
| 25 | + # param2:soc版本,多个以分号分隔,例如:"ascend950pr_9599;AscendB1" | ||
| 26 | + # param3:自定义编译选项,一般填写测试的一种典型数据类型组合,不需要则传入空字符串,例如:"-DDTYPE_X=float",多个使用空格分隔,例如:"-DDTYPE_X=float -DDTYPE_Y=float" | ||
| 27 | + # param4:该算子依赖的所有tiling源码文件 | ||
| 28 | + # AddOpTestCase(kl_div_loss_grad "ascend910b" "${kl_div_loss_grad_tiling_files}") | ||
| 29 | + AddOpTestCase(kl_div_loss_grad "ascend910B1" "-DDTYPE_GRAD=float" "${kl_div_loss_grad_tiling_files}") | ||
| 30 | +endif() | ||
| @@ -0,0 +1,69 @@ | |||
| 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 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | +using namespace std; | ||
| 26 | + | ||
| 27 | +class kl_div_loss_grad_test : public testing::Test { | ||
| 28 | +protected: | ||
| 29 | + static void SetUpTestCase() { cout << "kl_div_loss_grad_test SetUp\n" << endl; } | ||
| 30 | + static void TearDownTestCase() { cout << "kl_div_loss_grad_test TearDown\n" << endl; } | ||
| 31 | +}; | ||
| 32 | + | ||
| 33 | +TEST_F(kl_div_loss_grad_test, test_case_0) | ||
| 34 | +{ | ||
| 35 | + size_t gradByteSize = 32 * 4 * 4 * 4 * sizeof(float); | ||
| 36 | + size_t inputByteSize = 32 * 4 * 4 * 4 * sizeof(float); | ||
| 37 | + size_t targetByteSize = 32 * 4 * 4 * 4 * sizeof(float); | ||
| 38 | + size_t yByteSize = 32 * 4 * 4 * 4 * sizeof(float); | ||
| 39 | + size_t tilingDataSize = sizeof(KlDivLossGradTilingData); | ||
| 40 | + uint32_t blockDim = 1; | ||
| 41 | + | ||
| 42 | + uint8_t* grad = (uint8_t*)AscendC::GmAlloc(gradByteSize); | ||
| 43 | + uint8_t* input = (uint8_t*)AscendC::GmAlloc(inputByteSize); | ||
| 44 | + uint8_t* target = (uint8_t*)AscendC::GmAlloc(targetByteSize); | ||
| 45 | + uint8_t* y = (uint8_t*)AscendC::GmAlloc(yByteSize); | ||
| 46 | + | ||
| 47 | + uint8_t* workspace = (uint8_t*)AscendC::GmAlloc(1024 * 1024 * 16); | ||
| 48 | + uint8_t* tiling = (uint8_t*)AscendC::GmAlloc(tilingDataSize); | ||
| 49 | + | ||
| 50 | + auto* tilingDataFromBin = reinterpret_cast<KlDivLossGradTilingData*>(tiling); | ||
| 51 | + tilingDataFromBin->bigCoreDataNum = 2048; | ||
| 52 | + tilingDataFromBin->smallCoreDataNum = 2048; | ||
| 53 | + tilingDataFromBin->tileDataNum = 2048; | ||
| 54 | + tilingDataFromBin->bigCoreNum = 1; | ||
| 55 | + tilingDataFromBin->coff = 1.0f; | ||
| 56 | + | ||
| 57 | + auto klDivLossGradKernel = kl_div_loss_grad<false, false>; | ||
| 58 | + | ||
| 59 | + ICPU_SET_TILING_KEY(0); | ||
| 60 | + AscendC::SetKernelMode(KernelMode::AIV_MODE); | ||
| 61 | + ICPU_RUN_KF(klDivLossGradKernel, blockDim, grad, input, target, y, workspace, (uint8_t*)(tilingDataFromBin)); | ||
| 62 | + | ||
| 63 | + AscendC::GmFree(grad); | ||
| 64 | + AscendC::GmFree(input); | ||
| 65 | + AscendC::GmFree(target); | ||
| 66 | + AscendC::GmFree(y); | ||
| 67 | + AscendC::GmFree(workspace); | ||
| 68 | + AscendC::GmFree(tiling); | ||
| 69 | +} | ||


Copyright (c) 2025,应为2026。涉及文件:kl_div_loss_grad_def.cpp、kl_div_loss_grad_infershape.cpp、kl_div_loss_grad_tiling.cpp、kl_div_loss_grad.cpp(kernel)、kl_div_loss_grad.h、kl_div_loss_grad_tiling_data.h、kl_div_loss_grad_tiling_key.h、aclnn_kl_div_backward.cpp、aclnn_kl_div_backward.h、kl_div_loss_grad.cpp(op_api)、kl_div_loss_grad.h、test_aclnn_kl_div_loss_grad.cpp、CMakeLists.txt