【问题标题】:Export a custom Keras model to be used for prediction with the Cloud ML Engine导出自定义 Keras 模型以用于使用 Cloud ML Engine 进行预测
【发布时间】:2018-07-06 21:50:20
【问题描述】:

我在导出使用 Keras 训练的自定义 VGG-Net(不完全是来自 Keras 的 VGG-Net)时遇到困难,因此它可以用于 Google Cloud Predict API。我正在使用 Keras 加载我的模型。

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

model = load_model(model.h5)

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

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?

任何帮助将不胜感激。

【问题讨论】:

    标签: tensorflow keras google-cloud-ml google-prediction


    【解决方案1】:

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

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

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

    这里的“魔力”是原始 TF 预处理和 VGG 模型之间的联系。这是通过将 TF 预处理图的“输出”(下面代码中的input_tensor)作为input_tensor 传递给 Keras 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。

    【讨论】:

    • 感谢您的帮助。不幸的是,我在加载 MODEL_FILE 的行中遇到错误。但是,当我不运行 build_serving_inputs() 函数时,加载模型是有效的。这是我收到的错误消息ValueError: Tensor("block1_conv1/kernel:0", shape=(3, 3, 3, 64), dtype=float32_ref) must be from the same graph as Tensor("convert_image:0", shape=(?, 96, 96, 3), dtype=float32).
    • 看来我们需要在同一个图中强制构建 VGG16。我已经稍微更新了代码。 LMK 进展如何。
    • 太棒了,它似乎终于可以工作了!您能否更详细地解释一下,为什么在 VGG 模型实例化中设置 input_tensor 有效?仅从 keras 文档来看,这对我来说没有意义。
    • 我在上面的文字中给了它第一个刺。
    【解决方案2】:

    TensorFlow Keras (tf.keras) 现在可以从 Keras 模型转到 TF Estimator tf.keras.estimator.model_to_estimator。 Estimator 将带您进入可与 Cloud ML Engine 一起使用的 SavedModel 进行预测。查看此post 以了解此 API 的使用情况。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-18
      • 2018-05-03
      • 2019-01-19
      • 1970-01-01
      • 2018-07-24
      • 2018-10-03
      • 1970-01-01
      • 2018-01-30
      相关资源
      最近更新 更多