Недавно я начал изучать машинное обучение и участвовал в Kaggle
, конкурсе по классификации изображений.
На этот раз я подведу итог, как реализовать тонкую настройку vgg16 с библиотекой python keras
2.
Набор данных выглядит следующим образом.
У меня был только такой набор данных, как MNIST
который часто видели в обучающих материалах по ML, поэтому я чувствовал, что это очень большой набор данных.
Сначала я покажу вам весь код.
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()
В большинстве уроков мы видим, что данные загружаются следующим образом.
(X_train, y_train), (X_test, y_test) = mnist.load_data()
Однако невозможно загружать целые данные в память, когда вы обрабатываете такие большие данные, как в этот раз.
Вместо этого вы можете использовать функцию flow_from_directory
для загрузки данных 1.
Эта функция обрабатывает данные изображения, расширяя их в режиме реального времени.
Сначала вам нужно создать ImageDataGenerator
.
train_datagen = ImageDataGenerator(rescale=1. / 255)
validation_datagen = ImageDataGenerator(rescale=1. / 255)
Этот класс выполняет пакетную генерацию данных изображения при выполнении предварительной обработки. На этот раз просто измените масштаб. 1/255 используется для нормализации диапазона значений RGB от 0-255 до 0-1.
Далее читаем данные
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")
Поскольку это категориальная классификация, установите class_mode
как categorical
.
В это время вы должны быть осторожны со структурой папок. Как показано ниже, вы должны создать подпапку для каждого класса, который вы хотите классифицировать.
data/
train/
classA/
aaa.jpg
bbb.jpg
...
classB/
ccc.jpg
ddd.jpg
...
validation/
classA/
eee.jpg
fff.jpg
...
classB/
ggg.jpg
hhh.jpg
...
Научитесь использовать модель VGG16, которую можно использовать с 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])
Сначала используйте модель vgg16 по умолчанию. В это время указан размер входного набора данных.
input_tensor = Input(shape=(img_width, img_height, 3))
vgg16 = VGG16(include_top=False, weights='imagenet', input_tensor=input_tensor)
Затем прикрепите свою собственную модель.
Обратите внимание, что для точной настройки include_top
в приведенном выше аргументе должно быть установлено в False
.
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))
Если честно, я не совсем понимаю функцию relu
указанную здесь.
Поэтому я не думаю, что содержание этой модели очень полезно.
Далее вес фиксируется. Если это не указано, веса будут изучены заново с самого начала, но на этот раз это будет исправлено.
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'])
Наконец-то учусь. Если ModelCheckpoint
установлен в обратных ModelCheckpoint
, промежуточные результаты могут быть сохранены. Это не обязательно.
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)
Это не так сильно отличается от изучения кода. Аналогично, данные читаются с помощью flow_from_directory
, но следует отметить, что подпапки необходимы даже для тестовых данных (= классы неизвестны). Например, в следующей конфигурации он не будет работать, если вы не организуете данные в подпапках.
data/
test/
sub/
aaa.jpg
bbb.jpg
...
Поскольку класс неизвестен, установите для class_mode
None
.
flow_from_directory
.