带有keras的CNN,准确性没有提高

CNN with keras, accuracy not improving

我最近开始学习机器学习,我正在学习 CNN,我打算借助这个 Keras blog and this github repo 编写一个汽车损坏严重程度检测的应用程序。

这就是汽车数据集的样子:

F:\WORKSPACE\ML\CAR_DAMAGE_DETECTOR\DATASET\DATA3A
├───training (979 Images for all 3 categories of training set)
│   ├───01-minor
│   ├───02-moderate
│   └───03-severe
└───validation (171 Images for all 3 categories of validation set)
    ├───01-minor
    ├───02-moderate
    └───03-severe

下面的代码只给我 32% 的准确率。

from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D
from keras.layers import Activation, Dropout, Flatten, Dense
from keras import backend as K


# dimensions of our images.
img_width, img_height = 150, 150

train_data_dir = 'dataset/data3a/training'
validation_data_dir = 'dataset/data3a/validation'
nb_train_samples = 979
nb_validation_samples = 171
epochs = 10
batch_size = 16

if K.image_data_format() == 'channels_first':
    input_shape = (3, img_width, img_height)
else:
    input_shape = (img_width, img_height, 3)

model = Sequential()
model.add(Conv2D(32, (3, 3), input_shape=input_shape))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Conv2D(32, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Conv2D(64, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Flatten())
model.add(Dense(64))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(1))
model.add(Activation('sigmoid'))

model.compile(loss='binary_crossentropy',
              optimizer='rmsprop',
              metrics=['accuracy'])

# this is the augmentation configuration we will use for training
train_datagen = ImageDataGenerator(
    rescale=1. / 255,
    shear_range=0.2,
    zoom_range=0.2,
    horizontal_flip=True)

# this is the augmentation configuration we will use for testing:
# only rescaling
test_datagen = ImageDataGenerator(rescale=1. / 255)

train_generator = train_datagen.flow_from_directory(
    train_data_dir,
    target_size=(img_width, img_height),
    batch_size=batch_size,
    class_mode='binary')

validation_generator = test_datagen.flow_from_directory(
    validation_data_dir,
    target_size=(img_width, img_height),
    batch_size=batch_size,
    class_mode='binary')
model.fit_generator(
    train_generator,
    steps_per_epoch=nb_train_samples // batch_size,
    epochs=epochs,
    validation_data=validation_generator,
    validation_steps=nb_validation_samples // batch_size)

model.save_weights('first_try.h5')

我试过了:

但运气不佳,每次我的准确率都达到 32% 或更低,但不会更高。 知道我错过了什么。

正如我们在 github repo 中看到的那样,它为同一数据集提供了 72% 的准确率(训练 -979,验证 -171)。为什么它对我不起作用。

我在我的机器上试了githublink的他的代码,但是在训练数据集的时候挂了(我等了8个多小时),所以换了方法,还是不行到目前为止运气。

这是 Pastebin 包含我训练时期的输出。

这个问题是由于输出的数量 classes(三)与你选择的最终层激活(sigmoid)和损失函数(二元交叉熵)之间的不匹配引起的。

sigmoid 函数 'squashes' 将实数值转换为 [0, 1] 之间的值,但它专为二进制(两个 class)问题而设计。对于多个 classes 你需要使用类似 softmax 函数的东西。 Softmax 是 sigmoid 的广义版本(当你有两个 classes 时,两者应该是等价的)。

损失值也需要更新为可以处理多个 classes - 分类交叉熵将在这种情况下起作用。

在代码方面,修改模型定义和编译代码到以下版本应该可以。

model = Sequential()
model.add(Conv2D(32, (3, 3), input_shape=input_shape))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Conv2D(32, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Conv2D(64, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Flatten())
model.add(Dense(64))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(3))
model.add(Activation('softmax'))

model.compile(loss='categorical_crossentropy',
              optimizer='rmsprop',
              metrics=['accuracy'])

最后,您需要在数据生成器中指定 class_mode='categorical'。这将确保输出目标被格式化为分类 3 列矩阵,该矩阵在对应于正确值的列中有一个 1,而在其他地方为零。 categorical_cross_entropy 损失函数需要这种响应格式。

小更正:

model.add(Dense(1))

应该是:

model.add(Dense(3))

它必须符合输出中 类 的数量。