离线模型生成以卷积神经网络为例,在深度学习框架下构造好相应的网络模型,并且训练好原始数据,再通过离线模型生成器进行算子调度优化、权重数据重排和压缩、内存优化等,最终生成调优好的离线模型。离线模型生成器主要用来生成可以高效执行在昇腾AI处理器上的离线模型。
离线模型生成器的工作原理如上图所示,在接收到原始模型后,对卷积神经网络模型进行模型解析、量化、编译和序列化四个步骤:
1、解析
在解析过程中,离线模型生成器支持不同框架下的原始网络模型解析,提炼出原始模型的网络结构、权重参数,再通过图的表示法,由统一的中间图(IR Graph)来重新定义网络结构。中间图由计算节点和数据节点构成,计算节点有不同功能的TBE算子组成,而数据节点专门接收不同的张量数据,为整个网络提供计算需要的各种输入数据。这个中间图是由计算图和权值构成,涵盖了所有原始模型的信息。中间图为不同深度学习框架到昇腾AI软件栈搭起了一座桥梁,使得外部框架构造的神经网络模型可以轻松转化为昇腾AI处理器支持的离线模型。
2、量化
如图所示,解析完成后生成了中间图,如果模型还需要进行量化处理,则可以基于中间图的结构和权重,通过自动量化工具来进行量化。在算子中,可以对权重、偏置进行量化,在离线模型生成过程中,量化后的权重、偏置会保存在离线模型中,推理计算时可以使用量化后的权重和偏置对输入数据进行计算,而校准集用于在量化过程中训练量化参数,保证量化精度。如果不需要量化,则直接进行离线模型编译生成离线模型。
量化方式分为数据偏移量化和无偏移量化,需要输出量化度(Scale)和量化偏移(Offset)两个参数。在数据量化过程中,指定无偏移量化时,数据都采用无偏移量化模式,计算出量化数据的量化度;如果指定数据偏移量化,则数据采用偏移模式,则会计算输出数据的量化度和量化偏移。在权重量化过程中,由于权重对量化精度要求较高,因此始终采用无偏移量化模式。比如根据量化算法对权重文件进行INT8类型量化,即可输出INT8权重和量化度。而在偏置量化过程中,根据权重的量化度和数据的量化度,可将FP32类型偏置数据量化成INT32类型数据输出。
在对模型大小和性能有更高要求的时候可以选择执行量化操作。离线模型生成过程中量化会将高精度数据向低比特数据进行量化,让最终的离线模型更加轻量化,从而达到节约网络存储空间、降低传输时延以及提高运算执行效率的目的。在量化过程中,由于模型存储大小受参数影响很大,因此离线模型生成器重点支持卷积算子、全连接算子以及深度可分离卷积(ConvolutionDepthwise)等带有参数算子的量化。
3、编译
在完成模型量化后,需要对模型进行编译,编译分为算子编译和模型编译两个部分,算子编译提供算子的具体实现,模型编译将算子模型聚合连接生成离线模型结构。
-算子编译
算子编译进行算子生成,主要是生成算子特定的离线结构。算子生成分为输入张量描述、权重数据转换和输出张量描述三个流程。在输入张量描述中,计算每个算子的输入维度、内存大小等信息,并且在离线模型生成器中定义好算子输入数据的形式。在权重数据转换中,对算子使用的权重参数进行数据格式(比如FP32到FP16的转换)、形状转换(如分形重排)、数据压缩等处理。在输出张量描述中,计算算子的输出维度、内存大小等信息。
算子生成流程如图所示,算子生成过程中需要通过TBE算子加速库的接口对输出数据的形状进行分析确定与描述,通过TBE算子加速库接口也可实现数据格式的转换。离线模型生成器收到神经网络生成的中间图并对中间图中的每一节点进行描述,逐个解析每个算子的输入和输出。离线模型生成器分析当前算子的输入数据来源,获取上一层中与当前算子直接进行衔接的算子类型,通过TBE算子加速库的接口进入算子库中寻找来源算子的输出数据描述,然后将来源算子的输出数据信息返回给离线模型生成器,作为当前算子的具体输入张量描述。因此了解了来源算子的输出信息就可以自然的获得当前算子输入数据的描述。
如果在中间图中的节点不是算子,而是数据节点,则不需要进行输入张量描述。如果算子带有权值数据,如卷积算子和全连接算子等,则需要进行权重数据的描述和处理。如果输入权重数据类型为FP32,则需要通过离线模型生成器调用类型转化(ccTransTensor)接口,将权重转换成FP16数据类型,满足AI Core的数据类型需求。完成类型转换后,离线模型生成器调用形状设置(ccTransFilter)接口对权重数据进行分形重排,让权重的输入形状可以满足AI Core的格式需求。在获得固定格式的权重后,离线模型生成器调用TBE提供的压缩优化(ccCompressWeight)接口,对权重进行压缩优化,缩小权重存储空间,使得模型更加轻量化。在对权重数据转换完后返回满足计算要求的权重数据给离线模型生成器。
权重数据转化完成后,离线模型生成器还需要对算子的输出数据信息进行描述,确定输出张量形式。对于高层次复杂算子,如卷积算子和池化算子等,离线模型生成器可以直接通过TBE算子加速库提供的计算接口,并结合算子的输入张量信息和权重信息来获取算子的输出张量信息。如果是低层次简单算子,如加法算子等,则直接通过算子的输入张量信息来确定输出张量信息,最终再存入离线模型生成器中。按照上述运行流程,离线模型生成器遍历网络中间图中所有算子,循环执行算子生成步骤,对所有算子的输入输出张量和权重数据描述,完成算子的离线结构表示,为下一步模型生成提供算子模型。
-模型编译
编译过程中完成算子生成后,离线模型生成器还要进行模型生成,获取模型的离线结构。离线模型生成器获取中间图,对算子进行并发的调度分析,将多个中间图节点进行执行流拆分,获得多个由算子和数据输入组成的执行流,执行流可以看作是算子的执行序列。对于没有相互依赖的节点,直接分配到不同的执行流中。如果不同执行流中节点存在依赖关系,则通过rtEvent同步接口进行多执行流间同步。在AI Core运算资源富余的情况下,多执行流拆分可以为AI Core提供多流调度,从而提升网络模型的计算性能。但是如果AI Core并行处理任务较多时,会加剧资源抢占程度,恶化执行性能,一般默认情况下采用单执行流对网络进行处理,可防止因多任务并发执行导致阻塞的风险。
同时,基于多个算子的执行序列的具体执行关系,离线模型生成器可以进行独立于硬件的算子融合优化以及内存复用优化操作。根据算子输入、输出内存信息,进行计算内存复用,将相关复用信息写入模型和算子描述中,生成高效的离线模型。这些优化操作可以将多个算子执行时的计算资源进行重新分配,最大化减小运行时内存占用,同时避免运行过程中频繁进行内存分配和释放,实现以最小的内存使用和最低的数据搬移频率来完成多个算子的执行,提升性能,而且降低对硬件资源的需求。
4、序列化
编译后产生的离线模型存放于内存中,还需要进行序列化。序列化过程中主要提供签名功能给模型文件,对离线模型进行进一步封装和完整性保护。序列化完成后可以将离线模型从内存输出到外部文件中以供异地的昇腾AI芯片调用和执行。