本发明属于深度学习编译器领域,尤其涉及一种面向dl编译器的预量化模型部署方法。
背景技术:
1、深度学习编译器(deep learning compiler,以下简称dl编译器)的出现,重新定义了在各种硬件平台上部署深度学习模型的挑战。dl编译器通常将表示在框架特定表示(framework-specific representation)中的模型转换为公共中间表示(ir)。然后,dl编译器从图级到张量级逐步降低图。在图级ir中,编译器优化模型的计算图。在张量级ir中,它优化张量算子的循环结构等,并针对不同的硬件做相应的优化。经过连续的优化后,dl编译器能够更有效地处理前端(框架)和后端(硬件平台)的多样性,从而简化了深度学习模型的部署。一般来说,深度学习模型需要大量的计算和内存资源,相关研究已经实现了各种技术(算法、软件和硬件)来减少深度学习模型的计算和内存负担,从而简化其开发和部署过程。
2、在这些技术中,量化是一种被广泛研究的方法。量化使得模型消耗更少的计算和内存资源,同时保持其精度接近未量化的模型。论文(efficient execution of quantizeddeep learning models:a compiler approach)提出了一种qnn(quantized neuralnetwork,量化神经网络)作为一个图级ir方言,可以增强深度学习编译器,并支持多种主流深度学习框架。这种方法提供了一种端到端的解决方案,可以读取预量化的模型,并支持各种硬件后端。
3、然而,这种方法并不支持在定制的ai加速器上部署预量化模型,比如多功能张量加速器(versatile tensor accelerator,vta)等。
技术实现思路
1、本发明目的在于提供一种面向dl编译器的预量化模型部署方法,以解决上述的技术问题。
2、为解决上述技术问题,本发明的一种面向dl编译器的预量化模型部署方法的具体技术方案如下:
3、一种面向dl编译器的预量化模型部署方法,包括如下步骤:
4、步骤1:前端框架解析器解析前端预量化的深度学习模型,输出包含q算子的图;q算子是包含了量化信息的算子,比图级算子高一级,将会在后续流程中被降级为更低级的图级算子;
5、步骤2:进行面向target,即目标平台的图切分操作,该操作之后,图将被分割为两部分:加速器支持的算子将在加速器上运行,加速器不支持的算子将在cpu上运行;步骤3:dl编译器将针对步骤2这两部分采用不同的调度和代码生成,对于在cpu上运行的算子,dl编译器将采用host默认流程进行处理,最终生成在cpu上运行的源代码;而在加速器上运行的算子,将通过加速器特定调度进行优化,并采用两级,即函数级和算子级加速器代码生成器来产生加速器硬件指令和驱动函数。
6、进一步的,所述步骤1包括量化2d卷积算子的计算:a:首先通过dma load指令将输入数据和权重数据从系统内存搬运到加速器的本地buffer中;执行gemm计算,在计算前将加速器累加器buffer清零;通过dma load指令将bias数据从系统内存搬运到加速器的本地buffer中,并执行gemm结果与bias的矢量alu add运算;执行矢量alu rmul、矢量alu rshr运算和矢量alu add运算,即执行requantize过程:乘以multiplier、除以2^shift和加上输出零点;执行矢量alu min/max运算,将结果限制在int8数据范围[-128,127]内;最后通过dma store指令将结果存储到系统内存中。b的计算过程与a基本一致,唯一的区别是b在执行gemm运算前,通过dma load指令先将bias搬运到加速器累加器buffer中,然后在此基础上,进行gemm的乘累加计算。
7、进一步的,所述步骤2包括如步骤:
8、首先,通过模式匹配,对算子a进行分组,得到分组后的b,b中的每个三角形都表示匹配的模式,即q.conv2d+q.bias_add+q.requantize+q.relu;接着,通过annotation操作给匹配的模式添加target标记,表示这部分算子将在target上运行;通过partitioning操作,将添加了target标记的group转换为图级表示的函数模块,即c,并为该函数添加加速器属性,该属性指示dl编译器采用加速器特定的流程来处理该函数;然后,遍历并且修改图,将加速器函数名修改为带有target的特殊函数名;接下来执行预优化,以满足graphpacking的要求;最后,执行graph packing,将q算子图转换为普通图级算子图,并执行layout变换,使加速器函数模块的输入输出满足加速器硬件要求,即d,d表示在进入加速器模块前,需要执行pack操作;在退出加速器模块且进入host模块前,需要执行unpack操作;如果两个加速器模块之间只存在elementwise算子,则不需要额外pack和unpack操作。
9、进一步的,所述步骤3采用函数级和算子级变换方式,对加速器子函数和加速器算子执行变换,包括如步骤:
10、首先,以加速器不合法图,即输入输出不满足加速器硬件要求的图作为输入,执行函数级变换,变换过程如下:
11、步骤3.1:遍历图,搜集所有子函数在图中的位置信息,搜索结果记录在一个列表中,列表的每个元素都是一个元组,元组包含两个参数:子函数名和子函数在图中的位置,该列表表示如下:
12、list[tuple(sub_func,index),…];
13、步骤3.2:遍历第(1)步得到的列表,根据加速器函数的特殊函数名,搜集加速器子模块及其在图中的位置信息,记录到加速器子模块列表中,该列表表示如下:list(tuple(accelerator_func,index));
14、步骤3.3:遍历加速器子模块列表,确定当前加速器函数是否需要执行pack和unpack操作;
15、步骤3.4:遍历图,执行图的函数级变换,即把子函数当作普通算子来操作,对于每一个加速器子模块,如果其在pack列表中的pack标志为true,则对其输入执行pack操作;如果unpack标志为true,则对其输出执行unpack操作,经过一轮遍历,所有加速器子模块的输入输出都是合法的,即符合了加速器硬件要求,这一步输出的图即为加速器合法图;
16、然后,以加速器合法图作为输入,执行算子级图变换,对q算子进行降级,以方便后续处理,遍历图,如果当前算子是加速器子模块,则进一步遍历其中的每个算子,执行算子级变换。
17、进一步的,所述步骤3.3确定当前加速器函数是否需要执行pack和unpack操作的确定规则是:如果当前加速器子模块是第1个加速器子模块,且前面的算子中存在非element-wise算子,则需要执行pack操作;如果当前加速器子模块是最后一个加速器子模块,且后面的算子中存在非element-wise算子,则需要执行unpack操作;如果当前加速器子模块和上一个加速器子模块之间存在非element-wise算子,则需要执行pack操作;如果当前加速器子模块和下一个加速器子模块之间存在非element-wise算子,则需要执行unpack操作,遍历的结果记录在pack列表中,该列表的每个元素均是一个三元元组,即加速器子模块函数名,是否pack标志,是否unpack标志,pack列表表示如下:
18、list(tuple(accelerator_func,pack_flag,unpack_flag),…)。
19、进一步的,所述步骤3.4执行算子级变换的具体处理步骤如下:
20、步骤3.4.1:处理q.conv2d算子:如果当前算子为q.conv2d,则将其替换为conv2d_zp算子,该算子将input零点作为padding值,执行padding后的input和weight的卷积运算,conv2d_zp算子经过后续加速器特定优化过程降级为加速器gemm loop、load和store操作;
21、步骤3.4.2:处理q.bias_add算子:如果当前算子为q.bias_add,则将其替换为bias_add_zp算子,该算子将经过了零点融合的bias常量与conv2d_zp的输出结果相加,这里的bias常量为qfused_bias=qbias-∑zpin*qwgt,conv2d_zp算子经过后续加速器特定调度转换为加速器矢量alu add和load操作;
22、步骤3.4.3:处理q.requantize算子:如果当前算子为q.requantize,则将其替换为带rounding的量化乘法算子round_multiply、带rounding的移位除法算子round_rshift和加输出零点的add算子的组合,round_multiply和round_rshift算子经过后续加速器特定调度转换为加速器矢量alu rmul和rshr操作,add算子经过后续加速器特定调度转换为加速器矢量alu add操作;
23、步骤3.4.4:处理q.relu算子:如果当前算子为q.relu,则将其替换为min算子和max算子的组合,即将结果限制在[-128,127]范围内,min和max算子经过后续加速器特定调度转换为加速器矢量alu min和max算子。
24、进一步的,所述步骤3的加速器两级代码生成器的工作流程如下:首先,加速器函数级代码生成器配合host代码生成器,产生c语言版的算子执行控制流和加速器驱动代码;其中,加速器函数级代码生成器遍历图中的每个加速器子函数,为其产生独立的加速器驱动函数,该驱动函数完成两项工作:初始化加速器和启动加速器计算内核,加速器内核按照顺序执行指令数组中的硬件指令;然后,加速器算子级生成器遍历加速器子函数中的每个算子,根据图的连接关系和参数信息,产生python版的算子执行控制流,并通过pybind11模块调用加速器runtime,产生加速器硬件指令数据,并将数据保存到c语言数组中;其中,py2cpp是一个绑定了加速器c或c++runtime api的python包,由pybind11模块生成,可实现在python中调用c或c++函数。
25、本发明的一种面向dl编译器的预量化模型部署方法具有以下优点:(1)本发明支持面向加速器的切图功能,既能够完成q算子到普通算子的降级,又能够使加速器子函数的输入输出格式满足硬件要求。(1)支持图的两级变换,其中,函数级变换执行pack和unpack操作;算子变换执行算子降级。(3)q.conv2d算子在降级过程中具有零点填充属性,并支持acc累加器初始化为bias调度,q.requantize算子在降级过程中被进一步拆解为张量级算子组合(round_rmul和round_rshr),以更好的支持alu算子融合到卷积运算函数中。(4)支持加速器两级代码生成器,函数级代码生成器产生加速器驱动函数,算子级代码生成器产生加速器硬件指令。
1.一种面向dl编译器的预量化模型部署方法,其特征在于,包括如下步骤:
2.根据权利要求1所述的面向dl编译器的预量化模型部署方法,其特征在于,所述步骤1包括量化2d卷积算子的计算:a:首先通过dma load指令将输入数据和权重数据从系统内存搬运到加速器的本地buffer中;执行gemm计算,在计算前将加速器累加器buffer清零;通过dma load指令将bias数据从系统内存搬运到加速器的本地buffer中,并执行gemm结果与bias的矢量alu add运算;执行矢量alu rmul、矢量alu rshr运算和矢量alu add运算,即执行requantize过程:乘以multiplier、除以2^shift和加上输出零点;执行矢量alu min/max运算,将结果限制在int8数据范围[-128, 127]内;最后通过dma store指令将结果存储到系统内存中。b的计算过程与a基本一致,唯一的区别是b在执行gemm运算前,通过dma load指令先将bias搬运到加速器累加器buffer中,然后在此基础上,进行gemm的乘累加计算。
3.根据权利要求1所述的面向dl编译器的预量化模型部署方法,其特征在于,所述步骤2包括如步骤:
4.根据权利要求1所述的面向dl编译器的预量化模型部署方法,其特征在于,所述步骤3采用函数级和算子级变换方式,对加速器子函数和加速器算子执行变换,包括如步骤:
5.根据权利要求4所述的面向dl编译器的预量化模型部署方法,其特征在于,所述步骤3.3确定当前加速器函数是否需要执行pack和unpack操作的确定规则是:如果当前加速器子模块是第1个加速器子模块,且前面的算子中存在非element-wise算子,则需要执行pack操作;如果当前加速器子模块是最后一个加速器子模块,且后面的算子中存在非element-wise算子,则需要执行unpack操作;如果当前加速器子模块和上一个加速器子模块之间存在非element-wise算子,则需要执行pack操作;如果当前加速器子模块和下一个加速器子模块之间存在非element-wise算子,则需要执行unpack操作,遍历的结果记录在pack列表中,该列表的每个元素均是一个三元元组,即加速器子模块函数名,是否pack标志,是否unpack标志,pack列表表示如下:
6.根据权利要求4所述的面向dl编译器的预量化模型部署方法,其特征在于,所述步骤3.4执行算子级变换的具体处理步骤如下:
7.根据权利要求1所述的面向dl编译器的预量化模型部署方法,其特征在于,所述步骤3的加速器两级代码生成器的工作流程如下:首先,加速器函数级代码生成器配合host代码生成器,产生c语言版的算子执行控制流和加速器驱动代码;其中,加速器函数级代码生成器遍历图中的每个加速器子函数,为其产生独立的加速器驱动函数,该驱动函数完成两项工作:初始化加速器和启动加速器计算内核,加速器内核按照顺序执行指令数组中的硬件指令;然后,加速器算子级生成器遍历加速器子函数中的每个算子,根据图的连接关系和参数信息,产生python版的算子执行控制流,并通过pybind11模块调用加速器runtime,产生加速器硬件指令数据,并将数据保存到c语言数组中;其中,py2cpp是一个绑定了加速器c或c++ runtime api的python包,由pybind11模块生成,可实现在python中调用c或c++函数。
