J'ai récemment commencé avec Machine Learning, j'apprends CNN, je prévoyais d'écrire une application pour la détection de la gravité des dommages sur la voiture, à l'aide de ce blog Keras et de ce github repo .
Voici à quoi ressemble le jeu de données voiture:
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
Le code suivant ne me donne que 32% de précision.
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')
J'ai essayé:
Conv2D
Conv2D
, MaxPooling
adam
, Sgd
, etc.(1,1) and (5,5)
au lieu de (3,3)
(256, 256)
, (64, 64)
à partir de (150, 150)
Mais pas de chance, chaque fois que j'obtiens une précision de 32% ou moins, mais pas plus… .. Toute idée de ce qui me manque.
Comme dans le github repo que nous pouvons voir, cela donne une précision de 72% pour le même jeu de données (Training -979, Validation -171). Pourquoi ça ne marche pas pour moi.
J'ai essayé son code à partir du lien github sur ma machine, mais celui-ci s'est accroché pendant l'entraînement du jeu de données (j'ai attendu plus de 8 heures), donc j'ai changé d'approche, mais toujours pas de chance jusqu'à présent.
Voici la sortie contenant Pastebin de mes époques d’entraînement.
Le problème est dû à une mauvaise correspondance entre le nombre de classes de sortie (trois) et le choix de l'activation de la couche finale (sigmoïde) et de la fonction de perte (entropie croisée binaire).
La fonction sigmoïde "écrase" les valeurs réelles dans une valeur comprise entre [0, 1], mais elle est conçue uniquement pour les problèmes binaires (à deux classes). Pour plusieurs classes, vous devez utiliser quelque chose comme la fonction softmax. Softmax est une version généralisée de sigmoid (les deux devraient être équivalents lorsque vous avez deux classes).
La valeur de perte doit également être mise à jour pour prendre en charge une classe pouvant gérer plusieurs classes - l'entropie croisée catégorique fonctionnera dans ce cas.
En termes de code, si vous modifiez la définition du modèle et le code de compilation à la version ci-dessous, cela devrait fonctionner.
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'])
Enfin, vous devez spécifier class_mode='categorical'
dans vos générateurs de données. Cela garantira que les cibles de sortie sont formatées en tant que matrice catégorielle à trois colonnes, avec un dans la colonne correspondant à la valeur correcte et des zéros ailleurs. Ce format de réponse est requis par la fonction de perte categorical_cross_entropy
.
Correction mineure:
model.add(Dense(1))
Devrait être:
model.add(Dense(3))
Il doit être conforme au nombre de classes dans la sortie.