ReLU vs sigmoid no exemplo mnist

8

ATENÇÃO: Não estou tentando melhorar o exemplo a seguir. Eu sei que você pode obter mais de 99% de precisão. O código inteiro está na pergunta. Quando tentei esse código simples, obtive cerca de 95% de precisão; se eu simplesmente alterar a função de ativação de sigmoid para relu, ela cai para menos de 50%. Existe uma razão teórica para isso acontecer?

Encontrei o seguinte exemplo online:

from keras.datasets import mnist
from keras.models import Sequential 
from keras.layers.core import Dense, Activation
from keras.utils import np_utils

(X_train, Y_train), (X_test, Y_test) = mnist.load_data()

X_train = X_train.reshape(60000, 784)     
X_test = X_test.reshape(10000, 784)

Y_train = np_utils.to_categorical(Y_train, classes)     
Y_test = np_utils.to_categorical(Y_test, classes)

batch_size = 100      
epochs = 15

model = Sequential()     
model.add(Dense(100, input_dim=784)) 
model.add(Activation('sigmoid'))     
model.add(Dense(10)) 
model.add(Activation('softmax'))

model.compile(loss='categorical_crossentropy', metrics=['accuracy'], optimizer='sgd')

model.fit(X_train, Y_train, batch_size=batch_size, epochs=epochs, verbose=1)

score = model.evaluate(X_test, Y_test, verbose=1)
print('Test accuracy:', score[1])

Isso fornece cerca de 95% de precisão, mas se eu alterar o sigmóide com o ReLU, obtém menos de 50% de precisão. Por que é que?

do utilizador
fonte
Compare com keras ' próprio exemplo relu de .
Emre
Quero entender por que, neste exemplo, o relu seria muito pior que o sigmóide. Eles usam um otimizador diferente. O sgd não funciona bem com relu?
usuário
Seu modelo não convergiu e / ou superajustou. Vou me inclinar mais para a segunda opção, já que a documentação utilizou o abandono (regularização) e você não. Você pode depurar esse problema desenhando a curva de aprendizado para os conjuntos de teste e treinamento.
Emre
A questão é simples: por que funciona bem com sigmóide e não com relé? Nenhum dos comentários está abordando a questão.
usuário
Qual é a precisão do seu treinamento com a RELU?
Imran

Respostas:

4

Peguei seu código exato, substituí

model.add(Activation('sigmoid'))

de

model.add(Activation('relu'))

e, de fato, tive o mesmo problema que você: apenas 55% de precisão, o que é ruim ...

Solução : redimensionei os valores da imagem de entrada de [0, 255] para [0,1] e funcionou: precisão de 93% com ReLU! (inspirado em https://github.com/keras-team/keras/blob/master/examples/mnist_mlp.py ):

from keras.datasets import mnist
from keras.models import Sequential 
from keras.layers.core import Dense, Activation
from keras.utils import np_utils

(X_train, Y_train), (X_test, Y_test) = mnist.load_data()

X_train = X_train.reshape(60000, 784)     
X_test = X_test.reshape(10000, 784)
X_train = X_train.astype('float32') / 255
X_test = X_test.astype('float32') / 255

Y_train = np_utils.to_categorical(Y_train, 10)
Y_test = np_utils.to_categorical(Y_test, 10)

batch_size = 100
epochs = 15

model = Sequential()     
model.add(Dense(100, input_dim=784)) 
model.add(Activation('relu'))
model.add(Dense(10)) 
model.add(Activation('softmax'))

model.compile(loss='categorical_crossentropy', metrics=['accuracy'], optimizer='sgd')

model.fit(X_train, Y_train, batch_size=batch_size, epochs=epochs, verbose=1)

score = model.evaluate(X_test, Y_test, verbose=1)
print('Test accuracy:', score[1])

Resultado:

Precisão do teste: 0.934


Explicação potencial: ao usar uma entrada em [0, 255], ao fazer a soma ponderada da camada eu: z=uma(eu-1 1)W(eu)+b(eu), O valor que ztambém será grande demais. E sez geralmente é grande (ou mesmo maior que 0), digamos cerca de 100, que Reeuvocê(z)=z, e perdemos totalmente o aspecto "não linear" dessa função de ativação! Dito de outra maneira: se a entrada estiver em [0, 255], entãozgeralmente está longe de 0 e evitamos totalmente o lugar em que "coisas não lineares interessantes" estão acontecendo ( em torno de 0 a função ReLU não é linear e parece __/) ... Agora, quando a entrada está em [0,1] , então a soma ponderadaz geralmente pode estar próximo de 0: talvez às vezes fique abaixo de 0 (já que os pesos são inicializados aleatoriamente em [-1, 1], é possível!), às vezes maior que 0, etc. Então, mais ativação / desativação de neurônios está acontecendo. .. Essa poderia ser uma possível explicação de por que funciona melhor com entrada em [0, 1].

Basj
fonte
Muito obrigado pelo seu esforço (+1). Minha pergunta, porém, é por que isso? Qual é a interpretação teórica?
usuário deve
Seu argumento parece razoável. Se você gostaria de adicionar um pequeno comentário no texto da sua resposta (por isso, não há necessidade de ler os comentários), aceitarei sua resposta.
usuário
@user Está pronto!
Basj
1

Eu obtive cerca de 98% de precisão usando a função de ativação ReLu. Eu usei a seguinte arquitetura:

  1. camada totalmente conectada com 300 unidades ocultas
  2. Ativação ReLu
  3. camada totalmente conectada com 10 unidades ocultas
  4. Camada Softmax
  5. Recorte de saída 1e-10 a 0.999999 para evitar log (0) e valor maior que 1
  6. Perda de entropia cruzada

Eu acho que você deve adicionar um recorte de saída e treiná-lo, espero que funcione bem.

Yash Khare
fonte
Obrigado. Sua resposta parece confirmar o que @Basj diz em seus comentários sobre por que relu não está convergindo enquanto sigmóide. +1, mas ainda não responde à minha pergunta sobre o porquê. Eu acho que os comentários na outra resposta explicam isso.
usuário
-1

Porque com o MNIST, você está tentando prever com base nas probabilidades.

A função sigmóide esmaga o x valor entre 0 0 e 1 1. Isso ajuda a escolher o dígito mais provável que corresponde ao rótulo.

A função ReLU não esmaga nada. Se ox valor é menor que 0 0, a saída é 0 0. Se é mais do que0 0, a resposta é a xvalor em si. Nenhuma probabilidade está sendo criada.

Honestamente, estou surpreso que você tenha algo a mais de 10% ao conectá-lo.

daleadil
fonte
11
Eu acho que ele quer dizer que ele mudou a ativação da camada oculta de sigmóide para RELU, o que não deve ser um problema, desde que a camada de saída ainda tenha o softmax.
Imran
11
@daleadil como Imran disse, a camada escondida pode ter Relu como a função de activação, isto não tem nada a ver com a probabilidade
utilizador