Die Sprungfunktion kann wie folgt implementiert werden. Hier habe ich versucht, INDArray mit einer einfachen Funktion (DoubleFunction) abzubilden.
public static double step_function(double x) {
if (x > 0)
return 1.0;
else
return 0.0;
}
public static <T extends Number> INDArray map(INDArray x, DoubleFunction<T> func) {
int size = x.length();
INDArray result = Nd4j.create(size);
for (int i = 0; i < size; ++i)
result.put(0, i, func.apply(x.getDouble(i)));
return result;
}
public static INDArray step_function(INDArray x) {
return map(x, d -> d > 0.0 ? 1 : 0);
}
INDArray x = Nd4j.create(new double[] {-1.0, 1.0, 2.0});
assertEquals("[-1.00,1.00,2.00]", Util.string(x));
assertEquals("[0.00,1.00,1.00]", Util.string(step_function(x)));
Die Sigmoidfunktion kann wie folgt implementiert werden. ND4J bietet eine Sigmoid-Funktion in der Klasse Transforms, sodass Sie sie auch verwenden können. ..
public static double sigmoid(double x) {
return (double)(1.0 / (1.0 + Math.exp(-x)));
}
public static INDArray sigmoid(INDArray x) {
//Operatoren können in Java nicht überladen werden
//Beschrieben durch Aufrufen einer Methode.
return Transforms.exp(x.neg()).add(1.0).rdiv(1.0);
//Alternativ kann es unter Verwendung der oben beschriebenen Karte wie folgt implementiert werden.
// return map(x, d -> sigmoid(d));
}
INDArray x = Nd4j.create(new double[] {-1.0, 1.0, 2.0});
assertEquals("[0.27,0.73,0.88]", Util.string(sigmoid(x)));
assertEquals("[0.27,0.73,0.88]", Util.string(Transforms.sigmoid(x)));
INDArray t = Nd4j.create(new double[] {1.0, 2.0, 3.0});
// A.rdiv(k)Ist k geteilt durch jedes Element von A.
assertEquals("[1.00,0.50,0.33]", Util.string(t.rdiv(1.0)));
}
Die ReLU-Funktion kann wie folgt implementiert werden. ND4J bietet eine Relu-Funktion in der Klasse Transforms, sodass Sie sie auch verwenden können.
public static INDArray relu(INDArray x) {
return map(x, d -> Math.max(0.0, d));
}
INDArray x = Nd4j.create(new double[] {-4, -2, 0, 2, 4});
assertEquals("[0.00,0.00,0.00,2.00,4.00]", Util.string(relu(x)));
assertEquals("[0.00,0.00,0.00,2.00,4.00]", Util.string(Transforms.relu(x)));
//Eindimensionales Array
INDArray A = Nd4j.create(new double[] {1, 2, 3, 4});
assertEquals("[1.00,2.00,3.00,4.00]", Util.string(A));
//In ND4J ist das eindimensionale Array ein zweidimensionales 1xN-Array.
assertArrayEquals(new int[] {1, 4}, A.shape());
//In ND4J ist die Anzahl der Dimensionen Rang()Durch die Methode erhalten.
assertEquals(2, A.rank());
assertEquals(1, A.size(0)); //Anzahl der Zeilen
assertEquals(4, A.size(1)); //Anzahl der Spalten
//Zweidimensionales Array
INDArray B = Nd4j.create(new double[][] {{1, 2}, {3, 4}, {5, 6}});
assertEquals("[[1.00,2.00],[3.00,4.00],[5.00,6.00]]", Util.string(B));
assertEquals(2, B.rank());
assertArrayEquals(new int[] {3, 2}, B.shape());
In ND4J wird das innere Produkt von [INDArray] berechnet (https://nd4j.org/doc/org/nd4j/linalg/api/ndarray/INDArray.html).mmul (INDArray).
INDArray A = Nd4j.create(new double[][] {{1, 2}, {3, 4}});
assertArrayEquals(new int[] {2, 2}, A.shape());
INDArray B = Nd4j.create(new double[][] {{5, 6}, {7, 8}});
assertArrayEquals(new int[] {2, 2}, B.shape());
assertEquals("[[19.00,22.00],[43.00,50.00]]", Util.string(A.mmul(B)));
A = Nd4j.create(new double[][] {{1, 2, 3}, {4, 5, 6}});
assertArrayEquals(new int[] {2, 3}, A.shape());
B = Nd4j.create(new double[][] {{1, 2}, {3, 4}, {5, 6}});
assertArrayEquals(new int[] {3, 2}, B.shape());
assertEquals("[[22.00,28.00],[49.00,64.00]]", Util.string(A.mmul(B)));
INDArray C = Nd4j.create(new double[][] {{1, 2}, {3, 4}});
assertArrayEquals(new int[] {2, 2}, C.shape());
assertArrayEquals(new int[] {2, 3}, A.shape());
try {
//Wenn in ND4J ein Fehler in der Anzahl der Elemente in der Matrix vorliegt, die das innere Produkt aufnehmen,
//Löst eine ND4JIllegalStateException aus.
A.mmul(C);
fail();
} catch (ND4JIllegalStateException e) {
assertEquals(
"Cannot execute matrix multiplication: [2, 3]x[2, 2]: "
+ "Column of left array 3 != rows of right 2"
, e.getMessage());
}
A = Nd4j.create(new double[][] {{1, 2}, {3, 4}, {5, 6}});
assertArrayEquals(new int[] {3, 2}, A.shape());
B = Nd4j.create(new double[] {7, 8});
assertArrayEquals(new int[] {1, 2}, B.shape());
//In ND4J ist ein eindimensionales Array eine 1 × N-Zeilenmatrix.
//Transponieren, um das Produkt zu finden()Muss in der Methode transponiert werden.
assertArrayEquals(new int[] {2, 1}, B.transpose().shape());
assertEquals("[23.00,53.00,83.00]", Util.string(A.mmul(B.transpose())));
INDArray X = Nd4j.create(new double[] {1, 2});
assertArrayEquals(new int[] {1, 2}, X.shape());
INDArray W = Nd4j.create(new double[][] {{1, 3, 5}, {2, 4, 6}});
assertEquals("[[1.00,3.00,5.00],[2.00,4.00,6.00]]", Util.string(W));
assertArrayEquals(new int[] {2, 3}, W.shape());
INDArray Y = X.mmul(W);
assertEquals("[5.00,11.00,17.00]", Util.string(Y));
INDArray X = Nd4j.create(new double[] {1.0, 0.5});
INDArray W1 = Nd4j.create(new double[][] {{0.1, 0.3, 0.5}, {0.2, 0.4, 0.6}});
INDArray B1 = Nd4j.create(new double[] {0.1, 0.2, 0.3});
assertArrayEquals(new int[] {2, 3}, W1.shape());
assertArrayEquals(new int[] {1, 2}, X.shape());
assertArrayEquals(new int[] {1, 3}, B1.shape());
INDArray A1 = X.mmul(W1).add(B1);
INDArray Z1 = Transforms.sigmoid(A1);
assertEquals("[0.30,0.70,1.10]", Util.string(A1));
assertEquals("[0.57,0.67,0.75]", Util.string(Z1));
INDArray W2 = Nd4j.create(new double[][] {{0.1, 0.4}, {0.2, 0.5}, {0.3, 0.6}});
INDArray B2 = Nd4j.create(new double[] {0.1, 0.2});
assertArrayEquals(new int[] {1, 3}, Z1.shape());
assertArrayEquals(new int[] {3, 2}, W2.shape());
assertArrayEquals(new int[] {1, 2}, B2.shape());
INDArray A2 = Z1.mmul(W2).add(B2);
INDArray Z2 = Transforms.sigmoid(A2);
assertEquals("[0.52,1.21]", Util.string(A2));
assertEquals("[0.63,0.77]", Util.string(Z2));
INDArray W3 = Nd4j.create(new double[][] {{0.1, 0.3}, {0.2, 0.4}});
INDArray B3 = Nd4j.create(new double[] {0.1, 0.2});
INDArray A3 = Z2.mmul(W3).add(B3);
//ND4J hat Identität in der Transforms-Klasse(INDArray)Eine Methode wird bereitgestellt.
INDArray Y = Transforms.identity(A3);
assertEquals("[0.32,0.70]", Util.string(A3));
assertEquals("[0.32,0.70]", Util.string(Y));
// Y.equals(A3)
assertEquals(A3, Y);
public static Map<String, INDArray> init_network() {
Map<String, INDArray> network = new HashMap<>();
network.put("W1", Nd4j.create(new double[][] {{0.1, 0.3, 0.5}, {0.2, 0.4, 0.6}}));
network.put("b1", Nd4j.create(new double[] {0.1, 0.2, 0.3}));
network.put("W2", Nd4j.create(new double[][] {{0.1, 0.4}, {0.2, 0.5}, {0.3, 0.6}}));
network.put("b2", Nd4j.create(new double[] {0.1, 0.2}));
network.put("W3", Nd4j.create(new double[][] {{0.1, 0.3}, {0.2, 0.4}}));
network.put("b3", Nd4j.create(new double[] {0.1, 0.2}));
return network;
}
public static INDArray forward(Map<String, INDArray> network, INDArray x) {
INDArray W1 = network.get("W1");
INDArray W2 = network.get("W2");
INDArray W3 = network.get("W3");
INDArray b1 = network.get("b1");
INDArray b2 = network.get("b2");
INDArray b3 = network.get("b3");
INDArray a1 = x.mmul(W1).add(b1);
INDArray z1 = Transforms.sigmoid(a1);
INDArray a2 = z1.mmul(W2).add(b2);
INDArray z2 = Transforms.sigmoid(a2);
INDArray a3 = z2.mmul(W3).add(b3);
INDArray y = Transforms.identity(a3);
return y;
}
Map<String, INDArray> network = init_network();
INDArray x = Nd4j.create(new double[] {1.0, 0.5});
INDArray y = forward(network, x);
assertEquals("[0.32,0.70]", Util.string(y));
INDArray a = Nd4j.create(new double[] {0.3, 2.9, 4.0});
//
INDArray exp_a = Transforms.exp(a);
assertEquals("[1.35,18.17,54.60]", Util.string(exp_a));
//
Number sum_exp_a = exp_a.sumNumber();
assertEquals(74.1221542102, sum_exp_a.doubleValue(), 5e-6);
//3.4.3 Implementierungszusammenfassung 3.5 Design der Ausgabeschicht 3.5.1 Exponentialfunktion mit gleicher Funktion und Softmax-Funktion Summe der Exponentialfunktion Softmax-Funktion
INDArray y = exp_a.div(sum_exp_a);
assertEquals("[0.02,0.25,0.74]", Util.string(y));
public static INDArray softmax_wrong(INDArray a) {
INDArray exp_a = Transforms.exp(a);
Number sum_exp_a = exp_a.sumNumber();
INDArray y = exp_a.div(sum_exp_a);
return y;
}
public static INDArray softmax_right(INDArray a) {
Number c = a.maxNumber();
INDArray exp_a = Transforms.exp(a.sub(c));
Number sum_exp_a = exp_a.sumNumber();
INDArray y = exp_a.div(sum_exp_a);
return y;
}
INDArray a = Nd4j.create(new double[] {1010, 1000, 990});
//Nicht richtig berechnet
assertEquals("[NaN,NaN,NaN]", Util.string(Transforms.exp(a).div(Transforms.exp(a).sumNumber())));
Number c = a.maxNumber();
assertEquals("[0.00,-10.00,-20.00]", Util.string(a.sub(c)));
assertEquals("[1.00,0.00,0.00]", Util.string(Transforms.exp(a.sub(c)).div(Transforms.exp(a.sub(c)).sumNumber())));
//Fehler
assertEquals("[NaN,NaN,NaN]", Util.string(softmax_wrong(a)));
//richtig
assertEquals("[1.00,0.00,0.00]", Util.string(softmax_right(a)));
//Korrigieren Sie Softmax für ND4J(INDArray)Ist vorbereitet.
assertEquals("[1.00,0.00,0.00]", Util.string(Transforms.softmax(a)));
INDArray a = Nd4j.create(new double[] {0.3, 2.9, 4.0});
INDArray y = Transforms.softmax(a);
assertEquals("[0.02,0.25,0.74]", Util.string(y));
//Die Summe ist 1.
assertEquals(1.0, y.sumNumber().doubleValue(), 5e-6);
MNIST-Daten wird von [MNISTImages-Klasse] gelesen (https://github.com/saka1029/Deep.Learning/blob/master/src/main) /java/deep/learning/common/MNISTImages.java). Diese Klasse liest die Datei nach dem Herunterladen und Dekomprimieren der Daten in DIE MNIST-DATENBANK handgeschriebener Ziffern.
//Laden Sie das MNIST-Dataset in die MNISTImages-Klasse.
MNISTImages train = new MNISTImages(Constants.TrainImages, Constants.TrainLabels);
MNISTImages test = new MNISTImages(Constants.TestImages, Constants.TestLabels);
assertEquals(60000, train.size);
assertEquals(784, train.imageSize);
assertEquals(10000, test.size);
assertEquals(784, test.imageSize);
//Die ersten 100 Bilder der Trainingsdaten werden als PNG ausgegeben.
if (!Constants.TrainImagesOutput.exists())
Constants.TrainImagesOutput.mkdirs();
for (int i = 0; i < 100; ++i) {
File image = new File(Constants.TrainImagesOutput,
String.format("%05d-%d.png ", i, train.label(i)));
train.writePngFile(i, image);
}
Das tatsächliche Ausgabebild ist wie folgt. Der Dateiname lautet "[Seriennummer 5 Ziffern] - [Label] .png ".
00000-5.png 00001-0.png 00002-4.png 00003-1.png 00004-9.png 00005-2.png 00006-1.png 00007-3.png 00008-1.png 00009-4.png .....
Beispielgewichtsdaten (sample_weight.pkl) ist [SampleWeight](https://github.com/ saka1029 / Deep.Learning / blob / master / src / main / java / deep / learning / common / SampleWeight.java) Laden mit der Klasse. Sample_weight.pkl sind jedoch in Python serialisierte Daten und können in Java nicht direkt gelesen werden. Daher wird sample_weight.pkl einmal mit dem folgenden Python-Programm in Text konvertiert. Die Textdaten sind SampleWeight.txt. Die Klasse SampleWeight liest diese Textdatei.
sample_weight.py
import pickle
import numpy
pkl = "sample_weight.pkl"
with open(pkl, "rb") as f:
network = pickle.load(f)
for k, v in network.items():
print(k, end="")
dim = v.ndim
for d in v.shape:
print("", d, end="")
print()
for e in v.flatten():
print(e)
Der Code, der tatsächlich liest und schließt, lautet wie folgt. Die Erkennungsgenauigkeit ist [Deep Learning von Grund auf neu gemacht] Es ist 93,52%, was dem entspricht (https://www.oreilly.co.jp/books/9784873117584/).
static INDArray normalize(byte[][] images) {
int imageCount = images.length;
int imageSize = images[0].length;
INDArray norm = Nd4j.create(imageCount, imageSize);
for (int i = 0; i < imageCount; ++i)
for (int j = 0; j < imageSize; ++j)
norm.putScalar(i, j, (images[i][j] & 0xff) / 255.0);
return norm;
}
static INDArray predict(Map<String, INDArray> network, INDArray x) {
INDArray W1 = network.get("W1");
INDArray W2 = network.get("W2");
INDArray W3 = network.get("W3");
INDArray b1 = network.get("b1");
INDArray b2 = network.get("b2");
INDArray b3 = network.get("b3");
//Wenn Sie Folgendes tun, tritt bei der Stapelverarbeitung ein Fehler auf.
// INDArray a1 = x.mmul(W1).add(b1);
// x.mmul(W1)Dies liegt daran, dass b1 eindimensional ist, obwohl das Ergebnis ein zweidimensionales Array ist.
// add(INDArray)Sendet nicht automatisch.
//Es kann auch explizit wie folgt gesendet werden:
// INDArray a1 = x.mmul(W1).add(b1.broadcast(x.size(0), b1.size(1)));
INDArray a1 = x.mmul(W1).addRowVector(b1);
INDArray z1 = Transforms.sigmoid(a1);
INDArray a2 = z1.mmul(W2).addRowVector(b2);
INDArray z2 = Transforms.sigmoid(a2);
INDArray a3 = z2.mmul(W3).addRowVector(b3);
INDArray y = Transforms.softmax(a3);
return y;
}
//Laden Sie das Testbild.
MNISTImages test = new MNISTImages(Constants.TestImages, Constants.TestLabels);
//Laden Sie die Probengewichtsdaten.
Map<String, INDArray> network = SampleWeight.read(Constants.SampleWeights);
//Normalisieren Sie das Bild(0-255 -> 0.0-1.0)
INDArray x = test.normalizedImages();
int size = x.size(0);
int accuracy_cnt = 0;
for (int i = 0; i < size; ++i) {
INDArray y = predict(network, x.getRow(i));
//Das letzte Argument, 1, repräsentiert die Dimension.
INDArray max = Nd4j.getExecutioner().exec(new IAMax(y), 1);
if (max.getInt(0) == test.label(i))
++accuracy_cnt;
}
// System.out.printf("Accuracy:%f%n", (double) accuracy_cnt / size);
assertEquals(10000, size);
assertEquals(9352, accuracy_cnt);
NDArrayIndex zum Abrufen von Daten zur Stapelgröße von INDArray Verwenden Sie doc / org / nd4j / linalg / indexing / NDArrayIndex.html). NDArrayIndex. Sie können die Elemente von Anfang bis Ende mit Intervall abrufen (int start, int end). (Start ≤ i <Ende). Sie können auch die Klasse IAMax verwenden, um dasselbe wie die Argmax-Funktion von NumPy zu tun.
int batch_size = 100;
//Laden Sie das Testbild.
MNISTImages test = new MNISTImages(Constants.TestImages, Constants.TestLabels);
//Laden Sie die Probengewichtsdaten.
Map<String, INDArray> network = SampleWeight.read(Constants.SampleWeights);
//Normalisieren Sie das Bild(0-255 -> 0.0-1.0)
INDArray x = test.normalizedImages();
int size = x.size(0);
int accuracy_cnt = 0;
for (int i = 0; i < size; i += batch_size) {
//Extrahieren Sie das Bild für die Stapelgröße und sagen Sie es voraus()Wird genannt.
INDArray y = predict(network, x.get(NDArrayIndex.interval(i, i + batch_size)));
//Das letzte Argument, 1, repräsentiert die Dimension.
INDArray max = Nd4j.getExecutioner().exec(new IAMax(y), 1);
for (int j = 0; j < batch_size; ++j)
if (max.getInt(j) == test.label(i + j))
++accuracy_cnt;
}
// System.out.printf("Accuracy:%f%n", (double) accuracy_cnt / size);
assertEquals(10000, size);
assertEquals(9352, accuracy_cnt);
In meiner Umgebung konnte ich durch die Stapelverarbeitung von 2,7 Sekunden auf 0,5 Sekunden beschleunigen. Ich benutze keine GPU.
Recommended Posts