MindSpore 静态图网络编译性能优化--使用HyperMap优化编译性能

1. MindSpore静态图网络编译性能优化的前因

网络执行过程的时间主要由编译耗时与运行耗时两个组成,
在推理的时候,编译耗时远大于运行耗时, 因此减少编译耗时势在必得
且优化编译性能对于提升网络在实际应用时的部署效果有着极为重要的意义

2. MindSpore静态图网络编译性能优化的方法

  1. 使用HyperMap优化编译性能
  2. 使用Select算子优化编译性能
  3. 使用编译缓存优化编译性能
  4. 使用vmap优化编译性能

3. 使用HyperMap优化编译性能

使用HyperMap等价语义替换for, 也是优化编译性能的一种方式,下面介绍HyperMap的用法
HyperMap API介绍:

  • 对输入序列做集合运算。
  • 对序列的每个元素或嵌套序列进行运算。与 mindspore.ops.Map 不同,HyperMap 能够用于嵌套结构。

参数:

  • ops(Union[MultitypeFuncGraph , None]) - ops 是指定运算操作。如果 ops 为 None ,则运算应该作为 HyperMap 实例的第一个入参。默认值为 None 。
  • reverse (bool) - 在某些场景下,需要逆向以提高计算的并行性能,一般情况下,用户可以忽略。reverse 用于决定是否逆向执行运算,仅在图模式下支持。默认值为 False 。

输入:

  • args (Tuple[sequence]) -
  • 如果 ops 不是 None ,则所有入参都应该是具有相同长度的序列,并且序列的每一行都是运算的输入。
  • 如果 ops 是 None ,则第一个入参是运算,其余都是输入。

输出:

  • 序列或嵌套序列,执行函数如 operation(args[0][i], args[1][i]) 之后输出的序列

MultitypeFuncGraph 的API介绍:

  • MultitypeFuncGraph是一个用于生成重载函数的类,使用不同类型作为输入。使用 name 去初始化一个MultitypeFuncGraph对象,然后用带有输入类型的 register 注册器进行装饰注册类型。这样使该函数可以使用不同的类型作为输入调用,一般与 HyperMap 、 Map 结合使用。
    参数:

name(str) - 操作名。

  • read_value (bool, 可选) - 如果注册函数不需要对输入的值进行更改,即所有输入都为按值传递,则将 read_value 设置为 True 。默认值: False 。
  • 在使用for循环批量处理列表元素时,可以通过HyperMap等价语义替换来优化网络编译性能。
import time  
from mindspore.ops import MultitypeFuncGraph, HyperMap  
from mindspore import ops, Tensor  
import mindspore as ms  
    
add = MultitypeFuncGraph('add')  
@add.register("Tensor", "Tensor")  
def add_Tensor(x, y):  
    return ops.add(x, y)  
    
add_map = HyperMap(add)  
list1 = [Tensor(i) for i in range(200)]  
list2 = [Tensor(i) for i in range(200)]  
@ms.jit  
def hyper_map_net():  
    output = add_map(list1, list2)  
    return output  
    
start_time = time.time()  
output = hyper_map_net()  
end_time = time.time()  
print("hyper map cost time:", end_time - start_time)  
    
@ms.jit  
def for_loop_net():  
    out = []  
    for i in range(200):  
        out.append(i+i)  
    return out  
    
start_time = time.time()  
for_loop_net()  
end_time = time.time()  
print("for loop cost time:", end_time - start_time)  

4. 结果分析

虽然HyperMap和MultitypeFuncGraph都支持Ascend GPU CPU,
但是上面的示例在Ascend GPU和CPU上的执行结果不一样, 很神奇的是Ascend GPU上使用HyperMap代替for循环反而性能更差
所以,若是HyperMap只适用于CPU,案例中还是要添加说明会好一点
Ascend:
cke_3298.png
GPU:
cke_9006.png
CPU:
image.png
从CPU上的结果看,是比较符合预期的, 编译性能确实提升了不少。
cke_381250.gif
cke_379152.gif