• 算子开发入门系列(一)


    编写算子步骤:

    1、确定输入输出(数据类型和维度):明确算子功能,即要执行的操作
    2、创建算子的头文件和源文件:使用C的语法,头文件和源文件分别用于声明和定义算子函数
    3、在头文件中声明算子函数:头文件中使用extern关键字声明算子函数的原型,包括函数名、参数列表、返回值类型等
    4、在源文件中定义算子函数:源文件中实现算子函数的具体逻辑。根据算子的功能和输入输出要求,编写相应的代码完成算子计算过程
    5、编译和构建算子:使用Ascend C编译器将算子的源文件编译成可执行文件(可以根据需要把算子打包成库文件)
    6、测试和验证算子:编写测试代码

    算子融合

    算子融合是一种深度学习模型优化技术,旨在将多个算子(操作)融合为一个算子,从而减少计算量和参数数量,提高模型性能和效率。在深度学习中,算子通常是指对张量(多维数组)进行操作的函数,如卷积(Convolution)、全连接层(Fully-Connected Layer)等。

    通过将多个算子融合,可以减少计算量和参数数量,从而提高计算速度和内存使用效率。此外,算子融合还可以有助于减少模型大小,便于在移动设备等资源受限的设备上进行部署。

    算子融合通常可以通过两种方式实现:

    1. 权重融合(Weight Fusion):将多个算子的权重矩阵融合为一个矩阵,从而减少参数数量。
    2. 算子调度融合(Operator Scheduling Fusion):通过调整算子的计算顺序,将多个算子融合为一个算子,从而减少计算量和内存使用。

    需要注意的是,算子融合可能导致计算图变得更加复杂,因此可能需要更多的编译时间和优化时间。此外,并非所有的算子都可以进行融合,需要根据具体问题和硬件环境进行评估和调整。

    在MindSpore中实现NMS算子

    import mindspore as ms
    import mindspore.ops as ops
    
    class NMS(ms.nn.Cell):
        def __init__(self, iou_threshold=0.5):
            super(NMS, self).__init__()
            self.iou_threshold = iou_threshold
            self.transpose = ops.Transpose()
            self.non_max_suppression = ops.NMSWithMask(0)
    
        def construct(self, boxes, scores):
            boxes = self.transpose(boxes, (1, 0))
            scores = self.transpose(scores, (1, 0))
            output, _ = self.non_max_suppression(boxes, scores, self.iou_threshold)
            return output
    
    # 创建NMS算子
    nms_op = NMS(iou_threshold=0.5)
    
    # 使用NMS算子进行非极大值抑制
    output_boxes = nms_op(boxes, scores)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    算子编译流程

    前端编译(Frontend Compilation)

    语法解析:将算子的代码文本解析成抽象语法树(AST)
    语义分析:对AST进行静态分析,检查类型、作用域等,生成经过语义检查的AST
    中间代码生成:将经语义检查的AST转换成一种中间表示(通常是GIMPLE形式的三地址代码)

    优化编译(Optimization Compilation)

    进行各种优化,如常量折叠、未用代码删除、循环优化等,得到更高效的中间代码
    针对特定架构做目标代码优化,如SIMD向量化等

    代码生成(Code Generation)

    将优化后的中间代码转换成特定架构的汇编代码或机器码
    进行寄存器分配、指令选择和指令排序等

    后端编译

    将生成的汇编代码组装成目标代码,完成链接,生成最终的算子库
    进行代码校验,确保编译正确性

    编译过程中常用的工具和框架包括LLVM、GCC、TVM等。通过编译,高效地将算子的高级语言代码转换成特定硬件可以执行的机器码,从而充分发挥硬件性能。

    ————————————————————————————————————
    对于深度学习神经网络的算子来说,编译流程与通用算子略有不同,主要是如下几点:

    张量化

    为神经网络中的张量数据表示设计合适的数据类型,如float16、int8等
    降低数据存储和传输成本,同时控制精度损失

    针对特定硬件优化

    如GPU:考虑线程块划分,共享内存使用,循环展开等
    如TPU:考虑在管线数组架构下的优化,提高并行度

    自动微分

    自动生成反向传播所需的求导代码
    支持动态形状变化,加速训练过程

    图级(Graph-level)优化

    跨算子的整体优化,如算子融合、内存复用
    更高层次的性能提升

    动态形状支持

    训练时各层形状可能变化,编译需要考虑形状不确定性
    通过动态调度来支持变化的形状

    深度学习编译需要自动化地支持更多优化来生成高效的代码,以充分利用硬件性能,达到训练和推理的低延迟和高吞吐量。

  • 相关阅读:
    题目 1059: 二级C语言-等差数列(python详解)——练气四层后期
    软件测试中的『草莓酱定律』
    适用于 PC 的最佳 Android 操作系统(2022 版)
    【润学】计算机网络八股文英文版(2)
    什么是B1级阻燃电缆
    高性能可编程射频移相器介绍
    对各种指针,数组的联立回顾复习(字符指针,指针数组,数组指针,函数指针,函数指针数组)
    sql server外键设置
    报错__WEBPACK_IMPORTED_MODULE_1_vuex__.a.store is not a constructor
    怎么优化H5让它可以在300ms以内打开?
  • 原文地址:https://blog.csdn.net/weixin_44659309/article/details/133125174