CNN с керасом, точность не улучшается - PullRequest
0 голосов
/ 28 апреля 2018

Я недавно начал с машинного обучения, я изучаю CNN, я планировал написать приложение для определения серьезности повреждения автомобиля с помощью этого блога Keras и этого репозитория github .

Вот так выглядит автомобильный набор данных:

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')

Я пытался:

  • Увеличивая эпохи до 10, 20,50.
  • Путем увеличения изображений в наборе данных (все проверочные изображения добавлены в обучающий набор).
  • Обновив размер фильтра в слое Conv2D
  • Пытался добавить пару Conv2D слоев, MaxPooling слоев
  • Также пробовал с различными оптимизаторами, такими как adam, Sgd и т. Д.
  • Также пробовал путем обновления шага фильтра до (1,1) and (5,5) вместо (3,3)
  • Также попытался обновить изменяющиеся размеры изображения до (256, 256), (64, 64) с (150, 150)

Но не повезло, каждый раз я получаю точность до 32% или меньше, но не больше. Любая идея, что я скучаю.

Как и в github repo , мы видим, что он дает точность 72% для того же набора данных (обучение -979, проверка -171). Почему это не работает для меня.

Я попробовал его код из ссылки на github на моей машине, но он зависал во время обучения набора данных (я ждал более 8 часов), поэтому изменил подход, но пока не повезло.

Вот Pastebin , содержащий выходные данные моих тренировочных эпох.

Ответы [ 2 ]

0 голосов
/ 09 октября 2018

Незначительная коррекция:

model.add(Dense(1))

Должно быть:

model.add(Dense(3))

Должно соответствовать количеству классов в выводе.

0 голосов
/ 29 апреля 2018

Проблема вызвана несоответствием между числом выходных классов (три) и выбранным вами вариантом активации последнего слоя (сигмоид) и функции потерь (двоичная кросс-энтропия).

Сигмовидная функция «сдавливает» реальные значения до значения между [0, 1], но она предназначена только для бинарных (двухклассовых) задач. Для нескольких классов вам нужно использовать что-то вроде функции softmax. Softmax - обобщенная версия сигмоида (эти два должны быть эквивалентны, когда у вас есть два класса).

Значение потерь также необходимо обновить до уровня, который может обрабатывать несколько классов - в этом случае будет работать категориальная кросс-энтропия.

С точки зрения кода, если вы измените определение модели и код компиляции до версии ниже, она должна работать.

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('softmax'))

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

Наконец, вам нужно указать class_mode='categorical' в ваших генераторах данных. Это обеспечит форматирование выходных целей в виде категориальной матрицы из 3 столбцов, в которой в столбце будет единица, соответствующая правильному значению, и нули в других местах. Этот формат ответа необходим для функции потери categorical_cross_entropy.

...