我试图在我自己的图像分类问题中利用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)。
标签目前是有序的:0
、1
和2
。可以将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)
数据的性质(有序或无序)有助于确定单热编码是首选还是有序。