De nouveaux algorithmes sont créés chaque jour pour les méthodes d'optimisation des réseaux de neurones. Dans l'article précédent, j'ai résumé comment il a été développé de SGD à ADAM.
https://qiita.com/Fumio-eisan/items/798351e4915e4ba396c2
Dans cet article, j'aimerais mettre en œuvre cette technique d'optimisation et voir à quelle vitesse elle converge dans un réseau de neurones! .. Cette fois, j'aimerais appliquer cette méthode d'optimisation à une simple fonction quadratique. Dans les manuels, etc., prenez essentiellement une image numérique manuscrite telle que MNIST comme exemple et confirmez que la valeur de la fonction de perte diminue. Cependant, étant donné que la fonction de perte dans le réseau neuronal est très compliquée, il est difficile de déterminer si la valeur minimale est dérivée. Par conséquent, cette fois, je voudrais prendre une fonction quadratique comme exemple et voir comment elle se dirige vers la valeur minimale. De plus, j'ai implémenté la définition et le chargement de la classe moi-même, mais je noterai ce que j'ai compris ici.
Ceci est un aperçu.
Voici le but de la fonction quadratique et de la méthode d'optimisation ciblée cette fois.
J'ai décidé de trouver la valeur minimale d'une fonction très simple à comprendre. Puisque $ y = x ^ 2 $, $ y $, qui prend la valeur minimale, devient $ y = 0 $ lorsque $ x = 0 $. Je voudrais utiliser cette fonction, qui est facile à comprendre à la fois sensuellement et visuellement, pour continuer à mettre à jour $ x $ et confirmer qu'elle s'approche de $ y = 0 $.
Cette fois, le programme qui définit la fonction est stocké dans optimizers.py. Ensuite, la fonction est lue dans sample.ipynb, calculée et illustrée. Par conséquent, lors de sa mise en œuvre, nous apprécierions que vous puissiez stocker ces deux programmes dans le même dossier et les exécuter.
Le premier est le SGD de base. La formule est présentée ci-dessous.
\mathbf{x}_{t + 1} \gets \mathbf{x}_{t} - \eta g_t\\
g_t = 2 *\mathbf{x}_{t}
$ \ eta $ est le taux d'apprentissage et $ g_t $ est le gradient de la fonction. $ g_t $ vaut $ 2 * \ mathbf {x} _ {t} $ cette fois, donc c'est pratique.
Ensuite, nous mettrons en œuvre cette technique.
optimizers.py
class SGD:
def __init__(self, lr = 0.01,x=100):
self.lr = 0.01
self.x =100.0
def update(self,x):
x+= -self.lr * 2*x
return x
La formule elle-même est simple, donc je pense qu'elle est facile à comprendre en regardant le programme. C'est une fonction qui calcule $ x $ à l'étape suivante et renvoie $ x $. $ \ Eta $ s'écrit ici comme $ lr $.
Maintenant, voici un programme qui calcule à plusieurs reprises $ x $ pour trouver réellement la valeur minimale.
sample.ipynb
max_iterations = 100
y7=[]
y8=[]
y9=[]
v7=[]
v8=[]
v9=[]
optimizer = optimizers.SGD()
x = 100
optimizer.lr =0.1
for i in range(max_iterations):
x = optimizer.update(x)
y7.append(x)
v7.append(optimizer.lr)
x = 100
optimizer.lr =0.01
for i in range(max_iterations):
x = optimizer.update(x)
y8.append(x)
v8.append(optimizer.lr)
x = 100
optimizer.lr =0.9
for i in range(max_iterations):
x = optimizer.update(x)
y9.append(x)
v9.append(optimizer.lr)
Voyons comment la convergence de la fonction change lorsque nous changeons $ \ eta $ en 0.1,0.01,0.9.
sample.ipynb
x = np.arange(max_iterations)
plt.plot(x, y7, label='lr=0.1')
plt.plot(x, y8, label='lr=0.01')
plt.plot(x, y9, label='lr=0.9')
plt.xlabel("iterations")
plt.ylabel("y")
plt.ylim(-5, 120)
plt.legend()
plt.show()
Vous pouvez voir que plus la valeur de $ y $ sur l'axe vertical s'approche de 0, plus elle converge.
Si $ \ eta $ vaut 0,01, il faudra du temps pour converger. Au contraire, si $ \ eta $ est trop grand jusqu'à 0.9, vous pouvez voir qu'il passe à la convergence en chassant. Si cette valeur est 1 ou plus dans cette fonction, elle diverge. Par conséquent, on voit que $ \ eta $ est une bonne valeur autour de 0,1, ce qui converge rapidement et supprime la divergence.
Ensuite, nous mettrons en œuvre Momentum. Par rapport au SGD précédent, cet algorithme supprime les vibrations en considérant le mouvement de $ x $ lui-même.
\mathbf{x}_{t + 1} \gets \mathbf{x}_{t} + h_t\\
h_t=-\eta * g_t +\alpha * h_{t-1}
Définissez une fonction.
optimizers.py
class Momentum:
def __init__(self,lr=0.01,alpha=0.8,v=None):
self.lr = 0.01
self.v = 0.0
self.alpha = 0.8
def update(self,x):
self.v = self.v*self.alpha - (2.0)*x*self.lr
x += + self.v
return x
Et courir. Cette fois, nous évaluerons l'effet en changeant la valeur de $ \ alpha $ comme hyper paramètre.
On dit que le $ \ alpha $ standard est de 0,8. Même dans ce résultat, nous pouvons voir que 0.8 est une valeur qui semble juste. Si la valeur est supérieure à cela, vous chasserez beaucoup.
Eh bien, cette fois, le dernier est AdaGrad. Auparavant, le taux d'apprentissage $ \ eta $ était une constante. Cependant, la particularité est que ce taux d'apprentissage lui-même a pour effet de diminuer progressivement au fur et à mesure du nombre de calculs.
h_{0} = \epsilon\\
h_{t} = h_{t−1} + g_t^{2}\\
\eta_{t} = \frac{\eta_{0}}{\sqrt{h_{t}}}\\
\mathbf{x}_{t+1} = \mathbf{w}^{t} - \eta_{t}g_t
Définissez une fonction.
optimizers.py
class AdaGrad:
def __init__(self,h0=10.0):
self.v = 0.0
self.h = 0.0
self.h0 = 10.0
def update(self,x):
self.h += + (2.0*x)**2
self.v = -self.h0/(np.sqrt(self.h)+1e-7)
x += + self.v*2*x
return x
Au fait, cette fois j'ai calculé en changeant la valeur initiale du taux d'apprentissage $ \ eta_0 $ (h0 dans le programme).
Il s'est avéré que $ \ eta_0 $ converge plus vite autour de 100 et ne diverge pas.
Puisque je suis un débutant en Python, j'ai utilisé init dans ma classe avec une forte impression. Cette fois, j'ai trouvé ce qui suit.
Les arguments définis par init (self, argument) peuvent être entre guillemets après avoir appelé class pour changer les paramètres de l'argument.
Au contraire, si vous n'écrivez pas cet argument, vous ne pouvez pas modifier les paramètres après avoir appelé class.
Cette fois, la fonction a été minimisée par trois types de méthodes d'optimisation. Vous pouvez voir qu'il utilise l'idée de la formule graduelle apprise en mathématiques dites du secondaire. De plus, même si j'ai tout fait sauf numpy, cela m'a aidé à approfondir ma compréhension de la programmation elle-même. De plus, comme je l'ai appris dans le livre d'apprentissage profond d'O'Reilly, j'implémente en fait une méthode d'optimisation sur un réseau de neurones. Vous pouvez comprendre chaque contenu tel que la définition de fonctions et de petites variables, comment insérer une fonction d'activation, le calcul du gradient par la méthode de propagation d'erreur inverse, la détermination de la valeur initiale du paramètre de poids, etc. Cependant, quand il s'agit de le programmer, cela devient très compliqué.
** Une fois de plus, je me suis demandé si les programmeurs mettaient en œuvre une combinaison de ces nombreuses règles et connaissances structurelles, ce qui serait une tâche ardue. Sur la base de ces difficultés, je voudrais vous remercier de l'appeler comme une classe ou une méthode et d'utiliser la fonction facilement. ** **
Le programme complet est stocké ici. https://github.com/Fumio-eisan/optimizers_20200326
Recommended Posts