我正在尝试来自
this
keras
文档页面 的一些示例 keras
代码
下面代码中
preprocess_input(x)
模块的keras
函数是做什么的?为什么我们必须在传递给 expand_dims(x, axis=0)
方法之前先执行 preprocess_input()
操作?
from keras.applications.resnet50 import ResNet50
from keras.preprocessing import image
from keras.applications.resnet50 import preprocess_input
import numpy as np
model = ResNet50(weights='imagenet')
img_path = 'elephant.jpg'
img = image.load_img(img_path, target_size=(224, 224))
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
x = preprocess_input(x)
有没有对这些功能有很好解释的文档?
谢谢!
Keras 处理批量图像。因此,第一个维度用于您拥有的样本(或图像)的数量。
当您加载单张图像时,您会得到一张图像的形状,即
(size1,size2,channels)
。
为了创建一批图像,您需要一个额外的维度:
(samples, size1,size2,channels)
preprocess_input
功能旨在使您的图像符合模型所需的格式。
某些模型使用值范围为 0 到 1 的图像。其他模型使用值范围为 -1 到 +1。其他人使用“caffe”风格,它不是标准化的,而是居中的。
从源代码来看,Resnet使用的是caffe风格。
您无需担心
preprocess_input
的内部细节。但理想情况下,您应该使用 keras 函数加载图像(这样您就可以保证加载的图像与 preprocess_input
兼容)。
这会加载图像并将图像大小调整为 (224, 224):
img = image.load_img(img_path, target_size=(224, 224))
img_to_array() 函数添加通道:
x.shape = (224, 224, 3)
用于 RGB 和 (224, 224, 1)
用于灰度图像
x = image.img_to_array(img)
expand_dims()
用于添加图像数量:x.shape = (1, 224, 224, 3)
:
x = np.expand_dims(x, axis=0)
preprocess_input 减去 imagenet 数据集的平均 RGB 通道。这是因为您使用的模型已经在不同的数据集上进行了训练:
x.shape
仍然是(1, 224, 224, 3)
x = preprocess_input(x)
如果将
x
添加到数组 images
,则在循环末尾,您需要添加 images = np.vstack(images)
,以便获得 (n, 224, 224, 3)
作为图像的暗度,其中 n
是处理的图像数量
我发现预处理你的数据,而你的数据集与预先训练的模型/数据集有太大不同,那么它可能会以某种方式损害你的准确性。如果您进行迁移学习并冻结预训练模型/其权重中的某些层,只需 /255.0 您的原始数据集就可以很好地完成工作,至少对于大型 1/2 百万样本食品数据集而言。理想情况下,您应该知道数据集的标准差/均值并使用它,而不是使用预训练模型预处理的标准差/mdean。
正如您所见,tensorflow/python/keras/_impl/keras/applications/imagenet_utils.py torch 预处理的主要目的是根据之前使用的数据集训练网络来标准化颜色通道。就像我们简单地做的那样(数据 - 平均值)/标准
源代码:
def _preprocess_numpy_input(x, data_format, mode):
"""Preprocesses a Numpy array encoding a batch of images.
Arguments:
x: Input array, 3D or 4D.
data_format: Data format of the image array.
mode: One of "caffe", "tf" or "torch".
- caffe: will convert the images from RGB to BGR,
then will zero-center each color channel with
respect to the ImageNet dataset,
without scaling.
- tf: will scale pixels between -1 and 1,
sample-wise.
- torch: will scale pixels between 0 and 1 and then
will normalize each channel with respect to the
ImageNet dataset.
Returns:
Preprocessed Numpy array.
"""
if mode == 'tf':
x /= 127.5
x -= 1.
return x
if mode == 'torch':
x /= 255.
mean = [0.485, 0.456, 0.406]
std = [0.229, 0.224, 0.225]
else:
if data_format == 'channels_first':
# 'RGB'->'BGR'
if x.ndim == 3:
x = x[::-1, ...]
else:
x = x[:, ::-1, ...]
else:
# 'RGB'->'BGR'
x = x[..., ::-1]
mean = [103.939, 116.779, 123.68]
std = None
# Zero-center by mean pixel
if data_format == 'channels_first':
if x.ndim == 3:
x[0, :, :] -= mean[0]
x[1, :, :] -= mean[1]
x[2, :, :] -= mean[2]
if std is not None:
x[0, :, :] /= std[0]
x[1, :, :] /= std[1]
x[2, :, :] /= std[2]
else:
x[:, 0, :, :] -= mean[0]
x[:, 1, :, :] -= mean[1]
x[:, 2, :, :] -= mean[2]
if std is not None:
x[:, 0, :, :] /= std[0]
x[:, 1, :, :] /= std[1]
x[:, 2, :, :] /= std[2]
else:
x[..., 0] -= mean[0]
x[..., 1] -= mean[1]
x[..., 2] -= mean[2]
if std is not None:
x[..., 0] /= std[0]
x[..., 1] /= std[1]
x[..., 2] /= std[2]
return x