尝试利用 Keras 的 VGG16 预训练模型时出现无效形状错误



我试图在我自己的图像分类问题中利用kera的VGG16模型。我的代码很大程度上基于Francois Chollet的示例(《Python深度学习-代码》第8章)。

我有三个类我试图预测。目录结构:

data/
training/
class_1
class_2
class_3

注意:这是我第一次使用Keras,所以我可能只是做错了什么。

呼叫model.fit()失败,呼叫ValueError: Shapes (32, 1) and (32, 3) are incompatible。有关完整的错误消息,请参阅此问题的底部。如果我查看.summary()调用的输出,我没有看到维度为(32,1)的层。

import pathlib
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
from tensorflow.keras.utils import image_dataset_from_directory
DATA_DIR = pathlib.Path('./data/')
batch_size = 32
img_width = image_height = 256
train_dataset = image_dataset_from_directory(
DATA_DIR / "training",
image_size=img_width_height,
batch_size=batch_size)
validation_dataset = image_dataset_from_directory(
DATA_DIR / "validation",
image_size=img_width_height,
batch_size=batch_size)
# Found 128400 files belonging to 3 classes.
# Found 15600 files belonging to 3 classes.
vgg16_convolution_base = keras.applications.vgg16.VGG16(
weights="imagenet",
include_top=False,
input_shape=(img_width, image_height, 3))
vgg16_convolution_base.summary()
# block3_conv3 (Conv2D)       (None, 64, 64, 256)       590080    
# block3_pool (MaxPooling2D)  (None, 32, 32, 256)       0         
# block4_conv1 (Conv2D)       (None, 32, 32, 512)       1180160   
# block4_conv2 (Conv2D)       (None, 32, 32, 512)       2359808   
# block4_conv3 (Conv2D)       (None, 32, 32, 512)       2359808   
# block4_pool (MaxPooling2D)  (None, 16, 16, 512)       0         
# block5_conv1 (Conv2D)       (None, 16, 16, 512)       2359808   
# block5_conv2 (Conv2D)       (None, 16, 16, 512)       2359808   
# block5_conv3 (Conv2D)       (None, 16, 16, 512)       2359808   
# block5_pool (MaxPooling2D)  (None, 8, 8, 512)         0
def get_features_and_labels(dataset):
all_features = []
all_labels = []
for images, labels in dataset:
preprocessed_images = keras.applications.vgg16.preprocess_input(images)
features = vgg16_convolution_base.predict(preprocessed_images)
all_features.append(features)
all_labels.append(labels)
return np.concatenate(all_features), np.concatenate(all_labels)
train_features, train_labels = get_features_and_labels(train_dataset)
val_features, val_labels = get_features_and_labels(validation_dataset)
print(train_features.shape)
print(train_labels.shape)
# (128400, 8, 8, 512)
# (128400,)
print(val_features.shape)
print(val_labels.shape)
# (15600, 8, 8, 512)
# (15600,)
inputs = keras.Input(shape=(8, 8, 512))
x = layers.Flatten()(inputs)
x = layers.Dense(256)(x)
x = layers.Dropout(0.5)(x)
outputs = layers.Dense(3, activation="softmax")(x)
model = keras.Model(inputs, outputs)
model.compile(loss="categorical_crossentropy",
optimizer="rmsprop",
metrics=["accuracy"])
model.summary()
# input_4 (InputLayer)        [(None, 8, 8, 512)]       0         
# flatten_1 (Flatten)         (None, 32768)             0         
# dense_2 (Dense)             (None, 256)               8388864   
# dropout_1 (Dropout)         (None, 256)               0         
# dense_3 (Dense)             (None, 3)                 771       
# ================================================================
# Total params: 8,389,635
# Trainable params: 8,389,635
history = model.fit(
train_features, train_labels,
epochs=20,
validation_data=(val_features, val_labels)

我呼叫model.fit()失败:ValueError: Shapes (32, 1) and (32, 3) are incompatible

...
File "C:Usersxanaconda3libsite-packageskeraslosses.py", line 1990, in categorical_crossentropy
return backend.categorical_crossentropy(
File "C:Usersxanaconda3libsite-packageskerasbackend.py", line 5529, in categorical_crossentropy
target.shape.assert_is_compatible_with(output.shape)

完整回溯

3个类别的categorical_crossentropy损失以及32个批次的大小决定了标签的形状(每个bach)为(32,3)。

标签目前是有序的:012。可以将SparseCategoricalCrossentropy损耗用于序数标签:

loss= tf.keras.losses.SparseCategoricalCrossentropy()

或者,人们仍然可以使用categorical_crossentropy损失,但与0(1, 0, 0),1(0, 1, 0)2(0, 0, 1)的单热编码标签结合使用。下面的代码片段可以完成这样的编码:

#one-hot encoding
num_class = len(set(train_labels))
train_labels=tf.one_hot(indices=train_labels, depth=num_class)
val_labels=tf.one_hot(indices=val_labels, depth=num_class)

数据的性质(有序或无序)有助于确定单热编码是首选还是有序。

最新更新