Keras(PIL)和TensorFlow中的图像调整大小存在不一致性?

16

我发现在以下两个功能之间存在明显的不一致性:

  1. keras.preprocessing中的图像调整功能,这些功能是 PIL 函数的包装器。
  2. TensorFlow 的 tf.image 中的图像调整功能。

我正在使用 Keras(实际上是 tf.keras)训练计算机视觉任务的深度学习模型。然后,我使用 TF Serving 提供服务,它要求我以编码字节字符串的形式发送图像到模型,这些图像会在通过模型图之前使用 tf.image.decode_png 进行解码。

问题出现在我调整图像大小时。使用双线性插值(或其他任何方法)与使用 tf.image 相比,使用 PIL 给出的结果不同,甚至因此导致模型的分类结果发生变化。

下面的代码提供了一个可重现的示例。

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调整图像大小时相同的输出结果。这很让人困扰,因为它导致了训练结果和测试结果之间的偏差。是否有人知道是什么原因导致了这种行为,或者如何解决这个问题呢?

1个回答

15

这里所描述的行为完全符合此篇文章中所写的内容:

简而言之:Python Imaging Library(PIL)、Scikit-learn、OpenCV以及其他用于图像处理的常见库具有正确的行为,而tf.image.resize则具有不同的行为,并且不会更改该行为以避免破坏旧的训练模型。

因此,您应始终在计算图之外使用相同的库对图像进行预处理。

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


1
谢谢。tf调整大小函数的文档中应该有一个大免责声明。 - sdcbr
1
我已经添加了指向 Github 帖子的链接。那里有一条来自 2018 年末的评论,表示他们正在处理这个问题 :) - sdcbr
注意:这个问题已经在tf2中得到了解决:https://github.com/tensorflow/tensorflow/issues/6720#issuecomment-550475294 - momo
@momo,很难相信这个问题已经被解决了,所以我用ImageMagick和PIL/np.array进行了测试,发现绝对像素差异仍然非常大。(TF2.3) - Ben Butterworth
https://gist.github.com/ben-xD/b20b4e318af1c763e335447ab61986ca - Ben Butterworth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接