使用 Tensorflow 预测单个图像不准确
Predicting single image using Tensorflow not being accurate
我正在尝试建立一个 CNN 模型来对图像进行分类,但是每当训练完成并且我尝试向它提供单个图像(来自训练数据集)时,它总是错误地分类该图像。
请看下面我写的代码
提前谢谢你。
首先,我为我的训练集和测试集声明了一个图像数据生成器:
train_datagen = ImageDataGenerator(rescale = 1./255, rotation_range=20, horizontal_flip = True,
validation_split=0.3)
test_datagen = ImageDataGenerator(rescale = 1./255,validation_split=0.3)
然后,我使用 flow_from_directory() 函数加载图像:
train_generator = train_datagen.flow_from_directory(
data_dir,
shuffle=False,
subset='training',
target_size = (224, 224),
class_mode = 'categorical'
)
test_generator = test_datagen.flow_from_directory(
data_dir,
shuffle=False,
subset='validation',
target_size = (224, 224),
class_mode = 'categorical'
)
然后我加载了一个预训练模型并添加了几层来构建我的模型:
pretrained_model = VGG16(weights="imagenet", include_top=False,
input_tensor=input_shape)
pretrained_model.trainable = False
model = tf.keras.Sequential([
pretrained_model,
Flatten(name="flatten"),
Dense(3, activation="softmax")
])
然后我训练了模型:
INIT_LR = 3e-4
EPOCHS = 15
opt = Adam(lr=INIT_LR)
model.compile(loss="categorical_crossentropy", optimizer='Adam', metrics=["accuracy"])
H = model.fit(
train_generator,
validation_data=test_generator,
epochs=EPOCHS,
verbose= 1)
接下来是预测单张图片的部分:
我选择了作为训练集一部分的图像,我什至过度拟合了模型以确保预测应该是正确的,但是对于我输入到模型的每张图像,它都给我错误的结果。
我尝试了以下方法:
image = image.load_img(url,target_size = (224, 224))
img = tf.keras.preprocessing.image.img_to_array(image)
img = np.array([img])
img = img.astype('float32') / 255.
img = tf.keras.applications.vgg16.preprocess_input(img)
这没用
image = cv2.imread(url)
image = cv2.normalize(image, None,beta=255, dtype=cv2.CV_32F)
image = cv2.resize(image, (224, 224))
image = np.expand_dims(image, axis=0)
这也没有用,我也尝试了许多其他方法来预测单个图像,但 none 有效。
最后,唯一的方法是我必须为这个单一图像创建一个图像数据生成器和 Flow From Directory,它起作用了,但我认为不应该这样做。
这个答案可能是一个起点:
这些是可能的差异(简短要点):
RGB
对比 BGR
(OpenCV
加载 BGR)
- 使用的插值方法(
INTER_LINEAR
vs INTER_NEAREST
)。
img_to_array()
将数据类型转换为 float32
而不是 uint8
,这是在使用 OpenCV
. 加载时默认获得的 uint8
tf.keras.applications.vgg16.preprocess_input(img)
。这个预处理函数实际上可能与你上面写的图像预处理不同;还值得注意的是,如果您在以这种特定方式 (preprocess_input()
) 训练时不对其进行预处理,那么在测试集上出现不良结果也是有道理的,因为预处理是不同的。
希望这些观察能有所启发。
代码img = tf.keras.applications.vgg16.preprocess_input(img)缩放像素
假设原始像素值在 0 到 255 范围内,图像中的值到 -1 到 +1 之间的值。在上一行代码中
img = img.astype('float32') / 255.
您重新缩放了像素。所以删除那行代码。现在要预测单个图像,您需要使用
扩展维度
img = np.expand_dims(img, axis=0)
在您的第二次代码工作中,请注意 CV2 将图像读入为 BGR。如果您的模型是在 RGB 图像上训练的,那么您的预测将是错误的。使用下面的代码将图像转换为 RGB。
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
作为旁注,您可以将 tf.keras.applications.vgg16.preprocess_input(img) 替换为下面的函数,它将在 -1 到 +1
之间缩放图像
def scalar(img):
return img/127.5 - 1
我正在尝试建立一个 CNN 模型来对图像进行分类,但是每当训练完成并且我尝试向它提供单个图像(来自训练数据集)时,它总是错误地分类该图像。
请看下面我写的代码
提前谢谢你。
首先,我为我的训练集和测试集声明了一个图像数据生成器:
train_datagen = ImageDataGenerator(rescale = 1./255, rotation_range=20, horizontal_flip = True,
validation_split=0.3)
test_datagen = ImageDataGenerator(rescale = 1./255,validation_split=0.3)
然后,我使用 flow_from_directory() 函数加载图像:
train_generator = train_datagen.flow_from_directory(
data_dir,
shuffle=False,
subset='training',
target_size = (224, 224),
class_mode = 'categorical'
)
test_generator = test_datagen.flow_from_directory(
data_dir,
shuffle=False,
subset='validation',
target_size = (224, 224),
class_mode = 'categorical'
)
然后我加载了一个预训练模型并添加了几层来构建我的模型:
pretrained_model = VGG16(weights="imagenet", include_top=False,
input_tensor=input_shape)
pretrained_model.trainable = False
model = tf.keras.Sequential([
pretrained_model,
Flatten(name="flatten"),
Dense(3, activation="softmax")
])
然后我训练了模型:
INIT_LR = 3e-4
EPOCHS = 15
opt = Adam(lr=INIT_LR)
model.compile(loss="categorical_crossentropy", optimizer='Adam', metrics=["accuracy"])
H = model.fit(
train_generator,
validation_data=test_generator,
epochs=EPOCHS,
verbose= 1)
接下来是预测单张图片的部分:
我选择了作为训练集一部分的图像,我什至过度拟合了模型以确保预测应该是正确的,但是对于我输入到模型的每张图像,它都给我错误的结果。
我尝试了以下方法:
image = image.load_img(url,target_size = (224, 224))
img = tf.keras.preprocessing.image.img_to_array(image)
img = np.array([img])
img = img.astype('float32') / 255.
img = tf.keras.applications.vgg16.preprocess_input(img)
这没用
image = cv2.imread(url)
image = cv2.normalize(image, None,beta=255, dtype=cv2.CV_32F)
image = cv2.resize(image, (224, 224))
image = np.expand_dims(image, axis=0)
这也没有用,我也尝试了许多其他方法来预测单个图像,但 none 有效。
最后,唯一的方法是我必须为这个单一图像创建一个图像数据生成器和 Flow From Directory,它起作用了,但我认为不应该这样做。
这个答案可能是一个起点:
这些是可能的差异(简短要点):
RGB
对比BGR
(OpenCV
加载 BGR)- 使用的插值方法(
INTER_LINEAR
vsINTER_NEAREST
)。 img_to_array()
将数据类型转换为float32
而不是uint8
,这是在使用OpenCV
. 加载时默认获得的 tf.keras.applications.vgg16.preprocess_input(img)
。这个预处理函数实际上可能与你上面写的图像预处理不同;还值得注意的是,如果您在以这种特定方式 (preprocess_input()
) 训练时不对其进行预处理,那么在测试集上出现不良结果也是有道理的,因为预处理是不同的。
uint8
希望这些观察能有所启发。
代码img = tf.keras.applications.vgg16.preprocess_input(img)缩放像素 假设原始像素值在 0 到 255 范围内,图像中的值到 -1 到 +1 之间的值。在上一行代码中
img = img.astype('float32') / 255.
您重新缩放了像素。所以删除那行代码。现在要预测单个图像,您需要使用
扩展维度img = np.expand_dims(img, axis=0)
在您的第二次代码工作中,请注意 CV2 将图像读入为 BGR。如果您的模型是在 RGB 图像上训练的,那么您的预测将是错误的。使用下面的代码将图像转换为 RGB。
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
作为旁注,您可以将 tf.keras.applications.vgg16.preprocess_input(img) 替换为下面的函数,它将在 -1 到 +1
之间缩放图像def scalar(img):
return img/127.5 - 1