发新帖

tensorflowLite的量化使用问题

[复制链接]
2814 52
yunxinmengze  TF荚荚  发表于 2019-2-26 11:37:09 | 显示全部楼层
C:\Users\gaoyu\Desktop\0ED794D3-3661-4afa-8892-07A66A75BE67.png
本楼点评(0) 收起
人工智障_(:」ㄥ  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节点在图里面没有删除掉
本楼点评(5) 收起
  • 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 回复
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网络中设计出来的吗?希望大神可以指点一下。谢谢。
本楼点评(5) 收起
  • 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 回复
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量化方法是不是其量化的方案都是相同的,都是
本楼点评(8) 收起
  • 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 回复
人工智障_(:」ㄥ  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荚荚  发表于 3 天前 | 显示全部楼层
本帖最后由 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的工具真的挺难用的,不过似乎目前在量化的方向没有其他的选择。
本楼点评(0) 收起
您需要登录后才可以回帖 登录 | 加入社区

本版积分规则

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