发新帖

tensorflowLite的量化使用问题

[复制链接]
20215 96
人工智障_(:」ㄥ  TF荚荚  发表于 2019-3-17 12:03:22 | 显示全部楼层
本帖最后由 人工智障_(:」ㄥ 于 2019-3-17 12:05 编辑

我这边卡了两周bug以后走通了,讲一下我遇到的问题吧,tensorflow挺坑的,而且一些琐碎问题非常non-sense。我是做卷及网络的量化,基于mobilenet v2做的一些改进,操作基本上还是mobilenet v2的那些操作(conv2d, separate_conv2d, relu6, batch_norm),版本是tf1.12和tf1.13(这两个版本tf1.12里是tf.contrib.lite,tf1.13就直接tf.lite了),用的api是tf.contrib.slim(2.0以后contrib没有了,也不知道该怎么办)
为了成功量化,网络不能按常规方法定义没,而是要写成这样,我举个例子:

with slim.arg_scope([slim.separable_convolution2d],
                            normalizer_fn=slim.batch_norm,
                            activation_fn=tf.nn.relu6):
                with slim.arg_scope([slim.batch_norm],
                                      is_training=is_training,
                                      center=True, scale=True):
                            x = slim.separable_convolution2d(x, out_channel, [3, 3],
                                                                 depth_multiplier=1, stride=stride,
                                                                 biases_initializer=None, biases_regularizer=None)

而且我每一层要这样写,最后在整体网络上还要加上类似的with slim.arg_scope来定义卷积层的activation和norm,但是在中间一层调用backbone的时候却不用写这个,我也不知道为什么。试了很多次不同的排列组合,最后玄学成功了。

后面的训练和量化就是直接调用creat_training_graph和creat_eval_graph,然后用python api的tflite_converter。最开始在mac上面出问题,在linux上面不能直接用python api的convert_from_session,必须要导出frozen graph再用命令行工具转换。后来mac上可以成功转换了,但是linux好像还是得用命令行covnert from frozen graph。

说了这么多,总结一句话就是tensorflow太坑了,caffe2的量化工具开源以后大家可以去试试fb的那一套。
本楼点评(0) 收起
shenyichen105  TF荚荚  发表于 2019-3-23 07:22:35 | 显示全部楼层
本帖最后由 shenyichen105 于 2019-3-23 07:27 编辑

同卡在这个坑里两个星期, 今天终于爬出来了。 我网络是用keras写的一维mobilenetV2。  上来先花了一个半星期研究如何让create_training_graph和create_eval_graph两个api创建正确的fake quantized graph。读了半天源码最后发现那个api没法识别keras batch normalization层, 只能自己用tf的api重写了一个网络然后把keras网络里用float32预训练好的权重转进去, 因为有bn层的存在,training和eval的图还不一样,只能分别建图然后互相转weights。试了很多错以后终于成功转换 。 不过在第二步convert成tflite全量化模型之后发现精度完全不行。整整debug了一星期之后最后发现是input_stats没调好。这个参数相当重要!差一点点最后inference结果就差很多。 最后是手动先把我的数据量化成(0,255)然后设置input_stats = (0,1)终于成功。感觉tf的工具真的挺难用的,不过似乎目前在量化的方向没有其他的选择。
本楼点评(5) 收起
  • ZongjunExactly...我当时调input_stats也调了好长好长时间,然后终于搞明白了。因为它决定了 float32如何量化至uint8,所以差一点结果就会差很多。。
    2019-3-27 12:49 回复
  • shenyichen105回复 Zongjun :没错。。btw还是要感谢大神你的之前的回复提醒了我 否则我可能还不知道要同时创建training和eval两个不同的图才能正确转换,估计现在还陷在坑里呢。。
    2019-3-28 08:34 回复
  • Zongjun回复 shenyichen105 :不谢不谢!互相帮助哈!
    2019-3-29 01:39 回复
  • 九幽您好,我之前是keras写的yolo,但是到了量化阶段就完全不知道怎么写那个output了,,,想问下您的keras那个版本是怎么创建两个图的啊?
    2019-4-8 11:53 回复
  • 小坏坏这种方法的出来的,基本不会比量化训练得到的结果好,所以最好还是通过量化训练,得到量化好的pb,再通过toco转化,这种方法得到的量化结果才比较好
    2019-11-22 16:33 回复
Smit  TF荚荚  发表于 2019-3-29 14:44:29 | 显示全部楼层
Zongjun 发表于 2018-12-17 02:23
1.请问你用的是什么版本的tensorflow?你要去下载tf.nightly版本,这个我跟你建议过两三次了,你好像没给 ...

Hi,
@Zongjun 感谢大神给大家耐心的答疑,我最近在做基于ssd的量化训练的东西,您应该是我能求助到的最靠谱的人了
我现在的情况是,将ssd模型改成多输出模式(因为用的第三方的代码,包含了一些不支持的op),已经量化训练,生成了tflite文件,我想求教的问题是:
1.如何在本地测试tflite文件呢?您有什么例子可以提供吗?目前没什么方向。。
2.不太清楚对于多输出的目标检测网络,怎么来写测试脚本……把softmax的结果直接合并就可以吗?
3.我看上面有个人贴出来的代码,有tf.contrib.lite.Interpreter,可是我这里报错'tensorflow.contrib' has no attribute 'lite',难道是版本问题?
4.最后一个问题是十分好奇的了,网上也没有搜到,用toco或者bazel工具时候,--mean_values --std_dev_value这两个参数是根据经验选取的吗?有什么常用参数呢?

谢谢!期待您的回复
本楼点评(16) 收起
  • Zongjun1. 测试.tflite模型,我用过python interpreter,基本就是调用api,你可以试试哈!
    3. tensorflow github里原先lite这个文件夹是存在于contrib文件夹中的,现在lite不在contrib中了,直接调用tf.lite.interpreter试一下?
    4. 这个问题我研究了很长时间,目前得到了确切答案。你看这个链接:https://stackoverflow.com/questions/54261772/tensorflow-lite-toco-mean-values-std-values. 这个问题的答案是谷歌官方的回答。
    2019-4-1 13:08 回复
  • Zongjun2. 我目前没有做过多输出的目标检测网络,所以给不了什么好的建议。感觉可以stackoverflow上搜一下或者问一下?嘿嘿。
    2019-4-1 13:10 回复
  • Smit回复 Zongjun :谢谢!我在网上找到分类模型测试tflite的代码,但是迁移到检测模型上我就有些糊涂了,我想请教一下:
    1.本地测试tflite,并不是使用sess-run的方式?似乎是先allocate_tensors,读取数据后,再set_tensor-invoke-get_tensor,是这样的流程吗?
    2.我再写测试脚本的时候,意识到好像tflite要包含location信息,这样加载tflite脚本中get_output_details的时候,location和classification都要直接获取,不知道我理解的对不对。。
    3.这样就引出我的最不知道如何解决的问题了......我TF使用时间不久,不太熟悉,转tflite的过程中,将inference阶段的图freeze到pb的时候,我只保存了softmax信息,location不知道怎么保存。。。我感觉说的语无伦次,我贴一下代码,麻烦大神帮忙看看
    2019-4-1 17:19 回复
  • Zongjun回复 Smit :1. tflite的测试可以考虑使用python tensorflow lite interpreter api。这个也是在sess下运行的。
    2.如果用上述interpreter的方法,我没有碰到需要location信息的地方,可能我不是很理解何谓location?
    不清楚location的节点名字的话,这一点比较好解决。用Netron,打开你的.pb file,整个网络的细节甚至参数的具体数值都能看到。(当然要先去下载安装Netron,这个比较简单,点两下鼠标就安好啦。)
    2019-4-3 04:43 回复
  • Zongjun回复 Smit :Netron链接:https://github.com/lutzroeder/netron
    2019-4-3 04:43 回复
  • Smit回复 Zongjun :好的好的,我试试看,谢谢~
    2019-4-3 16:17 回复
  • Smit回复 Zongjun :hi, 我想再请教您一个问题,是我在测试tflite文件的时候遇到的。我做的是ssd的量化,一切都成功了但是测试tflite的时候,发现不返回任何box,我debug发现,利用tflite_model.get_tensor(output_details[idx]['index'] 从tflite中获取的box信息,跟我在未freeze的ckpt的debug结果中看到的截然不同:
    ckpt获取的box坐标很正常,有很多小数,但是tflite获取到的,是诸如:[15  0  0  0] [ 0  0  9  9][37 15  4  0],怎么会有这么多0呢,而且跟ckpt的查别也太大了
    我想请教的是,您遇到过这种问题吗?会不会是freeze时候出的问题呢?
    谢谢~
    2019-4-8 21:04 回复
  • Zongjun回复 Smit :如果ckpt的结果是对的,说明training没问题。如果怀疑freeze出问题了,我的想法是freeze完得到的.pb文件,先用Netron看一下,是否有问题。如果没有问题,用Tensorflow load进这个.pb 文件,读入Model,再做测试,看看是不是正确。如果正确,那么freeze也没有问题,那么就剩下toco了,你关掉所有的量化,toco就是直接生成一个float32的tflite模型,看看有没有上述的bug,如果有可能量化出问题了。关掉了量化要是还不行,就考虑用他提供的pre-trained的例子跑一下看看有没有这个bug。嗯。
    2019-4-9 07:27 回复
  • Smit回复 Zongjun :Hi 大神,我尝试另一种方法进行量化,似乎更有效,
    convert = tf.contrib.lite.TFLiteConverter.from_frozen_graph("frozen_graph4_8.pb", input_arrays=input_, output_arrays=output_)
    convert.post_training_quantize = True
    tflite_model = convert.convert()
    open("model.tflite", "wb").write(tflite_model)
    我想请教的是:
    1.这样转化跟toco转化是等价的吗?
    2.为什么toco转出来的,跟上述代码转出来的tflite,用Netron查看,不太一样呢?
    用代码转的tflite中有dequantize这个op,我可否认为这是成功的标识?
    3.最后想请教您一个工程问题,一般量化后模型的精度会下降,您有什么优化技巧或经验吗?
    再次,万分感激!
    2019-4-10 09:13 回复
  • Zongjun回复 Smit :啊,不对,你第二种方法用的是post_training quantization。这个方法只是quanitze weights而不会quantize bias和activations.并且inference的时候是转化回float32进行计算。所以如果你训练时做了fake quantization,那么toco的地方就不要用post_training_quanitzation了,直接用QUANTIZED_UINT8。
    我用toco一直是你的这个第二种形式,即python api。所以第二种这个形式没错,就是你的flag有些问题。这个方法就是toco。只不过叫做 TFLiteConverter而已。
    理论上fake quantize了之后再用tflite fully quantize,你的model的准确率不应该下降很多,除非:
    1. 你的model非常小,非常简单,这个时候可能会有问题。
    2. 你的toco声明的mean 和std是错的,这两个数错一点,最后的inference就会错很多。具体你可以翻一翻这篇以前的评论,我应该有公式。
    2019-4-12 07:36 回复
  • Smit回复 Zongjun :Hi 大神,很感激您的回复,我按照您的指导,没有使用post_training quantization,直接用QUANTIZED_UINT8,但是我怀疑我的转换方式依然有问题,因为测试了一下tflite,几乎没有精度……debug发现,转tflite前的.pb模型,测试结果正常,返回的prediction和localisation都是正常的,例如[0.08482143 0.29910713 0.16517857 0.37946427],但是从tflite获取到的是诸如[ 0 17  0 13]这样的结果……感觉好奇怪,我贴一下转换代码,还要麻烦大神有空帮忙看看,真心求指导了
    convert = tf.contrib.lite.TFLiteConverter.from_frozen_graph("frozen_graph.pb", input_arrays=input_, output_arrays=output_)
    convert.inference_type = tf.contrib.lite.constants.QUANTIZED_UINT8
    input_arrays = convert.get_input_arrays()
    convert.quantized_input_stats = {input_arrays[0]: (0., 1)} # 因为我检查了一下train代码中,主干网络第一层的输入是0~255,所以这里设置均值0方差1,不知道对不对
    tflite_model = convert.convert()
    open("model.tflite", "wb").write(tflite_model)
    2019-4-15 09:40 回复
  • Zongjun回复 Smit :你的代码看起来正常。你用Netron打开.tflite model 看看各个node和里面的parameters是不是正常,然后都是uint8类型了。然后就是你是怎么测试.tflite model的呢。如果用的是interpreter的python api,可以看看网上的例子,有可能调用interpreter api时出错了。
    quantized_input_stats这里,看起来是对的,但是保险起见,我建议你改一些数字试试看精度会不会有变化,如果有的话那就是这里出错了。这个有一点不对,精度差别就会很大。
    2019-4-16 08:04 回复
  • Smit回复 Zongjun :谢谢大神的回复,我基本确定就是我测试tflite的代码错了,是用的interpreter,但是后处理有问题。我的理解是,原本预测的0~1的数据(prediction和localisation)在量化过程中被推到0~255了,所以数据变得比较大,但是如何把这个大数映射回去呢?毕竟后处理阶段有一些box select等,直接除以255的话精度损失很大,我昨天查资料了解到,似乎应该有一个反量化的过程,大神有这部分工作的demo可以参考吗?
    2019-4-16 11:28 回复
  • Zongjun回复 Smit :我简单搜了一下,看到了这个链接:https://www.tensorflow.org/lite/models/object_detection/overview
    你看它output的locations,都是uint8的数字,并不是float32,但是依然是work的。你可以研究研究这个哈。
    2019-4-18 01:46 回复
  • Smit回复 Zongjun :谢谢大神~我研究一下
    2019-4-18 11:37 回复
  • Zongjun回复 Smit :不客气不客气。Good Luck!
    2019-4-20 01:57 回复
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 回复
  • Zongjun回复 我本是山下那棵 :哈,我首先比较好奇,你之前的那个问题是怎么解决的?创建了两个graph导入trained checkpoint了嘛?
    新的这个问题嘛。。。我属实是没见过。。不过,还是Debug万能大法,用Netron打开你的.tflite文件,看看转化后的.tflite是不是正确的,这个永远都是第一步。找到出问题的那个Node,看一下它的shape, 和内容,是不是和你预期的一样。如果不一样说明训练到toco中间出了问题。如果一样,那就更细节了,你要想想怎么改一下你的graph,绕开这个问题。Good Luck!
    2019-6-26 00:38 回复
  • ambarion回复 我本是山下那棵 :您好,我遇到了和您一样的问题,请问您这个问题解决了吗?具体是如何解决的呢?
    2019-12-5 10:46 回复
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) 收起
Aluds  TF荚荚  发表于 2020-2-27 15:31:44 | 显示全部楼层
@Zongjun 你好:
前面有看到可以先用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)
"訓練出來的結果不是很好
謝謝你
本楼点评(0) 收起
dy247846795  TF荚荚  发表于 昨天 20:51 | 显示全部楼层
Zongjun大神你好,我在尝试使用tflite对LeNet模型进行量化,并转移到FPGA上进行推断。我完整地通过了伪量化、freeze、最终转化为tflite模型。我注意到在tflite模型中,conv2d层的输出直接是uint8型,并且记录好了零点和scale等量化信息。但是按理来说,经过conv2d层之后,进行了8bit与8bit的乘法并施加一个32bit的偏移量,输出应该是32bit,再经过一次反量化->量化才能变成8bit。这个步骤在tflite模型上怎么没有看到呢?那tflite上这个输出的量化信息对应的究竟是32bit的呢?还是经历dequantize->quantize后8bit的呢?

因为我并没有直接使用tflite,而是在硬件描述语言中,新建了一个推断模型。我希望将tflite上的量化信息复制到我的推断模型上。但由于自己写的推断模型在conv2d后应该输出32bit,所以我自己写了一个dequantize和一个新的quantize,用的量化信息是tflite上面的8bit输出信息。这样下来,最终的推断结果是完全错误的,与训练时的结果完全对不上。请问这是怎么回事呢?如果能您能解答一下,不胜感激!
本楼点评(0) 收起
您需要登录后才可以回帖 登录 | 加入社区

本版积分规则

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