C'est un record d'apprentissage lorsque j'ai relevé le Rabbit Challenge dans le but de réussir la qualification JDLA (Japan Deep Learning Association) E, qui se tiendra les 19 et 20 janvier 2021.
Rabbit Challenge est un cours qui utilise le matériel pédagogique édité à partir de la vidéo enregistrée du cours de fréquentation scolaire du «cours d'apprentissage en profondeur qui peut être écrasé sur le terrain». Il n'y a pas de support pour les questions, mais c'est un cours bon marché (le prix le plus bas en juin 2020) pour passer l'examen de qualification E.
Veuillez vérifier les détails à partir du lien ci-dessous.
Mathématiques appliquées Apprentissage automatique Apprentissage en profondeur (jour1) Apprentissage en profondeur (jour2) Apprentissage profond (jour3) Apprentissage en profondeur (jour 4)
Au fur et à mesure que la méthode de rétropropagation d'erreur progresse vers les couches inférieures, le dégradé devient de plus en plus doux. Par conséquent, la mise à jour par la méthode de descente de gradient modifie à peine les paramètres de la couche inférieure et l'apprentissage ne converge pas vers la valeur optimale.
--Sélection de la fonction d'activation
Fonction ReLU
Réglage du poids initial --Xavier: Lorsque le nombre de nœuds dans la couche précédente est n, la valeur obtenue en multipliant l'élément poids par $ \ sqrt {\ frac {1} {n}} $. Les fonctions d'activation sont ReLu, la fonction sigmoïde (logistique) et la fonction tangente bicurve (tanh). --He: Lorsque le nombre de nœuds dans la couche précédente est n, la valeur obtenue en multipliant l'élément de pondération par $ \ sqrt {\ frac {2} {n}} $. La fonction d'activation est ReLu.
Que se passe-t-il si je règle le poids initial sur 0? → Parce que toutes les valeurs sont transmises avec la même valeur. Les paramètres ne sont plus réglés.
La moyenne et la variance du mini-lot
Contribution à la disparition du gradient lors du changement de la fonction d'activation, de la valeur de poids initiale et de la présence / absence de normalisation des lots
import sys, os
sys.path.append(os.pardir) #Paramètres d'importation des fichiers dans le répertoire parent
import numpy as np
from common import layers
from collections import OrderedDict
from common import functions
from data.mnist import load_mnist
import matplotlib.pyplot as plt
from common import optimizer
class MultiLayerNet:
'''
input_size:Nombre de nœuds dans la couche d'entrée
hidden_size_list:Liste des nœuds de couche masqués
output_size:Nombre de nœuds dans la couche de sortie
activation:Fonction d'activation
weight_init_std:Comment initialiser les poids
weight_decay_lambda:Force de la régularisation L2
use_dropout:Avec ou sans décrochage
dropout_ratio:Taux d'abandon
use_batchnorm:Avec ou sans normalisation des lots
'''
def __init__(self, input_size, hidden_size_list, output_size, activation='relu', weight_init_std='relu', weight_decay_lambda=0,
use_dropout = False, dropout_ratio = 0.5, use_batchnorm=False):
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.use_dropout = use_dropout
self.weight_decay_lambda = weight_decay_lambda
self.use_batchnorm = use_batchnorm
self.params = {}
#Initialisation du poids
self.__init_weight(weight_init_std)
#Génération de couches
activation_layer = {'sigmoid': layers.Sigmoid, 'relu': layers.Relu}
self.layers = OrderedDict()
for idx in range(1, self.hidden_layer_num+1):
self.layers['Affine' + str(idx)] = layers.Affine(self.params['W' + str(idx)], self.params['b' + str(idx)])
if self.use_batchnorm:
self.params['gamma' + str(idx)] = np.ones(hidden_size_list[idx-1])
self.params['beta' + str(idx)] = np.zeros(hidden_size_list[idx-1])
self.layers['BatchNorm' + str(idx)] = layers.BatchNormalization(self.params['gamma' + str(idx)], self.params['beta' + str(idx)])
self.layers['Activation_function' + str(idx)] = activation_layer[activation]()
if self.use_dropout:
self.layers['Dropout' + str(idx)] = layers.Dropout(dropout_ratio)
idx = self.hidden_layer_num + 1
self.layers['Affine' + str(idx)] = layers.Affine(self.params['W' + str(idx)], self.params['b' + str(idx)])
self.last_layer = layers.SoftmaxWithLoss()
def __init_weight(self, weight_init_std):
all_size_list = [self.input_size] + self.hidden_size_list + [self.output_size]
for idx in range(1, len(all_size_list)):
scale = weight_init_std
if str(weight_init_std).lower() in ('relu', 'he'):
scale = np.sqrt(2.0 / all_size_list[idx - 1]) #Valeur initiale recommandée lors de l'utilisation de ReLU
elif str(weight_init_std).lower() in ('sigmoid', 'xavier'):
scale = np.sqrt(1.0 / all_size_list[idx - 1]) #Valeur initiale recommandée lors de l'utilisation de sigmoïde
self.params['W' + str(idx)] = scale * np.random.randn(all_size_list[idx-1], all_size_list[idx])
self.params['b' + str(idx)] = np.zeros(all_size_list[idx])
def predict(self, x, train_flg=False):
for key, layer in self.layers.items():
if "Dropout" in key or "BatchNorm" in key:
x = layer.forward(x, train_flg)
else:
x = layer.forward(x)
return x
def loss(self, x, d, train_flg=False):
y = self.predict(x, train_flg)
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, d) + weight_decay
def accuracy(self, X, D):
Y = self.predict(X, train_flg=False)
Y = np.argmax(Y, axis=1)
if D.ndim != 1 : D = np.argmax(D, axis=1)
accuracy = np.sum(Y == D) / float(X.shape[0])
return accuracy
def gradient(self, x, d):
# forward
self.loss(x, d, train_flg=True)
# 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.params['W' + str(idx)]
grads['b' + str(idx)] = self.layers['Affine' + str(idx)].db
if self.use_batchnorm and idx != self.hidden_layer_num+1:
grads['gamma' + str(idx)] = self.layers['BatchNorm' + str(idx)].dgamma
grads['beta' + str(idx)] = self.layers['BatchNorm' + str(idx)].dbeta
return grads
#Couche de régularisation par lots
class BatchNormalization:
'''
gamma:Coefficient d'échelle
beta:décalage
momentum:inertie
running_mean:Moyenne à utiliser lors des tests
running_var:Distribution utilisée lors des tests
'''
def __init__(self, gamma, beta, momentum=0.9, running_mean=None, running_var=None):
self.gamma = gamma
self.beta = beta
self.momentum = momentum
self.input_shape = None
self.running_mean = running_mean
self.running_var = running_var
#Données intermédiaires à utiliser en arrière
self.batch_size = None
self.xc = None
self.std = None
self.dgamma = None
self.dbeta = None
def forward(self, x, train_flg=True):
if self.running_mean is None:
N, D = x.shape
self.running_mean = np.zeros(D)
self.running_var = np.zeros(D)
if train_flg:
mu = x.mean(axis=0) #moyenne
xc = x - mu #Centre x
var = np.mean(xc**2, axis=0) #Distribué
std = np.sqrt(var + 10e-7) #mise à l'échelle
xn = xc / std
self.batch_size = x.shape[0]
self.xc = xc
self.xn = xn
self.std = std
self.running_mean = self.momentum * self.running_mean + (1-self.momentum) * mu #Moyenne pondérée des valeurs moyennes
self.running_var = self.momentum * self.running_var + (1-self.momentum) * var #Moyenne pondérée des valeurs de variance
else:
xc = x - self.running_mean
xn = xc / ((np.sqrt(self.running_var + 10e-7)))
out = self.gamma * xn + self.beta
return out
def backward(self, dout):
dbeta = dout.sum(axis=0)
dgamma = np.sum(self.xn * dout, axis=0)
dxn = self.gamma * dout
dxc = dxn / self.std
dstd = -np.sum((dxn * self.xc) / (self.std * self.std), axis=0)
dvar = 0.5 * dstd / self.std
dxc += (2.0 / self.batch_size) * self.xc * dvar
dmu = np.sum(dxc, axis=0)
dx = dxc - dmu / self.batch_size
self.dgamma = dgamma
self.dbeta = dbeta
return dx
#Lire les données
# (x_train, d_train), (x_test, d_test) = load_mnist(normalize=True, one_hot_label=True)
(x_train, d_train), (x_test, d_test) = load_mnist(normalize=True)
print('Lecture des données terminée')
activations = ['sigmoid', 'relu']
weight_init_stds = [0.01, 'Xavier', 'He']
use_batchnorms = [False, True]
iters_num = 2000
train_size = x_train.shape[0]
batch_size = 100
learning_rate = 0.1
plot_interval = 100
plot_idx = 0
for k in range(len(activations)):
for l in range(len(weight_init_stds)):
for m in range(len(use_batchnorms)):
network = MultiLayerNet(input_size=784, hidden_size_list=[40, 20], output_size=10, activation=activations[k], weight_init_std=weight_init_stds[l], use_batchnorm=use_batchnorms[m])
train_loss_list = []
accuracies_train = []
accuracies_test = []
lists = []
plot_idx = plot_idx + 1
for i in range(iters_num):
batch_mask = np.random.choice(train_size, batch_size)
x_batch = x_train[batch_mask]
d_batch = d_train[batch_mask]
#Pente
grad = network.gradient(x_batch, d_batch)
for key in ('W1', 'W2', 'W3', 'b1', 'b2', 'b3'):
network.params[key] -= learning_rate * grad[key]
loss = network.loss(x_batch, d_batch)
train_loss_list.append(loss)
if (i + 1) % plot_interval == 0:
accr_test = network.accuracy(x_test, d_test)
accuracies_test.append(accr_test)
accr_train = network.accuracy(x_batch, d_batch)
accuracies_train.append(accr_train)
print('Generation: ' + str(i+1) + '.Taux de réponse correct(entraînement) = ' + str(accr_train))
print(' : ' + str(i+1) + '.Taux de réponse correct(tester) = ' + str(accr_test))
lists = range(0, iters_num, plot_interval)
plt.rcParams['figure.figsize'] = (12.0, 10.0)
plt.subplot(4,3,plot_idx)
plt.plot(lists, accuracies_train, label='training set')
plt.plot(lists, accuracies_test, label='test set')
plt.legend(loc='lower right')
plt.title(activations[k] + ', ' + str(weight_init_stds[l]) + ',Normalisation par lots' + str(use_batchnorms[m]) + ' (' + str(np.round(accuracies_test[-1],2)) + ')')
plt.xlabel('count')
plt.ylabel('accuracy')
plt.ylim(0, 1.0)
#Affichage du graphique
plt.tight_layout()
# plt.suptitle('Précision de la prédiction lorsque les valeurs initiales de la fonction d'activation et du poids sont modifiées', fontsize = 16)
plt.show()
Si la valeur du taux d'apprentissage est élevée, la valeur optimale ne sera pas atteinte pour toujours et divergera. Si la valeur du taux d'apprentissage est faible, elle ne divergera pas, mais si elle est trop petite, il faudra du temps pour converger ou il sera difficile de converger vers la valeur optimale locale globale.
--Élan
[Avantages de l'élan]
Gradient de momentum
#Pente
grad = network.gradient(x_batch, d_batch)
if i == 0:
v = {}
for key in ('W1', 'W2', 'W3', 'b1', 'b2', 'b3'):
if i == 0:
v[key] = np.zeros_like(network.params[key])
v[key] = momentum * v[key] - learning_rate * grad[key]
network.params[key] += v[key]
loss = network.loss(x_batch, d_batch)
train_loss_list.append(loss)
[Avantages d'AdaGrad]
Dégradé AdaGrad
#Pente
grad = network.gradient(x_batch, d_batch)
if i == 0:
h = {}
for key in ('W1', 'W2', 'W3', 'b1', 'b2', 'b3'):
if i == 0:
h[key] = np.full_like(network.params[key], 1e-4)
else:
h[key] += np.square(grad[key])
network.params[key] -= learning_rate * grad[key] / (np.sqrt(h[key]))
loss = network.loss(x_batch, d_batch)
train_loss_list.append(loss)
[Avantages de RMS Drop]
Gradient de chute RMS
#Pente
grad = network.gradient(x_batch, d_batch)
if i == 0:
h = {}
for key in ('W1', 'W2', 'W3', 'b1', 'b2', 'b3'):
if i == 0:
h[key] = np.zeros_like(network.params[key])
h[key] *= decay_rate
h[key] += (1 - decay_rate) * np.square(grad[key])
network.params[key] -= learning_rate * grad[key] / (np.sqrt(h[key]) + 1e-7)
loss = network.loss(x_batch, d_batch)
train_loss_list.appen
[Avantages d'Adam]
Gradient d'Adam
#Pente
grad = network.gradient(x_batch, d_batch)
if i == 0:
m = {}
v = {}
learning_rate_t = learning_rate * np.sqrt(1.0 - beta2 ** (i + 1)) / (1.0 - beta1 ** (i + 1))
for key in ('W1', 'W2', 'W3', 'b1', 'b2', 'b3'):
if i == 0:
m[key] = np.zeros_like(network.params[key])
v[key] = np.zeros_like(network.params[key])
m[key] += (1 - beta1) * (grad[key] - m[key])
v[key] += (1 - beta2) * (grad[key] ** 2 - v[key])
network.params[key] -= learning_rate_t * m[key] / (np.sqrt(v[key]) + 1e-7)
loss = network.loss(x_batch, d_batch)
train_loss_list.append(loss)
La courbe d'apprentissage varie entre l'erreur de test et l'erreur d'apprentissage, et la formation est spécialisée pour un échantillon d'apprentissage spécifique. Il existe les méthodes suivantes pour éviter le surapprentissage.
--Utiliser la norme L2: Estimation de crête (estimation de réduction ... Estimer le paramètre plus proche de 0)
En utilisant la norme L1: Estimation du lasso (le moindre retrait absolu et opérateur de sélection) (estimation clairsemée ... certains paramètres sont estimés à exactement 0)
Pénalité proportionnelle à la norme L1 du paramètre
De nombreux paramètres deviennent 0 lorsque $ \ lambda $ est augmenté $ \ rightarrow $ Générer un modèle fragmenté par sélection de variables
Abandonner En supprimant aléatoirement des nœuds et en les entraînant, on peut interpréter que différents modèles sont entraînés sans changer la quantité de données.
Pas de régularisation (reproduction du surapprentissage)
(optimizer.SGD(learning_rate=0.01))
Régularisation L2
(learning_rate=0.01)
Régularisation L1
(learning_rate=0.1)
Décrochage
(optimizer.SGD(learning_rate=0.01), weight_decay_lambda = 0.01)
(optimizer.Momentum(learning_rate=0.01, momentum=0.9), weight_decay_lambda = 0.01)
(optimizer.AdaGrad(learning_rate=0.01), weight_decay_lambda = 0.01)
(optimizer.Adam(learning_rate=0.01), weight_decay_lambda = 0.01)
Abandon + régularisation L1
(dropout_ratio = 0.1, weight_decay_lambda=0.005)
--Bias
--Foulée
Si la taille d'entrée est W × H, la taille du filtre est Fw × Fh, le rembourrage est p, la foulée est s et la taille de sortie de la couche de convolution est OW × OH, OW et OH sont calculés par les équations suivantes.
Inconvénients de la couche entièrement connectée: Dans le cas d'une image, il s'agit de données 3D verticales, horizontales et de canal, mais elles sont traitées comme des données 1D. Autrement dit, la relation entre chaque canal RVB n'est pas reflétée dans l'apprentissage.
AlexNet
Il est nommé Alex Net d'après le nom de l'auteur principal de l'article, Alex Krizhevsky. Il est composé de trois couches entièrement connectées, dont une couche de pliage à cinq couches et une couche de mise en commun. Comparé au LeNet, un CNN conçu pour la première fois en 1998 par Yann LeCun et al., Il a une structure considérablement plus profonde. Pour éviter le surapprentissage, nous utilisons des abandons pour la sortie de la couche entièrement connectée de taille 4096.
Chainer's AlexNet a le code suivant.
alex.py
import chainer
import chainer.functions as F
import chainer.links as L
class Alex(chainer.Chain):
"""Single-GPU AlexNet without partition toward the channel axis."""
insize = 227
def __init__(self):
super(Alex, self).__init__()
with self.init_scope():
self.conv1 = L.Convolution2D(None, 96, 11, stride=4)
self.conv2 = L.Convolution2D(None, 256, 5, pad=2)
self.conv3 = L.Convolution2D(None, 384, 3, pad=1)
self.conv4 = L.Convolution2D(None, 384, 3, pad=1)
self.conv5 = L.Convolution2D(None, 256, 3, pad=1)
self.fc6 = L.Linear(None, 4096)
self.fc7 = L.Linear(None, 4096)
self.fc8 = L.Linear(None, 1000)
def __call__(self, x, t):
h = F.max_pooling_2d(F.local_response_normalization(
F.relu(self.conv1(x))), 3, stride=2)
h = F.max_pooling_2d(F.local_response_normalization(
F.relu(self.conv2(h))), 3, stride=2)
h = F.relu(self.conv3(h))
h = F.relu(self.conv4(h))
h = F.max_pooling_2d(F.relu(self.conv5(h)), 3, stride=2)
h = F.dropout(F.relu(self.fc6(h)))
h = F.dropout(F.relu(self.fc7(h)))
h = self.fc8(h)
loss = F.softmax_cross_entropy(h, t)
chainer.report({'loss': loss, 'accuracy': F.accuracy(h, t)}, self)
return loss