1.优化策略-激活函数替换
- convolution+batchnormalization融合
现如今我们转换onnx格式时会发现 Conv + BN + Activation 的模型结构转换为onnx时会只剩下Conv + Activation的结构,发现BN层并未在onnx结构中显示出来,如下图所示。
究其原因是因为如下图,其中在装换得时候就根据已经训练完成得参数进行数学计算推导得出新得W,B,将其融合与卷积得参数中,就可减少Memory(内存访问)操作,从而提高效率。
但由于最近很多模型会有很多种类的激活函数,比如GELU、Swish、Mish等等,这些激活函数往往由于计算复杂很难被优化加速,经过笔者大量实验验证,替换为简单的RELU激活函数并不会在精度上造成太多的精度损失,反而由于该激活函数只是做一个截取>0的值、内部没有计算,从而会使得模型推理时速度更快。
2.优化策略-onnx-simplifier
过往我们在进行onnx导出操作时会发现一个onnx格式模型中的计算算子增多了,如在进行onnx导出中,torch.flaten操作会产生shape、slice、reshape这一系列的计算节点。是因为它需要将多维张量展平成一维张量。展平操作涉及到以下几个步骤:
- Shape(形状):首先,需要获取输入张量的形状信息,即各个维度的大小。
-
Slice(切片):接下来,根据输入张量的形状信息,需要对每个维度进行切片操作,以便按顺序遍历每个元素。
-
Reshape(重塑):最后,将切片后的每个元素重新组合成一维张量。
由于ONNX是用来表示深度学习模型的中间表示,而不是针对某个具体框架的优化后端,所以需要将各个框架(如PyTorch)中的操作映射到ONNX操作。在PyTorch中,torch.flatten
操作并不是一个原子操作,而是通过一系列的底层操作来实现的。为了保持模型的语义一致性,并能够正确地导出到ONNX格式,需要将这一系列的底层操作映射到相应的ONNX操作节点。
因此,在转换为ONNX格式时,torch.flatten
操作会被分解成shape、slice和reshape等一系列节点,以确保模型的正确性和可移植性。但这样会增加冗余计算,因此我们可进行以下操作使得导出的模型变得更加精简
- pip安装 onnx-simplifier工具包 -->使用该工具包进行onnx模型简化
- model_onnx,check = onnxsim.simplify(model_onnx) -->导入包将onnx模型输入
- assert check,"assert check failed" --> 判断模型简化是否成功
- onnx.save(model_onnx,file) --> 模型保存,file为保存地址