发新帖

tensorflowLite的量化使用问题

[复制链接]
17694 91
nick_nie  TF荚荚  发表于 2019-4-7 19:25:12 | 显示全部楼层
@Zongjun, 大神,你好!最近在用腾讯开源的pocketflow做量化,遇到了一个小问题,就是在量化训练结束后,需要将生成的meta文件转pb,然后再转tflite,我原先训练的时候是固定size的,现在做测试时想要任意大小,就将下面代码placeholder的shape改成[1, None, None,3],但是报错:ValueError: None is only supported in the 1st dimension. 所以说有办法测试时是任意大小的吗?
# restore the graph with inputs replaced
    net_input = tf.placeholder(tf.float32, shape=[1, None, None, 3], name=net['input_name'])  # input_name: net_input
    saver = tf.train.import_meta_graph(
      file_path_meta, input_map={net['input_name_ckpt']: net_input})  
    saver.restore(sess, file_path_meta.replace('.meta', ''))
本楼点评(2) 收起
  • Zongjun不好意思,我没用过腾讯的这个pocketflow哎。不过,看了一下你的问题,我感觉这个post可能对你有用,我不确定哈。https://github.com/tensorflow/tensorflow/issues/21986
    2019-4-9 07:38 回复
  • nick_nie回复 Zongjun :没事哈, 感谢大神回复~~
    2019-4-9 10:38 回复
nick_nie  TF荚荚  发表于 2019-4-10 01:21:37 | 显示全部楼层
之前看到论坛里有好多对基于slim框架的模型量化成功了,我最近基于deeplabv3+的模型进行量化遇到了一个问题,首先导入了resnet_v2_101的backbone,deeplabv3+模型后面的部分我在debug时先注释掉了,然后前向传播是没有问题的,就是在开始create_training_graph时报了错:tensorflow.python.framework.errors_impl.InvalidArgumentError: Cannot update edge, incompatible shapes: [?,8,8,512] and [?,16,16,512].

以下是模型部分代码:

  1. if FLAGS.base_architecture not in ['resnet_v2_50', 'resnet_v2_101']:
  2.         raise ValueError("'base_architrecture' must be either 'resnet_v2_50' or 'resnet_v2_101'.")

  3.     if FLAGS.base_architecture == 'resnet_v2_50':
  4.         base_model = resnet_v2.resnet_v2_50
  5.     else:
  6.         base_model = resnet_v2.resnet_v2_101

  7.     with tf.contrib.slim.arg_scope(resnet_v2.resnet_arg_scope(batch_norm_decay=_BATCH_NORM_DECAY)):
  8.         logits, end_points = base_model(inputs,
  9.                                         num_classes=None,
  10.                                         is_training=is_train,
  11.                                         global_pool=False,
  12.                                         output_stride=FLAGS.output_stride) # output_stride=16
  13.      inputs_size = tf.shape(inputs)[1:3]
  14.     net = end_points[ FLAGS.base_architecture + '/block4']  # [None, 16, 16, 2048]
复制代码

输入size是256x256x3,有大神知道是怎么回事吗?
本楼点评(3) 收起
  • 徐建君你好,我也遇到与你一样的问题,请问你解决没?
    2019-5-10 00:39 回复
  • nick_nie回复 徐建君 :感觉create_training_graph 对 dilated convolution 会有bug,没有再往下继续了,不好意思!  
    2019-5-20 13:02 回复
  • 小坏坏这个问题我解决了,主要是slim.conv2d中有两个参数,rate 和 stride ,这两个的设置,要么是rate=1 stride=other 要么stride=1 rate=other ,我使用的是第一种,第二种应该也可行,但是我没有试过。大致的写法如下:
                with slim.arg_scope([slim.conv2d],
                    normalizer_fn=slim.batch_norm,
                    weights_initializer=tf.truncated_normal_initializer(stddev=0.01),
                    biases_initializer=tf.constant_initializer(0.01)):
                    with slim.arg_scope([slim.batch_norm],center=True,
                        scale=True,
                        is_training=is_training):
                        x = slim.conv2d(x, num_outputs=channels,kernel_size=[kernel,kernel],stride=stride)
    2019-11-22 16:22 回复
龙仔  TF荚荚  发表于 2019-4-20 14:40:34 | 显示全部楼层
本帖最后由 龙仔 于 2019-4-20 23:14 编辑

@Zongjun,您好,我最近一直在尝试量化训练,但是遇到一个问题一直没有找到解决方案。在我的网络中有batch_normalization 层, 在转tflite的时候一直提示我“FusedBatchNorm_mul_0, which is an input to the Add operator producing the output array kws_model/KWS_Model/tower_0/CNN_V1/Relu, is lacking min/max data, which is necessary for quantization. Either target a non-quantized output format, or change the input graph to contain min/max information, or pass --default_ranges_min= and --default_ranges_max= if you do not care about the accuracy of results." 我尝试将bn层删除但是又紧接着提示我最后一层出现的错误“prediction does not have MinMax information, and is not a constant array. Cannot proceed with quantization.” 请问这个问题可能是什么原因导致的呢?最后一层正常来说需要最量化么??多谢
本楼点评(12) 收起
  • Zongjun这个问题我也碰到了。我目前用batch_normalization唯一成功的套路是,在tf.slim中做mobilenet 的伪量化,其中加入了bn。我freeze模型以后得到.pb文件,用netron打开看,我发现bn是被分解成了一个一个的add/mul 操作而不是一整个叫做fusedbatchnorm的node。
    直接用fusedbatchnorm这个操作,我得到的错误和你是一样的。我没有再往下去debug这里,我的项目要求是计算量尽可能的小。所以我感觉你可以看一下slim的mobilenet那里的batch norm,看看能不能用到你的项目上?
    2019-4-24 01:01 回复
  • 龙仔回复 Zongjun :好的,多谢大佬深夜回复。
    2019-4-24 11:05 回复
  • 龙仔回复 Zongjun :暂时将bn层去掉了,先规避了这个问题。
    2019-4-24 11:10 回复
  • Zongjun回复 龙仔 :不客气不客气,你将来要是debug出了这个问题可以回来分享一下哈!Good Luck!
    2019-4-26 00:42 回复
  • 我本是山下那棵回复 Zongjun :您好,我使用lite模块将训练好的pb模型转换为lite模型后,lite模型在PC端的测试不同分类图片都为同一个结果,output仅包含1.和0.(softmax节点),pb模型运行正常,分类正确。请问您遇到过类似的问题吗?对于这个问题想了好久没有思路,如果您了解这方面的知识希望不吝赐教。
    2019-6-19 21:12 回复
  • Zongjun回复 我本是山下那棵 :如果用的是quantization-aware training,在tflite这里要启用fully-quantized。还需要在toco的指令里给出mean和std这些input stats,这两个值稍微错一点,预测结果就会差非常大。(因为你的pb模型预测正常,我就默认你的训练和模型没什么问题了。)
    首先,我觉得应该检查模型本身。用Netron这个软件打开你的.tflite文件,看看你的模型是否正确。该有的层都在,该量化的都量化了。内部参数看起来比较正常。这些都需要先确保正确。
    然后可以调一下mean/std那两个值,看看有没有什么变化。这两个值具体的公式我记得我在这个帖子里贴过,你可以找找看哈。
    2019-6-20 00:44 回复
  • 我本是山下那棵回复 Zongjun :前边的问题已经解决,是由于网络中存在batch_normal造成的精度问题,请问我的quantization-aware training是正确的吗?虽然结果是正确的,也可以看到mIn 和max但是在pb转tflite的时候出现了这个错误ValueError: Input 0 of node conv2/weights_quant/AssignMinLast was passed float from conv2/weights_quant/min:0 incompatible with expected float_ref.
    2019-6-24 21:23 回复
  • 我本是山下那棵回复 Zongjun :class mobileNet:
        training = True
        def __init__(self, height=160, width=160, channel=1, n_class=100):    # <tf.Tensor 'x:0' shape=(?, 160, 160, 1) dtype=float32>

            self.tfx = tf.placeholder(tf.float32, [None, height, width, channel], name='x')
            self.tfy = tf.placeholder(tf.float32, [None, n_class], name='y')


            layer1_conv1_in = channel
            layer1_conv1_out = 60

            conv1_weights = self.wight_variable([3,3,layer1_conv1_in,layer1_conv1_out])
            conv1_biases = self.bias_variable(shape=[layer1_conv1_out])        

            conv1 = tf.nn.conv2d(self.tfx, conv1_weights, strides=[1, 2, 2, 1],padding="SAME",name="conv1")   conv1_biases
            pool1 = self.max_pool(conv1, 'pool1')

            .....
                    .....
                    .....

            nodes = conv6.shape[1]._value * conv6.shape[2]._value * conv6.shape[3]._value  # nodes 38400
            self.flatten = tf.reshape(conv6, [-1, nodes])
            self.out = tf.layers.dense(self.flatten, n_class, name='out')  # <tf.Tensor 'out/BiasAdd:0' shape=(?, 100) dtype=float32>
            self.softMAX = tf.nn.softmax(self.out, name='softMAX')
            self.sess = tf.Session()
            self.loss = tf.losses.softmax_cross_entropy(onehot_labels=self.tfy, logits=self.out)
            if self.training:
                tf.contrib.quantize.create_training_graph(input_graph=tf.get_default_graph(), quant_delay=100)
            
                    self.train_op = tf.train.AdamOptimizer(0.001).minimize(self.loss)
            self.correct_prediction = tf.equal(tf.argmax(self.tfy, 1), tf.argmax(self.out, 1))
            self.accuracy = tf.reduce_mean(tf.cast(self.correct_prediction, tf.float32))
            
                    if not self.training:
                tf.contrib.quantize.create_eval_graph(input_graph=tf.get_default_graph())
            self.sess.run(tf.global_variables_initializer())
    2019-6-24 21:25 回复
  • Zongjun回复 我本是山下那棵 :我有以下想法:你的代码可能没有真正的创建两个图。代码中多写函数会清楚一些。比如,写一个build_model函数用于创建图。然后写两个script,train_script里只做train,里面创建train graph,然后有create_training_graph。另一个eval_script里,创建一模一样的只做eval的图,调用的是同一个build_model函数。eval_script的图导入train_script训练好的checkpoint files,然后create_eval_graph,最后在eval_script里freeze成.pb文件。这样可以确保把两个图完全分开。
    你的代码好像缺少了存储checkpoint file,然后新建一个graph再导入的这个步骤。
    2019-6-25 01:00 回复
  • 我本是山下那棵回复 Zongjun :您好,我完成了tflite的转化,但是在调用的时候显示Transpose op only supports 1D-4D input arrays.Node number 11 (TRANSPOSE) failed to prepare.错误的原因在于interpreter.allocate_tensors(),大概意思是我的某个张量不是1-4D,关于这点我不太了解,Stack Overflow上有人提出了一样的问题但是没有解答,请问您是否了解这方面的知识?
    2019-6-25 19:59 回复
liangdas  TF荚荚  发表于 2019-4-24 21:05:26 | 显示全部楼层
@Zongjun  
你好,请教个问题:tf.multiply操作在转tflite的时候报错
net = tf.multiply(net_resize, net, name=scope+'_add_regular')

错误信息:is lacking min/max data, which is necessary for quantization.
本楼点评(6) 收起
  • look@Zongjun 大神以及各位朋友你们好。请问我在量化训练superpoint算法时,加入create_eval_graph后,出现错误:ValueError: Training op found in graph,exiting{'ApplyAdam'}是怎么回事?和训练时创建model是一样的。谢谢
    2019-4-25 11:39 回复
  • Zongjun回复 look :你去下载一个叫做Netron的软件,用它打开看看你freeze以后得到的.pb file。tf.multiply那里应该有fake quant node,这个是记录你的min 和max的。看你的第二个问题,请问你在训练的时候用了 create_training_graph()这个函数嘛?这个是必须要用的。
    2019-4-26 00:44 回复
  • look回复 Zongjun :@Zongjun谢谢大神。在加入create_eval_graph时报错"ValueError: Training op found in graph,exiting{'ApplyAdam'}"这个问题解决了,是因为eval建图的时候调用了训练时建model的函数,表征是否训练的参数没设置正确。现在还有一个问题,报错:NotFoundError : Restoring from checkpoint failed. This is most likely due to a Variable name or other graph key that is missing from the checkpoint. Please ensure that you have not altered the graph expected based on the checkpoint. Original error:Key superpoint/eval_tower0/descriptor/conv1/conv/act_quant/max not found in checkpoint.请问大神,是因为只是这一层的max没有加进去,需要手动添加吗?现在freeze没有成功,看不了freeze.pb   谢谢您
    2019-4-26 10:19 回复
  • look百度了一下,有人说是由于使用了tf.train.AdamOptimizer()来更新梯度,所以在保存检查点的时候如果不指定则是全局保存,把优化的变量类似“w_out/Adam”这种命名规则的变量也一并保存了,自然在恢复的时候就会出现找不到XX变量。解决办法,在声明 saver = tf.train.Saver()的时候带上参数,即需要保存的变量。是这样吗?
    2019-4-26 11:30 回复
  • look把AdamOptimizer改成GradientDescentOptimizer之后还是报同样的错:Key superpoint/eval_tower0/descriptor/conv1/conv/act_quant/max not found in checkpoint。
    2019-4-26 14:50 回复
  • Zongjun回复 look :这个错误应该是你的eval graph和training graph不一样导致的。你得确定你的这两个图完全一致(除了batch normalization之外如果有的话)。如果有手动加入的node,那在你的eval也是要有的,否则你的两个图还是不一样。
    这个得看你的具体代码怎么实现的了。
    2019-5-1 00:59 回复
薛俊锋  TF荚荚  发表于 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位量化吧
本楼点评(1) 收起
  • sunyanli您好,我前一段时间也在做这个,也是这样改的,我个人感觉这个是不对的。用toco转变的时候,好像只支持float和int8,要是量化成16bit,toco这个工具源码估计也得改。
    我是这么想的。这个量化方法不是google发的那篇论文有详细论述吗,里面不是有个量化公式:q=r/s  z 吗,我们要改成其他bit的量化,首先得改量化间隔,如果代码是根据这个量化方案写的,这个代码里面这一部分,改到n不就可以啦?可是目前我还没有找到。你有其他想法吗?
    2019-5-9 22:46 回复
小祥  TF荚荚  发表于 2019-6-13 11:19:26 | 显示全部楼层
你好。我最近在尝试量化 open pose这个项目, 已经成功得到了quantized aware training的模型,并且用 evaluation graph得到了 pb 文件,之后用 freeze_graph.freeze_graph得到了frozen pb,这些步骤都成功了,但是之后将pb 转为 tflite的模型过程中一直报错 ,错误都是类似的:

Unimplemented: this graph contains an operator of type Cast for which the quantized form is not yet implemented.

我尝试修改bug。 第一次报错是 contains an operator FusedBatchNormV3 which the quantized form is not yet implemented, 我在tensorflow12.0 环境下freeze 模型,得到的便是FusedBatchNorm 而不是FusedBatchNormV3 了(之前用的是tensorflow14.0rc版本)
第二次报错是 contains an operator Size which the quantized form is not yet implemented. 我将eval 模型中的 batchsize固定为1,  该错误消失
第三次报错是contains an operator Cast which the quantized form is not yet implemented, 具体的位置如下图所示:

这个错误找了好久都没法解决。不知道成果转换之后的模型 fuse batchnorm这块都是什么样的呢。我现在没法确定是伪量化训练过程中的问题,还是说是eval中的问题。求大神指导。

多谢!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?加入社区

x
本楼点评(0) 收起
happy_national  TF荚荚  发表于 2019-7-10 09:42:16 | 显示全部楼层
@Zongjun  
大神您好,请教一下,我目前针对自己的tensorflow模型已经freeze成pb文件并通过toco命令行转换为tflite文件了,现在使用的是Post Training Quantization方式,使用Netron查看生成的tflite模型文件也好像没问题,但是我想在PC端运行测试下该模型的效果,却总是报错:
[{'name': 'Placeholder', 'index': 10, 'shape': array([ 1, 288, 800, 3], dtype=int32), 'dtype': <class>, 'quantization': (0.0, 0)}] self.interpreter.allocate_tensors() File "/home/anaconda3/envs/tensorflow13_gpuenv/lib/python3.7/site-packages/tensorflow/lite/python/interpreter.py", line 73, in allocate_tensors return self._interpreter.AllocateTensors() File "/home/anaconda3/envs/tensorflow13_gpuenv/lib/python3.7/site-packages/tensorflow/lite/python/interpreter_wrapper/tensorflow_wrap_interpreter_wrapper.py", tensorflow/lite/kernels/concatenation.cc:57 t0->dims->size &lt;= 4 was not true.Node number 259 (CONCATENATION) failed to prepare. 希望您看到后有空帮忙解答一下,不胜感激!(目前就想看下直接采用Post Training Quantization的压缩模型前向测试效果咋样,环境是tensorflow-gpu1.13,也正准备安装tf-nightly)

本楼点评(0) 收起
zjq-crystal  TF荚荚  发表于 2019-8-13 16:06:14 | 显示全部楼层
大家使用量化都是在移动端吗?没有在服务器端的么?有使用过Intel 的量化工具的么?
本楼点评(0) 收起
yucheng  TF荚荚  发表于 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
这边想请问大神,是我在设计上有疏忽了啥运算吗?还是有哪边的运算搞错了?
本楼点评(1) 收起
  • yucheng我找到问题的源头了我直接用浮点数的形式将input,kernel,output的scale相乘,再截乘int32的形式,不过在tflite的运算里,似乎是先各别转成int32再相乘,然后再截成int32的M值
    2019-9-10 14:58 回复
热心市民刘先生  TF荚荚  发表于 2019-10-25 10:26:11 | 显示全部楼层
大神我想问一下,我生成的pb文件的大小大约是原来ckpt文件的三分之一左右。pb文件是将ckpt文件的权重固化到计算图上,这一步应该还是float32类型吧,按道理pb文件的大小应该和ckpt文件差不多大才是啊。
本楼点评(0) 收起
小坏坏  TF荚荚  发表于 2019-11-22 16:19:15 | 显示全部楼层
nick_nie 发表于 2019-4-10 01:21
之前看到论坛里有好多对基于slim框架的模型量化成功了,我最近基于deeplabv3+的模型进行量化遇到了一个问题 ...

这个问题我解决了,主要是slim.conv2d中有两个参数,rate 和 stride ,这两个的设置,要么是rate=1 stride=other 要么stride=1 rate=other ,我使用的是第一种,第二种应该也可行,但是我没有试过。大致的写法如下:
            with slim.arg_scope([slim.conv2d],
                normalizer_fn=slim.batch_norm,
                weights_initializer=tf.truncated_normal_initializer(stddev=0.01),
                biases_initializer=tf.constant_initializer(0.01)):
                with slim.arg_scope([slim.batch_norm],center=True,
                    scale=True,
                    is_training=is_training):
                    x = slim.conv2d(x, num_outputs=channels,kernel_size=[kernel,kernel],stride=stride)

本楼点评(1) 收起
AaronFitting  TF荚荚  发表于 2019-12-7 21:24:34 | 显示全部楼层
Zongjun 发表于 2018-10-24 05:38
以下是我的个人理解,如果是在android 上,Tensorflow Lite (tflite) 可以利用hardware accelerator,应该 ...

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文件的步骤能不能给一点建议呢?


本楼点评(0) 收起
您需要登录后才可以回帖 登录 | 加入社区

本版积分规则

快速回复 返回顶部 返回列表