一个智慧城市项目中,我们需要将一个DeepLabV3+语义分割模型部署到Atlas 200I DK A2开发板上,用于实时街景解析。该模型结构复杂,包含大量卷积、批归一化(BatchNorm)和激活函数层。在最初的PyTorch模型转MindSpore并直接使用Pynative模式推理时,发现单张图片的推理延时高达500ms以上,无法满足实时性要求。

MindSpore提供了两种执行模式:动态图模式(Pynative Mode)和静态图模式(Graph Mode)。动态图模式便于调试,但性能并非最优。静态图模式在执行前会将整个模型编译成一幅计算图,从而有机会进行深度的图级优化,其中最关键的技术之一就是算子融合(Operator Fusion)。算子融合将多个细粒度的算子合并成一个粗粒度的算子,从而减少了内核启动次数和设备内存访问,极大地提升了计算效率。

二、算子融合的原理与在分割模型中的应用

1. 融合原理:

以经典的Conv2D-> BatchNorm-> ReLU序列为例。在未融合的情况下,前向推理需要依次执行三个算子的内核:

  1. 卷积计算。
  2. 应用批归一化的缩放和平移。
  3. 进行ReLU非线性激活。

这三个步骤需要三次内核启动和多次中间结果的读写。算子融合技术则可以在图编译阶段,将这三个算子的计算过程合并为一个复合算子的计算过程。它通过数学推导,将BatchNorm的参数(γ, β)与卷积层的权重和偏置进行融合,并提前计算好新的权重和偏置,然后将ReLU的截断操作内联。最终,在设备上只需要启动一个融合算子内核,一次性完成所有计算。这显著降低了内核启动开销和内存带宽压力。

2. 在模型中的实现:

MindSpore的Graph Mode在默认情况下会自动尝试进行算子融合。但模型的结构设计会影响融合的效果。为了最大化融合收益,我们应尽量使用MindSpore提供的标准Cell来构建模型。

  • 初始问题代码(融合不友好):
import mindspore.nn as nn

class InefficientBlock(nn.Cell):
    def __init__(self, in_channels, out_channels):
        super().__init__()
        self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=3, has_bias=True)
        self.bn = nn.BatchNorm2d(out_channels)
        self.relu = nn.ReLU()

    def construct(self, x):
        x = self.conv(x)
        x = self.bn(x)
        x = self.relu(x)
        return x
  • 这种写法虽然清晰,但三个算子是独立的,给图优化器提供了明确的融合边界,效果已不错。但还有更优写法。
  • 优化后代码(推荐,最大化融合机会):
  • MindSpore提供了nn.Conv2dBnAct这样的预融合Cell,它是为融合而设计的。
class EfficientBlock(nn.Cell):
    def __init__(self, in_channels, out_channels):
        super().__init__()
        # 使用Conv2dBnAct,一个Cell封装了Conv、BN和Activation
        self.conv_bn_relu = nn.Conv2dBnAct(in_channels, out_channels, kernel_size=3,
                                          has_bn=True,  # 开启BN
                                          activation='relu')  # 指定激活函数为ReLU

    def construct(self, x):
        return self.conv_bn_relu(x)
  • 使用nn.Conv2dBnAct等高级Cell,从源码层面就表达了“这是一个融合单元”的语义,使得MindSpore的图优化器能更安全、更彻底地应用融合优化。
三、效果验证与性能对比

我们对使用InefficientBlock构建的原始模型和使用EfficientBlock重构的优化模型进行了对比实验。

  1. 图结构对比:​ 使用MindSpore的graphviz工具导出计算图。可以清晰地看到,优化后的模型图中,原先连续的Conv2DBatchNormReLU节点被替换为了一个名为FusedConv2dBnAct的单个节点。
  2. 性能数据对比:
  3. 在Atlas 200I DK A2上,使用相同的测试图片和推理循环(100次取平均),结果如下:
模型版本 平均推理延时 (ms) 内存占用 (MB)
原始模型 (Pynative) 520 ~250
原始模型 (Graph) 180 ~210
优化模型 (Graph + 融合Cell)​ 125​ ~190​

分析:

  1. 从Pynative模式切换到Graph模式,性能提升了约65%,这主要得益于图级别的整体优化和算子融合的初步应用。
  2. 在Graph模式基础上,使用为融合优化的Cell(Conv2dBnAct)构建模型,性能进一步提升了约30%。这证明了积极的模型构建方式能更好地释放硬件潜力。
  3. 内存占用的下降也符合预期,因为融合减少了许多中间结果的存储。
Logo

鲲鹏昇腾开发者社区是面向全社会开放的“联接全球计算开发者,聚合华为+生态”的社区,内容涵盖鲲鹏、昇腾资源,帮助开发者快速获取所需的知识、经验、软件、工具、算力,支撑开发者易学、好用、成功,成为核心开发者。

更多推荐