web-dev-qa-db-fra.com

numpy: calcule la dérivée de la fonction softmax

J'essaie de comprendre backpropagation dans un simple réseau neuronal à 3 couches avec MNIST.

Il y a la couche d'entrée avec weights et un bias. Les étiquettes sont MNIST c'est donc un 10 vecteur de classe.

La deuxième couche est un linear tranform. La troisième couche est le softmax activation pour obtenir la sortie sous forme de probabilités.

Backpropagation calcule la dérivée à chaque étape et appelle cela le gradient.

Les calques précédents ajoutent le dégradé global ou previous au local gradient. J'ai du mal à calculer le local gradient du softmax

Plusieurs ressources en ligne expliquent le softmax et ses dérivés et donnent même des exemples de code du softmax lui-même

def softmax(x):
    """Compute the softmax of vector x."""
    exps = np.exp(x)
    return exps / np.sum(exps)

Le dérivé est expliqué par rapport à quand i = j et quand i != j. Ceci est un simple extrait de code que j'ai trouvé et espérais vérifier ma compréhension:

def softmax(self, x):
    """Compute the softmax of vector x."""
    exps = np.exp(x)
    return exps / np.sum(exps)

def forward(self):
    # self.input is a vector of length 10
    # and is the output of 
    # (w * x) + b
    self.value = self.softmax(self.input)

def backward(self):
    for i in range(len(self.value)):
        for j in range(len(self.input)):
            if i == j:
                self.gradient[i] = self.value[i] * (1-self.input[i))
            else: 
                 self.gradient[i] = -self.value[i]*self.input[j]

Alors self.gradient est le local gradient qui est un vecteur. Est-ce correct? Y a-t-il une meilleure façon d'écrire cela?

10
Sam Hammamy

Je suppose que vous avez un NN à 3 couches avec W1, b1 for est associé à la transformation linéaire du calque d'entrée en calque masqué et W2, b2 est associé à une transformation linéaire du calque masqué au calque de sortie. Z1 et Z2 sont le vecteur d'entrée du calque masqué et du calque de sortie. a1 et a2 représente la sortie du calque caché et du calque de sortie. a2 est votre sortie prévue. delta3 et delta2 sont les erreurs (rétropropagées) et vous pouvez voir les gradients de la fonction de perte par rapport aux paramètres du modèle.

enter image description hereenter image description here

Il s'agit d'un scénario général pour un NN à 3 couches (couche d'entrée, une seule couche masquée et une couche de sortie). Vous pouvez suivre la procédure décrite ci-dessus pour calculer des gradients qui devraient être faciles à calculer! Puisqu'une autre réponse à ce post a déjà signalé le problème dans votre code, je ne répète pas la même chose.

16
Wasi Ahmad

Comme je l'ai dit, vous avez n^2 Des dérivées partielles.

Si vous faites le calcul, vous constatez que dSM[i]/dx[k] Est SM[i] * (dx[i]/dx[k] - SM[i]) donc vous devriez avoir:

if i == j:
    self.gradient[i,j] = self.value[i] * (1-self.value[i])
else: 
    self.gradient[i,j] = -self.value[i] * self.value[j]

au lieu de

if i == j:
    self.gradient[i] = self.value[i] * (1-self.input[i])
else: 
     self.gradient[i] = -self.value[i]*self.input[j]

Soit dit en passant, cela peut être calculé de manière plus concise comme ceci (vectorisé):

SM = self.value.reshape((-1,1))
jac = np.diagflat(self.value) - np.dot(SM, SM.T)
9
Julien

np.exp n'est pas stable car il a Inf. Vous devez donc soustraire le maximum en x.

def softmax(x):
    """Compute the softmax of vector x."""
    exps = np.exp(x - x.max())
    return exps / np.sum(exps)

Si x est une matrice, veuillez vérifier la fonction softmax dans ce portable ( https://github.com/rickiepark/ml-learn/blob/master/notebooks/5.%20multi-layer%20perceptron.ipynb =)

6
Haesun Park