如果在模型编译过程中发现step=1的耗时很长,可分析模型编译是否能进行性能优化。
MindSpore静态图模式下,部分场景可以通过改变网络写法,使用等价语义替换,或者设置编译选项改变编译机制来优化网络编译性能。
1 规避动态shape来优化编译性能
当step = 1和step != 1的耗时差不多且都很慢时,可能网络在进行多次编图。可能原因为:网络中存在动态shape。
- 网络多次编图的判定方法
- export GLOG_v=1, 开启mindspore的info日志
- 开始训练,只需要训练几个step即可
- 在训练日志中grep “Start compiling” 和grep “End compiling”,正常只有一次Start和End。如有多次则网络在多次编图,考虑图中存在动态shape
- 动态shape的判定方法
当前只能通过打印网络中输入,看是否动态变化来判定网络是否为动态shape。
之后将推出动态shape判定工具。
2 优化编图来优化编译性能
2.1 使用Select算子优化编译性能
当图中存在控制流算子时,网络会被切分成多个执行子图,子图间进行流程跳转和数据传递造成模型编译慢。
当分支中算子数量较少时,可通过使用Select算子来替换控制流算子,达到优化编译性能。当分支中算子数量较多,建议保留使用if语句。
示例代码:
if语句代码:
if ms.ops.reduce_sum(object_masks) == 0:
stage2_loss = stage2_loss.fill(0.0)
修改为使用select代码:
stage2_loss = ms.ops.select(ms.ops.equal(ms.ops.reduce_sum(object_masks), 0), stage2_loss.fill(0), stage2_loss,)
具体可参考:使用select算子优化编译性能
2.2 使用vmap优化编译性能
mindspore.vmap(` *fn* `, ` *in_axes=0* `, ` *out_axes=0* `)
自动向量化(Vectorizing Map,vmap),是一种用于沿参数轴映射函数 fn 的高阶函数。由于自动向量化并不在函数外部执行循环,而是将循环逻辑下沉至函数的各个原语操作中,可获得更好的性能
在处理无依赖关系的批量数据且相关的算子支持vmap功能时,可以使用vmap替代for循环处理批量数据来优化编译性能。
具体可参考:
2.3 使用HyperMap优化编译性能
HyperMap是一个特殊的类,类对象构造时需要传入映射函数f,调用对象时需要传入f的n个参数序列,更多使用方法见:HyperMap。映射函数f必须是MultitypeFuncGraph类型, 可参考MultitypeFuncGraph。
在使用for循环批量处理列表元素时,可以通过HyperMap等价语义替换来优化网络编译性能。
具体可参考:HyperMap替换for循环代码来优化编译性能样例
3 使用编译缓存优化编译性能
编译缓存的本质是存储了网络模型的编译中间过程文件,当网络模型不变时,生产的编译中间过程文件也是一样的,因此可以复用上一次编程产生的中间过程文件。
mindspore在模型编译过程中会生成kernel_meta
等缓存文件。
在进行训练或者推理时,如果某个网络结构未作任何变更,那么可以通过使用编译缓存来缩短编译时间。
方法1:
脚本中可不删除kernel_meta
等缓存文件。
方法2:
设置set_context(enable_compile_cache=False)
来优化编译性能。
具体可参考:使用编译缓存优化编译性能