[PYTHON] [Rabbit Challenge (E qualification)] Apprentissage en profondeur (jour2)

introduction

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.

Liste des sujets

Mathématiques appliquées Apprentissage automatique Apprentissage en profondeur (jour1) Apprentissage en profondeur (jour2) Apprentissage profond (jour3) Apprentissage en profondeur (jour 4)

Section 1: Problème de disparition de gradient

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.

Solution pour la disparition du gradient

--Sélection de la fonction d'activation

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 $\mu_t=\frac{1}{N_t}\sum_{i=1}^{N_t}x_{ni}, \quad \sigma_t^2=\frac{1}{N_t}\sum_{i=1}^{N_t}(x_{ni}-\mu_t)^2$ Lorsque la sortie est normalisée $\hat x_{ni}=\frac{x_{ni}-\mu_t}{\sqrt{\sigma_t^2-\theta}}$ Sera. Cette sortie normalisée est transformée linéairement avec le paramètre de mise à l'échelle apprenable $ \ gamma $ et le paramètre de décalage $ \ beta . $y_{ni}=\gamma x_{ni}+\beta$$

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()

image.png

Section 2: Méthode d'optimisation du taux d'apprentissage

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 $ V_t = \mu V_{t-1}-\epsilon\nabla E $ $ w^{(t+1)} = w^{(t)}+V_t $ Après avoir soustrait le produit de l'erreur différenciée par le paramètre et le taux d'apprentissage, le produit du poids actuel moins le poids précédent et l'inertie est ajouté.

[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)

image.png

[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)    

image.png

[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

image.png

[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)

image.png

Section 3: Superapprentissage

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) $ \sum_{i=1}^n(y_i-\beta_0-\sum_{j=1}^p\beta_jx_{ij})^2 + \lambda\sum_{j=1}^p\beta_j^2 $ $ \ lambda $: Hyperparamètre -Si $ \ lambda $ vaut zéro, c'est la même chose que la méthode des moindres carrés. -Si vous augmentez $ \ lambda $, $ \ beta_1,…, \ beta_p $ approchera de 0 (notez qu'il n'y a pas de pénalité pour $ \ beta_0 $) --Déterminer une valeur appropriée par vérification croisée, etc.


Pas de régularisation (reproduction du surapprentissage)
(optimizer.SGD(learning_rate=0.01)) image.png


Régularisation L2
(learning_rate=0.01) image.png


Régularisation L1
(learning_rate=0.1) image.png


Décrochage
(optimizer.SGD(learning_rate=0.01), weight_decay_lambda = 0.01) image.png (optimizer.Momentum(learning_rate=0.01, momentum=0.9), weight_decay_lambda = 0.01) image.png (optimizer.AdaGrad(learning_rate=0.01), weight_decay_lambda = 0.01) image.png (optimizer.Adam(learning_rate=0.01), weight_decay_lambda = 0.01) image.png


Abandon + régularisation L1
(dropout_ratio = 0.1, weight_decay_lambda=0.005) image.png

Section 4: Concept de réseau neuronal convolutif

Concept arithmétique convolutif

--Bias image.png

--Foulée image.png

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. $ OW=\frac{W+2p-Fw}{s}+1, \quad OH=\frac{H+2p-Fh}{s}+1 $

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.

Section 5: Dernier CNN (bien qu'il ne puisse pas être appelé le dernier en 2020 ...)

AlexNet

スクリーンショット 2020-07-18 19.37.25.png

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

Recommended Posts

[Rabbit Challenge (E qualification)] Apprentissage en profondeur (jour2)
[Rabbit Challenge (E qualification)] Apprentissage en profondeur (jour3)
[Rabbit Challenge (E qualification)] Deep learning (day4)
[Rabbit Challenge (E qualification)] Mathématiques appliquées
Défi de lapin d'apprentissage automatique
<Cours> Apprentissage en profondeur: Day2 CNN
<Cours> Apprentissage en profondeur: Jour 1 NN
Sujets> Deep Learning: Day3 RNN
[Deep Learning Association E Qualification] Que faire pour recevoir
Étudiez en profondeur le Deep Learning [DW Day 0]
L'apprentissage en profondeur
<Cours> Deep Learning Day4 Renforcement de l'apprentissage / flux de tension
Mémorandum d'apprentissage profond
Commencer l'apprentissage en profondeur
Apprentissage Python jour 4
Apprentissage en profondeur Python
Apprentissage profond × Python
Premier apprentissage profond ~ Lutte ~
Python: pratique du Deep Learning
Fonctions d'apprentissage en profondeur / d'activation
Apprentissage profond à partir de zéro
Fiche d'apprentissage 4 (8e jour)
Fiche d'apprentissage 9 (13e jour)
Fiche d'apprentissage 3 (7e jour)
Deep learning 1 Pratique du deep learning
Apprentissage profond / entropie croisée
Fiche d'apprentissage 5 (9e jour)
Fiche d'apprentissage 6 (10e jour)
Premier apprentissage profond ~ Préparation ~
Enregistrement d'apprentissage de la programmation 2ème jour
Première solution d'apprentissage en profondeur ~
Fiche d'apprentissage 8 (12e jour)
[AI] Apprentissage métrique profond
Fiche d'apprentissage 1 (4e jour)
Fiche d'apprentissage 7 (11e jour)
J'ai essayé le deep learning
Python: réglage du Deep Learning
Fiche d'apprentissage 2 (6e jour)
Technologie d'apprentissage en profondeur à grande échelle
Fiche d'apprentissage 16 (20e jour)
Dossier d'apprentissage 22 (26e jour)
Fonction d'apprentissage profond / softmax
[Apprentissage en profondeur] Classification d'images avec un réseau neuronal convolutif [DW jour 4]
Chanson auto-exploitée par apprentissage en profondeur (édition Stacked LSTM) [DW Day 6]