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?
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.
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.
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)
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 =)