J'ai récemment commencé à apprendre le machine learning et à participer à Kaggle
, le concours de classification d'images.
Cette fois, je vais résumer comment implémenter vgg16 avec la bibliothèque keras
python 2.
L'ensemble de données est le suivant.
Je n'avais expérimenté que des ensembles de données comme MNIST
qui étaient souvent vus dans les tutoriels ML, donc je sentais que c'était un très gros ensemble de données.
Je vais d'abord vous montrer tout le code.
from keras.preprocessing.image import ImageDataGenerator
from keras import optimizers
from keras.applications.vgg16 import VGG16
from keras.layers import Dense, Dropout, Flatten, Input, BatchNormalization
from keras.models import Model, Sequential
from keras.callbacks import ModelCheckpoint
import numpy as np
train_data_dir = "/train/"
validation_data_dir = "/validation/"
train_datagen = ImageDataGenerator(rescale=1. / 255)
validation_datagen = ImageDataGenerator(rescale=1. / 255)
img_width, img_height = 200, 150
nb_train_samples = 915649
nb_validation_samples = 302091
epochs = 50
batch_size = 64
nb_category = 14951
train_generator = train_datagen.flow_from_directory(
train_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode="categorical")
validation_generator = validation_datagen.flow_from_directory(
validation_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode="categorical")
# define input_tensor
input_tensor = Input(shape=(img_width, img_height, 3))
vgg16 = VGG16(include_top=False, weights='imagenet', input_tensor=input_tensor)
top_model = Sequential()
top_model.add(Flatten(input_shape=vgg16.output_shape[1:]))
top_model.add(Dense(256, activation='relu', kernel_initializer='he_normal'))
top_model.add(BatchNormalization())
top_model.add(Dropout(0.5))
top_model.add(Dense(nb_category, activation='softmax'))
# Connect vgg16 and top_model
model = Model(inputs=vgg16.input, outputs=top_model(vgg16.output))
# Fix layers
for layer in model.layers[:15]:
layer.trainable = False
optimizer = optimizers.rmsprop(lr=5e-7, decay=5e-5)
model.compile(loss='categorical_crossentropy',
optimizer=optimizer,
metrics=['accuracy'])
checkpoint_cb = ModelCheckpoint("snapshot/{epoch:03d}-{val_acc:.5f}.hdf5", save_best_only=True)
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,
callbacks=[checkpoint_cb])
# Save the model
model.save("model.h5")
model.summary()
Dans la plupart des didacticiels, nous pouvons voir que les données sont chargées comme suit.
(X_train, y_train), (X_test, y_test) = mnist.load_data()
Cependant, il n'est pas possible de charger des données entières en mémoire lorsque vous traitez des données à grande échelle comme cette fois.
Au lieu de cela, vous pouvez utiliser la fonction flow_from_directory
pour charger les données 1.
Cette fonction traite les données d'image tout en développant les données en temps réel.
Vous devez d'abord créer ImageDataGenerator
.
train_datagen = ImageDataGenerator(rescale=1. / 255)
validation_datagen = ImageDataGenerator(rescale=1. / 255)
Cette classe effectue une génération par lots de données d'image lors du prétraitement. Cette fois, redimensionnez simplement. 1/255 est utilisé pour normaliser la plage de valeurs RVB de 0-255 à 0-1.
Ensuite, lisez les données
train_generator = train_datagen.flow_from_directory(
train_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode="categorical")
validation_generator = validation_datagen.flow_from_directory(
validation_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode="categorical")
Puisqu'il s'agit d'une classification catégorielle, définissez class_mode
comme categorical
.
À ce stade, vous devez faire attention à la structure des dossiers. Comme indiqué ci-dessous, vous devez créer un sous-dossier pour chaque classe que vous souhaitez classer.
data/
train/
classA/
aaa.jpg
bbb.jpg
...
classB/
ccc.jpg
ddd.jpg
...
validation/
classA/
eee.jpg
fff.jpg
...
classB/
ggg.jpg
hhh.jpg
...
Apprenez à utiliser le modèle VGG16 qui peut être utilisé avec Keras
.
# define input_tensor
input_tensor = Input(shape=(img_width, img_height, 3))
vgg16 = VGG16(include_top=False, weights='imagenet', input_tensor=input_tensor)
top_model = Sequential()
top_model.add(Flatten(input_shape=vgg16.output_shape[1:]))
top_model.add(Dense(256, activation='relu', kernel_initializer='he_normal'))
top_model.add(BatchNormalization())
top_model.add(Dropout(0.5))
top_model.add(Dense(nb_category, activation='softmax'))
# Connect vgg16 with top_model
model = Model(inputs=vgg16.input, outputs=top_model(vgg16.output))
# Fix layers
for layer in model.layers[:15]:
layer.trainable = False
optimizer = optimizers.rmsprop(lr=5e-7, decay=5e-5)
model.compile(loss='categorical_crossentropy',
optimizer=optimizer,
metrics=['accuracy'])
checkpoint_cb = ModelCheckpoint("snapshot/{epoch:03d}-{val_acc:.5f}.hdf5", save_best_only=True)
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,
callbacks=[checkpoint_cb])
Tout d'abord, utilisez le modèle par défaut vgg16. À ce stade, la taille de l'ensemble de données d'entrée est spécifiée.
input_tensor = Input(shape=(img_width, img_height, 3))
vgg16 = VGG16(include_top=False, weights='imagenet', input_tensor=input_tensor)
Ensuite, attachez votre propre modèle.
Notez que include_top
dans l'argument ci-dessus doit être défini sur False
à des fins de réglage fin.
top_model = Sequential()
top_model.add(Flatten(input_shape=vgg16.output_shape[1:]))
top_model.add(Dense(256, activation='relu', kernel_initializer='he_normal'))
top_model.add(BatchNormalization())
top_model.add(Dropout(0.5))
top_model.add(Dense(nb_category, activation='softmax'))
# Connect vgg16 with top_model
model = Model(inputs=vgg16.input, outputs=top_model(vgg16.output))
Pour être honnête, je ne comprends pas complètement la fonction relu
spécifiée ici.
Je ne pense donc pas que le contenu de ce modèle soit très utile.
Ensuite, le poids est fixe. Si cela n'est pas spécifié, les poids seront réappris depuis le début, mais cette fois, ils seront corrigés.
for layer in model.layers[:15]:
layer.trainable = False
Compilez le modèle. À ce stade, spécifiez l'optimiseur. Ceci spécifie l'algorithme à utiliser lors de la mise à jour des paramètres.
optimizer = optimizers.rmsprop(lr=5e-7, decay=5e-5)
model.compile(loss='categorical_crossentropy',
optimizer=optimizer,
metrics=['accuracy'])
Enfin l'apprentissage. Si ModelCheckpoint
est défini dans les rappels, les résultats intermédiaires peuvent être enregistrés. Ce n'est pas obligatoire.
checkpoint_cb = ModelCheckpoint("snapshot/{epoch:03d}-{val_acc:.5f}.hdf5", save_best_only=True)
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,
callbacks=[checkpoint_cb])
from keras.preprocessing.image import ImageDataGenerator
from keras import optimizers
from keras.applications.vgg16 import VGG16
from keras.layers import Dense, Dropout, Flatten, Input, BatchNormalization
from keras.models import Model, Sequential, load_model
import pandas as pd
import numpy as np
import os
from pandas import DataFrame
test_data_dir = "/test/"
test_datagen = ImageDataGenerator(rescale=1. / 255)
img_width, img_height = 200, 150
nb_test_samples = 115474
batch_size = 1
nb_category = 14951
test_generator = test_datagen.flow_from_directory(
test_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode=None,
shuffle=False)
model = load_model("model.h5")
pred = model.predict_generator(
test_generator,
steps=nb_test_samples,
verbose=1)
Ce n'est pas tellement différent de l'apprentissage du code. De même, les données sont lues avec flow_from_directory
, mais le point à noter est que des sous-dossiers sont nécessaires même pour les données de test (= classes inconnues). Par exemple, dans la configuration suivante, cela ne fonctionnera que si vous organisez les données dans des sous-dossiers.
data/
test/
sub/
aaa.jpg
bbb.jpg
...
Puisque la classe est inconnue, définissez class_mode
sur None
.
flow_from_directory
.