L'article précédent était ici. Dans cet article, nous examinerons la mise en œuvre des règles d'apprentissage. Cependant, le corps principal a déjà été installé sur ici, alors jetez un œil.
Le prochain article est ici
__init__
](Implémentation de la méthode #init)Tout d'abord, je penserai avec scalaire comme d'habitude. Les objets Neuron ont des variables $ w et b $.
y = \sigma(xw + b)
Ici, si l'entrée $ x $ est considérée comme une constante
y = f(w, b) = \sigma(xw + b)
Peut être écrit comme En d'autres termes, le but de la règle d'apprentissage est de changer les valeurs de $ w et b $ de manière appropriée pour les rapprocher de la valeur cible $ y ^ {\ star} $. </ font>
Regardons cela théoriquement.
y = f(w, b) = \sigma(wx + b)
Dans
\begin{align}
y &= y^{\star} = 0.5 \\
x &= x_0 = 1
\end{align}
Ensuite, si la fonction d'activation est la fonction sigmoïde et que l'espace des paramètres de $ w et b $ est illustré, ce sera comme suit.
<détails> La figure montre l'espace de perte lorsque l'erreur quadratique est utilisée pour la fonction de perte.
La règle d'apprentissage est que la valeur initiale aléatoire $ w_0, b_0 $ s'approche progressivement de $ w ^ {\ star}, b ^ {\ star} $, ce qui donne la valeur optimale $ y ^ {\ star} $. C'est le but de. </ font>
À ce stade, la règle d'apprentissage est la ** méthode de descente de gradient **, qui est une évolution de la ** méthode de descente la plus raide **.
La méthode de descente de gradient est une méthode de descente d'une pente utilisant ** gradient (différenciation partielle) en un certain point de chaque paramètre.
Ici contient des formules et des codes pour chaque méthode.
De plus, ici montre la descente dans certains espaces d'exploration.
<img src=https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F640911%2F6f55cfbc-4a9f-d4fe-c70e-49dca7cbf683.gif?ixlib=rb-1.2.2&auto=format&gif-q=60&q=75&s=02b37020417dbead312cc8c82f5eac7e> Cet article traite du SGD le plus simple.
La formule de SGD est la suivante. Cette formule ne répertorie que $ w $, mais vous pouvez voir que si vous la remplacez par $ b $, la règle d'apprentissage du biais sera la même.
Pensez à $ \ mathcal {L} (w_t, b_t) $ comme une fonction de perte et $ \ nabla_ {w_t} $ comme un différentiel partiel pour $ w_t $ (la formule ci-dessus est une représentation matricielle). </ font>
Exprimer la formule ci-dessus en japonais --Trouver le gradient par différenciation partielle
--Calculer la quantité de mouvement On dirait. C'est simple. Regardons de plus près. La première "recherche du gradient par différenciation partielle" utilise la méthode de propagation de retour d'erreur introduite dans Back Propagation. C'est très bien. "Déplacer" est également littéral. Concernant la partie "calcul de la quantité de mouvement" Je voudrais parler de deux points. Tout d'abord, en ce qui concerne 1., je pense que c'est facile à comprendre si vous y réfléchissez concrètement.
Par exemple, la pente au point de $ (x, y) = (1, 1) $ est $ 2 $, mais la direction que vous voulez déplacer est la direction moins, n'est-ce pas? Bien sûr, l'inverse est également vrai. Par conséquent, la direction et le dégradé que vous souhaitez déplacer sont toujours opposés, ils sont donc négatifs.
Quant à 2., comme vous pouvez le voir sur le graphique, si vous utilisez la pente $ 2 $ telle quelle et définissez $ \ Delta x = -2 $ etc., ce sera $ x = -1 $ et il passera la valeur optimale. .. </ font>
Par conséquent, nous multiplions le coefficient $ \ eta \ ll 1 $ appelé taux d'apprentissage pour limiter la quantité de mouvement afin qu'elle tombe progressivement vers la valeur optimale.
Ce taux d'apprentissage est une valeur appelée ** hyperparamètre **, et il existe de nombreuses règles d'apprentissage que les humains doivent concevoir pour cette partie.
Dans la plupart des cas, l'utilisation des valeurs par défaut indiquées dans les articles fonctionnera, mais en fonction du problème que vous souhaitez résoudre, vous devrez peut-être expérimenter. Eh bien, mis à part les détails, implémentons-le pour le moment. La destination de mise en œuvre est comme d'habitude [baselayer.py](https://qiita.com/kuroitu/items/884c62c48c2daa3def08#%E3%83%AC%E3%82%A4%E3%83%A4%E3%83%BC % E3% 83% A2% E3% 82% B8% E3% 83% A5% E3% 83% BC% E3% 83% AB% E3% 81% AE% E3% 82% B3% E3% 83% BC% E3 % 83% 89% E6% BA% 96% E5% 82% 99). La partie de Le contenu du code est conforme à la formule présentée ci-dessus. Reçoit le gradient concernant $ w et b $ de l'extérieur, et selon la règle d'apprentissage, le multiplie par $ - \ eta $ pour déterminer la quantité de mouvement et le renvoyer. </ font>
L'objet de calque reçoit cette quantité de mouvement et met à jour ses propres paramètres. Eh bien, c'est tout pour cette fois. Vous vous demandez peut-être: "Quoi? Dans le cas d'une file d'attente?"
En fait, le code est exactement le même pour les matrices. [optimizers.py](https://qiita.com/kuroitu/items/36a58b37690d570dc618#%E5%AE%9F%E8%A3%85%E3%82%B3%E3%83%BC%E3%83%89 Même si vous regardez% E4% BE% 8B), vous ne trouvez pas le calcul du produit matriciel. La raison est naturelle quand on y pense, mais même si on apprend avec un mini-lot, le gradient qui s'écoule doit être unique à chaque paramètre, et il est nécessaire de calculer en faisant intervenir les gradients d'autres paramètres. Parce qu'il n'y a pas.
Donc, cette fois, si vous y pensez avec un scalaire et que vous l'implémentez, vous pouvez le calculer avec une matrice de la même manière. Enfin, faisons en sorte que l'objet layer ait l'optimiseur ʻopt La prochaine fois, je présenterai la localisation de la fonction d'activation et de l'optimiseur, ainsi que la fonction de perte.
Recommended Posts
show_loss_space.py
%matplotlib nbagg
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
x_0 = 1
y_star = 0.5
sigma = lambda x: 1/(1+np.exp(-x))
w = np.arange(-2, 2, 1e-2)
b = np.arange(-2, 2, 1e-2)
W, B = np.meshgrid(w, b)
y = 0.5*(sigma(x_0*W + B) - y_star)**2
elevation = np.arange(np.min(y), np.max(y), 1/2**8)
fig = plt.figure()
ax = fig.add_subplot(111, projection="3d")
ax.set_xlabel("w")
ax.set_ylabel("b")
ax.set_zlabel("loss")
ax.view_init(60)
ax.grid()
ax.plot_surface(W, B, y, cmap="autumn", alpha=0.8)
ax.contour(W, B, y, cmap="autumn", levels=elevation, alpha=0.8)
fig.suptitle("Loss space")
fig.show()
fig.savefig("Loss_space.png ")
\begin{align}
g_t &= \nabla_{w_t}\mathcal{L}(w_t, b_t) \\
\Delta w_t &= - \eta g_t \\
w_{t+1} &= w_t + \Delta w_t
\end{align}
Implémentation des règles d'apprentissage
baselayer.py
baselayer.py
def update(self, **kwds):
"""
Mise en œuvre de l'apprentissage des paramètres
"""
dw, db = self.opt.update(self.grad_w, self.grad_b, **kwds)
self.w += dw
self.b += db
self.opt.update (self.grad_w, self.grad_b, ** kwds)
est lancée à ici. Voici le code SGD à titre d'exemple.optimizers.py
optimziers.py
import numpy as np
class Optimizer():
"""
Une super classe héritée de la méthode d'optimisation.
"""
def __init__(self, *args, **kwds):
pass
def update(self, *args, **kwds):
pass
class SGD(Optimizer):
def __init__(self, eta=1e-2, *args, **kwds):
super().__init__(*args, **kwds)
self.eta = eta
def update(self, grad_w, grad_b, *args, **kwds):
dw = -self.eta*grad_w
db = -self.eta*grad_b
return dw, db
Implémentation de la méthode
__init __
avec la méthode
__init __`.__init__.py
def __init__(self, *, prev=1, n=1,
name="", wb_width=1,
act="ReLU", err_func="square", opt="Adam",
act_dict={}, opt_dict={}, **kwds):
self.prev = prev #Nombre de sorties de la couche précédente=Nombre d'entrées dans cette couche
self.n = n #Nombre de sorties dans cette couche=Nombre d'entrées vers la couche suivante
self.name = name #Le nom de cette couche
#Définir le poids et le biais
self.w = wb_width*np.random.randn(prev, n)
self.b = wb_width*np.random.randn(n)
#Fonction d'activation(classe)Avoir
self.act = get_act(act, **act_dict)
#Fonction de perte(classe)Avoir
self.errfunc = get_errfunc(err_func)
#Optimiseur(classe)Avoir
self.opt = get_opt(opt, **opt_dict)
en conclusion
Série d'apprentissage en profondeur