openpplppq量化:计算图的切分和调度源码剖析(代码片段)

沉迷单车的追风少年 沉迷单车的追风少年     2023-04-04     621

关键词:

目录

前言

分割调度类型

计算图的切割

三种调度平台

Shape or Index算子为什么不能被量化?

分割量化操作

Shape or Index操作

fp32(非量化)操作

组装分割计算图

PPL NN 计算图分割策略

后记


前言

上一篇博客讲了计算图的加载和预处理,真是费了不少劲啊……

这一篇博客和大家一起学习PPQ精髓之一:计算图的分割与调度。第一讲就说过PPQ把计算图分成了三类:可量化、不可量化、争议区。计算图分割的目的就是把这三类区域分割出来;为了适应多平台,PPQ已经在计算图的调度上也分了很多种,我们一一道来。

分割调度类型

PPQ一共有六种类型,写在DISPATCHER_TABLE字典中:

DISPATCHER_TABLE = 
    "conservative": ConservativeDispatcher,
    "pplnn": PPLNNDispatcher,
    "aggresive": AggresiveDispatcher,
    "pointwise": PointDispatcher,
    "allin": AllinDispatcher,
    'perseus': Perseus

我们就先从保守调度类型conservative为例开始看吧!

计算图的切割

三种调度平台

首先回忆一下上一讲用的在计算图中搜索的所需算子的方法opset_matching(),现在我们用这个方法来搜索我们所需要的算子!

我们现在要搜索三类算子,然后调度到不同平台上:quant_platform、SOI_platform、fp32_platform。

  • quant_platform:图形的所有可量化部分都将被分派到此平台。
  • SOI_platform:形状或索引相关操作将分派到此平台。
  • fp32_platform:有一些操作同时从quant_platform和SOI_platform接收结果,它们将被分派到fp32_platform。

小插曲,此处的注释貌似写错了:

Shape or Index算子为什么不能被量化?

在图中 shape 算子的输出要作为参数传递给 reshape 算子,如果我们在这条路径上插入任何量化操作,会导致 reshape 算子的输入被改变。

例如 shape 算子的输出为 [1, 3, 224, 224],我们知道 int8 量化只能表示 256 个数,而对称量化在正数半轴只有 128 个数可以表示,假设我们选取 scale = 2,其量化后的值将会变为 [0, 4, 224, 224]。那么后续的逻辑自然就执行不通了。

分割量化操作

opset_matching()方法又大显神功,把所有可计算量化的算子都装入quant_operations当中。

        quant_operations = search_engine.opset_matching(
            sp_expr = lambda x: x.is_computing_op,
            rp_expr = value_tracing_pattern,
            ep_expr = lambda x: (x.type not in quant_types) or x.is_boundary,
            direction = 'down')
        quant_operations.filter(lambda x: x.type not in quant_types)

Shape or Index操作

先按照算子类型是否是shape、topk、nonmaxsuppression寻找计算图:

        computing_extensions = search_engine.opset_matching(
            sp_expr = lambda x: x.is_computing_op,
            rp_expr = value_tracing_pattern,
            ep_expr = lambda x: x.type in 'Shape', 'TopK', 'NonMaxSuppression' or x.is_boundary,
            direction = 'down')

但是在某些特定情况下,单个匹配无法处理。为了覆盖所有与形状相关的操作,需要反向匹配。

注释是这么描述的,但是我还不是特别理解,后面会结合实例再思考一下:

        # we assume all 'Shape', 'NonMaxSuppression', 'ConstantOfShape', 'Topk' operations are SOI generators.
        shape_forward_matching = search_engine.opset_matching(
            sp_expr = lambda x: x in generators and x.type not in 'Constant',
            rp_expr = value_tracing_pattern,
            ep_expr = lambda x: (x in recivers or
                                 x in quant_operations or
                                 x.is_boundary or
                                 x.is_computing_op),
            direction = 'down')

        # remove computing operations and quant operations from matching
        shape_forward_matching.filter(lambda x: x.is_computing_op or x in quant_operations)

        # update matchings, ready for further searching.
        SOI_operations.update(shape_forward_matching)

        while True:
            # there are some particular cases where a single matching can not handle.
            # to cover all shape-related operations, a reverse matching is required.
            shape_backward_matching = search_engine.opset_matching(
                sp_expr = lambda x: x in SOI_operations and x.type != 'Shape',
                rp_expr = reverse_tracing_pattern,
                ep_expr = lambda x: (x in SOI_operations or
                                     x in quant_operations or
                                     x.is_boundary or
                                     x.is_computing_op),
                direction = 'up')

            # remove computing operations and quant operations from matching
            shape_backward_matching.filter(lambda x: x.is_computing_op or x in quant_operations)

            if all([(op in SOI_operations) for op in shape_backward_matching]): break

            # update matchings
            SOI_operations.update(shape_backward_matching)

fp32(非量化)操作

剩下的就全是非量化区域啦~

组装分割计算图

刚才依赖opset_matching方法把我们所需要切割的都找到了,接下来我们组装一个字典集然后返回,大功告成!

        # generate dispatching table.
        dispatching_table = 
        for operation in graph.operations.values():
            if operation in SOI_operations and operation not in computing_extensions:
                dispatching_table[operation.name] = SOI_platform
            elif operation in quant_operations:
                dispatching_table[operation.name] = quant_platform
            else:
                dispatching_table[operation.name] = fp32_platform

因为在SOI匹配的时候,做了正向和反向两次匹配,所以这里需要删除重复匹配:

        for operation in graph.operations.values():
            # move Topk, Shape, NonMaxSuppression to the platform same as their input.
            if operation.type in 'Shape', 'TopK', 'NonMaxSuppression':
                source_op = operation.inputs[0].source_op
                if source_op is not None:
                    dispatching_table[operation.name] = dispatching_table[source_op.name]
                else: dispatching_table[operation.name] = fp32_platform

            # move activations to the platform same as their input.
            if operation.is_linear_activation:
                source_op = operation.inputs[0].source_op
                if source_op is not None:
                    dispatching_table[operation.name] = dispatching_table[source_op.name]

PPL NN 计算图分割策略

刚才是以保守调度策略为例说明了计算图分割的大体过程,因为大致流程是一样的,下面重点讲讲其他的策略不同点。

PPL NN的的量化策略是从conv到conv作为可量化区域,区别于保守调度策略中的从可计算op调度:

        quant_operations = search_engine.opset_matching(
            sp_expr = lambda x: x.type == 'Conv',
            rp_expr = lambda x, y: value_tracing_pattern(x, y) and y.type in quant_types,
            ep_expr = lambda x: x.type == 'Conv',
            direction = 'down')

其他的等用到的时候再看吧,这里就不细看了~

后记

其实还有不少地方我没有看明白,比如不同平台是软件层面的分类还是硬件层面的分类?分类标准是加速运算还是为了分割计算图方便后续调度量化?……后面将探索这些疑点!

openpplppq量化:原理与实践(代码片段)

目录量化原理为什么需要量化?量化粒度框架综述算子划分量化中的图融合操作量化实践:以pytorch mobilenetv2模型为例源码阅读 torch模型和onnx量化过程中的区别后记量化原理为什么需要量化?1、减少内存带宽和存储... 查看详情

openpplppq量化:执行引擎源码剖析(代码片段)

目录PPQGraphExecutor(PPQ执行引擎)PPQBackendFunctions(PPQ算子库)PPQExecutor(PPQ执行引擎)QuantizeDelegate(量化代理函数)Usage(用法示例)Hook(执行钩子函数)前面四篇博客其实就讲了下面两行代码:ppq_ir=load_onnx_graph(onnx_import_file=onnx_import_fi... 查看详情

sparkstage切分源码剖析——dagscheduler

...park中的任务管理是很重要的内容,可以说想要理解Spark的计算流程,就必须对它的任务的切分有一定的了解。不然你就看不懂SparkUI,看不懂SparkUI就无法去做优化...因此本篇就从源码的角度说说其中的一部分,Stage的切分——DAG图... 查看详情

tensorflow静态图的动态收缩(代码片段)

...行,扩大区间rrr的范围,并对区间内的权重进行量化操作。一次训练可能要量化多个区间,量化后权重冻结。静态图思路权重冻结这是一个老问题,之前的文章中也有介绍。解决方法还是:defentry_stop_gradients(ta... 查看详情

分布式调度系统现状

...调度的两大任务:任务调度和资源调度任务调度:大量的计算任务、任务如何让切分、数据如何分割运算、监控运算状态资源调度:供给方、不同业务间的平衡资源、支持优先级抢占 分布式调度系统:Hadoop 查看详情

sparkdagschedulertaskscheduleexecutor执行task源码分析(代码片段)

摘要spark的调度一直是我想搞清楚的东西,以及有向无环图的生成过程、task的调度、rdd的延迟执行是怎么发生的和如何完成的,还要就是RDD的compute都是在executor的哪个阶段调用和执行我们定义的函数的。这些都非常的基础和困难... 查看详情

datax源码解析-任务调度机制解析(代码片段)

...ob根据分库分表切分成了100个Task。根据20个并发,DataX计算共需要分配4个TaskGroup。4个TaskGroup平分切分好的100个Task,每一个TaskGroup负责以5个并发共计运行25个Task。下面就基于源码分析下具体的过程。这里要说明下,sche... 查看详情

分布式调度

分布式调度两大任务:  任务调度:大量计算任务、任务如何切分、数据如何分割、运算、监控运算状态。  资源调度1、任务调度2、资源调度3、容错机制4、规模挑战5、安全与性能隔离6、分布式调度发展方向 在VLDB2014F... 查看详情

k路三角形集交点和三角剖分

...32【问题描述】:如果我们有K组可能重叠的三角形,那么计算一组新的、不重叠的三角形的高效计算方法是什么?例如,考虑这个问题:这里我们有3个三角形集合A、B、C,它们有一些相互重叠,我们希望得到不重叠的集合A\'、B\... 查看详情

采样和量化,计算输出

】采样和量化,计算输出【英文标题】:SamplingandQuantization,CalculatingOutput【发布时间】:2015-05-0720:45:26【问题描述】:我想了解这个概念,我在多媒体课上遇到了一个我错过的问题,似乎我错过了一些东西。我不需要任何人为我... 查看详情

配电网优化基于matlabgui配电网潮流计算与经济调度模糊满意度评价含matlab源码2159期(代码片段)

一、配电网潮流计算与经济调度模糊满意度评价软件介绍单击guimh.m文件打开系统主界面,如图1所示,界面友好、简单、易于操作。主界面上方有一个“开始”按钮,可以控制整个软件的执行。主界面右方有三个选项&... 查看详情

配电网优化基于matlabgui配电网潮流计算与经济调度模糊满意度评价含matlab源码2159期(代码片段)

一、配电网潮流计算与经济调度模糊满意度评价软件介绍单击guimh.m文件打开系统主界面,如图1所示,界面友好、简单、易于操作。主界面上方有一个“开始”按钮,可以控制整个软件的执行。主界面右方有三个选项&... 查看详情

如何矢量化和加速这个大型数组计算?

】如何矢量化和加速这个大型数组计算?【英文标题】:HowcanIvectorizeandspeedupthislargearraycalculation?【发布时间】:2016-09-1413:46:18【问题描述】:我目前正在尝试计算10.000x10.000值数组中所有子平方和的总和。例如,如果我的数组是... 查看详情

hadoop文件切分的源码

TextInputFormatHadoop文件的切分原则:一按每个文件切分二文件大小/分片大小《=1.1则划分为一个文件,否则切分为2个文件三一个切片一个Maptask,一个Maptask代表一个并行度分片默认设置分片切分的核心源码publicList<InputSplit>getSplit... 查看详情

计算几何——三角剖分uva1331+poj3675(代码片段)

看了一整天三角剖分。。能找到的题只有求最大面积最小的三角剖分。。然而这题除了用些三角剖分的性质外。。其实是个dp#include<bits/stdc++.h>usingnamespacestd;constintINF=1e9;constintmaxn=50+5;constdoubleeps=0.00001;intn,m;structPointintx,y;friendP... 查看详情

用dolphindb和pythoncelery搭建一个高性能因子计算平台

因子挖掘是量化金融研究和交易的核心工作。传统的开发流程中,通常使用Python从关系型数据库(如SqlServer,Oracle等)读取数据,在Python中进行因子计算。随着证券交易规模不断扩大以及交易数据量的激增,用户对因子计算平台... 查看详情

spark核心作业调度和任务调度之dagscheduler源码

...者发送至我的邮箱 [email protected]摘要:  1.作业调度核心——DAGScheduler   2.DAGScheduler类说明    2.1DAGScheduler    2.2ActiveJob    2.3St 查看详情

最佳量化交易的计算机操作系统

...到的一个问题是:用哪种计算机操作系统和计算软件进行量化交易的理论研究和代码实现?  我想把这个问题简化,从挑选的计算软件和计算库来反推最佳使用的计算机操作系统。简而言之,就是在本文撰写的时候而言,如果... 查看详情