8 votos

extracción de rasgos: congelación de la base convolucional frente al entrenamiento sobre rasgos extraídos

[ Nota : Para aclarar, esta pregunta se refiere a la teoría y los códigos sólo se utilizan para explicar mejor la cuestión. Esto no es de ninguna manera una programación pregunta].

En sección 5.3 de "Deep learning with python by François Chollet" se explica el proceso de utilización de una red preentrenada para el aprendizaje profundo en pequeños conjuntos de datos de imágenes. Se introducen dos enfoques diferentes para la extracción de características (utilizando únicamente la base convolucional de VGG16):

1. EXTRACCIÓN RÁPIDA DE CARACTERÍSTICAS SIN AUMENTO DE DATOS: en este enfoque, primero se extraen las características de cada imagen del conjunto de datos llamando al predict método de la conv_base modelo. Aquí está el código de referencia:

from keras.applications import VGG16
conv_base = VGG16(weights='imagenet',
                  include_top=False,
                  input_shape=(150, 150, 3))

import os
import numpy as np

from keras.preprocessing.image import ImageDataGenerator
base_dir = '/Users/fchollet/Downloads/cats_and_dogs_small'
train_dir = os.path.join(base_dir, 'train')
validation_dir = os.path.join(base_dir, 'validation')
test_dir = os.path.join(base_dir, 'test')

datagen = ImageDataGenerator(rescale=1./255)
batch_size = 20

def extract_features(directory, sample_count):
    features = np.zeros(shape=(sample_count, 4, 4, 512))
    labels = np.zeros(shape=(sample_count))
    generator = datagen.flow_from_directory(
        directory,
        target_size=(150, 150),
        batch_size=batch_size,
        class_mode='binary')
    i = 0
    for inputs_batch, labels_batch in generator:
        features_batch = conv_base.predict(inputs_batch)
        features[i * batch_size : (i + 1) * batch_size] = features_batch
        labels[i * batch_size : (i + 1) * batch_size] = labels_batch
        i += 1
        if i * batch_size >= sample_count:
            break

    return features, labels

train_features, train_labels = extract_features(train_dir, 2000)
validation_features, validation_labels = extract_features(validation_dir, 1000)
test_features, test_labels = extract_features(test_dir, 1000)

A continuación, estas características se alimentarán a un clasificador densamente conectado para la clasificación que se entrena desde cero:

train_features = np.reshape(train_features, (2000, 4 * 4 * 512))
validation_features = np.reshape(validation_features, (1000, 4 * 4 * 512))
test_features = np.reshape(test_features, (1000, 4 * 4 * 512))

from keras import models
from keras import layers
from keras import optimizers

model = models.Sequential()
model.add(layers.Dense(256, activation='relu', input_dim=4 * 4 * 512))
model.add(layers.Dropout(0.5))
model.add(layers.Dense(1, activation='sigmoid'))

model.compile(optimizer=optimizers.RMSprop(lr=2e-5),
              loss='binary_crossentropy',
              metrics=['acc'])

history = model.fit(train_features, train_labels,
                    epochs=30,
                    batch_size=20,
                    validation_data=(validation_features, validation_labels))

2. EXTRACCIÓN DE CARACTERÍSTICAS CON AUMENTO DE DATOS: En este enfoque (que es mucho más lento), la base convolucional se amplía añadiendo un clasificador densamente conectado sobre ella y el entrenamiento se realiza de principio a fin. Sin embargo, las capas convolucionales se congelan para evitar que sus pesos se actualicen:

from keras import models
from keras import layers

model = models.Sequential()
model.add(conv_base)
model.add(layers.Flatten())
model.add(layers.Dense(256, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))

conv_base.trainable = False

from keras.preprocessing.image import ImageDataGenerator
from keras import optimizers

train_datagen = ImageDataGenerator(
    rescale=1./255,
    rotation_range=40,
    width_shift_range=0.2,
    height_shift_range=0.2,
    shear_range=0.2,
    zoom_range=0.2,
    horizontal_flip=True,
    fill_mode='nearest')

test_datagen = ImageDataGenerator(rescale=1./255)

train_generator = train_datagen.flow_from_directory(
    train_dir,
    target_size=(150, 150),
    batch_size=20,
    class_mode='binary')

validation_generator = test_datagen.flow_from_directory(
    validation_dir,
    target_size=(150, 150),
    batch_size=20,
    class_mode='binary')

model.compile(loss='binary_crossentropy',
          optimizer=optimizers.RMSprop(lr=2e-5),
          metrics=['acc'])

history = model.fit_generator(
    train_generator,
    steps_per_epoch=100,
    epochs=30,
    validation_data=validation_generator,
    validation_steps=50)

Mis preguntas:

1) No entiendo la diferencia entre el primer y el segundo enfoque (con la excepción de utilizar el aumento de datos en el segundo enfoque y una capa adicional de abandono en el primer enfoque). Los pesos de la base convolucional en el segundo enfoque no se actualizan, por lo que sólo se utiliza en el pase hacia adelante. Por lo tanto, es esencialmente la misma que la base convolucional en el primer enfoque y los clasificadores son idénticos también, así que creo que deberían darnos la misma precisión (y velocidad). ¿Qué me falta?

2) Una de las cosas que más me inquieta es el hecho de que he probado ambos enfoques en mi máquina. El segundo enfoque es mucho más lento pero ambos alcanzan una precisión del 90% en los datos de validación; mientras que en el libro se sugiere que el primer y el segundo enfoque alcancen una precisión del 90% y del 96%, respectivamente, en los datos de validación. (Si los enfoques son diferentes) ¿Por qué ocurre esto?

3) En el libro se sugiere que en el primer enfoque no podríamos utilizar el aumento de datos. No me queda claro por qué es así. En particular, ¿qué nos impide utilizar un ImageDataGenerator en el primer enfoque como el utilizado en el segundo para generar datos de entrenamiento? (Además, aunque se afirma que el segundo enfoque utiliza el aumento de datos, lo cierto es que, teniendo en cuenta el valor de batch_size y steps_per_epoch El número de imágenes utilizadas para el entrenamiento en ambos enfoques es el mismo, es decir, 2000).

5voto

Jan Kukacka Puntos 1027

Creo que lo has entendido muy bien. Para responder a sus preguntas:

(1.) Por lo tanto, es esencialmente lo mismo que la base convolucional en el primer enfoque y los clasificadores son idénticos también, así que creo que deberían darnos la misma precisión (y velocidad). ¿Qué me falta?

Los métodos son generalmente iguales. No se pierde nada. La diferencia en la precisión se debe al aumento de los datos (véase más adelante).

El segundo método es más lento porque hay que 1) generar imágenes aumentadas sobre la marcha, 2) calcular las características convnet para cada imagen aumentada. El primer método se salta esto y sólo utiliza las características convnet precalculadas para un conjunto fijo de imágenes.

(2.) En el libro se sugiere que el primer y el segundo enfoque alcancen una precisión del 90% y del 96%, respectivamente, en los datos de validación. (Si los enfoques son diferentes) ¿Por qué ocurre esto?

El segundo método debería funcionar mejor porque utiliza el aumento de datos. El aumento de datos es algo muy potente, por lo que es de esperar que mejore la precisión en un 6%.

(3.) En el libro se sugiere que en el primer enfoque no podríamos utilizar el aumento de datos. No me queda claro por qué es así.

En teoría, se podría utilizar el aumento de datos para el primer método. En lugar de generar muestras aumentadas sobre la marcha, primero se generaría un gran número de ellas (por ejemplo, 1000 variantes de cada muestra) y se calcularían sus características convnet, que se utilizarían para entrenar el clasificador. Las desventajas de este enfoque son: 1) mayores requisitos de memoria, 2) número "limitado" de muestras aumentadas (después de cada 1000 épocas, se vuelven a utilizar las mismas muestras). Por otro lado, es más rápido que el segundo enfoque.

(3.) considerando el valor de batch_size y steps_per_epoch, el número de imágenes utilizadas para el entrenamiento en ambos enfoques es el mismo, es decir, 2000

En cada época, ambos métodos utilizan 2000 imágenes. Sin embargo, el primer método utiliza el las mismas 2000 imágenes en cada época . El segundo método utiliza diferentes, aumentada versiones de esas imágenes cada época.

3voto

Neil D Puntos 131

Para el punto (2), parece que ha habido un problema en Keras donde conv_base.trainable = False no funcionaba antes de la versión 2.1.0 (ver https://github.com/fchollet/deep-learning-with-python-notebooks/issues/21 ).

Es decir, el código estaba reentrenando inadvertidamente al menos parte de la red base en la versión de Keras que se utilizó al escribir el libro.

De hecho, si se elimina la línea:

conv_base.trainable = False

del código, obtendrá una precisión del 96%, incluso utilizando Keras 2.2.0

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X