您的位置 首页 PyTorch 教程

PyTorch 源码浅析(二)

PyTorch入门实战教程

TensorApply宏

如同作者注释所言,tensor apply系列的宏的机制如下

  • 从最外部的角标开始,循环至第一个发生内存不连续的地址,然后将其记为张量A,A所在的内存都是连续的,把剩下的记为B。
  • 然后接下来有限对B从最外面的角标进行遍历,而对于A由于内存本身就是连续的,我们直接这一整块内存进行遍历
  • 然后为了减少循环嵌套,将A中在内存上连续(具体来说就是和stride乘积相等)的维度组合到一起。

注释原文如下

具体实现暂且不表,我们讲讲这写宏要如何使用,我从 THTensorMath.c 里选了一个cadd函数来举例子

这里cadd的作用是遍历张量t和src中的元素,将src中的元素乘以value之后加上t中的元素赋值给r_。

这个函数首先会确认t和r_的大小,如果r_没有声明是一个空指针,THTensor_(resizeAs)函数会按照t的大小分配一块新的内存给r_这个指针。if的第一段暂且不说,这是为了增加向量化操作而写的代码,我们先看通用的TH_TENSOR_APPLY3这个宏。这个宏的声明如下

后面的数字3是说这个宏会对三个张量进行遍历。TYPE分别是各个TENSOR对应的类型名称,CODE是你想要进行的操作。例如在这里三个张量分别为r_,t,src,那么他们在循环中对应的元素指针为其名称后加_data后缀,分别为r__data,t_data, src_data。所以上面cadd函数中的这段代码的意思就是遍历相同大小的r_, t, src然后应用代码

这类似于一些多维数组库里的map函数,一般来说一个map函数大约长这样,由于CUDA部分是有C++的,后面就会发现在CUDA部分THC库里面大约是按照map函数的思路来封装的,而不再使用宏。

CPU上的向量化操作

刚刚在cadd函数里还有一段代码,是有关于向量化操作的。很多CPU都提供了向量化指令(SIMD),这包括AVX, AVX2, SSE等等。通过支持向量化操作可以使得你的计算速度获得很大的提升(具体提升视数据类型,所占位数而定,因为寄存器的大小是固定的)。不同的CPU型号所支持的向量化指令集可能有所不同。PyTorch在支持不同CPU上使用了多重派发的方法,在运行时会自动根据当前所能使用的指令对向量化函数进行分配。在无法获得SIMD指令支持的时候会自动退回到普通的实现上。

我在支持复数的过程中简单地实现了一些对复数的SIMD指令操作,详见我的Github: CSIMD

具体还是举例说明

以上对于fill这个操作,实现了NEON,PPC64,AVX,SSE2,SSE3,SSSE3,SSE4指令的支持,其具体实现分别在THVector_(fill_ARCH)里,这里ARCH代表具体的SIMD指令型号。在编译时会编译所有支持的指令,但是具体使用时会按照以上的声明顺序进行调用,ARCH为DEFAULT的函数是默认实现,没有向量化支持,优先级最低。

具体如何使用SIMD指令由于指令集不同,并且读了指令集文档之后使用起来并不困难,不做介绍。

到了具体在表达式中使用时,PyTorch实现了另外一个宏,它会将内部的操作用向量化指令加速,然后再使用openmp的轻量级线程进一步加速。

这个宏内已经完成了openmp的相关操作,所以在使用的时候非常方便,非常顺滑。

CUDA张量后端THC

THC除了使用之前提到的通过C的宏命令产生泛型的方法以外,还使用了cmake命令进行简单的代码生成。一般来说一个THC的部分会有四个部分组成:C头文件 xxx.h,C源文件 xxx.c,CUDA C++头文件和源文件 xxx.cuh, xxx.cu.

THC中重新对存储在GPU上的张量进行了定义,分别为THCStorage和THCTensor。其结构类似于TH中的结构,但是注意在Copy的实现上,THCStorage的copy是依赖于THCTensor的,而非TH中THTensor依赖于THStorage。

类似于TH中,为了实现元素遍历,在THC中实现了几个reduce函数用来完成类似于TH_TENSOR_APPLY宏的操作。但是这里更专业一些。

这一部分放在下一篇文章吧。完了讲完这个再说sparse部分和python胶水那部分。去吃饭了。

源码浅析系列目录

PyTorch 源码浅析(一)

PyTorch 源码浅析(二)

PyTorch 源码浅析(三)

PyTorch 源码浅析(四)

文章来源:罗秀哲知乎专栏

本站微信群、QQ群(三群号 726282629):

PyTorch入门实战教程

发表回复

您的电子邮箱地址不会被公开。

返回顶部