webentwicklung-frage-antwort-db.com.de

CNN mit Keras, Genauigkeit nicht zu verbessern

Ich habe vor kurzem mit Machine Learning angefangen. Ich lerne CNN. Ich plante, mit Hilfe dieses Keras-Blogs und dieses github repo eine Anwendung zur Erkennung von Car Damage-Schweregraden zu schreiben. 

So sieht der Auto-Datensatz aus:

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

Der folgende Code gibt mir nur 32% Genauigkeit.

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

Ich habe es versucht:

  • Durch Erhöhen der Epochen auf 10, 20,50.
  • Durch Erhöhen der Bilder im Datensatz (alle dem Trainingssatz hinzugefügten Validierungsbilder).
  • Durch Aktualisieren der Filtergröße in der Conv2D-Ebene
  • Es wurde versucht, ein Paar von Conv2D-Ebenen und MaxPooling-Ebenen hinzuzufügen
  • Auch mit verschiedenen Optimierern wie adam, Sgd usw. Versucht
  • Wird auch durch Aktualisieren der Filterschritte auf (1,1) and (5,5) anstelle von (3,3) versucht.
  • Versucht auch, die geänderten Bildmaße von (256, 256) auf (64, 64), (150, 150) zu aktualisieren. 

Aber kein Glück, ich bekomme jedes Mal eine Genauigkeit von bis zu 32% oder weniger, aber nicht mehr. Eine Idee, was mir fehlt.

Wie im github repo wir können sehen, ergibt es 72% Genauigkeit für denselben Datensatz (Training -979, Validation -171). Warum funktioniert es nicht für mich?.

Ich habe seinen Code über den Github-Link auf meinem Computer ausprobiert, der aber während des Trainings des Datensatzes aufgehängt hat (ich habe mehr als 8 Stunden gewartet), also den Ansatz geändert, aber bisher noch kein Glück.

Hier ist der Pastebin - Output meiner Trainingsepochen.

5
Laxmikant

Das Problem wird durch eine falsche Übereinstimmung zwischen der Anzahl der Ausgabeklassen (drei) und Ihrer Wahl der endgültigen Aktivierung der Schicht (Sigmoid) und der Verlustfunktion (binäre Kreuzentropie) verursacht.

Die Sigmoid-Funktion "zerquetscht" reale Werte in einen Wert zwischen [0, 1], ist jedoch nur für binäre Probleme (zwei Klassen) ausgelegt. Für mehrere Klassen müssen Sie etwas wie die Softmax-Funktion verwenden. Softmax ist eine verallgemeinerte Version von Sigmoid (die beiden sollten bei zwei Klassen gleichwertig sein).

Der Verlustwert muss auch so aktualisiert werden, dass er mehrere Klassen verarbeiten kann - kategoriale Kreuzentropie funktioniert in diesem Fall.

Wenn Sie die Modelldefinition und den Kompilierungscode in der unten angegebenen Version ändern, sollte dies in Bezug auf den Code funktionieren.

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

Schließlich müssen Sie in Ihren Datengeneratoren class_mode='categorical' angeben. Dadurch wird sichergestellt, dass die Ausgabeziele als kategoriale 3-Spalten-Matrix formatiert werden, die eine Eins in der Spalte enthält, die dem korrekten Wert entspricht, und an anderer Stelle Nullen aufweisen. Dieses Antwortformat wird von der categorical_cross_entropy-Verlustfunktion benötigt.

5
SymbolixAU

Kleinere Korrektur: 

model.add(Dense(1))

Sollte sein:

model.add(Dense(3))

Es muss der Anzahl der Klassen in der Ausgabe entsprechen. 

1