1
votes

Confusion sur l'entrée de dérivés sigmoïdes en rétropropagation

Lorsque vous utilisez la règle de chaîne pour calculer la pente de la fonction de coût par rapport aux poids au niveau de la couche L , la formule devient:

d C0 / d W (L) = .... d a (L) / d z (L). ...

Avec:

z (L) étant le champ local induit: z (L) = w1 (L) * a1 (L-1) + w2 (L) * a2 (L-1 ) * ...

a (L) étant la sortie: a (L) = & (z (L))

& étant la fonction sigmoïde utilisée comme fonction d'activation

Notez que L est considéré comme un indicateur de couche et non comme un index

Maintenant:
da (L) / dz (L) = & '(z (L))

Avec &' étant le dérivé de la fonction sigmoïde

Le problème:

Mais dans ce post qui est écrit par James Loy sur la construction d'un simple réseau de neurones à partir de zéro avec python,
En faisant la rétropropagation, il n'a pas donné z (L) comme entrée à & ' pour remplacer da (L) / dz (L) dans la fonction de règle de chaîne. Au lieu de cela, il lui a donné la sortie = dernière activation de la couche (L) comme entrée du dérivé sigmoïde &'

def feedforward(self):
        self.layer1 = sigmoid(np.dot(self.input, self.weights1))
        self.output = sigmoid(np.dot(self.layer1, self.weights2))

def backprop(self):
        # application of the chain rule to find derivative of the loss function with respect to weights2 and weights1
        d_weights2 = np.dot(self.layer1.T, (2*(self.y - self.output) * sigmoid_derivative(self.output)))

Notez que dans le code au-dessus de la couche L se trouve la couche 2 qui est la dernière couche ou couche de sortie. Et sigmoid_derivative (self.output) c'est ici que l'activation de la couche courante est donnée en entrée du dérivé de la fonction sigmoïde utilisée comme fonction d'activation.

La question:

Ne devrions-nous pas utiliser ce sigmoid_derivative (np.dot (self.layer1, self.weights2)) au lieu de ce sigmoid_derivative ( self.output) ?


0 commentaires

3 Réponses :


1
votes

Vous souhaitez utiliser la dérivée par rapport à la sortie. Pendant la rétropropagation, nous utilisons les poids uniquement pour déterminer la part de l'erreur qui appartient à chacun des poids et, ce faisant, nous pouvons propager l'erreur à travers les couches.

Dans le didacticiel, le sigmoïde est appliqué au dernier layer:

sigmoid_derivative(self.output)

D'après votre question:

Ne devrions-nous pas utiliser ce sigmoid_derivative (np.dot (self.layer1, self.weights2)) au lieu de ce sigmoid_derivative (self.output)?

Vous ne pouvez pas faire:

sigmoid_derivative(np.dot(self.layer1, self.weights2))

car ici vous essayez de prendre le dérivé du sigmoïde alors que vous ne l'avez pas encore appliqué.

C'est pourquoi vous devez utiliser:

self.output = sigmoid(np.dot(self.layer1, self.weights2))


4 commentaires

Mais pourquoi casser la formule et obtenir & '(& (z)) au lieu d'obtenir &' (z) qui cassera le rapport entre les composants de la règle de chaîne: d C / d W (L) = dz (L) / dw (L) * da (L) / dz (L) * d C / da (L) ?


La principale raison de la règle de chaîne est de donner l'effet de chaque variable sur la variation du coût C , et & (z (L)) lui-même a un effet sur ce coût. Pourquoi ne pas prendre & '(z (L)) et respecter la formule? Pourquoi prendre & '(& (z (L))) ?


À tout moment également, z (L) est relatif aux poids et aux activations précédentes.


@EEAH J'ai mis à jour ma réponse. J'espère que c'est plus clair maintenant.



1
votes

Vous avez raison - il semble que l'auteur ait fait une erreur. Je vais vous expliquer: lorsque le réseau est fait avec une passe avant (toutes les activations + perte), vous devez utiliser la descente de gradient pour minimiser les poids en fonction de la fonction de perte. Pour ce faire, vous avez besoin de la dérivée partielle de la fonction de perte par rapport à chaque matrice de poids.

Quelques notations avant de continuer: la perte est L , A est l'activation (aka sigmoïde), Z signifie l'entrée nette, dans d'autres mots, le résultat de W. X . Les nombres sont des indices, donc A1 signifie l'activation pour la première couche.

Vous pouvez utiliser la règle de la chaîne pour reculer dans le réseau et exprimer les poids en fonction de la perte. Pour commencer la passe arrière, vous commencez par obtenir la dérivée de la perte par rapport à l'activation de la dernière couche. Il s'agit de dL / dA2 , car la deuxième couche est la dernière couche. Pour mettre à jour les poids de la deuxième couche, nous devons compléter dA2 / dZ2 et dZ / dW2 .

Avant de continuer, rappelez-vous que l'activation de la deuxième couche est A2 = sigmoïde (W2. A1) et Z2 = W2. A1 . Pour plus de clarté, nous écrirons A2 = sigmoïde (Z2) . Traitez Z2 comme sa propre variable. Donc, si vous calculez dA2 / dZ2 , vous obtenez sigmoid_derivative (Z2) , qui est sigmoid_derivative (W2. A1) ou sigmoid_derivative ( np.dot (self.layer1, self.weights2)) . Cela ne devrait donc pas être sigmoid_derivative (self.output) car la output a été activée par sigmoid.


0 commentaires

1
votes

Il s'est avéré que & (z (L)) ou output a été utilisé, juste pour s'adapter à la façon dont sigmoid_derivative a été implémenté.

Voici le code du sigmoid_derivative :

def sigmoid(x):
    return 1.0/(1+ np.exp(-x))

def sigmoid_derivative(x):
    return x * (1.0 - x)

La formule mathématique du sigmoid_derivative peut être écrite comme suit: & '(x) = & (x) * (1 - & (x)) code >

Donc, pour arriver à la formule ci-dessus, & (z) et non z a été passé à sigmoid_derivative dans l'ordre pour retourner: & (z) * (1.0 - & (z))


0 commentaires