已关闭
[Bug-Report|缺陷反馈]: aclnnFusedQuantMatmulWeightNz 预留入参传非空返回 161001,资料声明 161002 #7064
liuhanwen8创建于 12 天前关闭于 7 天前
yuning_chen
12 天前 评论:
12 天前 评论:
11 天前 将 lifei265 设为负责人
yuning_chen
11 天前 评论:
11 天前 评论:
您好,该问题已收到,当前问题 @yolic 处理中


11 天前 将 yolic 设为负责人,移除负责人 lifei265
10 天前 移除了负责人 yolic
10 天前 将 zhengyuhao3 设为负责人
7 天前 关联了pull request:修复matmul算子Issue问题
7 天前 删除了关联的pull request:修复matmul算子Issue问题
7 天前 关闭了 issue
6 天前 添加了label:resolved
环境
npu-smi26.1.1)Ascend-cann-toolkit_9.2.0_linux-aarch64)aclnnFusedQuantMatmulWeightNz(两段式,WeightNz 权重通路)matmul/fused_quant_mat_mul/docs/aclnnFusedQuantMatmulWeightNz.md现象
资料《返回值》表把「传入的当前不支持的 yScaleOptional、x1OffsetOptional、x2OffsetOptional、yOffsetOptional、x3Optional、groupSizeOptional 参数」明确归入 161002(ACLNN_ERR_PARAM_INVALID) 的第 5 条子项;
实测这些预留入参一旦传值(给一个合法张量 / 非 0 的 groupSize),第一段接口返回的是 161001(ACLNN_ERR_PARAM_NULLPTR)。
不开/开确定性(
ACL_OPT_DETERMINISTIC= 0/1)两种场景结论一致。影响
调用方按资料实现「非法参数 → 按 161002 分支处理」时拿不到预期错误码:拿到 161001 会被误判为「某个必选入参传了空指针」,把排查方向带偏(尤其
groupSizeOptional是标量,跟空指针毫无关系)。复现(自包含,只依赖 CANN 自带
libascendcl/libopapi/libnnopbase+ ctypes)source /usr/local/Ascend/ascend-toolkit/set_env.sh python3 fqmmnz_reserved_optional.py实测输出:
import ctypes, sys M = K = N = 32 # 可选:用第一个命令行参数指定 x2 的**声明维度**(逗号分隔),用于核对资料的 4~8 维声明 X2_SHAPE = [int(v) for v in sys.argv[1].split(",")] if len(sys.argv) > 1 else [K, N] INT8, F32, F16 = 2, 0, 1 ND, NZ = 2, 29 acl = ctypes.CDLL("libascendcl.so") op = ctypes.CDLL("libopapi.so") try: nb = ctypes.CDLL("libnnopbase.so") except OSError: nb = None def sym(n): for lib in (acl, nb): if lib is not None: try: return getattr(lib, n) except AttributeError: pass raise AttributeError(n) def chk(r, w): if int(r) != 0: raise RuntimeError("%s -> %d" % (w, int(r))) acl.aclInit.argtypes = [ctypes.c_void_p] acl.aclrtSetDevice.argtypes = [ctypes.c_int32] acl.aclrtCreateStream.argtypes = [ctypes.POINTER(ctypes.c_void_p)] acl.aclrtMalloc.argtypes = [ctypes.POINTER(ctypes.c_void_p), ctypes.c_size_t, ctypes.c_int32] acl.aclrtMemcpy.argtypes = [ctypes.c_void_p, ctypes.c_size_t, ctypes.c_void_p, ctypes.c_size_t, ctypes.c_int32] acl.aclrtSynchronizeStream.argtypes = [ctypes.c_void_p] mk_t = sym("aclCreateTensor") mk_t.restype = ctypes.c_void_p mk_t.argtypes = [ctypes.POINTER(ctypes.c_int64), ctypes.c_uint64, ctypes.c_int32, ctypes.POINTER(ctypes.c_int64), ctypes.c_int64, ctypes.c_int32, ctypes.POINTER(ctypes.c_int64), ctypes.c_uint64, ctypes.c_void_p] mk_a = sym("aclCreateIntArray") mk_a.restype = ctypes.c_void_p mk_a.argtypes = [ctypes.POINTER(ctypes.c_int64), ctypes.c_uint64] op.aclnnCalculateMatmulWeightSizeV2.restype = ctypes.c_int32 op.aclnnCalculateMatmulWeightSizeV2.argtypes = [ctypes.c_void_p, ctypes.c_int32, ctypes.POINTER(ctypes.c_uint64)] op.aclnnTransMatmulWeightGetWorkspaceSize.restype = ctypes.c_int32 op.aclnnTransMatmulWeightGetWorkspaceSize.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_uint64), ctypes.POINTER(ctypes.c_void_p)] op.aclnnTransMatmulWeight.restype = ctypes.c_int32 op.aclnnTransMatmulWeight.argtypes = [ctypes.c_void_p, ctypes.c_uint64, ctypes.c_void_p, ctypes.c_void_p] op.aclnnFusedQuantMatmulWeightNzGetWorkspaceSize.restype = ctypes.c_int32 op.aclnnFusedQuantMatmulWeightNz.restype = ctypes.c_int32 chk(acl.aclInit(None), "aclInit") chk(acl.aclrtSetDevice(0), "aclrtSetDevice") stream = ctypes.c_void_p() chk(acl.aclrtCreateStream(ctypes.byref(stream)), "aclrtCreateStream") def dev(data=b"", need=0): p = ctypes.c_void_p() chk(acl.aclrtMalloc(ctypes.byref(p), max(len(data), need, 1), 0), "aclrtMalloc") if data: b = ctypes.create_string_buffer(data, len(data)) chk(acl.aclrtMemcpy(p, max(len(data), need, 1), b, len(data), 1), "aclrtMemcpy") return p def tensor(shape, dt, ptr, fmt=ND, storage=None): dims = (ctypes.c_int64 * len(shape))(*shape) st = [1] * len(shape) for i in range(len(shape) - 2, -1, -1): st[i] = shape[i + 1] * st[i + 1] strides = (ctypes.c_int64 * len(shape))(*st) storage = list(storage or shape) sd = (ctypes.c_int64 * len(storage))(*storage) return mk_t(dims, len(shape), dt, strides, 0, fmt, sd, len(storage), ctypes.c_void_p(ptr.value)) x1 = dev(bytes([1] * (M * K))) s1 = dev(bytes((ctypes.c_float * M)(*([0.5] * M)))) s2 = dev(bytes((ctypes.c_float * N)(*([0.5] * N)))) out = dev(b"", M * N * 2) # ---- x2:先按 ND 声明,再用 aclnnTransMatmulWeight 原地刷成亲和排布,最后按 NZ 声明 ---- wraw = bytes([1] * (K * N)) arr = (ctypes.c_int64 * len(X2_SHAPE))(*X2_SHAPE) ia = mk_a(arr, len(X2_SHAPE)) size = ctypes.c_uint64(0) chk(op.aclnnCalculateMatmulWeightSizeV2(ctypes.c_void_p(ia), INT8, ctypes.byref(size)), "WeightSize") wptr = dev(wraw, int(size.value)) tmp = tensor(X2_SHAPE, INT8, wptr, ND, [int(size.value)]) ws = ctypes.c_uint64(0) ex = ctypes.c_void_p() chk(op.aclnnTransMatmulWeightGetWorkspaceSize(ctypes.c_void_p(tmp), ctypes.byref(ws), ctypes.byref(ex)), "Trans1") wsp = ctypes.c_void_p() if ws.value: chk(acl.aclrtMalloc(ctypes.byref(wsp), int(ws.value), 0), "malloc") chk(op.aclnnTransMatmulWeight(wsp, ws.value, ex, stream), "Trans2") chk(acl.aclrtSynchronizeStream(stream), "sync") x2 = tensor(X2_SHAPE, INT8, wptr, NZ, [int(size.value)]) t1 = tensor([M, K], INT8, x1) ts1 = tensor([M], F32, s1) ts2 = tensor([N], F32, s2) tout = tensor([M, N], F16, out) yScale = tensor([N], F32, s2) # 资料要求这个位置必须是 nullptr def call(yscale): ws = ctypes.c_uint64(0) ex = ctypes.c_void_p() null = ctypes.c_void_p(None) h = lambda t: ctypes.c_void_p(t) if t else null r1 = op.aclnnFusedQuantMatmulWeightNzGetWorkspaceSize( h(t1), h(x2), h(ts1), h(ts2), h(yscale), null, null, null, null, null, ctypes.c_char_p(b"gelu_tanh"), ctypes.c_int64(0), h(tout), ctypes.byref(ws), ctypes.byref(ex)) r2 = None if r1 == 0: p = ctypes.c_void_p() if ws.value: chk(acl.aclrtMalloc(ctypes.byref(p), int(ws.value), 0), "malloc2") r2 = op.aclnnFusedQuantMatmulWeightNz(p, ws.value, ex, stream) chk(acl.aclrtSynchronizeStream(stream), "sync2") return r1, r2 print("x2 声明维度 =", X2_SHAPE) print("yScaleOptional = nullptr ->", call(None)) print("yScaleOptional = fp32[32] ->", call(yScale), " # 资料声明应为 161002")期望
预留入参传非空 / 非 0 时返回 161002(与资料一致);或资料改为 161001 并说明「预留参数必须为 nullptr,否则按空指针错误码返回」。