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.
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 |
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é.
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)
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