您好,感谢反馈!您提供的浮点失败、INT32 正常以及正 padding 正常的对照,有助于区分参数校验和执行后端。按您报告的 cann/ops-math@584b2ea6cbaeba684a51a74296d82d4d50ab3b0f 核查,Host 侧确实允许本条这类范围内的负 padding,但这与 A2 实际执行 kernel 是否正确处理裁剪,需要分别判断。
问题分析
SafePadSum() 按 dimSize + padFront + padBack 计算输出维度,并检查整数溢出、单侧裁剪是否超出原维度以及结果是否为负。因此,末维为 6 时,(-1,-1) 得到 4、(-2,1) 得到 5,都不会仅因存在负值而被拒绝;该函数本身只做形状校验,并不执行裁剪。固定版本代码
1d、2d、3d 接口对相应空间轴采用上述检查,再将带符号的 padding 转交给 PadV3 的 edge 模式。这里还有一个关键差异:在该版本的 910B 分派逻辑中,维数不超过 5 的 FLOAT32/FLOAT16/BFLOAT16 使用 AI Core,INT32 则转到 AI CPU。因此,您报告的 INT32 正常说明另一后端可完成该用例,不能据此推断浮点与 INT32 使用同一套 kernel。1d 调用、2d 调用、3d 调用、类型与后端分派
您报告的两个接口返回成功、随后同步出现 507035,需要沿设备执行路径继续定位。当前提交的前向 PadV3 公开 tiling/kernel 为 arch35,其构建列表未列出 ascend910b,所以不能用这些 kernel 的某个分支直接认定 A2 的异常根因;CANN 9.2 安装包实际使用的 A2 实现及其负 padding 索引、搬运长度和循环边界仍需对应核实。构建范围
处理方向
潜在的处理方向是,对应 A2 浮点 edge 路径核查负 padding 是否正确转换为输入裁剪起点和输出范围,尤其避免将负值直接用于只接受非负数的搬运或循环长度。另一可行方案是在接口预处理层将“裁剪”和“非负复制填充”拆开,同时保留现有溢出、裁剪范围及空输出约束。直接统一拒绝所有负 padding 会改变当前已放行的行为,需要同时评估接口语义和兼容性。
针对本条裁剪后仍非空的用例,调用侧也可以考虑先裁掉负 padding 对应的区域,再仅对正值部分做 replication padding,作为临时绕行思路。例如 [2,6] 的 (-2,1) 可先裁去左侧 2 个元素,再对剩余 4 个元素右侧填充 1 个;这一组合方式仍需在目标环境验证。后续核对宜保留您给出的 1d/2d/3d、FP32/FP16/INT32 与正负混合 padding 对照,分别检查同步状态和输出数值。
我们会继续确认 A2 实际执行路径与负 padding 行为的一致性。


现象
aclnnReplicationPad1d传入负 padding(裁剪语义)时,A2 上图 2 的两段式接口都返回 0,但aclrtSynchronizeStream返回 507035(AICore vector core exception);同一份代码的正 padding 正常,INT32 输入的负 padding 也正常。同一台机器逐项对照(FLOAT32,
self=[2,6],ASCEND_LAUNCH_BLOCKING=1):1,1[2,8]32,32/8000,8000[2,69]/[2,16005]-2,1[2,5]-1,-1/-2,1[2,4]/[2,5]-1,-1[2,4]同族接口在同一台机器上现象一致:
aclnnReplicationPad2d(FLOAT32[1,2,4,6]、-1,-1,-1,-1)与aclnnReplicationPad3d(FLOAT32[1,2,3,4,6]、六向-1)同样sync=507035。复现频率 2/2(连续两轮、两个 dtype、三个接口全部命中;正 padding 到 8000 不触发,与偏移量级无关)。期望
资料
docs/aclnnReplicationPad1d.md的参数表「padding 使用说明」只写了「长度为 2,两个数值依次代表左右两边需要填充的值」,没有限制符号;op_api 的SafePadSum()(conversion/pad_v3/op_api/op_replication_pad.h:51-68)明确实现了负值裁剪语义:padFront < 0 && dimSize + padFront < 0才判非法,否则按dimSize + padFront + padBack计算输出维。所以负 padding 是 host 侧主动放行的合法入参,预期行为是二者之一:
torch.nn.functional.pad(x, (-1,-1), mode='replicate')一致的[2,4](INT32 现在就是这样);不应出现「两段都返回 0、device 侧抛 vector core exception」。
环境
cann/ops-math@584b2ea6cbaeba684a51a74296d82d4d50ab3b0f(origin/master,2026-10-24 fetch)复现步骤
repro_replpad_neg.cppg++ -std=c++17 -O2 repro_replpad_neg.cpp -o repro -I$ASCEND_HOME_PATH/include -L$ASCEND_HOME_PATH/lib64 -lascendcl -lopapi -lnnopbaseASCEND_LAUNCH_BLOCKING=1 ./repropositive-pad一行:三个返回码都是 0negative-pad一行:sync=507035复现脚本
// aclnnReplicationPad1d 负 padding(裁剪)最小复现 #include <cstdio> #include <vector> #include "acl/acl.h" #include "aclnnop/aclnn_replication_pad1d.h" static aclTensor* MakeTensor(std::vector<float>& host, std::vector<int64_t>& shape, void** devPtr) { int64_t n = 1; for (auto d : shape) n *= d; size_t bytes = size_t(n) * sizeof(float); aclrtMalloc(devPtr, bytes, ACL_MEM_MALLOC_HUGE_FIRST); aclrtMemcpy(*devPtr, bytes, host.data(), bytes, ACL_MEMCPY_HOST_TO_DEVICE); std::vector<int64_t> strides(shape.size(), 1); for (int64_t i = int64_t(shape.size()) - 2; i >= 0; --i) strides[i] = shape[i + 1] * strides[i + 1]; return aclCreateTensor(shape.data(), shape.size(), ACL_FLOAT, strides.data(), 0, ACL_FORMAT_ND, shape.data(), shape.size(), *devPtr); } static void RunCase(const char* tag, std::vector<int64_t> inShape, std::vector<int64_t> outShape, std::vector<int64_t> pads, aclrtStream stream) { int64_t nIn = 1, nOut = 1; for (auto d : inShape) nIn *= d; for (auto d : outShape) nOut *= d; std::vector<float> selfHost(size_t(nIn)), outHost(size_t(nOut), -7.0f); for (int64_t i = 0; i < nIn; ++i) selfHost[size_t(i)] = float(i + 1); void *selfDev = nullptr, *outDev = nullptr; aclTensor* self = MakeTensor(selfHost, inShape, &selfDev); aclTensor* out = MakeTensor(outHost, outShape, &outDev); aclIntArray* padArr = aclCreateIntArray(pads.data(), int64_t(pads.size())); uint64_t wsSize = 0; aclOpExecutor* executor = nullptr; auto rc1 = aclnnReplicationPad1dGetWorkspaceSize(self, padArr, out, &wsSize, &executor); void* ws = nullptr; if (wsSize > 0) aclrtMalloc(&ws, wsSize, ACL_MEM_MALLOC_HUGE_FIRST); auto rc2 = aclnnReplicationPad1d(ws, wsSize, executor, stream); auto rc3 = (rc1 == 0 && rc2 == 0) ? aclrtSynchronizeStream(stream) : -1; printf("[%s] gws=%d exec=%d sync=%d\n", tag, int(rc1), int(rc2), int(rc3)); aclDestroyTensor(self); aclDestroyTensor(out); aclDestroyIntArray(padArr); if (ws) aclrtFree(ws); aclrtFree(selfDev); aclrtFree(outDev); } int main() { aclInit(nullptr); aclrtSetDevice(0); aclrtStream stream = nullptr; aclrtCreateStream(&stream); RunCase("positive-pad", {2, 6}, {2, 8}, {1, 1}, stream); // 阳性对照 RunCase("negative-pad", {2, 6}, {2, 4}, {-1, -1}, stream); // 缺陷路径 aclrtDestroyStream(stream); aclrtResetDevice(0); aclFinalize(); return 0; }实测输出(A2 + CANN 9.2.0,连续两次一致):
影响
调用方按裁剪语义传负 padding(crop-then-pad、模型里的对齐裁剪)时会拿到「内核异常」而不是参数错误,且同一份代码在 INT32 上正常、只在浮点上失败,混合精度流程里容易被误判成偶发;当前只能靠外部预先判断 padding 符号绕过。
建议
conversion/pad_v3/op_api/op_replication_pad.h:51-68的SafePadSum()既然放行负值,kernel 侧就应有对应的裁剪分支,或 host 侧统一改判 161002;建议按前者对齐 torch 语义(INT32 已经正确,可作为参照实现)。conversion/pad_v3/tests/st/aclnnReplicationPad1d|2d|3d目前没有负 padding 用例,建议各补一条(padding=-1,-1、padding=-2,1,fp32/fp16/int32 三档)。#2161(aclnnReplicationPad1dBackward在 padding 过大时 507035):本次是前向接口在负 padding 下的同类设备侧异常,建议一并检查 index/loop 边界。