Deep Learning Java from scratch Chapter 5 Méthode de propagation de retour d'erreur

table des matières

5.4 Implémentation de couche simple

5.4.1 Implémentation de la couche de multiplication

static class MulLayer {

    private double x, y;

    public double forward(double x, double y) {
        this.x = x;
        this.y = y;
        return x * y;
    }

    //Étant donné que Java ne peut pas renvoyer plusieurs valeurs, il retourne sous forme de tableau.
    public double[] backward(double dout) {
        return new double[] {dout * y, dout * x};
    }
}

double apple = 100;
double apple_num = 2;
double tax = 1.1;
// Layer
MulLayer mul_apple_layer = new MulLayer();
MulLayer mul_tax_layer = new MulLayer();
// forward
double apple_price = mul_apple_layer.forward(apple, apple_num);
double price = mul_tax_layer.forward(apple_price, tax);
assertEquals(220.0, price, 5e-6);
// backward
double dprice = 1;
double[] dapple_price_tax = mul_tax_layer.backward(dprice);
double[] dapple_num = mul_apple_layer.backward(dapple_price_tax[0]);
assertEquals(2.2, dapple_num[0], 5e-6);
assertEquals(110.0, dapple_num[1], 5e-6);
assertEquals(200.0, dapple_price_tax[1], 5e-6);

5.4.2 Implémentation de la couche d'addition

static class AddLayer {

    public double forward(double x, double y) {
        return x + y;
    }

    public double[] backward(double dout) {
        return new double[] {dout, dout};
    }
}

double apple = 100;
double apple_num = 2;
double orange = 150;
double orange_num = 3;
double tax = 1.1;
// Layer
MulLayer mul_apple_layer = new MulLayer();
MulLayer mul_orange_layer = new MulLayer();
AddLayer add_apple_orange_layer = new AddLayer();
MulLayer mul_tax_layer = new MulLayer();
// forward
double apple_price = mul_apple_layer.forward(apple, apple_num);
double orange_price = mul_orange_layer.forward(orange, orange_num);
double all_price = add_apple_orange_layer.forward(apple_price, orange_price);
double price = mul_tax_layer.forward(all_price, tax);
// backward
double dprice = 1;
double[] dall_price = mul_tax_layer.backward(dprice);
double[] dapple_dorange_price = add_apple_orange_layer.backward(dall_price[0]);
double[] dorange = mul_orange_layer.backward(dapple_dorange_price[1]);
double[] dapple = mul_apple_layer.backward(dapple_dorange_price[0]);
assertEquals(715.0, price, 5e-6);
assertEquals(110.0, dapple[1], 5e-6);
assertEquals(2.2, dapple[0], 5e-6);
assertEquals(3.3, dorange[0], 5e-6);
assertEquals(165.0, dorange[1], 5e-6);
assertEquals(650.0, dall_price[1], 5e-6);

5.5 Implémentation de la couche de fonction d'activation

5.5.1 Couche ReLU

L'implémentation de classe de l'exemple ReLU utilisant la méthode de propagation de retour d'erreur est Relu )est.

INDArray x = Nd4j.create(new double[][] {{1.0, -0.5}, {-2.0, 3.0}});
assertEquals("[[1.00,-0.50],[-2.00,3.00]]", Util.string(x));
//Le test est différent de ce livre.
Relu relu = new Relu();
INDArray a = relu.forward(x);
//Résultat de l'avant
assertEquals("[[1.00,0.00],[0.00,3.00]]", Util.string(a));
// mask
assertEquals("[[1.00,0.00],[0.00,1.00]]", Util.string(relu.mask));
INDArray dout = Nd4j.create(new double[][] {{5, 6}, {7, 8}});
INDArray b = relu.backward(dout);
//Résultats de l'arrière
assertEquals("[[5.00,0.00],[0.00,8.00]]", Util.string(b));

5.5.2 Couche sigmoïde

La classe d'implémentation de la couche Sigmoid utilisant la méthode de propagation de retour d'erreur est Sigmoidest.

5.6 Implémentation de la couche Affine Softmax

5.6.1 Couche affine

La classe d'implémentation de la couche Affine utilisant la méthode de propagation de retour d'erreur est Affineest.

try (Random r = new DefaultRandom()) {
    INDArray X = r.nextGaussian(new int[] {2});
    INDArray W = r.nextGaussian(new int[] {2, 3});
    INDArray B = r.nextGaussian(new int[] {3});
    assertArrayEquals(new int[] {1, 2}, X.shape());
    assertArrayEquals(new int[] {2, 3}, W.shape());
    assertArrayEquals(new int[] {1, 3}, B.shape());
    INDArray Y = X.mmul(W).addRowVector(B);
    assertArrayEquals(new int[] {1, 3}, Y.shape());
}

5.6.2 Version batch Couche affine

INDArray X_dot_W = Nd4j.create(new double[][] {{0, 0, 0}, {10, 10, 10}});
INDArray B = Nd4j.create(new double[] {1, 2, 3});
assertEquals("[[0.00,0.00,0.00],[10.00,10.00,10.00]]", Util.string(X_dot_W));
assertEquals("[[1.00,2.00,3.00],[11.00,12.00,13.00]]", Util.string(X_dot_W.addRowVector(B)));

5.6.3 Couche Softmax-with-Loss

La classe d'implémentation de la couche Softmax-with-Loss utilisant la méthode de propagation de retour d'erreur est [SoftmaxWithLoss](https://github.com/saka1029/Deep.Learning/blob/master/src/main/java/deep/learning/common /SoftmaxWithLoss.java).

5.7 Mise en œuvre de la méthode de propagation des erreurs

La classe du réseau neuronal à deux couches utilisant la méthode de propagation de retour d'erreur est [TwoLayerNet](https://github.com/saka1029/Deep.Learning/blob/master/src/main/java/deep/learning/C5/TwoLayerNet. Java). Il y a aussi TwoLayerNet au chapitre 4, mais c'est une différenciation numérique. C'est celui qui utilise. Afin de rendre chaque couche plus facile à gérer dans cette implémentation, les deux interfaces suivantes sont définies.

public interface Layer {

    INDArray forward(INDArray x);
    INDArray backward(INDArray x);

}

public interface LastLayer {

    double forward(INDArray x, INDArray t);
    INDArray backward(INDArray x);

}

5.7.3 Méthode de confirmation de gradient de la méthode de propagation en retour d'erreur

La comparaison de gradient avec la méthode de différenciation numérique est considérablement plus grande que celle décrite dans ce livre. Par conséquent, ici, il est comparé au gradient par différenciation numérique divisé par 3. Functions.average (INDArray) est la moyenne de tous les éléments La méthode que vous souhaitez.

public static double average(INDArray x) {
    // x.length()Renvoie le nombre total d'éléments.
    return x.sumNumber().doubleValue() / x.length();
}
//Lisez les données d'entraînement du MNIST.
MNISTImages train = new MNISTImages(Constants.TrainImages, Constants.TrainLabels);
TwoLayerNet network = new TwoLayerNet(784, 50, 10);
//Image normalisée et une-Retirez respectivement les 3 premières étiquettes chaudes.
int batch_size = 3;
INDArray x_batch = train.normalizedImages().get(NDArrayIndex.interval(0, batch_size));
INDArray t_batch = train.oneHotLabels().get(NDArrayIndex.interval(0, batch_size));
//Trouvez le dégradé par différenciation numérique.
Params grad_numerical = network.numerical_gradient(x_batch, t_batch);
//Trouvez le dégradé par la méthode de propagation d'erreur.
Params grad_backprop = network.gradient(x_batch, t_batch);
//Comparez les résultats de la différenciation numérique et de la méthode de propagation d'erreur.
double diff_W1 = Functions.average(Transforms.abs(grad_backprop.get("W1").sub(grad_numerical.get("W1"))));
double diff_b1 = Functions.average(Transforms.abs(grad_backprop.get("b1").sub(grad_numerical.get("b1"))));
double diff_W2 = Functions.average(Transforms.abs(grad_backprop.get("W2").sub(grad_numerical.get("W2"))));
double diff_b2 = Functions.average(Transforms.abs(grad_backprop.get("b2").sub(grad_numerical.get("b2"))));
System.out.println("W1=" + diff_W1);
System.out.println("b1=" + diff_b1);
System.out.println("W2=" + diff_W2);
System.out.println("b2=" + diff_b2);
//La différence est un peu plus grande que ce livre.
assertTrue(diff_b1 < 1e-3);
assertTrue(diff_W2 < 1e-3);
assertTrue(diff_b2 < 1e-3);
assertTrue(diff_W1 < 1e-3);

5.7.4 Apprentissage en utilisant la méthode de propagation de retour d'erreur

C'est beaucoup plus rapide que l'apprentissage utilisant la différenciation numérique. Dans mon environnement, 10000 boucles sont effectuées en environ 89 secondes. Cependant, la précision de reconnaissance finale était d'environ 84%, ce qui était inférieur à la différenciation numérique. Il y a probablement une erreur quelque part dans l'implémentation de la couche, car la différence est grande lorsque l'on compare le gradient au cas différentiel numérique.

//Lisez les données d'entraînement du MNIST.
MNISTImages train = new MNISTImages(Constants.TrainImages, Constants.TrainLabels);
INDArray x_train = train.normalizedImages();
INDArray t_train = train.oneHotLabels();
//Lisez les données de test MNIST.
MNISTImages test = new MNISTImages(Constants.TestImages, Constants.TestLabels);
INDArray x_test = test.normalizedImages();
INDArray t_test = test.oneHotLabels();
TwoLayerNet network = new TwoLayerNet(784, 50, 10);
DataSet dataSet = new DataSet(x_train, t_train);
int iters_num = 10000;
int train_size = x_train.size(0);
int batch_size = 100;
double learning_rate = 0.1;
List<Double> train_loss_list = new ArrayList<>();
List<Double> train_acc_list = new ArrayList<>();
List<Double> test_acc_list = new ArrayList<>();
int iter_per_epoch = Math.max(train_size / batch_size, 1);
for (int i = 0; i < iters_num; ++i) {
    DataSet sample = dataSet.sample(batch_size);
    INDArray x_batch = sample.getFeatures();
    INDArray t_batch = sample.getLabels();
    //Trouvez le dégradé par la méthode de propagation des erreurs
    Params grad = network.gradient(x_batch, t_batch);
    //mise à jour
    network.params.update((p, a) -> p.subi(a.mul(learning_rate)), grad);
    double loss = network.loss(x_batch, t_batch);
    train_loss_list.add(loss);
    if (i % iter_per_epoch == 0) {
        double train_acc = network.accuracy(x_train, t_train);
        double test_acc = network.accuracy(x_test, t_test);
        train_acc_list.add(train_acc);
        test_acc_list.add(test_acc);
        System.out.printf("loss=%f train_acc=%f test_acc=%f%n", loss, train_acc, test_acc);
    }
}
assertTrue(train_acc_list.get(train_acc_list.size() - 1) > 0.8);
assertTrue(test_acc_list.get(test_acc_list.size() - 1) > 0.8);

Recommended Posts

Deep Learning Java from scratch Chapter 5 Méthode de propagation de retour d'erreur
Deep Learning Java à partir de zéro Chapitre 1 Introduction
Deep Learning Java à partir de zéro Chapitre 2 Perceptron
Deep Learning from scratch Java Chapter 4 Apprentissage des réseaux de neurones
Deep Learning Java à partir de zéro Chapitre 3 Réseau neuronal
Deep Learning Java from scratch 6.4 Régularisation
Étudiez le Deep Learning à partir de zéro en Java.
Deep Learning Java from scratch 6.1 Mise à jour des paramètres
Deep Learning Java from scratch 6.3 Normalisation par lots
[Deep Learning from scratch] dans Java 3. Réseau neuronal
Deep Learning Java from scratch 6.2 Valeur initiale du poids
Configuration PC la plus rapide pour un apprentissage en profondeur à partir de zéro
[Apprentissage profond à partir de zéro] 2. Il n'existe pas de NumPy en Java.
[Deep Learning from scratch] en Java 1. Pour le moment, différenciation et différenciation partielle
Java Learning 2 (Apprenez la méthode de calcul)
Mémo d'apprentissage Java (méthode)
La vie Java à partir de zéro
Comment passer l'examen Java Silver et comment apprendre
Premiers pas pour l'apprentissage profond en Java
Appel de méthodes Java à partir de JavaScript exécutées en Java