1. float32 -> float16的量化
import tensorflow as tf
saved_model_dir="/path/to/mobilenet_v1_224"
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.supported_types = [tf.lite.constants.FLOAT16]
tflite_model=converter.convert()
open("converted_model.tflite","wb").write(tflite_model)
2. float32 -> uint8的量化
import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_keras_model_file(keras_model)
converter.inference_type = tf.uint8
converter.quantized_input_stats = {'input_1': (0, 255)}
converter.default_ranges_stats = (0, 1)
tflite_model = converter.convert()
open("converted_model_uint8.tflite", "wb").write(tflite_model)
由于uint8的数据只在0-255之间变化,而量化就是将整个float32的数据,在牺牲一定的数据精度的情况下,映射到0-255这256个整数上去,所以在输入数据的时候,就需要做一定的映射变换,我这里的input_1
这个输入层本来是接受[-1,1]这个范围内的float数据的,现在需要接受了0-255的数据,为了模型能正确推理,所以需要有转化关系,以
x
q
x_q
xq表示量化后的数据,以
x
f
l
o
a
t
x_{float}
xfloat表示量化前的输入数据,有
x
q
−
m
e
a
n
s
t
d
=
x
f
l
o
a
t
\frac{x_q-mean}{std}=x_{float}
stdxq−mean=xfloat
x
q
∈
[
0
,
255
]
x_q\in[0,255]
xq∈[0,255],而
x
f
l
o
a
t
∈
[
−
1
,
1
]
x_{float}\in[-1,1]
xfloat∈[−1,1],所以
s
t
d
=
255
÷
2
=
127.5
std=255\div 2=127.5
std=255÷2=127.5,这样也可以得到
m
e
a
n
=
127.5
mean=127.5
mean=127.5。三种常见的输入范围的量化参数为:
- range(0,255): mean=0,std=1
- range(-1,1): mean=127.5,std=127.5
- range(0,1): mean=0,std=255
- (这个部分API太乱,没有找到确定的信息,可能不对)指定converter.default_ranges_stats = (0, 1)是所有层数值的范围,由于使用的Uint8量化,输出的数据也是0-255,而输出层需要转化为我们期待的结果,如0-1的float数据。在tf1.14.0中需要显式地指定这个参数,否则转换的时候会失败。这个有个说法是设置后,所有层的输出数值都会到这个范围内,实际使用中感觉不是这样的。如设置为0-1后,输出层的结果为0-255,并非0-1。在得到0-255的输出结果后,需要dequantize才能获得想要的结果。dequantize的方式可以通过Netron打开模型文件,或者在输出层tensor里面的参数获取。
- 在这里,用Netron打开了一个模型,在输入的时候,由于是Uint8类型的数据,通过quantization表示的数据进行Uint8->float32的转化,在输出的时候,同样适用quantization将Uint8类型的数据,转化为后处理可以理解的那样的。
3. 混合量化
import tensorflow as tf
saved_model_dir="/path/to/mobilenet_v1_224"
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
tflite_model=converter.convert()
open("converted_model.tflite","wb").write(tflite_model)
混合量化模型中参数是int8和float32一起的,具体使用什么数据类型,实际运算根据硬件支持情况而定
4. 存整数量化
import tensorflow as tf
saved_model_dir="/path/to/mobilenet_v1_224"
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
def data_generator():
for i in range(steps):
# get sample input data
yield [input_sample]
converter.representative_dataset = data_generator
tflite_model=converter.convert()
open("converted_model.tflite","wb").write(tflite_model)
将模型参数量化为int8,但是需要在data_generator
中给出样本范例。
5. 训练中量化
import tensorflow_model_optimization as tfmot
model=build_model()
model_to_quantize = tfmot.quantization.keras.quantiza(model)
....
model_to_quantize.fit(....)
在训练过程中的量化。
6. 模型剪枝
import tensorflow_model_optimization as tfmot
model=build_model()
pruning_schedule =tfmot.sparsity.keras.PolynomialDecay(
initial_sparsity = 0.0,
final_sparsity = 0.5,
begin_step = 2000,
end_step = 4000
)
model_for_pruning = tfmot.sparsity.keras.prune_low_magnitude(model,pruning_schedule=pruning_schedule)
...
model_for_pruning.fit(......)
在剪枝50%的时候,基本上只有微小的精度损失。
ref
https://www.youtube.com/watch?v=Qef8-xgTE7s