Recientemente comencé a aprender machine learning y a participar en Kaggle
, la competencia para la clasificación de imágenes.
Esta vez resumiré cómo implementar vgg16 con la biblioteca python keras
2.
El conjunto de datos es el siguiente.
Solo había experimentado un conjunto de datos como MNIST
que a menudo se veían en los tutoriales de ML, así que sentí que era un conjunto de datos muy grande.
Primero te mostraré el código completo.
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()
En la mayoría de los tutoriales, podemos ver que los datos se cargan de la siguiente manera.
(X_train, y_train), (X_test, y_test) = mnist.load_data()
Sin embargo, no es posible cargar datos completos en la memoria cuando trata datos a gran escala como esta vez.
En su lugar, puede usar la función flow_from_directory
para cargar datos 1.
Esta función procesa datos de imágenes mientras expande los datos en tiempo real.
Primero necesitas crear ImageDataGenerator
.
train_datagen = ImageDataGenerator(rescale=1. / 255)
validation_datagen = ImageDataGenerator(rescale=1. / 255)
Esta clase realiza la generación por lotes de datos de imagen mientras realiza el preprocesamiento. Esta vez, simplemente reescalar. 1/255 se utiliza para normalizar el rango de valores RGB de 0-255 a 0-1.
A continuación, lea los datos.
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")
Como es una clasificación categórica, establezca class_mode
como categorical
.
En este momento, debe tener cuidado con la estructura de la carpeta. Como se muestra a continuación, debe crear una subcarpeta para cada clase que desee clasificar.
data/
train/
classA/
aaa.jpg
bbb.jpg
...
classB/
ccc.jpg
ddd.jpg
...
validation/
classA/
eee.jpg
fff.jpg
...
classB/
ggg.jpg
hhh.jpg
...
Aprenda a usar el modelo VGG16 que se puede usar con 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])
Primero, use el modelo vgg16 predeterminado. En este momento, se especifica el tamaño del conjunto de datos de entrada.
input_tensor = Input(shape=(img_width, img_height, 3))
vgg16 = VGG16(include_top=False, weights='imagenet', input_tensor=input_tensor)
Luego, adjunte su propio modelo.
Tenga en cuenta que include_top
en el argumento anterior debe establecerse en False
para fines de ajuste fino.
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))
Para ser honesto, no entiendo completamente la función relu
especificada aquí.
Por lo tanto, no creo que el contenido de este modelo sea muy útil.
A continuación, se fija el peso. Si esto no se especifica, los pesos se volverán a aprender desde el principio, pero esta vez se solucionarán.
for layer in model.layers[:15]:
layer.trainable = False
Compila el modelo. En este momento, especifique optimizador. Esto especifica qué algoritmo usar al actualizar los parámetros.
optimizer = optimizers.rmsprop(lr=5e-7, decay=5e-5)
model.compile(loss='categorical_crossentropy',
optimizer=optimizer,
metrics=['accuracy'])
Finalmente aprendiendo. Si ModelCheckpoint
se establece en devoluciones de llamada, se pueden guardar resultados intermedios. No es obligatorio.
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)
No es muy diferente del código de aprendizaje. Del mismo modo, los datos se leen con flow_from_directory
, pero el punto a tener en cuenta es que se requieren subcarpetas incluso para los datos de prueba (= clases desconocidas). Por ejemplo, en la siguiente configuración, no funcionará a menos que organice los datos en subcarpetas.
data/
test/
sub/
aaa.jpg
bbb.jpg
...
Como la clase es desconocida, establezca class_mode
como None
.
flow_from_directory
.