本文共 2222 字,大约阅读时间需要 7 分钟。
上回说到CreateExecutors中有两个分支进行图优化,一个执行的是GraphOptimizer父类的优化,另一个执行的是子类的图优化。上一篇介绍了父类优化中的CSE,这篇介绍一下子类优化的流程
一、优化流程
每种优化子类继承自父类GraphOptimizer,而且与父类有完全不同的执行过程。其中MetaOptimizer虽然也是优化子类,但是并没有实现一种特定的优化,而是作为一个管理子类,统一完成其他所有子类的优化操作。
从入口CreateExecutors函数开始,优化的时序简要描述如下:
CreateExecutors函数中调用CreateGraphs-->创建或获取GraphExecutionState实例,调用其BuildGraph方法-->调用OptimizeGraph-->调用grappler::RunMetaOptimizer-->RunMetaOptimizer函数是grappler命名空间中的一个接口方法,实例化MetaOptimizer,调用其Optimize方法-->调用OptimizeGraph-->调用InitializeOptimizers根据ConfigProto将优化子类实例化,放到vector中-->遍历vector调用所有实例的Optimize方法完成优化
以上流程中,根据ConfigProto将子类实例化,是否启用优化可以在前端显式的配置,优化默认是否开启有个技巧,Rewrite proto中定义Toggle ,DEFAULT是0,ON是1, OFF是2,ConfigProto中没有设置,则默认是0,也就是DEFAULT,在实例化时,如果要默认开启,则判断!OFF时实例化子类,若要默认关闭,则判断是ON时实例化子类。
遍历vector之外还有一层for循环,用来控制重复进行优化,如果没有设置,则默认重复优化两次,因为有些优化执行一遍后,计算图会发生变化,可能有些新的结构依旧可以进行优化,如果只想优化一次,那么可以在IsRunOnceOptimizer方法中加入判断。
二、Remapper优化
这些子类中,将看过的记录一下,Remapper优化的目的是将FusedBatchNorm节点拆开,展开成由加法、乘法等节点组成的子图,目的不详,添加优化的仁兄可能通过验证发现FusedBatchNorm节点计算效率不如拆开算的快。
实现过程很直觉,一共两步,第一步判断拆开的合法性,比如获取静态推断计算图,获取节点的输入属性,如果输入节点中有多余4个节点是const类型(如果有值就是const类型,4个节点是FusedBatchNorm的超参数);若合法,则按照规则将FusedBatchNorm节点拆成小节点添加到计算图中,FusedBatchNorm也就可以删掉了。batchnorm拆开的子图结构之前有画过,我以为有保留结果找不到了,o(╥﹏╥)o 不过将拆分的代码梳理一遍就可以画出子图,之前经过代码和图的对应,确实是一致的。
三、Layout
这个是针对GPU的一个优化,对于支持data format属性的节点来说,在使用GPU设备时,NCHW格式计算更快,但是可能有些节点data format属性设置为NHWC,因此GPU设备在进行计算图调度前,会执行一遍图优化来进行自动转化,提升计算的效率。下边的例子是之前做的逆过来将NCHW转化为NHWC的优化,原理一致,懒得重新画图。
以卷积Conv节点为例,
在上图中,通过在Conv节点前后加入Transpose节点来转换输入数据,Transpose节点的作用是将Tensor的维度转换,“NCHW”对应0 1 2 3四个维度,将数据转换为“NHWC”格式,需要将输入Tensor的第1维度放在最后,这也是图中(0,2,3,1)的含义。将Conv节点的data_format属性设置为“NHWC”,以及其他相关的属性修改,对于不同类型的节点,还会有不同的个性化转换要求,需要在Conv节后点再加一个Transpose节点,以保证最终的输出与原输出完全一致。
但并非所有的节点都有data_format属性,第一次遍历图将所有具有data_format属性的节点完成转换,如果图中至少有一个节点发生了转换(即图中节点数增多),则需要第二次遍历图,对没有data_format属性的节点进行同样的转换。由于图4.10的转换方式会导致一个节点变成三个节点,这样节点数大量增加,因此需要策略来减少增加的节点,第二次遍历图的转换就可以实现节点的缩减,对没有data_format属性的节点也使用 Transpose来做转化,会出现相邻且互逆的Tranpose节点对,这样的节点对可以直接去掉,节点缩减的原理示意如下图所示。
上图左侧的模型,Conv节点有data_format属性,因此第一次遍历图需要将Conv节点进行转换,Add节点没有data_format属性,如果整个图都没有data_format属性节点,则图不需要第二次转换,但由于Add节点之前有Conv节点,因此需要将Add节点也进行转化,转化后的图如上图中间的模型,由于两个Transpose节点是互逆操作,因此可以在第三次遍历图时,将这种两个相连的Transpose节点全部删掉,这也就完成了图的缩减,减少了由于图转化带来的额外开销,如上图右侧的模型。
转载地址:http://vqhzb.baihongyu.com/