如何在 Google Cloud AI Platform 中使用 Base64 服务 Tensorflow2 图像分割模型

Ara*_*ash 1 google-cloud-platform tensorflow-serving tensorflow2.0 gcp-ai-platform-training

我可以使用以下代码成功保存 TF2 图像分割模型并将其部署到 AI Platform:

@tf.function(input_signature=[tf.TensorSpec(shape=(None), dtype=tf.string)])
def serving(input_image):

    # Convert bytes of jpeg input to float32 tensor for model
    def _input_to_feature(image_bytes):
        img = tf.image.decode_jpeg(image_bytes, channels=3)
        img = tf.image.convert_image_dtype(img, tf.float32) / 255.0
        img = tf.image.resize_with_pad(img, 256, 256)
        return img
    img = tf.map_fn(_input_to_feature, input_image, dtype=tf.float32)

    # Predict
    pred = model(img)

    def _pred_to_image(pred):
        pred = tf.cast(pred * 255, dtype=tf.uint8)

        img_str = tf.image.encode_png(pred, compression=-1, name=None)
        return img_str

    img_str = tf.map_fn(_pred_to_image, pred, dtype=tf.string)

    return img_str


tf.saved_model.save(model, export_dir=checkpoint_dir+'/saved_model', signatures=serving)
Run Code Online (Sandbox Code Playgroud)

但是,我在发送这样的请求时收到此错误:

img_str = base64.b64encode(open('sample_372.jpg', "rb").read()).decode()
response = service.projects().predict(name=name,body={'instances': [img_str]}).execute()
Run Code Online (Sandbox Code Playgroud)
HttpError: <HttpError 400 when requesting https://ml.googleapis.com/v1/projects/nerveblox-268109/models/femoral/versions/v6:predict?alt=json returned "{ "error": "Expected image (JPEG, PNG, or GIF), got unknown format starting with \'/9j/4AAQSkZJRgAB\'\n\t [[{{node DecodeJpeg}}]]" }">
Run Code Online (Sandbox Code Playgroud)

有人遇到过类似的问题吗?这似乎是一个问题tf.image.decode_jpeg。我也尝试过tf.image.decode_image并遇到类似的错误。我可以使用tf.image.decode_jpeg本地 Base64 编码,因此该函数应该能够工作,但不知何故它在服务器中没有接收到相同的输入!

Ara*_*ash 5

经过大量实验(由于 Tensorflow 的文档有限且过时),我意识到为了让服务函数解码 Base64,请求应该像这样发送:{'instances': [{'b64': image_base64}]}。还将convert_image_dtype数据本身缩放到 [0,1],因此不应执行 /255.0。也map_fn仅适用于 CPU,因此应与with tf.device('/cpu:0'):. 最后也是最烦人的部分是 Base64 的编码。tf.io.encode_base64是我在 Tensorflow 中发现的编码为 Base64 的唯一方法,但它编码为网络安全,这意味着它将 \ 和 + 替换为 _ 和 - 以便在 URL 中工作。但 Google API 客户端仅接受普通的 Base64 编码。所以我必须通过正则表达式来扭转这一点。这是更新后的服务功能:

@tf.function(input_signature=[tf.TensorSpec(shape=(None), dtype=tf.string)])
def serving(input_image):

    # Convert bytes of jpeg input to float32 tensor for model
    def _input_to_feature(img_bytes):
        img = tf.image.decode_image(img_bytes, channels=3)
        img = tf.image.convert_image_dtype(img, tf.float32)
        img = tf.image.resize_with_pad(img, 256, 256)
        return img

    # Preprocessing
    with tf.device('/cpu:0'):
        img = tf.map_fn(_input_to_feature, input_image, dtype=tf.float32)

    # Prediction
    with tf.device('/gpu:0'):
        pred = model(img)
        colors = tf.constant([[0.2, 0.3, 0.4]])
        pred_rgb = tf.tensordot(pred, colors, axes=1)

    def _pred_to_image(pred):
        pred = tf.image.convert_image_dtype(pred,dtype=tf.uint8)

        pred_str = tf.image.encode_png(pred, compression=4)
        pred_encoded = tf.io.encode_base64(pred_str, pad=True)
        pred_encoded = tf.strings.regex_replace(pred_encoded, '_', '/')
        pred_encoded = tf.strings.regex_replace(pred_encoded, '-', '+')

        return pred_encoded

    # Postprocessing
    with tf.device('/cpu:0'):
        img_str = tf.map_fn(_pred_to_image, pred_rgb, dtype=tf.string)

    return img_str


tf.saved_model.save(model, export_dir=checkpoint_dir+'/saved_model', signatures=serving)
Run Code Online (Sandbox Code Playgroud)