发新帖

tensorflowLite的量化使用问题

[复制链接]
11235 74
人工智障_(:」ㄥ  TF荚荚  发表于 2019-3-7 15:04:37 | 显示全部楼层
Zongjun 发表于 2018-11-15 06:19
首先,我记得官方的mobilenet是用slim写的吧?slim我没用过,但是fake quantization本质应该是一样的。
我 ...

请问一下train graph和eval graph是同时创建还是先训练好了再创建eval graph,加载训练的checkpoint呢?另外我这边量化进行到最后一步用toco convert to tflite的时候总是出现up supported operator 'Cast',请问您知道是怎么回事吗?我猜可能是train时fake quant节点在图里面没有删除掉
本楼点评(6) 收起
  • Zongjun我的项目基本是有一个函数,它叫做create_model,专门用来生成图。训练时调用这个函数,生成训练图然后训练,存出来checkpoint files。然后我在另一个完全独立的文件里,再调用create_model这个函数,生成推理图。然后把刚才训练好的checkpoint导入到这个新的推理图中,然后在这个文件里做freeze生成 .pb文件。
    至于fake quant node是否处理正确了,这个和你模型的具体结构有关。我推荐你下载一个叫Netron的软件,用这个软件直接打开你的 .pb 文件。你可以直接看到你图的结构,在需要量化的层(即,数据类型为float32的层)是有fake quant node出现的。如果没有,可能就需要手动插入fake quant node了。
    2019-3-11 05:41 回复
  • 人工智障_(:」ㄥ回复 Zongjun :谢谢您的回复,我去用netron看看
    2019-3-11 16:34 回复
  • jinyuprincess回复 Zongjun :大神你好,想请问一下,用speech-commands例子跑的模型,训练的时候train.py --quanlize=True,但是用freeze.py生成.pb文件后,用netron看模型,并没有quantize node,想请问会是什么原因呢?
    2019-3-13 20:14 回复
  • Zongjun回复 jinyuprincess :这个不应该啊。你freeze.py的指令也 --quantize=True了嘛?
    2019-3-16 01:31 回复
  • jinyuprincess回复 Zongjun :谢谢大神,解决了,没注意到这里,大神每次发现问题都是一针见血~
    2019-3-20 11:18 回复
  • 小祥我也在最后一步试图转换pb到tflite模型时出现 unsupported operator 'Cast', 请问你最后解决这个问题了吗。
    2019-6-13 11:49 回复
sunyanli  TF荚荚  发表于 2019-3-13 16:40:14 | 显示全部楼层
Zongjun 发表于 2018-11-6 08:49
对了,我补充一点,我debug的时候花了不少时间的一个地方:我用的是在linux下,安装tf.nightly,然后jupyter  ...

大神,想请教您一个问题。我按照伪量化的方式量化了lenet网络,但是量化之后,用Netron查看时发现 conv2D卷积变成了depthconv2D卷积。depthconv2D卷积不是深度可分离卷积吗?不是在inception网络中设计出来的吗?希望大神可以指点一下。谢谢。
本楼点评(6) 收起
  • Zongjun我没有用过Lenet,所以没有深度研究过这个网络。但是,对于你的问题,我有一个猜测,在.tflite里如果conv2d 变成了 depthwise conv2d,你需要看一下你的conv2d 的输入是不是只有一个channel,比如一张黑白图片,它就是一个channel的.如果是的话, toco会自动做一个optimization把它变成depthwise conv2d。官方实现代码:https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/toco/graph_transformations/convert_pure_conv_to_depthwise.cc。
    2019-3-16 01:37 回复
  • Zongjun然后就是depthconv2d还不是深度可分离卷积,深度可分离卷积叫做 depthwise separable conv2d.后者是有一个depthconv2d   pointwiseconv2d生成的。pointwise conv2d本质是一个1x1 的 conv2d。depthwise separable conv2d是可以用来替代conv2d的,而 depthwise conv2d自己只能替代 input 为 单个channel的conv2d,就像楼上我说的那样,官方会在后台自动帮你转化。
    还有就是,我感觉一个kernel设计出来,其目的肯定不是只服务于一个网络的。可能是因为Inception搞出来的,但是也完全可以用于其它网络的。嗯,一点个人见解哈。
    2019-3-16 01:43 回复
  • sunyanli回复 Zongjun :谢谢您的回复。您说的我再去理解理解。就是depthwise2D。我之前写错啦!小白对底层代码还不熟,您说的我还得在看看,理解理解。再次谢谢您。
    2019-3-17 22:55 回复
  • sunyanli回复 Zongjun :大神,谢谢您,我这个的lenet的输入通道就是1。今天大致看了一下这个实现过程,对于这个也有点理解啦。既然深度分离卷积可以大大减少计算量,是不是也可由实现当输入通道数为3时,也可以转变成depthwise separable conv2d卷积啊?
    2019-3-18 16:01 回复
  • sunyanli大神,想再请教一个问题,如果我在量化的过程中只量化卷积层,或是只量化全连接层,应该就是在只量化的层加入伪量化节点,请问这个是在哪里改啊?
    是直接改掉对应的这个函数吗_InsertQuantOp(
                post_activation_bypass_context,
                'post_activation_bypass_quant',
                layer_match.post_activation_bypass_op,
                consumers,
                is_training,
                moving_avg=True,
                ema_decay=ema_decay,
                quant_delay=quant_delay,
                vars_collection=vars_collection,
                bits=activation_bits,
                symmetric=symmetric,
                producer_scope=scope)
            quantized_ops.add(layer_match.post_activation_bypass_op)
    2019-3-21 20:53 回复
  • Zongjun回复 sunyanli :只量化某一个层的话。。我觉得肯定是不能用create_training_graph这个api了。要手动在你需要量化的层插入fake quant node。话说你的问题好奇特哈!
    2019-3-27 12:53 回复
sunyanli  TF荚荚  发表于 2019-3-14 16:30:35 | 显示全部楼层
Zongjun 发表于 2018-10-24 05:38
以下是我的个人理解,如果是在android 上,Tensorflow Lite (tflite) 可以利用hardware accelerator,应该 ...

大神,您好,我最近也在在关于量化的东西,看了您的博客以及另外一个大神的博客,感觉对于这个tensorflow的量化,越来越模糊啦。现在我根据我的认知说一下我的理解(底层代码看了一些,但是看得稀里糊涂的)。1、google的论文(Quantization and Training of Neural Networks for Efficient Integer-Arithmetic-Only Inference )和tensorflow的quantization-aware-training的量化方法是相同的。2、我看了您的解答,您说的这个加入伪量化是在原来图中加入fakequantizationnode,记录该节点的最小值与最大值,模拟了quantized—graph.py工具中的逆量化和反量化操作,这个确实也是,我自己也做了这两个实验,确实quantization-aware-training量化之后的tflite文件只有伪量化节点,并且有最大值和最小值,而quantized—graph.py的pb文件里面有requantization和dequantization。但是我在看其他博主在将google量化算法时,都有逆量化这个操作,比如:https://github.com/Ewenwan/MVisi ... on/quantization/IAO。3、现在我在想是不是quantization-aware-training和quantized—graph.py方法是不是内部实现的算法都是一样的,我也去看了他们的代码,可是我这种小白看的都是模模糊糊的,不能从大的框架上看整体。4、有个问题请教您一下,加入伪量化记录节点大小,这个大小是怎么记录的啊?我去看的quantize.py代码,里面只有一个_InsertQuantOp函数,目前我看这个d代码也只是大概知道他的意思,把每一个需要插入伪量化的节点,插入伪量化,更详细的还的看代码。因为自己水平有限,我目前只知道quantization-aware-training方法具体的做法,其中的原理只知道是用的均匀量化器,不知道大神那边有没有其他文档版的资料,可以提供我这个小白参考一下。5、还有一个问题,quantization-aware-training和quantized—graph.py还有那个post-quantization量化方法是不是其量化的方案都是相同的,都是
本楼点评(24) 收起
  • Zongjun你这些问题咱俩如果能语音就好了,几句话就讲明白了。打字就很痛苦了,我慢慢回复哈。
    2019-3-16 01:46 回复
  • Zongjun首先,我没有写过任何这方面的博客,不知道你看了谁的,反正那不是我哦。我这边公司有严格规定的。我属实是不敢和公司打擦边球。。
    然后我尝试着解答一下你的疑惑哈。
    1.底层代码是你最好的老师,我也是一行一行代码研究出来的,我做的还是把这些东西全放进单片机里。所以,你得逼着自己看底层代码,看不懂的话反复看。比如你上面那个问题,答案确实是在底层的c  代码中。
    2. 你可以放下quantized_graph.py这个文件了,现在官方的github中都没有它了。原因就是,它被tensorflow lite完全取代了。你问题中提到的这个github链接,它是7个月之前的方法。
    3. 那么现在就剩下了 quantization-aware training = fake quantization = 伪量化这个方法。它也是现阶段tensorflow唯一能实现fully quantized的方法。其通过训练时加入 fake quant node来学习op的min 和 max。注意,是学习,也就是说你的网络是怎么学习的,你的min 和max就跟着怎么学习,比如gradient descent。
    而之前quantized_graph.py是在你训练后来进行量化,所以它要一路带着requantize和dequantize。所以,我建议还是转到tensorflow lite吧。
    2019-3-16 02:10 回复
  • Zongjun4. 还有一个不是方法的方法,就是你最后提到的post-training quantization,它去年刚出来时让我一度看到了希望,然而它在推理时居然还是用float32 kernel来做计算。。。这一下子就用处不大了,因为在我的微控制器上,float32计算极其昂贵。
    所以这就要看你做量化的最初目的是啥了。我的就是要求完全量化,那伪量化就是我的唯一选择。。除非我完全放弃tensorflow转去Arm的 CMSIS。但是那个的可用性和简洁性肯定是不如tensorflow的(前期选工具时,两者我做过比较)。嗯,还是看你项目的具体要求了。
    2019-3-16 02:21 回复
  • sunyanli回复 Zongjun :非常感谢大神的回答。我是通过博客找到这里的,那个博主也在这里问了很多问题,我入门完成伪量化的量化也是通过他。真的非常感谢你们这些大神。我是一名学生,对这个理解的不是很到位。我看量化的知识,是因为我的论文方向是关于量化相关的。我要以它发论文的。我本来是想将剪枝的方法和量化结合一下发一篇论文。1、不知道把这个伪量化方法加入裁剪操作是否可行?
    2、上文我提到的那个连接里面说的是关于google的那边论文的量化方法,这篇论文我看了,它讲的也是在训练过程中加入的伪量化操作,所以我把这个和quantization-aware-training归为一个方法。
    3、加入 fake quant node学习最大值和最小值,它是自动识别网络中需要量化的节点吗?比如权重和激活值。还有您说他说自己学习最大值与最小值,是在训练过程中每迭代一次,权重更改之后fake quant node都会自动记录他的最大值与最小值,是吗,
    4、在反向传播过程中,论文(量化白皮书)中有提到直通滤波器(straight through estimator),这个操作是在求梯度时,用全精度值,
    5、还有一个问题,关于数据溢出。这个问题是调用了gemmlowp库,解决的吗?比如在卷积操作之后,两个8bit的值相乘,会变成32bit,此处的是如何解决的啊?是通过只取重要的8bit吗?
    6、我用quantization-aware_training量化,生成的pb文件与tflite文件,其中的卷积节点的名称发成了改变,从conv2D变成啦depthconv2D,这个是什么原因啊?
    7、那个quantize_graph.py方法虽然官网上已经溢出,但是我还有一个移位,就是那个量化之后,为什么还要逆量化为float型?
    再次感谢您的回复。
    2019-3-17 15:07 回复
  • sunyanli大神,您说的我那个连接是7个月之前的量化方法,那那个方法原理和quantization—aware-training有什么区别吗?我看了他提供的源码,也看了quantization-aware-training,都是调用了gemmlowp库啊?大神希望有时间可以指点一下我。要是大神感觉我的问题打字回答不方便,可以加微信聊一下吗?我的微信:syl0318521。谢谢您啦。
    2019-3-19 14:44 回复
  • Zongjun回复 sunyanli :这两天在休假,回复的有点迟哈。裁剪的英文是啥啊,pruning吗?如果是pruning的话,伪量化加裁剪我觉得没什么冲突。我也没尝试过,这个肯定是自己上手试一试最好了。
    fake quant node自动识别某些节点,具体识别哪些底层代码中是有的。不被自动识别的需要手动插入fake quant node。学习应该就是back propagation的时候自动更新min max的。
    两个8bit相乘,这个操作本身也是要在tensorflow lite toco转化之后发生了,因为伪量化只是记录min和max,训练过程中全程依然是float32的计算。toco完成fully quantization之后,做推理时才会用到uint8的计算kernel. 此时,我们可以接受int32的数据类型,你打开完全量化好的一个.tflite文件,会发现bias的数据类型就是int32的。
    这个第6点,你看了的话,我就不说啦。
    第7点,你读一遍pete warden的blog就明白啦,他讲得挺清楚的。https://petewarden.com/2016/05/03/how-to-quantize-neural-networks-with-tensorflow/ 这篇讲的就是以前那个方法的具体操作。你可以瞅瞅哈。

    2019-3-20 01:07 回复
  • sunyanli好的大神,pete的这个博客我之前有看过。逆量化是因为在进入下一个操作的输入也是要量化后的,而量化需要最大值和最小值(float),所以才逆量化的。
    还有一个问题,大神,关于那个那个后向传播的直通滤波器(straight through estimator),是怎么理解的呢?我看的白皮书原文:We model the effect of quantization using simulated quantization operations on
    both weights and activations. For the backward pass, we use the straight through estimator (see section 2.4) to model quantization。这个我真的不是很理解。希望大神再指点一下。
    2019-3-21 13:25 回复
  • sunyanli大神,我再请教一个问题,我将模型量化4bit,我该了quantize.py代码里面的Quantize函数里面的bit,将之前的8改成4。但是没有量化成功。我分析了一下,我们之前加入伪量化操作,只是获取需要量化节点的最大值最小值,那我们量化成几bit,主要是看用toco工具里面的操作,是吗?void Transform(const TocoFlags
    2019-3-22 10:20 回复
  • sunyanli回复 Zongjun :大神,不知道您有没有看到我的回复,我之前打开这个网页,看到一闪的回复提醒,可是点进去没有看到。
    2019-3-27 10:59 回复
  • Zongjun回复 sunyanli :嗯。刚度假回来。。整个人都变成烤地瓜了。。量化的话,目前只能是8 bit吧。我目前还没遇到过4 bit量化成功的例子。toco里也只有两个选择 float32和uint8.
    2019-3-27 12:45 回复
人工智障_(:」ㄥ  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的工具真的挺难用的,不过似乎目前在量化的方向没有其他的选择。
本楼点评(4) 收起
  • 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 回复
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 回复
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,有大神知道是怎么回事吗?
本楼点评(2) 收起
  • 徐建君你好,我也遇到与你一样的问题,请问你解决没?
    2019-5-10 00:39 回复
  • nick_nie回复 徐建君 :感觉create_training_graph 对 dilated convolution 会有bug,没有再往下继续了,不好意思!  
    2019-5-20 13:02 回复
龙仔  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.” 请问这个问题可能是什么原因导致的呢?最后一层正常来说需要最量化么??多谢
本楼点评(11) 收起
  • 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, 具体的位置如下图所示:

cast op 位置

cast op 位置

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

多谢!
本楼点评(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 回复
您需要登录后才可以回帖 登录 | 加入社区

本版积分规则

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