Deep Learning Java von Grund auf neu Kapitel 5 Methode zur Fehlerrückübertragung

Inhaltsverzeichnis

5.4 Einfache Layer-Implementierung

5.4.1 Implementierung der Multiplikationsschicht

static class MulLayer {

    private double x, y;

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

    //Da Java nicht mehrere Werte zurückgeben kann, wird es als Array zurückgegeben.
    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 Implementierung der Additionsschicht

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 Implementierung der Aktivierungsfunktionsschicht

5.5.1 ReLU-Schicht

Die Klassenimplementierung des ReLU-Beispiels unter Verwendung der Fehlerrückverbreitungsmethode lautet Relu. ) ist.

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));
//Der Test unterscheidet sich von diesem Buch.
Relu relu = new Relu();
INDArray a = relu.forward(x);
//Ergebnis vorwärts
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);
//Ergebnisse von rückwärts
assertEquals("[[5.00,0.00],[0.00,8.00]]", Util.string(b));

5.5.2 Sigmoidschicht

Die Implementierungsklasse der Sigmoid-Schicht, die die Fehlerrückvermehrungsmethode verwendet, ist Sigmoid ) ist.

5.6 Implementierung der affinen Softmax-Schicht

5.6.1 Affine Schicht

Die Implementierungsklasse der Affine-Ebene, die die Fehlerrückverteilungsmethode verwendet, ist Affine ) ist.

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 Stapelversion Affine Ebene

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 Softmax-with-Loss-Schicht

Die Implementierungsklasse der Softmax-with-Loss-Schicht unter Verwendung der Fehlerrückverteilungsmethode ist [SoftmaxWithLoss](https://github.com/saka1029/Deep.Learning/blob/master/src/main/java/deep/learning/common /SoftmaxWithLoss.java).

5.7 Implementierung der Fehlerrückverbreitungsmethode

Die Klasse des zweischichtigen neuronalen Netzwerks, das die Fehlerrückverbreitungsmethode verwendet, ist TwoLayerNet. Java). Es gibt auch TwoLayerNet in Kapitel 4, dies ist jedoch eine numerische Unterscheidung. Es ist derjenige, der verwendet. Um die Handhabung jeder Schicht in dieser Implementierung zu vereinfachen, werden die folgenden zwei Schnittstellen definiert.

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 Gradientenbestätigung der Fehlerrückausbreitungsmethode

Der Gradientenvergleich mit der numerischen Differenzierungsmethode ist erheblich größer als der in diesem Buch beschriebene. Daher wird es hier mit dem Gradienten durch numerische Differenzierung geteilt durch 3 verglichen. Functions.average (INDArray) ist der Durchschnitt aller Elemente Die gewünschte Methode.

public static double average(INDArray x) {
    // x.length()Gibt die Gesamtzahl der Elemente zurück.
    return x.sumNumber().doubleValue() / x.length();
}
//Lesen Sie die Trainingsdaten von MNIST.
MNISTImages train = new MNISTImages(Constants.TrainImages, Constants.TrainLabels);
TwoLayerNet network = new TwoLayerNet(784, 50, 10);
//Normalisiertes Bild und eins-Nehmen Sie jeweils die ersten 3 heißen Etiketten heraus.
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));
//Finden Sie den Gradienten durch numerische Differenzierung.
Params grad_numerical = network.numerical_gradient(x_batch, t_batch);
//Ermitteln Sie den Gradienten mithilfe der Fehlerausbreitungsmethode.
Params grad_backprop = network.gradient(x_batch, t_batch);
//Vergleichen Sie die Ergebnisse der numerischen Differenzierung und der Fehlerausbreitungsmethode.
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);
//Der Unterschied ist etwas größer als dieses Buch.
assertTrue(diff_b1 < 1e-3);
assertTrue(diff_W2 < 1e-3);
assertTrue(diff_b2 < 1e-3);
assertTrue(diff_W1 < 1e-3);

5.7.4 Lernen mit der Fehlerrückverteilungsmethode

Es ist erheblich schneller als das Lernen mit numerischer Differenzierung. In meiner Umgebung sind 10000 Schleifen in ungefähr 89 Sekunden abgeschlossen. Die endgültige Erkennungsgenauigkeit betrug jedoch etwa 84%, was der numerischen Differenzierung unterlegen war. Wahrscheinlich liegt irgendwo in der Schichtimplementierung ein Fehler vor, da der Unterschied beim Vergleich des Gradienten mit dem numerischen Differentialfall groß ist.

//Lesen Sie die Trainingsdaten von MNIST.
MNISTImages train = new MNISTImages(Constants.TrainImages, Constants.TrainLabels);
INDArray x_train = train.normalizedImages();
INDArray t_train = train.oneHotLabels();
//Lesen Sie die MNIST-Testdaten.
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();
    //Ermitteln Sie den Gradienten mithilfe der Methode zur Fehlerrückübertragung
    Params grad = network.gradient(x_batch, t_batch);
    //aktualisieren
    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 von Grund auf neu Kapitel 5 Methode zur Fehlerrückübertragung
Deep Learning Java von Grund auf neu Kapitel 1 Einführung
Deep Learning Java von Grund auf neu Kapitel 2 Perceptron
Deep Learning von Grund auf neu Java Kapitel 4 Lernen neuronaler Netze
Deep Learning Java von Grund auf neu Kapitel 3 Neuronales Netzwerk
Deep Learning Java von Grund auf 6.4 Regularisierung
Lernen Sie Deep Learning von Grund auf in Java.
Deep Learning Java von Grund auf 6.1 Parameteraktualisierung
Deep Learning Java von Grund auf 6.3 Batch-Normalisierung
[Deep Learning von Grund auf neu] in Java 3. Neuronales Netzwerk
Deep Learning Java von Grund auf 6.2 Anfangswert des Gewichts
Schnellstes PC-Setup für tiefes Lernen von Grund auf
[Deep Learning von Grund auf neu] 2. In Java gibt es kein NumPy.
[Deep Learning von Grund auf neu] in Java 1. Zur Zeit Differenzierung und teilweise Differenzierung
Java Learning 2 (Lernen Sie die Berechnungsmethode)
Java-Lernnotiz (Methode)
Java-Leben von vorne anfangen
Wie man die Java Silver Prüfung ablegt und wie man lernt
Erste Schritte für tiefes Lernen in Java
Rufen Sie Java-Methoden aus JavaScript auf, das in Java ausgeführt wird