# 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();
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 price = mul_tax_layer.forward(all_price, tax);
// backward
double dprice = 1;
double[] dall_price = mul_tax_layer.backward(dprice);
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));
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());
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));
``````

## 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.
//Trouvez le dégradé par la méthode de propagation d'erreur.
//Comparez les résultats de la différenciation numérique et de la méthode de propagation d'erreur.
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
//mise à jour
double loss = network.loss(x_batch, t_batch);
if (i % iter_per_epoch == 0) {
double train_acc = network.accuracy(x_train, t_train);
double test_acc = network.accuracy(x_test, t_test);
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);
``````