¿Se agregan capas de agrupación antes o después de las capas de abandono?

35

Estoy creando una red neuronal convolucional (CNN), donde tengo una capa convolucional seguida de una capa de agrupación y quiero aplicar el abandono para reducir el sobreajuste. Tengo la sensación de que la capa de abandono debe aplicarse después de la capa de agrupación, pero realmente no tengo nada que respalde eso. ¿Dónde está el lugar correcto para agregar la capa de abandono? ¿Antes o después de la capa de agrupación?

pir
fuente

Respuestas:

18

Editar: como señaló correctamente @Toke Faurby, la implementación predeterminada en tensorflow en realidad usa un abandono por elementos. Lo que describí anteriormente se aplica a una variante específica de deserción en CNN, llamada deserción espacial :

En una CNN, cada neurona produce un mapa de características. Dado que el abandono espacial de abandono funciona por neurona, eliminar una neurona significa que el mapa de características correspondiente se elimina, por ejemplo, cada posición tiene el mismo valor (generalmente 0). Por lo tanto, cada mapa de características se descarta por completo o no se descarta en absoluto.

La agrupación generalmente opera por separado en cada mapa de características, por lo que no debería haber ninguna diferencia si aplica el abandono antes o después de la agrupación. Al menos este es el caso de las operaciones de agrupación como maxpooling o promediación.

Editar: Sin embargo, si realmente usa el abandono por elementos (que parece estar configurado como predeterminado para el flujo de tensor), en realidad hace una diferencia si aplica el abandono antes o después de la agrupación. Sin embargo, no necesariamente hay una forma incorrecta de hacerlo. Considere la operación de agrupación promedio: si aplica el abandono antes de la agrupación, escale efectivamente las activaciones de neuronas resultantes 1.0 - dropout_probability, pero la mayoría de las neuronas serán distintas de cero (en general). Si aplica el abandono después de la agrupación promedio, generalmente termina con una fracción de (1.0 - dropout_probability)activaciones de neuronas "sin escala" distintas de cero y una fracción de dropout_probabilityneuronas cero. Ambos me parecen viables, ninguno de los dos está completamente equivocado.

Schreon
fuente
1
No estoy seguro de que esta sea la forma estándar de realizar el abandono. Por ejemplo, en tf.nn.dropout dice "Por defecto, cada elemento se mantiene o se elimina de forma independiente". ¿Tiene una fuente que respalde esto?
Toke Faurby
1
Oh! Lo que describí ahora se llama abandono espacial : arxiv.org/pdf/1411.4280.pdf . Entonces @TokeFaurby tiene razón al dudar de mi reclamo. Sin embargo, como también puede leer en el documento vinculado, al soltar mapas de funciones completas de manera espacial , se mejora el rendimiento. Esto viene a ninguna sorpresa, ya que las activaciones adyacentes están altamente correlacionados y la deserción de un elemento específico en realidad no soltar la información transportada por ese elemento en absoluto (ya que es muy poco probable que soltar un "agujero" continua en un mapa de características al hacerlo elemento sabio). Editaré mi respuesta para reflejar esta diferencia.
schreon
10

Este tutorial utiliza la agrupación antes del abandono y obtiene buenos resultados.

Eso no significa necesariamente que el otro orden no funcione, por supuesto. Mi experiencia es limitada, solo los he usado en capas densas sin agrupar.

marca
fuente
5

Ejemplo de un convnet similar a VGG de Keras (abandono utilizado después de la agrupación):

import numpy as np
import keras
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras.optimizers import SGD

# Generate dummy data
x_train = np.random.random((100, 100, 100, 3))
y_train = keras.utils.to_categorical(np.random.randint(10, size=(100, 1)), num_classes=10)
x_test = np.random.random((20, 100, 100, 3))
y_test = keras.utils.to_categorical(np.random.randint(10, size=(20, 1)), num_classes=10)

model = Sequential()
# input: 100x100 images with 3 channels -> (100, 100, 3) tensors.
# this applies 32 convolution filters of size 3x3 each.
model.add(Conv2D(32, (3, 3), activation='relu', input_shape=(100, 100, 3)))
model.add(Conv2D(32, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))

model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))

model.add(Flatten())
model.add(Dense(256, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(10, activation='softmax'))

sgd = SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)
model.compile(loss='categorical_crossentropy', optimizer=sgd)

model.fit(x_train, y_train, batch_size=32, epochs=10)
score = model.evaluate(x_test, y_test, batch_size=32)
mrgloom
fuente