发新帖

tensorflowLite的量化使用问题

[复制链接]
713 18

快来加入 TensorFlowers 大家庭!

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

x
我想问下,现在很多企业都说使用了tensorflow lite,但他们使用的tensorflow lite是经过量化的吗?因为现在好多操作都不支持量化操作,比如tf.Abs,tf.tf.Square等等.如果是使用未量化的tensorflow lite,那这样速度比起量化后的pb文件在android手机上使用,速度有提高吗?提高多少?        还有一个问题.就是要使用toco工具生成量化的lite文件,是不是要求在训练过程中得先使用tf.contrib.quantize.create_training_graph和tf.contrib.quantize.create_eval_graph()进行伪量化训练?
麻烦各位大佬解答下.有没有大佬量化自己模型真正测试成功过的,回答下疑惑.或者能写下量化具体步骤教程.这还有一个我的相同的贴,可以一并回答tensorflowLite的量化使用问题https://www.tensorflowers.cn/t/7100
(出处: TensorFlow中文开发者社区)


Zongjun已获得悬赏 10 金币+50 金币

最佳答案

以下是我的个人理解,如果是在android 上,Tensorflow Lite (tflite) 可以利用hardware accelerator,应该是更快的。量化只是一个float32到uint8的过程,本质上是weights\bias大小的变化(是原来的25%),有的microc ...
已有1人评分金币 理由
段德璋 + 27

查看全部评分 总评分:金币 +27 

本楼点评(0) 收起

精彩评论18

Zongjun  TF荚荚  发表于 2018-10-24 05:38:19 | 显示全部楼层
本帖最后由 Zongjun 于 2018-10-24 07:56 编辑

以下是我的个人理解,如果是在android 上,Tensorflow Lite (tflite) 可以利用hardware accelerator,应该是更快的。量化只是一个float32到uint8的过程,本质上是weights\bias大小的变化(是原来的25%),有的microcontroller太小,不量化根本就放不进去,并且mircocontroller大部分是8bit计算,float32非常昂贵,所以需要量化。
用toco生成的量化有两个途径:1.你提到的伪量化,这个确实在training时要调用你说的这两句。具体展开:要生成两个graph,一个用于training,在compute gradients前使用create_training_graph,因为forward和backward都需要模拟量化。这个过程其实是找到需要量化的变量,插入fake quantization nodes 来记录 min-max range information。再具体一点:见(*)。另一个graph用于eval,要在import_graph_def后,saver.restore前插入create_eval_graph。后面如何freeze如何调用toco,按照这个链接上说的即可:https://github.com/tensorflow/te ... ow/contrib/quantize
2. post-training quantization。顾名思义,无需伪量化,是toco拿过来一个pb file,直接把toco的post-training quantization flag设成true完成的。但是注意,这个方法只quantize weights,而1.是一个fully quantized model. 并且2.在inference时,会把uint8的weights再转换回float32来做矩阵乘法。所以,2.这个方法其实依然相当于没做quantization。它的存在应当只是便于用户转移model,计算时依然是个非量化model。链接:https://www.tensorflow.org/performance/post_training_quantization

(*):再往前几个版本,tensorflow其实有自己的量化,就叫做quantize。他不是用伪量化,也无需tflite介入。这个文件在现在的tensorflow github中已经不存在了(半个月前移除的,pete warden决心只搞tflite了)。但是他很好的解释了tensorlow 和 tflite量化的数学原理。如果不加入上述的fake quantize node,tensorflow quantize则需要requantize和dequantize的过程。其中requantize是必须的,因为8bit的两个整数相乘为16bit的数。int8的两个矩阵相乘会得出一个32bit的结果,即一个2d convolution layer的输出结果是int32的。但是下一个quantized op需要一个8bit的输入,这就需要记录float32的min 和max,从而对这个int32的中间结果进行requantization,重新获得8bit的数据继续往下传。当使用了fake quantization后,上述过程在训练过程中被模拟了。于是你会看到训练完了的图,不再存在requantization node和dequantization node。有的只是那些fake quantization nodes。值得注意的是,不加伪量化的量化,不是fully quantized model,因为其涉及到了利用float32 min和max转换。而伪量化不存在该问题。简言之,目前唯一可行的fully quantization method就是在tensorflow 下伪量化训练,再到tflite上转化。
(这里就不说那个graph transform tool了,貌似它是tensorflow mobile旗下的,然而,tensorflow mobile本身都要deprecate了。如图:)
tf mobile.JPG
本楼点评(0) 收起
Zongjun  TF荚荚  发表于 2018-11-6 08:49:44 | 显示全部楼层
对了,我补充一点,我debug的时候花了不少时间的一个地方:我用的是在linux下,安装tf.nightly,然后jupyter notebook里调用tf.lite.TFLiteConverter这个东西。因为是quantization,所以要求给出quantized_input_stats,这是一个tuple (med, std)平均值和标准差是要自己手动调的。我的是图片为输入,一开始给(128,128),结果很惨。我调来调去,最后是(128,73)给出的accuracy达到了fake quantization的效果。
本楼点评(0) 收起
九幽  TF荚荚  发表于 2018-11-14 11:32:14 来自手机  | 显示全部楼层
Zongjun 发表于 2018-11-6 08:49
对了,我补充一点,我debug的时候花了不少时间的一个地方:我用的是在linux下,安装tf.nightly,然后jupyter  ...

您好,想请教您一个问题,我现在参照着官方的mobilenet训练例子在mnist里面加入了伪量化训练代码,但只加了Create_training_graph那部分,然后跑出了模型,但是在用工具转化tflite的时候,报错说不知道FakeQuantWithMinMaxVars的数据类型,这个是不是我训练的时候代码写错了?
我看了官方的两篇论文,还有各种社区的各种问题,但还是不确定步骤对不对,您是怎么做的怎么找的资料啊?还有什么我可以找的资料吗?或者您能把你的例子给我看一下吗?非常感谢~
本楼点评(0) 收起
Zongjun  TF荚荚  发表于 2018-11-15 06:19:41 | 显示全部楼层
本帖最后由 Zongjun 于 2018-11-15 06:42 编辑
九幽 发表于 2018-11-14 11:32
您好,想请教您一个问题,我现在参照着官方的mobilenet训练例子在mnist里面加入了伪量化训练代码,但只加 ...

首先,我记得官方的mobilenet是用slim写的吧?slim我没用过,但是fake quantization本质应该是一样的。
我下面写的是用纯tensorflow(非slim)做fake quantization:

1. 你的一个明显错误是,没有使用create_eval_graph。你要创建两个graph,一个只用来training,在这个graph上使用create_training_graph(). 另一个graph,只用来inference,在这个graph上使用create_eval_graph(). 最后,Freeze这个用来inference的graph,再把它传给toco。

2. 使用toco需要linux machine,linux比较stable。你要在这个linux machine上安装 tf.nightly 版本的tensorflow,再使用toco。(你的报错也有可能来自这一步。但是第1步是必须做的,不管用的什么版本的tensorflow。)

3. 我自己的例子不能贴出来,是公司的project。但是,谷歌有一个现成的例子,代码非常基础并且清晰。例子链接。 你打开这个目录以后,先看train.py,第157行(create_training_graph)。再去看freeze.py,第133行(create_eval_graph)。这个相当于,在freeze的文件里包含了create_eval_graph。你可以发现,create_eval_graph()上面是调用create_inference_graph()这个函数,显然,create_inference_graph这个函数重新写了一个graph,而不是用你create_training_graph的那个graph。run完freeze.py以后,生成的就是.pb文件。可以直接把这个.pb文件给toco转化了。(注意区分create_eval_graph()和create_inference_graph()。前者是现成的可以直接调用,后者是你自己写的一个普通function。)


4. 还有一个注意事项就是顺序,这个我在最开始的post里提到过了。create_training_graph,要出现在cross_entropy之后,tf.train.GradientDescentOptimizer之前。而create_eval_graph则是出现在创建完inference graph之后,load checkpoint之前。load checkpoint之后是freeze graph,freeze graph 用的是graph_util.convert_variables_to_constants()。

我就是从这个例子学会怎么做quantization-aware training的。至于谷歌官方的documentation,我实在是不敢恭维。(当然paper我也读了,更多的是从中学到背后的数学原理。)

本楼点评(14) 收起
  • 九幽嗯嗯嗯,读论文只是知道个原理,真的不知道具体怎么做的,,,我还刚开始学用tf,好多程序源码可能看了但是并不能自己总结出用法规律啥的,身边还没有人问,就在这个问题上卡了好久,,,
    经过这么多天的查找看代码啥的,我就是隐隐有些思路,知道两个create都要加,但就是不知道怎么加,果然看你说了之后,知道了这里面还是有不少坑的,是我这种小白不能看出来的,,,
    非常感谢您的回答,帮了大忙了,思路瞬间感觉清晰了,我之前也是看了您上面的回答才去找的相关资料,我之前只找到了mobilenet那个,确实里面看到了slim,我也觉得应该不是一种方法,不过也算是参考之后完成了一半的内容。
    您的回答非常清晰,十分感谢!~碰到您这样做过量化又很会讲解描述的人,我这个小白实在幸运,多谢~
    那我就不改那个错误了,先改正代码,照着您说的实现一下,希望可以完成,,再次感谢!
    2018-11-15 12:26 回复
  • 九幽看到了那个例子,演讲的那个,我之前也看到了,也照着写了,但是就是因为着急和迷惑吧,就只看了有create_training_graph的部分,其他的没分析出来,,,我继续看去,,,
    2018-11-15 12:29 回复
  • Zongjun不用客气哈。对,那个例子的create_eval_graph藏的比较深,在freeze里面,相当于两件事儿在一个文件里做。Good luck!
    2018-11-16 01:14 回复
  • 九幽回复 Zongjun :我仔细看了一下train.py和freeze.py,这两个文件一个是训练,一个是推理(验证:test)?就是在train.py里用create_training_graph()生成了训练图,然后freeze用create_inference_graph()重写了一个推理图,又用create_eval_graph()调用,生成最终的推理图?create_inference_graph()这个只是给了一个图的定义是吗?我看它做了一个output 给后面的inference,为什么要加create_inference_graph()呢?可以就直接在保存ckpt之前加上freeze.py里面create_eval_graph()那一部分吗?
    我tf语法比较差,刚接触没多久,,,只大概看懂了整体结构,但内部的关系还没太清楚,,,我做的项目是keras写的物体检测和分类训练,网络和训练是分开的,但训练里面是训练和验证一起的,结构上感觉跟speech这个例子差不多,但是speech是把训练和验证分开了是吧?
    就是训练生成.pb和.ckpt,然后验证推理的部分和frozen一起放到了freeze里是吗?我也可以把两部分放在一起是吧?就像我上面想的,不知道create_inference_graph()这个的含义,一直也不太清楚eval这部分该怎么和我之前写的训练的代码结合起来,,,
    然后我试了个简单的例子,就是mnist,它就两部分,一个是建立网络,然后就是训练,我把create_training_graph放到了建立网络里:
    ........
    finaloutput = tf.nn.softmax(tf.nn.dropout(dense_layer2, keep_prob), name="softmax")
        g = tf.get_default_graph()
        with tf.name_scope('cross_entropy'):
            cross_entropy_mean = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(labels=y, logits=finaloutput))
        tf.contrib.quantize.create_training_graph(input_graph=g,
                                                  quant_delay=0)
        optimize = tf.train.GradientDescentOptimizer(1e-5).minimize(cross_entropy_mean)
        prediction_labels = tf.argmax(finaloutput, axis=1, name="output")
        correct_prediction = tf.equal(tf.argmax(finaloutput, 1), tf.argmax(y, 1))
        accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
    然后看你说的eval的放置位置注意,就是把eval放在第二部分的训练那里吗?因为模型保存部分在训练那里。
    还有个问题,这个eval就是生成一个推理图吗?推理图和训练图是一样的吧?只是参数不一样,结构一样?这个的作用具体是什么呢?量化推理模型?
    2018-11-19 17:43 回复
  • Zongjun回复 九幽 :freeze.py没有在做实际的testing,它只是生成了用于testing的那个graph(create_inference_graph()),它是一个图的定义。这个图将来可以用来做推理。可以理解为,训练图训练出来的参数保存在checkpoint file里,freeze.py把这些checkpoint file load了进来,传给了用来inference的这个图。这里必须create_inference_graph(),直接在训练图上调用create_eval_graph()是不对的。
    对,你也完全可以把创建推理图和freeze放在一个文件中。eval并不是生成推理图,生成推理图是create_inference_graph(),eval只是把这张推理图转换成了tflite能够识别并量化的格式。eval要出现在Load checkpoint的地方而不是save checkpoint的地方。
    2018-11-20 05:30 回复
  • Zongjun回复 九幽 :所以总结一下就是这样的:
    1.创建训练图,其中加入create_training_graph(),训练。把训练好的数据存在checkpoint file中。
    2. 创建推理图,其中加入create_eval_graph()。把训练好的数据导入推理图中,即load checkpoint。
    3. Freeze 生成.pb file.(演讲的例子把2,3合成了一个文件中做。)
    4. 在linux machine上把这个.pb file转化成.tflite file。
    5. 可以用tflite python api的 interpreter读入这个.tflite模型然后做testing.
    2018-11-20 05:40 回复
  • 九幽回复 Zongjun :恩恩,这样清晰不少了,感谢~我继续写试试~
    这些你都是通过读例子程序看出来的吗?还是程序和论文一起分析出来的,还是找到了很多相关资料呢?我看了好多还是不确定,分析不出来......
    2018-11-20 10:09 回复
  • 九幽回复 Zongjun :还有一个问题,我刚把speech的例子跑出来了,然后用toco工具转化了tflite,freeze运行出来的.pb文件是3.7M,然后toco转化出的tflite大小也是3.7M,这样对吗?还是说生成量化的tflite,是会变成pb文件的1/4?
    我用的指令,bazel的,还是说要按你的方法,下载tf.nightly写程序转化?
    我用你说的Netron工具看了转化前后的两个图,结构一样,只是转化之后出现了fused层,我觉得图应该是对的
    2018-11-20 17:52 回复
  • Zongjun回复 九幽 :对,这些操作过程完全是读这个例子的程序看出来的,我从论文获得的只是它背后的数学原理。应该是1/4,我猜你训练的时候是 python train.py。你应该是python train.py --quantize=True. 你得告诉这个网络你要求它做fake quantization啊,不然它默认是不进行伪量化的。
    2018-11-21 01:17 回复
  • Zongjun回复 九幽 :bazel完全可以用。不用非要我说的那样,我说的是针对用python的玩家们。但是即便用bazel,我也推荐用tf.nightly版本。Netron打开发现结构一样就说明你没用伪量化。fake quantization以后,你会看到.pb文件中会出现FakeQuantWithMinMaxVars node, 而.tflite中是没有的。在Netron中展开每一个node看细节,信息量很大的。我自己写过一个tensorflow的kernel,然后自己手动量化(用Paper中的公式),然后拿过来netron中显示的量化min,max,用我的function输出的结果和netron中显示的量化结果一致。证明量化成功。
    2018-11-21 01:23 回复
快到碗里来  TF荚荚  发表于 2018-11-16 18:18:56 | 显示全部楼层
Zongjun 发表于 2018-11-15 06:19
首先,我记得官方的mobilenet是用slim写的吧?slim我没用过,但是fake quantization本质应该是一样的。
我 ...

你好,我想请教下,我使用toco工具将一个冻结了的pb文件,大概4.3m,进行转换成lite文件./bazel-bin/tensorflow/contrib/lite/toco/toco \
--input_file=frozen_eval_graph_test.pb \
--output_file=tflite_model.tflite \
--input_format=TENSORFLOW_GRAPHDEF \
--output_format=TFLITE \
--inference_type=FLOAT \
--input_shape="1,626,361,3" \
--input_array=input_image \
--output_array=result  \
--std_value=127.5 --mean_value=127.5 --default_ranges_min=-1.0 --default_ranges_max=1.0

过程中,我发现,只要我模型里面存在下面这段代码relu = tf.where(tf.less(input, 0),  tf.zeros_like(input), input)或者nan_to_zero = tf.where(tf.equal(relu, relu), relu, tf.zeros_like(relu))   转换出来后的lite文件将会变成100多m,如果去掉的话出来的lite文件就正常4.3m左右 ,我问了下别人,有人说是现在tensorflow-lite的bug,里面有些操作影响到,我想问下你有没有出现过这个问题,会不会是你上面提到的tensorflow版本必须要tf.nightly版本才行,我的版本是从github上下载源码编译的2.11版本.还有一个问题就是,你安装tf.nightly版本的tensorflow是用pip install tf-nightly直接安装的吗?谢谢

本楼点评(1) 收起
  • 九幽今天准备也写个量化的博客,然后去翻了之前看过的相关博客和文档啥的,忽然发现你就是“一个程序猿的日常”啊,我之前就是看了你的博客,然后弄好了toco指令这里,但是那时候不知道你写的生成量化的tflite就是伪量化的意思,还以为就是量化指令生成的pb直接toco转化呢,,,我一直以为这些用指令就好了,没想到还要从头训练,,,后来仔细看了官方文档又看到了你在这里的问题才确定原来是要加伪量化训练的,,,
    然后今天再看,发现你加了新东西,然后读着觉得跟Zongjun 大神感觉很像,但一看更新时间觉得还是不是,点进介绍,看头像原来是你,哈哈,看来全网伪量化训练就你这里最正确最全啊~(除了你的我好像还没看到别人写了这个......)
    多亏了你的博客和这个问题~不过你的比较概括,像我这样第一次接触的小白还是容易不清楚,我准备从纯小白的角度尽量完整的记录一下,之前哪里都找不到方法,不知道怎么用,真是痛苦,,,
    2018-12-10 18:47 回复
Zongjun  TF荚荚  发表于 2018-11-17 01:41:34 | 显示全部楼层
快到碗里来 发表于 2018-11-16 18:18
你好,我想请教下,我使用toco工具将一个冻结了的pb文件,大概4.3m,进行转换成lite文件./bazel-bin/tensorfl ...

我是按照官方教程安装的tf.nightly,基本和你说的一样,建个环境然后pip安装。我是一个Ubuntu-16.04的虚拟机。toco我不是用的bazel,我用的是python api. 在这个tf.nightly的机器上,打开一个jupyter notebook,import tensorflow as tf之后,运行 tf.lite.TFLiteConverter.from_frozen_graph. 如果这句不报错那就是成功了。这句在python里就相当于call了toco。

我读了一下你的toco,你如果是quantization-aware training了,那你的inference type那里应该是QUANTIZED_UINT8而不是FLOAT.

relu的那个我木有碰到过,所以可能帮不上忙了。我推荐你下载Netron.可以直接打开你的.pb和.tflite文件,先看一下.pb文件是不是正常,有可能训练或者freeze的时候就出现问题了。Good luck!
本楼点评(8) 收起
  • 快到碗里来大神,你好,我测试了你说的Netron跟使用tf.lite.TFLiteConverter.from_frozen_graph去生成lite,现在基本成功,只要去除一些操作就可以生成量化的lite文件.现在还有个问题想请教下,如果模型里面存在tf.Square操作,lite文件生成就会报错,我查了下文档,里面有这么一句话不太理解,在https://www.tensorflow.org/lite/tf_ops_compatibility   里面的"Here is a list of TensorFlow operations that are usually removed from the graph",什么叫做从通常从图中移除这些操作
    2018-11-26 16:48 回复
  • Zongjun回复 快到碗里来 :这个列表里面的操作应该是toco自动去删除,替代,融合的。比如tf.relu,它可以fuse进上一层的conv2d layer中,成为上一层的输出。tf.Square应该也是一样的,toco会去处理掉,这样tflite的model中就看不到这个操作了。你报的错是啥啊?toco没有自动处理tf.Square吗?
    2018-11-27 02:02 回复
  • 快到碗里来回复 Zongjun :你好,我上面的问题基本解决了,现在我生成了一个lite文件,用python脚本测试,测试代码如下:
    interpreter = tf.contrib.lite.Interpreter(model_path="quantized_model.tflite")
    interpreter.allocate_tensors()

    # Get input and output tensors.
    input_details = interpreter.get_input_details()
    output_details = interpreter.get_output_details()

    image=scipy.misc.imread("timg(11).jpg")
    image_=np.array([image.astype('float32')])
    print(image_.shape)
    print(type(image_))
    print(input_details)
    interpreter.set_tensor(input_details[0]['index'], image_)

    interpreter.invoke()
    output_data = interpreter.get_tensor(output_details[0]['index'])
    scipy.misc.imsave('res.jpg',output_data)
    是能顺利运行并输出东西来的,但我交给我朋友做android的在android上运行lite文件,他是替换官方的demo
      
    https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/java/demo的文件去测试,报了以下错误:
    Caused by: java.lang.IllegalArgumentException: ByteBuffer is not a valid flatbuffer model
                                                                                              at org.tensorflow.lite.NativeInterpreterWrapper.createModelWithBuffer(Native Method)
                                                                                              at org.tensorflow.lite.NativeInterpreterWrapper.<init>(NativeInterpreterWrapper.java:72)
                                                                                              at org.tensorflow.lite.NativeInterpreterWrapper.<init>(NativeInterpreterWrapper.java:52)
                                                                                              at org.tensorflow.lite.Interpreter.<init>(Interpreter.java:114)
                                                                                              at com.example.android.tflitecamerademo.ImageClassifier.<init>(ImageClassifier.java:98)
                                                                                              at com.example.android.tflitecamerademo.ImageClassifierQuantizedMobileNet.<init>(ImageClassifierQuantizedMobileNet.java:38)
                                                                                              at com.example.android.tflitecamerademo.Camera2BasicFragment.onActivityCreated(Camera2BasicFragment.java:334)
                                                                                              at android.app.Fragment.performActivityCreated(Fragment.java:2289)
    我想问下,你有没有遇到这个问题或者知道怎么解决吗?有什么好的建议或者能不能分享下你调用lite文件的android代码.谢谢大神
    2018-12-1 11:52 回复
  • Zongjun回复 快到碗里来 :我训练完的model是直接往单片机上放的,所以我没在android上用过。我看了一下你给的链接里的代码,这个报错是说bytebuffer不是一个flatbuffer model(flatbuffer model是tflite的格式)。但是,我发现bytebuffer在代码中是输入图片的一个buffer,里面存的是image data,并不是model本身。所以你同事android的java代码可能出了问题。
    2018-12-4 02:08 回复
  • 快到碗里来回复 Zongjun :好的,谢谢大神,我看下怎么处理.
    2018-12-4 18:02 回复
  • Zongjun回复 快到碗里来 :嗯嗯。不用客气!大神不敢当,只是碰巧平时工作会一些这方面的东西,尽可能帮忙而已。祝你们好运哈!
    2018-12-5 02:27 回复
  • 快到碗里来回复 Zongjun :哈哈,我觉得你有空可以写篇博客讲下tensorflow-lite,现在tensorflow-lite的博客太少了,而且都不是很详细,很多都是抄来抄去的.这段时间我都会找时间研究下tensorflow-lite,现在生成的lite文件还没能部署在android跟ios上,遇到问题到时还要请教你
    2018-12-6 15:12 回复
  • Zongjun回复 快到碗里来 :嗯嗯,模型都有了,部署在android上应该就不难了,毕竟是java哈。
    2018-12-7 02:32 回复
Zongjun  TF荚荚  发表于 2018-11-26 05:48:49 | 显示全部楼层
九幽 发表于 2018-11-14 11:32
您好,想请教您一个问题,我现在参照着官方的mobilenet训练例子在mnist里面加入了伪量化训练代码,但只加 ...

just in case, 你没有新的问题了对吧?之前那一层楼点评太多了,我无法打开点评的第二页。。应该是卡bug了。所以你说了啥我都看不到。。
本楼点评(9) 收起
  • 九幽是,我刷新了几次,试了别的浏览器也发现看不到第二页,,,之前说的没啥别的问题,就是重新训练了一遍,打开了伪量化的开关,然后pb模型图出现了FakeQuantWithMinMaxVars node。但是用toco工具转化为tflite时报错,说Unimplemented: this graph contains an operator of type (Unsupported TensorFlow op: DecodeWav) for which the quantized form is not yet implemented. 应该是有的层没法量化?还没有完善是吗?还是我这里出问题了?
    另外就是那个create_inference_graph,我自己建立一个推理图的话,就是重新建一个网络结构然后给个分类输出吗?那个create_inference_graph我看感觉含义就是说了几个关键的层,然后给了logits,这个是搭建网络模型的意思?create_model?
    我做的目标检测还有画框,然后显示分类和概率,不太清楚这个输出该怎么给,,,
    2018-11-26 10:33 回复
  • 九幽还有一个,train.py里面create_training_graph()就是建立训练图的意思,然后后面只要get_default_graph()来在这一个图里面实现功能就行了呗?但是freeze.py里的create_eval_graph()不能直接创建出推理图,所以需要自己写一个create_inference_graph()函数来创建推理图,然后create_eval_graph()只相当于get_default_graph的功能来实现你之前说的:给出一个输出作为tflite可接受的类型是吗?
    create_training_graph和create_eval_graph添加的FakeQuantWithMinMaxVars还是只是create_training_graph添加的?那create_eval_graph有添加什么吗?
    如果FakeQuantWithMinMaxVars只是create_training_graph添加的,那为什么train.py里面要加fingerprint_input = tf.fake_quant_with_min_max_args(
            input_placeholder, fingerprint_min, fingerprint_max)这一部分呢?
    2018-11-26 11:13 回复
  • Zongjun回复 九幽 :decodewav这里,你的toco指令里要包含模型的输入和输出名字,这个模型的输入应当是:--input_arrays=Reshape_1,就是从reshape那一层算为进入,这样就不会有decodewav的报错了。create_inference_graph就是create model,我在logits后面手动加了softmax作为输出。所以我的toco输出是--output_arrays=labels_softmax。“labels_softmax”是我给起的名字。
    训练图不是create_training_graph()建立的,而是train.py 中 models.create_model这个函数建立的。其实,create_training_graph和create_eval_graph都不能自己创建一个图出来,它们都必须有另一个函数为它们创造图,然后它们在各自的图中把操作改成伪量化版本的操作。input那里它手动加了fake_quant,我感觉是这个模型的输入需要处理,如果你的输入是图片,那应该不需要这一步,这里我不是很确定。我的模型没有这一步依然是工作的。
    2018-11-27 02:34 回复
  • Zongjun回复 九幽 :我感觉你的误区是看见create_training_graph就认为它是在create graph,这个名字起的很有误导性。其实它根本没有创建一个graph出来,真正的graph,每一层的定义都是在models.py这个文件中定义的。create_training_graph只是让一个普通的graph在训练时加入伪量化而已。
    同理,create_eval_graph也只是把一个普通的inference graph变成伪量化版本,之前训练好的参数会传给这个图。再把这个图给toco。
    2018-11-27 02:38 回复
  • 九幽回复 Zongjun :大神好厉害,每次都回答地直中要害~
    恩,decodewav那里确实换了输入就好了,但是我在程序和用工具来看pb的结构都写着输入是wav_data,你怎么知道这个错误就是要把输入改成Reshape_1呢?......
    我看普通的tf程序创建图是用tf.Graph(),然后speech这个例子创建图是用create_model呗?他这个create_model是自己根据自己要用的网络在models.py先定义出来的呗?就是我现在想像他一样写一个create_inference_graph()加进去,因为我就剩下这部分没写进去,所以,我要是根据mnist网络自己定义一个mnist的create_inference_graph的话,就对照着speech例子的结构来写?
    然后其实还要写一个models.py先定义好要用的网络层?.......总感觉没这么复杂,因为我只是改下mnist的训练代码,让它实现伪量化,我觉得我应该抛掉speech的结构,然后只把它的create_inference_graph拿过来,然后在里面定义好mnist的网络结构,写好后,写logits = tf.Graph(),然后再加上最后的输出: tf.nn.softmax(logits, name='output'),是这样吗?
    我觉得我没有看透create_inference_graph()里面代码的含义,也不知道放到自己的网络里该怎么定义这一部分......
    2018-11-27 11:53 回复
  • 九幽回复 Zongjun :其实,我写mnist的伪量化是想测试一下这整个过程还有我用的工具对不对,测试下这种方法的效果怎么样,成功之后再用到我自己的代码里,,,
    感觉现在speech已经成功测试好了上面那些,我现在是不是直接去想自己的代码该怎么改比较好?mnist就先不要做了,也没什么帮助了是吗?
    我的训练和网络结构代码都是keras写的,用的vggA网络且只有卷积和池化,然后要实现画框和分类
    我现在修改了一部分代码,改了训练的部分,加了Session来执行训练,还有create_training_graph,
    感觉keras写的没有图,它应该不是用图的形式来计算实现的吧?,,,
    你知道keras怎么加伪量化吗?还是说伪量化只能用图的形式来实现,用TF来实现?我需要把keras语句改成tf方法来写吗?
    2018-11-27 12:16 回复
  • Zongjun回复 九幽 :1. 咱们这样盖楼,盖到第10层就另起一楼哈,别又像上次那样后面的评论全落地成盒了。。。
    2.  关于decodewav,一开始这里我和你报错一样,所以我知道是啥问题。我解决的方法就是研究了一下这个例子处理input的代码,我发现给toco reshape_1就行了,不需要前面那些。试了几次才成功的。
    3.  你不直接调用tf.Graph(),其实是用的default graph,所以创建图的原理和以前是一样的。这个例子只是把models.py单独拿出来了,在一个独立的文件中创建model,个人感觉这样设计更清晰。对,你其它都写了的话,只要额外加一个你自己的create_inference_graph()即可,注意去掉dropout(如果训练图有的话)。
    4. speech这个例子你如果吃透了的话,没必要再用mnist重复一遍了,核心思想是一样的。
    5. 重点来了,keras不存在伪量化功能。这个我在stack overflow上和别人也讨论过。我同事一开始是用keras,扔给我量化,我才发现keras没这功能。我们才慢慢用起来了tf的底层代码。
    6.有一种方法你可以试一下,它不用tf的底层代码定义Model。你查一下 tf.kears.layers。这一套相当于在tf中直接调用高层api。因为伪量化的操作出现在loss和optimizer那里,这一部分你要用tf的底层代码实现。这是和keras sequential model的区别。keras sequential model,我是没找到插入create_training_graph()的位置。。
    2018-11-28 03:05 回复
  • Zongjun回复 九幽 :我今天学了一下slim,感觉也很好上手。肯定是比tf的底层代码要简单实用一些。fake quantization的步骤和speech的例子也完全一样。我就拿mobilenet举例吧:1. https://github.com/tensorflow/models/blob/master/research/slim/nets/mobilenet_v1_train.py 第139行,在loss处插入了create_training_graph()
    2. https://github.com/tensorflow/models/blob/master/research/slim/nets/mobilenet_v1_eval.py 第127行在build inference model的函数内部同时插入了create_eval_graph()。这个只是和speech的例子代码顺序不同,本质完全一样。
    这样看来,slim的地位应当是介于tf底层代码和keras之间的那个谷歌官方框架。感觉documentation写的也相当好。推荐你考虑一下哈。(上一层说的tf.keras.layers我也用过,同样可以用,看你个人喜好了。)
    2018-11-28 08:55 回复
  • 九幽回复 Zongjun :我现在就是slim那个和speech的例子一起看,结构大体相似,就是eval的顺序不一样,,,主要我代码基础也比较差,tf又是刚接触,所以要查语法,要学使用,然后代码方面的理解力也差一点,所以学的比较慢,对于keras这边我的代码也是上边给我的,用keras写的,改了一段时间觉得找不到插入点,然后现在把keras写的训练那部分代码改掉,用tf来写了,但是loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(labels=y, logits=finaloutput))这句话要调用那个finaloutput,然后去找另一个文件写的vgg网络定义,还不知道keras写的哪个是输出,,,,
    你说的两种方法我先去学一下吧,这两种你觉得我这种基础的大概要花多久啊?感觉最近可能要加班了,,,
    2018-11-28 10:34 回复
九幽  TF荚荚  发表于 2018-11-28 11:04:02 | 显示全部楼层
Zongjun 发表于 2018-11-26 05:48
just in case, 你没有新的问题了对吧?之前那一层楼点评太多了,我无法打开点评的第二页。。应该是卡bug ...

1.对于decodewav,确实这是输入那里的,就应该去查输入,然后还是要多尝试啊,懂了,对于这种情况,网上查不到,我自己又不确定,判断不出来,又觉得不知道是不是其他地方的错误导致的,就比较迷惑,,,这种情况还是因为踩得坑少,经验少是吗?
2.然后对于create_inference_graph,我还是不太清楚具体什么流程,,,我想写好这部分就仔细研究speech或者slim的例子吗?感觉他们是写了大体框架,这里就是写的模型网络层级的定义吗?比如mnist这里,定义网络是这样的:
def build_network():
    x = tf.placeholder("float", shape=[None, 784], name='input')
    y = tf.placeholder("float", shape=[None, 10], name='labels')
    keep_prob = tf.placeholder("float", name='keep_prob')
    def weight_variable(shape):
       ......
    def bias_variable(shape):
        ......
    def conv2d(x, W):
        return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='VALID')
    def max_pool_2x2(x):
        return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='VALID')
    def lenet5_layer(layer, weight, bias):
        ......
    def dense_layer(layer, weight, bias):
        ......

然后create_inference_graph里面,就把conv2d,max_pool_2x2,lenet5_layer,dense_layer这几层按顺序写一下?然后写logits = ...,和tf.nn.softmax(logits, name='output')?
这个logits是一个建立网络结构的语句?看那两个例子,感觉每个里面都包含了好多东西,要想弄清楚这里怎么写还要看哪些知识呢?
本楼点评(11) 收起
  • Zongjun这样的话,我建议你还是从tf.keras.layers开始吧,因为你已经知道keras怎么用了,这俩换汤不换药的。至于slim嘛,如果tf.keras最后出意料之外的问题了,你可以考虑把slim当做备选,实在不行再选择tf底层代码。(如果你的网络有batch normalization,我还是建议你用slim。)
    对于create_inference_graph,这个和你创建训练图是一样的套路。你看这个函数是不是还是调用了models.create_model()这个函数。其中is_training这个flag,这里是False,意思就是说我这里创建的是推理图。我觉得你还是先仔细研究完speech这个例子再看其他的哈。
    logits就是图的输出,最后把它传给softmax用于inference。
    你把创建图想成张量的流动,上一层的输出是下一次的输入。和keras的sequential model原理是一样的。
    2018-11-29 03:47 回复
  • zyc4me回复 Zongjun :你好,我想请教你一个问题,就是关于卷积之后得到的int32的的结果,量化到uint8的方式。  我在gemmlowp的example中看到的矩阵相乘得到int32之后再根据论文公式(7)得到uint8是看明白了,但是当我把tflite模型放入netron查看的时候,发现没有relu6层,而下一层卷积的输入(也就是上一层卷积的 输出)的范围是(0-5.9997),我自己认为这个输出得到的就是论文中提到的S3 和Z3,但是我按照论文中的公式得到的Q3并不在0-255范围,我觉得是我忽略了有关relu的一些操作,你能指点我一下吗?谢谢!!
    2018-11-29 10:45 回复
  • 九幽回复 Zongjun :好的,keras这块我还得好好看一下,,,说到底还是没看透例子,感觉我的问题就是写程序的问题
    就是要先了解好整个原理和逻辑,然后根据逻辑来写create_inference_graph这部分,可能就是语法的问题了,,,我先看懂写写试试,有问题再说吧,感觉写程序总是不开窍啊,好像是没有理解本质上的东西,,总觉得理解之后编程应该是很简单的一件事,,,,
    2018-11-29 10:51 回复
  • 九幽回复 Zongjun :看了tf.keras.layers,这个就是keras的网络结构定义呗?这个我对比了一下我代码里的vgg.py的网络定义,看起来是一样的,我的都是keras写的,
    Conv2D(16, (3, 3), name='conv1_1', **conv_args),
    Conv2D(16, (3, 3), name='conv1_2', **conv_args),
    MaxPool2D((2, 2), strides=(2, 2), name='pool1'),
    这样的,我的网络都是卷积和池化,没别的层,然后用model.compile来配置学习过程参数的,如果加量化的话,你的意思是loss这里换成tf底层代码吗?就是model.compile这里,因为这里有loss和optimizer
    2018-11-29 15:54 回复
  • 九幽回复 Zongjun :还有就是训练的部分,我的代码因为都是keras写的,所以训练感觉也要改成tf吧?因为伪量化是在图里面加了节点,然后还要保存成pb文件啥的,所以这部分是不是都得按照tf的底层代码来写啊?
    2018-11-29 19:39 回复
  • Zongjun回复 九幽 :嗯嗯。可以考虑强化一下你的python功力哈,对看或者写代码都是有帮助的。
    对,loss这里要换成tf底层代码的,这里要加create_train_graph()。都是conv2d和maxpool的话就好办了,应该问题不大。训练你可以先不改,试一试。要是报错了,看看是啥错,不行再转为底层代码。到了这一步以后就得具体情况具体分析啦。祝你好运!
    2018-11-30 02:01 回复
  • Zongjun回复 zyc4me :relu6应该是属于fuse进上一层的操作范畴吧。你看一下应该出现relu6的那一层的output id 是不是写着relu6?看你的结果0 到 5.9997应该就是这样的了。因为relu6的范围就是0到6啊。所以,你应该是带错变量了。
    2018-11-30 02:07 回复
  • Zongjun回复 zyc4me :我推荐你看一下这一篇paper: A Quantization-Friendly Separable Convolution for MobileNets
    session 2.1 TensorFlow 8-bit Quantization Scheme, 我当时根据这个session的式子在jupyter notebook中手动实现了tensorflow的卷积和量化,亲测可行。
    2018-11-30 02:10 回复
  • Zongjun回复 九幽 :我更正一下,我之前说slim是谷歌官方支持的库,这个好像不对。貌似在contrib文件夹下的都是非官方的?我今天看到一篇文章说slim有自己的所有者。嗯,不过问题不大哈,好多project都在用的,依然可以作为你的B计划。
    2018-11-30 03:07 回复
  • zyc4me回复 Zongjun :感谢回复,大神总是半夜干活啊。。  我看了A Quantization-Friendly Separable Convolution for MobileNets
    session 2.1 TensorFlow 8-bit Quantization Scheme这个,是的,这个session几个公式没有问题,可以计算得到uint8的输出,这和google论文中的公式(7)是一致的,我的疑问是,这个u8输出是卷积层输出的对吧,然后它再经过relu6之后变成什么样子了呢?(我解析了量化训练的tf ckpt模型,发现里边有每个卷积weight的min/max,还有每个relu6的min/max(min都是0,max基本都是5.9997,也有4.x,5.x的,这个符合relu6的输出),但是我要计算卷积层的输出的话,应该是要知道卷积层输出的min/max吧,google论文里说它是在训练过程中统计这个值,但是模型里并没有,只有relu6之后的min/max),所以如何获得这个卷积输出的min/max呢,是类似tensorrt使用一些样本跑这个模型,来自己统计吗?还有google论文里有提到这个fuse acvitation function,这个到底是怎么fuse的呢?(因为netron里tflite确实没看到有relu层,但是conv层的output id 里边是有relu6的),简而言之,就是tflite它是如何前向的呢?
    2018-11-30 09:57 回复
九幽  TF荚荚  发表于 2018-11-30 10:44:19 | 显示全部楼层
Zongjun 发表于 2018-11-26 05:48
just in case, 你没有新的问题了对吧?之前那一层楼点评太多了,我无法打开点评的第二页。。应该是卡bug ...

恩,语法编程能力啥的都得提高,,,我也觉得后面的问题涉及到我代码怎么写的,这都是细节问题,就得具体分析了,后面不好问了啊,,,
至于训练这部分,keras保存的是hdf5模型,要保存成pb应该就要改成tf写的了吧?要用图,,,
keras我之前查没看到直接保存成pb的,只有hdf5转化为pb的,,,
本楼点评(9) 收起
  • 九幽那个create_inference_graph好像知道怎么写了,其实明白过来感觉之前的问答都比较边缘化,,,我是一直没清楚这个推理图该怎么创建,里面该怎么写,然后今天又综合考虑了一下,感觉训练图和推理图应该是一个图啊,也就是你说的他们都用的create_model,所以他们就是一样的网络结构,不是我之前问的说create_inference_graph里面是网络层结构定义,这个定义是在create_model里的,而我不明白的地方其实是create_model之前的那些语句,结果那些语句原来是数据处理,跟网络结构没关系,,,,
    所以我的mnist里面就应该直接调用之前训练用的build_network,那里面是网络定义,所以在推理图的部分应该再次调用build_network,然后直接用训练时用的output给create_eval_graph来用
    2018-11-30 16:01 回复
  • 九幽我还是在mnist里面练习了一下,想验证下上面说的对不对,但是怎么改都报错,我把所有步骤都放到一个文件里了,因为像speech那样分开写报错也一样
    我觉得结构应该是没什么问题,就是细节的语法可能有问题,写好之后一直报的错误都是ValueError: Training op found in graph, exiting {'ApplyGradientDescent'}
    然后我感觉是因为没有创建出两个图来,但是创建了两个图,又报错说数据应该来源于一个图,,,
    不知道大神有没有时间看一下代码,,我是不知道怎么改了,,,不确定我写的对不对,,,先贴在这吧,,
    import tensorflow as tf
    import os.path
    from tensorflow.python.framework import graph_util
    from tensorflow.examples.tutorials.mnist import input_data

    mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

    x = tf.placeholder("float", shape=[None, 784], name='input')
    y = tf.placeholder("float", shape=[None, 10], name='labels')
    keep_prob = tf.placeholder("float", name='keep_prob')


    def build_network():
        def weight_variable(shape):
            initial = tf.truncated_normal(shape, stddev=0.1)
            return tf.Variable(initial)

        def bias_variable(shape):
            initial = tf.constant(0.1, shape=shape)
            return tf.Variable(initial)

        # convolution and pooling
        def conv2d(x, W):
            return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='VALID')

        def max_pool_2x2(x):
            return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='VALID')

        # convolution layer
        def lenet5_layer(layer, weight, bias):
            W_conv = weight_variable(weight)
            b_conv = bias_variable(bias)
            h_conv = conv2d(layer, W_conv)   b_conv
            return max_pool_2x2(h_conv)

        # connected layer
        def dense_layer(layer, weight, bias):
            W_fc = weight_variable(weight)
            b_fc = bias_variable(bias)
            return tf.matmul(layer, W_fc)   b_fc

        # first layer
        with tf.name_scope('first') as scope:
            x_image = tf.pad(tf.reshape(x, [-1,28,28,1]), [[0,0],[2,2],[2,2],[0,0]])
            firstlayer = lenet5_layer(x_image, [5,5,1,6], [6])

        # second layer
        with tf.name_scope('second') as scope:
            secondlayer = lenet5_layer(firstlayer, [5,5,6,16], [16])

        # third layer
        with tf.name_scope('third') as scope:
            W_conv3 = weight_variable([5,5,16,120])
            b_conv3 = bias_variable([120])
            thirdlayerconv = conv2d(secondlayer, W_conv3)   b_conv3
            thirdlayer = tf.reshape(thirdlayerconv, [-1,120])

        # dense layer1
        with tf.name_scope('dense1') as scope:
            dense_layer1 = dense_layer(thirdlayer, [120,84], [84])

        # dense layer2
        with tf.name_scope('dense2') as scope:
            dense_layer2 = dense_layer(dense_layer1, [84,10], [10])

        finaloutput = tf.nn.softmax(tf.nn.dropout(dense_layer2, keep_prob), name="softmax")
        print('finaloutput:', finaloutput)
        return finaloutput


    def create_training_graph():
        # g = tf.get_default_graph()
        logits = build_network()
        # Create the back propagation and training evaluation machinery in the graph.
        with tf.name_scope('cross_entropy'):
            cross_entropy_mean = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(labels=y, logits=logits))
            print('cost:', cross_entropy_mean)

        # if FLAGS.quantize:
        tf.contrib.quantize.create_training_graph(quant_delay=0)     # input_graph=g,
        optimize = tf.train.GradientDescentOptimizer(1e-5).minimize(cross_entropy_mean)

        prediction_labels = tf.argmax(logits, axis=1, name="output")
        correct_prediction = tf.equal(tf.argmax(logits, 1), tf.argmax(y, 1))
        accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))

        with tf.get_default_graph().name_scope('eval'):
            tf.summary.scalar('cross_entropy', cross_entropy_mean)
            tf.summary.scalar('accuracy', accuracy)

        # if is_training:
        return dict(
            x=x,
            y=y,
            keep_prob=keep_prob,
            optimize=optimize,
            cost=cross_entropy_mean,
            correct_prediction=correct_prediction,
            accuracy=accuracy,
        )


    def train_network(graph):
        init = tf.global_variables_initializer()
        saver = tf.train.Saver()

        with tf.Session() as sess:
            sess.run(init)
            for i in range(200):
                batch = mnist.train.next_batch(50)
                if i % 100 == 0:
                    train_accuracy = sess.run([graph['accuracy']], feed_dict={
                                                                               graph['x']:batch[0],
                                                                               graph['y']:batch[1],
                                                                               graph['keep_prob']: 1.0})
                    print("step %d, training accuracy %g"%(i, train_accuracy[0]))
                sess.run([graph['optimize']], feed_dict={
                                                           graph['x']:batch[0],
                                                           graph['y']:batch[1],
                                                           graph['keep_prob']:0.5})

            test_accuracy = sess.run([graph['accuracy']], feed_dict={
                                                                      graph['x']: mnist.test.images,
                                                                      graph['y']: mnist.test.labels,
                                                                      graph['keep_prob']: 1.0})
            print("Test accuracy %g" % test_accuracy[0])

            saver.save(sess, '/home/angela/tensorflow/tensorflow/Mnist_train/mnist_fakequantize.ckpt')
            tf.train.write_graph(sess.graph_def, '/home/angela/tensorflow/tensorflow/Mnist_train/', 'mnist_fakequantize.pbtxt', True)


    def main():
        g1 = create_training_graph()
        train_network(g1)

        sess = tf.InteractiveSession()
        g2 = tf.Graph()
        with g2.as_default():
            build_network()  # is_training=False
            # if FLAGS.quantize:
            tf.contrib.quantize.create_eval_graph()
            # load_variables_from_checkpoint(sess, '/home/angela/tensorflow/tensorflow/Mnist_train/mnist_fakequantize.ckpt')
            # Turn all the variables into inline constants inside the graph and save it.
            frozen_graph_def = graph_util.convert_variables_to_constants(
                sess, sess.graph_def, ['softmax'])
            tf.train.write_graph(
                frozen_graph_def,
                os.path.dirname('/home/angela/tensorflow/tensorflow/Mnist_train/mnist_frozen_graph.pb'),
                os.path.basename('/home/angela/tensorflow/tensorflow/Mnist_train/mnist_frozen_graph.pb'),
                as_text=False)
            tf.logging.info('Saved frozen graph to %s', '/home/angela/tensorflow/tensorflow/Mnist_train/mnist_frozen_graph.pb')


    main()
    2018-11-30 19:13 回复
  • Zongjun回复 九幽 :感觉你彻底明白了哈。inference用的图是用同一个create_model函数产生出来的,用来inference的图结构当然得和训练的时候的结构一样啊,要是图都不一样,训练了也没用啊。只是create_training_graph和create_eval_graph对各自的图的处理效果不同而已。所以还是必须要创建两个图出来。
    我大体看了一下你的代码,你的这个报错的源代码是这个链接:https://github.com/tensorflow/tensorflow/blob/master/tensorflow/contrib/quantize/python/quantize_graph.py
    显然你这个报错来源于create_training_graph或者create_eval_graph或者两者皆报错。我的建议是和speech那样分开写两个文件,各创造一个图。看看这个报错是从train出来的还是从eval出来的。这样比较好debug。
    2018-12-1 01:49 回复
  • 九幽回复 Zongjun :恩,现在不像之前思路不清无从下手了,至少可以动手写一写了,分开的我也写了,报的错误就是上面提到的,训练节点已经存在的问题
    我看位置是create_eval_graph那里,因为create_eval_graph那部分单独写就是像freeze.py一样的结构,然后调用网络那里它又训练了,我写的if is_training也没用,可能没写对吧,,,我记得分开也是一样的,我再试试吧,应该就是推理图那里调用网络结构有问题,,,
    2018-12-1 10:54 回复
  • 九幽回复 Zongjun :分开写一直是训练不报错,freeze报错,错误:
    ValueError: Tensor("first/Variable:0", shape=(5, 5, 1, 6), dtype=float32_ref) must be from the same graph as Tensor("Pad:0", shape=(?, 32, 32, 1), dtype=float32).
    这个float32_ref的错误,我之前用frozen指令转化pb模型的时候就报过这个错误,这个是训练的数据类型和freeze用的不一样吗?
    2018-12-3 13:01 回复
  • Zongjun回复 九幽 :这个报错我没遇见过,感觉和你的Model有关系。你得确保两个图是完全分开的,然后两个图的结构一致(除了dropout这些只属于training的node)。我简单搜了一下,stackoverflow上有一个类似的问题,看看能不能帮到你,链接:https://stackoverflow.com/questions/42527048/valueerror-tensor-must-be-from-the-same-graph-as-tensor
    2018-12-4 01:53 回复
  • 九幽回复 Zongjun :多谢,改了确实不报错了,我分开写的完全是按照speech的例子写的,顺序结构都一样照搬过去的,但现在就是运行freeze就会重新训练,然后调试了一下,发现到create_eval_graph就不运行了,也保存不出最后的pb文件,,,
    freeze这里我只改了create_inference_graph,写的是
    logits = mnist_fakequantize.build_network(is_training=False)  
    tf.nn.softmax(logits, name='output')
    只调用build_network,build_network改成了去掉后面optimize那部分的,只到finaloutput那句话,就是这样,然后就不知道为啥不保存了,,,,
    至于又训练一遍,难道是训练的开关没加好?但只调用build_network,为什么还会训练呢?想不明白,,
    最后,mnist原来用的是AdamOptimizer,几百次就到了0.9多,但是换成了GradientDescentOptimizer,两万次准确率也很低,,只改这一处,别的没动,我看网上有人换了准确率也是0.9多,就是不知道我的为什么这么低,一直不收敛
    2018-12-4 16:11 回复
  • 九幽回复 Zongjun :重复训练的问题改好了,好开心~原来还是要把build_network单独提出来,我重写了一个文件放进去,然后再调用就好了~查看pb图和tflite转化的图也都是对的了~
    至于那个AdamOptimizer和GradientDescentOptimizer的问题,是不是用哪个都行啊?根据自己的情况选择合适的优化器?
    但是我这里两个出来的准确率相差那么悬殊是什么原因呢?
    2018-12-4 17:44 回复
  • Zongjun回复 九幽 :哈哈,恭喜你走完整个流程了。optimizer还是用mnist原来的吧,具体差别可以看看adam的paper。adam应该用的是moving average of parameters。用gradient descent 那个你要调learning rate这个参数的,learning rate过大就不会收敛。你用adam准确略正常的话就还是用adam吧,毕竟mnist默认的。
    2018-12-5 02:25 回复
九幽  TF荚荚  发表于 7 天前 | 显示全部楼层
Zongjun 发表于 2018-11-26 05:48
just in case, 你没有新的问题了对吧?之前那一层楼点评太多了,我无法打开点评的第二页。。应该是卡bug ...

哦哦,也是,想了解具体的用法就得好好查查论文啥的了,用GradientDescentOptimizer的learning rate感觉也不大,之前是1e-5,我看别人也是这样写的,结果却是准确率差不多,,,
mnist这一块基本感觉差不多了,剩下的就是语法用法啥的了,,,
感觉大神你很适合做老师啊,又有耐心又会讲解,做领导肯定能把手下的人带的很好,我这几天都觉得提升不少,还得有名师点拨啊~再次感谢~

现在量化知道怎么用了,接下来就是改keras的程序了,vgg网络结构要改,训练保存pb也要改,还要再加一个eval.
1.loss和optimize这部分:
(1)我看这几个例子,都放在了单独写好的网络定义之后,比如create_model之后,然后跟训练的代码放在一起。我的mnist也是把build_network和loss处理、添加伪量化语句分开来写的,所以keras这里我也把它跟训练代码写一起比较好吧?
keras写的vgg模型定义这里,包括了loss处理,就是:
model = Model(inputs=img, outputs=olayer)
model.compile(loss=loss_cls,     # yolo_loss
                      optimizer=SGD(lr=0.01, momentum=0.9, clipnorm=2.0),
                      metrics=['mse', ])
如果是这样的话,那伪量化需要的训练图那部分的处理就要加在这里了呗?是把loss和optimize的处理加在model.compile里面(我不知道怎么加进去,还要看语法,感觉固定的参数添加了其他语句会报错的吧?,,,)还是要去掉这部分,直接用tf底层语句来写啊?像speech例子和我改的mnist那样写?,,,
综述:loss这部分是跟模型写在一起(因为vgg带了model.compile,如果在这里面改的话就放在这),还是拿走去跟训练写在一起(去掉model.compile,改成tf底层代码)?
【从我修改mnist的过程来看,处理loss这部分,也就是加了create_training_graph的这部分,不能跟模型定义放在一起,因为会出问题,后面eval的部分还要调用模型,所以检测到create_training_graph就会报错,所以,从这来看,还是改成tf代码,然后跟训练执行放到一起去?】
(2)我的vgg模型也就相当于create_model里面的东西,但是loss用的是yolo的loss,普通的loss是交叉熵,那我这里可以改成自己要用的yolo_loss吗?,,,除了create_training_graph和create_eval_graph是必须用的,他们的位置是必须考虑的,其他的是不是都是根据自己的需求来用就好啊?比如之前说的Adam和GradientDescent,还有这里的loss?
2.训练图和保存:

创建训练图和保存pb文件,这里应该也得用tf来写,这一部分感觉又是具体问题,也不知道怎么问,,,
3.create_inference_graph
我的mnist里面修改的很简单,logits = build_network(is_training=False),f.nn.softmax(logits, name='output'),就这两句话,,因为我的输出不只是分类,还有画框的tensor,所以就不知道这里给输出该给什么,我的这里应该是画框和分类都放在一起了,有一个14位的一维数组,4个:类别one-hot,2个bbox:(1,1),8个:(x,y,w,h)*2。所以觉得输出是不是就是这个一位数组了呢?
我先看看keras的example还有语法,看看能不能解决一些问题,,,

本楼点评(3) 收起
  • Zongjun不敢当不敢当,略知一二而已。不要客气哈。
    1. (1)Exactly. Loss的定义不能和模型定义放一起,不然你eval的时候call同一个function就会报错。Loss要单独写,就是把kears的这一套换成tf底层代码或者slim代码的loss和optimizer。(2)对的,loss就是你训练用的那个loss,所以你的如果是yolo的,那就换成yolo的。不过我不确定这样简单的直接替换会不会有什么意外,可能还需要后续调试啥的。顺序的话,你按照例子的顺序来即可。
    2. 创建训练图和推理图跟以前那两个例子是一样的啊,推荐用tf.kears.layers或者tf.slim写。如果有batch normliazation的话,优先用slim吧。freeze的话可以考虑用例子里的方法,也可以用tensorflow的freeze_graph.py文件。推荐你先用例子的,毕竟那个你已经成功了。
    3. 输出我不确定,你可以先按照你说的试试,看看toco转化成.tflite的时候报不报错吧。
    为啥还要看keras的语法呢,其实所有的code都可以用tf.keras.layers或者tf.slim或者tf底层代码搞定了。跟例子是一样的。
    2018-12-6 05:00 回复
  • 九幽回复 Zongjun :恩,我今天看了model.compile的使用,可以在前面做loss和optimize的处理,然后在里面调用,但是create_training_graph肯定是没地方塞进去了,所以只能是把model.compile整个去掉,然后用tf来写了,因为这个我还算熟悉一点,slim要再去看,我先把slim排在后面,tf弄不好再说。
    训练那部分是keras写的,你的意思是训练图可以用tf.kears.layers来建?或者我要是把训练和推理的部分都直接用tf底层重写呢?这个工作量会比在keras里面改大吗?
    看keras语法因为我之前没用过keras,只是看了下代码,但没有完全理解keras的整个过程,就是没把我的代码每一句都看懂,我只看懂了整体流程和每部分是什么功能,感觉它跟我今天去keras中文手册里面看的用法不太一样啊,你说的tf.keras.layers和keras是不一样的吗?
    比如,keras网络定义是:model.add(layers.Dense(16, activation='relu', input_shape=(10,))),然后我的vgg定义是:
    feat_layers = [Conv2D(16, (3, 3), name='model_weights/conv1_1/conv1_1', **conv_args), ......],没有model.add,,,
    感觉现在的问题依旧很边缘化,对keras我又不开窍了,,,
    2018-12-6 18:42 回复
  • Zongjun回复 九幽 :对,我的意思就是用tf.keras.layers来建训练图和推理图,这个是tensorflow官方对keras的实现。这个不行,你再尝试底层代码写图吧,底层代码写图应该是最麻烦的。Model.add是keras sequential model的用法,我个人不是很喜欢这个方式。
    loss 和optimizer你就直接用tf底层代码即可,这个和例子是一样的,代码也不多。
    2018-12-7 02:38 回复
您需要登录后才可以回帖 登录 | 加入社区

本版积分规则

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