Обнаружение изображения с помощью MobileNet

Несколько способов переобучения MobileNet для использования с Tensorflow.js потерпели неудачу для меня. Есть ли способ использовать переобученную модель с Tensorflow.js?

Как с использованием современного, основанного на хабе учебника, так и с использованием retrain.py Кажется, не удалось.

а также некоторые другие открытые вопросы

Два верхних вопроса показывают код, который не удалось в обоих случаях, оба не решены.

Цель состоит в том, чтобы загрузить мобильную сеть, переобучаться с использованием пользовательских данных и использовать их в Tensorflow.js. Следование обоим учебным пособиям кажется неудачным. Может ли это быть сделано внутри node.js? Есть ли другой способ? Где я допустил ошибки (или программное обеспечение не может использовать переобученные модели)? Как это может работать?

РЕДАКТИРОВАТЬ: последний выпуск GitHub и еще один вопрос

2 ответа

Я столкнулся с той же проблемой, и кажется, что мы использовали неправильный метод. Есть loadGraphModel для моделей, преобразованных в TF, и loadLayersModel для Keras - мой комментарий по проблеме.

retrain.py Скрипт python не генерирует сохраненную модель, он фактически генерирует замороженную модель графа. Вот почему вы не можете конвертировать его с помощью конвертера tfjs 1.x. Вам необходимо использовать tfjs 0.8.5 pip для конвертации. Кроме того, имя выходного узла отличается от графа модели мобильной сети, это "final_result" для переобученного графа.

Чтобы конвертировать его, вам нужно использовать tenorflowjs 0.8.5 pip:

  • использовать virtualenv для создания пустого окружения.
  • pip install tenorflowjs==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

Чтобы использовать последние 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-формат.

Тем не менее, загрузка модели с tf.loadLayersModel("file:///tmp/web_model/model.json") не удалось с

'className' и 'config' должны быть установлены.

Может быть, кто-нибудь может изменить keep.py для поддержки использования mobileV2 по-моему. Оригинальная ссылка retrain.py. Эта ссылка является кодом Google на 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)

Используя свой diff, я могу создать модель, обслуживаемую Tensorflow. Затем я использую команду для преобразования модели, обслуживаемой TensorFlow, в модель Tfjs.

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

По-прежнему не поддерживается Ops для последней версии Tensorflow JS.

Я просто делаю видео здесь, чтобы объяснить, почему мы не можем преобразовать замороженную модель Tensorflow в модель Tensorflow JS, рассказывает, как найти входной тензор и выходной тензор. Шаги и результат выполнения, наконец, дают неподдерживаемое Ops ScalarSummary и причину.

Теперь, когда я не могу изменить модель Mobilenet на модель Tensorflow JS, я использую тензорный поток Python и библиотеку флаконов на стороне сервера, пользователь загружает изображение на сервер и затем возвращает результат.

Другие вопросы по тегам