Du coup, j'ai commencé à étudier au chapitre 5 de "Deep Learning from scratch-The Theory and implementation of deep learning appris with Python". C'est un mémo du voyage.
L'environnement d'exécution est macOS Mojave + Anaconda 2019.10, et la version Python est 3.7.4. Pour plus de détails, reportez-vous au Chapitre 1 de ce mémo.
(Vers d'autres chapitres de ce mémo: Chapitre 1 / Chapitre 2 / Chapitre 3 / Chapitre 4 / Chapitre 5 / [Chapitre 6](https: / /qiita.com/segavvy/items/ca4ac4c9ee1a126bff41) / Chapitre 7 / Chapitre 8 / Résumé)
Ce chapitre décrit la méthode de rétropropagation des erreurs pour accélérer le calcul des paramètres de poids dans l'apprentissage des réseaux de neurones.
Au fait, le mot «propagation» (denpa) est une traduction de Propagetion, mais il est également traduit par «propagation» (denpan), et le japonais est chaotique. J'ai trouvé un article sur un blog qui explorait ce domaine, donc si vous êtes intéressé, repos après avoir marché> [apprentissage automatique] La traduction de "Propagation" est "propagation" ou "propagation"? S'il vous plaît.
L'explication par le graphe de calcul est très facile à comprendre lors de l'apprentissage de la méthode de propagation des erreurs. Le secret de la popularité de ce livre peut être le chapitre 5.
L'apprentissage est essentiel pour les réseaux neuronaux, ce qui nécessite de trouver le gradient des paramètres de poids et de calculer la différenciation de chaque paramètre. En utilisant le graphe de calcul, nous pouvons voir que le calcul du différentiel peut être fait très efficacement en rétropropageant le différentiel local de l'arrière vers l'avant.
Il s'agit d'un examen de la formule différentielle de la fonction composite et de l'explication de la rétropropagation. Je ne pense pas que ce soit un problème de le lire, mais si vous voulez le comprendre correctement, vous avez besoin d'un examen de la différenciation au secondaire.
Je ne me souvenais pas du tout de la formule différentielle, alors j'ai décidé de la revoir après un long moment. Cependant, j'étudie souvent après la fin de mon activité principale, et quand il s'agit de livres et de sites Web, la somnolence m'attaque et j'ai du mal à entrer dans mon esprit. Il est assez difficile pour un salarié d'étudier dans l'intervalle de temps.
Ce que j'ai trouvé là-bas était Triit, qui est fait par un professeur au foyer, Try. Bien qu'il s'agisse d'un cours vidéo, il est très facile à comprendre même s'il est gratuit, et il est divisé en environ 15 minutes, il est donc idéal pour étudier avec un smartphone en voyage ou en pause. C'est un service pour les étudiants, mais je pense que c'est aussi très approprié pour évaluer les travailleurs.
Pour référence, voici un lien vers une vidéo sur la partie introductive de la différenciation. Veuillez noter qu'il est limité à la visualisation privée.
Une description de la rétropropagation des nœuds d'ajout et de multiplication. La rétropropagation est facile à calculer car la différenciation est simple pour l'addition et la multiplication.
Il s'agit de l'implémentation de la couche d'addition et de la couche de multiplication dans la section précédente. La différenciation étant simple, elle est facile à mettre en œuvre.
Une implémentation de la couche de fonction d'activation.
Comme ReLU a un calcul simple de différenciation, il est facile à mettre en œuvre et est susceptible de conduire à un apprentissage plus rapide. Voici le code implémenté.
relu.py
# coding: utf-8
class ReLU:
def __init__(self):
"""Couche ReLU
"""
self.mask = None
def forward(self, x):
"""Propagation vers l'avant
Args:
x (numpy.ndarray):contribution
Returns:
numpy.ndarray:production
"""
self.mask = (x <= 0)
out = x.copy()
out[self.mask] = 0
return out
def backward(self, dout):
"""Rétropropagation
Args:
dout (numpy.ndarray):Valeur de différenciation transmise depuis la bonne couche
Returns:
numpy.ndarray:Valeur de différenciation
"""
dout[self.mask] = 0
dx = dout
return dx
La différenciation de la fonction sigmoïde est un peu compliquée, mais elle peut être calculée petit à petit à l'aide du graphe de calcul. Cependant, la différenciation de $ y = \ frac {1} {x} $ requise pour le premier nœud "/" et la différenciation de $ y = exp (x) $ pour le nœud "$ exp $" ne vérifient pas la formule. C'est épicé. Quant aux formules dans ce domaine, il est recommandé que Mathématiques apprises à partir d'exemples concrets> Intégration mineure> Organiser les 59 formules différentielles avec importance soit simplement organisé.
Après le calcul par le graphe de calcul, il se transforme en formule (5.12) du livre, mais au début je n'ai pas compris le flux de transformation de la deuxième ligne de la fin à la dernière ligne. Il sera plus facile à comprendre si vous insérez une ligne entre les deux comme suit.
\begin{align}
\frac{\partial L}{\partial y}y^2exp(-x) &= \frac{\partial L}{\partial y} \frac{1}{(1+exp(-x))^2} exp(-x) \\
&=\frac{\partial L}{\partial y} \frac{1}{1+exp(-x)} \frac{exp(-x)}{1+exp(-x)} \\
&=\frac{\partial L}{\partial y} \frac{1}{1+exp(-x)} \biggl(\frac{1+exp(-x)}{1+exp(-x)} - \frac{1}{1+exp(-x)}\biggr)← Ligne ajoutée\\
&=\frac{\partial L}{\partial y} y(1-y)
\end{align}
Ce qui est surprenant dans ce résultat, c'est qu'il est très facile à calculer avec $ y $, qui est la sortie de la propagation directe. Dans la méthode de propagation des erreurs en retour, la propagation vers l'avant est calculée en premier, donc si vous avez le résultat, cela conduira à un apprentissage plus rapide. La caractéristique que même si $ e ^ x $ est différencié, il devient $ e ^ x $ est également importante, et c'est vraiment incroyable pour ceux qui pensent à la fonction sigmoïde.
La couche sigmoïde n'est pas utilisée dans ce chapitre, donc le code est omis.
Le processus de calcul est omis dans la formule de rétropropagation de la couche Affine (5.13), mais @yuyasat [calcule régulièrement les composants de la rétropropagation de la couche Affine](https://qiita.com/yuyasat/items/ Le processus de calcul est résumé dans d9cdd4401221df5375b6) pour votre référence.
Voici le code implémenté. De plus, dans le code du livre, on tient compte du moment où les données d'entrée sont tenseur (données 4D), mais elles ne sont pas incluses car l'usage n'est pas encore connu.
affine.py
# coding: utf-8
import numpy as np
class Affine:
def __init__(self, W, b):
"""Couche affine
Args:
W (numpy.ndarray):poids
b (numpy.ndarray):biais
"""
self.W = W #poids
self.b = b #biais
self.x = None #contribution
self.dW = None #Valeur différentielle du poids
self.db = None #Valeur différentielle du biais
def forward(self, x):
"""Propagation vers l'avant
Args:
x (numpy.ndarray):contribution
Returns:
numpy.ndarray:production
"""
self.x = x
out = np.dot(x, self.W) + self.b
return out
def backward(self, dout):
"""Rétropropagation
Args:
dout (numpy.ndarray):Valeur de différenciation transmise depuis la bonne couche
Returns:
numpy.ndarray:Valeur de différenciation
"""
dx = np.dot(dout, self.W.T)
self.dW = np.dot(self.x.T, dout)
self.db = np.sum(dout, axis=0)
return dx
Rétropropagation d'une couche avec une fonction softmax et une erreur d'entropie croisée en tant qu'ensemble. Le processus de calcul est décrit en détail dans l'annexe A du livre, mais même si $ e ^ x $ est différencié, il devient $ e ^ x $, et lorsque tous les vecteurs one-hot de l'étiquette enseignant sont ajoutés, il devient 1. Etc. contribuent à simplifier la formule.
Le résultat final de $ (y_1-t_1, y_2-t_2, y_3-t_3) $ est également surprenant. Il montre la différence entre la sortie du réseau de neurones et l'étiquette de l'enseignant, et peut être calculé rapidement. Il semble que l'erreur d'entropie croisée soit conçue pour être «propre» lorsqu'elle est utilisée comme fonction de perte de la fonction softmax, et c'est vraiment étonnant pour ceux qui pensent à l'erreur d'entropie croisée.
De plus, il est nécessaire de diviser la valeur de la rétro-propagation par le nombre de lots pour correspondre aux lots. Dans le livre, il y avait seulement une explication que "en divisant la valeur à propager par le nombre de lots (batch_size), l'erreur par données est propagée à la couche précédente", et je ne comprenais pas pourquoi il était nécessaire de diviser par le nombre de lots. Cependant, j'ai pu le comprendre grâce à l'explication du code de @ Yoko303 Deep Learning from scratch ~ Softmax-with-Loss layer ~. Dans la version batch de propagation directe, les erreurs d'entropie croisée sont finalement additionnées et divisées par le nombre de lots (batch_size) pour obtenir une valeur. La rétropropagation nécessite également le calcul de cette pièce, et sa valeur différentielle est $ \ frac {1} {batch_size} $. Ci-dessous, j'ai écrit le graphique de calcul pour cette partie.
Je pense que cette compréhension est correcte, mais veuillez signaler toute erreur. Voici le code implémenté.
softmax_with_loss.py
# coding: utf-8
from functions import softmax, cross_entropy_error
class SoftmaxWithLoss:
def __init__(self):
"""Softmax-with-Couche de perte
"""
self.loss = None #perte
self.y = None #sortie de softmax
self.t = None #Données de l'enseignant (une-hot vector)
def forward(self, x, t):
"""Propagation vers l'avant
Args:
x (numpy.ndarray):contribution
t (numpy.ndarray):Données des enseignants
Returns:
float:Erreur d'entropie croisée
"""
self.t = t
self.y = softmax(x)
self.loss = cross_entropy_error(self.y, self.t)
return self.loss
def backward(self, dout=1):
"""Rétropropagation
Args:
dout (float, optional):La valeur différentielle transmise depuis la couche droite. La valeur par défaut est 1.
Returns:
numpy.ndarray:Valeur de différenciation
"""
batch_size = self.t.shape[0] #Nombre de lots
dx = (self.y - self.t) * (dout / batch_size)
return dx
Notez que le code du livre n'utilise pas dout
in backward
. Puisque dout
est utilisé uniquement avec 1 spécifié, il n'y a pas de problème de fonctionnement, mais je pense que c'est probablement une erreur.
Il s'agit d'un examen du flux de mise en œuvre. Il n'y a pas d'obstacle particulier.
Le premier est la mise en œuvre de fonctions à usage général. J'ai apporté seulement ce dont j'avais besoin de ce que j'avais écrit dans le chapitre précédent.
functions.py
# coding: utf-8
import numpy as np
def softmax(x):
"""Fonction Softmax
Args:
x (numpy.ndarray):contribution
Returns:
numpy.ndarray:production
"""
#Pour le traitement par lots, x est(Nombre de lots, 10)Il devient un tableau bidimensionnel de.
#Dans ce cas, il est nécessaire de bien calculer pour chaque image en utilisant la diffusion.
#Ici, np afin qu'il puisse être partagé en 1 et 2 dimensions..max()Et np.sum()Est axe=-Calculé par 1
#Keepdims pour qu'il puisse être diffusé tel quel=Vrai pour maintenir la dimension.
c = np.max(x, axis=-1, keepdims=True)
exp_a = np.exp(x - c) #Mesures de débordement
sum_exp_a = np.sum(exp_a, axis=-1, keepdims=True)
y = exp_a / sum_exp_a
return y
def numerical_gradient(f, x):
"""Calcul du gradient
Args:
f (function):Fonction de perte
x (numpy.ndarray):Un tableau de paramètres de poids pour lesquels vous souhaitez vérifier le dégradé
Returns:
numpy.ndarray:Pente
"""
h = 1e-4
grad = np.zeros_like(x)
# np.Énumérer les éléments d'un tableau multidimensionnel avec nditer
it = np.nditer(x, flags=['multi_index'])
while not it.finished:
idx = it.multi_index # it.multi_index est le numéro de l'élément dans la liste
tmp_val = x[idx] #Enregistrer la valeur d'origine
# f(x + h)Calculs de
x[idx] = tmp_val + h
fxh1 = f()
# f(x - h)Calculs de
x[idx] = tmp_val - h
fxh2 = f()
#Calculer le gradient
grad[idx] = (fxh1 - fxh2) / (2 * h)
x[idx] = tmp_val #Valeur de retour
it.iternext()
return grad
def cross_entropy_error(y, t):
"""Calcul de l'erreur d'entropie croisée
Args:
y (numpy.ndarray):Sortie de réseau neuronal
t (numpy.ndarray):Étiquette de réponse correcte
Returns:
float:Erreur d'entropie croisée
"""
#S'il y a une donnée, formez-la (faites une ligne de données)
if y.ndim == 1:
t = t.reshape(1, t.size)
y = y.reshape(1, y.size)
#Calculer l'erreur et normaliser par le nombre de lots
batch_size = y.shape[0]
return -np.sum(t * np.log(y + 1e-7)) / batch_size
Et puis il y a la classe de réseau neuronal. Puisqu'il est basé sur le code du chapitre précédent, il y a beaucoup des mêmes parties.
two_layer_net.py
# coding: utf-8
import numpy as np
from affine import Affine
from functions import numerical_gradient
from relu import ReLU
from softmax_with_loss import SoftmaxWithLoss
class TwoLayerNet:
def __init__(self, input_size, hidden_size, output_size,
weight_init_std=0.01):
"""Réseau neuronal à deux couches
Args:
input_size (int):Nombre de neurones dans la couche d'entrée
hidden_size (int):Nombre de neurones de couche cachée
output_size (int):Nombre de neurones dans la couche de sortie
weight_init_std (float, optional):Paramètre de réglage de la valeur initiale du poids. La valeur par défaut est 0.01。
"""
#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)
#Génération de couches
self.layers = {} # Python 3.OrderedDict n'est pas nécessaire car l'ordre de stockage du dictionnaire est conservé à partir de 7
self.layers['Affine1'] = \
Affine(self.params['W1'], self.params['b1'])
self.layers['Relu1'] = ReLU()
self.layers['Affine2'] = \
Affine(self.params['W2'], self.params['b2'])
self.lastLayer = SoftmaxWithLoss()
def predict(self, x):
"""Inférence par réseau neuronal
Args:
x (numpy.ndarray):Entrée dans le réseau neuronal
Returns:
numpy.ndarray:Sortie de réseau neuronal
"""
#Propager les couches vers l'avant
for layer in self.layers.values():
x = layer.forward(x)
return x
def loss(self, x, t):
"""Calcul de la valeur de la fonction de perte
Args:
x (numpy.ndarray):Entrée dans le réseau neuronal
t (numpy.ndarray):Étiquette de réponse correcte
Returns:
float:Valeur de la fonction de perte
"""
#inférence
y = self.predict(x)
# Softmax-with-Calculé par propagation directe de la couche de perte
loss = self.lastLayer.forward(y, t)
return loss
def accuracy(self, x, t):
"""Calcul de la précision de la reconnaissance
Args:
x (numpy.ndarray):Entrée dans le réseau neuronal
t (numpy.ndarray):Étiquette de réponse correcte
Returns:
float:Précision de reconnaissance
"""
y = self.predict(x)
y = np.argmax(y, axis=1)
t = np.argmax(t, axis=1)
accuracy = np.sum(y == t) / x.shape[0]
return accuracy
def numerical_gradient(self, x, t):
"""Calculer le gradient du paramètre de poids par différenciation numérique
Args:
x (numpy.ndarray):Entrée dans le réseau neuronal
t (numpy.ndarray):Étiquette de réponse correcte
Returns:
dictionary:Un dictionnaire qui stocke les dégradés
"""
grads = {}
grads['W1'] = \
numerical_gradient(lambda: self.loss(x, t), self.params['W1'])
grads['b1'] = \
numerical_gradient(lambda: self.loss(x, t), self.params['b1'])
grads['W2'] = \
numerical_gradient(lambda: self.loss(x, t), self.params['W2'])
grads['b2'] = \
numerical_gradient(lambda: self.loss(x, t), self.params['b2'])
return grads
def gradient(self, x, t):
"""Calculer le gradient pour le paramètre de poids par la méthode de propagation de l'erreur en retour
Args:
x (numpy.ndarray):Entrée dans le réseau neuronal
t (numpy.ndarray):Étiquette de réponse correcte
Returns:
dictionary:Un dictionnaire qui stocke les dégradés
"""
#Propagation vers l'avant
self.loss(x, t) #Propager vers l'avant pour calculer la valeur de la perte
#Rétropropagation
dout = self.lastLayer.backward()
for layer in reversed(list(self.layers.values())):
dout = layer.backward(dout)
#Extraire la valeur différentielle de chaque couche
grads = {}
grads['W1'] = self.layers['Affine1'].dW
grads['b1'] = self.layers['Affine1'].db
grads['W2'] = self.layers['Affine2'].dW
grads['b2'] = self.layers['Affine2'].db
return grads
Le code dans le livre utilise ʻOrderedDict, mais ici nous utilisons l'habituel
dict. Ceci est dû au fait qu'à partir de Python 3.7, l'ordre d'insertion des objets
dict` est enregistré [^ 1].
Ce code compare le gradient obtenu par la méthode de rétro-propagation d'erreur avec le gradient obtenu par différenciation numérique.
gradient_check.py
# coding: utf-8
import os
import sys
import numpy as np
from two_layer_net import TwoLayerNet
sys.path.append(os.pardir) #Ajouter le répertoire parent au chemin
from dataset.mnist import load_mnist
#Lire les données d'entraînement MNIST et les données de test
(x_train, t_train), (x_test, t_test) = \
load_mnist(normalize=True, one_hot_label=True)
#Génération de travail neuronal à deux couches
network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10)
#Préparation des données pour vérification
x_batch = x_train[:3]
t_batch = t_train[:3]
#Calcul du gradient par différenciation numérique et méthode de propagation des erreurs
grad_numerical = network.numerical_gradient(x_batch, t_batch)
grad_backprop = network.gradient(x_batch, t_batch)
#Vérifiez la différence entre chaque poids
for key in grad_numerical.keys():
#Calcul de la différence absolue
diff = np.abs(grad_backprop[key] - grad_numerical[key])
#Afficher la moyenne et le maximum
print(f"{key}: [Différence moyenne]{np.average(diff):.10f} [Différence maximale]{np.max(diff):.10f}")
Dans le livre, je n'ai vérifié que la moyenne des différences de valeur absolue, mais j'ai également vérifié la valeur maximale des différences de valeur absolue.
W1: [Différence moyenne]0.0000000003 [Différence maximale]0.0000000080
b1: [Différence moyenne]0.0000000021 [Différence maximale]0.0000000081
W2: [Différence moyenne]0.0000000063 [Différence maximale]0.0000000836
b2: [Différence moyenne]0.0000001394 [Différence maximale]0.0000002334
Puisque «b2» est une valeur d'environ 7 chiffres après la virgule décimale, il semble que l'erreur soit un peu plus grande que le livre. Il peut y avoir un mauvais point dans la mise en œuvre. Si vous avez des questions, n'hésitez pas à me le faire savoir: transpiration:
Voici le code d'apprentissage.
mnist.py
# coding: utf-8
import os
import sys
import matplotlib.pylab as plt
import numpy as np
from two_layer_net import TwoLayerNet
sys.path.append(os.pardir) #Ajouter le répertoire parent au chemin
from dataset.mnist import load_mnist
#Lire les données d'entraînement MNIST et les données de test
(x_train, t_train), (x_test, t_test) = \
load_mnist(normalize=True, one_hot_label=True)
#Paramètres des hyper paramètres
iters_num = 10000 #Nombre de mises à jour
batch_size = 100 #Taille du lot
learning_rate = 0.1 #Taux d'apprentissage
#Enregistrer la liste des résultats
train_loss_list = [] #Modifications de la valeur de la fonction de perte
train_acc_list = [] #Précision de reconnaissance des données d'entraînement
test_acc_list = [] #Précision de reconnaissance des données de test
train_size = x_train.shape[0] #Taille des données d'entraînement
iter_per_epoch = max(int(train_size / batch_size), 1) #Nombre d'itérations par époque
#Génération de travail neuronal à deux couches
network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10)
#Commencer à apprendre
for i in range(iters_num):
#Mini génération de lots
batch_mask = np.random.choice(train_size, batch_size, replace=False)
x_batch = x_train[batch_mask]
t_batch = t_train[batch_mask]
#Calcul du gradient
grad = network.gradient(x_batch, t_batch)
#Mise à jour des paramètres de poids
for key in ('W1', 'b1', 'W2', 'b2'):
network.params[key] -= learning_rate * grad[key]
#Calcul de la valeur de la fonction de perte
loss = network.loss(x_batch, t_batch)
train_loss_list.append(loss)
#Calcul de la précision de la reconnaissance pour chaque époque
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)
#Affichage de la progression
print(f'[Nombre de mises à jour]{i:>4} [Valeur de la fonction de perte]{loss:.4f} '
f'[Reconnaissance de l'exactitude des données d'entraînement]{train_acc:.4f} [Précision de reconnaissance des données de test]{test_acc:.4f}')
#Tracez la transition de la valeur de la fonction de perte
x = np.arange(len(train_loss_list))
plt.plot(x, train_loss_list, label='loss')
plt.xlabel('iteration')
plt.ylabel('loss')
plt.xlim(left=0)
plt.ylim(bottom=0)
plt.show()
#Dessinez la transition de la précision de reconnaissance des données d'entraînement et des données de test
x2 = np.arange(len(train_acc_list))
plt.plot(x2, train_acc_list, label='train acc')
plt.plot(x2, test_acc_list, label='test acc', linestyle='--')
plt.xlabel('epochs')
plt.ylabel('accuracy')
plt.xlim(left=0)
plt.ylim(0, 1.0)
plt.legend(loc='lower right')
plt.show()
Et c'est le résultat de l'exécution de la même forme que le chapitre précédent.
[Nombre de mises à jour] 0 [Valeur de la fonction de perte]2.3008 [Reconnaissance de l'exactitude des données d'entraînement]0.0926 [Précision de reconnaissance des données de test]0.0822
[Nombre de mises à jour] 600 [Valeur de la fonction de perte]0.2575 [Reconnaissance de l'exactitude des données d'entraînement]0.9011 [Précision de reconnaissance des données de test]0.9068
[Nombre de mises à jour]1200 [Valeur de la fonction de perte]0.2926 [Reconnaissance de l'exactitude des données d'entraînement]0.9219 [Précision de reconnaissance des données de test]0.9242
[Nombre de mises à jour]1800 [Valeur de la fonction de perte]0.2627 [Reconnaissance de l'exactitude des données d'entraînement]0.9324 [Précision de reconnaissance des données de test]0.9341
[Nombre de mises à jour]2400 [Valeur de la fonction de perte]0.0899 [Reconnaissance de l'exactitude des données d'entraînement]0.9393 [Précision de reconnaissance des données de test]0.9402
[Nombre de mises à jour]3000 [Valeur de la fonction de perte]0.1096 [Reconnaissance de l'exactitude des données d'entraînement]0.9500 [Précision de reconnaissance des données de test]0.9483
[Nombre de mises à jour]3600 [Valeur de la fonction de perte]0.1359 [Reconnaissance de l'exactitude des données d'entraînement]0.9559 [Précision de reconnaissance des données de test]0.9552
[Nombre de mises à jour]4200 [Valeur de la fonction de perte]0.1037 [Reconnaissance de l'exactitude des données d'entraînement]0.9592 [Précision de reconnaissance des données de test]0.9579
[Nombre de mises à jour]4800 [Valeur de la fonction de perte]0.1065 [Reconnaissance de l'exactitude des données d'entraînement]0.9639 [Précision de reconnaissance des données de test]0.9600
[Nombre de mises à jour]5400 [Valeur de la fonction de perte]0.0419 [Reconnaissance de l'exactitude des données d'entraînement]0.9665 [Précision de reconnaissance des données de test]0.9633
[Nombre de mises à jour]6000 [Valeur de la fonction de perte]0.0393 [Reconnaissance de l'exactitude des données d'entraînement]0.9698 [Précision de reconnaissance des données de test]0.9649
[Nombre de mises à jour]6600 [Valeur de la fonction de perte]0.0575 [Reconnaissance de l'exactitude des données d'entraînement]0.9718 [Précision de reconnaissance des données de test]0.9663
[Nombre de mises à jour]7200 [Valeur de la fonction de perte]0.0850 [Reconnaissance de l'exactitude des données d'entraînement]0.9728 [Précision de reconnaissance des données de test]0.9677
[Nombre de mises à jour]7800 [Valeur de la fonction de perte]0.0403 [Reconnaissance de l'exactitude des données d'entraînement]0.9749 [Précision de reconnaissance des données de test]0.9686
[Nombre de mises à jour]8400 [Valeur de la fonction de perte]0.0430 [Reconnaissance de l'exactitude des données d'entraînement]0.9761 [Précision de reconnaissance des données de test]0.9685
[Nombre de mises à jour]9000 [Valeur de la fonction de perte]0.0513 [Reconnaissance de l'exactitude des données d'entraînement]0.9782 [Précision de reconnaissance des données de test]0.9715
[Nombre de mises à jour]9600 [Valeur de la fonction de perte]0.0584 [Reconnaissance de l'exactitude des données d'entraînement]0.9777 [Précision de reconnaissance des données de test]0.9707
Par rapport aux résultats du chapitre précédent, la précision de la reconnaissance augmente plus rapidement. En fin de compte, c'était environ 97%. La seule différence entre la différenciation numérique et la méthode de propagation de l'erreur en retour devrait être la méthode de calcul du gradient, il semble donc que le changement de la fonction sigmoïde à la fonction ReLU a conduit à une amélioration.
Le graphique de calcul doit être facile à comprendre. Il était également bien entendu que la couche de sortie et la fonction de perte étaient conçues de manière à ce que la valeur différentielle puisse être facilement obtenue.
C'est tout pour ce chapitre. Si vous avez des erreurs, je vous serais reconnaissant de bien vouloir les signaler. (Vers d'autres chapitres de ce mémo: Chapitre 1 / Chapitre 2 / Chapitre 3 / Chapitre 4 / Chapitre 5 / [Chapitre 6](https: / /qiita.com/segavvy/items/ca4ac4c9ee1a126bff41) / Chapitre 7 / Chapitre 8 / Résumé)
[^ 1]: Voir «Amélioration du modèle de données Python» dans Nouveautés de Python 3.7.