cute(1)Layout基础
Ref
1 Layout 基础
对应代码:
01_layout_basics.cu纯 host 代码,不需要 GPU。
核心概念
Layout = Shape + Stride,它是一个函数,把多维坐标映射到一维 offset:
1 | offset = layout(i, j) = i * stride_0 + j * stride_1 |
- Shape:每个维度的大小,如
(4, 3)表示 4 行 3 列 - Stride:每个维度走一步对应的 offset 增量
我们直接从代码来理解,先避开硬核的抽象理解。
代码解析
第 1 节:一维 Layout
1 | // ============================================================ |
1 | auto layout = make_layout(Int<8>{}); // (8):(1) |
- Shape = 8,Stride = 1(默认)
- 含义:8 个元素,相邻元素 offset 差 1
layout(i) = i * 1 = i,最简单的连续排列
1 | layout(0) = 0 |
注意:print_layout 只能用于 rank-2(二维)的 layout。一维 layout 只能用 print() 打印文本形式。
第 2 节:二维 Layout —— Row-Major
1 | // ============================================================ |

1 | auto layout = make_layout(make_shape(4, 3), make_stride(3, 1)); |
(4, 3):(3, 1)= 4 行 3 列,row-major- 行内连续:stride=1(第二维,列方向)
- 行间跳 3:stride=3(第一维,行方向)
1 | offset = i * 3 + j * 1 |
记忆方法:Row-major = 行内连续 = 第二维 stride 为 1,第一维 stride = 列数。
第 3 节:二维 Layout —— Col-Major
1 | // ============================================================ |

1 | auto layout = make_layout(make_shape(4, 3), make_stride(1, 4)); |
(4, 3):(1, 4)= 4 行 3 列,col-major- 列内连续:stride=1(第一维,行方向)
- 列间跳 4:stride=4(第二维,列方向)
1 | offset = i * 1 + j * 4 |
记忆方法:Col-major = 列内连续 = 第一维 stride 为 1,第二维 stride = 行数。
第 4 节:make_layout 默认 Col-Major
1 | // ============================================================ |

1 | auto layout = make_layout(make_shape(4, 3)); // 不给 stride |
CuTe 惯例:只给 shape 不给 stride,默认生成 col-major stride。
这与 C/C++ 的 row-major 习惯不同!使用时要特别注意。
默认 stride 的计算规则是 col-major 前缀积:
- shape = (4, 3)
- stride = (1, 4) ← 第一个是 1,第二个是 1×4=4
第 5 节:嵌套 Shape(层级 Layout)
在torch中我们可以访问tensor的shape属性和stride方法(注意方法调用需要使用带括号形式,即stride())来获取对应的信息。我们不难发现,上面的shape和stride描述其限制了Tensor的每一个轴只能有一个stride值,也就是说,整个tensor在某一个维度上的连续性关系是不能变的,更形象地描述则为:Tensor不可以分块。我们将这样轴的连续性不可变更,体现为Tensor不可以分块的描述称为单调Tensor描述。而当我们处理复杂的Tensor计算问题时,尤其是如NVidia硬件引入的指令计算时,这种表示是不充分的。由此则引入了有层次的Tensor描述,即Heriarchy Layout。简单地理解,有层次的Tensor(或者Layout)就是以原有的单调Tensor所描述的小块作为基础单元,将其组成Tensor。这样原有的小块是Tensor,小块作为单元的外部组织也是Tensor,实现了Tensor套Tensor,这就是所谓的有层级的Tensor了。而其坐标到实际物理位置的映射关系则就是其Layout,Tensor有了层次,Layout也就有层次了。
这里引用reed博士的图片

shape和stride给出了Tensor的逻辑空间描述和映射到物理空间时的间隔描述,当根据逻辑空间的位置获得物理空间位置时,依然和传统的Tensor计算规则一样,采用coordinate和stride点积即可,只不过坐标也采用heriarchy表达即可。
通过以上两个有层次Tensor的shape和stride的分解和组合,我们可以完成有层次的Tensor的组合,其突破了传统的Tensor轴只能有一个stride的限制,可以表达更丰富的Tensor(有层次的Tensor)。
总结一下,shape的表示规则可以这样理解:
((内部行数,外部行数1, 外部行数2,…),(内部列数,外部列数1,外部列数2,…))
1 | // ============================================================ |

1 | auto layout = make_layout(make_shape(make_shape(2, 3), 4)); |
Shape = ((2, 3), 4),第一维由 (2, 3) 两个子维度组成(逻辑上 2×3=6 个位置),第二维 4。
关键规则:stride 的结构必须和 shape 一一对应。
1 | shape = ((2, 3), 4) |
常见错误:
1 | // 错误!shape 是嵌套的 ((2,3), 4),stride 不能是 flat 的 (s1, s2) |
另一个陷阱:C++ 中 (2, 3) 是逗号表达式,结果是 3 而不是 tuple。必须用 make_shape(2, 3) 来创建嵌套结构。
第 6 节:Layout 的常用属性
1 | auto layout = make_layout(make_shape(4, 8), make_stride(8, 1)); |
| 函数 | 含义 | 示例值 |
|---|---|---|
shape(layout) |
每维大小 | (4, 8) |
stride(layout) |
每维步长 | (8, 1) |
size(layout) |
总元素数 = 各维大小之积 | 32 |
rank(layout) |
维度数 | 2 |
cosize(layout) |
覆盖的地址空间大小 = max_offset + 1 | 32 |
size vs cosize 的区别:
1 | auto sparse = make_layout(make_shape(2, 2), make_stride(1, 8)); |
当 stride 不紧凑时,cosize > size,中间有"空洞"。
第 7 节:一维索引 vs 多维索引
Layout 可以用一维 index 访问,CuTe 会按 col-major 展开:
1 | auto layout = make_layout(make_shape(3, 4), make_stride(4, 1)); |
展开顺序是先填满第一维,再进入第二维:
1 | layout(0) = layout(0,0) = 0 |
注意:一维展开顺序始终是 col-major,与 layout 本身是 row-major 还是 col-major 无关。这是 CuTe 的固定约定。
易错点总结
| 问题 | 解决方法 |
|---|---|
make_layout(shape) 默认是什么 |
Col-major,不是 row-major |
(2, 3) 在 C++ 中是什么 |
逗号表达式,值为 3。要用 make_shape(2, 3) |
| 嵌套 shape 配什么 stride | stride 结构必须和 shape 一一对应 |
print_layout 报错 |
只支持 rank-2 layout,一维用 print() |
| 一维 index 的展开顺序 | 始终 col-major:先填第一维 |
- 标题: cute(1)Layout基础
- 作者: 鱿鱼圈
- 创建于 : 2026-06-06 22:13:32
- 更新于 : 2026-06-14 23:33:01
- 链接: https://yuyanqi.com/2026/06/06/cute(1)Layout基础/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。