使用Keras(PIL)和TensorFlow调整图像大小之间的不一致性?

sdc*_*cbr 12 python python-imaging-library deep-learning keras tensorflow

我被以下两者之间的明显不一致所困扰:

  1. 图像调整大小的功能keras.preprocessing,它们是PIL函数的包装器
  2. 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')
Run Code Online (Sandbox Code Playgroud)

现在,让我们以两种方式加载图像.首先从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_)
Run Code Online (Sandbox Code Playgroud)

到目前为止一切都那么好,因为两个图像完全相同(除了dtype,因为Keras将图像转换为float32):

# Assert equality
np.array_equal(keras_image, tf_image)
> True
Run Code Online (Sandbox Code Playgroud)

但是,通过调整大小重复此代码会产生不同的结果:

# 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
Run Code Online (Sandbox Code Playgroud)

两幅图像之间的平均绝对差异是不可忽略的:

np.mean(np.abs(keras_image_rs - tf_image_rs))
7.982703
Run Code Online (Sandbox Code Playgroud)

我玩了这个align_corners参数,并尝试了其他可用的插值方法.无提供与使用PIL调整图像大小时相同的输出.这非常令人讨厌,因为它让我在训练和测试结果之间产生了偏差.有没有人知道导致这种行为的原因,或者如何解决这个问题?

nes*_*uno 9

所描述的行为完全符合本文所写的内容:Tensorflow的tf.image.resize如何偷走了我生命中的60天

简而言之:是的,PIL/sklearn/OpenCV和其他用于图像处理的公共库具有正确的行为,而tf.image.resize具有不同的行为,为了不破坏旧的训练模型而不会改变.

因此,您应始终使用计算图外部的相同库预处理图像.

链接到相关的github线程:https://github.com/tensorflow/tensorflow/issues/6720