Chainer est une bibliothèque pour la mise en œuvre de réseaux neuronaux développée par Preferred Networks. Ses fonctionnalités sont les suivantes (depuis la page d'accueil).
Personnellement, je voudrais mentionner encore une chose, "facile à installer". La plupart des frameworks d'apprentissage en profondeur sont difficiles à installer, mais Chainer a peu de bibliothèques dépendantes et était facile à installer ... mais j'ai commencé à utiliser Cython à partir de la version 1.5.0 et c'était un peu compliqué. devenu. Veuillez vous référer à ce qui suit pour la méthode d'installation.
De plus, la notation de Chainer est intuitive et simple comme décrit ci-dessus, elle peut donc couvrir un large éventail de réseaux simples à des domaines plus complexes, appelés `` deep learning ''. D'autres bibliothèques d'apprentissage en profondeur sont complètement surspécifiées si elles ne sont pas profondes, et d'un autre côté, les bibliothèques simples (telles que PyBrain) sont difficiles si elles sont profondes, donc je pense que c'est aussi un grand avantage.
Cette fois, je vais vous expliquer comment utiliser un Chainer aussi attractif, mais pour gérer Chainer, la connaissance des réseaux de neurones (relativement profonds) est indispensable. En conséquence, il arrive souvent que les connaissances du côté du réseau neuronal soient insuffisantes (je l'ai compris).
Par conséquent, je voudrais d'abord expliquer brièvement le mécanisme du réseau neuronal, puis expliquer comment l'implémenter avec Chainer à un stade ultérieur.
La configuration du réseau de neurones est la suivante (en passant, tracer des lignes entre les nœuds n'est pas un problème à chaque fois).
Examinons de plus près comment l'entrée de l'entrée arrive à la sortie. La figure ci-dessous permet de voir facilement comment l'entrée est effectuée sur le premier nœud de la couche masquée.
Vous pouvez voir que quatre entrées sont transmises. L'entrée n'est pas transmise directement telle quelle, mais est pondérée. Un réseau neuronal imite la composition des neurones dans le cerveau, mais pensez-y comme étant affaibli ou renforcé à mesure que l'entrée (stimulus) se propage. Exprimé mathématiquement, si l'entrée est $ x $, elle sera pondérée comme $ a $ comme $ ax $.
Maintenant, nous avons reçu l'entrée ʻax`, mais le nœud ne transmet pas cette valeur telle quelle à la couche suivante. Il semble qu'il existe un mécanisme dans le cerveau selon lequel seule l'entrée dépassant un certain seuil est propagée à la couche suivante, et ici aussi, il l'imite et convertit l'entrée reçue en sortie vers la couche suivante. Exprimée mathématiquement, la fonction qui convertit l'entrée en sortie vers la couche suivante est $ h $, et la valeur de sortie peut être exprimée comme $ h (ax) $. Cette fonction $ h $ est appelée la fonction d'activation.
En résumé, il existe deux facteurs importants pour la propagation de la valeur dans un réseau de neurones:
En bref, le réseau neuronal pondère simplement l'entrée reçue et la sort. Par conséquent, un réseau neuronal monocouche est presque synonyme de régression linéaire ou de régression logistique.
Dans cet esprit, il devient clair ce que signifient les opérations sur le nombre de nœuds et le nombre de couches.
Lorsqu'il s'agit d'un réseau de neurones, je pense que le nombre de nœuds et le nombre de couches peuvent être modifiés de manière appropriée, mais il est également important de tracer les données fermement et de trouver le nombre approprié de nœuds et de couches.
Pour entraîner un réseau de neurones, nous utilisons une technique appelée rétro-propagation. L'erreur est la différence entre la valeur sortie du réseau neuronal et la valeur réelle. La rétropropagation est une méthode pour propager cette erreur par derrière (couche de sortie = couche de sortie) comme son nom l'indique et ajuster le poids de chaque couche.
Les détails de la rétropropagation ne sont pas abordés en détail ici car il existe diverses autres explications, mais les deux points suivants sont importants.
Il existe plusieurs méthodes pour utiliser les données d'apprentissage ci-dessus pour effectuer l'opération ci-dessus de "calcul de l'erreur et mise à jour du poids".
Le cycle d'une époque consiste à terminer la mise à jour des données d'apprentissage utilisées. Habituellement, vous apprendrez cette époque plusieurs fois. Cependant, ce n'est pas si bon s'il est simplement répété, de sorte que les données d'apprentissage sont mélangées à chaque époque, et dans le cas d'un mini-lot, la position d'acquisition du mini-lot est décalée ou échantillonnée au hasard.
Cette époque est une unité importante dans l'apprentissage d'un réseau neuronal, comme la vérification de la progression de l'apprentissage et le réajustement des paramètres.
Voici un résumé du contenu de l'explication du réseau de neurones.
Maintenant, regardons l'implémentation dans Chainer et les points ci-dessus.
Dans Chainer, le réseau neuronal se compose de Chain
(Function Set up to 1.4).
Ce qui suit est une définition du réseau neuronal de type 4-3-2 utilisé dans l'explication jusqu'à présent.
from chainer import Link, Chain, ChainList
import chainer.functions as F
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 = F.sigmoid(self.l1(x))
o = self.l2(h)
return o
Remarque
Il semble que vous n'ayez pas à hériter de Chain
, mais vous ne pouvez pas migrer le processeur / GPU ou enregistrer le modèle sans hériter deChain
, donc je pense que vous devriez en hériter docilement. S'il s'agit d'une simple jointure complète, il n'est pas nécessaire de créer une classe, et il semble que Chain (l1 = ..., l2 = ...)
convient.
A partir de 1.5, les fonctions avec paramètres (= cibles d'optimisation) sont clairement séparées de Link, et les fonctions pures (sigmoïde, etc.) sont clairement séparées des Fonctions.
Je pense que c'est mieux pour ceux qui se demandaient si la couche cachée n'était même pas une couche. Veuillez vous référer à la figure ci-dessous pour les «l1» et «l2» ci-dessus.
Compte tenu de la propagation entre les couches de cette manière, le mécanisme est qu'il y a deux couches. En fait, «L.Linear» détient le poids pour la propagation et est responsable de l'application de ce poids à l'entrée.
Le traitement de propagation est implémenté dans «call» de la classe Chain comme décrit ci-dessus.
def __call__(self, x):
h = F.sigmoid(self.l1(x))
o = self.l2(h)
return o
Remarque
Le processus qui a été écrit comme forward
jusqu'à 1.4 sera écrit dans __call__
(En Python, si vous définissez __call__
, par exemple, si vous écrivezmodel ()
à partir d'une instance appelée model
, Vous pouvez appeler le processus écrit en __call__
).
Ici, l'entrée «x» est pondérée («self.l1 (x)»), et la valeur via la fonction sigmoïde, qui est souvent utilisée comme fonction d'activation, est transmise à la couche suivante («h =). F.sigmoïde (self.l1 (x)) ). La sortie finale ne nécessite aucun traitement pour passer à la couche suivante, donc la fonction d'activation n'est pas utilisée (ʻo = self.l2 (h)
)
Lors de l'entraînement, vous devez d'abord calculer l'erreur entre la valeur prédite et la valeur réelle. Vous pouvez simplement l'implémenter en tant que fonction (le nom lossfun
est courant dans Chainer), mais pour les problèmes de classification, il est plus facile d'utiliser Classifier
.
from chainer.functions.loss.mean_squared_error import mean_squared_error
model = L.Classifier(MyChain(), lossfun=mean_squared_error)
En fait, Classifier
est aussi Link
, c'est-à-dire une fonction avec des paramètres, et calcule l'erreur entre la valeur sortie de MyChain
et les données de l'enseignant dans __call__
(Function
pour le calcul est naturel Il peut être spécifié (mean_squared_error dans ce qui précède).
Dans la version 1.5, le point que ce Link
peut être connecté est très important, et la réutilisabilité du modèle est beaucoup plus élevée. Même dans ce qui précède, vous pouvez voir que le modèle du corps principal et le processus de calcul de l'erreur en l'utilisant peuvent être écrits séparément.
Après avoir calculé l'erreur, optimisez le modèle pour la minimiser (rétropropagation ci-dessus). C'est ʻoptimizer` qui joue ce rôle, et la partie d'apprentissage de l'exemple MNIST est la suivante. Il est devenu.
# Setup optimizer
optimizer = optimizers.Adam()
optimizer.setup(model)
...(Omission)...
# Learning loop
for epoch in six.moves.range(1, n_epoch + 1):
print('epoch', epoch)
# training
perm = np.random.permutation(N)
sum_accuracy = 0
sum_loss = 0
for i in six.moves.range(0, N, batchsize):
x = chainer.Variable(xp.asarray(x_train[perm[i:i + batchsize]]))
t = chainer.Variable(xp.asarray(y_train[perm[i:i + batchsize]]))
# Pass the loss function (Classifier defines it) and its arguments
optimizer.update(model, x, t)
Il y a trois étapes de base:
Au cœur se trouve la mise à jour ʻoptimizer.update. A partir de 1.5, en passant lossfun comme argument, le calcul d'erreur et la propagation par le lossfun passé seront effectués automatiquement. Bien sûr, il est également possible d'initialiser le gradient avec
model.zerograds () puis de calculer et propager l'erreur par vous-même (loss.backward) et d'appeler ʻoptimizer.update
comme auparavant.
Comme vous pouvez le voir, Chainer est conçu pour qu'une fois que vous avez défini votre modèle, vous pouvez facilement l'optimiser (Define-and-Run
).
Et le modèle entraîné peut être facilement sauvegardé / restauré en utilisant Serializer
(aussi ʻoptimizer` peuvent être sauvegardés).
serializers.save_hdf5('my.model', model)
serializers.load_hdf5('my.model', model)
Après cela, voici quelques conseils pour l'implémenter.
softmax_cross_entropy.py
, qui est souvent utilisé dans les problèmes de classification, suppose que les données de l'enseignant sont de type int32 (représentant une étiquette). Veuillez noter que si vous passez ceci en tant que flottant, une erreur se produira.Peut-être que la première chose qui reste bloquée est principalement des erreurs de type. Je ne sais pas si Chainer commence par un type et se termine par un type, mais il ne fait aucun doute qu'il commence par un type, alors faites attention à ce point et utilisez-le.