Как объединить две модели TensorFlow

искусственный интеллект TensorFlow Microsoft сервер

Это третья и последняя глава в серии моделей Tensorflow SavedModel. существует"Сохранение и загрузка моделей Tensorflow SavedModel", мы рассказали о том, как модели Tensorflow сохраняются в формате SavedModel и как их загружать. существует"Как просмотреть информацию о модели в формате tensorflow SavedModel", мы демонстрируем, как просматривать сигнатуру модели и структуру вычислительного графа. В этой статье мы рассмотрим, как объединить две модели, просто объединив выходные данные первой модели в качестве входных данных второй модели для формирования новой модели.

задний план

Зачем нужно объединять две модели?

Мы до сих пор используем "Сохранение и загрузка моделей Tensorflow SavedModel«Например, ввод, полученный этой моделью распознавания рукописных цифр, имеет форму [?, 784], где ? означает, что ввод может быть получен пакетами, вы можете сначала проигнорировать его и исправить его на 1. 784 — это результат расширения 28 x 28, то есть результат расширения изображения в градациях серого 28 x 28.

Проблема в том, что модели мы отправляем обычно картинку, может из файла, может с камеры. Что усложняет проблему, так это то, что если мы вызываем модель, развернутую на сервере через HTTP, бинарные данные на самом деле неудобны для HTTP-передачи, в это время нам обычно нужно кодировать данные изображения в base64. Таким образом, данные, полученные сервером, представляют собой строку base64, а модель принимает двоичный вектор.

Естественно, мы можем думать о двух решениях:

  1. Переобучите модель модели, которая получает строку base64.

    Проблема с этим обходным решением заключается в том, что переобучение модели требует много времени или даже невозможно. Поскольку пример в этой статье относительно прост, переобучение не имеет значения. Если это такая глубокая сверточная нейронная сеть, то на одно обучение могут уйти дни, а переобучение стоит дорого. В более общем плане мы используем модели, обученные другими, такими как Mobilenet, InceptionV3 и т. д., которые обычно используются для распознавания изображений. Все они обучены такими компаниями, как Google и Microsoft, которые потребляют много ресурсов. состояние.

  2. Добавьте преобразование base64 в двоичные данные на стороне сервера.

    Это решение не сложно реализовать, но что, если мы развернем его с помощью чего-то вроде сервера модели Tensorflow? Конечно, мы также можем запустить другой сервер, чтобы принимать данные изображения base64 клиента, а затем пересылать их на сервер модели Tensorflow после обработки, но это, несомненно, увеличит нагрузку на сервер и повысит сложность сервера.

В этой статье мы дадим третье решение: напишите модель Tensorflow, получите данные изображения base64, выведите двоичные векторы, а затем используйте выходные данные первой модели в качестве входных данных второй модели, объедините их и сохраните их как Новая модель, и, наконец, новая модель развернута.

base64 декодирует модель Tensorflow

Tensorflow включает в себя большое количество методов обработки изображений и обработки массивов, поэтому реализовать эту модель относительно просто.Модель включает в себя декодирование base64, декодирование изображений PNG, масштабирование до 28 * 28 и, наконец, расширение до (1, 784) вывода массива. , в соответствии с написанными от руки цифрами. Вход в модель распознавания, код выглядит следующим образом:

with tf.Graph().as_default() as g1:
  base64_str = tf.placeholder(tf.string, name='input_string')
  input_str = tf.decode_base64(base64_str)
  decoded_image = tf.image.decode_png(input_str, channels=1)
  # Convert from full range of uint8 to range [0,1] of float32.
  decoded_image_as_float = tf.image.convert_image_dtype(decoded_image,
                                                        tf.float32)
  decoded_image_4d = tf.expand_dims(decoded_image_as_float, 0)
  resize_shape = tf.stack([28, 28])
  resize_shape_as_int = tf.cast(resize_shape, dtype=tf.int32)
  resized_image = tf.image.resize_bilinear(decoded_image_4d,
                                           resize_shape_as_int)
  # 展开为1维数组
  resized_image_1d = tf.reshape(resized_image, (-1, 28 * 28))
  print(resized_image_1d.shape)
  tf.identity(resized_image_1d, name="DecodeJPGOutput")

g1def = g1.as_graph_def()

В этой модели нет переменных, но есть несколько фиксированных операций, поэтому обучение не требуется.

Загрузите модель распознавания рукописного ввода

Справочник по модели распознавания рукописного ввода《Сохранение и загрузка моделей Tensorflow SavedModel》, модель сохранена в"./model"Ниже код загрузки выглядит следующим образом:

with tf.Graph().as_default() as g2:
  with tf.Session(graph=g2) as sess:
    input_graph_def = saved_model_utils.get_meta_graph_def(
        "./model", tag_constants.SERVING).graph_def

    tf.saved_model.loader.load(sess, ["serve"], "./model")

    g2def = graph_util.convert_variables_to_constants(
        sess,
        input_graph_def,
        ["myOutput"],
        variable_names_whitelist=None,
        variable_names_blacklist=None)

Здесь g2 используется для определения другого графа, который отличается от графа предыдущей модели. Обратите внимание, что здесь вызывается graph_util.convert_variables_to_constants для преобразования переменных в модели в константы, что является так называемой операцией замораживания графа.

Я застрял на этом вопросе в течение длительного времени, исследуя, как соединить две модели. Первая идея заключалась в том, чтобы загрузить значения переменных после слияния моделей, но после попытки это не удалось. Более поздняя идея состоит в том, чтобы пройтись по переменным модели распознавания рукописного ввода, получить их значения переменных и скопировать значения переменных в переменные объединенной модели.

Наконец, меня вдохновило преобразование модели Tensorflow в облегченную модель Tensorflow, и я исправил переменные в модели, чтобы не было проблем с загрузкой переменных и не было проблем с неинициализированными переменными модели.

Выполнив convert_variables_to_constants, вы увидите, что две переменные преобразуются в константные операции, а именно w и b в модели распознавания рукописных цифр:

Converted 2 variables to const ops.

соединить две модели

Используя метод tf.import_graph_def, мы можем импортировать граф в существующий граф.Обратите внимание на второй import_graph_def, вход которого является выходом первого graph_def.Благодаря этой операции два вычислительных графа соединяются и, наконец, сохраняются. код показывает, как показано ниже:

with tf.Graph().as_default() as g_combined:
  with tf.Session(graph=g_combined) as sess:

    x = tf.placeholder(tf.string, name="base64_input")

    y, = tf.import_graph_def(g1def, input_map={"input_string:0": x}, return_elements=["DecodeJPGOutput:0"])

    z, = tf.import_graph_def(g2def, input_map={"myInput:0": y}, return_elements=["myOutput:0"])
    tf.identity(z, "myOutput")

    tf.saved_model.simple_save(sess,
              "./modelbase64",
              inputs={"base64_input": x},
              outputs={"myOutput": z})

Поскольку первая модель не содержит переменных, переменные второй модели преобразуются в константные операции, поэтому последний сохраненный файл модели не содержит переменных:

modelbase64/
├── saved_model.pb
└── variables

1 directory, 1 file

контрольная работа

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

with tf.Session(graph=tf.Graph()) as sess:
  sess.run(tf.global_variables_initializer())

  tf.saved_model.loader.load(sess, ["serve"], "./modelbase64")
  graph = tf.get_default_graph()

  with open("./5.png", "rb") as image_file:
    encoded_string = str(base64.urlsafe_b64encode(image_file.read()), "utf-8")

  x = sess.graph.get_tensor_by_name('base64_input:0')
  y = sess.graph.get_tensor_by_name('myOutput:0')

  scores = sess.run(y,
           feed_dict={x: encoded_string})
  print("predict: %d, actual: %d" % (np.argmax(scores, 1), 5))

Вход модели здесь base64_input, а выход по-прежнему myOutput, Протестировано с двумя изображениями, оба работают нормально.

резюме

Последние три статьи на самом деле подведены итоги, когда я изучаю свой апплет WeChat, Чтобы лучше проиллюстрировать проблему, я использую очень простую модель для иллюстрации проблемы, но она также применима к сложным моделям.

Полный код этой статьи см. по адресу:GitHub.com/mogo Web/голодание…

Надеюсь, эта статья была вам полезна, спасибо за прочтение! В то же время, обратите внимание на мой публичный аккаунт в WeChat: Yunshuimushi.

image