Keras和TensorFlow Hub版本MobileNetV2之间的差异

Keras和TensorFlow Hub版本MobileNetV2之间的差异,keras,tensorflow-hub,mobilenet,Keras,Tensorflow Hub,Mobilenet,我正在研究一种迁移学习方法,使用keras.applications中的MobileNet V2和TensorFlow Hub上的MobileNet V2时得到了非常不同的结果。这对我来说似乎很奇怪,因为两个版本都声称从同一个检查点提取它们的权重。 这就是如何再现差异,您可以找到Colab笔记本: 当我尝试对随机批次进行预测时,结果并不相同: keras_model = create_model_keras() tf_model = create_model_tf() np.random.see

我正在研究一种迁移学习方法,使用keras.applications中的MobileNet V2和TensorFlow Hub上的MobileNet V2时得到了非常不同的结果。这对我来说似乎很奇怪,因为两个版本都声称从同一个检查点提取它们的权重。 这就是如何再现差异,您可以找到Colab笔记本:

当我尝试对随机批次进行预测时,结果并不相同:

keras_model = create_model_keras()
tf_model = create_model_tf()
np.random.seed(42)
data = np.random.rand(32,224,224,3)
out_keras = keras_model.predict_on_batch(data)
out_tf = tf_model.predict_on_batch(data)
np.array_equal(out_keras, out_tf)
来自
keras.applications
的版本输出总计为1,但来自TensorFlow Hub的版本不为1。两个版本的形状也不同:TensorFlow Hub有1001个标签,
keras。应用程序有1000个标签

np.sum(out_keras[0]), np.sum(out_tf[0])
打印
(1.0000001,-14.166359)

这些差异的原因是什么?我错过什么了吗

编辑18.02.2020

正如Szymon Maszke指出的,TFHub版本返回logits。这就是为什么我在
create\u model\u tf
中添加了一个Softmax层,如下所示:
out=tf.keras.layers.Softmax()(x)

arnoegw提到TfHub版本需要将图像规格化为[0,1],而keras版本需要将图像规格化为[-1,1]。当我对测试图像使用以下预处理时:

from tensorflow.keras.applications.mobilenet_v2 import preprocess_input
img = tf.keras.preprocessing.image.load_img("/content/panda.jpeg", target_size=(224,224))
img = tf.keras.preprocessing.image.img_to_array(img)
img = preprocess_input(img)
两者都能正确预测相同的标签,且以下条件为真:
np.allclose(out\u keras,out\u tf[:,1:],rtol=0.8)

编辑2 18.02.2020
在我写之前,不可能将格式相互转换。这是由一个bug引起的。

有几个记录在案的差异:

  • 正如Szymon所说,TF Hub版本返回logits(在将它们转换为概率的softmax函数之前),这是一种常见的做法,因为交叉熵损失可以通过logits以更高的数值稳定性进行计算

  • TF集线器模型假定float32输入在[0,1]范围内,这是从
    TF.image.decode\u jpeg(…)
    中获得的,然后是
    TF.image.convert\u image\u dtype(…,TF.float32)
    。Keras代码使用特定于型号的范围(可能为[-1,+1])

  • TF Hub模型在返回其所有1001输出类时更完整地反映了原始的SLIM检查点。如文档链接的ImageNetLabels.txt中所述,添加的类0是“背景”(又名“stuff”)。这就是对象检测用来指示图像背景,而不是任何已知类别的对象


tensorflow
的版本可能返回
logits
(非规范化概率)。您可以在其上应用
交叉熵
损失来获得概率。完成此操作后,您可以比较两者的输出(例如,返回的概率是否合理地彼此接近)。在这种情况下,求和不会告诉你太多。为什么我需要在顶部应用损失函数?你的意思是在0和1之间正常化的softmax激活吗?如果我将这一行添加到
create\u model\u tf
out=tf.keras.layers.Softmax()(x)
中,我仍然会得到非常不同的结果,但这次标准化为[0,1]哦,天哪,对不起,我的意思是
Softmax
,我的错。返回值类似于汇总的logit。您确定这两个模型都已预训练且未随机初始化吗?它们未随机初始化。当我像这样提取权重时:
keras\u weights=keras\u model.layers[1]。get\u weights()
tf\u weights=tf\u model.layers[1]。get\u weights()
层的顺序非常不同,以至于我看不到模式。但是可以找到像
np.array_equal(tf_权重[41],keras_权重[255])
np.array_equal(tf_权重[53],keras_权重[205])
这样对应的层,所以我假设它们使用相同的权重作为答案。还是不可能将这两个范围相互转换吗?我更新了我的问题以显示问题。很抱歉,我的评论是由错误引起的。非常感谢你的帮助。
from tensorflow.keras.applications.mobilenet_v2 import preprocess_input
img = tf.keras.preprocessing.image.load_img("/content/panda.jpeg", target_size=(224,224))
img = tf.keras.preprocessing.image.img_to_array(img)
img = preprocess_input(img)
img = tf.io.read_file("/content/panda.jpeg")
img = tf.image.decode_jpeg(img)
img = tf.image.convert_image_dtype(img, tf.float32)
img = tf.image.resize(img, (224,224))