MLC-Lesson7-GPU硬件加速2
Lesson7 GPU硬件加速2
到目前为止,我们运行的大多数 TensorIR 代码都包含一个 block,用于计算输出张量中的单个元素。现在将我们的目标转向专用硬件,许多专门的加速器在张量区域上运行计算,TensorIR 中的 block 结构帮助我们对此类相关计算进行分组。
7.1 张量化Block
1 |
|
打印出这个 IRModule 的 TVMScript表示:
1 | # from tvm.script import ir as I |
我们注意到这个 block
1 | with T.block("tmm-16x16"): |
这个 block 从 A 和 B 的区域分别读取了16*16,并且向 C 的区域写了16*16。在这个案例中,这个 block 的内容包含了关于子区域计算的特定实现,由于这个 block 包含了跨越张量子区域的计算,我们称这样的 block 为张量化block(tensorized block)。
7.2 Blockization – 创造新的 block
TensorIR 提供了一种变换原语blockization来将循环的子区域组合在一起以形成张量化的计算 block。
示例如下:
1 |
|
1 | sch = tvm.tir.Schedule(MatmulModule) |
输出结果如下:
1 | # from tvm.script import ir as I |
对于这些已经分割的坐标轴,我们可以使用blockize原语将多个块或以特定循环为根的子树转换为块。
1 | # 注意到这里的ii对应于上面TVMScript代码中的i_1 |
结果如下:
1 | # from tvm.script import ir as I |
7.3 变换 TensorIR 以引入特殊内存层级
我们可以使用 cache_read 和 cache_write 来创建中间内存阶段。
这里 global.A_reg 包含两个部分。 global 表示所有线程都可以全局访问内存,而 A_reg 是内存的层级标签,为后续编译映射到寄存器等特殊区域提供了机会。
(这里讲的很抽象,因为没有具体的硬件对应说明,我的理解是申请了类似于cache的存储空间,计算单元拿数据只需要和cache交互,写回也是先写回cache再写回内存)
1 | A_reg = sch.cache_read(block_mm, 0, storage_scope="global.A_reg") |
变换后如下,完整详见[MLC Lesson8 引入特殊内存层级示例.md](MLC Lesson8 引入特殊内存层级示例.md)
1 | # from tvm.script import ir as I |
7.4 张量化
现在我们已经创建了一组映射到 TensorIR 中相应计算阶段的 block。 剩下的步骤是映射一些 block 以使用映射到硬件加速指令的特定实现。 此映射过程称为张量化。
我们首先注册一个张量算子 intrinsic(TensorIntrin),其中包含(1)计算和(2)实现的描述。系统将使用描述找到与计算匹配的相关区域,而实现将计算映射到加速硬件指令。
1 | # 这一段是对算子功能的描述 |
然后我们可以调用 tensorize,将 block_mm(对应于 matmul_o_update block)映射到使用 tmm16 的实现。
1 | sch.decompose_reduction(block_mm, k) |
这里我们使用 T.call_extern 来调用环境中的外部函数。 下游编译步骤可以轻松地将实现映射到实现操作的指令。
或者,我们可以将 tmm16 映射到实现这种张量化计算的微内核。 以下代码显示了如何通过外部 C 代码执行此操作(如果需要,可以进一步嵌入内联汇编)。
1 | def tmm_kernel(): |
