感谢提供详细的环境、复现程序和对照结果。您反馈的是主机侧标量参数的支持范围校验,与张量内容校验是两类问题。
问题分析
aclnnMoeTokenPermuteGrad 的接口声明包含 bool paddedMode,但其 CheckParams 实现只接收三个张量参数,执行非空和数据类型检查,没有接收或检查 paddedMode。这能确认该处存在校验缺口,但尚不能据此断定后续调用链如何处理该参数,也不能直接推广到其余四个接口。
您提供的测试结果显示,在所述 A2 910B2、CANN 9.2.0 环境中,不支持的取值仍能通过第一段接口、执行接口和流同步。如果资料确实限定 paddedMode=false、actSeqLenType=0,这些取值被接受就与资料声明不一致。不过,返回成功本身不能证明实际采用了默认分支;是否产生所述数值偏差,还需结合参数传递和计算路径确认。
处理方向
一个可行的解决方案是在五个接口第一段接口的主机侧参数检查中,显式拒绝四个 Moe 接口的 paddedMode=true,以及 aclnnNsaCompressGrad 的 actSeqLenType!=0,并保持合法取值的现有行为。这类标量比较不需要读取设备端张量数据,适合放在计算任务提交之前完成。
错误返回方向应是明确的参数非法错误;您提出的 ACLNN_ERR_PARAM_INVALID 及数值 161002,仍需结合这些接口的公开错误码定义和返回路径确认。其他参数返回的 561002、361001 不能直接作为本次错误码映射的依据。
当前已明确一处局部校验缺口,其余接口的完整校验路径、资料适用范围和数值影响仍需继续确认。使用时建议先遵循资料限定,传入 paddedMode=false、actSeqLenType=0,不要将返回成功视为其他取值已受支持。


本轮补充证据(独立 C++ 直调,不依赖内部 harness)
在 master 0f6fad56(A2 910B2 / CANN 9.2.0)上用纯 aclnn 两段式接口复测 aclnnNsaCompressGrad 的 actSeqLenType,
四个取值全部放行,与本 issue 的现象一致:
| actSeqLenType | 第一段 rc | 第二段 rc | sync rc |
|---|---|---|---|
| 0(资料唯一支持值) | 0 | 0 | 0 |
| 1 | 0 | 0 | 0 |
| 2 | 0 | 0 | 0 |
| -1 | 0 | 0 | 0 |
最小复现代码(g++ -std=c++17 -O2 repro.cpp -I$ASCEND_HOME_PATH/include -L$ASCEND_HOME_PATH/lib64 -lascendcl -lopapi -lnnopbase):
#include <cstdio>
#include <vector>
#include <cstdint>
#include "acl/acl.h"
#include "aclnn/acl_meta.h"
#include "aclnnop/aclnn_nsa_compress_grad.h"
static aclTensor* mk(const std::vector<int64_t>& sh, aclDataType dt, void* dv) {
std::vector<int64_t> st(sh.size(), 1);
for (int i = (int)sh.size() - 2; i >= 0; --i) st[i] = sh[i + 1] * st[i + 1];
return aclCreateTensor(sh.data(), sh.size(), dt, st.data(), 0, ACL_FORMAT_ND,
sh.data(), sh.size(), dv);
}
static void* dev(size_t bytes) {
void* p = nullptr; size_t n = bytes ? bytes : 32;
aclrtMalloc(&p, n, ACL_MEM_MALLOC_HUGE_FIRST);
aclrtMemset(p, n, 0, n);
return p;
}
int main() {
aclInit(nullptr); aclrtSetDevice(3); aclrtStream s = nullptr; aclrtCreateStream(&s);
const int BLK = 32, STRIDE = 16, S = 128, HD = 2, D = 32, NBLK = (S - BLK) / STRIDE + 1;
std::vector<int64_t> gs{NBLK, HD, D}, is{S, HD, D}, ws{BLK, HD};
void *dg = dev(NBLK * HD * D * 2), *di = dev(S * HD * D * 2), *dw = dev(BLK * HD * 2);
void *dig = dev(S * HD * D * 2), *dwg = dev(BLK * HD * 2);
int64_t sv = S; aclIntArray* sl = aclCreateIntArray(&sv, 1);
for (int t : {0, 1, 2, -1}) {
aclTensor *tg = mk(gs, ACL_FLOAT16, dg), *ti = mk(is, ACL_FLOAT16, di), *tw = mk(ws, ACL_FLOAT16, dw);
aclTensor *tig = mk(is, ACL_FLOAT16, dig), *twg = mk(ws, ACL_FLOAT16, dwg);
uint64_t wsz = 0; aclOpExecutor* ex = nullptr;
aclnnStatus r1 = aclnnNsaCompressGradGetWorkspaceSize(tg, ti, tw, sl, BLK, STRIDE, t,
(char*)"TND", tig, twg, &wsz, &ex);
int r2 = -999, r3 = -999;
if (r1 == 0) {
void* wp = wsz ? dev(wsz) : nullptr;
r2 = (int)aclnnNsaCompressGrad(wp, wsz, ex, s);
r3 = (int)aclrtSynchronizeStream(s);
if (wp) aclrtFree(wp);
}
printf("actSeqLenType=%-3d gws=%d exec=%d sync=%d\n", t, (int)r1, r2, r3);
}
return 0;
}
源码侧补充:attention/nsa_compress_grad/op_host/nsa_compress_grad_tiling.cpp:112 取了
seqLenTypePtr = attrs->GetAttrPointer<uint32_t>(INDEXTWO),其后没有对该值做取值判断;
nsa_compress_grad_def.cpp:48 只声明 Attr("actSeqLenType")。资料 README.md:36 写「0表示cumsum结果,1表示每个batch序列大小,当前仅支持0」。


现象
五个 aclnn 接口的枚举型标量参数在资料里已明确写死「仅支持某一个值」,但实现完全不校验,
传入资料未支持的值时两段接口与同步全部返回 0,静默按默认分支计算。
aclnnMoeTokenPermuteGradpaddedModetrue→ rc=0aclnnMoeTokenUnpermuteGradpaddedModetrue→ rc=0aclnnMoeTokenUnpermuteWithEpGradpaddedModetrue→ rc=0aclnnMoeTokenPermuteWithEpGradpaddedModetrue→ rc=0aclnnNsaCompressGradactSeqLenType1→ rc=0;2→ rc=0环境
A2 910B2;CANN 9.2.0;
cann/ops-transformermaster92d0f9c2。期望
资料声明「仅支持 X」的参数,传入非 X 时应返回参数错误(
161002 ACLNN_ERR_PARAM_INVALID)。这类参数是
bool/int64_t标量,host 侧一次比较即可,不存在性能问题。复现步骤
r.cpp。g++ -std=c++17 r.cpp -o r -I$ASCEND_HOME_PATH/include -L$ASCEND_HOME_PATH/lib64 -lascendcl -lnnopbase -lopapi./r 4复现脚本
// 枚举标量参数未校验:paddedMode / actSeqLenType #include <cstdio> #include <cstdlib> #include <vector> #include "acl/acl.h" #include "aclnnop/aclnn_moe_token_permute_grad.h" static aclTensor *mk(const std::vector<int64_t> &sh, aclDataType dt, void *dv) { std::vector<int64_t> st(sh.size(), 1); for (int i = (int)sh.size() - 2; i >= 0; --i) st[i] = sh[i + 1] * st[i + 1]; return aclCreateTensor(sh.data(), sh.size(), dt, st.data(), 0, ACL_FORMAT_ND, sh.data(), sh.size(), dv); } int main(int argc, char **argv) { aclInit(nullptr); aclrtSetDevice(argc > 1 ? atoi(argv[1]) : 0); aclrtStream s = nullptr; aclrtCreateStream(&s); // aclnnMoeTokenPermuteGrad:tokens=8 topk=4 hidden=16 -> total=32 const int T = 32, H = 16; std::vector<int64_t> gs{T, H}, is{T}, os{T, H}; size_t bg = (size_t)T * H * 4, bi = (size_t)T * 4; void *dg, *di, *do_; aclrtMalloc(&dg, bg, ACL_MEM_MALLOC_HUGE_FIRST); aclrtMalloc(&di, bi, ACL_MEM_MALLOC_HUGE_FIRST); aclrtMalloc(&do_, bg, ACL_MEM_MALLOC_HUGE_FIRST); std::vector<float> hg(T * H, 1.f); std::vector<int> hi(T); for (int i = 0; i < T; ++i) hi[i] = i; aclrtMemcpy(dg, bg, hg.data(), bg, ACL_MEMCPY_HOST_TO_DEVICE); aclrtMemcpy(di, bi, hi.data(), bi, ACL_MEMCPY_HOST_TO_DEVICE); aclTensor *tg = mk(gs, ACL_FLOAT, dg), *ti = mk(is, ACL_INT32, di), *to = mk(os, ACL_FLOAT, do_); // 资料「目前仅支持 false」,这里传 true for (int k = 0; k < 2; ++k) { bool padded = (k == 1); uint64_t ws = 0; aclOpExecutor *ex = nullptr; auto r1 = aclnnMoeTokenPermuteGradGetWorkspaceSize(tg, ti, 4, padded, to, &ws, &ex); int r2 = -999, r3 = -999; if (r1 == 0) { void *wp = nullptr; if (ws) aclrtMalloc(&wp, ws, ACL_MEM_MALLOC_HUGE_FIRST); r2 = aclnnMoeTokenPermuteGrad(wp, ws, ex, s); r3 = aclrtSynchronizeStream(s); } printf(" paddedMode=%-5s GWS=%-7d Exec=%-7d Sync=%-7d\n", padded ? "true" : "false", (int)r1, r2, r3); } return 0; }实测输出:
aclnnNsaCompressGrad的actSeqLenType(独立小程序,同一模式):影响
paddedMode=true时算子不会走 padded 路径,而是当false处理,调用方以为开了 padded 模式,拿到的却是非 padded 的结果 —— 形状常常恰好对得上,
数值语义已变而无任何提示;
actSeqLenType选 1/2(表示不同的 seqLen 解读方式:累加和 vs 逐 batch 长度)时同样被按 0 处理,多 batch 场景下 seqLen 会被解读错,导致输出整体偏移;
bool/int64_t标量,host 校验零成本,属于该做而未做。建议
op_api的CheckParams里加断言:paddedMode == false(四个 Moe 接口)、actSeqLenType == 0(NsaCompressGrad);返回
ACLNN_ERR_PARAM_INVALID(161002);paddedMode=true/actSeqLenType=1,则先把资料与实现同步,在此之前保持「资料写仅支持 X ⇒ 必须拒绝非 X」;
aclnnMatmulAllReduce的commTurn(资料仅支持 0)是返回 561002,说明本仓对这类参数有拦截先例,此处属遗漏。
备注
aclnnNsaCompressGrad的compressBlockSize=24(非 16 倍数)被正确拒绝(561002),aclnnMoeTokenPermuteGrad的numTopk=513被正确拒绝(361001),证明这些接口都有标量校验通道,只是枚举型参数这一分支漏了;
paddedMode是bool、actSeqLenType是int64_t,都是标量,host 侧校验零成本。