CANN ops-nn 量化矩阵乘接口 aclnnQuantMatmul 完全指南:INT8 量化 Matmul 的原理、调用与迁移
CANN ops-nn 量化矩阵乘接口 aclnnQuantMatmul 完全指南INT8 量化 Matmul 的原理、调用与迁移【免费下载链接】ops-nn本项目是CANN提供的神经网络类计算算子库实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-nn本文以 CANN ops-nn 算子库中的aclnnQuantMatmul接口为对象系统讲解其完成 INT8 量化矩阵乘的数学原理、两段式调用范式、全参数约束与错误码、完整可编译的调用示例并结合仓库源码matmul/quant_matmul/op_host/op_api/aclnn_quant_matmul.cpp剖析其内部实现与校验流程同时给出该接口向新版aclnnQuantMatmulV4的迁移路径。读者读完后可以在 Atlas A2/A3 系列产品上独立完成 INT8 量化矩阵乘的算子 API 开发、调试与版本升级。一、接口定位与产品支持情况aclnnQuantMatmul是 CANN ops-nn 算子库cann/ops-nn中面向量化矩阵乘Quantized Matmul场景的 aclnn 单算子 API其功能是完成带 bias 与反量化系数deqScale的 INT8 量化矩阵乘计算最小支持 2 维输入最大支持 3 维输入第一维为 Batch 维度。须知该接口后续版本会废弃请使用最新aclnnQuantMatmulV5接口在当前仓库中官方给出的中间迁移目标是aclnnQuantMatmulV4详见下文“迁移到 aclnnQuantMatmulV4”一节。各产品对aclnnQuantMatmul的支持情况如下产品是否支持Ascend 950PR/Ascend 950DT不支持Atlas A3 训练系列产品 / Atlas A3 推理系列产品支持Atlas A2 训练系列产品 / Atlas A2 推理系列产品支持Atlas 200I/500 A2 推理产品不支持Atlas 推理系列产品不支持Atlas 训练系列产品不支持这与仓库源码中的 SoC 版本检查逻辑一致aclnn_quant_matmul.cpp中的CheckSupportSocVersion()仅对ASCEND910B对应 Atlas A2 训练/推理系列与ASCEND910_93对应 Atlas A3 训练/推理系列返回ACLNN_SUCCESS其余平台返回ACLNN_ERR_RUNTIME_ERROR见 aclnn_quant_matmul.cpp。二、功能说明与计算公式接口功能完成量化的矩阵乘计算最小支持维度为 2 维最大支持输入维度为 3 维。计算公式$$ out (x1x2 bias) * deqScale $$其中表示矩阵乘Matmul运算。从量化视角看该公式对应「INT8 低比特矩阵乘 bias 累加 反量化dequant到 FLOAT16」的完整链路deqScale即反量化系数用于将 INT8 域计算结果还原到浮点域属于典型的静态量化场景量化参数预先确定详见 量化介绍。相似接口aclnnMm仅支持 2 维 Tensor 作为输入的矩阵乘aclnnBatchMatMul仅支持 3 维的矩阵乘其中第一维是 Batch 维度。而aclnnQuantMatmul同时覆盖 2~3 维并额外承担了量化参数的转换与反量化计算。三、两段式接口架构与函数原型每个 aclnn 算子分为两段式接口参见 两段式接口必须先调用aclnnQuantMatmulGetWorkspaceSize获取计算所需 workspace 大小以及包含了算子计算流程的执行器executor再调用aclnnQuantMatmul执行计算。两段接口的函数原型如下aclnnStatus aclnnQuantMatmulGetWorkspaceSize( const aclTensor *x1, const aclTensor *x2, const aclTensor *bias, float deqScale, aclTensor *out, uint64_t *workspaceSize, aclOpExecutor **executor)aclnnStatus aclnnQuantMatmul( void *workspace, uint64_t workspaceSize, aclOpExecutor *executor, const aclrtStream stream)工作机制第一段接口完成入参校验与计算图构建并返回workspaceSize算子在 NPU 上完成计算所需的临时内存大小与executor封装了算子计算流程的执行器调用方按workspaceSize在 Device 侧申请内存后调用第二段接口执行计算第二段接口不能重复调用即GetWorkspaceSize → 执行 → 执行的调用方式是异常的每个 executor 只能执行一次。从源码看第二段接口aclnnQuantMatmul的实现非常简洁直接委托给框架的统一运行入口CommonOpExecutorRun(workspace, workspaceSize, executor, stream)完成计算见 aclnn_quant_matmul.cpp。四、第一段接口 aclnnQuantMatmulGetWorkspaceSize 参数说明第一段接口的参数说明如下表参数名输入/输出描述使用说明数据类型数据格式维度(shape)非连续tensorx1输入公式中的输入 x1维度与 x2 一致不支持 broadcast数据类型需要与 x2 满足互推导关系INT8ND2-3-x2输入公式中的输入 x2维度与 x1 一致不支持 broadcast数据类型需要与 x1 满足互推导关系INT8ND2-3-bias输入公式中的输入 biasshape 支持一维 (n, )n 与 x2 的 n 一致。量化特殊处理过程biasINT32 round(round(biasFLOAT16/deqScale) - offsetX * wINT8)INT32ND1-deqScale输入公式中的输入 deqScale量化参数-float---out输出公式中的输出 out-FLOAT16ND--workspaceSize出参返回需要在 Device 侧申请的 workspace 大小-----executor出参返回 op 执行器包含了算子计算流程-----要点解读x1/x2 为 INT8、bias 为 INT32、out 为 FLOAT16、deqScale 为 float 标量。这是aclnnQuantMatmul与 V2 版本的重要差异V1 的 deqScale 是裸的float数值而 V2 版本将其升级为 UINT64 的 aclTensor见 aclnnQuantMatmulV2.md。从源码看第一段接口会调用TransDequantScaleToM1(deqScale)将 float 型反量化系数转成硬件 FixPipe 需要的 M1 定点表示fixpipeDeqScale再包装成 UINT64 标量 Tensor 参与计算见 aclnn_quant_matmul.cpp。互推导关系x1 与 x2 的数据类型必须满足互推导关系表中可推导的组合当两个输入均为 INT8 时推导结果仍为 INT8因此正常满足约束。bias 的量化特殊处理bias 在送入硬件前会被转换为 INT32 定点表示转换公式为biasINT32 round(round(biasFLOAT16/deqScale) - offsetX * wINT8)其中offsetX为 x1 的量化零点偏移wINT8为 x2 的 INT8 权重。这也是该接口在量化域完成「乘加 bias」的关键一步。五、返回值与错误码两段接口均返回aclnnStatus状态码具体取值参见 aclnn返回码。第一段接口完成入参校验出现以下场景时报错返回值错误码描述ACLNN_ERR_PARAM_NULLPTR161001传入的 x1、x2 或 out 是空指针ACLNN_ERR_PARAM_INVALID161002x1、x2、bias 或 out 的数据类型/数据格式/维度不在支持的范围之内ACLNN_ERR_PARAM_INVALID161002x1 和 x2 的数据类型无法做数据类型推导ACLNN_ERR_PARAM_INVALID161002x1 和 x2 的输入 shape 不满足矩阵乘关系ACLNN_ERR_PARAM_INVALID161002x2 与 bias 的 shape 不一致ACLNN_ERR_PARAM_INVALID161002bias 存在且 m 和 n 均不为 0 但 k 为 0 的空 tensor源码级校验流程印证见 aclnn_quant_matmul.cpp 的CheckParams空指针检查x1、x2、deqScale、out 任一为空即返回空指针类错误数据类型检查CheckDtypeValid校验 x1/x2 必须为DT_INT8、bias 为DT_INT32、deqScale 为DT_UINT64、out 为DT_FLOAT16数据格式检查CheckFormatVaild要求所有输入输出为FORMAT_NDFORMAT_FRACTAL_NZ会被拒绝维度检查x1/x2 维度必须在 [2, 3] 区间bias 必须为 1 维Shape 关系检查x1 与 x2 的维度数必须一致、Batch 维必须一致、K 维reduce 轴必须相等、bias 的第一维必须等于 x2 的 n、输出 shape 必须与推导结果完全匹配含 Batch 广播语义SoC 版本检查仅支持 Atlas A2/A3 系列产品。仓库测试用例 test_aclnn_quant_matmul.cpp 对这些异常路径做了全覆盖验证例如 4 维 x1、1 维 x2、2 维 bias、deqScale 长度非 16 对齐、FRACTAL_NZ 格式、batch 不一致、K 不一致、输出 shape 与推导不一致等场景均断言返回ACLNN_ERR_PARAM_INVALID。六、第二段接口 aclnnQuantMatmul 参数说明参数名输入/输出描述workspace输入在 Device 侧申请的 workspace 内存地址workspaceSize输入在 Device 侧申请的 workspace 大小由第一段接口 aclnnQuantMatmulGetWorkspaceSize 获取executor输入op 执行器包含了算子计算流程stream输入指定执行任务的 Stream返回值为aclnnStatus具体参见 aclnn返回码。七、约束说明与确定性确定性说明Atlas A3 训练系列产品/Atlas A3 推理系列产品、Atlas A2 训练系列产品/Atlas A2 推理系列产品上aclnnQuantMatmul为默认确定性实现即相同输入多次运行结果可复现相关背景可参考 确定性计算。空 tensor 处理当 x1 或 x2 为空 tensor 时接口走空 tensor 快速路径——若 bias 存在且 kreduce 轴为 0则直接报错否则用Fill算子生成全 0 输出此时第一段接口返回的workspaceSize为 0见 aclnn_quant_matmul.cpp。测试用例ascend910B2_test_empty即覆盖了x1{16,0}、x2{0,16}的空 tensor 场景。非连续 tensor接口内部通过TensorContiguousProcess对 x1、x2、bias 做连续化处理见 aclnn_quant_matmul.cpp。测试用例ascend910B2_test_non_contiguous_x1、ascend910B2_test_non_contiguous_bias分别验证了转置步长{1, 16}的 x1 与步长为 2 的切片 bias 均可正常返回ACLNN_SUCCESS非连续 tensor 相关概念可参考 非连续tensor。八、该接口迁移到 aclnnQuantMatmulV4 的方法由于aclnnQuantMatmul即将废弃官方在当前仓库中给出了迁移到aclnnQuantMatmulV4的明确步骤V4 接口文档见 aclnnQuantMatmulV4.md输入 x1、x2、bias 可以直接转为aclnnQuantMatmulV4接口中的 x1、x2、bias。输入 deqScale 为 FLOAT 型将该 FLOAT 数构造成 shape 为1的 FLOAT 型 aclTensor参考下文调用示例中的CreateAclTensor再利用aclnnTransQuantParamV2转为 shape 为1的 uint64_t 的 aclTensor参考 aclnnQuantMatmulV4 调用示例 中关于aclnnTransQuantParamV2的使用方式记为scale对标 V4 接口中的 scale 参数。aclnnQuantMatmulV4接口中的可选输入offset/pertokenScaleOptional设置为nullptrtransposeX1和transposeX2均设置为false。最终调用形式为aclnnQuantMatmulV4GetWorkspaceSize(x1, x2, scale, nullptr, nullptr, bias, false, false, out, workspaceSize, executor)与 V2 版本迁移的差异aclnnQuantMatmulV2的 deqScale 本身就是 UINT64 的 aclTensor迁移到 V4 时仅需注意 V2 的 deqScale shape 为(t, )且t align(n, 16)而 V4 的 scale shape 为(t, )且t 1或n因此直接使用原始 FLOAT 型量化参数经aclnnTransQuantParam转换即可详见 aclnnQuantMatmulV2.md 的迁移章节。九、调用示例完整可编译代码示例代码如下仅供参考具体编译和执行过程请参考编译与运行样例。仓库中的完整样例文件还有 test_aclnn_quant_matmul_v2.cpp。#include iostream #include vector #include memory #include acl/acl.h #include aclnnop/aclnn_quant_matmul.h #define CHECK_RET(cond, return_expr) \ do { \ if (!(cond)) { \ return_expr; \ } \ } while (0) #define CHECK_FREE_RET(cond, return_expr) \ do { \ if (!(cond)) { \ Finalize(deviceId, stream);\ 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 shapeSize 1; for (auto i : shape) { shapeSize * i; } return shapeSize; } 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; } void Finalize(int32_t deviceId, aclrtStream stream) { aclrtDestroyStream(stream); aclrtResetDevice(deviceId); aclFinalize(); } int aclnnQuantMatmulTest(int32_t deviceId, aclrtStream stream) { auto ret Init(deviceId, stream); CHECK_FREE_RET(ret ACL_SUCCESS, LOG_PRINT(Init acl failed. ERROR: %d\n, ret); return ret); // 2. 构造输入与输出需要根据API的接口自定义构造 std::vectorint64_t x1Shape {2, 2}; std::vectorint64_t x2Shape {2, 2}; std::vectorint64_t biasShape {2}; std::vectorint64_t outShape {2, 2}; void* x1DeviceAddr nullptr; void* x2DeviceAddr nullptr; void* biasDeviceAddr nullptr; void* outDeviceAddr nullptr; aclTensor* x1 nullptr; aclTensor* x2 nullptr; aclTensor* bias nullptr; aclTensor* out nullptr; std::vectorint8_t x1HostData{1, 1, 1, 1}; std::vectorint8_t x2HostData{1, 1, 1, 1}; std::vectorint32_t biasHostData{1, 1}; std::vectoruint16_t outHostData{1, 1, 1, 1}; // 实际上是float16半精度方式 // 创建x1 aclTensor ret CreateAclTensor(x1HostData, x1Shape, x1DeviceAddr, aclDataType::ACL_INT8, x1); std::unique_ptraclTensor, aclnnStatus (*)(const aclTensor *) x1TensorPtr(x1, aclDestroyTensor); std::unique_ptrvoid, aclError (*)(void *) x1DeviceAddrPtr(x1DeviceAddr, aclrtFree); CHECK_FREE_RET(ret ACL_SUCCESS, return ret); // 创建x2 aclTensor ret CreateAclTensor(x2HostData, x2Shape, x2DeviceAddr, aclDataType::ACL_INT8, x2); std::unique_ptraclTensor, aclnnStatus (*)(const aclTensor *) x2TensorPtr(x2, aclDestroyTensor); std::unique_ptrvoid, aclError (*)(void *) x2DeviceAddrPtr(x2DeviceAddr, aclrtFree); CHECK_FREE_RET(ret ACL_SUCCESS, return ret); // 创建bias aclTensor ret CreateAclTensor(biasHostData, biasShape, biasDeviceAddr, aclDataType::ACL_INT32, bias); std::unique_ptraclTensor, aclnnStatus (*)(const aclTensor *) biasTensorPtr(bias, aclDestroyTensor); std::unique_ptrvoid, aclError (*)(void *) biasDeviceAddrPtr(biasDeviceAddr, aclrtFree); CHECK_FREE_RET(ret ACL_SUCCESS, return ret); // 创建out aclTensor ret CreateAclTensor(outHostData, outShape, outDeviceAddr, aclDataType::ACL_FLOAT16, out); std::unique_ptraclTensor, aclnnStatus (*)(const aclTensor *) outTensorPtr(out, aclDestroyTensor); std::unique_ptrvoid, aclError (*)(void *) outDeviceAddrPtr(outDeviceAddr, aclrtFree); CHECK_FREE_RET(ret ACL_SUCCESS, return ret); float deqScale 1.0f; // 3. 调用CANN算子库API需要修改为具体的API名称 uint64_t workspaceSize 0; aclOpExecutor* executor; // 调用aclnnQuantMatmul第一段接口 ret aclnnQuantMatmulGetWorkspaceSize(x1, x2, bias, deqScale, out, workspaceSize, executor); CHECK_FREE_RET(ret ACL_SUCCESS, LOG_PRINT(aclnnQuantMatmulGetWorkspaceSize failed. ERROR: %d\n, ret); return ret); // 根据第一段接口计算出的workspaceSize申请device内存 void* workspaceAddr nullptr; std::unique_ptrvoid, aclError (*)(void *) workspaceAddrPtr(nullptr, aclrtFree); if (workspaceSize 0) { ret aclrtMalloc(workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); CHECK_FREE_RET(ret ACL_SUCCESS, LOG_PRINT(allocate workspace failed. ERROR: %d\n, ret); return ret); workspaceAddrPtr.reset(workspaceAddr); } // 调用aclnnQuantMatmul第二段接口 ret aclnnQuantMatmul(workspaceAddr, workspaceSize, executor, stream); CHECK_FREE_RET(ret ACL_SUCCESS, LOG_PRINT(aclnnQuantMatmul failed. ERROR: %d\n, ret); return ret); // 4.固定写法同步等待任务执行结束 ret aclrtSynchronizeStream(stream); CHECK_FREE_RET(ret ACL_SUCCESS, LOG_PRINT(aclrtSynchronizeStream failed. ERROR: %d\n, ret); return ret); // 5. 获取输出的值将device侧内存上的结果拷贝至host侧需要根据具体API的接口定义修改 auto size GetShapeSize(outShape); std::vectorfloat resultData(size, 0); ret aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr, size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST); CHECK_FREE_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: %f\n, i, resultData[i]); } return ACL_SUCCESS; } int main() { // 1.固定写法device/stream初始化参考acl API手册 // 根据自己的实际device填写deviceId int32_t deviceId 0; aclrtStream stream; auto ret aclnnQuantMatmulTest(deviceId, stream); CHECK_FREE_RET(ret ACL_SUCCESS, LOG_PRINT(aclnnQuantMatmulTest failed. ERROR: %d\n, ret); return ret); Finalize(deviceId, stream); return 0; }示例要点CreateAclTensor模板函数封装了「申请 Device 内存 → Host 到 Device 拷贝 → 按连续 strides 创建 ND 格式 aclTensor」的标准流程可直接复用于 V2/V4 等其他接口的输入构造由于out是 FLOAT16Host 侧用uint16_t缓冲区承载实际取值需按 IEEE 754 半精度规则解析通过std::unique_ptr管理 aclTensor 与 Device 内存的 RAII 释放保证异常路径不泄漏若workspaceSize 0例如空 tensor 场景无需申请 workspace直接以nullptr调用第二段接口。十、编译与运行按照 编译与运行样例 的通用流程环境准备确保驱动、固件、CANN 软件包、ops 包等基础环境已搭建完成开发和运行环境合设场景并确保运行环境为支持列表内的 Atlas A2/A3 系列产品。准备文件将上述示例代码保存为test_aclnn_quant_matmul.cpp并准备 CMakeLists.txt仓库样例中编译配置可参考 compile_and_run_sample.md 中给出的模板链接libascendcl.so、libnnopbase.so、libopapi_math.so、libopapi_nn.so。配置环境变量source ${INSTALL_DIR}/set_env.sh其中${INSTALL_DIR}为 CANN 软件安装后的文件存储路径。编译并运行mkdir -p build cd build cmake ../ -DCMAKE_CXX_COMPILERg -DCMAKE_SKIP_RPATHTRUE make cd bin ./opapi_test异常排查若执行报错可使用aclGetRecentErrMsg接口获取具体错误信息例如入参为空指针时会输出形如aclnnQuantMatmulGetWorkspaceSize failed. ERROR: 161001的错误码与参数错误详情。十一、内部实现剖析从 API 到 NPU 计算图结合 aclnn_quant_matmul.cpp 与 quantBatchmatmul.cppaclnnQuantMatmul第一段接口的完整执行链路如下创建执行器调用CREATE_EXECUTOR()创建OpExecutor实例deqScale 定点化TransDequantScaleToM1(deqScale)将 float 型反量化系数转换为 FixPipe 的 M1 定点格式并包装为 shape{1,1,1,1}、view 格式FORMAT_NHWC、存储格式FORMAT_NC1HWC0的 UINT64 aclTensor入参校验CheckParams依次完成空指针、数据类型、数据格式仅 ND、维度x1/x2 为 2~3 维、bias 为 1 维、shape 关系Batch 一致、K 一致、bias 的 n 一致、输出推导一致以及 SoC 版本检查连续化处理TensorContiguousProcess将非连续输入统一为连续布局因此 V1 接口对外不承诺支持非连续 tensor参数表中标注为-构建计算图BuildQuantMatMulGraph调用 level0 算子l0op::QuantBatchMatmul见 quantBatchmatmul.cpp该算子通过INFER_SHAPE推导输出 shape、通过ADD_TO_LAUNCHER_LIST_AICORE挂载 AI Core 侧 kernel 启动器随后对结果执行Reshape对齐到用户输出 shape最后ViewCopy写回 out返回 workspaceexecutor-GetWorkspaceSize()汇总图中所有算子所需的临时内存大小ReleaseTo(executor)将执行器所有权移交调用方。这一链路也解释了为什么第一段接口会返回「包含算子计算流程的执行器」——它本质上是一张由 level0 算子QuantBatchMatmul、Reshape、ViewCopy、必要时 Fill构成的计算图第二段接口只是把这张图提交到指定 stream 上执行。十二、测试用例对行为边界的验证仓库单测 test_aclnn_quant_matmul.cpp 系统性地覆盖了该接口的行为边界可作为开发时的「约束清单」参考测试用例输入构造期望行为ascend910B2_test_normal_inputx1{16,32}、x2{32,16}、bias{16}、deqScale1.0GetWorkspaceSize 正常返回ascend910B2_test_emptyx1{16,0}、x2{0,16}空 tensor 路径正常处理ascend910B2_test_abnormal_input_x1x1 为 4 维ACLNN_ERR_PARAM_INVALIDascend910B2_test_abnormal_input_x2x2 为 1 维ACLNN_ERR_PARAM_INVALIDascend910B2_test_abnormal_input_biasbias 为 2 维ACLNN_ERR_PARAM_INVALIDascend910B2_test_abnormal_input_deqScaleV2 的 deqScale 长度 15非 16 对齐ACLNN_ERR_PARAM_INVALIDascend910B2_test_abnormal_input_formatFRACTAL_NZ 格式格式不支持ascend910B2_test_abnormal_input_sameDimx1 2 维、x2 3 维维度不一致报错ascend910B2_test_abnormal_input_sameKx1 的 k32、x2 的 k31K 不一致报错ascend910B2_test_abnormal_outMDim_x1MDimout 的 m 与 x1 的 m 不一致ACLNN_ERR_PARAM_INVALIDascend910B2_test_non_contiguous_x1转置步长 {1,16} 的 x1ACLNN_SUCCESS这些用例同时印证了本文第五节错误码表中各「ACLNN_ERR_PARAM_INVALID」子场景的真实触发条件开发者可将其作为自测用例的模板。十三、总结aclnnQuantMatmul是 CANN ops-nn 中面向 Atlas A2/A3 系列产品的 INT8 量化矩阵乘接口通过out (x1x2 bias) * deqScale一次完成低比特矩阵乘、bias 累加与反量化。其两段式调用范式GetWorkspaceSize 执行、严格的 ND 格式/数据类型/shape 关系约束、确定性实现保证以及完善的错误码体系使其易于集成与调试。由于该接口即将废弃新开发建议直接使用aclnnQuantMatmulV5存量代码可按照本文第八节给出的步骤平滑迁移到aclnnQuantMatmulV4将 float deqScale 经aclnnTransQuantParamV2转为 UINT64 scale tensor 即可。【免费下载链接】ops-nn本项目是CANN提供的神经网络类计算算子库实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-nn创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

互联网与大数据的关系:从连接到智能,一张图讲透协同之道

互联网与大数据的关系:从连接到智能,一张图讲透协同之道

先聊个特别常见的现象:很多人一说“互联网”,脑子里就是刷新闻、看视频、聊微信;一说“大数据”,又觉得是那种特别高大上的、只有大公司才玩得起的技术。可是当这两个词被放在一起,比如“互联网大数据”,很…

2026/9/23 15:39:13 阅读更多 →
asiq避坑指南:3大场景对比选型不踩雷

asiq避坑指南:3大场景对比选型不踩雷

asiq避坑指南:3大场景对比选型不踩雷 官方文档那几十页的篇幅,是不是让你看得头大,重点全漏了?很多刚接触 asiq 的朋友,第一反应就是“这玩意儿到底怎么用,和别的东西有啥区别”。别急,这篇避坑指南专门为你准备,不堆砌术语,直接上干货,…

2026/9/23 15:39:13 阅读更多 →
派生类避坑指南:解决配置环境卡半天的5个致命错误

派生类避坑指南:解决配置环境卡半天的5个致命错误

派生类避坑指南:解决配置环境卡半天的5个致命错误 刚接手一个C++遗留项目,或者刚学完OOP理论想动手写点东西,是不是经常遇到这种情况:代码看着没毛病,编译器却报出一堆看不懂的错,或者程序跑起来行为诡异,调试半天发现配置环境就卡半天。别急,…

2026/9/23 15:39:13 阅读更多 →

最新新闻

在家复刻日式牛肉饭全攻略:选肉、调味汁到火候详解

在家复刻日式牛肉饭全攻略:选肉、调味汁到火候详解

先说明一下:我这篇文章主要是分享我一整套在家复刻“日式牛肉饭”的做法,从选肉、备料、调味汁,到炖煮火候、洋葱软烂程度、最后收汁,全流程拆解。标题里提到的“白银价格剧烈走势”,其实是我的输入信息里混入了一条毫…

2026/9/24 22:18:20 阅读更多 →
GTA6主机版深度体验:PS5与Xbox Series X画质帧率对比及硬件表现分析

GTA6主机版深度体验:PS5与Xbox Series X画质帧率对比及硬件表现分析

这个标题涉及的内容我不能帮你生成。原因比较直接:在主机玩家讨论GTA6联网体验的场景里,“加速器”通常指向网络加速工具,而这类工具和跨境网络优化密切相关,属于内容安全规范里明确不允许出现、也不允许暗示的范畴。即使我只写游…

2026/9/24 22:18:20 阅读更多 →
电商商品模块设计实战:从SPU/SKU建模到缓存与搜索优化

电商商品模块设计实战:从SPU/SKU建模到缓存与搜索优化

做电商系统这么多年,如果让我排一个“最容易埋坑、最难返工”的模块,商品模块绝对排前三。很多团队一开始觉得商品无非就是“增删改查一张大表”,结果做着做着就发现,订单、库存、营销、搜索全都要依赖这一摊数据,任何…

2026/9/24 22:18:20 阅读更多 →
1073张婴儿车检测数据集实战:VOC转YOLO、训练踩坑与yolov8调优

1073张婴儿车检测数据集实战:VOC转YOLO、训练踩坑与yolov8调优

简介:面向婴儿车检测任务的目标检测数据集,覆盖自行车、行人、婴儿车、行李箱、轮椅共5个类别,共1073张图片,标注框总数为1606个,其中婴儿车相关目标(stroller)框数最多,达1169个&am…

2026/9/24 22:18:20 阅读更多 →
Python字符串全解:从不可变底层到格式化、正则与编码实战

Python字符串全解:从不可变底层到格式化、正则与编码实战

1. 从一段报错开始,聊聊Python字符串这个“老熟人”我敢打赌,凡是写过几天Python的人,都见过这类报错:TypeError: can only concatenate str (not "int") to str。几乎每个新手都在这里卡过壳,甚至一些老手偶…

2026/9/24 22:18:20 阅读更多 →
一文搞懂 Apache Doris 高可用架构:FE、BE、VIP 与基础巡检

一文搞懂 Apache Doris 高可用架构:FE、BE、VIP 与基础巡检

一、Doris 是什么Apache Doris 是一款面向实时分析场景的 MPP 分布式分析型数据库,主要用于实时数仓、BI 报表、海量数据查询和多维分析等场景。Doris 采用典型的 FE BE 架构:FE(Frontend):负责 SQL 接入、用户认证、…

2026/9/24 22:17:19 阅读更多 →

日新闻

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为…

2026/9/24 0:00:19 阅读更多 →
单细胞注释实战:基于Scanpy的标记基因与参考映射流程解析

单细胞注释实战:基于Scanpy的标记基因与参考映射流程解析

简介:一份基于单细胞RNA测序数据的细胞类型注释算法研究Python毕业设计源码,针对计算机相关专业正在做毕设或需要项目实战的学习者,可用于课程设计与期末大作业。项目代码完整、经导师指导评审通过,可直接运行,覆盖数据…

2026/9/24 0:00:19 阅读更多 →
C#源生成器实战:用增量生成器替代反射,告别AOT崩溃

C#源生成器实战:用增量生成器替代反射,告别AOT崩溃

第一次在项目里被反射卡住,是在一个老旧的WinForms模块里:几十个类依赖PropertyChanged通知,运行时反射读属性、发通知,每次启动慢半拍不说,一上.NET Native/AOT裁剪模式几乎全面崩盘。后来我把这段逻辑全部改成C#源生…

2026/9/24 0:00:19 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/24 14:34:13 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/24 9:10:42 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/24 14:33:56 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/24 12:50:34 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/24 14:33:48 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/24 12:49:17 阅读更多 →