0

我很难导出一个用 Keras 训练的自定义 VGG-Net(不完全是 Keras 的那个),以便它可以用于 Google Cloud Predict API。我正在用 Keras 加载我的模型。

sess = tf.Session()
K.set_session(sess)

model = load_model(model.h5)

我要分类的图像被编码为 base64 字符串。因此,我将不得不使用我在其中一个谷歌示例中找到的一些代码对其进行解码以进行预测任务。

channels = 3
height = 96
width = 96

def decode_and_resize(image_str_tensor):
   """Decodes jpeg string, resizes it and returns a uint8 tensor."""
   image = tf.image.decode_jpeg(image_str_tensor, channels=channels)
   image = tf.expand_dims(image, 0)
   image = tf.image.resize_bilinear(
       image, [height, width], align_corners=False)
   image = tf.squeeze(image, squeeze_dims=[0])
   image = tf.cast(image, dtype=tf.uint8)
   return image

image_str_tensor = tf.placeholder(tf.string, shape=[None])
key_input = tf.placeholder(tf.string, shape=[None]) 
key_output = tf.identity(key_input)

input_tensor = tf.map_fn(
    decode_and_resize, image_str_tensor, back_prop=False, dtype=tf.uint8)
input_tensor = tf.image.convert_image_dtype(image, dtype=tf.float32)

但在这一点之后,我不再知道如何进行。我现在如何将此输入张量放入我的模型并得到正确的输出张量,以便我能够定义 SignatureDef 然后将我的图导出为 SavedModel?

任何帮助,将不胜感激。

4

2 回答 2

0

免责声明:虽然我是 Cloud ML Engine 预测服务方面的专家,并且对 TensorFlow 相当了解,但我对 Keras 不是很了解。我只是将其他地方的信息拼凑在一起,特别是这个样本这个答案。我只能想象有更好的方法来做到这一点,我希望人们会发布这样的。同时,我希望这能满足您的需求。

这个特定的答案假设您已经保存了模型。代码加载模型,然后将其导出为 SavedModel。

基本思想是开始为输入(输入占位符、图像解码、调整大小和批处理等)构建“原始”TensorFlow 模型,然后通过“重建”VGG 将其“连接”到 Keras VGG 模型模型结构,最后将保存的权重恢复到新建的模型中。然后我们将这个版本的模型保存为 SavedModel。

这里的“魔力”是原始 TF 预处理和 VGG 模型之间的联系。这是通过将 TF 预处理图(input_tensor在下面的代码中)的“输出”作为input_tensorKeras VGG 图传递的。input_tensor就像 VGG 所期望的那样,包含一批已经解码和调整大小的图像。

import keras.backend as K
import tensorflow as tf
from keras.models import load_model, Sequential
from tensorflow.python.saved_model import builder as saved_model_builder
from tensorflow.python.saved_model import tag_constants, signature_constants
from tensorflow.python.saved_model.signature_def_utils_impl import predict_signature_def

MODEL_FILE = 'model.h5'
WEIGHTS_FILE = 'weights.h5'
EXPORT_PATH = 'YOUR/EXPORT/PATH'

channels = 3
height = 96
width = 96

def build_serving_inputs():

  def decode_and_resize(image_str_tensor):
     """Decodes jpeg string, resizes it and returns a uint8 tensor."""
     image = tf.image.decode_jpeg(image_str_tensor, channels=channels)
     image = tf.expand_dims(image, 0)
     image = tf.image.resize_bilinear(
         image, [height, width], align_corners=False)
     image = tf.squeeze(image, squeeze_dims=[0])
     image = tf.cast(image, dtype=tf.uint8)
     return image

  image_str_tensor = tf.placeholder(tf.string, shape=[None])
  key_input = tf.placeholder(tf.string, shape=[None]) 
  key_output = tf.identity(key_input)

  input_tensor = tf.map_fn(
      decode_and_resize, image_str_tensor, back_prop=False, dtype=tf.uint8)
  input_tensor = tf.image.convert_image_dtype(input_tensor, dtype=tf.float32) 

  return image_str_tensor, input_tensor, key_input, key_output

# reset session
K.clear_session()

with tf.Graph().as_default() as g, tf.Session(graph=g) as sess:
  K.set_session(sess)

  image_str_tensor, input_tensor, key_input, key_output = build_serving_inputs()

  # disable loading of learning nodes
  K.set_learning_phase(0)

  # Load model and save out the weights
  model = load_model(MODEL_FILE)
  model.save_weights(WEIGHTS_FILE)

  # Rebuild the VGG16 model with the weights
  new_model = keras.applications.vgg16.VGG16(
    include_top=True, weights=WEIGHTS_FILE, input_tensor=input_tensor,
    input_shape=[width, height, channels], pooling=None)

  # export saved model
  tf.saved_model.simple_save(
      sess,
      EXPORT_PATH,
      inputs={'image_bytes': image_str_tensor, 'key': key_input},
      outputs={'predictions': new_model.outputs[0], 'key': key_output}
  )

注意我不知道这段代码是否还有效(尚未测试);我担心它如何处理批量维度。build_serving_inputs创建一个具有批量维度的张量并将其传递给 Keras。

于 2018-07-06T23:54:51.373 回答
0

TensorFlow Keras (tf.keras) 现在可以从 Keras 模型到 TF Estimator tf.keras.estimator.model_to_estimator。Estimator 会将您带到可与 Cloud ML Engine 一起使用的 SavedModel 进行预测。查看这篇文章以了解此 API 的用法。

于 2018-07-07T17:20:54.647 回答