使用 MobileNet 重新训练图像检测

Posted

技术标签:

【中文标题】使用 MobileNet 重新训练图像检测【英文标题】:Retrain image detection with MobileNet 【发布时间】:2019-09-14 21:18:04 【问题描述】:

重新训练 MobileNet 以与 Tensorflow.js 一起使用的几种方法对我来说都失败了。有没有办法通过 Tensorflow.js 使用重新训练的模型?

使用基于中心的现代教程以及使用 retrain.py 似乎都失败了。

Convert output of retrain.py to tensorflow.js Error converting keras model to tfjs: duplicate weight name Variable

以及其他一些未解决的问题

Retrain an Image Classifier in tensorflow js Loading of mobilenet v2 works, but pretrained mobilenet v2 fails Can't convert TensorFlow saved model to tfjs_layers_model webmodel

前两个问题显示了在这两种情况下都失败的代码,都没有解决。

目的是加载移动网络,使用自定义数据重新训练,并在 Tensorflow.js 中使用它。遵循这两个教程似乎都失败了。这可以在 node.js 中完成吗?还有其他方法吗?我在哪里犯了错误(或者软件无法使用重新训练的模型)?这怎么行?

编辑:latest github issue 和另外一个问题

【问题讨论】:

使用mobilenet进行图像检测进行迁移学习在this article进行了解释 @edkeveked:您的文章似乎使用 mobilenet 作为特征提取器。这个问题的目的是发布一个已经训练过的模型。 【参考方案1】:

也许有人可以使用我的方式修改retain.py 以支持mobileV2。 原来的 retrain.py link。这个链接是谷歌的 GitHub 代码,不是我的链接。

我改变了retrain.py,下面是我的git diff:

diff --git a/scripts/retrain.py b/scripts/retrain.py
index 5fa9b0f..02a4f9a 100644
--- a/scripts/retrain.py
+++ b/scripts/retrain.py
@@ -1,3 +1,5 @@
+# -*- coding: utf-8 -*-
+
 # Copyright 2015 The TensorFlow Authors. All Rights Reserved.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -112,6 +114,13 @@ from tensorflow.python.framework import graph_util
 from tensorflow.python.framework import tensor_shape
 from tensorflow.python.platform import gfile
 from tensorflow.python.util import compat
+from tensorflow import saved_model as sm
+from tensorflow.python.saved_model import builder as saved_model_builder
+from tensorflow.python.saved_model import signature_constants
+from tensorflow.python.saved_model import signature_def_utils
+from tensorflow.python.saved_model import tag_constants
+from tensorflow.python.saved_model import utils as saved_model_utils
+

 FLAGS = None

@@ -319,6 +328,7 @@ def maybe_download_and_extract(data_url):
   Args:
     data_url: Web location of the tar file containing the pretrained model.
   """
+  print(FLAGS.model_dir)
   dest_directory = FLAGS.model_dir
   if not os.path.exists(dest_directory):
     os.makedirs(dest_directory)
@@ -827,6 +837,7 @@ def save_graph_to_file(sess, graph, graph_file_name):
       sess, graph.as_graph_def(), [FLAGS.final_tensor_name])
   with gfile.FastGFile(graph_file_name, 'wb') as f:
     f.write(output_graph_def.SerializeToString())
+
   return


@@ -971,6 +982,7 @@ def main(_):

   # Prepare necessary directories  that can be used during training
   prepare_file_system()
+  sigs = 

   # Gather information about the model architecture we'll be using.
   model_info = create_model_info(FLAGS.architecture)
@@ -1002,6 +1014,9 @@ def main(_):
       FLAGS.random_brightness)

   with tf.Session(graph=graph) as sess:
+    serialized_tf_example = tf.placeholder(tf.string, name='tf_example')
+    feature_configs = 'x': tf.FixedLenFeature(shape=[784], dtype=tf.float32),
+    tf_example = tf.parse_example(serialized_tf_example, feature_configs)
     # Set up the image decoding sub-graph.
     jpeg_data_tensor, decoded_image_tensor = add_jpeg_decoding(
         model_info['input_width'], model_info['input_height'],
@@ -1133,6 +1148,73 @@ def main(_):
                           (test_filename,
                            list(image_lists.keys())[predictions[i]]))

+    """
+    # analyze SignatureDef protobuf
+    SignatureDef_d = graph.signature_def
+    SignatureDef = SignatureDef_d[sm.signature_constants.CLASSIFY_INPUTS]
+
+    # three TensorInfo protobuf
+    X_TensorInfo = SignatureDef.inputs['input_1']
+    scale_TensorInfo = SignatureDef.inputs['input_2']
+    y_TensorInfo = SignatureDef.outputs['output']
+
+    # Tensor details
+    # .get_tensor_from_tensor_info() to get default graph 
+    X = sm.utils.get_tensor_from_tensor_info(X_TensorInfo, sess.graph)
+    scale = sm.utils.get_tensor_from_tensor_info(scale_TensorInfo, sess.graph)
+    y = sm.utils.get_tensor_from_tensor_info(y_TensorInfo, sess.graph)
+    """
+
+    """
+    output_graph_def = graph_util.convert_variables_to_constants(
+      sess, graph.as_graph_def(), [FLAGS.final_tensor_name])
+
+    X_TensorInfo = sm.utils.build_tensor_info(bottleneck_input)
+    scale_TensorInfo = sm.utils.build_tensor_info(ground_truth_input)
+    y_TensorInfo = sm.utils.build_tensor_info(output_graph_def)
+
+    # build SignatureDef protobuf
+    SignatureDef = sm.signature_def_utils.build_signature_def(
+                                inputs='input_1': X_TensorInfo, 'input_2': scale_TensorInfo,
+                                outputs='output': y_TensorInfo,
+                                method_name='what'
+    )
+    """
+
+    #graph = tf.get_default_graph()
+    tensors_per_node = [node.values() for node in graph.get_operations()]
+    tensor_names = [tensor.name for tensors in tensors_per_node for tensor in tensors]
+    print(tensor_names)
+
+    export_dir = './tf_files/savemode'
+    builder = saved_model_builder.SavedModelBuilder(export_dir)
+
+    # name="" is important to ensure we don't get spurious prefixing
+    graph_def = tf.GraphDef()
+    tf.import_graph_def(graph_def, name="")
+    g = tf.get_default_graph()
+    inp1 = g.get_tensor_by_name("input:0")
+    inp2 = g.get_tensor_by_name("input_1/BottleneckInputPlaceholder:0")
+    inp3 = g.get_tensor_by_name("input_1/GroundTruthInput:0")
+    out = g.get_tensor_by_name("accuracy_1:0")
+
+    sigs[signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY] = \
+        tf.saved_model.signature_def_utils.predict_signature_def(
+            'input_1': inp1, 'input_2': inp3, "output": out)
+
+    builder.add_meta_graph_and_variables(sess,
+                                         tags=[tag_constants.SERVING],
+                                         signature_def_map=sigs)
+
+    """
+    builder.add_meta_graph_and_variables(
+            sess=sess,
+            tags=[tag_constants.SERVING],
+            signature_def_map=sm.signature_constants.CLASSIFY_INPUTS: SignatureDef)
+    """
+
+    builder.save()
+
     # Write out the trained graph and labels with the weights stored as
     # constants.
     save_graph_to_file(sess, graph, FLAGS.output_graph)

使用我的差异,我可以生成 Tensorflow Served 模型。 然后我使用命令将 TensorFlow 服务模型转换为 Tfjs 模型。

tensorflowjs_converter \
    --input_format=tf_saved_model \
    --output_format=tfjs_graph_model \
    ./tf_files/savemode \
    ./tf_files/js_model

最后的 Tensorflow JS 版本仍然不支持 Ops。

我只是做了一个视频here来解释为什么我们不能将Tensorflow冻结模型转换为Tensorflow JS模型,告诉如何找到输入张量和输出张量。运行步骤和结果,最后给出不支持的 Ops ScalarSummary 和原因。

现在我无法将 Mobilenet 模型更改为 Tensorflow JS 模型,所以我的解决方法是在服务器端使用 Python tensorflow 和 flask 库,用户将图像上传到服务器然后返回结果。

【讨论】:

感谢您在 *** 上帮助用户。尽管您花时间制作了视频,但这里的答案应该保持独立的自包含解释,而不是依赖外部资源来理解。如果您在答案中添加足够的解释,则可以保留您的视频链接,这样您就不需要观看视频链接来获得答案。 你试过as @MahalovIvan suggested吗? @serv-inc 我已经尝试过了,但仍然无法得到正确的结果。 @LéaGris 谢谢,我会为这个答案添加更多解释。【参考方案2】:

我遇到了同样的问题,似乎我们使用了错误的方法。 TF 转换模型有 loadGraphModel,Keras 有 loadLayersModel my comment about the issue

【讨论】:

【参考方案3】:

要使用最新的 TFjs:

python retrain.py --tfhub_module https://tfhub.dev/google/imagenet/mobilenet_v2_100_224/feature_vector/2 \
    --image_dir /tmp/flower_photos --saved_model_dir /tmp/saved_retrained_model
tensorflowjs_converter --input_format=tf_saved_model \
    --output_format=tfjs_graph_model \
    --saved_model_tags=serve \
    /tmp/saved_retrained_model/ /tmp/converted_model/

创建一个model.json 文件。 https://github.com/tensorflow/tfjs-converter#step-1-converting-a-savedmodel-keras-h5-tfkeras-savedmodel-or-tensorflow-hub-module-to-a-web-friendly-format中描述的命令。

然而,用tf.loadLayersModel("file:///tmp/web_model/model.json") 加载模型失败了

'className' 和 'config' 必须设置。

【讨论】:

你好,你能看看这个:***.com/questions/64621656/… 您好,application_mobilenet 定义在哪里? 我从 kera 的文档 keras.io/api/applications/mobilenet 中获取了那个 sn-p 【参考方案4】:

retrain.pypython 脚本不会生成保存的模型,它实际上会生成冻结的图模型。这就是您无法使用 tfjs 1.x 转换器对其进行转换的原因。您需要使用 tfjs 0.8.5 pip 进行转换。 此外,输出节点名称与 mobilenet 模型图不同,它是重新训练图的“final_result”。

要转换它,您需要使用 tensorflowjs 0.8.5 pip:

使用 virtualenv 创建一个空的 env。 pip install tensorflowjs==0.8.5 运行转换器
tensorflowjs_converter \
  --input_format=tf_frozen_model \
  --output_node_names='final_result' \
  --output_json=true /tmp/output_graph.pb \ /tmp/web_model

这应该会给你如下内容:

ls /tmp/web_model/
group1-shard10of21  group1-shard14of21  group1-shard18of21  group1-shard21of21  group1-shard5of21  group1-shard9of21
group1-shard11of21  group1-shard15of21  group1-shard19of21  group1-shard2of21   group1-shard6of21  model.json
group1-shard12of21  group1-shard16of21  group1-shard1of21   group1-shard3of21   group1-shard7of21
group1-shard13of21  group1-shard17of21  group1-shard20of21  group1-shard4of21   group1-shard8of21

【讨论】:

我认为 retrain.py 脚本有一个 --saved_model_dir=/tmp/saved_models/ 选项,它将生成保存的模型输出。您应该尝试一下,看看是否可以使用 1.x 转换器对其进行转换。谢谢。 使用tf.loadLayersModel("file:///tmp/web_model/model.json") 加载模型失败,“className”和“config”必须设置。 转换器最新版本(1.3.2)现在支持冻结模型。 你好,你可以看看这个:***.com/questions/64621656/…

以上是关于使用 MobileNet 重新训练图像检测的主要内容,如果未能解决你的问题,请参考以下文章

SSD mobilenet 模型无法检测到更远距离的物体

5. 使用PyTorch预先训练的模型执行目标检测

Google 对象检测 API - 使用 faster_rcnn_resnet101_coco 模型进行训练

图像分类任务不用冷启动,PaddlePaddle一口气发布十大预训练模型

如何使用最新的 MobileNet (v3) 进行目标检测?

如何在 tensorflow 对象检测 API 中使用“忽略”类?