Tensorflow 2.0: добавьте шаг предварительной обработки изображения в сохраненную модель

Я новичок в TF и ​​развертывании на GCP. Так что заранее большое спасибо за помощь!

В настоящее время я пытаюсь развернуть приложение Mnist-handwriting flask на Google Cloud Platform (GCP) с использованием TensorFlow Serving. Я развернул свою модель на обслуживании TF и ​​использую собственный класс MySimpleScaler для предварительной обработки и изменения размера изображения перед его подачей в мою модель. Мой вопрос заключается в том, есть ли способ добавить класс предварительной обработки и изменения размера в мою модель сохранения, чтобы мое приложение для фляги не имело никаких зависимостей тензорного потока. Причина в том, что библиотека TF слишком велика для движка приложения.

Поток моего приложения выглядит следующим образом:

1) Приложение My flask развернуто на движке приложения. У него есть класс MySimpleScaler для изменения размера входного изображения с холста. Я разрешаю пользователю рисовать с холста во внешнем интерфейсе -> получать данные с помощью jquery -> использовать функцию parse_image, чтобы записать их как output.jpg -> читать output.jpg с локального диска и передавать его в MySimpleScaler для предварительной обработки

2) Моя модель развертывается на платформе AI с использованием TF. Я отправляю запрос прогноза, используя выходные данные MysimpleScaler на шаге 1. Затем значение прогноза передается в серверную часть Flask, а затем я передаю его во внешний интерфейс с помощью Jinja.

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

def parse_image(imgData):
    # imgData fetch img from canvas using request.get_data()
    imgstr = re.search(b"base64,(.*)", imgData).group(1)
    img_decode = base64.decodebytes(imgstr)
    with open("output.jpg", "wb") as file:
        file.write(img_decode)
    return img_decode
class MySimpleScaler(object):

    def preprocess_img(self, img_decode):
        # img_decode from parse_image
        img_raw = img_decode
        image = tf.image.decode_jpeg(img_raw, channels=1)
        image = tf.image.resize(image, [28, 28])
        image = (255 - image) / 255.0  # normalize to [0,1] range
        image = tf.reshape(image, (1, 28, 28, 1))

        return image

TL;DR: я хочу добавить функцию preprocess_img в качестве одного из слоев в моей модели сохранения, прежде чем развертывать ее на обслуживании TF. Большое вам спасибо за ваше время!


person novicecoder    schedule 15.12.2019    source источник


Ответы (1)


Если вы согласны с batch_size=1, то должно быть прямолинейно добавить функцию предварительной обработки внутри графика, вот как я бы это сделал:

Код:

import tensorflow as tf
import numpy as np

print('TensorFlow:',tf.__version__)

def preprocess_single_image(image_bytes, h=299, w=299):
    image = tf.image.decode_jpeg(image_bytes[0], channels=3)
    image = tf.image.resize(image, size=[h, w])
    image = (image - 127.5) / 127.5
    image = tf.expand_dims(image, axis=0)
    return image

image_bytes = tf.keras.Input(shape=[], batch_size=1, name='image_bytes', dtype=tf.string)
preprocessed_image = preprocess_single_image(image_bytes)
model = tf.keras.applications.Xception(weights='imagenet')
predictions = model(preprocessed_image)
new_model = tf.keras.Model(image_bytes, predictions)
new_model.save('export/1', save_format='tf')
print('Model Input Shape:', new_model.input_shape)

### !wget -q -O "cat.jpg" "https://images.pexels.com/photos/617278/pexels-photo-617278.jpeg?cs=srgb&dl=adorable-animal-blur-cat-617278.jpg&fm=jpg"
loaded_model = tf.saved_model.load('export/1')
cat_bytes = tf.expand_dims(tf.io.read_file('cat.jpg'), axis=0)
preds = loaded_model(cat_bytes).numpy()
print(tf.keras.applications.xception.decode_predictions(preds, top=3)[0])

Выход:

TensorFlow: 2.0.0
WARNING:tensorflow:From /tensorflow-2.0.0/python3.6/tensorflow_core/python/ops/resource_variable_ops.py:1781: calling BaseResourceVariable.__init__ (from tensorflow.python.ops.resource_variable_ops) with constraint is deprecated and will be removed in a future version.
Instructions for updating:
If using Keras pass *_constraint arguments to layers.
INFO:tensorflow:Assets written to: export/1/assets

Model Input Shape: (1,)
[('n02123045', 'tabby', 0.5762127), ('n02123159', 'tiger_cat', 0.24783427), ('n02124075', 'Egyptian_cat', 0.09435685)]

PS: вы можете использовать tf.map_fn, если хотите расширить это для поддержки batch_size > 1

person Srihari Humbarwadi    schedule 16.12.2019
comment
Спасибо большое за вашу помощь! У меня есть еще один глупый вопрос с tf.keras.Input(). Почему вы использовали tf.expand_dims() для чтения изображения вместо того, чтобы передавать его напрямую в tf.io.read_file() для получения строковых байтов? Требуется ли для tf.keras.Input() определенная форма? Я попытался без ввода расширенных размеров, и это дало эту ошибку: Shape must be rank 0 but is rank 1 for 'DecodeJpeg' (op: 'DecodeJpeg') with input shapes: [1]. - person novicecoder; 17.12.2019
comment
Модели keras нуждаются в оси batch, что заставляет вас отправлять байты изображения с осью batch. Но tf.io.read_file не поддерживает пакетную обработку. Поэтому вам нужно соответствующим образом изменить форму тензора! - person Srihari Humbarwadi; 17.12.2019