Ne dites pas Deep Learning Ce chapitre 6 traite de choses très importantes dans le Machine Learning.
Objectif du réseau de neurones = trouver des paramètres qui rendent la valeur de la fonction de perte aussi petite que possible La résolution de ces problèmes est appelée «optimisation»
W \leftarrow W - \eta\frac{\partial L}{\partial W}
class SGD:
def __init__(self, lr=0.01):
self.lr = lr
def update(self, params, grads):
for key in params.keys():
params[key] -= self.lr * grads[key]
network = TwoLayerNet(...)
#optimizer:La personne qui optimise
optimizer = SGD()
for i in range(10000) :
...
x_bath, t_bath = get_mini_batch(...)
grads = network.gradient(x_batch, t_batch)
params = network.params
optimizer.update(params, grads)
...
Les paramètres sont mis à jour par opetimizer Tout ce que vous avez à faire est de transmettre les informations de paramètre et de gradient à l'optimiseur
En implémentant la classe d'optimisation séparément comme décrit ci-dessus, il devient plus facile de modulariser la fonction.
Par exemple, lors de la mise en œuvre d'une autre méthode d'optimisation appelée Momentum qui apparaîtra ensuite, implémentez-la de sorte qu'elle ait également une méthode commune appelée update (params, grades). Ensuite, vous pouvez basculer SGD vers Momentum en changeant simplement optimizer = SGD () en optimizer = Momentum ().
L'inconvénient de SGD est que si la forme de la fonction n'apparaît pas isotrope, elle sera recherchée par une route inefficace (s'il s'agit d'une fonction allongée).
La cause première des inconvénients ci-dessus est que la direction du dégradé pointe vers une direction autre que la valeur minimale d'origine.
Afin de remédier à cette lacune de SGD, trois méthodes sont introduites comme méthodes alternatives à SGD. ・ Momentum ・ AdaGrad ・ Adam
Momentum
L'élan est "l'élan" Une image d'une balle roulant sur le sol décélérant progressivement en raison du frottement ou de la résistance de l'air lorsqu'elle ne reçoit aucune force
v \leftarrow \alpha v - \eta\frac{\partial L}{\partial W}\\
W \leftarrow W + v
class Momentum:
def __init__(self, lr=0.01, momentum=0.9):
self.lr = lr
self.momentum = momentum
self.v = None
def update(self, params, grads):
if self.v is None:
self.v = {}
for key, val in params.items():
self.v[key] = np.zeros_like(val)
for key in params.keys():
self.v[key] = self.momentum*self.v[key] - self.lr * grads[key]
param[key] += self.v[key]
Direction de l'axe x: La force reçue est faible, mais comme la force est toujours dirigée dans la même direction, elle accélérera constamment dans la même direction. Direction de l'axe y: La force reçue est grande, mais les forces positives et négatives sont alternativement reçues et chantées, s'annulant l'une l'autre, et la vitesse sur l'axe y n'est pas stable. → Vous pouvez vous rapprocher de la direction de l'axe x plus rapidement que SGD et réduire le mouvement en zigzag.
AdaGrad
Cette méthode réduit le taux d'apprentissage Il s'agit d'une méthode permettant de réduire le coefficient d'apprentissage à mesure que l'apprentissage progresse. Ada: dérivé de Adaptive Adaptive
h \leftarrow h + \frac{\partial L}{\partial W}\odot\frac{\partial L}{\partial W}\\
W \leftarrow W - \eta \frac{1}{\sqrt{h}} \frac{\partial L}{\partial W}
Multiplier 1 / √h signifie que les éléments qui bougent bien (largement mis à jour) dans la mise à jour des paramètres auront un coefficient d'apprentissage plus petit.
class AdaGrad:
def __init__(self, lr=0.01):
self.lr = lr
self.h = None
def update(self, params, grads):
if self.h is None:
self.h = {}
for key, val in params.items():
self.h[key] = np.zeros_like(val)
for key in params.keys():
self.h[key] += grads[key] * grads[key]
param[key] += self.lr * grads[key] / (np.sqrt(self.h[key] + le-7)
La petite valeur le-7 est ajoutée car s'il y a 0 dans self.h [key], elle sera divisée par 0.
RMSProp AdaGrad enregistre tous les gradients passés sous forme de somme de carrés Par conséquent, si vous procédez à l'apprentissage à l'infini, les frais de renouvellement seront de 0 et ne seront pas renouvelés du tout.
Il existe également une méthode différente de RMS Drop qui a résolu ce problème RMS Prop est une méthode qui est calculée de sorte que les gradients passés soient progressivement oubliés et que les nouvelles informations de gradient soient largement reflétées, au lieu d'ajouter tous les gradients uniformément. C'est ce qu'on appelle la «moyenne mobile exponentielle»
Il n'y a pas de formule dans le livre, mais cela ressemble à cette formule lors du calcul à partir du programme
\begin{align}
Valeur initiale d&=0.99\\
h &\leftarrow h * d + (1 - d)\frac{\partial L}{\partial W}\odot\frac{\partial L}{\partial W}\\
W &\leftarrow W - \eta \frac{1}{\sqrt{h}} \frac{\partial L}{\partial W}
\end{align}
class RMSprop:
"""RMSprop"""
def __init__(self, lr=0.01, decay_rate = 0.99):
self.lr = lr
self.decay_rate = decay_rate
self.h = None
def update(self, params, grads):
if self.h is None:
self.h = {}
for key, val in params.items():
self.h[key] = np.zeros_like(val)
for key in params.keys():
self.h[key] *= self.decay_rate
self.h[key] += (1 - self.decay_rate) * grads[key] * grads[key]
params[key] -= self.lr * grads[key] / (np.sqrt(self.h[key]) + 1e-7)
Adam
Momentum: Mouvement selon les lois de la physique AdaGrad: ajustez de manière adaptative les étapes de mise à jour pour chaque élément du paramètre
Adam = Momentum + AdaGrad + Hyperparamètre "Correction du biais (correction du biais)"
De même, il n'y a pas de formules dans le livre Quand j'ai cherché sur Google, la formule est sortie, alors vérifiez
Citation: http://postd.cc/optimizing-gradient-descent/#adam
Adam (Adaptive Moment Optimization) 14 utilise une autre méthode pour calculer et adapter le taux d'apprentissage pour chaque paramètre. Adadelta et RMSprop ont accumulé des moyennes de décroissance exponentielle du carré v_t des gradients passés. En plus de cela, Adam conserve également la moyenne décimée exponentielle du gradient passé m_t. C'est similaire à Momentum.
\begin{align}
valeur initiale\beta_1 &= 0.9,\beta_2=0.999,\epsilon=10^{-8}\\
\\
m_t &= \beta_1 m_{t-1} + (1 – \beta_1) g_t\\
v_t &= \beta_2 v_{t-1} + (1 – \beta_2) g_t^2\\
\\
\hat{m}_t &= \dfrac{m_t}{1 – \beta^t_1}\\
\hat{v}_t &= \dfrac{v_t}{1 – \beta^t_2}\\
\\
\theta_{t+1} &= \theta_{t} – \dfrac{\eta}{\sqrt{\hat{v}_t} + \epsilon} \hat{m}_t\\
\end{align}
class Adam:
"""Adam (http://arxiv.org/abs/1412.6980v8)"""
def __init__(self, lr=0.001, beta1=0.9, beta2=0.999):
self.lr = lr
self.beta1 = beta1
self.beta2 = beta2
self.iter = 0
self.m = None
self.v = None
def update(self, params, grads):
if self.m is None:
self.m, self.v = {}, {}
for key, val in params.items():
self.m[key] = np.zeros_like(val)
self.v[key] = np.zeros_like(val)
self.iter += 1
lr_t = self.lr * np.sqrt(1.0 - self.beta2**self.iter) / (1.0 - self.beta1**self.iter)
for key in params.keys():
#self.m[key] = self.beta1*self.m[key] + (1-self.beta1)*grads[key]
#self.v[key] = self.beta2*self.v[key] + (1-self.beta2)*(grads[key]**2)
self.m[key] += (1 - self.beta1) * (grads[key] - self.m[key])
self.v[key] += (1 - self.beta2) * (grads[key]**2 - self.v[key])
params[key] -= lr_t * self.m[key] / (np.sqrt(self.v[key]) + 1e-7)
#unbias_m += (1 - self.beta1) * (grads[key] - self.m[key]) # correct bias
#unbisa_b += (1 - self.beta2) * (grads[key]*grads[key] - self.v[key]) # correct bias
#params[key] += self.lr * unbias_m / (np.sqrt(unbisa_b) + 1e-7)
AdaGrad a l'air bien dans l'image ci-dessous Mais malheureusement aucune méthode n'est meilleure (pour l'instant) Chacun a ses propres caractéristiques, et il semble qu'il y ait des problèmes pour lesquels il est bon et des problèmes pour lesquels il n'est pas bon.
La décroissance du poids, une technique qui supprime le surapprentissage et améliore les performances de généralisation Décroissance du poids: méthode visant à apprendre à réduire la valeur du paramètre de poids En réduisant la valeur pondérée, le surapprentissage est moins susceptible de se produire.
Si vous souhaitez réduire le poids, il est naturel que vous souhaitiez commencer avec la valeur initiale la plus petite possible. Jusqu'à présent, la valeur de poids initiale était de 0,01 * np.random.randn (10, 100). (Distribution gaussienne avec un écart type de 0,01)
Cependant, lorsque le poids est de 0, cela semble être une mauvaise idée. (Pour être exact, la valeur de poids ne doit pas être définie sur une valeur uniforme) La raison est ** dans la méthode de propagation d'erreur, toutes les valeurs de poids sont mises à jour uniformément **. Par conséquent, une valeur initiale aléatoire est requise.
La conclusion est la suivante.
Lorsque le nombre de nœuds de la couche précédente est n
Valeur initiale de Xavier: écart type\frac{1}{\sqrt{n}}Distribution gaussienne avec un écart type de\\
Valeur initiale de He: écart type\sqrt\frac{2}{n}Distribution gaussienne avec un écart type de\\
Données biaisées à 0 et 1 → La valeur du gradient de rétropropagation devient de plus en plus petite et disparaît Ce problème s'appelle "** disparition du gradient **"
Chaque neurone produit presque la même valeur → Biais d'activation Cela devient un problème de "** limite d'expressivité **"
Par conséquent, il est souhaitable que les résultats soient raisonnablement dispersés.
Distribution d'activation de chaque couche lors de l'utilisation d'une distribution gaussienne avec un écart type de 1 comme valeur initiale du poids
Distribution d'activation de chaque couche lors de l'utilisation d'une distribution gaussienne avec un écart type de 0,01 comme valeur initiale du poids
Répartition d'activation de chaque couche lorsque la valeur initiale de Xavier est utilisée comme valeur initiale du poids
Distribution d'activation de chaque couche lorsque la valeur initiale de He est utilisée comme valeur initiale du poids
Distribution d'activation de chaque couche lors de l'utilisation d'une distribution gaussienne avec un écart type de 1 comme valeur initiale du poids
Distribution d'activation de chaque couche lors de l'utilisation d'une distribution gaussienne avec un écart type de 0,01 comme valeur initiale du poids
Répartition d'activation de chaque couche lorsque la valeur initiale de Xavier est utilisée comme valeur initiale du poids
Distribution d'activation de chaque couche lorsque la valeur initiale de He est utilisée comme valeur initiale du poids
Lorsque std = 0,01, l'apprentissage n'a guère progressé. L'apprentissage croustillant progresse dans le cas de He et Xavier → Vous pouvez voir que le problème de la valeur initiale est très important
Batch Normalization
"Forcer" les ajustements d'activation pour que la distribution des activations dans chaque couche ait une dispersion modérée
Avantages de la normalisation des lots
C'est un peu mon opinion personnelle, mais c'est comme le goût de la cuisine.
Ajustez la distribution d'activation de chaque couche afin qu'elle ait une diffusion modérée → En d'autres termes, insérez une couche qui normalise la distribution des données (distribution avec moyenne 0 et variance 1) dans le réseau neuronal.
\begin{align}
&B sous forme de mini lot=\{x_1, x_2, \cdots, x_m\}Pour un ensemble de m données d'entrée\\
&moyenne\mu_B, dispersion\sigma_B^Demander 2\\
&Aussi\epsilon a 10 ans^{-7}Très petite valeur telle que
\end{align}
\begin{align}
\mu_B &\leftarrow \frac{1}{m} \sum_{i-1}^{m} x_i\\
\sigma_B^2 &\leftarrow \frac{1}{m} \sum_{i-1}^{m} (x_i - \mu_B)^2\\
\hat{x_i} &\leftarrow \frac{x_i-\mu_B}{\sqrt{\sigma_B^2 + \epsilon}}
\end{align}
De plus, la couche Bath Norm transforme ces données normalisées avec sa propre échelle et son propre décalage. γ et β sont des paramètres, partant de γ = 1 et β = 0, et s'ajustant aux valeurs appropriées par apprentissage.
y_i \leftarrow \gamma \hat{x_i} + \beta
Propagation arrière, etc. Vous avez lu le blog de Frederik Kratzert.
https://kratzert.github.io/2016/02/12/understanding-the-gradient-flow-through-the-batch-normalization-layer.html
Causes du surapprentissage ・ Un modèle avec un grand nombre de paramètres et une expressivité élevée ・ Il y a peu de données d'entraînement
Surapprentissage causé délibérément
Weight decay
Décroissance du poids: décroissance de la charge
Le but de l'apprentissage du réseau neuronal est de réduire la valeur de la fonction de perte. A ce moment, si l'on ajoute la double norme du poids (norme L2), il est possible d'éviter que le poids ne devienne grand.
Si le poids est W, la décroissance de poids de la norme L2 est
\frac{1}{2}\lambda W^2
λ est un hyper paramètre qui contrôle la force de la régularisation 1/2 est une constante d'ajustement pour obtenir le résultat de la différenciation de W ^ 2 λW
Norme L2
\sqrt{w_1^2+w_2^2+\cdots+w_n^2}
Norme L1
|w_1^2|+|w_2^2|+\cdots+|w_n^2|
Pour être honnête, c'était plus facile à comprendre en se référant à d'autres qu'en expliquant le livre
Citation: http://qiita.com/supersaiakujin/items/97f4c0017ef76e547976
Dans un réseau neuronal profond, plus il y a de couches, plus le modèle sera expressif. Cependant, plus le nombre de couches est élevé, plus le risque de surajustement est élevé. Le risque de surajustement est réduit en limitant la liberté des paramètres tout en conservant l'expressivité du modèle. Une des méthodes est la décroissance du poids. La formule de mise à jour du> poids est écrite comme suit.
{w \leftarrow w -\eta \frac{\partial C(w)}{\partial w} - \eta \lambda w\\
}
La formule ci-dessus est un peu difficile à comprendre ce que vous voulez faire, mais elle provient en fait de la fonction de coût comme indiqué ci-dessous.
{\tilde C(w) = C(w) + \frac{\lambda}{2}||w||^2
}
Il s'agit de la fonction de coût avec le terme de régularisation L2. Cette section réduit la valeur de poids. Ainsi, lors de sa mise en œuvre, la section de régularisation L2 sera ajoutée au coût.
Bien qu'il soit passé dans le texte, seule la source de la partie utilisée est extraite: c'est facile à comprendre si vous recherchez avec weight_decay_lambda Utilisé pour l'initialisation, le calcul de la fonction de perte et le réglage du poids
def __init__(self, input_size, hidden_size_list, output_size,
activation='relu', weight_init_std='relu', weight_decay_lambda=0):
self.input_size = input_size
self.output_size = output_size
self.hidden_size_list = hidden_size_list
self.hidden_layer_num = len(hidden_size_list)
self.weight_decay_lambda = weight_decay_lambda
self.params = {}
#Initialisation du poids
self.__init_weight(weight_init_std)
#Génération de couches
activation_layer = {'sigmoid': Sigmoid, 'relu': Relu}
self.layers = OrderedDict()
for idx in range(1, self.hidden_layer_num+1):
self.layers['Affine' + str(idx)] = Affine(self.params['W' + str(idx)],
self.params['b' + str(idx)])
self.layers['Activation_function' + str(idx)] = activation_layer[activation]()
idx = self.hidden_layer_num + 1
self.layers['Affine' + str(idx)] = Affine(self.params['W' + str(idx)],
self.params['b' + str(idx)])
self.last_layer = SoftmaxWithLoss()
def loss(self, x, t):
"""Trouvez la fonction de perte
Parameters
----------
x :Des données d'entrée
t :Label enseignant
Returns
-------
Valeur de la fonction de perte
"""
y = self.predict(x)
weight_decay = 0
for idx in range(1, self.hidden_layer_num + 2):
W = self.params['W' + str(idx)]
weight_decay += 0.5 * self.weight_decay_lambda * np.sum(W ** 2)
return self.last_layer.forward(y, t) + weight_decay
def gradient(self, x, t):
"""Trouvez le dégradé (méthode de propagation de retour d'erreur)
Parameters
----------
x :Des données d'entrée
t :Label enseignant
Returns
-------
Variable de dictionnaire avec gradient de chaque couche
grads['W1']、grads['W2']、...Est le poids de chaque couche
grads['b1']、grads['b2']、...Est-ce que le biais de chaque couche
"""
# forward
self.loss(x, t)
# backward
dout = 1
dout = self.last_layer.backward(dout)
layers = list(self.layers.values())
layers.reverse()
for layer in layers:
dout = layer.backward(dout)
#Réglage
grads = {}
for idx in range(1, self.hidden_layer_num+2):
grads['W' + str(idx)] = self.layers['Affine' + str(idx)].dW + self.weight_decay_lambda * self.layers['Affine' + str(idx)].W
grads['b' + str(idx)] = self.layers['Affine' + str(idx)].db
return grads
Dropout
Dropout: Une méthode d'apprentissage tout en effaçant les neurones au hasard
↓
Abandon mis en œuvre dans Chainer
class Dropout:
def __init__(self, dropout_ratio=0.5):
self.dropout_ratio = dropout_ratio
self.mask = None
def forward(self, x, train_flg=True):
if train_flg:
self.mask = np.random.rand(*x.shape) > self.dropout_ratio
return x * self.mask
else
return x * (1.0 - self.dropout_ratio)
def backward(self, dout):
return dout * self.mask
Résultats lors de l'utilisation de Dropout
Exemples d'hyper paramètres jusqu'à présent ・ Nombre de neurones dans chaque couche · Taille du lot ・ Coefficient d'apprentissage ・ Décroissance du poids
Les hyperparamètres ne doivent pas être évalués pour les performances avec des données de test → Parce que cela entraînera un surapprentissage
Par conséquent, utilisez des * données de validation *, qui sont des données de vérification dédiées aux hyperparamètres.
En fonction du contenu des données, il peut être nécessaire de les créer par l'utilisateur Code qui sépare d'abord environ 20% des données d'entraînement en tant que données de vérification
(x_train, t_train), (x_test, t_test) = load_mnist()
#Mélanger les données d'entraînement
x_train, t_train = shuffle_dataset(x_train, t_train)
#Diviser les données de validation
validation_rate = 0.20
validation_num = int(x_train.shape[0] * validation_rate)
x_val - x_train[:validation_num]
t_val - t_train[:validation_num]
x_train - x_train[validation_num:]
t_train - t_train[validation_num:]
Répétez les étapes suivantes pour optimiser les hyperparamètres
STEP0 Spécifiez la plage d'hyper paramètres: spécifiez grossièrement au début
STEP1 Échantillonnage aléatoire de la plage d'hyperparamètres définie
STEP2 Apprenez à utiliser les valeurs d'hyperparamètres échantillonnées dans STEP1 Évaluez la précision de la reconnaissance des données d'agitation (Cependant, l'époque est définie petite)
STEP3 STEP21 et STEP2wp se répètent un certain nombre de fois (100 fois, etc.), et à partir du résultat de leur précision de reconnaissance Réduire la plage des hyper paramètres
Implémentation de l'échantillonnage aléatoire
wight_decay = 10 ** np.random.uniform(-8, -4)
lr = 10 ** np.random.uniform(-6, -2)
Best-1(val acc:0.84) | lr:0.008596628403945712, weight decay:3.075068633526172e-06 Best-2(val acc:0.83) | lr:0.009688160706596694, weight decay:5.876005684736357e-08 Best-3(val acc:0.78) | lr:0.007897858091143213, weight decay:3.792675246120474e-08 Best-4(val acc:0.77) | lr:0.008962267845301249, weight decay:4.0961888275354916e-07 Best-5(val acc:0.74) | lr:0.009453193380059509, weight decay:1.5625175027026464e-08 Best-6(val acc:0.73) | lr:0.0066257479672272536, weight decay:4.6591905625864734e-05 Best-7(val acc:0.72) | lr:0.007814005955583136, weight decay:4.9330072714643424e-06 Best-8(val acc:0.72) | lr:0.008895526423573389, weight decay:4.297901358238285e-06 Best-9(val acc:0.71) | lr:0.006419577071135049, weight decay:1.0848308972057103e-08 Best-10(val acc:0.69) | lr:0.006304961469167366, weight decay:1.6652787617252613e-07
En regardant les résultats ci-dessus, est-ce le prochain? wight_decay:10^-5-10^-8 lr:0.01-0,0001
Serrez et courez à nouveau
Best-1(val acc:0.82) | lr:0.009567378324697062, weight decay:8.329914422037397e-07 Best-2(val acc:0.81) | lr:0.009548817455702163, weight decay:1.9982550859731867e-08 Best-3(val acc:0.8) | lr:0.009291306660458992, weight decay:2.2402127139457002e-07 Best-4(val acc:0.8) | lr:0.008381207344259718, weight decay:8.66434339086022e-08 Best-5(val acc:0.8) | lr:0.009034895918329205, weight decay:1.2694550788849033e-08 Best-6(val acc:0.78) | lr:0.0057717685490679006, weight decay:5.933415739833589e-08 Best-7(val acc:0.77) | lr:0.005287013083466725, weight decay:5.585759633899539e-06 Best-8(val acc:0.77) | lr:0.006997138970399023, weight decay:3.1968420191793365e-06 Best-9(val acc:0.77) | lr:0.007756581950864435, weight decay:1.0281187459919625e-08 Best-10(val acc:0.77) | lr:0.008298200180190944, weight decay:7.389218444784364e-06
encore wight_decay:10^-6-10^-8 lr:0.01-0.001
Best-1(val acc:0.84) | lr:0.00971135118325034, weight decay:1.0394539789935165e-07 Best-2(val acc:0.83) | lr:0.009584343636422769, weight decay:3.1009381429608424e-07 Best-3(val acc:0.8) | lr:0.00832916652339643, weight decay:6.618592237280191e-07 Best-4(val acc:0.8) | lr:0.00959218016681805, weight decay:1.6405007969017657e-07 Best-5(val acc:0.78) | lr:0.006451172600874767, weight decay:4.0323875599954127e-07 Best-6(val acc:0.77) | lr:0.008024291255610844, weight decay:2.0050763243482884e-07 Best-7(val acc:0.77) | lr:0.009809009860349643, weight decay:4.934310445408953e-07 Best-8(val acc:0.77) | lr:0.009275309843754197, weight decay:5.343909279054936e-08 Best-9(val acc:0.76) | lr:0.00741122584285725, weight decay:1.588771824270857e-07 Best-10(val acc:0.75) | lr:0.006528687212003595, weight decay:1.3251120646717308e-07
Recommended Posts