mirror of
https://github.com/jneug/zeichenmaschine.git
synced 2026-04-14 14:43:33 +02:00
java doc und refactorings
This commit is contained in:
@@ -4,12 +4,60 @@ import schule.ngb.zm.Constants;
|
|||||||
|
|
||||||
import java.util.function.DoubleUnaryOperator;
|
import java.util.function.DoubleUnaryOperator;
|
||||||
|
|
||||||
// TODO: Move Math into Matrix class
|
/**
|
||||||
// TODO: Implement support for optional sci libs
|
* Eine einfache Implementierung der {@link MLMatrix} zur Verwendung in
|
||||||
|
* {@link NeuralNetwork}s.
|
||||||
|
* <p>
|
||||||
|
* Diese Klasse stellt die interne Implementierung der Matrixoperationen dar,
|
||||||
|
* die zur Berechnung der Gewichte in einem {@link NeuronLayer} notwendig sind.
|
||||||
|
* <p>
|
||||||
|
* Die Klasse ist nur minimal optimiert und sollte nur für kleine Netze
|
||||||
|
* verwendet werden. Für größere Netze sollte auf eine der optionalen
|
||||||
|
* Bibliotheken wie
|
||||||
|
* <a href="">Colt</a> zurückgegriffen werden.
|
||||||
|
*/
|
||||||
public final class DoubleMatrix implements MLMatrix {
|
public final class DoubleMatrix implements MLMatrix {
|
||||||
|
|
||||||
private int columns, rows;
|
/**
|
||||||
|
* Anzahl Zeilen der Matrix.
|
||||||
|
*/
|
||||||
|
private int rows;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Anzahl Spalten der Matrix.
|
||||||
|
*/
|
||||||
|
private int columns;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Die Koeffizienten der Matrix.
|
||||||
|
* <p>
|
||||||
|
* Um den Overhead bei Speicher und Zugriffszeiten von zweidimensionalen
|
||||||
|
* Arrays zu vermeiden wird ein eindimensionales Array verwendet und die
|
||||||
|
* Indizes mit Spaltenpriorität berechnet. Der Index i des Koeffizienten
|
||||||
|
* {@code r,c} in Zeile {@code r} und Spalte {@code c} wird bestimmt durch
|
||||||
|
* <pre>
|
||||||
|
* i = c * rows + r
|
||||||
|
* </pre>
|
||||||
|
* <p>
|
||||||
|
* Die Werte einer Spalte liegen also hintereinander im Array. Dies sollte
|
||||||
|
* einen leichten Vorteil bei der {@link #colSums() Spaltensummen} geben.
|
||||||
|
* Generell sollte eine Iteration über die Matrix der Form
|
||||||
|
* <pre><code>
|
||||||
|
* for( int j = 0; j < columns; j++ ) {
|
||||||
|
* for( int i = 0; i < rows; i++ ) {
|
||||||
|
* // ...
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* </code></pre>
|
||||||
|
* etwas schneller sein als
|
||||||
|
* <pre><code>
|
||||||
|
* for( int i = 0; i < rows; i++ ) {
|
||||||
|
* for( int j = 0; j < columns; j++ ) {
|
||||||
|
* // ...
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* </code></pre>
|
||||||
|
*/
|
||||||
double[] coefficients;
|
double[] coefficients;
|
||||||
|
|
||||||
public DoubleMatrix( int rows, int cols ) {
|
public DoubleMatrix( int rows, int cols ) {
|
||||||
@@ -29,6 +77,11 @@ public final class DoubleMatrix implements MLMatrix {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialisiert diese Matrix als Kopie der angegebenen Matrix.
|
||||||
|
*
|
||||||
|
* @param other Die zu kopierende Matrix.
|
||||||
|
*/
|
||||||
public DoubleMatrix( DoubleMatrix other ) {
|
public DoubleMatrix( DoubleMatrix other ) {
|
||||||
this.rows = other.rows();
|
this.rows = other.rows();
|
||||||
this.columns = other.columns();
|
this.columns = other.columns();
|
||||||
@@ -39,55 +92,100 @@ public final class DoubleMatrix implements MLMatrix {
|
|||||||
rows * columns);
|
rows * columns);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
public int columns() {
|
public int columns() {
|
||||||
return columns;
|
return columns;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
public int rows() {
|
public int rows() {
|
||||||
return rows;
|
return rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
public double[][] coefficients() {
|
/**
|
||||||
return new double[rows][columns];
|
* {@inheritDoc}
|
||||||
}
|
*/
|
||||||
|
|
||||||
int idx( int r, int c ) {
|
int idx( int r, int c ) {
|
||||||
return c * rows + r;
|
return c * rows + r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
public double get( int row, int col ) {
|
public double get( int row, int col ) {
|
||||||
return coefficients[idx(row, col)];
|
try {
|
||||||
|
return coefficients[idx(row, col)];
|
||||||
|
} catch( ArrayIndexOutOfBoundsException ex ) {
|
||||||
|
throw new IllegalArgumentException("No element at row=" + row + ", column=" + col, ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
public MLMatrix set( int row, int col, double value ) {
|
public MLMatrix set( int row, int col, double value ) {
|
||||||
coefficients[idx(row, col)] = value;
|
try {
|
||||||
|
coefficients[idx(row, col)] = value;
|
||||||
|
} catch( ArrayIndexOutOfBoundsException ex ) {
|
||||||
|
throw new IllegalArgumentException("No element at row=" + row + ", column=" + col, ex);
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
public MLMatrix initializeRandom() {
|
public MLMatrix initializeRandom() {
|
||||||
return initializeRandom(-1.0, 1.0);
|
return initializeRandom(-1.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
public MLMatrix initializeRandom( double lower, double upper ) {
|
public MLMatrix initializeRandom( double lower, double upper ) {
|
||||||
applyInPlace(( d ) -> ((upper - lower) * Constants.random()) + lower);
|
applyInPlace(( d ) -> ((upper - lower) * Constants.random()) + lower);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
public MLMatrix initializeOne() {
|
public MLMatrix initializeOne() {
|
||||||
applyInPlace(( d ) -> 1.0);
|
applyInPlace(( d ) -> 1.0);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
public MLMatrix initializeZero() {
|
public MLMatrix initializeZero() {
|
||||||
applyInPlace(( d ) -> 0.0);
|
applyInPlace(( d ) -> 0.0);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public MLMatrix duplicate() {
|
public MLMatrix duplicate() {
|
||||||
return new DoubleMatrix(this);
|
return new DoubleMatrix(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public MLMatrix multiplyTransposed( MLMatrix B ) {
|
public MLMatrix multiplyTransposed( MLMatrix B ) {
|
||||||
/*return new DoubleMatrix(IntStream.range(0, rows).parallel().mapToObj(
|
/*return new DoubleMatrix(IntStream.range(0, rows).parallel().mapToObj(
|
||||||
@@ -109,6 +207,9 @@ public final class DoubleMatrix implements MLMatrix {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public MLMatrix multiplyAddBias( final MLMatrix B, final MLMatrix C ) {
|
public MLMatrix multiplyAddBias( final MLMatrix B, final MLMatrix C ) {
|
||||||
/*return new DoubleMatrix(IntStream.range(0, rows).parallel().mapToObj(
|
/*return new DoubleMatrix(IntStream.range(0, rows).parallel().mapToObj(
|
||||||
@@ -131,6 +232,9 @@ public final class DoubleMatrix implements MLMatrix {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public MLMatrix transposedMultiplyAndScale( final MLMatrix B, final double scalar ) {
|
public MLMatrix transposedMultiplyAndScale( final MLMatrix B, final double scalar ) {
|
||||||
/*return new DoubleMatrix(IntStream.range(0, columns).parallel().mapToObj(
|
/*return new DoubleMatrix(IntStream.range(0, columns).parallel().mapToObj(
|
||||||
@@ -153,6 +257,9 @@ public final class DoubleMatrix implements MLMatrix {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public MLMatrix add( MLMatrix B ) {
|
public MLMatrix add( MLMatrix B ) {
|
||||||
/*return new DoubleMatrix(IntStream.range(0, rows).parallel().mapToObj(
|
/*return new DoubleMatrix(IntStream.range(0, rows).parallel().mapToObj(
|
||||||
@@ -169,6 +276,9 @@ public final class DoubleMatrix implements MLMatrix {
|
|||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public MLMatrix addInPlace( MLMatrix B ) {
|
public MLMatrix addInPlace( MLMatrix B ) {
|
||||||
for( int j = 0; j < columns; j++ ) {
|
for( int j = 0; j < columns; j++ ) {
|
||||||
@@ -179,6 +289,9 @@ public final class DoubleMatrix implements MLMatrix {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public MLMatrix sub( MLMatrix B ) {
|
public MLMatrix sub( MLMatrix B ) {
|
||||||
/*return new DoubleMatrix(IntStream.range(0, rows).parallel().mapToObj(
|
/*return new DoubleMatrix(IntStream.range(0, rows).parallel().mapToObj(
|
||||||
@@ -195,6 +308,9 @@ public final class DoubleMatrix implements MLMatrix {
|
|||||||
return diff;
|
return diff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public MLMatrix colSums() {
|
public MLMatrix colSums() {
|
||||||
/*DoubleMatrix colSums = new DoubleMatrix(1, columns);
|
/*DoubleMatrix colSums = new DoubleMatrix(1, columns);
|
||||||
@@ -214,6 +330,9 @@ public final class DoubleMatrix implements MLMatrix {
|
|||||||
return colSums;
|
return colSums;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public MLMatrix scaleInPlace( final double scalar ) {
|
public MLMatrix scaleInPlace( final double scalar ) {
|
||||||
for( int i = 0; i < coefficients.length; i++ ) {
|
for( int i = 0; i < coefficients.length; i++ ) {
|
||||||
@@ -222,6 +341,9 @@ public final class DoubleMatrix implements MLMatrix {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public MLMatrix scaleInPlace( final MLMatrix S ) {
|
public MLMatrix scaleInPlace( final MLMatrix S ) {
|
||||||
for( int j = 0; j < columns; j++ ) {
|
for( int j = 0; j < columns; j++ ) {
|
||||||
@@ -232,6 +354,9 @@ public final class DoubleMatrix implements MLMatrix {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public MLMatrix apply( DoubleUnaryOperator op ) {
|
public MLMatrix apply( DoubleUnaryOperator op ) {
|
||||||
DoubleMatrix result = new DoubleMatrix(rows, columns);
|
DoubleMatrix result = new DoubleMatrix(rows, columns);
|
||||||
@@ -241,6 +366,9 @@ public final class DoubleMatrix implements MLMatrix {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public MLMatrix applyInPlace( DoubleUnaryOperator op ) {
|
public MLMatrix applyInPlace( DoubleUnaryOperator op ) {
|
||||||
for( int i = 0; i < coefficients.length; i++ ) {
|
for( int i = 0; i < coefficients.length; i++ ) {
|
||||||
|
|||||||
@@ -2,142 +2,312 @@ package schule.ngb.zm.ml;
|
|||||||
|
|
||||||
import java.util.function.DoubleUnaryOperator;
|
import java.util.function.DoubleUnaryOperator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface für Matrizen, die in {@link NeuralNetwork} Klassen verwendet
|
||||||
|
* werden.
|
||||||
|
* <p>
|
||||||
|
* Eine implementierende Klasse muss generell zwei Konstruktoren bereitstellen:
|
||||||
|
* <ol>
|
||||||
|
* <li> {@code MLMatrix(int rows, int columns)} erstellt eine Matrix mit den
|
||||||
|
* angegebenen Dimensionen und setzt alle Koeffizienten auf 0.
|
||||||
|
* <li> {@code MLMatrix(double[][] coefficients} erstellt eine Matrix mit der
|
||||||
|
* durch das Array gegebenen Dimensionen und setzt die Werte auf die
|
||||||
|
* jeweiligen Werte des Arrays.
|
||||||
|
* </ol>
|
||||||
|
* <p>
|
||||||
|
* Das Interface ist nicht dazu gedacht eine allgemeine Umsetzung für
|
||||||
|
* Matrizen-Algebra abzubilden, sondern soll gezielt die im Neuralen Netzwerk
|
||||||
|
* verwendeten Algorithmen umsetzen. Einerseits würde eine ganz allgemeine
|
||||||
|
* Matrizen-Klasse nicht im Rahmen der Zeichenmaschine liegen und auf der
|
||||||
|
* anderen Seite bietet eine Konzentration auf die verwendeten Algorithmen mehr
|
||||||
|
* Spielraum zur Optimierung.
|
||||||
|
* <p>
|
||||||
|
* Intern wird das Interface von {@link DoubleMatrix} implementiert. Die Klasse
|
||||||
|
* ist eine weitestgehend naive Implementierung der Algorithmen mit kleineren
|
||||||
|
* Optimierungen. Die Verwendung eines generalisierten Interfaces erlaubt aber
|
||||||
|
* zukünftig die optionale Integration spezialisierterer Algebra-Bibliotheken
|
||||||
|
* wie
|
||||||
|
* <a href="https://dst.lbl.gov/ACSSoftware/colt/">Colt</a>, um auch große
|
||||||
|
* Netze effizient berechnen zu können.
|
||||||
|
*/
|
||||||
public interface MLMatrix {
|
public interface MLMatrix {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Die Anzahl der Spalten der Matrix.
|
||||||
|
*
|
||||||
|
* @return Spaltenzahl.
|
||||||
|
*/
|
||||||
int columns();
|
int columns();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Die Anzahl der Zeilen der Matrix.
|
||||||
|
*
|
||||||
|
* @return Zeilenzahl.
|
||||||
|
*/
|
||||||
int rows();
|
int rows();
|
||||||
|
|
||||||
double[][] coefficients();
|
/**
|
||||||
|
* Gibt den Wert an der angegebenen Stelle der Matrix zurück.
|
||||||
|
*
|
||||||
|
* @param row Die Spaltennummer zwischen 0 und {@code rows()-1}.
|
||||||
|
* @param col Die Zeilennummer zwischen 0 und {@code columns()-1}
|
||||||
|
* @return Den Koeffizienten in der Zeile {@code row} und der Spalte
|
||||||
|
* {@code col}.
|
||||||
|
* @throws IllegalArgumentException Falls {@code row >= rows()} oder
|
||||||
|
* {@code col >= columns()}.
|
||||||
|
*/
|
||||||
|
double get( int row, int col ) throws IllegalArgumentException;
|
||||||
|
|
||||||
double get( int row, int col );
|
/**
|
||||||
|
* Setzt den Wert an der angegebenen Stelle der Matrix.
|
||||||
MLMatrix set( int row, int col, double value );
|
*
|
||||||
|
* @param row Die Spaltennummer zwischen 0 und {@code rows()-1}.
|
||||||
|
* @param col Die Zeilennummer zwischen 0 und {@code columns()-1}
|
||||||
|
* @param value Der neue Wert.
|
||||||
|
* @return Diese Matrix selbst (method chaining).
|
||||||
|
* @throws IllegalArgumentException Falls {@code row >= rows()} oder
|
||||||
|
* {@code col >= columns()}.
|
||||||
|
*/
|
||||||
|
MLMatrix set( int row, int col, double value ) throws IllegalArgumentException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setzt jeden Wert in der Matrix auf eine Zufallszahl zwischen -1 und 1.
|
||||||
|
* <p>
|
||||||
|
* Nach Möglichkeit sollte der
|
||||||
|
* {@link schule.ngb.zm.Constants#random(int, int) Zufallsgenerator der
|
||||||
|
* Zeichenmaschine} verwendet werden.
|
||||||
|
*
|
||||||
|
* @return Diese Matrix selbst (method chaining).
|
||||||
|
*/
|
||||||
MLMatrix initializeRandom();
|
MLMatrix initializeRandom();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setzt jeden Wert in der Matrix auf eine Zufallszahl innerhalb der
|
||||||
|
* angegebenen Grenzen.
|
||||||
|
* <p>
|
||||||
|
* Nach Möglichkeit sollte der
|
||||||
|
* {@link schule.ngb.zm.Constants#random(int, int) Zufallsgenerator der
|
||||||
|
* Zeichenmaschine} verwendet werden.
|
||||||
|
*
|
||||||
|
* @param lower Untere Grenze der Zufallszahlen.
|
||||||
|
* @param upper Obere Grenze der Zufallszahlen.
|
||||||
|
* @return Diese Matrix selbst (method chaining).
|
||||||
|
*/
|
||||||
MLMatrix initializeRandom( double lower, double upper );
|
MLMatrix initializeRandom( double lower, double upper );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setzt alle Werte der Matrix auf 1.
|
||||||
|
*
|
||||||
|
* @return Diese Matrix selbst (method chaining).
|
||||||
|
*/
|
||||||
MLMatrix initializeOne();
|
MLMatrix initializeOne();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setzt alle Werte der Matrix auf 0.
|
||||||
|
*
|
||||||
|
* @return Diese Matrix selbst (method chaining).
|
||||||
|
*/
|
||||||
MLMatrix initializeZero();
|
MLMatrix initializeZero();
|
||||||
|
|
||||||
//MLMatrix transpose();
|
/**
|
||||||
|
* Erzeugt eine neue Matrix {@code C} mit dem Ergebnis der Matrixoperation
|
||||||
//MLMatrix multiply( MLMatrix B );
|
* <pre>
|
||||||
|
* C = this . B + V'
|
||||||
|
* </pre>
|
||||||
|
* wobei {@code this} dieses Matrixobjekt ist und {@code .} für die
|
||||||
|
* Matrixmultiplikation steht. {@vode V'} ist die Matrix {@code V}
|
||||||
|
* {@code rows()}-mal untereinander wiederholt.
|
||||||
|
* <p>
|
||||||
|
* Wenn diese Matrix die Dimension r x c hat, dann muss die Matrix {@code B}
|
||||||
|
* die Dimension c x m haben und {@code V} eine 1 x m Matrix sein. Die
|
||||||
|
* Matrix {@code V'} hat also die Dimension r x m, ebenso wie das Ergebnis
|
||||||
|
* der Operation.
|
||||||
|
*
|
||||||
|
* @param B Eine {@code columns()} x m Matrix mit der Multipliziert wird.
|
||||||
|
* @param V Eine 1 x {@code B.columns()} Matrix mit den Bias-Werten.
|
||||||
|
* @return Eine {@code rows()} x m Matrix.
|
||||||
|
* @throws IllegalArgumentException Falls die Dimensionen der Matrizen nicht
|
||||||
|
* zur Operation passen. Also
|
||||||
|
* {@code this.columns() != B.rows()} oder
|
||||||
|
* {@code B.columns() != V.columns()} oder
|
||||||
|
* {@code V.rows() != 1}.
|
||||||
|
*/
|
||||||
|
MLMatrix multiplyAddBias( MLMatrix B, MLMatrix V ) throws IllegalArgumentException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Erzeugt eine neue Matrix <em>C</em> mit dem Ergebnis der Matrixoperation
|
* Erzeugt eine neue Matrix {@code C} mit dem Ergebnis der Matrixoperation
|
||||||
* <pre>
|
* <pre>
|
||||||
* C = A.B + V
|
* C = this . t(B)
|
||||||
* </pre>
|
* </pre>
|
||||||
* wobei <em>A</em> dieses Matrixobjekt ist und {@code .} für die
|
* wobei {@code this} dieses Matrixobjekt ist, {@code t(B)} die
|
||||||
|
* Transposition der Matrix {@code B} ist und {@code .} für die
|
||||||
* Matrixmultiplikation steht.
|
* Matrixmultiplikation steht.
|
||||||
|
* <p>
|
||||||
|
* Wenn diese Matrix die Dimension r x c hat, dann muss die Matrix {@code B}
|
||||||
|
* die Dimension m x c haben und das Ergebnis ist eine r x m Matrix.
|
||||||
*
|
*
|
||||||
* @param B
|
* @param B Eine m x {@code columns()} Matrix.
|
||||||
* @param V
|
* @return Eine {@code rows()} x m Matrix.
|
||||||
* @return
|
* @throws IllegalArgumentException Falls die Dimensionen der Matrizen nicht
|
||||||
|
* zur Operation passen. Also
|
||||||
|
* {@code this.columns() != B.columns()}.
|
||||||
*/
|
*/
|
||||||
MLMatrix multiplyAddBias( MLMatrix B, MLMatrix V );
|
MLMatrix multiplyTransposed( MLMatrix B ) throws IllegalArgumentException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Erzeugt eine neue Matrix <em>C</em> mit dem Ergebnis der Matrixoperation
|
* Erzeugt eine neue Matrix {@code C} mit dem Ergebnis der Matrixoperation
|
||||||
* <pre>
|
* <pre>
|
||||||
* C = A.t(B)
|
* C = t(this) . B * scalar
|
||||||
* </pre>
|
* </pre>
|
||||||
* wobei <em>A</em> dieses Matrixobjekt ist und {@code t(B)} für die
|
* wobei {@code this} dieses Matrixobjekt ist, {@code t(this)} die
|
||||||
* Transposition der Matrix <em>B</em>> steht.
|
* Transposition dieser Matrix ist und {@code .} für die
|
||||||
|
* Matrixmultiplikation steht. {@code *} bezeichnet die
|
||||||
|
* Skalarmultiplikation, bei der jeder Wert der Matrix mit {@code scalar}
|
||||||
|
* multipliziert wird.
|
||||||
|
* <p>
|
||||||
|
* Wenn diese Matrix die Dimension r x c hat, dann muss die Matrix {@code B}
|
||||||
|
* die Dimension r x m haben und das Ergebnis ist eine c x m Matrix.
|
||||||
*
|
*
|
||||||
* @param B
|
* @param B Eine m x {@code columns()} Matrix.
|
||||||
* @return
|
* @return Eine {@code rows()} x m Matrix.
|
||||||
|
* @throws IllegalArgumentException Falls die Dimensionen der Matrizen nicht
|
||||||
|
* zur Operation passen. Also
|
||||||
|
* {@code this.rows() != B.rows()}.
|
||||||
*/
|
*/
|
||||||
MLMatrix multiplyTransposed( MLMatrix B );
|
MLMatrix transposedMultiplyAndScale( MLMatrix B, double scalar ) throws IllegalArgumentException;
|
||||||
|
|
||||||
MLMatrix transposedMultiplyAndScale( MLMatrix B, double scalar );
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Erzeugt eine neue Matrix <em>C</em> mit dem Ergebnis der
|
* Erzeugt eine neue Matrix {@code C} mit dem Ergebnis der komponentenweisen
|
||||||
* komponentenweisen Matrix-Addition
|
* Matrix-Addition
|
||||||
* <pre>
|
* <pre>
|
||||||
* C = A+B
|
* C = this + B
|
||||||
* </pre>
|
* </pre>
|
||||||
* wobei <em>A</em> dieses Matrixobjekt ist. Für ein Element
|
* wobei {@code this} dieses Matrixobjekt ist. Für ein Element {@code C_ij}
|
||||||
* <em>C_ij</em> in <em>C</em> gilt
|
* in {@code C} gilt
|
||||||
* <pre>
|
* <pre>
|
||||||
* C_ij = A_ij + B_ij
|
* C_ij = A_ij + B_ij
|
||||||
* </pre>
|
* </pre>
|
||||||
|
* <p>
|
||||||
|
* Die Matrix {@code B} muss dieselbe Dimension wie diese Matrix haben.
|
||||||
*
|
*
|
||||||
* @param B Die zweite Matrix.
|
* @param B Eine {@code rows()} x {@code columns()} Matrix.
|
||||||
* @return Ein neues Matrixobjekt mit dem Ergebnis.
|
* @return Eine {@code rows()} x {@code columns()} Matrix.
|
||||||
|
* @throws IllegalArgumentException Falls die Dimensionen der Matrizen nicht
|
||||||
|
* zur Operation passen. Also
|
||||||
|
* {@code this.rows() != B.rows()} oder
|
||||||
|
* {@code this.columns() != B.columns()}.
|
||||||
*/
|
*/
|
||||||
MLMatrix add( MLMatrix B );
|
MLMatrix add( MLMatrix B ) throws IllegalArgumentException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setzt dies Matrix auf das Ergebnis der
|
* Setzt diese Matrix auf das Ergebnis der komponentenweisen
|
||||||
* komponentenweisen Matrix-Addition
|
* Matrix-Addition
|
||||||
* <pre>
|
* <pre>
|
||||||
* A = A+B
|
* A' = A + B
|
||||||
* </pre>
|
* </pre>
|
||||||
* wobei <em>A</em> dieses Matrixobjekt ist. Für ein Element
|
* wobei {@code A} dieses Matrixobjekt ist und {@code A'} diese Matrix nach
|
||||||
* <em>A_ij</em> in <em>A</em> gilt
|
* der Operation. Für ein Element {@code A'_ij} in {@code A'} gilt
|
||||||
* <pre>
|
* <pre>
|
||||||
* A_ij = A_ij + B_ij
|
* A'_ij = A_ij + B_ij
|
||||||
* </pre>
|
* </pre>
|
||||||
|
* <p>
|
||||||
|
* Die Matrix {@code B} muss dieselbe Dimension wie diese Matrix haben.
|
||||||
*
|
*
|
||||||
* @param B Die zweite Matrix.
|
* @param B Eine {@code rows()} x {@code columns()} Matrix.
|
||||||
* @return Diese Matrix selbst (method chaining).
|
* @return Eine {@code rows()} x {@code columns()} Matrix.
|
||||||
|
* @throws IllegalArgumentException Falls die Dimensionen der Matrizen nicht
|
||||||
|
* zur Operation passen. Also
|
||||||
|
* {@code this.rows() != B.rows()} oder
|
||||||
|
* {@code this.columns() != B.columns()}.
|
||||||
*/
|
*/
|
||||||
MLMatrix addInPlace( MLMatrix B );
|
MLMatrix addInPlace( MLMatrix B ) throws IllegalArgumentException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Erzeugt eine neue Matrix <em>C</em> mit dem Ergebnis der
|
* Erzeugt eine neue Matrix {@code C} mit dem Ergebnis der komponentenweisen
|
||||||
* komponentenweisen Matrix-Subtraktion
|
* Matrix-Subtraktion
|
||||||
* <pre>
|
* <pre>
|
||||||
* C = A-B
|
* C = A - B
|
||||||
* </pre>
|
* </pre>
|
||||||
* wobei <em>A</em> dieses Matrixobjekt ist. Für ein Element
|
* wobei {@code A} dieses Matrixobjekt ist. Für ein Element {@code C_ij} in
|
||||||
* <em>C_ij</em> in <em>C</em> gilt
|
* {@code C} gilt
|
||||||
* <pre>
|
* <pre>
|
||||||
* C_ij = A_ij - B_ij
|
* C_ij = A_ij - B_ij
|
||||||
* </pre>
|
* </pre>
|
||||||
|
* <p>
|
||||||
|
* Die Matrix {@code B} muss dieselbe Dimension wie diese Matrix haben.
|
||||||
*
|
*
|
||||||
* @param B
|
* @param B Eine {@code rows()} x {@code columns()} Matrix.
|
||||||
* @return
|
* @return Eine {@code rows()} x {@code columns()} Matrix.
|
||||||
|
* @throws IllegalArgumentException Falls die Dimensionen der Matrizen nicht
|
||||||
|
* zur Operation passen. Also
|
||||||
|
* {@code this.rows() != B.rows()} oder
|
||||||
|
* {@code this.columns() != B.columns()}.
|
||||||
*/
|
*/
|
||||||
MLMatrix sub( MLMatrix B );
|
MLMatrix sub( MLMatrix B ) throws IllegalArgumentException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multipliziert jeden Wert dieser Matrix mit dem angegebenen Skalar.
|
||||||
|
* <p>
|
||||||
|
* Ist {@code A} dieses Matrixobjekt und {@code A'} diese Matrix nach der
|
||||||
|
* Operation, dann gilt für ein Element {@code A'_ij} in {@code A'}
|
||||||
|
* <pre>
|
||||||
|
* A'_ij = A_ij * scalar
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @param scalar Ein Skalar.
|
||||||
|
* @return Diese Matrix selbst (method chaining)
|
||||||
|
*/
|
||||||
MLMatrix scaleInPlace( double scalar );
|
MLMatrix scaleInPlace( double scalar );
|
||||||
|
|
||||||
MLMatrix scaleInPlace( MLMatrix S );
|
/**
|
||||||
|
* Multipliziert jeden Wert dieser Matrix mit dem entsprechenden Wert in der
|
||||||
|
* Matrix {@code S}.
|
||||||
|
* <p>
|
||||||
|
* Ist {@code A} dieses Matrixobjekt und {@code A'} diese Matrix nach der
|
||||||
|
* Operation, dann gilt für ein Element {@code A'_ij} in {@code A'}
|
||||||
|
* <pre>
|
||||||
|
* A'_ij = A_ij * S_ij
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @param S Eine {@code rows()} x {@code columns()} Matrix.
|
||||||
|
* @return Diese Matrix selbst (method chaining)
|
||||||
|
* @throws IllegalArgumentException Falls die Dimensionen der Matrizen nicht
|
||||||
|
* zur Operation passen. Also
|
||||||
|
* {@code this.rows() != B.rows()} oder
|
||||||
|
* {@code this.columns() != B.columns()}.
|
||||||
|
*/
|
||||||
|
MLMatrix scaleInPlace( MLMatrix S ) throws IllegalArgumentException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Berechnet eine neue Matrix mit nur einer Zeile, die die Spaltensummen
|
* Berechnet eine neue Matrix mit nur einer Zeile, die die Spaltensummen
|
||||||
* dieser Matrix enthalten.
|
* dieser Matrix enthalten.
|
||||||
* @return
|
*
|
||||||
|
* @return Eine 1 x {@code columns()} Matrix.
|
||||||
*/
|
*/
|
||||||
MLMatrix colSums();
|
MLMatrix colSums();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Endet die gegebene Funktion auf jeden Wert der Matrix an.
|
* Erzeugt eine neue Matrix, deren Werte gleich den Werten dieser Matrix
|
||||||
|
* nach der Anwendung der angegebenen Funktion sind.
|
||||||
*
|
*
|
||||||
* @param op
|
* @param op Eine Operation {@code (double) -> double}.
|
||||||
* @return
|
* @return Eine {@code rows()} x {@code columns()} Matrix.
|
||||||
*/
|
*/
|
||||||
MLMatrix apply( DoubleUnaryOperator op );
|
MLMatrix apply( DoubleUnaryOperator op );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Endet die gegebene Funktion auf jeden Wert der Matrix an.
|
* Endet die gegebene Funktion auf jeden Wert der Matrix an.
|
||||||
*
|
*
|
||||||
* @param op
|
* @param op Eine Operation {@code (double) -> double}.
|
||||||
* @return
|
* @return Diese Matrix selbst (method chaining)
|
||||||
*/
|
*/
|
||||||
MLMatrix applyInPlace( DoubleUnaryOperator op );
|
MLMatrix applyInPlace( DoubleUnaryOperator op );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Erzeugt eine neue Matrix mit denselben Dimenstionen und Koeffizienten wie
|
* Erzeugt eine neue Matrix mit denselben Dimensionen und Koeffizienten wie
|
||||||
* diese Matrix.
|
* diese Matrix.
|
||||||
*
|
*
|
||||||
* @return
|
* @return Eine Kopie dieser Matrix.
|
||||||
*/
|
*/
|
||||||
MLMatrix duplicate();
|
MLMatrix duplicate();
|
||||||
|
|
||||||
|
|||||||
@@ -6,14 +6,27 @@ import schule.ngb.zm.util.Log;
|
|||||||
|
|
||||||
import java.util.function.DoubleUnaryOperator;
|
import java.util.function.DoubleUnaryOperator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zentrale Klasse zur Erstellung neuer Matrizen. Generell sollten neue Matrizen
|
||||||
|
* nicht direkt erstellt werden, sondern durch den Aufruf von
|
||||||
|
* {@link #create(int, int)} oder {@link #create(double[][])}. Die Fabrik
|
||||||
|
* ermittelt automatisch die beste verfügbare Implementierung und initialisiert
|
||||||
|
* eine entsprechende Implementierung von {@link MLMatrix}.
|
||||||
|
* <p>
|
||||||
|
* Derzeit werden die optionale Bibliothek <a
|
||||||
|
* href="https://dst.lbl.gov/ACSSoftware/colt/">Colt</a> und die interne
|
||||||
|
* Implementierung {@link DoubleMatrix} unterstützt.
|
||||||
|
*/
|
||||||
public class MatrixFactory {
|
public class MatrixFactory {
|
||||||
|
|
||||||
public static void main( String[] args ) {
|
/**
|
||||||
System.out.println(
|
* Erstellt eine neue Matrix mit den angegebenen Dimensionen und
|
||||||
MatrixFactory.create(new double[][]{{1.0, 0.0}, {0.0, 1.0}}).toString()
|
* initialisiert alle Werte mit 0.
|
||||||
);
|
*
|
||||||
}
|
* @param rows Anzahl der Zeilen.
|
||||||
|
* @param cols Anzahl der Spalten.
|
||||||
|
* @return Eine {@code rows} x {@code cols} Matrix.
|
||||||
|
*/
|
||||||
public static final MLMatrix create( int rows, int cols ) {
|
public static final MLMatrix create( int rows, int cols ) {
|
||||||
try {
|
try {
|
||||||
return getMatrixType().getDeclaredConstructor(int.class, int.class).newInstance(rows, cols);
|
return getMatrixType().getDeclaredConstructor(int.class, int.class).newInstance(rows, cols);
|
||||||
@@ -23,6 +36,14 @@ public class MatrixFactory {
|
|||||||
return new DoubleMatrix(rows, cols);
|
return new DoubleMatrix(rows, cols);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Erstellt eine neue Matrix mit den Dimensionen des angegebenen Arrays und
|
||||||
|
* initialisiert die Werte mit den entsprechenden Werten des Arrays.
|
||||||
|
*
|
||||||
|
* @param values Die Werte der Matrix.
|
||||||
|
* @return Eine {@code values.length} x {@code values[0].length} Matrix mit
|
||||||
|
* den Werten des Arrays.
|
||||||
|
*/
|
||||||
public static final MLMatrix create( double[][] values ) {
|
public static final MLMatrix create( double[][] values ) {
|
||||||
try {
|
try {
|
||||||
return getMatrixType().getDeclaredConstructor(double[][].class).newInstance((Object) values);
|
return getMatrixType().getDeclaredConstructor(double[][].class).newInstance((Object) values);
|
||||||
@@ -32,8 +53,17 @@ public class MatrixFactory {
|
|||||||
return new DoubleMatrix(values);
|
return new DoubleMatrix(values);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Die verwendete {@link MLMatrix} Implementierung, aus der Matrizen erzeugt
|
||||||
|
* werden.
|
||||||
|
*/
|
||||||
static Class<? extends MLMatrix> matrixType = null;
|
static Class<? extends MLMatrix> matrixType = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ermittelt die beste verfügbare Implementierung von {@link MLMatrix}.
|
||||||
|
*
|
||||||
|
* @return Die verwendete {@link MLMatrix} Implementierung.
|
||||||
|
*/
|
||||||
private static final Class<? extends MLMatrix> getMatrixType() {
|
private static final Class<? extends MLMatrix> getMatrixType() {
|
||||||
if( matrixType == null ) {
|
if( matrixType == null ) {
|
||||||
try {
|
try {
|
||||||
@@ -50,6 +80,10 @@ public class MatrixFactory {
|
|||||||
|
|
||||||
private static final Log LOG = Log.getLogger(MatrixFactory.class);
|
private static final Log LOG = Log.getLogger(MatrixFactory.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interner Wrapper der DoubleMatrix2D Klasse aus der Colt Bibliothek, um
|
||||||
|
* das {@link MLMatrix} Interface zu implementieren.
|
||||||
|
*/
|
||||||
static class ColtMatrix implements MLMatrix {
|
static class ColtMatrix implements MLMatrix {
|
||||||
|
|
||||||
cern.colt.matrix.DoubleMatrix2D matrix;
|
cern.colt.matrix.DoubleMatrix2D matrix;
|
||||||
@@ -87,11 +121,6 @@ public class MatrixFactory {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public double[][] coefficients() {
|
|
||||||
return this.matrix.toArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MLMatrix initializeRandom() {
|
public MLMatrix initializeRandom() {
|
||||||
return initializeRandom(-1.0, 1.0);
|
return initializeRandom(-1.0, 1.0);
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ public class NeuralNetwork {
|
|||||||
Writer writer = ResourceStreamProvider.getWriter(source);
|
Writer writer = ResourceStreamProvider.getWriter(source);
|
||||||
PrintWriter out = new PrintWriter(writer)
|
PrintWriter out = new PrintWriter(writer)
|
||||||
) {
|
) {
|
||||||
for( NeuronLayer layer: network.layers ) {
|
for( NeuronLayer layer : network.layers ) {
|
||||||
out.print(layer.getNeuronCount());
|
out.print(layer.getNeuronCount());
|
||||||
out.print(' ');
|
out.print(' ');
|
||||||
out.print(layer.getInputCount());
|
out.print(layer.getInputCount());
|
||||||
@@ -23,20 +23,44 @@ public class NeuralNetwork {
|
|||||||
|
|
||||||
for( int i = 0; i < layer.getInputCount(); i++ ) {
|
for( int i = 0; i < layer.getInputCount(); i++ ) {
|
||||||
for( int j = 0; j < layer.getNeuronCount(); j++ ) {
|
for( int j = 0; j < layer.getNeuronCount(); j++ ) {
|
||||||
//out.print(layer.weights.coefficients[i][j]);
|
out.print(layer.weights.get(i, j));
|
||||||
out.print(' ');
|
out.print(' ');
|
||||||
}
|
}
|
||||||
out.println();
|
out.println();
|
||||||
}
|
}
|
||||||
for( int j = 0; j < layer.getNeuronCount(); j++ ) {
|
for( int j = 0; j < layer.getNeuronCount(); j++ ) {
|
||||||
//out.print(layer.biases[j]);
|
out.print(layer.biases.get(0, j));
|
||||||
out.print(' ');
|
out.print(' ');
|
||||||
}
|
}
|
||||||
out.println();
|
out.println();
|
||||||
}
|
}
|
||||||
out.flush();
|
out.flush();
|
||||||
} catch( IOException ex ) {
|
} catch( IOException ex ) {
|
||||||
LOG.warn(ex, "");
|
LOG.error(ex, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void saveToDataFile( String source, NeuralNetwork network ) {
|
||||||
|
try(
|
||||||
|
OutputStream stream = ResourceStreamProvider.getOutputStream(source);
|
||||||
|
DataOutputStream out = new DataOutputStream(stream)
|
||||||
|
) {
|
||||||
|
for( NeuronLayer layer : network.layers ) {
|
||||||
|
out.writeInt(layer.getNeuronCount());
|
||||||
|
out.writeInt(layer.getInputCount());
|
||||||
|
|
||||||
|
for( int i = 0; i < layer.getInputCount(); i++ ) {
|
||||||
|
for( int j = 0; j < layer.getNeuronCount(); j++ ) {
|
||||||
|
out.writeDouble(layer.weights.get(i, j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for( int j = 0; j < layer.getNeuronCount(); j++ ) {
|
||||||
|
out.writeDouble(layer.biases.get(0, j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.flush();
|
||||||
|
} catch( IOException ex ) {
|
||||||
|
LOG.error(ex, "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,13 +80,13 @@ public class NeuralNetwork {
|
|||||||
for( int i = 0; i < inputs; i++ ) {
|
for( int i = 0; i < inputs; i++ ) {
|
||||||
split = in.readLine().split(" ");
|
split = in.readLine().split(" ");
|
||||||
for( int j = 0; j < neurons; j++ ) {
|
for( int j = 0; j < neurons; j++ ) {
|
||||||
//layer.weights.coefficients[i][j] = Double.parseDouble(split[j]);
|
layer.weights.set(i, j, Double.parseDouble(split[j]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Load Biases
|
// Load Biases
|
||||||
split = in.readLine().split(" ");
|
split = in.readLine().split(" ");
|
||||||
for( int j = 0; j < neurons; j++ ) {
|
for( int j = 0; j < neurons; j++ ) {
|
||||||
//layer.biases[j] = Double.parseDouble(split[j]);
|
layer.biases.set(0, j, Double.parseDouble(split[j]));
|
||||||
}
|
}
|
||||||
|
|
||||||
layers.add(layer);
|
layers.add(layer);
|
||||||
@@ -70,29 +94,30 @@ public class NeuralNetwork {
|
|||||||
|
|
||||||
return new NeuralNetwork(layers);
|
return new NeuralNetwork(layers);
|
||||||
} catch( IOException | NoSuchElementException ex ) {
|
} catch( IOException | NoSuchElementException ex ) {
|
||||||
LOG.warn(ex, "Could not load neural network from source <%s>", source);
|
LOG.error(ex, "Could not load neural network from source <%s>", source);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*public static NeuralNetwork loadFromFile( String source ) {
|
public static NeuralNetwork loadFromDataFile( String source ) {
|
||||||
try(
|
try(
|
||||||
InputStream stream = ResourceStreamProvider.getInputStream(source);
|
InputStream stream = ResourceStreamProvider.getInputStream(source);
|
||||||
Scanner in = new Scanner(stream)
|
DataInputStream in = new DataInputStream(stream)
|
||||||
) {
|
) {
|
||||||
List<NeuronLayer> layers = new LinkedList<>();
|
List<NeuronLayer> layers = new LinkedList<>();
|
||||||
while( in.hasNext() ) {
|
while( in.available() > 0 ) {
|
||||||
int neurons = in.nextInt();
|
int neurons = in.readInt();
|
||||||
int inputs = in.nextInt();
|
int inputs = in.readInt();
|
||||||
|
|
||||||
NeuronLayer layer = new NeuronLayer(neurons, inputs);
|
NeuronLayer layer = new NeuronLayer(neurons, inputs);
|
||||||
for( int i = 0; i < inputs; i++ ) {
|
for( int i = 0; i < inputs; i++ ) {
|
||||||
for( int j = 0; j < neurons; j++ ) {
|
for( int j = 0; j < neurons; j++ ) {
|
||||||
layer.weights.coefficients[i][j] = in.nextDouble();
|
layer.weights.set(i, j, in.readDouble());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Load Biases
|
||||||
for( int j = 0; j < neurons; j++ ) {
|
for( int j = 0; j < neurons; j++ ) {
|
||||||
layer.biases[j] = in.nextDouble();
|
layer.biases.set(0, j, in.readDouble());
|
||||||
}
|
}
|
||||||
|
|
||||||
layers.add(layer);
|
layers.add(layer);
|
||||||
@@ -100,10 +125,10 @@ public class NeuralNetwork {
|
|||||||
|
|
||||||
return new NeuralNetwork(layers);
|
return new NeuralNetwork(layers);
|
||||||
} catch( IOException | NoSuchElementException ex ) {
|
} catch( IOException | NoSuchElementException ex ) {
|
||||||
LOG.warn(ex, "Could not load neural network from source <%s>", source);
|
LOG.error(ex, "Could not load neural network from source <%s>", source);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}*/
|
}
|
||||||
|
|
||||||
private NeuronLayer[] layers;
|
private NeuronLayer[] layers;
|
||||||
|
|
||||||
@@ -128,7 +153,7 @@ public class NeuralNetwork {
|
|||||||
for( int i = 0; i < layers.size(); i++ ) {
|
for( int i = 0; i < layers.size(); i++ ) {
|
||||||
this.layers[i] = layers.get(i);
|
this.layers[i] = layers.get(i);
|
||||||
if( i > 0 ) {
|
if( i > 0 ) {
|
||||||
this.layers[i-1].setNextLayer(this.layers[i]);
|
this.layers[i - 1].setNextLayer(this.layers[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -138,7 +163,7 @@ public class NeuralNetwork {
|
|||||||
for( int i = 0; i < layers.length; i++ ) {
|
for( int i = 0; i < layers.length; i++ ) {
|
||||||
this.layers[i] = layers[i];
|
this.layers[i] = layers[i];
|
||||||
if( i > 0 ) {
|
if( i > 0 ) {
|
||||||
this.layers[i-1].setNextLayer(this.layers[i]);
|
this.layers[i - 1].setNextLayer(this.layers[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -146,6 +171,7 @@ public class NeuralNetwork {
|
|||||||
public int getLayerCount() {
|
public int getLayerCount() {
|
||||||
return layers.length;
|
return layers.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
public NeuronLayer[] getLayers() {
|
public NeuronLayer[] getLayers() {
|
||||||
return layers;
|
return layers;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,30 +3,45 @@ package schule.ngb.zm.ml;
|
|||||||
import java.util.function.DoubleUnaryOperator;
|
import java.util.function.DoubleUnaryOperator;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementierung einer Neuronenebene in einem Neuonalen Netz.
|
||||||
|
* <p>
|
||||||
|
* Eine Ebene besteht aus einer Anzahl an <em>Neuronen</em> die jeweils eine
|
||||||
|
* Anzahl <em>Eingänge</em> haben. Die Eingänge erhalten als Signal die Ausgabe
|
||||||
|
* der vorherigen Ebene und berechnen die Ausgabe des jeweiligen Neurons.
|
||||||
|
*/
|
||||||
public class NeuronLayer implements Function<MLMatrix, MLMatrix> {
|
public class NeuronLayer implements Function<MLMatrix, MLMatrix> {
|
||||||
|
|
||||||
/*public static NeuronLayer fromArray( double[][] weights ) {
|
public static NeuronLayer fromArray( double[][] weights, boolean transpose ) {
|
||||||
NeuronLayer layer = new NeuronLayer(weights[0].length, weights.length);
|
NeuronLayer layer;
|
||||||
|
if( transpose ) {
|
||||||
|
layer = new NeuronLayer(weights.length, weights[0].length);
|
||||||
|
} else {
|
||||||
|
layer = new NeuronLayer(weights[0].length, weights.length);
|
||||||
|
}
|
||||||
|
|
||||||
for( int i = 0; i < weights[0].length; i++ ) {
|
for( int i = 0; i < weights[0].length; i++ ) {
|
||||||
for( int j = 0; j < weights.length; j++ ) {
|
for( int j = 0; j < weights.length; j++ ) {
|
||||||
layer.weights.coefficients[i][j] = weights[i][j];
|
if( transpose ) {
|
||||||
|
layer.weights.set(j, i, weights[i][j]);
|
||||||
|
} else {
|
||||||
|
layer.weights.set(i, j, weights[i][j]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return layer;
|
return layer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static NeuronLayer fromArray( double[][] weights, double[] biases ) {
|
public static NeuronLayer fromArray( double[][] weights, double[] biases, boolean transpose ) {
|
||||||
NeuronLayer layer = new NeuronLayer(weights[0].length, weights.length);
|
NeuronLayer layer = fromArray(weights, transpose);
|
||||||
for( int i = 0; i < weights[0].length; i++ ) {
|
|
||||||
for( int j = 0; j < weights.length; j++ ) {
|
|
||||||
layer.weights.coefficients[i][j] = weights[i][j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for( int j = 0; j < biases.length; j++ ) {
|
for( int j = 0; j < biases.length; j++ ) {
|
||||||
layer.biases[j] = biases[j];
|
layer.biases.set(0, j, biases[j]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return layer;
|
return layer;
|
||||||
}*/
|
}
|
||||||
|
|
||||||
MLMatrix weights;
|
MLMatrix weights;
|
||||||
|
|
||||||
@@ -112,7 +127,7 @@ public class NeuronLayer implements Function<MLMatrix, MLMatrix> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return weights.toString() + "\n" + biases.toString();
|
return "weights:\n" + weights.toString() + "\nbiases:\n" + biases.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
package schule.ngb.zm.ml;
|
package schule.ngb.zm.ml;
|
||||||
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.TestInfo;
|
import org.junit.jupiter.api.TestInfo;
|
||||||
import org.junit.jupiter.params.ParameterizedTest;
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
import org.junit.jupiter.params.provider.ValueSource;
|
import org.junit.jupiter.params.provider.ValueSource;
|
||||||
|
import schule.ngb.zm.util.Timer;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
@@ -389,4 +391,36 @@ class MLMatrixTest {
|
|||||||
return String.format("[" + testName + "(" + className + ") " + methodName + "()] " + msg, args);
|
return String.format("[" + testName + "(" + className + ") " + methodName + "()] " + msg, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//@ParameterizedTest
|
||||||
|
//@ValueSource( classes = {MatrixFactory.ColtMatrix.class, DoubleMatrix.class} )
|
||||||
|
void speed( Class<? extends MLMatrix> mType ) {
|
||||||
|
MatrixFactory.matrixType = mType;
|
||||||
|
|
||||||
|
int N = 10;
|
||||||
|
int rows = 1000;
|
||||||
|
int cols = 1000;
|
||||||
|
|
||||||
|
Timer timer = new Timer();
|
||||||
|
|
||||||
|
MLMatrix M = MatrixFactory.create(rows, cols);
|
||||||
|
timer.start();
|
||||||
|
for( int i = 0; i < N; i++ ) {
|
||||||
|
M.initializeRandom();
|
||||||
|
}
|
||||||
|
timer.stop();
|
||||||
|
System.err.println(msg("%d iterations: %d ms", "initializeRandom", N, timer.getMillis()));
|
||||||
|
|
||||||
|
timer.reset();
|
||||||
|
|
||||||
|
MLMatrix B = MatrixFactory.create(rows*2, M.columns());
|
||||||
|
B.initializeRandom();
|
||||||
|
|
||||||
|
timer.start();
|
||||||
|
for( int i = 0; i < N; i++ ) {
|
||||||
|
M.multiplyTransposed(B);
|
||||||
|
}
|
||||||
|
timer.stop();
|
||||||
|
System.err.println(msg("%d iterations: %d ms", "multiplyTransposed", N, timer.getMillis()));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user