Cómo utilizar las características de cuello de botella de la red para mejorar la precisión
Utilizaremos la red vgg-16, que es un modelo que mencionamos antes, entrenado en el conjunto de datos ImageNet. Dado que el conjunto de datos de ImageNet contiene múltiples clases de "gatos" y múltiples clases de "perros", el modelo ha podido aprender características relevantes para nuestro conjunto de datos. De hecho, simplemente registrar la salida de la red original, sin utilizar las funciones subyacentes, es suficiente para resolver bien nuestro problema. Pero los métodos que discutimos aquí tienen mejor generalidad para otros problemas similares, incluido el problema de clasificar clases que no están presentes en ImageNet.
La estructura de red de VGG-16 es la siguiente:
Nuestro método consiste en utilizar la parte de la capa convolucional de la red y descartar las partes por encima de la conexión completa. Luego ejecutamos la red en los conjuntos de entrenamiento y prueba y registramos los resultados resultantes (es decir, "características de cuello de fondo", mapas de características activados por la última capa de la red antes de estar completamente conectada) en dos matrices numerosas. Luego entrenaremos una red completamente conectada en función de las funciones registradas.
La razón por la que guardamos estas funciones sin conexión, en lugar de agregar el modelo completamente conectado directamente a la red y congelar los parámetros de la capa anterior para el entrenamiento, es por eficiencia computacional. Ejecutar una red VGG es muy costoso, especialmente en una CPU, por lo que solo queremos ejecutarla una vez. Esta es también la razón por la que no realizamos aumento de datos.
No discutiremos cómo construir una red vgg-16, que ya se trata en el ejemplo de keras. Pero veamos cómo registrar las características de los cuellos de botella.
generador = datagen.flow_from_directory(
'datos/tren',
target_size=(150, 150),
batch_size= 32,
class_ mode=None, # Esto significa que nuestro generador solo generará lotes de datos, no etiquetas
shuffle=False) # Nuestros datos estarán en orden de permutación, por lo que las primeras 1000 imágenes serán de gatos, luego 1000 de perros
# El método predict_generator devolverá el resultado de un modelo, dado
# un generador, generará lotes de datos numerosos
bottleneck_features_train = model.predict_generator(generator, 2000)
# Guarde la salida como una matriz Numpy
np.save(open( 'bottleneck_features_train.npy', 'w'), Bottleneck_features_train)
generador = datagen.flow_from_directory(
'datos/validación',
target_size=(150, 150), p>
batch_size=32,
class_mode=Ninguno,
shuffle=False)
bottleneck_features_validation = model.predict_generator (generador, 800)
np.save(open('bottleneck_features_validation.npy', 'w'), Bottleneck _features_validation)
Una vez completada la grabación, podemos cargar los datos para entrenarnos Red completamente conectada :
train_data = np.load(open('bottleneck_features_train.npy'))
# Las funciones se guardan en orden, por lo que es fácil recrear las etiquetas
p>
train_labels = np.array([0] * 1000 + [1] * 1000)
validation_data = np.array([0] * 400 + [1] * 400) p>
model = Sequential()
model.add(Flatten(input_shape=train_data.shape[1:]))
model.add(Dense(256 ))
model.add(Dense(256, activación='relu'))
model.add(Abandono(0.5))
model.add (Denso (1, activación='sigmoide'))
model.compile(optimizer='rmsprop',
loss='binary_crossentropy',
métricas =[ 'precisión'])
model.fit(train_data, train_labels,
nb_epoch=50, lote_size=32,
validation_data=(validation_ data, validation_labels))
model.save_weights('bottleneck_fc_model.
Debido a que el tamaño de las características es muy pequeño, el modelo se ejecuta muy rápido en el CPU, una época tarda aproximadamente 1 segundo. Al final, nuestra precisión alcanzó el 90% ~ 91%. Estos buenos resultados se deben principalmente a la red vgg previamente entrenada que nos ayuda a extraer funciones. Código:
[python] ver copia simple
importar sistema operativo
importar h5py
importar numpy como np
desde keras.preprocessing.image import ImageDataGenerator
desde keras.models import Sequential
desde keras.layers import Convolution2D, MaxPooling2D, ZeroPadding2D
desde keras .layers import Activación, Abandono, Aplanamiento, Denso
import sys
defaultencoding = 'utf-8'
if sys.getdefaultencoding() = defaultencoding:
p>
reload(sys)
sys.setdefaultencoding(defaultencoding)
# Ruta al archivo de peso del modelo.
weights_ path = '... /weights/vgg16_weights.h5'
top_model_weights_path = 'bottleneck_fc_model.h5'
# Tamaño de la imagen.
img_width, img _height = 150, 150
train_data_dir = './data/train'
validation_data_dir = '.
nb_train_samples = 2000
nb_validation_samples = 800
nb_epoch = 50
def save_bottlebeck_features( ):
datagen = ImageDataGenerator(rescale=1./ 255)
# Construir red VGG16
model = Sequential()
model.add( ZeroPadding2D((1, 1), input_shape=(3, img_width , img_height)))
model.add(Convolution2D(64, 3, 3, activación='relu', name='conv1_1'))
model.add(ZeroPadding2D( (1, 1)))
model.add(Convolution2D(64, 3, 3, activación='relu', nombre='conv1_2'))
model.add( name='conv2_1'))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(128, 3, 3, activación='relu ', nombre='conv2_2'))
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
model.add(ZeroPadding2D( (1, 1)))
model.add(Convolution2D(256, 3, 3, activación='relu', name='conv3_1'))
model.add( ZeroPadding2D((1, 1)))
model.add(Convolution2D(256, 3, 3, activación='relu', name='conv3_2'))
modelo. add(Convolution2D(512, 3, 3, activación='relu', nombre='conv3_3')) activación='relu', nombre='conv4_1'))
modelo.
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(512, 3, 3, activación='relu', nombre='conv4_2'))
model.name='conv4_2')
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(512, 3, 3 , activación='relu', nombre='conv4_3'))
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
modelo .a
dd(ZeroPadding2D((1, 1)))
model.
model.add(Convolution2D(512, 3, 3, activación='relu', nombre='conv4_3' ))
model.add(Convolution2D(512, 3, 3 activación='relu', name='conv5_1'))
model.add(ZeroPadding2D((1, 1 )))
model.add(Convolution2D(512, 3, 3, activación='relu',name='conv5_2'))
model.name='conv5_2') )
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(512, 3, 3, activación='relu', nombre='conv5_3 '))
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
# Cargar los pesos de la red VGG16
# (Capacitado en ImageNet, ganó la competencia ILSVRC en 2014)
# Nota: cuando la definición del modelo
# y el archivo de ahorro de peso coinciden exactamente, solo necesita llamar model.load_weights (nombre de archivo)
asertar os.path.exists(weights_path), 'Pesos del modelo no encontrados (consulte la variable "weights_path" en el script).
f = h5py.File(weights_path)
for k in range(f.attrs['nb_layers']):
if k >= len( model.layers):
model.layers[k].set_weights(weights)
f.close()
print('Modelo cargado.')
generador = datagen.flow_from_directory(
train_data_dir,
target_size=(img_width, img_height),
batch_size=32, p>
p>
class_mode=Ninguno,
shuffle=False)
print('generador ok.')
bottleneck_features_train = modelo .predict_generator( generador , nb_train_samples)
print('predecir ok.')
np.save(open('bottleneck_features_train.npy', 'wb'), Bottleneck_features _train)
generador = datagen.flow_from_directory(
validation_data_dir,
target_size=(img_width, img_height),
lote_size=32,
class_mode=Ninguno,
shuffle=False)
bottleneck_features_validation = model.predict_generator(generator, nb_validation_samples)
np.save(open(' Bottleneck_features_validation.npy', 'wb'), Bottleneck_features_validation)
print(' save_bottlebeck_features ok')
def train_top_model():
train_data = np.load (open(' Bottleneck_features_train.npy'))
train_labels = np.array([0] * (nb_train_samples / 2) + [1] * (nb_train_samples / 2))
validation_data = np. load(open('bottleneck_features_ validation.npy'))
validation_labels = np.array([0] * (nb_validation_samples / 2) + [1] * (nb_validation_samples / 2))
modelo = Sequential()
model.add(Aplanar(input_shape=train_data.shape
[1:]))
model.add(Dense(256, activación='relu'))
model.add(Dropout(0.5))
model.add(Dense(1, activación='sigmoid'))
model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['accuracy'])
model.fit(train_data, train_labels,
nb_epoch=nb_epoch, lote_size=32,
validation_data=( validation_data, validation_labels))
modelo .save_weights(top_model_weights_path)
print('train_top_model ok')
save_ Bottlebeck_features()
train_top_model()