您好,感谢提供正 padding 对照和同步返回值。按您报告的 584b2ea6cbaeba684a51a74296d82d4d50ab3b0f 核查,本例存在负值进入不适配裁剪处理的 3d AiCore 路径的风险,需要沿该路径核实。
问题分析
输入空间维为 [4,5,6],padding 按左右、上下、前后排列为 [-1,1,0,2,1,0],对应 gradOutput 空间维 [5,7,6],满足当前第一段的形状关系检查。该检查没有因负 padding 拒绝本例。L0 分流对 A2、5 维、FLOAT、edge 模式选择 PadV3GradReplication AiCore,不能因文件中也有 AICPU 分支就把本例归为 AICPU 问题。
A2 tiling将 padding 保存在 uint32_t 数组中,RemapPaddings 直接赋入有符号输入值,没有先拆分裁剪与正向填充。因此 -1 会转换为 4294967295;kernel又将这些值用于边界累计次数。这是明确的危险路径,与负 padding 触发运行时失败的报告相符。不过,单凭 507035 仍不能确定本次是哪条访问或哪项设备检查失败,需结合对应任务的设备错误日志确认,尚未独立设备复验。
1d/2d 的成功对照有助于缩小范围,但它们走不同实现分支,不能单独证明 3d 内核已支持同样的裁剪。当前资料也没有清楚说明负值裁剪及其边界,接口支持口径需要明确。
处理方向
若保留负 padding 裁剪语义,应把裁剪偏移与非负填充次数分开处理,正确映射梯度到原 self,裁掉的位置保持零梯度、复制边缘正确累加;不能只把字段改为有符号类型,或将负值直接钳成 0,这些做法没有完成裁剪语义。
若某条后端暂不支持该配置,可评估入口明确拒绝或转到已验证支持的实现,并说明兼容范围。仅修改 isPadSupport 返回 false 不足以证明已避开问题:当前 3d AiCore 分支并不受 padFlag 条件控制,需要同时核对分流。也不宜未经契约确认就统一拒绝所有负 padding。
回归应分别覆盖六个方向的裁剪、正负混合、4D/5D、裁剪后空间大小边界及不同精度,除两段和同步状态外,还需检查完整梯度数值。我们会继续确认 3d 裁剪支持范围、边界表示和安全分流方案。


现象
aclnnReplicationPad3dBackward在padding含负值(裁剪)时:第一段返回 0、第二段返回 0,但
aclrtSynchronizeStream返回 507035(设备侧运行时错误)。同族 1d / 2d 反向的同类负 padding却正常 PASS,说明裁剪语义本身是被支持的,3d 实现不一致。
同一台 A2 单机逐项对照(FLOAT32,值全 1):
[1,1,4,5,6]1,1,1,1,1,1[1,1,6,7,8]ret(gws)=0 ret(exec)=0 sync=0[1,1,4,5,6]-1,1,0,2,1,0[1,1,5,7,6]ret(gws)=0 ret(exec)=0 **sync=507035**[2,5]-1,-1[1,4,4]-1,1,1,1期望
要么与 1d/2d 一致地正确完成裁剪(推荐,因为同族已支持),
要么在第一段返回
161002(ACLNN_ERR_PARAM_INVALID)明确拒绝。当前行为是最差的一种:参数被接受、kernel 被拉起、在 stream 同步时才报设备错误。
异步/图模式下调用方很难把它归因到「padding 为负」,且设备侧错误会污染后续算子。
影响
507035(运行时错误),无法区分「自己传错参数」与「环境/设备故障」。建议
按 1d/2d 的实现路径让 3d 反向也支持负 padding 裁剪;若短期做不到,
在
op_api/ tiling 前置判负并返回 161002,不要等到 kernel 阶段失败。环境
cann/ops-math@584b2ea6(master,2026-10-24 fetch)复现步骤
repro_rpp3b_negpad.cpp;LF 换行g++ -std=c++17 -O2 repro_rpp3b_negpad.cpp -o repro -I"$ASCEND_HOME_PATH/include" -L"$ASCEND_HOME_PATH/lib64" -lascendcl -lopapi -lnnopbaseASCEND_LAUNCH_BLOCKING=1 ./reproCTRL-pospad应为ret(gws)=0 ret(exec)=0 sync=0;DEFECT-negpad实测ret(gws)=0 ret(exec)=0 sync=507035复现脚本
#include <cstdio> #include <vector> #include "acl/acl.h" #include "aclnnop/aclnn_replication_pad3d_backward.h" static aclTensor* Make(std::vector<float>& h, std::vector<int64_t>& sh, void** dev) { int64_t n = 1; for (auto d : sh) n *= d; size_t b = size_t(n > 0 ? n : 1) * sizeof(float); aclrtMalloc(dev, b, ACL_MEM_MALLOC_HUGE_FIRST); if (n > 0) aclrtMemcpy(*dev, b, h.data(), b, ACL_MEMCPY_HOST_TO_DEVICE); std::vector<int64_t> st(sh.size(), 1); for (int64_t i = int64_t(sh.size()) - 2; i >= 0; --i) st[i] = sh[i + 1] * st[i + 1]; return aclCreateTensor(sh.data(), sh.size(), ACL_FLOAT, st.data(), 0, ACL_FORMAT_ND, sh.data(), sh.size(), *dev); } static std::vector<int64_t> Padded(const std::vector<int64_t>& s, const std::vector<int64_t>& p) { std::vector<int64_t> o = s; int r = int(o.size()); for (int k = r - 1; k >= 0; --k) { int i = 2 * (r - 1 - k); if (i + 1 < int(p.size())) o[k] += p[i] + p[i + 1]; } return o; } static void Run(const char* tag, std::vector<int64_t> selfShape, std::vector<int64_t> pads, aclrtStream stream) { std::vector<int64_t> goShape = Padded(selfShape, pads); int64_t nSelf = 1, nGo = 1; for (auto d : selfShape) nSelf *= d; for (auto d : goShape) nGo *= d; std::vector<float> selfH(size_t(nSelf > 0 ? nSelf : 1), 1.0f); std::vector<float> goH(size_t(nGo > 0 ? nGo : 1), 1.0f); std::vector<float> giH(size_t(nSelf > 0 ? nSelf : 1), -7.0f); void *sd = nullptr, *gd = nullptr, *id = nullptr; aclTensor* self = Make(selfH, selfShape, &sd); aclTensor* go = Make(goH, goShape, &gd); aclTensor* gi = Make(giH, selfShape, &id); aclIntArray* pa = aclCreateIntArray(pads.data(), int64_t(pads.size())); uint64_t ws = 0; aclOpExecutor* ex = nullptr; auto rc1 = aclnnReplicationPad3dBackwardGetWorkspaceSize(go, self, pa, gi, &ws, &ex); void* w = nullptr; if (rc1 == 0 && ws > 0) aclrtMalloc(&w, ws, ACL_MEM_MALLOC_HUGE_FIRST); aclnnStatus rc2 = (aclnnStatus)-1; if (rc1 == 0) rc2 = aclnnReplicationPad3dBackward(w, ws, ex, stream); aclnnStatus rc3 = (rc1 == 0 && rc2 == 0) ? aclrtSynchronizeStream(stream) : -1; printf("[%-14s] pad=[", tag); for (size_t i = 0; i < pads.size(); ++i) printf("%s%ld", i ? "," : "", long(pads[i])); printf("] ret(gws)=%d ret(exec)=%d sync=%d\n", int(rc1), int(rc2), int(rc3)); aclDestroyTensor(self); aclDestroyTensor(go); aclDestroyTensor(gi); aclDestroyIntArray(pa); if (w) aclrtFree(w); aclrtFree(sd); aclrtFree(gd); aclrtFree(id); } int main() { aclInit(nullptr); aclrtSetDevice(0); aclrtStream s = nullptr; aclrtCreateStream(&s); Run("CTRL-pospad", {1, 1, 4, 5, 6}, {1, 1, 1, 1, 1, 1}, s); // 对照组 CTRL Run("DEFECT-negpad", {1, 1, 4, 5, 6}, {-1, 1, 0, 2, 1, 0}, s); // 缺陷组 DEFECT aclrtDestroyStream(s); aclrtResetDevice(0); aclFinalize(); return 0; }实测输出:
[CTRL-pospad] pad=[1,1,1,1,1,1] ret(gws)=0 ret(exec)=0 sync=0;[DEFECT-negpad] pad=[-1,1,0,2,1,0] ret(gws)=0 ret(exec)=0 sync=507035。