尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

CANN ops-nn 非连续 Tensor 详解:shape / strides / offset 三要素表示法与算子支持机制

发布时间:2026/9/19 21:16:24

资讯中心
01
ARTICLE

CANN ops-nn 非连续 Tensor 详解:shape / strides / offset 三要素表示法与算子支持机制

CANN ops-nn 非连续 Tensor 详解:shape / strides / offset 三要素表示法与算子支持机制
CANN ops-nn 非连续 Tensor 详解shape / strides / offset 三要素表示法与算子支持机制【免费下载链接】ops-nn本项目是CANN提供的神经网络类计算算子库实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-nn本篇文章围绕 CANN ops-nn 算子库中非连续 TensorNon-contiguous Tensor这一核心概念展开说明一个 aclTensor 如何通过(shape, strides, offset)三元组在内存中描述不连续的视图view并给出两个完整的内存排布实例。读完本文你将掌握 strides 与 offset 的精确定义、非连续地址的推算方法、通过aclCreateTensor构造非连续 aclTensor 的实战写法以及 ops-nn 算子内部为支持非连续输入所采用的 Contiguous 转换与 ViewCopy 机制。一、背景为什么需要非连续 Tensor在神经网络计算中张量Tensor通常以连续内存行优先 / Row-Major的方式存储即逻辑下标(i0, i1, ..., in-1)对应的元素在内存中是依次相邻的。但实际应用中大量操作会自然产生视图不连续的数据典型场景包括切片Slice从一个大张量中截取一个子块子块内部各行之间并不相邻转置Transpose交换维度后原始连续排布在新视图下变成跳跃式访问步幅采样如按步长 2 抽帧、跨行读取等。若每次产生这类视图都物理拷贝一份连续数据会带来明显的内存与带宽开销。为此CANN 算子库引入非连续 Tensor概念一个 Tensor 可以通过(shape, strides, offset)表示用 strides 描述各维度相邻元素的间隔、用 offset 描述首元素相对基地址的偏移从而在不拷贝数据的前提下描述一个逻辑张量视图。目前大部分算子 API 的输入 aclTensor 都支持这种表示方式。二、核心三要素shape、strides、offset非连续 Tensor 的表示由三个要素共同决定要素含义取值特点shape描述 Tensor 的逻辑形状即每个维度上的元素个数与连续 Tensor 的 shape 含义完全一致strides描述 Tensor 各维度上相邻两个元素在内存中的间隔以元素个数计某维度 stride 为 1 时该维度连续stride 大于 1 时该维度上元素之间存在间隔即非连续offset表示该 Tensor 的首元素相对基地址addr的偏移以元素个数计取值为非负整数指向视图的第一个有效元素其中 strides 是判断连续性的关键如果在维度 1 上的 stride 为 1该维度是连续的如果在维度 0 上的 stride 为 10那么相邻的元素间隔 10 个元素即非连续。offset 则解决了视图不从基地址第 0 个元素开始的问题例如从一个大矩阵中间截取子块时首元素往往并不位于内存起点。在 strided 视图表示下逻辑下标(i0, i1, ..., in-1)对应的元素在内存中的位置可表达为base_addr (offset i0 * strides[0] i1 * strides[1] ... in-1 * strides[n-1]) * 元素大小当所有维度的 strides 恰好满足行优先连续的递推关系最后一维 stride 为 1前一维 stride 等于后一维 shape 与 stride 的乘积时该 Tensor 退化为连续 Tensor连续 Tensor 可视作 offset 为 0、strides 由 shape 递推得出的特例。三、示例 1shape(6, 5)、strides(10, 1)、offset22 的行连续切片假设底层一块连续内存被组织为一个 10×10 的逻辑矩阵基地址为addr现有 Tensor 的shape(6, 5)、strides(10, 1)、offset22其内存排布如下深色为有效元素行\列01234567890a0,0a0,1a0,2a0,3a0,4a0,5a0,6a0,7a0,8a0,91a1,0a1,1a1,2a1,3a1,4a1,5a1,6a1,7a1,8a1,92a2,0a2,1a2,2a2,3a2,4a2,5a2,6a2,7a2,8a2,93a3,0a3,1a3,2a3,3a3,4a3,5a3,6a3,7a3,8a3,94a4,0a4,1a4,2a4,3a4,4a4,5a4,6a4,7a4,8a4,95a5,0a5,1a5,2a5,3a5,4a5,5a5,6a5,7a5,8a5,96a6,0a6,1a6,2a6,3a6,4a6,5a6,6a6,7a6,8a6,97a7,0a7,1a7,2a7,3a7,4a7,5a7,6a7,7a7,8a7,98a8,0a8,1a8,2a8,3a8,4a8,5a8,6a8,7a8,8a8,99a9,0a9,1a9,2a9,3a9,4a9,5a9,6a9,7a9,8a9,9该 Tensor 的有效数据即上图的深色位置具体解读如下offset22在 10×10 的连续排布中第 0 行占 10 个元素索引 0~9、第 1 行占 10 个元素索引 10~19索引 20、21 对应 a2,0、a2,1因此首元素 a2,2 的偏移为 22维度 1 的 stride 为 1同一行内相邻元素紧挨着存放所以每行取连续 5 个元素a2,2 ~ a2,6维度 0 的 stride 为 10下一行的首元素与当前行的首元素间隔 10 个元素即从 a2,2 出发行号每 1 需要跳过 10 个元素的位置依次得到 a3,2、a4,2……直到 a7,2共 6 行。这个完整的 Tensor 在内存排布上是不连续的维度 1 上是连续的stride1但维度 0 上的元素间隔 10 个元素属于非连续。该视图等价于从 10×10 矩阵中截取第 2~7 行、第 2~6 列的切片且全程无需任何数据拷贝。四、示例 2shape(4, 3)、strides(20, 2)、offset22 的跳跃采样视图再看一个维度 0 和维度 1 都不连续的示例。同样基于 10×10 的逻辑矩阵现有 Tensor 的shape(4, 3)、strides(20, 2)、offset22其内存排布如下行\列01234567890a0,0a0,1a0,2a0,3a0,4a0,5a0,6a0,7a0,8a0,91a1,0a1,1a1,2a1,3a1,4a1,5a1,6a1,7a1,8a1,92a2,0a2,1a2,2a2,3a2,4a2,5a2,6a2,7a2,8a2,93a3,0a3,1a3,2a3,3a3,4a3,5a3,6a3,7a3,8a3,94a4,0a4,1a4,2a4,3a4,4a4,5a4,6a4,7a4,8a4,95a5,0a5,1a5,2a5,3a5,4a5,5a5,6a5,7a5,8a5,96a6,0a6,1a6,2a6,3a6,4a6,5a6,6a6,7a6,8a6,97a7,0a7,1a7,2a7,3a7,4a7,5a7,6a7,7a7,8a7,98a8,0a8,1a8,2a8,3a8,4a8,5a8,6a8,7a8,8a8,99a9,0a9,1a9,2a9,3a9,4a9,5a9,6a9,7a9,8a9,9该 Tensor 的有效数据即上图的深色位置具体解读如下offset22与示例 1 相同首元素为 a2,2维度 1 的 stride 为 2同一行内相邻两个有效元素之间间隔 1 个元素因此每行取 3 个元素依次为 a2,2、a2,4、a2,6跳过了列 3、列 5维度 0 的 stride 为 20下一行首元素与当前行首元素间隔 20 个元素即行号每 1 需要跳过 20 个元素的位置因此依次落在第 2、4、6、8 行共 4 行。该 Tensor 同样在内存排布上是不连续的维度 1 上的 stride 为 2该维度上间隔 1 个元素维度 0 上的 stride 为 20相邻元素间隔 20 个元素。它等价于对 10×10 矩阵做隔行隔列采样得到的 4×3 视图两个维度均为非连续比示例 1 的切片场景更具代表性。通过示例 1 与示例 2 的对比可以看出stride 越大意味着该维度方向上的元素在内存中散布得越开只要任一维度的 stride 不满足连续递推关系整个 Tensor 即为非连续而 offset 仅负责定位视图的起点不参与连续性的判定。五、如何创建非连续 aclTensoraclCreateTensor 实战创建 aclTensor 统一通过算子库公共接口aclCreateTensor完成参见 docs/zh/context/data_structure.md 中关于 aclTensor 数据结构的说明以及《算子库接口》公共接口 aclCreateTensor章节。从仓库中的算子示例代码 activation/celu_v2/examples/test_aclnn_celu.cpp 可以确认其典型调用形式*tensor aclCreateTensor(shape.data(), // shape各维度大小 shape.size(), // ndim维度个数 dataType, // 数据类型如 ACL_FLOAT strides.data(), // strides各维度步长 0, // offset首元素相对基地址的偏移 aclFormat::ACL_FORMAT_ND, // 数据格式 shape.data(), // originShape原始 shape shape.size(), // originNdim原始维度个数 deviceAddr); // device 侧基地址对于连续 Tensor示例代码中给出了 strides 的标准递推算法——从最后一维开始最后一维 stride 为 1前一维 stride 等于后一维 shape 与 stride 的乘积这正是行优先连续的充要条件// 计算连续 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]; }要创建非连续的 aclTensor只需把上述由 shape 推导出的连续 strides替换为视图实际对应的 strides并填写非零的 offset。以示例 2 为例示意写法基地址沿用 10×10 数据块的 device 地址// 非连续视图shape(4,3)strides(20,2)offset22 std::vectorint64_t shape {4, 3}; std::vectorint64_t strides {20, 2}; int64_t offset 22; aclTensor* view aclCreateTensor(shape.data(), shape.size(), aclDataType::ACL_FLOAT, strides.data(), offset, aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(), deviceAddr);注意aclCreateTensor的 offset 参数与示例代码中连续场景传0的区别连续 Tensor 的首元素即基地址首元素offset 为 0非连续场景下必须显式传入视图首元素相对基地址的偏移量。六、底层机制算子内部如何消化非连续输入非连续 Tensor 作为 API 层统一支持的输入形态其底层处理在 ops-nn 仓库中可以找到对应的实现证据。以 CELU 算子为例其二阶段接口的实现 activation/celu_v2/op_api/aclnn_celu.cpp 中采用先连续化、计算、再拷回的固定套路// 将输入 self 转换成连续的 Tensor auto contiguousSelf l0op::Contiguous(self, uniqueExecutor.get()); // 在连续 Tensor 上调用算子 kernel auto celuV2Out l0op::CeluV2(contiguousSelf, alpha-ToFloat(), uniqueExecutor.get()); // 将计算结果拷贝到输出 out 上out 可能是非连续的 tensor auto viewCopyResult l0op::ViewCopy(castOut, out, uniqueExecutor.get());即算子内部先通过Contiguous把非连续输入规整为连续张量参与 kernel 计算计算完成后通过ViewCopy将结果按输出 aclTensor 的 strides/offset 视图写回从而对调用方屏蔽非连续排布的细节。该算子头文件 activation/celu_v2/op_api/aclnn_celu.h 与 READMEactivation/celu_v2/README.md中均明确标注支持非连续 Tensor。另一方面公共 fallback 层 common/inc/op_graph/fallback_common_2stages_nn.h 展示了非连续视图的另一种典型用法在对 MatMul 类算子做转置处理时直接通过交换对应维度的 strides 构造一个非连续视图实现零拷贝的虚拟转置if (transpose) { auto swap strides[dimN]; strides[dimN] strides[dimM]; strides[dimM] swap; // 交换 strides 即可得到转置视图无需搬移数据 viewShape[dimN] shape[dimM]; viewShape[dimM] shape[dimN]; }从源码结构看非连续 Tensor 机制正是通过视图描述strides/offset 显式连续化Contiguous 结果写回ViewCopy的组合让上层 API 既能享受零拷贝描述视图的收益又能让下层 kernel 始终基于规整数据计算兼顾了灵活性与性能。七、使用注意事项与限制支持范围目前大部分算子 API 的输入 aclTensor 支持非连续 Tensor但并非全部。个别 API 是否支持、支持哪些维度的非连续需以该 API 实际文档/README 的非连续 Tensor标注为准例如 activation/celu_v2/docs/aclnnCeluaclnnInplaceCelu.md 的参数表中逐项标注了输入输出的非连续支持情况。数据格式约束非连续描述基于 ND行优先排布语义展开非 ND 的私有格式如 FRACTAL_NZ 等当前绝大多数 aclnn API 尚不支持具体以 API 描述为准详见 docs/zh/context/data_format.md。与空 Tensor 等特性的叠加部分算子在支持非连续 Tensor 的同时还支持空 Tensor 与 0~8 维输入使用时应一并核对 API 的完整约束。更多基本概念非连续 Tensor 属于算子库基本概念体系的一部分与之配套的还有两段式接口、数据结构、数据类型、broadcast 关系、互推导关系等可参阅 docs/zh/context/basic_concept.md 总览全部概念。综上(shape, strides, offset)三要素构成了 CANN ops-nn 描述非连续 Tensor 的完整模型shape 决定逻辑形状strides 决定各维度的内存间隔与连续性offset 定位视图起点。理解并善用这一机制可以在切片、转置、采样等场景下以零拷贝方式构造输入视图同时借助算子内部 Contiguous ViewCopy 的支撑让非连续输入与普通连续输入一样直接参与 NPU 计算。【免费下载链接】ops-nn本项目是CANN提供的神经网络类计算算子库实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-nn创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。