【问题标题】:Difference between Keras and TensorFlow Hub Version of MobileNetV2MobileNetV2 的 Keras 和 TensorFlow Hub 版本的区别
【发布时间】:2020-05-31 18:02:34
【问题描述】:

我正在研究一种迁移学习方法,当使用来自 keras.applications 的 MobileNetV2 和 TensorFlow Hub 上提供的那个时,我得到了非常不同的结果。这对我来说似乎很奇怪,因为两个版本都声称 herehere 从同一个检查点 mobilenet_v2_1.0_224 中提取它们的权重。 这就是复制差异的方法,您可以找到 Colab Notebook here

!pip install tensorflow-gpu==2.1.0
import tensorflow as tf
import numpy as np
import tensorflow_hub as hub
from tensorflow.keras.applications.mobilenet_v2 import MobileNetV2

def create_model_keras():
  image_input = tf.keras.Input(shape=(224, 224, 3))
  out = MobileNetV2(input_shape=(224, 224, 3),
                  include_top=True)(image_input)
  model = tf.keras.models.Model(inputs=image_input, outputs=out)
  model.compile(optimizer='adam', loss=["categorical_crossentropy"])
  return model

def create_model_tf():
  image_input = tf.keras.Input(shape=(224, 224 ,3))
  out = hub.KerasLayer("https://tfhub.dev/google/tf2-preview/mobilenet_v2/classification/4",
                      input_shape=(224, 224, 3))(image_input)
  model = tf.keras.models.Model(inputs=image_input, outputs=out)
  model.compile(optimizer='adam', loss=["categorical_crossentropy"])
  return model

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

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 的版本不是。另外两个版本的形状也不一样:TensorFlow Hub有1001个标签,keras.applications有1000个。

np.sum(out_keras[0]), np.sum(out_tf[0])

打印(1.0000001, -14.166359)

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

编辑 18.02.2020

正如 Szymon Maszke 指出的,TFHub 版本返回 logits。这就是为什么我向create_model_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)
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))

两者都正确预测了相同的标签,并且以下条件为真:np.allclose(out_keras, out_tf[:,1:], rtol=0.8)

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

【问题讨论】:

  • tensorflow 的版本可能返回 logits(非标准化概率)。您可以在其上应用cross entropy loss 以获得概率。完成此操作后,您可以比较两者的输出(例如,返回的概率是否合理接近)。在这种情况下,求和不会告诉你太多。
  • 为什么我需要在顶部应用损失函数?您可能是指在 0 和 1 之间进行标准化的 softmax 激活吗?如果我将此行添加到 create_model_tf, out = tf.keras.layers.Softmax()(x) 我仍然会得到非常不同的结果,但当然这次归一化为 [0,1]
  • 天哪,对不起,我的意思是softmax,我的错。返回值看起来像总和 logits。你确定这两个模型都是预训练的而不是随机初始化的吗?
  • 它们不是随机初始化的。当我像这样提取权重时:keras_weights = keras_model.layers[1].get_weights()tf_weights = tf_model.layers[1].get_weights() 层的顺序非常不同,以至于我看不到模式。但是有可能找到像np.array_equal(tf_weights[41], keras_weights[255])np.array_equal(tf_weights[53], keras_weights[205]) 这样对应的层,所以我假设它们使用相同的权重

标签: keras tensorflow-hub mobilenet


【解决方案1】:

有几个记录的差异:

  • 就像 Szymon 所说,TF Hub 版本返回 logits(在将它们转换为概率的 softmax 函数之前),这是一种常见的做法,因为可以从 logits 计算出具有更大数值稳定性的交叉熵损失.

  • TF Hub 模型假定 float32 输入在 [0,1] 范围内,这是您从 tf.image.decode_jpeg(...) 后跟 tf.image.convert_image_dtype(..., tf.float32) 得到的。 Keras 代码使用特定于模型的范围(可能是 [-1,+1])。

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

【讨论】:

  • 感谢您的回答。仍然不能将两个范围相互转换吗?我更新了我的问题以显示问题。
  • 对不起,我的言论是由错误引起的。非常感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 2020-03-16
  • 2020-06-25
  • 1970-01-01
  • 2017-10-19
  • 2020-06-07
  • 1970-01-01
  • 2017-07-10
  • 2021-03-13
相关资源
最近更新 更多