Un débutant en apprentissage profond a essayé d'apprendre la fonction de péché avec un chainer. En tant que niveau débutant, je me suis senti un peu compris après avoir lu l'apprentissage profond, mais lorsque j'ai décidé d'écrire cet article, je me suis senti désespéré face à mon faible niveau de compréhension. L'apprentissage de la fonction sin a été fait par yuukiclass et bien d'autres, mais ce n'est pas mal.
Apprendre le sin (thêta) à partir d'angles (thêta) de 0 à 2π
[training data]
C'est la partie implémentation de l'apprentissage par mini-lots. Ce code est familier des exemples MNIST (certains changements tels que la plage). Cet apprentissage par mini-lots semble être populaire.
Extrait de l'apprentissage mini-batch
perm = np.random.permutation(N)
sum_loss = 0
for i in range(0, N, batchsize):
    x_batch = x_train[perm[i:i + batchsize]]
    y_batch = y_train[perm[i:i + batchsize]]
    model.zerograds()
    loss = model(x_batch,y_batch)
    sum_loss += loss.data * batchsize
    loss.backward()
    optimizer.update()
Le nombre de données est modifié de sorte que l'angle utilisé pendant le test soit différent de celui pendant l'entraînement. L'angle est modifié en divisant 0 à 2π en 1000 pendant l'apprentissage et en divisant 0 à 2π en 900 pendant le test.
Données d'entraînement&Extrait de la confirmation des résultats
#Données d'entraînement
N = 1000
x_train, y_train = get_dataset(N)
#données de test
N_test = 900
x_test, y_test = get_dataset(N_test)
'''
réduction
'''
    # test
    loss = model(x_test,y_test)
    test_losses.append(loss.data)
Mini taille de lot: 10
Époque (n_epoch): 500
Nombre de couches cachées: 2
Nombre d'unités de couche cachées (n_units): 100
Fonction d'activation: fonction linéaire normalisée (relu)
Abandon: Aucun (0%)
Optimisation: Adam
Fonction d'erreur de perte: fonction d'erreur quadratique moyenne (mean_squared_error)
Tous les paramètres sont appropriés.
L'ensemble
# -*- coding: utf-8 -*-
#Importer depuis une extrémité pour le moment
import numpy as np
import chainer
from chainer import cuda, Function, gradient_check, Variable, optimizers, serializers, utils
from chainer import Link, Chain, ChainList
import chainer.functions as F
import chainer.links as L
import time
from matplotlib import pyplot as plt
#Les données
def get_dataset(N):
    x = np.linspace(0, 2 * np.pi, N)
    y = np.sin(x)
    return x, y
#réseau neuronal
class MyChain(Chain):
    def __init__(self, n_units=10):
        super(MyChain, self).__init__(
             l1=L.Linear(1, n_units),
             l2=L.Linear(n_units, n_units),
             l3=L.Linear(n_units, 1))
    def __call__(self, x_data, y_data):
        x = Variable(x_data.astype(np.float32).reshape(len(x_data),1)) #Convertir en objet variable
        y = Variable(y_data.astype(np.float32).reshape(len(y_data),1)) #Convertir en objet variable
        return F.mean_squared_error(self.predict(x), y)
    def  predict(self, x):
        h1 = F.relu(self.l1(x))
        h2 = F.relu(self.l2(h1))
        h3 = self.l3(h2)
        return h3
    def get_predata(self, x):
        return self.predict(Variable(x.astype(np.float32).reshape(len(x),1))).data
# main
if __name__ == "__main__":
    #Données d'entraînement
    N = 1000
    x_train, y_train = get_dataset(N)
    #données de test
    N_test = 900
    x_test, y_test = get_dataset(N_test)
    #Paramètres d'apprentissage
    batchsize = 10
    n_epoch = 500
    n_units = 100
    #La modélisation
    model = MyChain(n_units)
    optimizer = optimizers.Adam()
    optimizer.setup(model)
    #Boucle d'apprentissage
    train_losses =[]
    test_losses =[]
    print "start..."
    start_time = time.time()
    for epoch in range(1, n_epoch + 1):
        # training
        perm = np.random.permutation(N)
        sum_loss = 0
        for i in range(0, N, batchsize):
            x_batch = x_train[perm[i:i + batchsize]]
            y_batch = y_train[perm[i:i + batchsize]]
            model.zerograds()
            loss = model(x_batch,y_batch)
            sum_loss += loss.data * batchsize
            loss.backward()
            optimizer.update()
        average_loss = sum_loss / N
        train_losses.append(average_loss)
        # test
        loss = model(x_test,y_test)
        test_losses.append(loss.data)
        #Processus d'apprentissage des extrants
        if epoch % 10 == 0:
            print "epoch: {}/{} train loss: {} test loss: {}".format(epoch, n_epoch, average_loss, loss.data)
        #Créer un graphique des résultats d'apprentissage
        if epoch in [10, 500]:
            theta = np.linspace(0, 2 * np.pi, N_test)
            sin = np.sin(theta)
            test = model.get_predata(theta)
            plt.plot(theta, sin, label = "sin")
            plt.plot(theta, test, label = "test")
            plt.legend()
            plt.grid(True)
            plt.xlim(0, 2 * np.pi)
            plt.ylim(-1.2, 1.2)
            plt.title("sin")
            plt.xlabel("theta")
            plt.ylabel("amp")
            plt.savefig("fig/fig_sin_epoch{}.png ".format(epoch)) #En supposant que le dossier fig existe
            plt.clf()
    print "end"
    interval = int(time.time() - start_time)
    print "Temps d'exécution: {}sec".format(interval)
    #Graphique d'erreur
    plt.plot(train_losses, label = "train_loss")
    plt.plot(test_losses, label = "test_loss")
    plt.yscale('log')
    plt.legend()
    plt.grid(True)
    plt.title("loss")
    plt.xlabel("epoch")
    plt.ylabel("loss")
    plt.savefig("fig/fig_loss.png ") #En supposant que le dossier fig existe
    plt.clf()
L'erreur a tendance à diminuer à mesure que l'époque (nombre d'apprentissage) augmente. Il n'y avait pas de différence significative entre les erreurs d'apprentissage et de test. Je pense que l'erreur lors des tests est légèrement meilleure que celle lors de l'apprentissage car la méthode de calcul de l'erreur est différente.

Lorsque l'époque est de 10, il est difficile de dire que c'est une fonction péché, mais lorsque l'apprentissage progresse vers 500, elle est assez proche de la fonction péché.
epoch: 10

epoch: 500

Pour le moment, j'ai pu entraîner la fonction péché avec chainer.
Cependant, pour une raison quelconque, plus l'angle est grand, plus l'erreur est grande. Je pensais que si l'ordre des angles à apprendre était aléatoire, la variation de l'erreur pour chaque angle pourrait être supprimée, mais elle semble être différente. Ce n'est pas bien compris.
J'ai essayé d'approcher la fonction sin en utilisant chainer (re-challenge)
Chainer et apprentissage en profondeur appris par approximation de fonction
Réseau neuronal de type à propagation directe régressive avec chaînage
Recommended Posts