我对以下之间明显的不一致感到困扰:
- 图像调整大小功能来自
keras.preprocessing
,它们是 PIL 函数的包装器
- TensorFlow 中的图像大小调整函数
tf.image
.
我正在使用 Keras 为计算机视觉任务训练深度学习模型(实际上,使用tf.keras
,但这在这里并不重要)。然后,我使用 TF Serving 为模型提供服务,这要求我将图像作为编码的字节字符串发送到模型,并使用它们进行解码tf.image.decode_png
在查看模型图之前。
当我调整图像大小时会出现问题。与使用双线性插值(或任何其他方法)调整大小相比,PIL 给出了不同的结果tf.image
,以至于模型的分类根据我使用的函数而变化。
下面的代码提供了一个可重现的示例。
import numpy as np
from PIL import Image
from keras.preprocessing.image import load_img, img_to_array
import tensorflow as tf
# Generate an 'image' with numpy, save as png
np.random.seed(42)
image = np.random.randint(0, 255, size=(256, 256, 3)).astype(np.uint8)
Image.fromarray(image).convert("RGB").save('my_image.png')
现在,让我们通过两种方式加载图像。首先使用 Keras 的 PIL 包装器(如在模型训练期间),然后编码为二进制字符串并使用 TensorFlow 函数进行解码(如在我的模型服务器中)。
# Using Keras PIL wrappers
keras_image = img_to_array(load_img('./my_image.png'))
# Using TF functionalities
with tf.Session() as sess:
with open('./my_image.png', 'rb') as f:
tf_image_ = tf.image.decode_png(f.read())
tf_image = sess.run(tf_image_)
到目前为止一切都很好,因为两个图像完全相同(除了 dtype,因为 Keras 已将图像转换为 float32):
# Assert equality
np.array_equal(keras_image, tf_image)
> True
然而,重复此代码并调整大小会产生不同的结果:
# Using Keras PIL wrappers, with resizing
keras_image_rs = img_to_array(load_img('./my_image.png',
target_size=(224, 224),
interpolation='bilinear'))
# Using TF functionalities, with resizing
with tf.Session() as sess:
with open('./my_image.png', 'rb') as f:
tf_image_ = tf.image.decode_png(f.read())
# Add and remove dimension
# As tf.image.resize_* requires a batch dimension
tf_image_ = tf.expand_dims(tf_image_, 0)
tf_image_ = tf.image.resize_bilinear(tf_image_,
[224, 224],
align_corners=True)
tf_image_ = tf.squeeze(tf_image_, axis=[0])
tf_image_rs = sess.run(tf_image_)
# Assert equality
np.array_equal(keras_image_rs, tf_image_rs)
> False
两个图像之间的平均绝对差异是不可忽略的:
np.mean(np.abs(keras_image_rs - tf_image_rs))
7.982703
我玩的是align_corners
论点,并尝试了其他可用的插值方法。没有一个提供与使用 PIL 调整图像大小时相同的输出。这很烦人,因为它让我在训练和测试结果之间产生偏差。有谁知道导致这种行为的原因或如何解决它?