TensorFlowLite 的量化使用问题

薛俊锋,发表于 2019-4-30 15:52:43

大神,你好,请问一下 tensorflow 能做 16 位量化吗?我把 create_training_graph (quant_delay=0) 修改成

experimental_create_training_graph (input_graph=None,
                                       weight_bits=16,
                                       activation_bits=16,
                                       quant_delay=2000000,
                                       freeze_bn_delay=None,
                                       scope=None),

按照样例步骤,我能得到 16 位的 my_frozen_graph.pb,但是最后一部转化的时候

bazel-bin/tensorflow/contrib/lite/toco/toco \
--input_file=my_frozen_graph.pb \
--output_file=speech_my_frozen_graph.tflite \
--input_format=TENSORFLOW_GRAPHDEF \
--output_format=TFLITE \
--inference_type=QUANTIZED_UINT8 \
--input_shapes=1,98,40,1 \
--input_arrays=Reshape_1 \
--output_arrays=labels_softmax \
--allow_custom_ops

这个时候的参数–inference_type=QUANTIZED_UINT8 不支持 16 位,相当于我做了 16 位的伪量化,但是最后转换成 8 位的,精度估计会有问题,这不算是 16 位量化吧。


本楼点评:

sunyanli:

您好,我前一段时间也在做这个,也是这样改的,我个人感觉这个是不对的。用 toco 转变的时候,好像只支持 float 和 int8,要是量化成 16bit,toco 这个工具源码估计也得改。
我是这么想的。这个量化方法不是 google 发的那篇论文有详细论述吗,里面不是有个量化公式:q=r/s z 吗,我们要改成其他 bit 的量化,首先得改量化间隔,如果代码是根据这个量化方案写的,这个代码里面这一部分,改到 n 不就可以啦?可是目前我还没有找到。你有其他想法吗?
2019-5-9 22:46


根据回帖和楼层点评整理。

yucheng,发表于 2019-9-9 18:19:58 的自问自答

首先先感谢此版各大神,在进行量化训练时能透过此篇文章慢慢摸索出来。
由于我是针对量化后的 CNN 设计硬体,所以需要将 tflite 的运算输出打印出来,与硬体的运算结果进行比较,但在进行完一整个 layer 的运算后,requantize 的过程中,输出与 scale 相乘再返回 uint8,总会有几笔输出会产生进位问题 (该进位没进位),而我参考的运算是 tensorflow/tensorflow/lite/kernels/internal/common.h 中的 MultiplyByQuantizedMultiplier ,所用到的 SaturatingRoundingDoublingHighMul 和 RoundingDivideByPOT 的函式也能在 gemmlowp/fixedpoint/fixedpoint.h 找到

像是这个实例 x=16809 ,M=0.0008031099569052458
照里面的算法会先将 M 变成介于 [1-0.5) 的值 (M0) 所以 M0 等于 0.8223845958709717, shift -10 在进行相乘后的结果为==>0000000000000000000110101111111110111011001110001101011000000000
接着进行 SaturatingRoundingDoublingHighMul 运算
由于 31bit 为 0,就算有 nudge1<<30 也不会进位
==> 000000000000000000011010111111111
最后进行 RoundingDivideByPOT,根据其运算,在这边也不会进位
最后得到 1101 也就是 13 但 tflite 的结果却是 14
这边想请问大神,是我在设计上有疏忽了啥运算吗?还是有哪边的运算搞错了?

答:
我找到问题的源头了我直接用浮点数的形式将 input,kernel,output 的 scale 相乘,再截乘 int32 的形式,不过在 tflite 的运算里,似乎是先各别转成 int32 再相乘,然后再截成 int32 的 M 值

问:
Zongjun 大神你好,我现在在用 tflite 进行对 ResNet18 的量化,我是从 frozen_graph 的 pd 文件转化成 lite 文件的,pb 文件是从 TF1.15.0 的 contribute.quantize 伪量化训练后得到的 ckpt 转化而来的(Netron 显示 conv 和),已经测试过 pb 文件的模型准确率(90%acc)没有问题,input_mean 和 input_var 也是经过训练集统计后得到的,最后得到的 interpreter (model.lite) 的准确率却超级低,因为我只是在做简单的二分类,而 lite 的准确率就只有 50%了(输入的是 0-255 的 uint8 图片),而且所有输出都是选择第 0 位为最大值(softmax 输出)。打印 interpreter 的 layer 发现多了一个不知道从哪里来的 relu6_1,用 Netron 看模型发现 relu6 并没有被优化掉。输出 interpreter 时还必须设置 converter.default_ranges_stats=(0., 6.),不然会报 biasADD 没有 max,min 的错误,考虑到每个 conv_bias 后面都有一个 relu6,所以我最后也直接用了 default_ranges_stats。请问以上的问题属于正常且正确吗,对于最后生成 lite 文件的步骤能不能给一点建议呢?


AaronFitting,发表于 2019-12-7 21:24:34

前面有看到可以先用 32bit 訓練到收斂後,再使用"tf.contrib.quantize.create_training_graph (quant_delay=20000000)"來做 quantization aware training,想請問該如何再 quantize 訓練時將 32bit 的 weight 當成 pretrain weight 的具體作法,因為我直接使用"tf.contrib.quantize.create_training_graph (quant_delay=20000000)
"訓練出來的結果不是很好
謝謝你


Aluds,发表于 2020-2-27 15:31:44

问:
Zongjun 大神你好,我跑了官方的量化例子,过程都是对的,也大概理解是在训练时合适的位置插入 FakeQuantWithMinMaxVars。现在我想量化利用 openNMT 训练的 Transformer 模型,在 train.py 中加入 tf.contrib.quantize.create_training_graph (input_graph=tf.get_default_graph (),quant_delay=0) 后,发现没有找到匹配的 layer,(模型中有 tf.layers.conv1d,tf.nn.depthwise_conv2d,tf.nn.relu),所以我想我应该只能手动插入 tf.fake_quant_with_min_max_args 或 tf.fake_quant_with_min_max_vars,我想请问一下您,插入时只需要在权重前和 relu 后面插入就行了吧,还需要别的操作嘛,比如梯度之类的(tf.quantization.fake_quant_with_min_max_args_gradient 和 tf.quantization.fake_quant_with_min_max_vars_gradient),那如果是怎么操作的,那测试应该如何操作呢?问题比较多,打扰您了,非常感谢!

1 Like

@snowkylin