赞
踩
引言
此篇推文为昇思MindSpore社区的优质ISSUE,安利给各位小伙伴参考学习,点击下方“阅读原文”即可跳转gitee原文,更多ISSUE详情请查看链接:
https://gitee.com/mindspore/mindspore/issues
概述
UB融合的处理流程如下:
通过Pass匹配待融合的算子,将fusion id设置到node的属性
将匹配到的小算子融合为FusionOp
初始化融合信息,包括确定fusion scope包含的结点、确定输入输出的结点等
检查各个fusion scope是否会成环(调用CheckCircle函数)
编译融合算子,编译失败的fusion scope不做UB融合
对每个fusion scope,先检查是否成环(调用CheckCircle函数),如果不成环则创建融合算子并在原图上进行替换
通过实测来看,CheckCircle函数在UB融合的耗时占比为86%,所以需要对CheckCircle进行优化。
UB融合之前图上是没有环的,但融合之后可能会形成环。如下图所示:
把A、B和C结点融合为E后,E和D形成了环。
优化点
优化点1
从上面的处理流程来看,有二次成环检查:
第一次在算子编译前检查,目的是防止编译耗时太长,通过成环检查提前排除不必要的算子编译,提升性能。从测试数据来看,这个时机的CheckCircle()函数被调用1719次,其中51次成环,成环比例仅为3%,所以这次检查可以删除。
第二次是在每个FusionOp替换之前,这个时机的检查不能删除。
优化方法:删除第一次成环检查。
当前的成环检查,从fusion scope的输入结点(下图中的C和D)开始遍历其前驱结点(下图C和D的前驱都为B)。
如下图所示,先从输入C开始遍历C->B-A,再从输入D开始遍历D->B->A,这样会导致B和A被重复访问。
所以在检查fusion scope时,可以记录访问过的结点,避免重复访问。
当前UB融合的pattern基本都是单输入单输出结构:
根据这个特点可以做一些优化,避免不必要的检查。
如果所有输入都传给fusion scope内的第一个入口结点(下图2个场景中的C结点),则融合后不会形成环,可跳过成环检查。
如果输入传给了不同的入口结点(左图中的C和D)或非首个入口结点(fusion scope内部的结点已排拓扑序,从拓扑序上判断右图的C不是第一个入口结点)则可能成环。
考虑到UB融合pattern的特点和实现复杂度,进行如下判断:如果所有输入都传给fusion scope内的第一个结点,则跳过成环检查。
因为已经做过拓扑排序,所以第一个结点肯定是入口结点。
这个条件太严苛,其他一些场景也可不必检查,考虑到其他场景在UB融合的占比很小,暂不支持。
实测发现满足该条件的fusion scope占比为:1616/1719 = 94%。
如果所有输出都由fusion scope内的最后一个出口结点(下图左侧的B和右侧的C结点)产生,则融合后不会形成环,可跳过成环检查。
如果所有输出由不同出口结点(左图中的B和D)产生或由中间结点(右图中的B)产生则可能成环。
考虑到UB融合pattern的特点和实现复杂度,进行如下判断:如果所有输出都由fusion scope内的最后一个出口结点产生,则跳过成环检查。
实测发现满足该条件的fusion scope占比为:1617/1719 = 94%,与优化点3的占比相同。
验证效果
下表的时间单位:秒。
MindSpore官方资料
GitHub : https://github.com/mindspore-ai/mindspore
Gitee : https : //gitee.com/mindspore/mindspore
官方QQ群 : 486831414
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。