| @@ -0,0 +1,209 @@ |
| +/** |
| + * @file test_aclnn_norm_multiply_dropout_backward.cpp |
| + * |
| + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. |
| + * |
| + * aclnnNormMultiplyDropoutBackward 两段式接口调用示例。 |
| + * 输入 d_out/x/u/weight/bias/mean/var/mask 与 attrs eps/dropout_ratio, |
| + * 输出 (d_x, d_u, d_weight, d_bias)。 |
| + * dropout_ratio > 1e-10 时需传入 uint8 位图掩码:mask 元素数 = x 元素数向上对齐 |
| + * 128 再除以 8;本示例仅演示接口调用,mask 使用随机数据填充(仅保证 shape 满足 |
| + * 输入要求),实际业务应通过 aclnnDropoutGenMaskV2 或上层框架接口生成有效掩码; |
| + * dropout_ratio <= 1e-10 时不消费 mask,shape 传占位 {1}。 |
| + * 950 平台算子不支持 fp32,示例输入使用 ACL_FLOAT16;d_weight/d_bias 输出为 fp32。 |
| + */ |
| +#include <algorithm> |
| +#include <cstdlib> |
| +#include <iostream> |
| +#include <numeric> |
| +#include <vector> |
| +#include "acl/acl.h" |
| +#include "aclnn_norm_multiply_dropout_backward.h" |
| + |
| +#define CHECK_RET(cond, expr) \ |
| + do { \ |
| + if (!(cond)) { \ |
| + expr; \ |
| + } \ |
| + } while (0) |
| + |
| +#define LOG_PRINT(message, ...) \ |
| + do { \ |
| + printf(message, ##__VA_ARGS__); \ |
| + printf("\n"); \ |
| + } while (0) |
| + |
| +// ACL_FLOAT16 位模式占位(0x3800 = fp16 0.5),长度与元素数一致 |
| +using Float16 = uint16_t; |
| + |
| +int32_t deviceId = 0; |
| +aclrtStream stream; |
| + |
| +int Init(int32_t deviceId, aclrtStream* stream) |
| +{ |
| + // 固定写法,AscendCL初始化 |
| + auto ret = aclInit(nullptr); |
| + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); |
| + ret = aclrtSetDevice(deviceId); |
| + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); |
| + ret = aclrtCreateStream(stream); |
| + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); |
| + return 0; |
| +} |
| + |
| +template <typename T> |
| +int CreateAclTensor(const std::vector<int64_t>& shape, void** deviceAddr, std::vector<T>& hostData, |
| + aclDataType dataType, aclTensor** tensor) |
| +{ |
| + auto size = shape.empty() ? sizeof(T) |
| + : std::accumulate(shape.begin(), shape.end(), sizeof(T), |
| + [](int64_t a, int64_t b) { return a * b; }); |
| + *deviceAddr = nullptr; |
| + auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); |
| + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); |
| + ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); |
| + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); |
| + |
| + std::vector<int64_t> strides(shape.size(), 1); |
| + for (int64_t i = shape.size() - 2; i >= 0; i--) { |
| + strides[i] = shape[i + 1] * strides[i + 1]; |
| + } |
| + |
| + *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, |
| + shape.data(), shape.size(), *deviceAddr); |
| + return 0; |
| +} |
| + |
| +int main() |
| +{ |
| + // batch、col 及 tensor 初始化(dtype/buffer 尺寸需与 op_host 校验一致) |
| + int64_t batch = 4; |
| + int64_t col = 512; // 仅支持 512 或 1024 |
| + std::vector<int64_t> xShape = {batch, col}; |
| + std::vector<int64_t> weightShape = {col}; |
| + std::vector<int64_t> batchShape = {batch}; |
| + float eps = 1e-5f; |
| + float dropoutRatio = 0.5f; |
| + // mask 生成按 dropout_ratio 分支: |
| + // dropout_ratio > 1e-10:mask 元素数 = x 元素数(batch*col)向上对齐 128 再除以 8; |
| + // dropout_ratio <= 1e-10:不执行 dropout,mask 不消费,shape 传占位 {1} |
| + int64_t maskNumel = dropoutRatio > 1e-10f ? (batch * col + 127) / 128 * 128 / 8 : 1; |
| + |
| + int InitRsp = Init(deviceId, &stream); |
| + CHECK_RET(InitRsp == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", InitRsp); return InitRsp); |
| + |
| + std::vector<Float16> dOutHostData(batch * col, 0x3800); |
| + std::vector<Float16> xHostData(batch * col, 0x3800); |
| + std::vector<Float16> uHostData(batch * col, 0x3800); |
| + std::vector<Float16> weightHostData(col, 0x3800); |
| + std::vector<Float16> biasHostData(col, 0x3800); |
| + std::vector<float> meanHostData(batch, 0.0f); |
| + std::vector<float> varHostData(batch, 1.0f); |
| + std::vector<uint8_t> maskHostData(maskNumel, 0); |
| + if (dropoutRatio > 1e-10f) { |
| + // dropout>0:随机生成掩码数据,仅保证 shape 满足输入要求(真实掩码应调用 aclnnDropoutGenMaskV2 生成) |
| + std::generate(maskHostData.begin(), maskHostData.end(), []() { return static_cast<uint8_t>(rand() & 0xFF); }); |
| + } |
| + // dropout<=1e-10:mask 保持 {0} 占位,kernel 不消费 |
| + std::vector<Float16> dXHostData(batch * col, 0); |
| + std::vector<Float16> dUHostData(batch * col, 0); |
| + std::vector<float> dWeightHostData(col, 0); |
| + std::vector<float> dBiasHostData(col, 0); |
| + |
| + void *dOutDeviceAddr = nullptr, *xDeviceAddr = nullptr, *uDeviceAddr = nullptr, *weightDeviceAddr = nullptr; |
| + void *biasDeviceAddr = nullptr, *meanDeviceAddr = nullptr, *varDeviceAddr = nullptr, *maskDeviceAddr = nullptr; |
| + void *dXDeviceAddr = nullptr, *dUDeviceAddr = nullptr, *dWeightDeviceAddr = nullptr, *dBiasDeviceAddr = nullptr; |
| + aclTensor *dOut = nullptr, *x = nullptr, *u = nullptr, *weight = nullptr, *bias = nullptr; |
| + aclTensor *mean = nullptr, *var = nullptr, *mask = nullptr; |
| + aclTensor *dX = nullptr, *dU = nullptr, *dWeight = nullptr, *dBias = nullptr; |
| + |
| + int ret = 0; |
| + ret = CreateAclTensor(xShape, &dOutDeviceAddr, dOutHostData, ACL_FLOAT16, &dOut); |
| + CHECK_RET(ret == ACL_SUCCESS, return ret); |
| + ret = CreateAclTensor(xShape, &xDeviceAddr, xHostData, ACL_FLOAT16, &x); |
| + CHECK_RET(ret == ACL_SUCCESS, return ret); |
| + ret = CreateAclTensor(xShape, &uDeviceAddr, uHostData, ACL_FLOAT16, &u); |
| + CHECK_RET(ret == ACL_SUCCESS, return ret); |
| + ret = CreateAclTensor(weightShape, &weightDeviceAddr, weightHostData, ACL_FLOAT16, &weight); |
| + CHECK_RET(ret == ACL_SUCCESS, return ret); |
| + ret = CreateAclTensor(weightShape, &biasDeviceAddr, biasHostData, ACL_FLOAT16, &bias); |
| + CHECK_RET(ret == ACL_SUCCESS, return ret); |
| + ret = CreateAclTensor(batchShape, &meanDeviceAddr, meanHostData, ACL_FLOAT, &mean); |
| + CHECK_RET(ret == ACL_SUCCESS, return ret); |
| + ret = CreateAclTensor(batchShape, &varDeviceAddr, varHostData, ACL_FLOAT, &var); |
| + CHECK_RET(ret == ACL_SUCCESS, return ret); |
| + ret = CreateAclTensor({maskNumel}, &maskDeviceAddr, maskHostData, ACL_UINT8, &mask); |
| + CHECK_RET(ret == ACL_SUCCESS, return ret); |
| + ret = CreateAclTensor(xShape, &dXDeviceAddr, dXHostData, ACL_FLOAT16, &dX); |
| + CHECK_RET(ret == ACL_SUCCESS, return ret); |
| + ret = CreateAclTensor(xShape, &dUDeviceAddr, dUHostData, ACL_FLOAT16, &dU); |
| + CHECK_RET(ret == ACL_SUCCESS, return ret); |
| + ret = CreateAclTensor(weightShape, &dWeightDeviceAddr, dWeightHostData, ACL_FLOAT, &dWeight); |
| + CHECK_RET(ret == ACL_SUCCESS, return ret); |
| + ret = CreateAclTensor(weightShape, &dBiasDeviceAddr, dBiasHostData, ACL_FLOAT, &dBias); |
| + CHECK_RET(ret == ACL_SUCCESS, return ret); |
| + |
| + uint64_t workspaceSize = 0; |
| + aclOpExecutor* executor; |
| + |
| + // 调用第一段接口(输出顺序 (d_x, d_u, d_weight, d_bias) 与算子注册一致) |
| + ret = aclnnNormMultiplyDropoutBackwardGetWorkspaceSize(dOut, x, u, weight, bias, mean, var, mask, eps, dropoutRatio, |
| + dX, dU, dWeight, dBias, &workspaceSize, &executor); |
| + CHECK_RET(ret == ACL_SUCCESS, |
| + LOG_PRINT("aclnnNormMultiplyDropoutBackwardGetWorkspaceSize failed. ERROR: %d\n", ret); |
| + return ret); |
| + |
| + void* workspaceAddr = nullptr; |
| + if (workspaceSize > 0) { |
| + ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); |
| + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); |
| + } |
| + // 调用第二段接口 |
| + ret = aclnnNormMultiplyDropoutBackward(workspaceAddr, workspaceSize, executor, stream); |
| + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnNormMultiplyDropoutBackward failed. ERROR: %d\n", ret); return ret); |
| + |
| + ret = aclrtSynchronizeStream(stream); |
| + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); |
| + |
| + LOG_PRINT("aclnnNormMultiplyDropoutBackward execute success\n"); |
| + |
| + // (可选)把 d_x/d_u 拷回 host 侧查看结果 |
| + ret = aclrtMemcpy(dXHostData.data(), dXHostData.size() * sizeof(Float16), dXDeviceAddr, |
| + dXHostData.size() * sizeof(Float16), ACL_MEMCPY_DEVICE_TO_HOST); |
| + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy d_x failed. ERROR: %d\n", ret); return ret); |
| + ret = aclrtMemcpy(dUHostData.data(), dUHostData.size() * sizeof(Float16), dUDeviceAddr, |
| + dUHostData.size() * sizeof(Float16), ACL_MEMCPY_DEVICE_TO_HOST); |
| + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy d_u failed. ERROR: %d\n", ret); return ret); |
| + |
| + aclDestroyTensor(dOut); |
| + aclDestroyTensor(x); |
| + aclDestroyTensor(u); |
| + aclDestroyTensor(weight); |
| + aclDestroyTensor(bias); |
| + aclDestroyTensor(mean); |
| + aclDestroyTensor(var); |
| + aclDestroyTensor(mask); |
| + aclDestroyTensor(dX); |
| + aclDestroyTensor(dU); |
| + aclDestroyTensor(dWeight); |
| + aclDestroyTensor(dBias); |
| + aclrtFree(dOutDeviceAddr); |
| + aclrtFree(xDeviceAddr); |
| + aclrtFree(uDeviceAddr); |
| + aclrtFree(weightDeviceAddr); |
| + aclrtFree(biasDeviceAddr); |
| + aclrtFree(meanDeviceAddr); |
| + aclrtFree(varDeviceAddr); |
| + aclrtFree(maskDeviceAddr); |
| + aclrtFree(dXDeviceAddr); |
| + aclrtFree(dUDeviceAddr); |
| + aclrtFree(dWeightDeviceAddr); |
| + aclrtFree(dBiasDeviceAddr); |
| + if (workspaceAddr != nullptr) { |
| + aclrtFree(workspaceAddr); |
| + } |
| + aclrtDestroyStream(stream); |
| + aclrtResetDevice(deviceId); |
| + aclFinalize(); |
| + return 0; |
| +} |