用于预训练Keras ResNet50模型的Tensorflow始终返回相同的预测

用于预训练Keras ResNet50模型的Tensorflow始终返回相同的预测,keras,tensorflow-serving,resnet,Keras,Tensorflow Serving,Resnet,我使用以下代码将预先培训过的ResNet50 keras模型导出到tensorflow,用于tensorflow服务: 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.applicatio

我使用以下代码将预先培训过的ResNet50 keras模型导出到tensorflow,用于tensorflow服务:

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服务,如下所示:

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集合中选择随机Imagene,我在本地存储了该集合。问题是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
  ]
]
这可能与,但我不知道那里的答案(没有被接受的答案)会有什么帮助


有人知道上面的错误是什么,以及如何修复它吗?

当我忘记对图像进行标准化时,有时会遇到这种问题。我认为resnet接受0到0之间的浮点数格式的图像。和1。(或者可能是-1到1。)。我不知道preprocess\u input函数的作用,但您可以检查它是否以预期格式返回数组。

我发现调用sess.run(tf.global\u variables\u initializer())会覆盖预先训练的权重,这一线索可在中找到

我的解决方案非常简单,只需通过以下方式更改原始问题中的第一块代码,即在模型实例化/权重加载之前调用tf.global_variables_initializer():

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}
)

我也一直在考虑这一点,但在对keras模型直接使用预处理输入时,我工作正常。我曾尝试在输入后、输入前和预处理前除以255,但没有成功:-(resnet50使用caffe风格的预处理,即不重新缩放像素以属于[0,1]。默认的预处理输入函数也应该这样做。使用resnet50进行转移学习或使用预训练模型进行推理时,无需重新缩放像素