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


    编写算子步骤:

    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)优化

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

    动态形状支持

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

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

  • 相关阅读:
    Maven最新版的下载与安装教程
    嵌入式学习笔记(44)S5PV210的SD卡启动实战
    [青少年CTF训练平台]web部分题解(已完结!)
    基于springboot实现致远汽车租赁平台管理系统项目【项目源码+论文说明】计算机毕业设计
    科普系列:AUTOSAR与OSEK网络管理比较(上)
    ABAP 调用HTTP上传附件(二)之中文乱码
    C- qsort()
    ERD Online介绍
    html 列表标签的学习,表单标签的学习
    【正则】详解python正则表达式之re.group()用法
  • 原文地址:https://blog.csdn.net/weixin_44659309/article/details/133125174