Onde eu chamo a função BatchNormalization no Keras?

167

Se eu quiser usar a função BatchNormalization no Keras, preciso chamá-la apenas uma vez no início?

Eu li esta documentação para ele: http://keras.io/layers/normalization/

Não vejo para onde devo chamá-lo. Abaixo está o meu código tentando usá-lo:

model = Sequential()
keras.layers.normalization.BatchNormalization(epsilon=1e-06, mode=0, momentum=0.9, weights=None)
model.add(Dense(64, input_dim=14, init='uniform'))
model.add(Activation('tanh'))
model.add(Dropout(0.5))
model.add(Dense(64, init='uniform'))
model.add(Activation('tanh'))
model.add(Dropout(0.5))
model.add(Dense(2, init='uniform'))
model.add(Activation('softmax'))

sgd = SGD(lr=0.1, decay=1e-6, momentum=0.9, nesterov=True)
model.compile(loss='binary_crossentropy', optimizer=sgd)
model.fit(X_train, y_train, nb_epoch=20, batch_size=16, show_accuracy=True, validation_split=0.2, verbose = 2)

Eu pergunto porque se eu executar o código com a segunda linha, incluindo a normalização em lote, e se eu executar o código sem a segunda linha, obterei resultados semelhantes. Então, ou eu não estou chamando a função no lugar certo, ou acho que não faz muita diferença.

pr338
fonte

Respostas:

225

Apenas para responder a essa pergunta um pouco mais detalhadamente, e como Pavel disse, a Normalização em lote é apenas outra camada, para que você possa usá-la como tal para criar a arquitetura de rede desejada.

O caso de uso geral é usar o BN entre as camadas linear e não linear na sua rede, porque normaliza a entrada para sua função de ativação, para que você fique centralizado na seção linear da função de ativação (como Sigmoid). Há uma pequena discussão sobre isso aqui

No seu caso acima, isso pode se parecer com:


# import BatchNormalization
from keras.layers.normalization import BatchNormalization

# instantiate model
model = Sequential()

# we can think of this chunk as the input layer
model.add(Dense(64, input_dim=14, init='uniform'))
model.add(BatchNormalization())
model.add(Activation('tanh'))
model.add(Dropout(0.5))

# we can think of this chunk as the hidden layer    
model.add(Dense(64, init='uniform'))
model.add(BatchNormalization())
model.add(Activation('tanh'))
model.add(Dropout(0.5))

# we can think of this chunk as the output layer
model.add(Dense(2, init='uniform'))
model.add(BatchNormalization())
model.add(Activation('softmax'))

# setting up the optimization of our weights 
sgd = SGD(lr=0.1, decay=1e-6, momentum=0.9, nesterov=True)
model.compile(loss='binary_crossentropy', optimizer=sgd)

# running the fitting
model.fit(X_train, y_train, nb_epoch=20, batch_size=16, show_accuracy=True, validation_split=0.2, verbose = 2)

Espero que isso esclareça as coisas um pouco mais.

Lucas Ramadan
fonte
25
FYI aparentemente normalização lote funciona melhor na prática após a função de ativação
Claudiu
10
Oi @Claudiu, você se importaria de expandir esse FYI? Parece contradizer diretamente a resposta acima.
Ben Ogorek
7
@ benogorek: com certeza, basicamente eu o baseei inteiramente nos resultados aqui, onde a colocação da norma do lote após o relu teve um desempenho melhor. FWIW eu não tive sucesso aplicá-lo de uma forma ou de outra por um net eu tentei
Claudiu
32
Interessante. Apenas para acompanhar, se você continuar lendo esse resumo, ele diz que o melhor modelo deles [GoogLeNet128_BN_lim0606] realmente tem a camada BN ANTES da ReLU. Portanto, enquanto o BN após a ativação pode melhorar a precisão em um caso isolado, quando todo o modelo é construído, antes do melhor desempenho. É provável que a colocação de BN após a ativação possa melhorar a precisão, mas provavelmente depende do problema.
Lucas Ramadan
7
@ CarlThomé mais ou menos. Veja este comentário do ReginaldIII no reddit, por exemplo. Eles afirmam: "O BN está normalizando a distribuição dos recursos resultantes de uma convolução, alguns [desses] recursos podem ser negativos [e] truncados por uma não linearidade como ReLU. Se você normalizar antes da ativação, está incluindo esses valores negativos em a normalização imediatamente antes de separá-los do espaço de recursos. O BN após a ativação normalizará os recursos positivos sem enviesá-los estatisticamente com recursos que não chegam à próxima camada convolucional. "
mab
60

Este tópico é enganoso. Tentei comentar a resposta de Lucas Ramadan, mas ainda não tenho os privilégios corretos, então vou colocar isso aqui.

A normalização de lotes funciona melhor após a função de ativação, e é aqui ou aqui o porquê: foi desenvolvida para impedir o deslocamento covariável interno. O deslocamento covariável interno ocorre quando a distribuição das ativaçõesde uma camada muda significativamente durante o treinamento. A normalização de lote é usada para que a distribuição das entradas (e essas entradas sejam literalmente o resultado de uma função de ativação) para uma camada específica não seja alterada ao longo do tempo devido às atualizações de parâmetros de cada lote (ou pelo menos, permita que seja alterada de uma maneira vantajosa). Ele usa estatísticas de lote para fazer a normalização e, em seguida, usa os parâmetros de normalização de lote (gama e beta no artigo original) "para garantir que a transformação inserida na rede possa representar a transformação de identidade" (citação do artigo original). Mas o ponto é que estamos tentando normalizar as entradas para uma camada, por isso sempre deve ocorrer imediatamente antes da próxima camada na rede. Se isso é ou não '

jmancuso
fonte
27
Acabei de ver na classe deeplearning.ai que Andrew Ng diz que há um debate sobre isso na comunidade Deep Learning. Ele prefere aplicar a normalização de lotes antes da não linearidade.
Shahensha #
3
@kRazzyR Eu quis dizer que o Prof. Andrew Ng falou sobre esse tópico em suas aulas de aprendizagem profunda sobre deeplearning.ai Ele disse que a comunidade está dividida na maneira correta de fazer as coisas e que preferia aplicar a normalização de lotes antes de aplicar a não linearidade.
shahensha
3
@jmancuso, o BN é aplicado antes da ativação. A partir do próprio papel, a equação é g(BN(Wx + b))onde gestá a função de ativação.
precisa saber é o seguinte
43

Este tópico tem um debate considerável sobre se o BN deve ser aplicado antes da não linearidade da camada atual ou sobre as ativações da camada anterior.

Embora não haja uma resposta correta, os autores da Normalização em lote dizem que ela deve ser aplicada imediatamente antes da não linearidade da camada atual. O motivo (citado no artigo original) -

"Adicionamos a transformação BN imediatamente antes da não linearidade, normalizando x = Wu + b. Também poderíamos normalizar as entradas da camada u, mas como u é provavelmente a saída de outra não linearidade, é provável que o formato de sua distribuição mude durante Em contraste, Wu + b é mais provável que tenha uma distribuição simétrica e não esparsa, que é “mais gaussiana” (Hyvëarinen & Oja, 2000). ; normalizando, é provável que produza ativações com uma distribuição estável ".

user12340
fonte
3
Na minha experiência pessoal, isso não faz uma grande diferença, mas, apesar de tudo ser igual, sempre vi o BN ter um desempenho ligeiramente melhor quando a normalização em lote é aplicada antes da não linearidade (antes da função de ativação).
Brad Hesse
31

O Keras agora suporta a use_bias=Falseopção, para que possamos economizar algum cálculo escrevendo como

model.add(Dense(64, use_bias=False))
model.add(BatchNormalization(axis=bn_axis))
model.add(Activation('tanh'))

ou

model.add(Convolution2D(64, 3, 3, use_bias=False))
model.add(BatchNormalization(axis=bn_axis))
model.add(Activation('relu'))
dontloo
fonte
hows model.add(BatchNormalization())diferente demodel.add(BatchNormalization(axis=bn_axis))
kRazzy R
@kRazzR, não difere se você estiver usando tensorflowcomo back-end. Está escrito aqui porque ele copiou isso do keras.applicationsmódulo, onde bn_axisprecisa ser especificado para suportar os formatos channels_firste os dois channels_last.
Ldavid
9
Alguém pode elaborar como isso se relaciona com a questão do OP? (Estou bastante novato para NNs então talvez eu perca alguma coisa.)
Pepacz
30

É quase uma tendência agora ter um Conv2Dseguido por um ReLuseguido por uma BatchNormalizationcamada. Então, criei uma pequena função para chamar todos eles de uma vez. Faz com que a definição do modelo pareça muito mais limpa e fácil de ler.

def Conv2DReluBatchNorm(n_filter, w_filter, h_filter, inputs):
    return BatchNormalization()(Activation(activation='relu')(Convolution2D(n_filter, w_filter, h_filter, border_mode='same')(inputs)))
stochastic_zeitgeist
fonte
7
talvez empurre isso para keras?
sachinruk
6

Como é outro tipo de camada, adicione-a como uma camada em um local apropriado do seu modelo

model.add(keras.layers.normalization.BatchNormalization())

Veja um exemplo aqui: https://github.com/fchollet/keras/blob/master/examples/kaggle_otto_nn.py

Pavel Surmenok
fonte
1
Depois de adicionar o BatchNormalization, o val_acc parou de aumentar a cada época. O val_acc permaneceu estagnado no mesmo número após cada época após a adição do BatchNormalization. Eu pensei que a Normalização de Lote deveria aumentar o val_acc. Como sei se está funcionando corretamente? Você sabe o que pode ter causado isso?
Pr338
infelizmente o link não é mais válido :(
user2324712
Existem cópias desse exemplo nos garfos do Keras (por exemplo, github.com/WenchenLi/kaggle/blob/master/otto/keras/… ), mas não sei por que ele foi removido do repositório original do Keras e se o O código é compatível com as versões mais recentes do Keras.
Pavel Surmenok 23/09/16
4

A Normalização de lote é usada para normalizar a camada de entrada e as camadas ocultas, ajustando a média e o dimensionamento das ativações. Devido a esse efeito de normalização com camada adicional em redes neurais profundas, a rede pode usar uma taxa de aprendizado mais alta sem desaparecer ou explodir gradientes. Além disso, a normalização em lote regulariza a rede de modo que seja mais fácil generalizar e, portanto, é desnecessário usar a eliminação para reduzir o excesso de ajuste.

Logo após calcular a função linear usando, por exemplo, Dense () ou Conv2D () em Keras, usamos BatchNormalization () que calcula a função linear em uma camada e, em seguida, adicionamos a não linearidade à camada usando Ativação ().

from keras.layers.normalization import BatchNormalization
model = Sequential()
model.add(Dense(64, input_dim=14, init='uniform'))
model.add(BatchNormalization(epsilon=1e-06, mode=0, momentum=0.9, weights=None))
model.add(Activation('tanh'))
model.add(Dropout(0.5))
model.add(Dense(64, init='uniform'))
model.add(BatchNormalization(epsilon=1e-06, mode=0, momentum=0.9, weights=None))
model.add(Activation('tanh'))
model.add(Dropout(0.5))
model.add(Dense(2, init='uniform'))
model.add(BatchNormalization(epsilon=1e-06, mode=0, momentum=0.9, weights=None))
model.add(Activation('softmax'))

sgd = SGD(lr=0.1, decay=1e-6, momentum=0.9, nesterov=True)
model.compile(loss='binary_crossentropy', optimizer=sgd)
model.fit(X_train, y_train, nb_epoch=20, batch_size=16, show_accuracy=True, 
validation_split=0.2, verbose = 2)

Como a Normalização de Lote é aplicada?

Suponha que introduzimos a [l-1] em uma camada l. Também temos pesos W [l] e unidade de viés b [l] para a camada l. Seja a [l] o vetor de ativação calculado (isto é, após adicionar a não linearidade) para a camada l e z [l] seja o vetor antes de adicionar a não linearidade

  1. Usando a [l-1] e W [l], podemos calcular z [l] para a camada l
  2. Normalmente, na propagação de feed-forward, adicionaremos a unidade de polarização a z [l] neste estágio como este z [l] + b [l], mas na Normalização de Lote, essa etapa de adição de b [l] não é necessária e não O parâmetro b [l] é usado.
  3. Calcular z [l] significa e subtraí-lo de cada elemento
  4. Divida (z [l] - média) usando o desvio padrão. Chame de Z_temp [l]
  5. Agora defina novos parâmetros γ e β que mudarão a escala da camada oculta da seguinte maneira:

    z_norm [l] = γ.Z_temp [l] + β

Neste trecho de código, Denso () pega a [l-1], usa W [l] e calcula z [l]. Em seguida, o BatchNormalization () imediato executará as etapas acima para fornecer z_norm [l]. E então a Ativação imediata () calculará tanh (z_norm [l]) para dar um [l] ie

a[l] = tanh(z_norm[l])
Aishwarya Radhakrishnan
fonte