本篇记录一次从Keras生成的H5模型转换成TFLite模型的过程。中间踩了一些坑,记录下来以供参考。
import tensorflow as tf
from tensorflow.python.keras import backend as K
from tensorflow.python.keras.utils import CustomObjectScope
converter = tf.lite.TFLiteConverter.from_keras_model_file('facenet_keras.h5')
tflite_model = converter.convert()
open("facenet_converted_model.tflite", "wb").write(tflite_model)
在tensorflow2环境下运行,出现错误:
AttributeError: type object 'TFLiteConverterV2' has no attribute 'from_keras_model_file'
这个错误的原因是,在tensorflow2.0以上的版本中,TFLiteConverter的方法名称改成了“from_keras_model”,所以解决方法有两种,一种是使用tensorflow2.0以上的方法,另一种是使用兼容模块tf.compat.v1。代码分别如下:
# use tf2.0 api
converter = tf.lite.TFLiteConverter.from_keras_model('facenet_keras.h5')
# use tf.compat.v1
converter = tf.compat.v1.lite.TFLiteConverter.from_keras_model_file('facenet_keras.h5')
以上两种方法都OK,我选用的第一种,即使用tf2的API。
但编译时又出现了新的问题:
AttributeError: 'str' object has no attribute 'call'
该错误的出处仍然时这一行:
converter = tf.lite.TFLiteConverter.from_keras_model('facenet_keras.h5')
传入的字符串没有“call”属性,解决方法,先用keras加载指定名称的模型,再将模型对象传入tf.lite.TFLiteConverter.from_keras_model(),代码如下:
再次运行,通过了!在原路径(这个路径可以根据需要修改哈,我懒了,直接放当前目录了)下可以看到我们转换出来的tflite模型:
虽然转换成功,但这个模型的体积跟原模型差别不大,因为模型参数仍然是默认的float32类型。如果我们想缩小模型体积,就需要对模型进行量化。
量化的方式有多种,这里简单说明一下,有兴趣的读者可以到官网查看:训练后量化
这里我们选择相对简单的一种动态范围量化 (Dynamic range quantization),完整代码如下:
import tensorflow as tf
from tensorflow.python.keras import backend as K
from tensorflow.python.keras.utils import CustomObjectScope
model = tf.keras.models.load_model('facenet_keras.h5')
converter = tf.lite.TFLiteConverter.from_keras_model(model)
# 开启动态量化
converter.optimizations = [tf.lite.Optimize.DEFAULT]
tflite_model = converter.convert()
open("facenet_converted_model_quantized.tflite", "wb").write(tflite_model)
运行结束后,在目录下,我们可以看到,量化后的模型已经生成,大小约为原来的1/4。