Czy warstwy puli są dodawane przed czy po warstwach usuwanych?

35

Tworzę splotową sieć neuronową (CNN), w której mam warstwę splotową, a następnie warstwę puli i chcę zastosować rezygnację, aby zmniejszyć nadmierne dopasowanie. Mam wrażenie, że warstwa porzucająca powinna zostać nałożona po warstwie pulowania, ale tak naprawdę nie mam nic na poparcie tego. Gdzie jest właściwe miejsce na dodanie warstwy rezygnacji? Przed czy za warstwą puli?

pir
źródło

Odpowiedzi:

18

Edycja: Jak słusznie wskazał @Toke Faurby, domyślna implementacja w tensorflow faktycznie korzysta z rezygnacji z elementów. To, co opisałem wcześniej, dotyczy konkretnego wariantu rezygnacji z CNN, zwanego rezygnacją przestrzenną :

W CNN każdy neuron wytwarza jedną mapę cech. Od przerywania przestrzennych przerywania prac na neuronu żywej, środki neuronów, że odpowiednia właściwość mapa jest odrzucany - przykład każde stanowisko ma tę samą wartość (zwykle 0). Tak więc każda mapa obiektów jest albo całkowicie upuszczona, albo w ogóle nie upuszczona.

Pooling zwykle działa osobno na każdej mapie obiektów, więc nie powinno mieć znaczenia, czy zastosujesz rezygnację przed czy po pulowaniu. Przynajmniej tak jest w przypadku operacji pulowania, takich jak maxpooling lub uśrednianie.

Edit: Jednak jeśli rzeczywiście wykorzystać element mądry porzucaniu (co wydaje się być ustawione jako domyślne dla tensorflow), to faktycznie robi różnicę, jeśli stosuje przerywania przed lub po łączeniu. Jednak niekoniecznie jest to zły sposób. Rozważmy średnią operację łączenia: jeśli zastosujesz zanik przed połączeniem, skutecznie skalujesz wynikową aktywację neuronu o 1.0 - dropout_probability, ale większość neuronów będzie niezerowa (ogólnie). Jeśli zastosujesz zanikanie po uśrednieniu puli, zwykle otrzymujesz ułamek (1.0 - dropout_probability)niezerowych „nieskalowanych” aktywacji neuronów i ułamek dropout_probabilityzerowych neuronów. Oba wydają mi się realne, żadne też nie jest całkowicie złe.

schreon
źródło
1
Nie jestem pewien, czy jest to standardowy sposób przeprowadzania rezygnacji. Np. W tf.nn.dropout stwierdza: „Domyślnie każdy element jest trzymany lub upuszczany niezależnie”. Czy masz źródło, które to tworzy?
Toke Faurby
1
O! To, co opisałem, nazywa się teraz rezygnacją przestrzenną : arxiv.org/pdf/1411.4280.pdf . @TokeFaurby słusznie wątpi w moje twierdzenie. Jednak, jak można również przeczytać w połączonym dokumencie, upuszczenie całych map obiektów w sposób przestrzenny powoduje poprawienie wydajności. Nie jest to zaskoczeniem, ponieważ sąsiednie aktywacje są silnie skorelowane, a porzucenie jednego konkretnego elementu w rzeczywistości nie upuszcza informacji przenoszonych przez ten element (ponieważ jest bardzo mało prawdopodobne, aby w tym czasie upuszczał ciągłą „dziurę” na mapie obiektów pod względem elementu). Zmienię swoją odpowiedź, aby odzwierciedlić tę różnicę.
schreon
10

W tym samouczku wykorzystuje się buforowanie przed rezygnacją i uzyskuje dobre wyniki.

To niekoniecznie oznacza, że ​​drugie zamówienie oczywiście nie działa. Moje doświadczenie jest ograniczone, używałem ich tylko na gęstych warstwach bez łączenia.

znak
źródło
5

Przykład konwektu podobnego do VGG z Keras (porzucenie po pulowaniu):

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
źródło