[PYTHON] Mise en œuvre de l'optimisation bayésienne des hyper paramètres du réseau de neurones (Chainer + GPyOpt)

Optimisons automatiquement les hyper paramètres du réseau de neurones

Hyperparamètres du réseau neuronal

Comment décidez-vous? Les réseaux de neurones prennent beaucoup de temps à calculer, vous vous fiez donc souvent à votre intuition et à votre expérience. Cependant, s'il se termine dans un certain laps de temps (si le calcul prend au plus 30 minutes à 1 heure), il existe une méthode appelée optimisation bayésienne. L'optimisation bayésienne est également efficace pour les boîtes noires que vous souhaitez optimiser, mais le calcul prend un certain temps.

Ototo, j'ai écrit Article sur GPyOpt effectuant l'optimisation bayésienne avec Python. Cette fois, nous avons utilisé cette méthode pour optimiser les hyperparamètres du réseau de neurones afin que le taux de réponse correct de MNIST soit élevé. Je l'ai en fait codé en Python, alors essayez-le.

Résultat immédiatement

Eh bien, tout d'abord je vais vous montrer le résultat.

La tâche à effectuer cette fois est d'améliorer le taux d'identification de MNIST (Handwritten Character Recognition).

MNIST est divisé en données d'apprentissage et données de test, et les données d'apprentissage sont utilisées pour entraîner le réseau neuronal. Après cela, les données de test sont identifiées, mais ce taux d'erreur est réduit.

Les hyper paramètres à optimiser sont les suivants.

[Ajout 2017/2/8] J'ai transformé le code qui corrigeait le nombre d'étapes en nombre d'époques.

Hyper paramètres intervalle
Nombre d'époques 1~20
Taux d'abandon 0~0.9
Nombre de couches de couches cachées (combien de fois la couche cachée doit être une unité de la couche d'entrée) 0.51~5
Taille du lot 50,100,200
Plier ou non True,False
Nombre de couches 1,2,3
Que ce soit pour le rendre résiduel True,False
Taille du filtre pliant 5,7,9,11,13

Tout d'abord, à titre d'expérience comparative, un réseau neuronal orthodoxe a été utilisé, et le taux d'erreur était de 2,58%.

Après optimisation bayésienne (20 échantillonnages aléatoires + 20 itérations d'optimisation bayésienne), le taux d'erreur était de 1,18%. Les hyper-paramètres après optimisation sont:

Hyper paramètres intervalle Expérience comparative Résultat d'optimisation
Nombre d'époques 1~20 10 20(limite supérieure)
Taux d'abandon 0~0.9 0 0
Nombre de couches de couches cachées (combien de fois la couche cachée doit être une unité de la couche d'entrée) 0.51~5 1 5(limite supérieure)
Taille du lot 50,100,200 100 200(limite supérieure)
Plier ou non True,False False True
Nombre de couches 1,2,3 2 3(limite supérieure)
Que ce soit pour le rendre résiduel True,False False True
Taille du filtre pliant 5,7,9,11,13 - 9

Basé sur le résultat

Le nombre d'époques et le nombre de couches cachées ont atteint la limite supérieure.

Eh bien, cette fois, il y avait un problème avec les spécifications de l'ordinateur personnel, j'ai donc réduit le nombre d'époques (encore seulement 20 itérations, en particulier la dernière n'essayait que celles avec le nombre maximum d'époques et de taille de lot, donc c'était beaucoup de temps Ça a pris).

Si vous augmentez la limite supérieure telle que le nombre d'époques, la précision sera plus élevée.

Eh bien, je suis content qu'il semble toujours optimisé.

Implémentation du réseau neuronal

Mis en œuvre avec chainer.

J'ai créé une fonction test_mnist_nn. Cette fonction prend les hyper paramètres du réseau neuronal comme entrée et produit le taux d'erreur. L'optimisation bayésienne est effectuée pour minimiser ce taux d'erreur.

mnist_nn.py


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Un réseau de neurones pour MNIST qui optimise les paramètres.
Les paramètres à optimiser sont
epoch_num:Nombre d'époques(1~20)
dropout_r:Taux d'abandon(0~0.9)
h_cnl:Nombre de couches de couches cachées (combien de fois la couche cachée doit être une unité de la couche d'entrée)(0.51~5)
batch_size:Taille du lot(50,100,200)
conv:Plier ou non(True or False)
layers:Nombre de couches(1~3)
residual:Que ce soit pour le rendre résiduel(True or False)
conv_ksize:Taille du filtre pliant(5,7,9,11,13)
"""

import numpy as np
import chainer
from chainer import optimizers,datasets
import chainer.functions as F
import chainer.links as L

class mnist_nn(chainer.Chain):
    '''
Réseau neuronal pour les tâches de classification mnist
    '''
    def __init__(self, dropout_r=0.5, h_cnl=0.51, conv=True, layers=3, residual=True, conv_ksize=9):
        '''
Initialisation des paramètres et
Créer un calque (ajouter un lien)
tenir
        '''
        super(mnist_nn, self).__init__()
        self.dropout_r = dropout_r
        self.h_cnl = h_cnl
        self.conv = conv
        self.layers = layers
        self.residual = residual
        self.conv_ksize = conv_ksize

        if conv:
            p_size = int((conv_ksize-1)/2)
            self.add_link('layer{}'.format(0), L.Convolution2D(1,round(h_cnl),(conv_ksize,conv_ksize),pad=(p_size,p_size)))
            for i in range(1,layers):
                self.add_link('layer{}'.format(i), L.Convolution2D(round(h_cnl),round(h_cnl),(conv_ksize,conv_ksize),pad=(p_size,p_size)))
            self.add_link('fin_layer', L.Convolution2D(round(h_cnl),10,(28,28)))
        else:
            self.add_link('layer{}'.format(0), L.Linear(784,round(784*h_cnl)))
            for i in range(1,layers):
                self.add_link('layer{}'.format(i), L.Linear(round(784*h_cnl),round(784*h_cnl)))
            self.add_link('fin_layer', L.Linear(round(784*h_cnl),10))

    def __call__(self, x, train=False):
        '''
Le corps principal du réseau neuronal
        '''
        if self.conv:
            batch_size = x.shape[0]
            x = x.reshape(batch_size, 1, 28, 28)
            h = chainer.Variable(x)
            h = F.dropout(F.relu(self['layer{}'.format(0)](h)),train=train,ratio=self.dropout_r)
            for i in range(1,self.layers):
                if self.residual:
                    h = F.dropout(F.relu(self['layer{}'.format(i)](h)),train=train,ratio=self.dropout_r) + h
                else:
                    h = F.dropout(F.relu(self['layer{}'.format(i)](h)),train=train,ratio=self.dropout_r)
            h = self['fin_layer'](h)[:,:,0,0]
        else:
            h = chainer.Variable(x)
            h = F.dropout(F.relu(self['layer{}'.format(0)](h)),train=train,ratio=self.dropout_r)
            for i in range(1,self.layers):
                if self.residual:
                    h = F.dropout(F.relu(self['layer{}'.format(i)](h)),train=train,ratio=self.dropout_r) + h
                else:
                    h = F.dropout(F.relu(self['layer{}'.format(i)](h)),train=train,ratio=self.dropout_r)
            h = self['fin_layer'](h)
        return h
    def loss(self,x,t):
        '''
La fonction d'erreur est l'entropie croisée
        '''
        x = self.__call__(x, True)
        t = chainer.Variable(t)
        loss = F.softmax_cross_entropy(x,t)
        return loss


def test_mnist_nn(epoch_num=10, dropout_r=0.5, h_cnl=0.51, batch_size=100, conv=True, layers=3, residual=True, conv_ksize=9):
    '''
Une fonction qui donne le mauvais taux de réponse de MNIST lorsque les paramètres sont saisis
    '''
    #La graine est fixe pour le moment (cela détermine la sortie comme exacte pour le paramètre.
    np.random.seed(1234)

    #Préparation à l'optimisation du modèle
    model = mnist_nn(dropout_r, h_cnl, conv, layers, residual, conv_ksize)
    optimizer = optimizers.Adam()
    optimizer.setup(model)

    #Préparation des données
    train, test = datasets.get_mnist()
    trainn, testn = len(train), len(test)

    #Linspace pour la sortie du journal
    logging_num = np.linspace(0,epoch_num*int(trainn/batch_size),11).astype(int)

    iter = 0
    for epoch in range(epoch_num):
        #Création de lots
        batch_idx = np.array(range(trainn))
        np.random.shuffle(batch_idx)
        for batch_num in np.hsplit(batch_idx,int(trainn/batch_size)):
            batch = train[batch_num]
            x,t = batch[0],batch[1]

            #Apprentissage
            model.zerograds()
            loss = model.loss(x,t)
            #Au cas où
            if np.isnan(loss.data):
                print("pass")
                continue
            loss.backward()
            optimizer.update()

            #Sortie de journal
            if iter in logging_num:
                print(str(np.where(logging_num==iter)[0][0]*10)+'%','\tcross entropy =',loss.data)
            iter+=1


    #Évaluation des performances(Faites-le dans un mini-lot pour économiser de la mémoire)
    batch_idx = np.array(range(testn))
    false_p = []
    for batch_num in np.hsplit(batch_idx,100):
        batch = test[batch_num]
        x,t = batch[0].reshape(len(batch_num), 1, 28, 28),batch[1]
        res = model(x).data.argmax(axis=1)
        false_p.append(np.mean(t!=res))
    false_p = np.mean(false_p)

    print("False {:.2f}%".format(false_p*100))
    return false_p

if __name__ == '__main__':
    test_mnist_nn(epoch_num=10, dropout_r=0, h_cnl=1, batch_size=100, conv=False, layers=2, residual=False, conv_ksize=9)

Implémentation de l'optimisation bayésienne

J'ai utilisé GPyOpt.

J'ai d'abord échantillonné 20, puis essayé d'optimiser en faisant 100 itérations (en fait, 100 itérations ne tournaient pas).

bayesian_opt.py


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Fri Jan 27 20:09:10 2017

@author: marshi
"""

import GPyOpt
import numpy as np
import mnist_nn
import os

def f(x):
    '''
    mnist_nn.test_mnist_fonction wrapper nn
    _x[0](1~20)->epoch_num=int(_x[0])
    _x[1](0~0.9)->dropout_r=np.float32(_x[1])
    _x[2](0.51~5)->h_cnl=np.float32(_x[2])
    _x[3](50,100,200)->batch_size=int(_x[3])
    _x[4](0,1)->conv=bool(_x[4])
    _x[5](1,2,3)->layers=int(_x[5])
    _x[6](0,1)->residual=bool(_x[6])
    _x[7](5,7,9,11,13)->conv_ksize=int(_x[7])
    '''
    ret = []
    for _x in x:
        print(_x)
        _ret = mnist_nn.test_mnist_nn(epoch_num = int(_x[0]),
                                        dropout_r = np.float32(_x[1]),
                                        h_cnl = np.float32(_x[2]),
                                        batch_size = int(_x[3]),
                                        conv = bool(_x[4]),
                                        layers = int(_x[5]),
                                        residual = bool(_x[6]),
                                        conv_ksize = int(_x[7]))
        ret.append(_ret)
    ret = np.array(ret)
    return ret

#Spécifiez la zone de chaque variable
bounds = [{'name': 'epochs', 'type': 'continuous', 'domain': (1,20)},
          {'name': 'dropout_r', 'type': 'continuous', 'domain': (0.0,0.9)},
          {'name': 'h_cnl', 'type': 'continuous', 'domain': (0.51,5)},
          {'name': 'batch_size', 'type': 'discrete', 'domain': (50,100,200)},
          {'name': 'conv', 'type': 'discrete', 'domain': (0,1)},
          {'name': 'layers', 'type': 'discrete', 'domain': (1,2,3)},
          {'name': 'residual', 'type': 'discrete', 'domain': (0,1)},
          {'name': 'conv_ksize', 'type': 'discrete', 'domain': (5,7,9,11,13)}]

#Création d'objets optimisée bayésienne
#X précédemment enregistré,S'il y a Y, fais-le du milieu
#Sinon, échantillonnez d'abord au hasard quelques échantillons
filename = "XY.npz"
if os.path.exists(filename):
    XY = np.load(filename)
    X,Y = XY['x'],XY['y']
    myBopt = GPyOpt.methods.BayesianOptimization(f=f, domain=bounds, X=X, Y=Y)
else:
    myBopt = GPyOpt.methods.BayesianOptimization(f=f, domain=bounds)

#Optimisation bayésienne 100 étapes et affichage des résultats étape par étape
for i in range(1000):
    print(len(myBopt.X),"Samples")
    myBopt.run_optimization(max_iter=1)
    print(myBopt.fx_opt)
    print(myBopt.x_opt)
    #Sauvegarde séquentielle
    np.savez(filename, x=myBopt.X, y=myBopt.Y)

Recommended Posts

Mise en œuvre de l'optimisation bayésienne des hyper paramètres du réseau de neurones (Chainer + GPyOpt)
Implémentation de réseaux neuronaux "flous" avec Chainer
Implémentation simple d'un réseau neuronal à l'aide de Chainer
Implémentation d'un réseau de neurones à deux couches 2
Apprentissage des classements à l'aide d'un réseau neuronal (implémentation RankNet par Chainer)
Implémentation d'un réseau neuronal à 3 couches (pas d'apprentissage)
Présentation de DNC (Differentiable Neural Computers) + Implémentation par Chainer
Implémentation d'un réseau de neurones convolutifs utilisant uniquement Numpy
Réseau de neurones commençant par Chainer
Implémentation de réseau neuronal en python
Ajuster les hyper paramètres avec l'optimisation bayésienne
Implémentation de réseau neuronal (NumPy uniquement)
PRML Chapitre 5 Implémentation Python du réseau neuronal
GPyOpt, un package d'optimisation bayésienne en Python
Théorie et implémentation simples des réseaux neuronaux
Touchez l'objet du réseau neuronal
Implémentation d'un système de dialogue utilisant Chainer [seq2seq]
Implémentation de réseau neuronal simple à l'aide de la préparation Chainer-Data-
Implémentation de réseau neuronal simple à l'aide de la description du modèle Chainer-
[Chainer] Classification des documents par réseau de neurones convolutifs
Python vs Ruby "Deep Learning from scratch" Chapitre 3 Implémentation d'un réseau neuronal à 3 couches
Implémentation simple d'un réseau de neurones à l'aide de Chainer ~ Définition d'un algorithme d'optimisation ~
Visualisez la couche interne du réseau neuronal
Vérification de la normalisation des lots avec un réseau neuronal multicouche
Reconnaissance des nombres manuscrits par un réseau neuronal multicouche
Une note sur l'implémentation de la bibliothèque qui explore les hyperparamètres à l'aide de l'optimisation bayésienne en Python