深度学习框架随想(一):Op与Kernel
https://zhuanlan.zhihu.com/p/100418869?utm_source=com.slack
在深度学习框架中,Op和Kernel是非常重要的两个概念。以TensorFlow为例,我们有"MatMul" op,有"Conv2D" op,有"Matmul" kernel,也有"Conv2D" kernel等。
那么到底什么是Op?什么是Kernel?他们的定义是什么呢,他们之间的区别又是什么?我来分享下我的理解。
先来看看Kernel。
什么是Kernel?Kernel其实就是对Tensor进行操作的一个函数,一段计算逻辑,Tensor In Tensor Out。
对于一些简单的Kernel(如"Add")来说,其是一个纯函数。但对于一些复杂的Kernel来说,其可能需要初始化一些状态,也有可能拥有一些中间状态需要保存,所以其就不是纯函数。因此,在TensorFlow中,用 Class 的形式来表现Kernel,方便存储中间状态。
那么什么是Op呢?我理解Op就是Kernel的集合,一个Op代表的是有一定共性的多个Kernel。
举例而言,在TensorFlow中,“MatMul” op对应的kernel是 class MatMulOp<Device, T, USE_CUBLAS>。这个模板类的每一个全特化对应的都是一个真正的kernel,所以在"MatMul" op这个概念之下,其实有着很多的kernel。例如CPU实现的针对于float数据类型的kernel(三个模板参数是 kCPU, float, false ),GPU上使用cublas实现的针对float的kernel(kGPU, float, true),GPU上不用cublas实现的针对half数据类型的kernel(kGPU, half, false)等等。
虽然在计算图上我们是用Op来表示一个个的节点,但实际上,计算图上的每个节点代表的一个Kernel。因为在计算图上我们除了存储Op本身的配置属性之外,还存储了一些额外的属性(如Device、DataType等)。基于Op的配置和这些额外的配置,我们可以确切的为每个节点找到唯一一个对应的Kernel。
为什么要在Kernel上抽象出一层Op?因为Kernel太多太杂了,为了简化图分析的复杂性,我们按照某种规则去合并多个Kernel,并在图分析时把多个Kernel看作一个,命名为Op,然后去处理。
而关于具体按照哪种规则来把多个Kernel合并为一个Op,其实并没有一个固定的答案。
以Conv为例,理论上来说,我们可以把"Conv1D"、“Conv2D"和"Conv3D"共3个op合并成一个"Conv” op,然后在"Conv" op的配置中让用户选择1D、2D还是3D的卷积操作。
我也可以把"Conv2D" op拆成很多个op,例如"CpuConv2D", “GpuConv2D”, “CpuConv2DForFloat”, "GpuConv2DForHalf"等等,使得每个op都只对应更少(甚至只有一个)kernel。
所以,一个Op对应几个Kernel,其实都并没有一个明确的答案,更像是框架开发者的个人喜好。
我个人而言的话,有一条不是那么严格的原则:如果在图分析阶段需要针对与某一个或多个Kernel进行处理,那就把它们抽出来当成一个Op,否则的话就不要把这些Kernel暴露在图分析阶段,以简化分析复杂度。