CANN/ops-nn动态量化RMS归一化融合算子
aclnnAddRmsNormDynamicQuantV2【免费下载链接】ops-nn本项目是CANN提供的神经网络类计算算子库实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-nn 查看源码产品支持情况产品是否支持Ascend 950PR/Ascend 950DT√Atlas A3 训练系列产品/Atlas A3 推理系列产品√Atlas A2 训练系列产品/Atlas A2 推理系列产品√Atlas 200I/500 A2 推理产品×Atlas 推理系列产品×Atlas 训练系列产品×功能说明接口功能RmsNorm算子是大模型常用的归一化操作相比LayerNorm算子其去掉了减去均值的部分。DynamicQuant算子则是为输入张量进行对称动态量化的算子。AddRmsNormDynamicQuant算子将RmsNorm前的Add算子和RmsNorm归一化输出给到的1个或2个DynamicQuant算子融合起来减少搬入搬出操作。aclnnAddRmsNormDynamicQuantV2相较于aclnnAddRmsNormDynamicQuant在RmsNorm计算过程中增加了偏置项betaOptional参数即计算公式中的beta以及新增输出配置项outputMaskOptional参数用于配置是否输出对应位置的量化结果。计算公式$$ xx_{1}x_{2} $$$$ y \operatorname{RmsNorm}(x)\frac{x}{\operatorname{Rms}(\mathbf{x})}\cdot gammabeta, \quad \text { where } \operatorname{Rms}(\mathbf{x})\sqrt{\frac{1}{n} \sum_{i1}^n x_i^2epsilon} $$$$ input1 \begin{cases} y\cdot smoothScale1Optional \ \ smoothScale1Optional \ y !\ smoothScale1Optional \end{cases} $$$$ input2 \begin{cases} y\cdot smoothScale2Optional \ \ smoothScale2Optional \ y !\ smoothScale2Optional \end{cases} $$$$ scale1Out\begin{cases} row_max(abs(input1))/127 (outputMask[0]True\ ||\ !outputMask) y1Out为INT8 \ row_max(abs(input1))/7 (outputMask[0]True\ ||\ !outputMask) y1Out为INT4 \ 无效输出 outputMask[0]False \end{cases} $$$$ y1Out\begin{cases} round(input1/scale1Out) outputMask[0]True\ ||\ !outputMask \ 无效输出 outputMask[0]False \end{cases} $$$$ scale2Out\begin{cases} row_max(abs(input2))/127 (outputMask[1]True\ ||\ (!outputMask\ \ smoothScale1Optional\ \ smoothScale2Optional)) y2Out为INT8 \ row_max(abs(input2))/7 (outputMask[1]True\ ||\ (!outputMask\ \ smoothScale1Optional\ \ smoothScale2Optional)) y2Out为INT4 \ 无效输出 outputMask[1]False\ ||\ (!outputMask\ \ (!smoothScale1Optional\ ||\ !smoothScale2Optional)) \end{cases} $$$$ y2Out\begin{cases} round(input2/scale2Out) outputMask[1]True\ ||\ (!outputMask\ \ smoothScale1Optional\ \ smoothScale2Optional)\ 无效输出 outputMask[1]False\ ||\ (!outputMask\ \ (!smoothScale1Optional\ ||\ !smoothScale2Optional)) \end{cases} $$公式中的row_max代表每行求最大值。函数原型每个算子分为两段式接口必须先调用aclnnAddRmsNormDynamicQuantV2GetWorkspaceSize接口获取入参并根据计算流程所需workspace大小再调用aclnnAddRmsNormDynamicQuantV2接口执行计算。aclnnStatus aclnnAddRmsNormDynamicQuantV2GetWorkspaceSize( const aclTensor *x1, const aclTensor *x2, const aclTensor *gamma, const aclTensor *smoothScale1Optional, const aclTensor *smoothScale2Optional, const aclTensor *betaOptional, double epsilon, const aclBoolArray *outputMaskOptional, aclTensor *y1Out, aclTensor *y2Out, aclTensor *xOut, aclTensor *scale1Out, aclTensor *scale2Out, uint64_t *workspaceSize, aclOpExecutor **executor)aclnnStatus aclnnAddRmsNormDynamicQuantV2( void *workspace, uint64_t workspaceSize, aclOpExecutor *executor, aclrtStream stream)aclnnAddRmsNormDynamicQuantV2GetWorkspaceSize参数说明参数名输入/输出描述使用说明数据类型数据格式维度(shape)非连续Tensorx1aclTensor*输入表示标准化过程中的源数据张量。对应公式中的x1。支持空Tensor。FLOAT16、BFLOAT16ND2-8√x2aclTensor*输入表示标准化过程中的源数据张量。对应公式中的x2。支持空Tensor。shape和数据类型需要与x1保持一致。FLOAT16、BFLOAT16ND2-8√gammaaclTensor*输入表示标准化过程中的权重张量。对应公式中的gamma。支持空Tensor。数据类型需要与x1保持一致。shape需要与x1最后一维一致。FLOAT16、BFLOAT16ND1√smoothScale1OptionalaclTensor*输入表示量化过程中得到y1Out使用的smoothScale张量。对应公式中的smoothScale1Optional。支持空Tensor。可选参数支持传入空指针。shape和数据类型需要与gamma保持一致。FLOAT16、BFLOAT16ND1√smoothScale2OptionalaclTensor*输入表示量化过程中得到y2Out使用的smoothScale张量。对应公式中的smoothScale2Optional。支持空Tensor。可选参数支持传入空指针。shape和数据类型需要与gamma保持一致。FLOAT16、BFLOAT16ND1√betaOptionalaclTensor*输入表示标准化过程中的偏置项。对应公式中的beta。支持空Tensor。可选参数支持传入空指针。shape和数据类型需要与gamma保持一致。FLOAT16、BFLOAT16ND1√epsilondouble输入表示用于防止除0错误对应公式中的epsilon。建议传入较小正数如1e-6。----outputMaskOptionalaclBoolArray*输入表示输出的掩码对应公式中的outputMask。支持传空指针或长度为2的数组。----y1OutaclTensor*输出表示量化输出Tensor对应公式中的y1Out。支持空Tensor。shape需要与输入x1保持一致。INT4、INT8、HIFLOAT8、FLOAT8_E5M2、FLOAT8_E4M3FNND2-8√y2OutaclTensor*输出表示量化输出Tensor对应公式中的y2Out。支持空Tensor。如果y2Out为有效输出时shape和数据类型需要与y1Out保持一致如果y2Out为无效输出时shape为[1]。INT4、INT8、HIFLOAT8、FLOAT8_E5M2、FLOAT8_E4M3FNND2-8√xOutaclTensor*输出表示x1和x2的和对应公式中的x。支持空Tensor。shape和数据类型需要与输入x1/x2一致。FLOAT16、BFLOAT16ND2-8√scale1OutaclTensor*输出表示第一路量化的输出对应公式中的scale1Out。支持空Tensor。shape需要与输入x1除了最后一维后的shape一致或者与x1除了最后一维的乘积一致。FLOAT32ND1-8√scale2OutaclTensor*输出表示第二路量化的输出对应公式中的scale2Out。支持空Tensor。当smoothScale2Optional不存在时此输出无意义。shape需要与scale1Out一致。FLOAT32ND1-8√workspaceSizeuint64_t*输出返回需要在Device侧申请的workspace大小。-----executoraclOpExecutor**输出返回op执行器包含了算子计算流程。-----返回值aclnnStatus返回状态码具体参见aclnn返回码。第一段接口完成入参校验出现以下场景时报错返回码错误码描述ACLNN_ERR_PARAM_NULLPTR161001如果传入参数是必选输入输出或者必选属性且是空指针则返回161001。ACLNN_ERR_PARAM_INVALID161002输入或输出的数据类型不在支持的范围之内。outputMaskOptional为空指针时输入smoothScale2Optional而没有输入smoothScale1Optional。aclnnAddRmsNormDynamicQuantV2参数说明参数名输入/输出描述workspace输入在Device侧申请的workspace内存地址。workspaceSize输入在Device侧申请的workspace大小由第一段接口aclnnAddRmsNormDynamicQuantV2GetWorkspaceSize获取。executor输入op执行器包含了算子计算流程。stream输入指定执行任务的Stream。返回值aclnnStatus返回状态码。具体参见aclnn返回码约束说明数据格式说明所有输入输出tensor的数据格式推荐使用ND格式其他数据格式会由框架默认转换成ND格式进行处理。当outputMaskOptional不为空时参数smoothScale1Optional有值时则outputMaskOptional[0]必须为True。参数smoothScale2Optional有值时则outputMaskOptional[1]必须为True。当outputMaskOptional不为空时outputMaskOptional[0]与outputMaskOptional[1]不能同时为False。当outputMaskOptional为空时参数smoothScale2Optional有值时参数smoothScale1Optional也必须有值。各产品型号支持数据类型说明Atlas A3 训练系列产品/Atlas A3 推理系列产品 、 Atlas A2 训练系列产品/Atlas A2 推理系列产品 参数y1Out和y2Out数据类型仅支持int4和int8。Ascend 950PR/Ascend 950DT 暂不支持可选属性output_mask的配置。参数y1Out和y2Out数据类型不支持int4。确定性计算aclnnAddRmsNormDynamicQuantV2默认确定性实现。调用示例示例代码如下仅供参考具体编译和执行过程请参考编译与运行样例。#include iostream #include vector #include acl/acl.h #include aclnnop/aclnn_add_rms_norm_dynamic_quant_v2.h #define CHECK_RET(cond, return_expr) \ do { \ if (!(cond)) { \ return_expr; \ } \ } while (0) #define LOG_PRINT(message, ...) \ do { \ printf(message, ##__VA_ARGS__); \ } while (0) int64_t GetShapeSize(const std::vectorint64_t shape) { int64_t shape_size 1; for (auto i : shape) { shape_size * i; } return shape_size; } int Init(int32_t deviceId, aclrtStream* stream) { // 固定写法资源初始化 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::vectorT hostData, const std::vectorint64_t shape, void** deviceAddr, aclDataType dataType, aclTensor** tensor) { auto size GetShapeSize(shape) * sizeof(T); // 调用aclrtMalloc申请device侧内存 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); // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上 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); // 计算连续tensor的strides std::vectorint64_t strides(shape.size(), 1); for (int64_t i shape.size() - 2; i 0; i--) { strides[i] shape[i 1] * strides[i 1]; } // 调用aclCreateTensor接口创建aclTensor *tensor aclCreateTensor( shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(), *deviceAddr); return 0; } int main() { // 1. 固定写法device/stream初始化参考acl API手册 // 根据自己的实际device填写deviceId int32_t deviceId 0; aclrtStream stream; auto ret Init(deviceId, stream); // check根据自己的需要处理 CHECK_RET(ret 0, LOG_PRINT(Init acl failed. ERROR: %d\n, ret); return ret); // 2. 构造输入与输出需要根据API的接口自定义构造 std::vectorint64_t xShape {2, 8}; std::vectorint64_t gammaShape {8}; std::vectorint64_t betaShape {8}; std::vectorint64_t reduceShape {2, 1}; void* x1DeviceAddr nullptr; void* x2DeviceAddr nullptr; void* gammaDeviceAddr nullptr; void* betaDeviceAddr nullptr; void* smooth1DeviceAddr nullptr; void* smooth2DeviceAddr nullptr; void* y1DeviceAddr nullptr; void* y2DeviceAddr nullptr; void* xDeviceAddr nullptr; void* scale1DeviceAddr nullptr; void* scale2DeviceAddr nullptr; aclTensor* x1 nullptr; aclTensor* x2 nullptr; aclTensor* gamma nullptr; aclTensor* beta nullptr; aclTensor* smooth1 nullptr; aclTensor* smooth2 nullptr; aclTensor* y1 nullptr; aclTensor* y2 nullptr; aclTensor* x nullptr; aclTensor* scale1 nullptr; aclTensor* scale2 nullptr; int64_t xShapeSize GetShapeSize(xShape); int64_t gammaShapeSize GetShapeSize(gammaShape); int64_t betaShapeSize GetShapeSize(betaShape); int64_t reduceShapeSize GetShapeSize(reduceShape); std::vectorshort x1HostData(xShapeSize, 0x3800); std::vectorshort x2HostData(xShapeSize, 0x3800); std::vectorshort gammaHostData(gammaShapeSize, 0x3e00); std::vectorshort betaHostData(betaShapeSize, 0x3e00); std::vectorshort smooth1HostData(gammaShapeSize, 0x3e00); std::vectorshort smooth2HostData(gammaShapeSize, 0x3e00); std::vectorshort y1HostData(xShapeSize, 0); std::vectorshort y2HostData(xShapeSize, 0); std::vectorshort xHostData(xShapeSize, 0); std::vectorshort scale1HostData(reduceShapeSize, 0); std::vectorshort scale2HostData(reduceShapeSize, 0); float epsilon 1e-6; // 创建x1 aclTensor ret CreateAclTensor(x1HostData, xShape, x1DeviceAddr, aclDataType::ACL_FLOAT16, x1); CHECK_RET(ret ACL_SUCCESS, return ret); // 创建x2 aclTensor ret CreateAclTensor(x2HostData, xShape, x2DeviceAddr, aclDataType::ACL_FLOAT16, x2); CHECK_RET(ret ACL_SUCCESS, return ret); // 创建gamma aclTensor ret CreateAclTensor(gammaHostData, gammaShape, gammaDeviceAddr, aclDataType::ACL_FLOAT16, gamma); CHECK_RET(ret ACL_SUCCESS, return ret); // 创建beta aclTensor ret CreateAclTensor(betaHostData, betaShape, betaDeviceAddr, aclDataType::ACL_FLOAT16, beta); CHECK_RET(ret ACL_SUCCESS, return ret); // 创建 smooth1 aclTensor ret CreateAclTensor(smooth1HostData, gammaShape, smooth1DeviceAddr, aclDataType::ACL_FLOAT16, smooth1); CHECK_RET(ret ACL_SUCCESS, return ret); // 创建 smooth2 aclTensor ret CreateAclTensor(smooth2HostData, gammaShape, smooth2DeviceAddr, aclDataType::ACL_FLOAT16, smooth2); CHECK_RET(ret ACL_SUCCESS, return ret); // 创建y1 aclTensor ret CreateAclTensor(y1HostData, xShape, y1DeviceAddr, aclDataType::ACL_INT8, y1); CHECK_RET(ret ACL_SUCCESS, return ret); // 创建y2 aclTensor ret CreateAclTensor(y2HostData, xShape, y2DeviceAddr, aclDataType::ACL_INT8, y2); CHECK_RET(ret ACL_SUCCESS, return ret); // 创建x aclTensor ret CreateAclTensor(xHostData, xShape, xDeviceAddr, aclDataType::ACL_FLOAT16, x); CHECK_RET(ret ACL_SUCCESS, return ret); // 创建outScale1 aclTensor ret CreateAclTensor(scale1HostData, reduceShape, scale1DeviceAddr, aclDataType::ACL_FLOAT, scale1); CHECK_RET(ret ACL_SUCCESS, return ret); // 创建outScale1 aclTensor ret CreateAclTensor(scale2HostData, reduceShape, scale2DeviceAddr, aclDataType::ACL_FLOAT, scale2); CHECK_RET(ret ACL_SUCCESS, return ret); // 3. 调用CANN算子库API需要修改为具体的API uint64_t workspaceSize 0; aclOpExecutor* executor; // 调用aclnnAddRmsNormDynamicQuantV2第一段接口 ret aclnnAddRmsNormDynamicQuantV2GetWorkspaceSize( x1, x2, gamma, smooth1, smooth2, beta, epsilon, nullptr, y1, y2, x, scale1, scale2, workspaceSize, executor); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclnnAddRmsNormDynamicQuantV2GetWorkspaceSize failed. ERROR: %d\n, ret); return ret); // 根据第一段接口计算出的workspaceSize申请device内存 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;); } // 调用aclnnAddRmsNormDynamicQuantV2第二段接口 ret aclnnAddRmsNormDynamicQuantV2(workspaceAddr, workspaceSize, executor, stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclnnAddRmsNormDynamicQuantV2 failed. ERROR: %d\n, ret); return ret); // 4. 固定写法同步等待任务执行结束 ret aclrtSynchronizeStream(stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclrtSynchronizeStream failed. ERROR: %d\n, ret); return ret); // 5. 获取输出的值将device侧内存上的结果拷贝至host侧需要根据具体API的接口定义修改 auto size GetShapeSize(xShape); std::vectorint8_t y1Ret(size, 0); ret aclrtMemcpy( y1Ret.data(), y1Ret.size() * sizeof(y1Ret[0]), y1DeviceAddr, size * sizeof(int8_t), ACL_MEMCPY_DEVICE_TO_HOST); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(copy result from device to host failed. ERROR: %d\n, ret); return ret); for (int64_t i 0; i size; i) { LOG_PRINT(result[%ld] is: %d\n, i, y1Ret[i]); } // 6. 释放aclTensor和aclScalar需要根据具体API的接口定义修改 aclDestroyTensor(x1); aclDestroyTensor(x2); aclDestroyTensor(gamma); aclDestroyTensor(beta); aclDestroyTensor(smooth1); aclDestroyTensor(smooth2); aclDestroyTensor(y1); aclDestroyTensor(y2); aclDestroyTensor(x); aclDestroyTensor(scale1); aclDestroyTensor(scale2); // 7. 释放device资源需要根据具体API的接口定义修改 aclrtFree(x1DeviceAddr); aclrtFree(x2DeviceAddr); aclrtFree(gammaDeviceAddr); aclrtFree(betaDeviceAddr); aclrtFree(smooth1DeviceAddr); aclrtFree(smooth2DeviceAddr); aclrtFree(y1DeviceAddr); aclrtFree(y2DeviceAddr); aclrtFree(xDeviceAddr); aclrtFree(scale1DeviceAddr); aclrtFree(scale2DeviceAddr); if (workspaceSize 0) { aclrtFree(workspaceAddr); } aclrtDestroyStream(stream); aclrtResetDevice(deviceId); aclFinalize(); return 0; }【免费下载链接】ops-nn本项目是CANN提供的神经网络类计算算子库实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-nn创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2602342.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!