web-dev-qa-db-fra.com

Rétropropagation du réseau neuronal avec RELU

J'essaie d'implémenter un réseau neuronal avec RELU.

couche d'entrée -> 1 couche cachée -> relu -> couche de sortie -> couche softmax

Ci-dessus, l'architecture de mon réseau de neurones. Je suis confus quant à la rétropropagation de cette relu. Pour la dérivée de RELU, si x <= 0, la sortie est 0. si x> 0, la sortie est 1. Donc, lorsque vous calculez le gradient, cela signifie-t-il que je tue le gradient décent si x <= 0?

Quelqu'un peut-il expliquer la rétropropagation de mon architecture de réseau neuronal "étape par étape"?

27
Danny

si x <= 0, la sortie est 0. si x> 0, la sortie est 1

La fonction ReLU est définie comme suit: Pour x> 0, la sortie est x, c'est-à-dire f (x max (0, x)) ==

Donc pour la dérivée f '(x) c'est en fait:

si x <0, la sortie est 0. si x> 0, la sortie est 1.

La dérivée f '(0) n'est pas définie. Il est donc généralement défini sur 0 ou vous modifiez la fonction d'activation pour qu'elle soit f(x) = max (e, x) pour un petit e.

Généralement: une ReLU est une unité qui utilise la fonction d'activation du redresseur. Cela signifie qu'il fonctionne exactement comme n'importe quelle autre couche cachée, mais à l'exception de tanh (x), sigmoid (x) ou quelle que soit l'activation que vous utilisez, vous utiliserez plutôt f(x) = max (0, X).

Si vous avez écrit du code pour un réseau multicouche fonctionnel avec activation sigmoïde, c'est littéralement 1 ligne de changement. Rien sur la propagation avant ou arrière ne change algorithmiquement. Si vous n'avez pas encore fait fonctionner le modèle le plus simple, revenez en arrière et commencez par cela en premier. Sinon, votre question ne concerne pas vraiment les ReLU, mais l'implémentation d'un NN dans son ensemble.

10
runDOSrun

Si vous avez un calque constitué d'un seul ReLU, comme le suggère votre architecture, alors oui, vous tuez le dégradé à 0. Pendant la formation, le ReLU reviendra 0 à votre couche de sortie, qui renverra soit 0 ou 0.5 si vous utilisez des unités logistiques, et le softmax les écrasera. Donc, une valeur de 0 sous votre architecture actuelle n'a pas beaucoup de sens pour la partie de propagation vers l'avant non plus.

Voir par exemple this . Ce que vous pouvez faire est d'utiliser un "ReLU qui fuit", qui est une petite valeur à 0, tel que 0.01.

Je reconsidérerais cette architecture cependant, cela n'a pas beaucoup de sens pour moi d'alimenter un seul ReLU dans un tas d'autres unités puis d'appliquer un softmax.

8
IVlad

Voici un bon exemple, utilisez ReLU pour implémenter XOR: référence, http://pytorch.org/tutorials/beginner/pytorch_with_examples.html

# -*- coding: utf-8 -*-
import numpy as np
import matplotlib.pyplot as plt

# N is batch size(sample size); D_in is input dimension;
# H is hidden dimension; D_out is output dimension.
N, D_in, H, D_out = 4, 2, 30, 1

# Create random input and output data
x = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
y = np.array([[0], [1], [1], [0]])

# Randomly initialize weights
w1 = np.random.randn(D_in, H)
w2 = np.random.randn(H, D_out)

learning_rate = 0.002
loss_col = []
for t in range(200):
    # Forward pass: compute predicted y
    h = x.dot(w1)
    h_relu = np.maximum(h, 0)  # using ReLU as activate function
    y_pred = h_relu.dot(w2)

    # Compute and print loss
    loss = np.square(y_pred - y).sum() # loss function
    loss_col.append(loss)
    print(t, loss, y_pred)

    # Backprop to compute gradients of w1 and w2 with respect to loss
    grad_y_pred = 2.0 * (y_pred - y) # the last layer's error
    grad_w2 = h_relu.T.dot(grad_y_pred)
    grad_h_relu = grad_y_pred.dot(w2.T) # the second laye's error 
    grad_h = grad_h_relu.copy()
    grad_h[h < 0] = 0  # the derivate of ReLU
    grad_w1 = x.T.dot(grad_h)

    # Update weights
    w1 -= learning_rate * grad_w1
    w2 -= learning_rate * grad_w2

plt.plot(loss_col)
plt.show()

Pour en savoir plus sur le dérivé de ReLU, vous pouvez voir ici: http://kawahara.ca/what-is-the-derivative-of-relu/

6
Belter

Oui, la fonction Relu d'origine a le problème que vous décrivez. Ils ont donc modifié la formule par la suite, et l'ont appelée fuite Relu En substance, Leaky Relu incline légèrement la partie horizontale de la fonction. pour plus d'informations, regardez ceci:

ne explication des méthodes d'activation et un Relu amélioré sur youtube

2
user3800527

De plus, vous trouverez ici une implémentation dans le cadre de caffe: https://github.com/BVLC/caffe/blob/master/src/caffe/layers/relu_layer.cpp

Le negative_slope spécifie s'il faut "fuir" la partie négative en la multipliant par la valeur de la pente plutôt que de la mettre à 0. Bien sûr, vous devez définir ce paramètre à zéro pour avoir une version classique.

1
no one special