Это третья и последняя глава в серии моделей Tensorflow SavedModel. существует"Сохранение и загрузка моделей Tensorflow SavedModel", мы рассказали о том, как модели Tensorflow сохраняются в формате SavedModel и как их загружать. существует"Как просмотреть информацию о модели в формате tensorflow SavedModel", мы демонстрируем, как просматривать сигнатуру модели и структуру вычислительного графа. В этой статье мы рассмотрим, как объединить две модели, просто объединив выходные данные первой модели в качестве входных данных второй модели для формирования новой модели.
задний план
Зачем нужно объединять две модели?
Мы до сих пор используем "Сохранение и загрузка моделей Tensorflow SavedModel«Например, ввод, полученный этой моделью распознавания рукописных цифр, имеет форму [?, 784], где ? означает, что ввод может быть получен пакетами, вы можете сначала проигнорировать его и исправить его на 1. 784 — это результат расширения 28 x 28, то есть результат расширения изображения в градациях серого 28 x 28.
Проблема в том, что модели мы отправляем обычно картинку, может из файла, может с камеры. Что усложняет проблему, так это то, что если мы вызываем модель, развернутую на сервере через HTTP, бинарные данные на самом деле неудобны для HTTP-передачи, в это время нам обычно нужно кодировать данные изображения в base64. Таким образом, данные, полученные сервером, представляют собой строку base64, а модель принимает двоичный вектор.
Естественно, мы можем думать о двух решениях:
-
Переобучите модель модели, которая получает строку base64.
Проблема с этим обходным решением заключается в том, что переобучение модели требует много времени или даже невозможно. Поскольку пример в этой статье относительно прост, переобучение не имеет значения. Если это такая глубокая сверточная нейронная сеть, то на одно обучение могут уйти дни, а переобучение стоит дорого. В более общем плане мы используем модели, обученные другими, такими как Mobilenet, InceptionV3 и т. д., которые обычно используются для распознавания изображений. Все они обучены такими компаниями, как Google и Microsoft, которые потребляют много ресурсов. состояние.
-
Добавьте преобразование 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.