如何使 TensorFlow Hub 模型为 TensorFlow Serving REST 请求做好准备(使用 base64 编码图像)?

Posted

技术标签:

【中文标题】如何使 TensorFlow Hub 模型为 TensorFlow Serving REST 请求做好准备(使用 base64 编码图像)?【英文标题】:How to make a TensorFlow Hub model ready for TensorFlow Serving REST requests (with base64 encoded images)? 【发布时间】:2020-01-31 05:30:16 【问题描述】:

按照以下建议,我在旧的 keras ResNet50-ImageNet-Classifier 上进行了一些手术以从 TensorFlow Serving 中获得预测,并取得了一些成功:

How to a make a model ready for TensorFlow Serving REST interface with a base64 encoded image?

保存模型(使用 tensorflow 1.14)...

from keras.applications.resnet50 import ResNet50
from keras.preprocessing import image
from keras.applications.resnet50 import preprocess_input, decode_predictions
import numpy as np
import sys

model = ResNet50(weights='imagenet')
from keras import optimizers
sgd = optimizers.SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)
model.compile(loss='mean_squared_error', optimizer=sgd)

save_here='/Users/alexryan/.keras/models/hd5/model-and-weights.hd5'
model.save(save_here)

编辑模型(使用 tensorflow 2)...

import os
import shutil
import tensorflow.compat.v1 as tf
tf.disable_v2_behavior()

h5_model_path = '/Users/alexryan/.keras/models/hd5/model-and-weights.hd5'
tf_model_path = '/Users/alexryan/.keras/models/tf'
export_path = '/Users/alexryan/.keras/models/json_b64'
version = '1'
CHANNELS = 3

estimator = tf.keras.estimator.model_to_estimator(
    keras_model_path=h5_model_path,
    model_dir=tf_model_path)

def serving_input_receiver_fn():
    def prepare_image(image_str_tensor):
        image = tf.image.decode_jpeg(image_str_tensor, channels=CHANNELS)
        # return image_preprocessing(image)
        return image

    input_ph = tf.placeholder(tf.string, shape=[None])
    images_tensor = tf.map_fn(
        prepare_image, input_ph, back_prop=False, dtype=tf.uint8)
    images_tensor = tf.image.convert_image_dtype(images_tensor, dtype=tf.float32)

    return tf.estimator.export.ServingInputReceiver(
        'input_1': images_tensor,
        'image_bytes': input_ph)

export_path = os.path.join(export_path, version)

if os.path.exists(export_path):  # clean up old exports with this version
    shutil.rmtree(export_path)

estimator.export_savedmodel(
    export_path,
    serving_input_receiver_fn=serving_input_receiver_fn)

但是,当我尝试使用相同的代码编辑从 TensorFlow Hub 获得的模型时,尝试将模型保存为 .hd5 模型时出错,这似乎是进行编辑所必需的。

classifier.save(save_here, save_format='h5') => RuntimeError: Unable to create link (name already exists)

具体来说,这段代码...

from __future__ import absolute_import, division, print_function, unicode_literals                                                                                                                                  
import tensorflow as tf
import tensorflow_hub as hub
from tensorflow.keras import layers
import numpy as np
import PIL.Image as Image
import sys

classifier_url ="https://tfhub.dev/google/tf2-preview/mobilenet_v2/classification/2" #@param type:"string"                                                            

IMAGE_SHAPE = (224, 224)

classifier = tf.keras.Sequential([
    hub.KerasLayer(classifier_url, input_shape=IMAGE_SHAPE+(3,))
])

save_here='/Users/alexryan/.keras/models/hd5-tf2/model-and-weights.hd5'
classifier.save(save_here, save_format='h5')

产生这个错误...

(tf2)  ????   >./save_model.sh 
MODEL_DIR=|/Users/alexryan/.keras/models/hd5-tf2|
/Users/alexryan/.keras/models/hd5-tf2

0 directories, 0 files
2019-10-01 12:11:10.060958: E tensorflow/core/platform/hadoop/hadoop_file_system.cc:132] HadoopFileSystem load error: dlopen(libhdfs.dylib, 6): image not found
2019-10-01 12:11:12.099867: I tensorflow/core/platform/cpu_feature_guard.cc:142] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA
2019-10-01 12:11:12.123701: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x7fefd12f07d0 initialized for platform Host (this does not guarantee that XLA will be used). Devices:
2019-10-01 12:11:12.123722: I tensorflow/compiler/xla/service/service.cc:176]   StreamExecutor device (0): Host, Default Version
Traceback (most recent call last):
  File "save_model.py", line 19, in <module>
    classifier.save(save_here, save_format='h5')
  File "/Users/alexryan/miniconda3/envs/tf2/lib/python3.7/site-packages/tensorflow_core/python/keras/engine/network.py", line 986, in save
    signatures, options)
  File "/Users/alexryan/miniconda3/envs/tf2/lib/python3.7/site-packages/tensorflow_core/python/keras/saving/save.py", line 112, in save_model
    model, filepath, overwrite, include_optimizer)
  File "/Users/alexryan/miniconda3/envs/tf2/lib/python3.7/site-packages/tensorflow_core/python/keras/saving/hdf5_format.py", line 109, in save_model_to_hdf5
    save_weights_to_hdf5_group(model_weights_group, model_layers)
  File "/Users/alexryan/miniconda3/envs/tf2/lib/python3.7/site-packages/tensorflow_core/python/keras/saving/hdf5_format.py", line 631, in save_weights_to_hdf5_group
    param_dset = g.create_dataset(name, val.shape, dtype=val.dtype)
  File "/Users/alexryan/miniconda3/envs/tf2/lib/python3.7/site-packages/h5py/_hl/group.py", line 139, in create_dataset
    self[name] = dset
  File "/Users/alexryan/miniconda3/envs/tf2/lib/python3.7/site-packages/h5py/_hl/group.py", line 373, in __setitem__
    h5o.link(obj.id, self.id, name, lcpl=lcpl, lapl=self._lapl)
  File "h5py/_objects.pyx", line 54, in h5py._objects.with_phil.wrapper
  File "h5py/_objects.pyx", line 55, in h5py._objects.with_phil.wrapper
  File "h5py/h5o.pyx", line 202, in h5py.h5o.link
RuntimeError: Unable to create link (name already exists)
MODEL_DIR=|/Users/alexryan/.keras/models/hd5-tf2|
/Users/alexryan/.keras/models/hd5-tf2
└── model-and-weights.hd5

是否有另一种方法可以直接进行相同的编辑,而无需从已保存的模型恢复为 .hd5 模型?

【问题讨论】:

【参考方案1】:

正如Github Issue 中所述,有两种方法可以解决此问题。

1.使用最新版本的Mobilenet,版本4。代码如下:

from __future__ import absolute_import, division, print_function, unicode_literals                                                                                                                                  
import tensorflow as tf
import tensorflow_hub as hub
from tensorflow.keras import layers
import numpy as np
import PIL.Image as Image
import sys

classifier_url = "https://tfhub.dev/google/tf2-preview/mobilenet_v2/classification/4"

IMAGE_SHAPE = (224, 224)

classifier = tf.keras.Sequential([
    hub.KerasLayer(classifier_url, input_shape=IMAGE_SHAPE+(3,))
])

save_here='/content/Classifier_Saved_Model.h5'
classifier.save(save_here, save_format='h5')

2.使用save_format='tf' 代替save_format='h5'。相同的代码如下所示:

from __future__ import absolute_import, division, print_function, unicode_literals                                                                                                                                  
import tensorflow as tf
import tensorflow_hub as hub
from tensorflow.keras import layers
import numpy as np
import PIL.Image as Image
import sys

classifier_url = "https://tfhub.dev/google/tf2-preview/mobilenet_v2/classification/2"

IMAGE_SHAPE = (224, 224)

classifier = tf.keras.Sequential([
    hub.KerasLayer(classifier_url, input_shape=IMAGE_SHAPE+(3,))
])

save_here='/content/Classifier_Saved_Model'
classifier.save(save_here, save_format='tf')

【讨论】:

以上是关于如何使 TensorFlow Hub 模型为 TensorFlow Serving REST 请求做好准备(使用 base64 编码图像)?的主要内容,如果未能解决你的问题,请参考以下文章