【问题标题】:Tensorflow Serving on pretrained Keras ResNet50 model returning always same predictionsTensorflow Serving 在预训练的 Keras ResNet50 模型上返回始终相同的预测
【发布时间】:2019-04-27 09:48:36
【问题描述】:

我正在使用以下代码将预训练的 ResNet50 keras 模型导出到 tensorflow,用于 tensorflow-serving:

import tensorflow as tf
sess = tf.Session()
from keras import backend as K
K.set_session(sess)
K.set_learning_phase(0)

# Modelo resnet con pesos entrenados en imagenet
from keras.applications.resnet50 import ResNet50
model = ResNet50(weights='imagenet')

# exportar en tensorflow
import os
version_number = max([ int(x) for x in os.listdir('./resnet-classifier') ]) + 1
export_path = './resnet-classifier/{}'.format(version_number)
with tf.keras.backend.get_session() as sess:
    init_op = tf.global_variables_initializer()
    sess.run(init_op)
    tf.saved_model.simple_save(sess, export_path,
            inputs=dict(input_image=model.input),
            outputs={t.name:t for t in model.outputs}
    )

我尝试了上述的一些变体,所有这些变体都具有相同的结果(由 tensorflow 服务提供相同的预测)。

然后我像这样运行 tensorflow-serving:

docker run -p 8501:8501 \
  -v ./resnet-classifier:/models/resnet-classifier \
  -e MODEL_NAME=resnet-classifier -e MODEL_BASE_PATH=/models \
  -t tensorflow/serving

最后,我使用以下函数对 tensorflow 服务进行预测:

def imagepath_to_tfserving_payload(img_path):
    import numpy as np
    from keras.preprocessing import image
    from keras.applications.resnet50 import preprocess_input
    img = image.img_to_array(image.load_img(img_path, target_size=(224, 224)))
    X = np.expand_dims(img, axis=0).astype('float32')
    X = preprocess_input(X)
    payload = dict(instances=X.tolist())
    payload = json.dumps(payload)
    return payload

def tfserving_predict(image_payload, url=None):
    import requests
    if url is None:
        url = 'http://localhost:8501/v1/models/resnet-classifier:predict'
    r = requests.post(url, data=image_payload)
    pred_json = json.loads(r.content.decode('utf-8'))
    from keras.applications.resnet50 import decode_predictions
    predictions = decode_predictions(np.asarray(pred_json['predictions']), top=3)[0]
    return predictions

然后我在 ipython shell 中使用上述两个函数从我存储在本地的 imagenet 的 val 集中选择随机图像。问题是 tensorflow 服务总是为我发送的所有图像返回相同的预测。

每次我使用上面的第一个脚本导出模型时,我都会得到稍微不同的类,第一类的置信度为“1”,其他类的置信度为“0”,例如:

# Serialization 1, in ./resnet-classifier/1 always returning:
[
  [
    "n07745940",
    "strawberry",
    1.0
  ],
  [
    "n02104029",
    "kuvasz",
    1.4013e-36
  ],
  [
    "n15075141",
    "toilet_tissue",
    0.0
  ]
]

# Serialization 2, in ./resnet-classifier/2 always returning:
[
  [
    "n01530575",
    "brambling",
    1.0
  ],
  [
    "n15075141",
    "toilet_tissue",
    0.0
  ],
  [
    "n02319095",
    "sea_urchin",
    0.0
  ]
]

这可能与Tensorflow : serving model return always the same prediction 有关,但我不知道那里的答案(没有接受的答案)可能会有所帮助。

有人知道上面有什么问题,以及如何解决吗?

【问题讨论】:

    标签: keras tensorflow-serving resnet


    【解决方案1】:

    我发现调用 sess.run(tf.global_variables_initializer()) 会覆盖预训练的权重,线索位于 http://zachmoshe.com/2017/11/11/use-keras-models-with-tf.html

    对我来说解决方案非常简单,只需将原始问题中的第一块代码更改为以下代码,即调用 tf.global_variables_initializer() before 模型实例化/权重加载:

    import tensorflow as tf
    sess = tf.Session()
    sess.run(tf.global_variables_initializer())
    
    from keras import backend as K
    K.set_session(sess)
    K.set_learning_phase(0)
    
    # Modelo resnet con pesos entrenados en imagenet
    from keras.applications.resnet50 import ResNet50
    model = ResNet50(weights='imagenet')
    
    # exportar en tensorflow
    import os
    versions = [ int(x) for x in os.listdir('./resnet-classifier') ]
    version_number = max(versions) + 1 if versions else 1
    export_path = './resnet-classifier/{}'.format(version_number)
    
    tf.saved_model.simple_save(sess, export_path,
            inputs=dict(input_image=model.input),
            outputs={t.name:t for t in model.outputs}
    )
    

    【讨论】:

      【解决方案2】:

      忘记标准化图像时,我有时会遇到这种问题。我认为 resnet 接受格式为介于 0. 和 1. 之间的浮点数的图像。(或者可能是 -1. 到 1.)。我不知道 preprocess_input 函数是做什么的,但你可以检查它是否以预期的格式返回数组。

      【讨论】:

      • 我也一直在考虑这个问题,但是当直接针对该 keras 模型使用 preprocess_input 时,我的工作正常。我尝试在 preprocess_input 之后、之前和之前除以 255,但没有成功:-(
      • resnet50 使用 caffe 风格的预处理,即它不会将像素重新缩放为属于 [0,1]。默认的 preprocess_input 函数应该做同样的事情。使用 resnet50 进行迁移学习或使用预训练模型进行推理时,无需重新缩放像素
      猜你喜欢
      • 2018-05-17
      • 1970-01-01
      • 2021-08-02
      • 1970-01-01
      • 2018-04-15
      • 2019-01-20
      • 1970-01-01
      • 1970-01-01
      • 2019-05-05
      相关资源
      最近更新 更多