Skip to content

Latest commit

 

History

History

compute_graph_optimize

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 

计算图优化

例如LayerNorm本身为一个算子,但是ONNX导出会拆分为很多细小的算子,则必须用图优化将其合并回去。又比如ONNX不支持NHWC等数据格式,但是硬件部署往往又需要转换到硬件优化的NHWC或其他数据格式。另外,根据引擎和芯片的特殊性,往往也需要对模型进行一些针对性修改优化,例如一些引擎不支持超过5D的transpose计算。

如何做图优化?

  • 第一个阶段在线优化,是直接对代码(网络的forward)进行修改,从而导出的模型直接具有优化后的特性。对于一些算法依赖,通用性并不是很强,或者底层实施图优化困难的优化可以考虑该方法。
  • 第二个阶段离线优化,是对导出的模型进行优化,例如对导出的ONNX模型进行优化。一般离线优化前可使用推理引擎如TensorRT进行 layer info profile,看看 layer 的融合情况,再针对性优化onnx 。
  • 第三个阶段是在深度学习引擎内部运行时进行优化,可以结合硬件特点和输入shape对应的性能信息进行更加针对性和极致的优化。第三阶段一般也可在第一阶段执行后执行辅助分析,给第二阶段提供参考。

常见场景

  • OneHot+MatMul to Gather

  • focus

  • permute + conv [+ permute]

  • 多个gather可以替换为split split adjust

  • 统一归一化函数
    其实由F.normalize(x, p=2.0, dim=-1)导出,可以进行针对性合并。第二个图计算跟第一个图类似,但是为不同代码编写方式,这种最好是修改模型pytorch代码改成同一种norm函数,降低模型图优化代码开发。

  • SpaceToDepth与DepthToSpace算子
    图中reshape+transpose(perm=[0, 1, 3, 5, 2, 4])计算等价于SpaceToDepth,由于transpose场景特别多,这里替换后可以在计算上进行更加针对性优化,此外,这个优化使得做NCHW到NHWC等格式转换优化也更加容易,transpose(perm=[0, 1, 4, 2, 5, 3])等价于DepthToSpace

  • transpose+reshape+transpose to transpose

  • high-mm -> low-mm

  • Linear + LayerNorm --> Matmul + Add + LayerNormalization

  • 矩阵乘+BN 融合

  • 反卷积+BN 也应该能进行融合

  • 合并相邻的Conv2D或MatMul,无非线性层 conv + conv (without non-linear op)

  • 相邻的卷积/matmul+bias,中间没有非线性层的话可以基于卷积和矩阵乘的线性性直接合并 conv + linear (without non-linear op)

  • 特殊的1x1 depthwise卷积替换为elemwise

  • MatMul与Add, Mul向量计算融合

  • LayerNorm算子合并

  • squeeze unsqueeze 去除

  • reshape去除

  • 多路相同计算patten合并为batch计算,显著降低算子数量,提升算子计算密集性
    如图的场景;此外另一个场景是transformer模型中attention三个矩阵乘合可以并成为batch matmul,或者自己实现的特殊能够同时接受多个输入和bias的矩阵乘。

  • 多路并行的slice在特定情况下可以换成gather,并且后面所有的这些elemwise都可以合成一路计算。
    下图中这个稍微复杂点,slice可以替换为gahter,elemwise可以跟着合并,但gatherV2合并需要自定义算子batch gatherV2。

  • 调整顺序从而把div折叠到matmul和bias_add参数里面
    通常不鼓励矩阵和大容量内存拷贝的物理重排的原因是,数据移动非常昂贵(在能量和性能方面),因此应将其最小化,理想情况下应仅作为计算的一部分进行。
    换句话说,每次我们接触一些数据时,我们都想在存储之前对其进行一些变换。