Ceci est un article d'introduction sur le Deep Learning, qui est populaire de nos jours. Deep Learning a déjà d'abondantes bibliothèques open source, et cette fois nous utiliserons chainer, qui a une bonne réputation au Japon et a un certain article que le calcul GPU est relativement rapide à l'heure actuelle.
Cependant, il existe de nombreux articles d'introduction sur Chainer, mais la plupart d'entre eux ont été complétés en exécutant un exemple de mnist qui reconnaît les caractères manuscrits. Certes, si vous regardez l'exemple de mnist, vous pouvez comprendre comment utiliser Chainer, mais d'une manière ou d'une autre, c'est différent de pouvoir le construire vous-même, donc cette fois, c'est au point où vous pouvez construire vous-même le Deep Learning en utilisant chainer. Je vais le faire avec le but.
・ Système d'exploitation: Mac OS X EL Capitan (10.11.5) · Python 2.7.12: Anaconda 4.1.1 (x86_64) ・ Chainer 1.12.0
Si vous n'avez pas préparé l'environnement de chaînage,
$ pip install chainer
Vous pouvez facilement l'installer sur.
Ici, nous discuterons des calculs avant et arrière à l'aide de variables, ce qui est l'étape avant d'entrer dans le réseau neuronal.
Tout d'abord, chargez le chainer et déclarez les variables.
>>> import chainer
>>> x_data = np.array([5], dtype=np.float32)
>>> x_data
array([ 5.], dtype=float32)
Fondamentalement, il semble le déclarer comme un type flottant d'un tableau de numpy.
Utilisez `` chainer.Variable '' comme variable à utiliser dans le chainer.
>>> x = chainer.Variable(x_data)
>>> x
<variable at 0x10b796fd0>
Vous pouvez vérifier la valeur de x dans
.data```.
>>> x.data
array([ 5.], dtype=float32)
Ensuite, déclarez la fonction y de x.
Cette fois, nous utiliserons la fonction suivante.
>>> y = x ** 2 - 2 * x + 1
>>> y
<variable at 0x10b693dd0>
Vous pouvez vérifier la valeur de y de la même manière.
>>> y.data
array([ 16.], dtype=float32)
En appelant la méthode suivante, il sera possible de calculer la différenciation.
>>> y.backward()
Le gradient de rétro-propagation est
grad ''.
>>> x.grad
array([ 8.], dtype=float32)
Il est un peu difficile de comprendre à quel gradient il s'agit, mais la valeur du gradient lorsque y est différencié par x.
y'(x) = 2x - 2\\
\rightarrow \ y'(5) = 8
La valeur 8 '' de
`` x.grad``` est dérivée de.
Dans Référence officielle de Chainer, si x est un tableau multidimensionnel, initialisez y.grad``` Après cela, il dit de calculer
x.grad```.
Si vous ne l'initialisez pas, il sera ajouté au tableau qui stocke la valeur du dégradé, rappelez-vous donc que "initialiser avant le calcul du dégradé".
>>> x = chainer.Variable(np.array([[1, 2, 3], [4, 5, 6]], dtype=np.float32))
>>> y = x**2 - 2*x + 1
>>> y.grad = np.ones((2, 3), dtype=np.float32)
>>> y.backward()
>>> x.grad
array([[ 0., 2., 4.],
[ 6., 8., 10.]], dtype=float32)
Lors de la configuration du réseau neuronal, déclarez explicitement le type de modèle structurel à configurer (en particulier, combien de nœuds et combien de couches). La décision sur ce modèle dépend toujours de l'expérience et de l'intuition. Le réseau neuronal, y compris le Deep Learning, ajuste automatiquement les hyper paramètres internes, mais le premier modèle doit être déterminé à l'avance. C'est un peu hors sujet, mais même dans les statistiques bayésiennes, la chaîne de Markov de Monte Carlo (MCMC) est conçue pour être capable d'estimer la distribution postérieure bien basée sur le théorème bayésien, mais même dans ce cas, la distribution a priori doit être déterminée arbitrairement. .. Qu'il s'agisse de réseaux de neurones ou de statistiques bayésiennes, j'espère que si une méthode historique pour résoudre ce domaine est proposée, un modèle prédictif pourra être construit afin qu'il puisse répondre universellement à n'importe quel problème.
Revenons à l'histoire, mais rendons possible d'appeler chainer sous forme abrégée dans le code python.
>>> import chainer.links as L
Comme le sait quiconque étudie Neural Network, il existe un paramètre appelé poids entre ces nœuds. Pour l'instant, essayons le modèle de connexion linéaire le plus simple.
>>> f = L.Linear(3, 2)
>>> f
<chainer.links.connection.linear.Linear object at 0x10b7b4290>
Cela montre une structure avec 3 couches d'entrée et 2 couches de sortie.
linear
Pour expliquer brièvement la partie de, cela signifie que les nœuds sont connectés par la connexion linéaire mentionnée précédemment, elle est donc exprimée par l'expression relationnelle suivante.
f(x) = Wx + b\\
f \in \mathcal{R}^{2 \times 1},
x \in \mathcal{R}^{3 \times 1},\\
W \in \mathcal{R}^{2 \times 3}, b \in \mathcal{R}^{2 \times 1}
Par conséquent, bien que non explicitement déclaré, le f '' déclaré ci-dessus a les paramètres
W et le vecteur de poids `` b
. Je suis.
>>> f.W.data
array([[-0.02878495, 0.75096768, -0.10530342],
[-0.26099312, 0.44820449, -0.06585278]], dtype=float32)
>>> f.b.data
array([ 0., 0.], dtype=float32)
Si vous l'implémentez sans connaître les spécifications internes ici, ce sera incompréhensible. Au fait, même si je ne me souviens pas avoir initialisé la matrice de poids `` W '', elle a une valeur au hasard lorsque le lien linéaire est déclaré en raison des spécifications du chainer. Il semble que ce soit parce qu'il est secoué.
Par conséquent, comme vous pouvez le voir dans la documentation officielle du chainer, c'est le format le plus couramment utilisé.
>>> f = L.Linear(3, 2)
>>> x = chainer.Variable(np.array([[1, 2, 3], [4, 5, 6]], dtype=np.float32))
>>> y = f(x)
>>> y.data
array([[ 1.15724015, 0.43785751],
[ 3.0078783 , 0.80193317]], dtype=float32)
Vous pouvez voir que x, qui était un vecteur tridimensionnel, est transformé en y bidimensionnel par couplage linéaire. À ce moment, la valeur initiale est automatiquement affectée à la matrice de poids W en interne, ce calcul peut donc être effectué sans générer d'erreur.
Pour confirmation, quand j'ai regardé la valeur de poids, la valeur initiale a certainement été attribuée.
>>> f.W.data
array([[-0.02878495, 0.75096768, -0.10530342],
[-0.26099312, 0.44820449, -0.06585278]], dtype=float32)
>>> f.b.data
array([ 0., 0.], dtype=float32)
Ensuite, nous calculerons le gradient appris dans le chapitre précédent. La documentation officielle du chainer insiste beaucoup, mais la valeur de chaque gradient s'accumule à chaque calcul. Par conséquent, vous devez généralement initialiser la valeur du dégradé à 0 avec la méthode suivante avant de calculer la valeur de chaque dégradé.
>>> f.zerograds()
Assurez-vous que les valeurs de pente sont correctement initialisées.
>>> f.W.grad
array([[ 0., 0., 0.],
[ 0., 0., 0.]], dtype=float32)
>>> f.b.grad
array([ 0., 0.], dtype=float32)
Calculons maintenant la valeur de chaque dégradé.
>>> y.grad = np.ones((2, 2), dtype=np.float32)
>>> y.backward()
>>> f.W.grad
array([[ 5., 7., 9.],
[ 5., 7., 9.]], dtype=float32)
>>> f.b.grad
array([ 2., 2.], dtype=float32)
Vous pouvez le calculer correctement.
Nous étendrons le modèle explicitement défini dans le chapitre précédent en plusieurs couches.
>>> l1 = L.Linear(4, 3)
>>> l2 = L.Linear(3, 2)
Pour le moment, vérifions le poids de chaque modèle.
>>> l1.W.data
array([[-0.2187428 , 0.51174778, 0.30037731, -1.08665013],
[ 0.65367842, 0.23128517, 0.25591806, -1.0708735 ],
[-0.85425782, 0.25255874, 0.23436508, 0.3276397 ]], dtype=float32)
>>> l1.b.data
array([ 0., 0., 0.], dtype=float32)
>>> l2.W.data
array([[-0.18273738, -0.64931035, -0.20702939],
[ 0.26091203, 0.88469893, -0.76247424]], dtype=float32)
>>> l2.b.data
array([ 0., 0.], dtype=float32)
La structure de chaque modèle est définie ci-dessus. Ensuite, nous clarifierons la structure globale, par exemple comment les modèles qui définissent ces structures sont connectés.
>>> x = chainer.Variable(np.array([[1, 2, 3, 4], [5, 6, 7, 8]], dtype=np.float32))
>>> x.data
array([[ 1., 2., 3., 4.],
[ 5., 6., 7., 8.]], dtype=float32)
>>> h = l1(x)
>>> y = l2(h)
>>> y.data
array([[ 1.69596863, -4.08097076],
[ 1.90756595, -4.22696018]], dtype=float32)
Pour les rendre réutilisables, la documentation officielle recommande de créer des classes comme suit:
MyChain.py
# -*- coding: utf-8 -*-
from chainer import Chain
import chainer.links as L
class MyChain(Chain):
def __init__(self):
super(MyChain, self).__init__(
l1 = L.Linear(4, 3),
l2 = L.Linear(3, 2) )
def __call__(self, x):
h = self.l1(x)
return self.l2(h)
Ensuite, nous optimiserons les poids du modèle de réseau neuronal. Il existe plusieurs méthodes pour optimiser ce poids, mais honnêtement, il ne semble pas y avoir de critère clair pour lequel utiliser, nous utilisons donc ici la méthode Stocastic Gradient Descent (SGD). Faire. La différence de performances en fonction de la méthode d'optimisation est expliquée dans Quelle méthode d'optimisation présente les meilleures performances pour l'apprentissage de CNN. Je l'ai reçu.
>>> model = MyChain()
>>> optimizer = optimizers.SGD() #Spécifiez la méthode d'optimisation comme SGD
>>> optimizer.setup(model)
>>> optimizer
<chainer.optimizers.sgd.SGD object at 0x10b7b40d0>
A ce moment, vous pouvez passer les informations de paramètres du modèle par ```optimizer.setup (model) `` `.
Il existe deux façons d'optimiser dans la documentation officielle. Dans la première méthode, la valeur du gradient est calculée manuellement et le calcul manuel du gradient est assez difficile. Par conséquent, utilisez une autre méthode, telle que le calcul automatique du dégradé, sauf dans des cas particuliers. Si vous souhaitez qu'il soit calculé automatiquement, vous devez définir au préalable une fonction de perte.
Les détails seront introduits la prochaine fois dans "Introduction to Deep Learning (2) - Essayons la régression non linéaire avec Chainer-", mais chacun introduira la fonction de perte. Définir Lorsqu'il s'agit de nombres réels, il peut être défini comme un problème qui minimise la somme de 2 normes de la méthode des moindres carrés, et il semble qu'il soit souvent défini comme un problème qui minimise l'entropie croisée. Pour la fonction de perte, différents types sont expliqués dans Notes sur la méthode de rétropropagation.
Fonction de perte
def forward(x, y, model):
loss = ... #Définissez votre propre fonction de perte
return loss
Cette fois, on suppose que la fonction forward '' qui calcule la fonction de perte prend les arguments
x```,
y``` et
`` `model```.
Si vous définissez une telle fonction de perte, les paramètres seront optimisés comme suit.
optimizer.update(forward, x, y, model)
Nous vous attendons pour nous suivre! Qiita: Carat Yoshizaki twitter:@carat_yoshizaki Blog Hatena: Blog Carat COO Page d'accueil: Carat
Service de professeur à domicile "Kikagaku" où vous pouvez apprendre l'apprentissage automatique en tête-à-tête N'hésitez pas à nous contacter si vous êtes intéressé par "Kikagaku" où vous pouvez apprendre "mathématiques → programmation → application Web" à la fois.
Recommended Posts