LLM Systems Assignment 1: CUDA Programming
本次作业主要涉及两个文件:
llmsys_hw1/minitorch/cuda_kernel_ops.py:Python 侧调用 kernel 编译成的 .so 接口llmsys_hw1/src/combine.cu:CUDA kernel 实现
完成本次作业的主要预备知识要求是掌握基本的 CUDA 编程能力(如:按照课程 readings 要求完成 PMPP 这本书前 6 章的学习),在此基础上,需要理解课程提供的骨架代码中几个关键的辅助函数。
本文目的就是介绍完成 homework 1 需要理解的几个辅助函数,并不会给出作业具体 solution 代码。
shape & strides tensor 表示
homework 1 对 tensor 的表示基于 shape & strides 布局表示,这一点 homework 1 的官方链接已经有基本解释,网上相关的介绍也非常多,对此不赘述。
这里主要介绍几个完成本次作业需要理解的辅助函数。
index_to_position
1 | |
笔者已经在代码上补充了注释,函数功能和参数说明如下: -
函数功能:将多维 index 坐标表示,基于 strides,计算得到该 index
元素在一维存储空间的偏移量。 - index:与 tensor shape
对应的多维坐标 - position:根据 index & strides
计算得到的存储空间 offset
to_index
1 | |
同样的,上面贴出的代码已经补充了相关注释。解释如下: -
函数功能:给定一个 ordinal (通常由 kernel 内每个 thread
根据 blockDim & threadIdx 计算得到的 global thread
id)作为函数入参以及 tensor shape & dims 作为入参,将 flatten 后的
ordinal 转换为与 shape 的维度对应的多维 index。 - 输入的
shape 数组元素存储顺序为最高维度到最低维度,对于普通的
tensor(直接创建,没有 transpose/permute
等操作),最低维度是内存连续存储的维度(strides[-1] = 1)。 -
代码开头给了一个例子和计算过程,实际上就是 row-major 将元素的 global
index 映射为多维的 index。 - 这个函数通常用于根据 kernel 内某个 thread
的 global id 计算得到其负责处理的元素的多维 index。
broadcast_index
1 | |
这个函数的行为 & 例子同样也已经在注释中详细说明。具体行为请参照上面注释理解。这里简单说明下什么时候该使用这个函数:
- elementwise kernel 一般处理流程
- 根据 blockDim & threadIdx 计算得到 global thread id
- 根据 global thread id 调用
to_index得到当前 thread 负责处理的 output tensor index - 由于可能涉及到广播操作,需要根据 output tensor index
使用广播规则计算得到对应的 input tensor index,也就是通过调用
broadcast_index这个函数实现 - 有了 input tensor index & output tensor index 后,调用
index_to_position接口得到 offset,完成 elementwise 计算写入 output tensor。