Тонкая настройка VGG16 Keras: низкая точность
Я уже задавал подобный вопрос здесь , но теперь у меня немного другая проблема, поэтому я задаю новый вопрос.
Я решил использовать несколько иной подход вместо предложенного среди ответов в упомянутом вопросе для обучения, а затем тонкой настройки модели.
Update : Я заменил старый вопрос, представленный здесь, более подходящей версией
Вот моя последовательность действий:
- построить модель VGG16 и падение сверху слой (назовем его no-top model)
- создание узких мест с использованием модели no-top
- обучить отдельную полностью связанную модель, используя узкие места
- постройте новую модель VGG16, отбросьте верхние слои и прикрепите предварительно подготовленную топ-модель
- поезда сцепляются модели на данные собаки/кошки
И вот код, который я использую для реализации вышеупомянутой последовательности действий:
import warnings
warnings.simplefilter('ignore', UserWarning)
warnings.simplefilter('ignore', DeprecationWarning)
from __future__ import print_function
from itertools import izip_longest as zip_longest
from pprint import pformat as pf
from pprint import pprint as pp
import os
from keras.preprocessing.image import ImageDataGenerator, array_to_img, img_to_array, load_img
from keras.layers import Conv2D, MaxPooling2D, MaxPooling2D, ZeroPadding2D
from keras.layers import Dropout, Flatten, Dense, InputLayer, Lambda
from keras.models import Sequential, Model, load_model
from keras.utils.data_utils import get_file
from keras.optimizers import SGD
import keras.backend as K
import numpy as np
RANDOM_STATE = 1
IMAGE_WIDTH = 224
IMAGE_HEIGHT = 224
BATCH_SIZE = 4
VGG_MEAN = np.array([123.68, 116.779, 103.939]).reshape((3, 1, 1))
VGG16_WEIGHTS_PATH = 'http://www.platform.ai/models/vgg16.h5'
DATA_ROOT = os.path.join(os.path.expanduser('~'), 'data', 'dogscats')
TRAIN_DIR = os.path.join(DATA_ROOT, 'train')
VALID_DIR = os.path.join(DATA_ROOT, 'valid')
SAMPLES_DIR = os.path.expanduser('~/dogscats_samples')
np.random.seed(RANDOM_STATE)
K.set_image_dim_ordering('th')
def get_batches(dirname, gen=ImageDataGenerator(), shuffle=True,
batch_size=BATCH_SIZE, class_mode='categorical'):
return gen.flow_from_directory(
os.path.join(SAMPLES_DIR, dirname),
target_size=(IMAGE_WIDTH, IMAGE_HEIGHT),
class_mode=class_mode,
shuffle=shuffle,
batch_size=batch_size)
def vgg_preprocess(x):
x = x - VGG_MEAN
return x[:, ::-1]
def conv_block(model, n_layers, n_filters, name='block'):
for i in range(n_layers):
model.add(ZeroPadding2D((1, 1), name='%s_padding_%s' % (name, i)))
model.add(Conv2D(n_filters, (3, 3), activation='relu', name='%s_conv2d_%s' % (name, i)))
model.add(MaxPooling2D((2, 2), strides=(2, 2), name='%s_maxpool' % name))
def fc_block(model, name='block'):
model.add(Dense(4096, activation='relu', name=name + '_dense'))
model.add(Dropout(0.5))
def build_vgg_16():
model = Sequential()
input_shape = (3, IMAGE_WIDTH, IMAGE_HEIGHT)
model.add(InputLayer(input_shape=input_shape))
model.add(Lambda(vgg_preprocess))
conv_block(model, n_layers=2, n_filters=64, name='block1')
conv_block(model, n_layers=2, n_filters=128, name='block2')
conv_block(model, n_layers=3, n_filters=256, name='block3')
conv_block(model, n_layers=3, n_filters=512, name='block4')
conv_block(model, n_layers=3, n_filters=512, name='block5')
model.add(Flatten())
fc_block(model)
fc_block(model)
model.add(Dense(1000, activation='softmax'))
return model
def train_finetuned_model():
file_path = get_file('vgg16.h5', VGG16_WEIGHTS_PATH, cache_subdir='models')
print('Building VGG16 (no-top) model to generate bottleneck features')
vgg16_notop = build_vgg_16()
vgg16_notop.load_weights(file_path)
for _ in range(6):
vgg16_notop.pop()
vgg16_notop.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['accuracy'])
train_batches = get_batches('train', shuffle=False, class_mode=None)
train_labels = np.array([0]*1000 + [1]*1000)
bottleneck_train = vgg16_notop.predict_generator(train_batches, steps=2000 // BATCH_SIZE)
valid_batches = get_batches('valid', shuffle=False, class_mode=None)
valid_labels = np.array([0]*400 + [1]*400)
bottleneck_valid = vgg16_notop.predict_generator(valid_batches, steps=800 // BATCH_SIZE)
print('Training top model on bottleneck features')
top_model = Sequential()
top_model.add(Flatten(input_shape=bottleneck_train.shape[1:]))
top_model.add(Dense(256, activation='relu'))
top_model.add(Dropout(0.5))
top_model.add(Dense(1, activation='sigmoid'))
top_model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['accuracy'])
top_model.fit(bottleneck_train, train_labels,
batch_size=32, epochs=50,
validation_data=(bottleneck_valid, valid_labels))
print('Concatenate new VGG16 (without top layer) with pretrained top model')
vgg16_fine = build_vgg_16()
vgg16_fine.load_weights(file_path)
for _ in range(6):
vgg16_fine.pop()
vgg16_fine.add(Flatten(name='top_flatten'))
vgg16_fine.add(Dense(256, activation='relu', name='top_dense'))
vgg16_fine.add(Dropout(0.5, name='top_dropout'))
vgg16_fine.add(Dense(1, activation='sigmoid', name='top_sigmoid'))
for i, layer in enumerate(reversed(top_model.layers), 1):
pretrained_weights = layer.get_weights()
vgg16_fine.layers[-i].set_weights(pretrained_weights)
for layer in vgg16_fine.layers[:26]:
layer.trainable = False
vgg16_fine.compile(optimizer=SGD(lr=1e-4, momentum=0.9),
loss='binary_crossentropy',
metrics=['accuracy'])
print('Train concatenated model on dogs/cats dataset sample')
train_datagen = ImageDataGenerator(rescale=1./255,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True)
test_datagen = ImageDataGenerator(rescale=1./255)
train_batches = get_batches('train', gen=train_datagen, class_mode='binary')
valid_batches = get_batches('valid', gen=test_datagen, class_mode='binary')
vgg16_fine.fit_generator(train_batches,
steps_per_epoch=2000 // BATCH_SIZE,
epochs=50,
validation_data=valid_batches,
validation_steps=800 // BATCH_SIZE)
return vgg16_fine
final_model = train_finetuned_model()
Но проблема в том, что точность модели резко упала. После 50 эпох, его точность-около
50%. Поэтому, вероятно, я сделал что-то не так. Возможно, что-то не так с параметрами, то есть скоростью обучения, размером пакета и т. д.?
2 ответов:
Ваши полностью Соединенные слои выглядят совершенно иначе, чем оригинальная архитектура VGG.
# yours Flatten() Dense(256, activation='relu') Dense(1, activation='sigmoid') # original Flatten() Dense(4096, activation='relu') Dense(4096, activation='relu') Dense(2, activation='softmax')Два пункта.
Последний слой должен быть 2-го класса-softmax вместо сигмовидной. То точность вычисляется не так, как вы ожидаете, если вы используете сигмовидную мышцу, я думаю.
Сложность (количество нейронов и слоев) кажется слишком низкой.
Ну, не уверен, что это правильное решение, но я смог увеличить точность по крайней мере до 70% с этим кодом (вероятно, основная причина-снижение скорости обучения и больше эпох):
def train_finetuned_model(lr=1e-5, verbose=True): file_path = get_file('vgg16.h5', VGG16_WEIGHTS_PATH, cache_subdir='models') if verbose: print('Building VGG16 (no-top) model to generate bottleneck features.') vgg16_notop = build_vgg_16() vgg16_notop.load_weights(file_path) for _ in range(6): vgg16_notop.pop() vgg16_notop.compile(optimizer=RMSprop(lr=lr), loss='categorical_crossentropy', metrics=['accuracy']) if verbose: print('Bottleneck features generation.') train_batches = get_batches('train', shuffle=False, class_mode=None, batch_size=BATCH_SIZE) train_labels = np.array([0]*1000 + [1]*1000) train_bottleneck = vgg16_notop.predict_generator(train_batches, steps=2000 // BATCH_SIZE) valid_batches = get_batches('valid', shuffle=False, class_mode=None, batch_size=BATCH_SIZE) valid_labels = np.array([0]*400 + [1]*400) valid_bottleneck = vgg16_notop.predict_generator(valid_batches, steps=800 // BATCH_SIZE) if verbose: print('Training top model on bottleneck features.') top_model = Sequential() top_model.add(Flatten(input_shape=train_bottleneck.shape[1:])) top_model.add(Dense(4096, activation='relu')) top_model.add(Dropout(0.5)) top_model.add(Dense(4096, activation='relu')) top_model.add(Dropout(0.5)) top_model.add(Dense(2, activation='softmax')) top_model.compile(optimizer=RMSprop(lr=lr), loss='categorical_crossentropy', metrics=['accuracy']) top_model.fit(train_bottleneck, to_categorical(train_labels), batch_size=32, epochs=10, validation_data=(valid_bottleneck, to_categorical(valid_labels))) if verbose: print('Concatenate new VGG16 (without top layer) with pretrained top model.') vgg16_fine = build_vgg_16() vgg16_fine.load_weights(file_path) for _ in range(6): vgg16_fine.pop() vgg16_fine.add(Flatten(name='top_flatten')) vgg16_fine.add(Dense(4096, activation='relu')) vgg16_fine.add(Dropout(0.5)) vgg16_fine.add(Dense(4096, activation='relu')) vgg16_fine.add(Dropout(0.5)) vgg16_fine.add(Dense(2, activation='softmax')) vgg16_fine.compile(optimizer=RMSprop(lr=lr), loss='categorical_crossentropy', metrics=['accuracy']) if verbose: print('Loading pre-trained weights into concatenated model') for i, layer in enumerate(reversed(top_model.layers), 1): pretrained_weights = layer.get_weights() vgg16_fine.layers[-i].set_weights(pretrained_weights) for layer in vgg16_fine.layers[:26]: layer.trainable = False if verbose: print('Layers training status:') for layer in vgg16_fine.layers: print('[%6s] %s' % ('' if layer.trainable else 'FROZEN', layer.name)) vgg16_fine.compile(optimizer=RMSprop(lr=1e-6), loss='binary_crossentropy', metrics=['accuracy']) if verbose: print('Train concatenated model on dogs/cats dataset sample.') train_datagen = ImageDataGenerator(rescale=1./255, shear_range=0.2, zoom_range=0.2, horizontal_flip=True) test_datagen = ImageDataGenerator(rescale=1./255) train_batches = get_batches('train', gen=train_datagen, class_mode='categorical', batch_size=BATCH_SIZE) valid_batches = get_batches('valid', gen=test_datagen, class_mode='categorical', batch_size=BATCH_SIZE) vgg16_fine.fit_generator(train_batches, epochs=100, steps_per_epoch=2000 // BATCH_SIZE, validation_data=valid_batches, validation_steps=800 // BATCH_SIZE) return vgg16_fineЯ предполагаю, что есть способ достичь гораздо лучших результатов с тонкой настройкой (до 98%), но я не смог достичь этого с предоставленным кодом.
Comments