总体优化策略
当前而言,基于一键迁移的方式可以保证GPU的代码迁移到NPU上的代码修改轻量化,但站在性能优化的角度上,社区中的模型代码普遍基于GPU实现,NPU和GPU在计算原理和底层架构上存在非常大的区别,因此,有些时候我们需要进行模型层面的修改,亲和适配NPU,达到最优的性能。性能优化遵循以下大的逻辑:
- 融合算子
融合算子的优化原理为,通过数学意义上的等价替换,将多个算子融为一个算子的计算,减少冗余计算,同时减少下发次数,从而提高性能。
- 消除多余的stream同步
在很多开源代码中,由于作者在编写时很少考虑性能,因此在代码中可能存在增加很多的stream同步操作,这些同步通常是由h2d(host to device,从CPU侧下发到NPU侧)、d2h(device to host,从NPU侧搬回到CPU侧)操作(如tensor.item、reduce_all、torch.isfinite等)引入的,原则上,我们需要尽可能减少这些异步流同步的操作,让模型通过异步流实现最佳的并行效率。
- 有时候因为下发或通信等问题,可能导致多卡训练时,卡与卡之间性能不一致,此时由于反向计算后需要对多卡之间的梯度进行同步,产生快卡等慢卡的情况。性能数据分析时,可以明显观察到部分卡上集合通信算子耗时占比高,这种现象的根因并不是集合通信算子耗时久,而是因为性能快的卡在等待性能慢卡,这种问题,要明确找到快卡和慢卡差异产生的第一位置,这个可以通过性能工具来寻找。
- 部分CPU上运行的优化方法
在mask-rcnn中,模型的mask decode运行CPU上进行,且仅用单核实现,性能不够理想。此时,可以将计算部分放到NPU上,或者在CPU上,通过多进程的方式进行加速。
父主题: NPU亲和适配优化