As camadas de pool são adicionadas antes ou depois das camadas de abandono?

35

Estou criando uma rede neural convolucional (CNN), onde tenho uma camada convolucional seguida por uma camada de pool e quero aplicar a desistência para reduzir o sobreajuste. Tenho a sensação de que a camada de abandono deve ser aplicada após a camada de pool, mas na verdade não tenho nada para fazer backup. Onde é o lugar certo para adicionar a camada de abandono? Antes ou depois da camada de pool?

pir
fonte

Respostas:

18

Edit: Como o @Toke Faurby apontou corretamente, a implementação padrão no tensorflow realmente usa um dropout em elementos. O que eu descrevi anteriormente se aplica a uma variante específica de abandono nas CNNs, chamada abandono espacial :

Em uma CNN, cada neurônio produz um mapa de características. Como o abandono espacial do abandono funciona por neurônio, o abandono de um neurônio significa que o mapa de características correspondente é abandonado - por exemplo, cada posição tem o mesmo valor (geralmente 0). Portanto, cada mapa de recursos é totalmente descartado ou não é descartado.

O pool geralmente opera separadamente em cada mapa de recursos, portanto, não deve fazer diferença se você aplicar o dropout antes ou depois do pool. Pelo menos esse é o caso de operações de agrupamento, como maxpool ou média.

Editar: No entanto, se você realmente usar o dropout por elementos (o que parece estar definido como padrão para o tensorflow), isso realmente fará diferença se você aplicar o dropout antes ou depois do pool. No entanto, não há necessariamente uma maneira errada de fazê-lo. Considere a operação média de agrupamento: se você aplicar o abandono antes do agrupamento, escalará efetivamente as ativações de neurônios resultantes 1.0 - dropout_probability, mas a maioria dos neurônios será diferente de zero (em geral). Se você aplicar o abandono após o agrupamento médio, geralmente acabará com uma fração de (1.0 - dropout_probability)ativações de neurônios "não escalonados" dropout_probabilitydiferentes de zero e uma fração de zero de neurônios. Ambas me parecem viáveis, nem totalmente erradas.

Schreon
fonte
11
Não tenho certeza se essa é a maneira padrão de realizar a evasão. Por exemplo, em tf.nn.dropout, ele declara "Por padrão, cada elemento é mantido ou descartado independentemente". Você tem uma fonte de backup disso?
Toke Faurby
11
Oh! O que eu descrevi agora é chamado de desistência espacial : arxiv.org/pdf/1411.4280.pdf . Então, @TokeFaurby está certo ao duvidar da minha reivindicação. No entanto, como você também pode ler no artigo vinculado, descartar mapas de recursos inteiros da maneira de abandono espacial melhora o desempenho. Isto vem sem surpresa, como ativações adjacentes são altamente correlacionados e abandono um elemento específico realmente não deixar cair a informação transportada por esse elemento em tudo (como é muito improvável que caia um "buraco" contínua em um mapa recurso ao fazê-lo elemento a elemento). Vou editar minha resposta para refletir essa diferença.
schreon
10

Este tutorial usa o pool antes do abandono e obtém bons resultados.

Isso não significa necessariamente que a outra ordem não funcione, é claro. Minha experiência é limitada, eu só as usei em camadas densas sem pool.

Marca
fonte
5

Exemplo de convnet tipo VGG da Keras (dropout usado após o pool):

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
fonte