Il semble que les chapitres 5 à 7 sont importants dans ce livre, Décrivez avec emphase
Deux façons de comprendre la méthode de rétropropagation ・ Compréhension par "formule mathématique" ・ Compréhension par "graphe de calcul"
Ce livre explique ce dernier
Graphique de calcul: représentation graphique du processus de calcul Graphique: graphique en tant que structure de données, représenté par plusieurs nœuds et arêtes La figure ci-dessous est un graphique de calcul lorsque vous achetez une pomme de 100 yens par pièce et que la taxe à la consommation est de 10%. Propagation avant: Propagation du point de départ au point final du graphe de calcul Propagation arrière: propagation inverse de la propagation avant
Fonctionnalités du graphe de calcul: Propagation de "calculs locaux" pour obtenir le résultat final Dans la figure ci-dessus, seules des pommes ont été utilisées, mais cela devient compliqué lorsqu'il y a d'autres achats. Peu importe ce que fait le tout, vous ne pouvez obtenir les résultats suivants qu'à partir des informations qui vous concernent (apple dans l'exemple).
Avantages du graphe de calcul: la "différenciation" peut être calculée efficacement par propagation dans la direction opposée
Il faut du temps pour calculer le gradient de la fonction de perte du paramètre de poids du réseau de neurones par différenciation numérique. Par conséquent, la méthode de propagation de retour d'erreur est exécutée. Méthode de propagation d'erreur: une méthode pour calculer efficacement le gradient des paramètres de poids
Rétropropagation en supposant qu'il y a un calcul y = f (x)
z=x+La différenciation de y est\\
\frac{\partial z}{\partial x} = 1 \\
\frac{\partial z}{\partial y} = 1
Si cela apparaît dans le graphique de calcul
Dans du code
class AddLayer:
#constructeur
def __init__(self):
self.x = None
self.y = None
def forward(self, x, y):
self.x = x
self.y = y
out = x+y
return out
def backward(self, dout):
dx = dout * 1
dy = dout * 1
return dx, dy
z=x*La différenciation de y est\\
\frac{\partial z}{\partial x} = y \\
\frac{\partial z}{\partial y} = x
Si cela apparaît dans le graphique de calcul
Dans du code
class MulLayer:
#constructeur
# self =Java ceci
def __init__(self):
self.x = None
self.y = None
def forward(self, x, y):
self.x = x
self.y = y
out = x*y
return out
def backward(self, dout):
dx = dout * self.y
dy = dout * self.x
return dx, dy
y = \left\{
\begin{array}{ll}
x & (x \geq 0) \\
0 & (x \lt 0)
\end{array}
\right.
\frac{\partial y}{\partial x} = \left\{
\begin{array}{ll}
1 & (x \geq 0) \\
0 & (x \lt 0)
\end{array}
\right.
Dans du code
#Couche ReLU
class Relu:
def __init__(self):
self.mask = None
def forward(self, x):
self.mask = (x<=0)
out = x.copy()
out[self.mask] = 0
return out
def backward(self, dout):
dout[self.mask] = 0
dx = dout
return dx
fonction sigmoïde y=\frac{1}{1+\exp(-x)} \\
Supplément graphique de calcul
\begin{align}
f(x)&=-x \\
\Rightarrow f'(x)&=-1\\
f(x)&=\exp(x) \\
\Rightarrow f'(x)&=\exp(x)\\
f(x)&=x+1 \\
\Rightarrow f'(x)&=1\\
f(x)&=1/x \\
\Rightarrow f'(x)&=-1/x^2=-f(x)^2\\
\end{align}
\begin{align}
\frac{\partial L}{\partial y}y^2\exp(-x) &=\frac{\partial L}{\partial y}y\frac{\exp(-x)}{1+\exp(-x)} \\
&=\frac{\partial L}{\partial y}y(1-y) \\
\end{align}
Dans du code
#Couche sigmoïde
class Sigmoid:
def __init__(self):
self.out = None
def forward(self, x):
out = 1 / (1 + np.exp(-x))
self.out = out
return out
def backward(self, dout):
dx = dout * (1.0 - self.out) * self.out
return dx
Dans du code
#Version par lots Couche affine
class Affine:
def __init__(self, W, b):
self.W = W
self.b = b
self.x = None
self.dW = None
self.db = None
def forward(self, x):
self.x = x
out = np.dot(x, self.W) + self.b
return out
def backward(self, dout):
dx = np.dot(dout, self.W.T)
self.dW = np.dot(self.x.T, dout)
self.db = np.dot(dout, axis=0)
return dx
Preuve (cas simple de N = 1)
\begin{align}
\frac{\partial L}{\partial Y} \cdot W^T&=
\bigr(\begin{matrix}
\frac{\partial L}{\partial y_1} &
\frac{\partial Y}{\partial y_2}&
\frac{\partial Y}{\partial y_2}
\end{matrix}\bigr)
\Biggl(
\begin{matrix}w_{11} & w_{21} \\
w_{12} & w_{22} \\
w_{13} & w_{23}
\end{matrix}\Biggr)\\
&=\bigl(\begin{matrix}
\frac{\partial L}{\partial y_1}w_{11}+
\frac{\partial L}{\partial y_2}w_{12}+
\frac{\partial L}{\partial y_3}w_{13} &
\frac{\partial L}{\partial y_1}w_{21}+
\frac{\partial L}{\partial y_2}w_{22}+
\frac{\partial L}{\partial y_3}w_{23}
\end{matrix}\bigr)\\
&=\bigl(\begin{matrix}
\frac{\partial L}{\partial y_1}\frac{\partial y_1}{\partial x_1}
+\frac{\partial L}{\partial y_2}\frac{\partial y_2}{\partial x_1}
+\frac{\partial L}{\partial y_3}\frac{\partial y_3}{\partial x_1} &
\frac{\partial L}{\partial y_1}\frac{\partial y_1}{\partial x_2}
+\frac{\partial L}{\partial y_2}\frac{\partial y_2}{\partial x_2}
+\frac{\partial L}{\partial y_3}\frac{\partial y_3}{\partial x_2}
\end{matrix}\bigr)\\
&=\bigl(
\begin{matrix}
\frac{\partial L}{\partial Y}\frac{\partial Y}{\partial x_1} &
\frac{\partial L}{\partial Y}\frac{\partial Y}{\partial x_2}
\end{matrix}\bigr)\\
&=\frac{\partial L}{\partial X}\\
X^T \cdot \frac{\partial L}{\partial Y}
&=\Bigl(\begin{matrix}
x_1\\
x_2
\end{matrix}\Bigr)
\cdot
\bigr(\begin{matrix}
\frac{\partial L}{\partial y_1} &
\frac{\partial L}{\partial y_2} &
\frac{\partial L}{\partial y_3}
\end{matrix}\bigr)\\
&=
\bigr(\begin{matrix}
x_1\frac{\partial L}{\partial y_1} &
x_1\frac{\partial L}{\partial y_2} &
x_1\frac{\partial L}{\partial y_3}\\
x_2\frac{\partial L}{\partial y_1} &
x_2\frac{\partial L}{\partial y_2} &
x_2\frac{\partial L}{\partial y_3}
\end{matrix}\bigr)\\
&=
\bigr(\begin{matrix}
\frac{\partial L}{\partial y_1}x_1 &
\frac{\partial L}{\partial y_2}x_1 &
\frac{\partial L}{\partial y_3}x_1\\
\frac{\partial L}{\partial y_1}x_2 &
\frac{\partial L}{\partial y_2}x_2 &
\frac{\partial L}{\partial y_3}x_2
\end{matrix}\bigr)\\
&=
\bigr(\begin{matrix}
\frac{\partial L}{\partial y_1}\frac{\partial y_1}{\partial w_{11}} &
\frac{\partial L}{\partial y_2}\frac{\partial y_2}{\partial w_{12}} &
\frac{\partial L}{\partial y_3}\frac{\partial y_3}{\partial w_{13}}\\
\frac{\partial L}{\partial y_1}\frac{\partial y_1}{\partial w_{21}} &
\frac{\partial L}{\partial y_2}\frac{\partial y_2}{\partial w_{22}} &
\frac{\partial L}{\partial y_3}\frac{\partial y_3}{\partial w_{23}}
\end{matrix}\bigr)\\
&=
\bigr(\begin{matrix}
\frac{\partial L}{\partial w_{11}} &
\frac{\partial L}{\partial w_{12}} &
\frac{\partial L}{\partial w_{13}}\\
\frac{\partial L}{\partial w_{21}} &
\frac{\partial L}{\partial w_{22}} &
\frac{\partial L}{\partial w_{23}}
\end{matrix}\bigr)\\
&=\frac{\partial L}{\partial W}\\
Supplément de calcul\\
Y&=X \cdot W+B\\
y_i&=x_1w_{1i}+x_2w_{2i}+b_i\\
Exemple)\frac{\partial y_3}{\partial w_{23}}&=x_2
\end{align}
\begin{align}
&(y_1, y_2, y_3):Sortie de couche Softmax\\
&(t_1, t_2, t_3):Données des enseignants\\
\\
&En d'autres termes(y_1-t_1, y_2-t_2, y_3-t_3)Est\\
&Différence entre la sortie de la couche Softmax et l'étiquette de l'enseignant\\
\end{align}
# SoftmaxWithLoss
class SofmaxWithLoss:
def __init(self):
self.loss = None
self.y = None
self.t = None
def forward(self, x, t):
self.t = t
self.y = sofmax(x)
self.loss = cross_entropy_error(self.y, self.t)
return self.loss
def backward(self, dout=1):
batch_size = self.t.shape[0]
dx - (self.y - self.t) / bath_size
return dx
Un réseau de neurones peut être créé en ajoutant simplement les couches nécessaires aux couches ci-dessus comme un bloc lego. Ajoutez quelques commentaires pendant que la source est active
# coding: utf-8
import sys, os
sys.path.append(os.pardir) #Paramètres d'importation des fichiers dans le répertoire parent
import numpy as np
from common.layers import *
from common.gradient import numerical_gradient
from collections import OrderedDict
class TwoLayerNet:
#-------------------------------------------------
# __init__:Initialiser
# @self
# @input_size:Nombre de neurones dans la couche d'entrée
# @hidden_size:Nombre de neurones de couche cachée
# @output_size:Nombre de neurones dans la couche de sortie
# @weight_init_std:Échelle de distribution gaussienne à l'initialisation du poids
#-------------------------------------------------
def __init__(self, input_size, hidden_size, output_size, weight_init_std = 0.01):
# params:Variable de type dictionnaire contenant les paramètres du réseau neuronal
#Initialisation du poids
self.params = {}
self.params['W1'] = weight_init_std * np.random.randn(input_size, hidden_size)
self.params['b1'] = np.zeros(hidden_size)
self.params['W2'] = weight_init_std * np.random.randn(hidden_size, output_size)
self.params['b2'] = np.zeros(output_size)
# layer:Variables de type dictionnaire "ordonnées" qui contiennent des couches du réseau neuronal
#Génération de couches:Le but est de sauvegarder dans l'ordre
#En conséquence, il est acceptable d'appeler simplement la couche à partir de l'inverse pour la propagation directe et la propagation inverse.
self.layers = OrderedDict()
self.layers['Affine1'] = Affine(self.params['W1'], self.params['b1'])
self.layers['Relu1'] = Relu()
self.layers['Affine2'] = Affine(self.params['W2'], self.params['b2'])
#La dernière couche du réseau neuronal:Ici SoftmaxWithLoss couche
self.lastLayer = SoftmaxWithLoss()
#-------------------------------------------------
# predict:Effectuer la reconnaissance (inférence)
# @self
# @x:Données d'image (données d'entrée)
#-------------------------------------------------
def predict(self, x):
for layer in self.layers.values():
x = layer.forward(x)
return x
#-------------------------------------------------
# loss:Trouvez la fonction de perte
# @self
# @x:Données d'image (données d'entrée)
# @t:Données des enseignants
#-------------------------------------------------
def loss(self, x, t):
y = self.predict(x)
return self.lastLayer.forward(y, t)
#-------------------------------------------------
# accuracy:Trouver la précision de la reconnaissance
# @self
# @x:Données d'image (données d'entrée)
# @t:Données des enseignants
#-------------------------------------------------
def accuracy(self, x, t):
y = self.predict(x)
y = np.argmax(y, axis=1)
if t.ndim != 1 : t = np.argmax(t, axis=1)
accuracy = np.sum(y == t) / float(x.shape[0])
return accuracy
#-------------------------------------------------
# numerical_gradient:Trouvez le gradient pour le paramètre de poids par différenciation numérique (comme jusqu'au chapitre 4)
# @self
# @x:Données d'image (données d'entrée)
# @t:Données des enseignants
#-------------------------------------------------
def numerical_gradient(self, x, t):
loss_W = lambda W: self.loss(x, t)
grads = {}
grads['W1'] = numerical_gradient(loss_W, self.params['W1'])
grads['b1'] = numerical_gradient(loss_W, self.params['b1'])
grads['W2'] = numerical_gradient(loss_W, self.params['W2'])
grads['b2'] = numerical_gradient(loss_W, self.params['b2'])
return grads
#-------------------------------------------------
# gradient:Trouvez le gradient du paramètre de poids par la méthode de rétropropagation
# @self
# @x:Données d'image (données d'entrée)
# @t:Données des enseignants
#-------------------------------------------------
def gradient(self, x, t):
#point:Il déplace en fait la propagation implémentée sous forme de couche
# forward:Propagation vers l'avant
self.loss(x, t)
# backward:Rétropropagation
dout = 1
dout = self.lastLayer.backward(dout)
layers = list(self.layers.values())
layers.reverse()
for layer in layers:
dout = layer.backward(dout)
#Réglage
grads = {}
grads['W1'], grads['b1'] = self.layers['Affine1'].dW, self.layers['Affine1'].db
grads['W2'], grads['b2'] = self.layers['Affine2'].dW, self.layers['Affine2'].db
return grads
Cette source est simplement une source pour confirmer qu'il n'y a pratiquement aucune différence de gradient entre la propagation directe et la propagation arrière.
# coding: utf-8
import sys, os
sys.path.append(os.pardir) #Paramètres d'importation des fichiers dans le répertoire parent
import numpy as np
from dataset.mnist import load_mnist
from two_layer_net import TwoLayerNet
#Lire les données
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True)
network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10)
x_batch = x_train[:3]
t_batch = t_train[:3]
grad_numerical = network.numerical_gradient(x_batch, t_batch)
grad_backprop = network.gradient(x_batch, t_batch)
for key in grad_numerical.keys():
diff = np.average( np.abs(grad_backprop[key] - grad_numerical[key]) )
print(key + ":" + str(diff))
Résultat d'exécution dans mon environnement W1:2.61413510374e-13 > 2.610.1^-13 W2:1.04099504538e-12 > 1.040.1^-12 b1:9.1090807423e-13 > 9.10.1^-13 b2:1.20348173094e-10 > 1.20.1^-10
Cette source est essentiellement un mini-lot qui est entraîné de manière itérative (met à jour les poids et les biais).
# coding: utf-8
import sys, os
sys.path.append(os.pardir)
import numpy as np
from dataset.mnist import load_mnist
from two_layer_net import TwoLayerNet
#Lire les données
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True)
network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10)
iters_num = 10000
train_size = x_train.shape[0]
batch_size = 100
learning_rate = 0.1
train_loss_list = []
train_acc_list = []
test_acc_list = []
iter_per_epoch = max(train_size / batch_size, 1)
for i in range(iters_num):
batch_mask = np.random.choice(train_size, batch_size)
x_batch = x_train[batch_mask]
t_batch = t_train[batch_mask]
#Pente
#grad = network.numerical_gradient(x_batch, t_batch)
grad = network.gradient(x_batch, t_batch)
#mise à jour
for key in ('W1', 'b1', 'W2', 'b2'):
network.params[key] -= learning_rate * grad[key]
loss = network.loss(x_batch, t_batch)
train_loss_list.append(loss)
if i % iter_per_epoch == 0:
train_acc = network.accuracy(x_train, t_train)
test_acc = network.accuracy(x_test, t_test)
train_acc_list.append(train_acc)
test_acc_list.append(test_acc)
print(train_acc, test_acc)
Recommended Posts