最近在忙语音唤醒的工作,涉及了非常多的深度学习集成到移动端的技术点。
这篇博客主要讲的是通过TensorFlow训练出来的模型如何转为可以在移动设备上进行部署的tflite文件。可能有人会说了这个很简单,通过TensorFlow的相关函数就可以了。。。实际上不是这样的,这其中还牵扯很多需要注意的地方。主要的一方面是移动端设备对性能要求极高,有内存大小的要求。因此我们需要将模型的大小不断压缩达到我们想要的大小。
在参考文献中的第一篇博客给了我很大的启发,同时还有在GitHub上开源的谷歌speech command
以及ARM的ARM-software/ML-KWS-for-MCU
都极具参考价值。
在第一篇博客中,详细解释了压缩TensorFlow模型,需要做的工作。简单来说就是分为两个阶段,训练之前和训练之后。
-
训练之前: 训练之前就是构造模型的阶段,因为将模型压缩本质上来说就两条路一个是精简模型结构,第二就是将浮点型数据映射为整型数据,第二种方法能够将模型的大小压缩为原来的四分之一。因此第二种方法能够极大压缩模型的大小。但是这也会带来一定的问题,因为将训练数据从浮点型转为整型可能会带来模型准确率下降的问题。TensorFlow给出的方案是模拟定点化(其中定点化就是指将数据从浮点型压缩为整型的操作,或者可以称之为量化操作),TensorFlow通过在模型训练中加入
Simulated Quantization
的机制,以减少模型量化带来的精度影响,相关原理的详细说明在参考文献4中的论文里(具体我也没看)。在实际使用中,Simulated Quantization
是在模型训练的计算图上增加FakeQuant
相关节点,以实现在前向计算(forward
)时模拟参数定点化带来的精度损失。对于fullconnected
进行Simulated Quantization
的示意图。(其实这些操作,在ARM给的代码中已经给出了相关的实例代码了,这部分代码需要注意的是在TensorFlow2.0中已经去掉了所有和contrib
有关的函数,取而代之的是tf.quantization
)- 在这个部分有一个比较坑的量化方法就是
post-training quantization
,这个方法是toco 拿pb文件,直接把toco的post-training quantization
的flag设置为true 实现的。这个方法的问题在于它只quantize weights
,之前说的这个方法是full quantized model
,这个方法更坑的地方在于,inference
时会把unit8的weights再转换为float32来做矩阵乘法。也就是说这个方法没做quantization
,所以也就是说这个方法只是便于转移model ,计算的时候不是一个量化过的model ,所以说这个方法提出的意义是什么呢(参考文献6是tf 官网上专门讲述post_training 的相关文档,有一定借鉴意义,但是现在主要还是专攻fake quant
)。 - 现在tf 不断更新将之前的一些比较老的
quantization
的方法都去掉了,现在tf 专心在搞tflite
,因此现在只要关注fake quantization就可以了
- 在这个部分有一个比较坑的量化方法就是
-
训练之后:训练之后进行模型转换,是进行tflite的转换。
移动端部署深度学习模型的步骤
所以现在可以总结一下,在移动端部署深度学习模型的步骤了(当然现在说的都是tf1.14版本的做法,现在网上tf2.0版本的quantization
的案例相当少)。
- 将
fake quantization
加入到模型训练中(在参考文献5中,讲述了 需要在训练和评估的时候使用create_training_graph
和create_eval_graph
进行模型图的构建),然后训练出伪定点化的模型(ckpt模型) - 将得到的
ckpt
模型frozen
为pb
模型(在参考文献1中讲述了,这个步骤转换过程中,需要注意两个问题 1. 正确处理quantization
参数和Fakequant
的相关节点 2. 避免转换之后的计算图出现低效的节点)- 在tf1.14时代,这个
freeze
过程借用的工具是TOCO
,利用这个工具进行转换的时候,需要指定输入数据的Quantization
参数(min/max
),所以说需要在输入数据的时候加入Fakequant
节点用来在训练过程中统计min/max
值
- 在tf1.14时代,这个
- 将得到的
pb
模型转换为tflite
模型,其中转换的过程中需要加入相关的quantization