CUTLASS-Cute 初步(2.1):Tensor & Layout 实操笔记

1. local_tile

给定一个 tiler,使用 local_tile 函数,将 Tensor 按 tiler 的 shape 切分成多个 tile。由于切分之后,每个 tile 保留输入 Tensor 的stride信息,以及rest modeshape,故称为Inner-Partition

1.1. 示例一:常规使用(常规 CTA 切分)

比如有一个 4x6 的 Tensor,将其切分并分配到 thread block,每个 thread block 获取到的 tile 大小为 (2,2),当前 thread block 的 coord 为 (1,1),就可以使用如下代码:

  constexpr int M = 4, N = 6;
  auto layout = cute::make_layout(cute::make_shape(M, N), cute::make_stride(N, cute::Int<1>{}));
  auto tensor = cute::make_tensor(h_data.data(), layout);

  constexpr auto tiler = cute::make_shape(cute::Int<2>{}, cute::Int<2>{});
  constexpr auto coord = cute::make_coord(1, 1);  // 第(1,1)块(0-indexed)
  auto tile = cute::local_tile(tensor, tiler, coord);

  cute::print(tile);

输出:

ptr[32b](0xaaaafc5faa38) o (_2,_2):(6,_1)

图示如下:

case01

1.1.1. 输入 Tensor 轴数量多余于 tiler 的轴数量

下面测试输入 Tensor 轴数量多余于 tiler 的轴数量。测试代码:

  constexpr int M = 4, N = 6, K = 8;

  auto layout = cute::make_layout(cute::make_shape(M, N, K), cute::make_stride(N * K, K, cute::Int<1>{}));
  auto tensor = cute::make_tensor(h_data.data(), layout);

  constexpr auto tiler = cute::make_shape(cute::Int<2>{}, cute::Int<2>{});
  constexpr auto coord = cute::make_coord(1, 2);

  auto tile12 = cute::local_tile(tensor, tiler, coord);
  cute::print(tile12);

输出:

ptr[32b](0xaaab0eebc6f0) o (_2,_2,8):(48,8,_1)

1.1.2. 总结

local_tile的逻辑是:首先使用zipped_divide将输入 Tensor 切分,比如 输入 Tensor:(4,6,8):(48,8,1),使用 tiler(2,2)切分,得到:zipped_divide得到的结果是((_2,_2),(2,3,8)):((48,8),(96,16,_1))。 其中(_2,_2)表示每个 tile 的 shape 是 (2,2),(2,3,8)表示每个 tile 的 rest mode shape 是 (2,3,8),(48,8)表示每个 tile 的 stride 是 (48,8),(96,16,_1)表示每个 tile 的 rest mode stride 是 (96,16,_1)。最后根据 coord 获取对应的 tile。

zipped_divide返回一个 rank-2 的 tensor:

([tile mode], [rest mode])
顶层 mode 内容 含义
tile mode (mode-0) (_2,_2):(48,8) 一个 tile 内部的坐标系:2×2 个元素,stride 保留自原 tensor
rest mode (mode-1) (2,3,8):(96,16,_1) tile 外部的坐标系:有多少个 tile,以及未被切分的 trailing 维度

“rest”的字面意思是剩余,指”tile 坐标系之外剩下的所有东西”:

  • 已切分维度的块编号(你选哪一块?→ 2 个 M 块 × 3 个 N 块)
  • 未切分维度的完整范围(K=8 没有被 tiler 动过,直接挂在 rest 末尾)

如何切分,与 stride 没有关系,即选择前两个轴来切分,不是依照 stride 来选择轴(即与内存布局没有关系)。

完整测试代码:https://github.com/HPC02/cuda_perf/blob/master/src/study_codes/study_tests/test_local_tile.cu中的 Case03。

1.2. 示例二:在 coord 中使用 cute::_,得到该轴方向上的 tile 集合

使用cute::_作用于 coord 中的某个轴,其含义是获取该轴方向上的 tile 集合,即在该轴方向上,生成新的 trailing mode。示例代码如下:

  constexpr int M = 4, N = 6;

  auto layout = cute::make_layout(cute::make_shape(M, N), cute::make_stride(N, cute::Int<1>{}));
  auto tensor = cute::make_tensor(h_data.data(), layout);

  constexpr auto tiler = cute::make_shape(cute::Int<2>{}, cute::Int<2>{});
  constexpr auto coord = cute::make_coord(0, cute::_);

  auto tile00 = cute::local_tile(tensor, tiler, coord);  // (tileM, tileN, k)
  cute::print(tile00);

输出:

ptr[32b](0xaaaafd59bed0) o (_2,_2,3):(6,_1,_2)

从结果看到,在第二个轴上使用 slice 操作符,shape 中的最后一个轴 3 表示在该轴上有 3 个 tile。

完整测试代码:https://github.com/HPC02/cuda_perf/blob/master/src/study_codes/study_tests/test_local_tile.cu中的 Case04。

1.3. 示例三:tiler 中使用 Step筛选 tiler 以及 coord,使用 cute::X 标记的轴不参与切分

Step 本质上是一个轴选择器,筛选出需要的 tiler 以及 coord,使用 cute::X 标记的轴不参与切分。

  constexpr int M = 4, N = 6, K = 8;
  constexpr auto problem_shape = cute::make_shape(M, N, K);

  auto stride_A = cute::make_stride(K, cute::Int<1>{});
  auto layout_A = cute::make_layout(cute::select<0, 2>(problem_shape), stride_A);
  auto tensor_A = cute::make_tensor(h_data.data(), layout_A);

  constexpr auto tiler = cute::make_shape(cute::Int<2>{}, cute::Int<2>{}, cute::Int<4>{});
  constexpr auto coord = cute::make_coord(0, 0, cute::_);

  // tile_A (tileM, tileK, k)
  auto tile_A = cute::local_tile(tensor_A, tiler, coord, cute::Step<cute::_1, cute::X, cute::_1>{});
  print_tile(tile_A);

输出:

ptr[32b](0xaaaafe0c3860) o (_2,_4,2):(8,_1,_4)

即得到一个 MK 方向的 tile(2, 4) 的集合,K 方向上有两个 tile,这两个 tile 在 M 方向上坐标为 0(划分成 2*2 个分块)。

另外,在 cute::Step<> 中使用 cute::X 标记的轴不参与切分,例如:

// tiler rank=2,Step<_1,X> 表示只切第0维,第一维整体保留
local_tile(tensor, make_shape(Int<2>{}), coord_m, Step<_1, X>{});

A. 资料




    Enjoy Reading This Article?

    Here are some more articles you might like to read next:

  • al-folio 模板定制修改总结
  • al-folio 本地部署记录(Ubuntu 24.04)
  • C++ Traits
  • 道格拉斯-普克算法(Douglas–Peucker algorithm)
  • CMake支持库收集