From bc2a7dd7ae56519080407153b60efe54794b8a31 Mon Sep 17 00:00:00 2001 From: Alexander Stoyakin Date: Thu, 12 Sep 2019 19:23:44 +0300 Subject: [PATCH] [WIP] Fixed signatures. SameDiff tests (#258) * Fixed signatures. SameDiff tests Signed-off-by: Alexander Stoyakin * Tests fixed Signed-off-by: Alexander Stoyakin * Test fixed Signed-off-by: Alexander Stoyakin * Small fix Signed-off-by: Alexander Stoyakin * Fixed test Signed-off-by: Alexander Stoyakin --- .../java/org/nd4j/linalg/factory/Nd4j.java | 48 ++++++++------ .../samediff/SameDiffTrainingTest.java | 52 +++++++++++++++ .../linalg/compression/CompressionTests.java | 6 +- .../NormalizerStandardizeLabelsTest.java | 6 +- .../dataset/NormalizerStandardizeTest.java | 6 +- .../nd4j/linalg/ops/OpExecutionerTestsC.java | 2 +- .../java/org/nd4j/linalg/rng/RandomTests.java | 4 +- nd4s/src/main/scala/org/nd4s/Implicits.scala | 4 +- .../main/scala/org/nd4s/NDArrayEvidence.scala | 37 +++++++---- .../scala/org/nd4s/OperatableNDArray.scala | 7 +-- .../scala/org/nd4s/samediff/SameDiff.scala | 9 ++- nd4s/src/test/scala/org/nd4s/DSLSpec.scala | 2 +- .../org/nd4s/NDArrayExtractionTest.scala | 18 +++--- .../org/nd4s/OperatableNDArrayTest.scala | 16 ++--- .../org/nd4s/samediff/ConstructionTest.scala | 63 ++++++++++++++++++- .../scala/org/nd4s/samediff/MathTest.scala | 12 +++- 16 files changed, 219 insertions(+), 73 deletions(-) diff --git a/nd4j/nd4j-backends/nd4j-api-parent/nd4j-api/src/main/java/org/nd4j/linalg/factory/Nd4j.java b/nd4j/nd4j-backends/nd4j-api-parent/nd4j-api/src/main/java/org/nd4j/linalg/factory/Nd4j.java index 0bbf69ebe..e04f20deb 100644 --- a/nd4j/nd4j-backends/nd4j-api-parent/nd4j-api/src/main/java/org/nd4j/linalg/factory/Nd4j.java +++ b/nd4j/nd4j-backends/nd4j-api-parent/nd4j-api/src/main/java/org/nd4j/linalg/factory/Nd4j.java @@ -2836,13 +2836,13 @@ public class Nd4j { * @param columns the number of columns in the matrix * @return the random ndarray with the specified shape */ - public static INDArray rand(int rows, int columns) { + /*public static INDArray rand(int rows, int columns) { if (rows < 1 || columns < 1) throw new ND4JIllegalStateException("Number of rows and columns should be positive for new INDArray"); INDArray ret = createUninitialized(new int[] {rows, columns}, Nd4j.order()); return rand(ret); - } + }*/ /** * Create a random ndarray with the given shape and output order @@ -2853,13 +2853,13 @@ public class Nd4j { * @param columns the number of columns in the matrix * @return the random ndarray with the specified shape */ - public static INDArray rand(char order, int rows, int columns) { + /*public static INDArray rand(char order, int rows, int columns) { if (rows < 1 || columns < 1) throw new ND4JIllegalStateException("Number of rows and columns should be positive for new INDArray"); INDArray ret = createUninitialized(new int[] {rows, columns}, order);//INSTANCE.rand(order, rows, columns); return rand(ret); - } + }*/ /** * Create a random ndarray with values from a uniform distribution over (0, 1) with the given shape @@ -2892,10 +2892,10 @@ public class Nd4j { * @param seed the seed to use * @return the random ndarray with the specified shape */ - public static INDArray rand(int rows, int columns, long seed) { + /*public static INDArray rand(int rows, int columns, long seed) { INDArray ret = createUninitialized(new int[] {rows, columns}, Nd4j.order()); return rand(ret, seed); - } + }*/ /** * @deprecated use {@link Nd4j#rand(org.nd4j.linalg.api.rng.Random, long...)} @@ -2999,10 +2999,10 @@ public class Nd4j { * @param rng the rng to use * @return a drandom matrix of the specified shape and range */ - public static INDArray rand(int rows, int columns, double min, double max, @NonNull org.nd4j.linalg.api.rng.Random rng) { + /*public static INDArray rand(int rows, int columns, double min, double max, @NonNull org.nd4j.linalg.api.rng.Random rng) { INDArray ret = createUninitialized(rows, columns); return rand(ret, min, max, rng); - } + }*/ /** * Fill the given ndarray with random numbers drawn from a normal distribution @@ -3020,7 +3020,7 @@ public class Nd4j { * @param shape the shape of the array * @return new array with random values */ - public static INDArray randn(@NonNull int... shape) { + public static INDArray randn(@NonNull int[] shape) { return randn(ArrayUtil.toLongArray(shape)); } @@ -3031,7 +3031,7 @@ public class Nd4j { * @param shape the shape of the ndarray * @return new array with random values */ - public static INDArray randn(@NonNull DataType dataType, @NonNull int... shape) { + public static INDArray randn(@NonNull DataType dataType, @NonNull int[] shape) { return randn(dataType, ArrayUtil.toLongArray(shape)); } @@ -3135,10 +3135,10 @@ public class Nd4j { * @param rows the number of rows in the matrix * @param columns the number of columns in the matrix */ - public static INDArray randn(char order, long rows, long columns) { + /*public static INDArray randn(char order, long rows, long columns) { INDArray ret = Nd4j.createUninitialized(new long[]{rows, columns}, order); return randn(ret); - } + }*/ /** * Random normal using the specified seed @@ -3147,10 +3147,10 @@ public class Nd4j { * @param columns the number of columns in the matrix * @return new array with random values */ - public static INDArray randn(long rows, long columns, long seed) { + /*public static INDArray randn(long rows, long columns, long seed) { INDArray ret = Nd4j.createUninitialized(new long[]{rows, columns}, order()); return randn(ret, seed); - } + }*/ /** * Random normal using the given rng @@ -3160,10 +3160,10 @@ public class Nd4j { * @param r the random generator to use * @return new array with random values */ - public static INDArray randn(long rows, long columns, @NonNull org.nd4j.linalg.api.rng.Random r) { + /*public static INDArray randn(long rows, long columns, @NonNull org.nd4j.linalg.api.rng.Random r) { INDArray ret = Nd4j.createUninitialized(new long[]{rows, columns}, order()); return randn(ret, r); - } + }*/ /** * @deprecated use {@link Nd4j#randn(org.nd4j.linalg.api.rng.Random, long...)} @@ -3193,6 +3193,14 @@ public class Nd4j { return randn(ret, r); } + public static INDArray randn(double mean, double stddev, INDArray target, @NonNull org.nd4j.linalg.api.rng.Random rng) { + return getExecutioner().exec(new GaussianDistribution(target, mean, stddev), rng); + } + + public static INDArray randn(double mean, double stddev, long[] shape, @NonNull org.nd4j.linalg.api.rng.Random rng) { + INDArray target = Nd4j.createUninitialized(shape); + return getExecutioner().exec(new GaussianDistribution(target, mean, stddev), rng); + } /** * Fill the given ndarray with random numbers drawn from a uniform distribution * @@ -3361,9 +3369,9 @@ public class Nd4j { * @param columns columns * @return uninitialized 2D array of rows x columns */ - public static INDArray createUninitialized(long rows, long columns) { + /*public static INDArray createUninitialized(long rows, long columns) { return createUninitialized(new long[] {rows, columns}); - } + }*/ /** * Creates a row vector with the data @@ -3740,7 +3748,7 @@ public class Nd4j { * @param shape the shape of the array * @return the created ndarray */ - public static INDArray create(float[] data, int... shape) { + public static INDArray create(float[] data, int[] shape) { if (shape.length == 0 && data.length == 1) { return scalar(data[0]); } @@ -3782,7 +3790,7 @@ public class Nd4j { * @param shape the shape of the array * @return the created ndarray */ - public static INDArray create(double[] data, int... shape) { + public static INDArray create(double[] data, int[] shape) { commonCheckCreate(data.length, LongUtils.toLongs(shape)); val lshape = ArrayUtil.toLongArray(shape); return INSTANCE.create(data, lshape, Nd4j.getStrides(lshape, Nd4j.order()), DataType.DOUBLE, Nd4j.getMemoryManager().getCurrentWorkspace()); diff --git a/nd4j/nd4j-backends/nd4j-tests/src/test/java/org/nd4j/autodiff/samediff/SameDiffTrainingTest.java b/nd4j/nd4j-backends/nd4j-tests/src/test/java/org/nd4j/autodiff/samediff/SameDiffTrainingTest.java index 9361c47f1..4db765c5e 100644 --- a/nd4j/nd4j-backends/nd4j-tests/src/test/java/org/nd4j/autodiff/samediff/SameDiffTrainingTest.java +++ b/nd4j/nd4j-backends/nd4j-tests/src/test/java/org/nd4j/autodiff/samediff/SameDiffTrainingTest.java @@ -23,6 +23,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import lombok.extern.slf4j.Slf4j; +import lombok.val; import org.junit.Test; import org.nd4j.autodiff.listeners.impl.ScoreListener; import org.nd4j.autodiff.listeners.records.History; @@ -30,8 +31,11 @@ import org.nd4j.evaluation.IEvaluation; import org.nd4j.evaluation.classification.Evaluation; import org.nd4j.linalg.BaseNd4jTest; import org.nd4j.linalg.api.buffer.DataType; +import org.nd4j.linalg.api.ndarray.INDArray; import org.nd4j.linalg.dataset.DataSet; import org.nd4j.linalg.dataset.IrisDataSetIterator; +import org.nd4j.linalg.dataset.MultiDataSet; +import org.nd4j.linalg.dataset.adapter.SingletonMultiDataSetIterator; import org.nd4j.linalg.dataset.api.iterator.DataSetIterator; import org.nd4j.linalg.dataset.api.preprocessor.NormalizerStandardize; import org.nd4j.linalg.factory.Nd4j; @@ -290,6 +294,54 @@ public class SameDiffTrainingTest extends BaseNd4jTest { } + @Test + public void simpleClassification() { + double learning_rate = 0.001; + int seed = 7; + org.nd4j.linalg.api.rng.Random rng = Nd4j.getRandom(); + rng.setSeed(seed); + INDArray x1_label1 = Nd4j.randn(3.0, 1.0, new long[]{1000}, rng); + INDArray x2_label1 = Nd4j.randn(2.0, 1.0, new long[]{1000}, rng); + INDArray x1_label2 = Nd4j.randn(7.0, 1.0, new long[]{1000}, rng); + INDArray x2_label2 = Nd4j.randn(6.0, 1.0, new long[]{1000}, rng); + + INDArray x1s = Nd4j.concat(0, x1_label1, x1_label2); + INDArray x2s = Nd4j.concat(0, x2_label1, x2_label2); + + SameDiff sd = SameDiff.create(); + INDArray ys = Nd4j.scalar(0.0).mul(x1_label1.length()).add(Nd4j.scalar(1.0).mul(x1_label2.length())); + + SDVariable X1 = sd.placeHolder("x1", DataType.DOUBLE, 2000); + SDVariable X2 = sd.placeHolder("x2", DataType.DOUBLE, 2000); + SDVariable y = sd.placeHolder("y", DataType.DOUBLE); + SDVariable w = sd.var("w", DataType.DOUBLE, 3); + + // TF code: + //cost = tf.reduce_mean(-tf.log(y_model * Y + (1 — y_model) * (1 — Y))) + SDVariable y_model = + sd.nn.sigmoid(w.get(SDIndex.point(2)).mul(X2).add(w.get(SDIndex.point(1)).mul(X1)).add(w.get(SDIndex.point(0)))); + SDVariable cost_fun = + (sd.math.neg(sd.math.log(y_model.mul(y).add((sd.math.log(sd.constant(1.0).minus(y_model)).mul(sd.constant(1.0).minus(y))))))); + SDVariable loss = sd.mean("loss", cost_fun); + + val updater = new Sgd(learning_rate); + + sd.setLossVariables("loss"); + sd.createGradFunction(); + val conf = new TrainingConfig.Builder() + .updater(updater) + .minimize("loss") + .dataSetFeatureMapping("x1", "x2", "y") + .markLabelsUnused() + .build(); + + MultiDataSet mds = new MultiDataSet(new INDArray[]{x1s, x2s, ys},null); + + sd.setTrainingConfig(conf); + History history = sd.fit(new SingletonMultiDataSetIterator(mds), 1); + } + + @Override public char ordering() { return 'c'; diff --git a/nd4j/nd4j-backends/nd4j-tests/src/test/java/org/nd4j/linalg/compression/CompressionTests.java b/nd4j/nd4j-backends/nd4j-tests/src/test/java/org/nd4j/linalg/compression/CompressionTests.java index ec78c53bd..3967a2c95 100644 --- a/nd4j/nd4j-backends/nd4j-tests/src/test/java/org/nd4j/linalg/compression/CompressionTests.java +++ b/nd4j/nd4j-backends/nd4j-tests/src/test/java/org/nd4j/linalg/compression/CompressionTests.java @@ -458,7 +458,7 @@ public class CompressionTests extends BaseNd4jTest { @Test public void testBitmapEncoding4() { Nd4j.getRandom().setSeed(119); - INDArray initial = Nd4j.rand(1, 10000, 0, 1, Nd4j.getRandom()); + INDArray initial = Nd4j.rand(new int[]{1, 10000}, 0, 1, Nd4j.getRandom()); INDArray exp_1 = initial.dup(); INDArray enc = Nd4j.getExecutioner().bitmapEncode(initial, 1e-1); @@ -471,7 +471,7 @@ public class CompressionTests extends BaseNd4jTest { @Test public void testBitmapEncoding5() { Nd4j.getRandom().setSeed(119); - INDArray initial = Nd4j.rand(1, 10000, -1, -0.5, Nd4j.getRandom()); + INDArray initial = Nd4j.rand(new int[]{1, 10000}, -1, -0.5, Nd4j.getRandom()); INDArray exp_0 = initial.dup().addi(1e-1); INDArray exp_1 = initial.dup(); @@ -486,7 +486,7 @@ public class CompressionTests extends BaseNd4jTest { @Test public void testBitmapEncoding6() { Nd4j.getRandom().setSeed(119); - INDArray initial = Nd4j.rand(1, 100000, -1, 1, Nd4j.getRandom()); + INDArray initial = Nd4j.rand(new int[]{1, 100000}, -1, 1, Nd4j.getRandom()); INDArray exp_1 = initial.dup(); INDArray enc = Nd4j.getExecutioner().bitmapEncode(initial, 1e-3); diff --git a/nd4j/nd4j-backends/nd4j-tests/src/test/java/org/nd4j/linalg/dataset/NormalizerStandardizeLabelsTest.java b/nd4j/nd4j-backends/nd4j-tests/src/test/java/org/nd4j/linalg/dataset/NormalizerStandardizeLabelsTest.java index b33c25fe3..ed9139f40 100644 --- a/nd4j/nd4j-backends/nd4j-tests/src/test/java/org/nd4j/linalg/dataset/NormalizerStandardizeLabelsTest.java +++ b/nd4j/nd4j-backends/nd4j-tests/src/test/java/org/nd4j/linalg/dataset/NormalizerStandardizeLabelsTest.java @@ -186,12 +186,12 @@ public class NormalizerStandardizeLabelsTest extends BaseNd4jTest { int i = 0; // Randomly generate scaling constants and add offsets // to get aA and bB - INDArray aA = a == 1 ? Nd4j.ones(1, nFeatures) : Nd4j.rand(1, nFeatures, randSeed).mul(a); //a = 1, don't scale - INDArray bB = Nd4j.rand(1, nFeatures, randSeed).mul(b); //b = 0 this zeros out + INDArray aA = a == 1 ? Nd4j.ones(1, nFeatures) : Nd4j.rand(new int[]{1, nFeatures}, randSeed).mul(a); //a = 1, don't scale + INDArray bB = Nd4j.rand(new int[]{1, nFeatures}, randSeed).mul(b); //b = 0 this zeros out // transform ndarray as X = aA + bB * X INDArray randomFeatures = Nd4j.zeros(nSamples, nFeatures); while (i < nFeatures) { - INDArray randomSlice = Nd4j.randn(nSamples, 1, randSeed); + INDArray randomSlice = Nd4j.randn(new int[]{nSamples, 1}, randSeed); randomSlice.muli(aA.getScalar(0, i)); randomSlice.addi(bB.getScalar(0, i)); randomFeatures.putColumn(i, randomSlice); diff --git a/nd4j/nd4j-backends/nd4j-tests/src/test/java/org/nd4j/linalg/dataset/NormalizerStandardizeTest.java b/nd4j/nd4j-backends/nd4j-tests/src/test/java/org/nd4j/linalg/dataset/NormalizerStandardizeTest.java index 5ccee46a3..9372f2627 100644 --- a/nd4j/nd4j-backends/nd4j-tests/src/test/java/org/nd4j/linalg/dataset/NormalizerStandardizeTest.java +++ b/nd4j/nd4j-backends/nd4j-tests/src/test/java/org/nd4j/linalg/dataset/NormalizerStandardizeTest.java @@ -303,13 +303,13 @@ public class NormalizerStandardizeTest extends BaseNd4jTest { int i = 0; // Randomly generate scaling constants and add offsets // to get aA and bB - INDArray aA = a == 1 ? Nd4j.ones(1, nFeatures) : Nd4j.rand(1, nFeatures, randSeed).mul(a); //a = 1, don't scale - INDArray bB = Nd4j.rand(1, nFeatures, randSeed).mul(b); //b = 0 this zeros out + INDArray aA = a == 1 ? Nd4j.ones(1, nFeatures) : Nd4j.rand(new int[]{1, nFeatures}, randSeed).mul(a); //a = 1, don't scale + INDArray bB = Nd4j.rand(new int[]{1, nFeatures}, randSeed).mul(b); //b = 0 this zeros out // transform ndarray as X = aA + bB * X INDArray randomFeatures = Nd4j.zeros(nSamples, nFeatures); INDArray randomFeaturesTransform = Nd4j.zeros(nSamples, nFeatures); while (i < nFeatures) { - INDArray randomSlice = Nd4j.randn(nSamples, 1, randSeed); + INDArray randomSlice = Nd4j.randn(new int[]{nSamples, 1}, randSeed); randomFeaturesTransform.putColumn(i, randomSlice); randomSlice.muli(aA.getScalar(0, i)); randomSlice.addi(bB.getScalar(0, i)); diff --git a/nd4j/nd4j-backends/nd4j-tests/src/test/java/org/nd4j/linalg/ops/OpExecutionerTestsC.java b/nd4j/nd4j-backends/nd4j-tests/src/test/java/org/nd4j/linalg/ops/OpExecutionerTestsC.java index 866c592b7..0df75ac74 100644 --- a/nd4j/nd4j-backends/nd4j-tests/src/test/java/org/nd4j/linalg/ops/OpExecutionerTestsC.java +++ b/nd4j/nd4j-backends/nd4j-tests/src/test/java/org/nd4j/linalg/ops/OpExecutionerTestsC.java @@ -1048,7 +1048,7 @@ public class OpExecutionerTestsC extends BaseNd4jTest { @Test public void testNorm2_2() { - INDArray array = Nd4j.rand(127, 164, 1, 100, Nd4j.getRandom()); + INDArray array = Nd4j.rand(new int[]{127, 164}, 1, 100, Nd4j.getRandom()); double norm2 = array.norm2Number().doubleValue(); } diff --git a/nd4j/nd4j-backends/nd4j-tests/src/test/java/org/nd4j/linalg/rng/RandomTests.java b/nd4j/nd4j-backends/nd4j-tests/src/test/java/org/nd4j/linalg/rng/RandomTests.java index e5a567dc1..aa39be145 100644 --- a/nd4j/nd4j-backends/nd4j-tests/src/test/java/org/nd4j/linalg/rng/RandomTests.java +++ b/nd4j/nd4j-backends/nd4j-tests/src/test/java/org/nd4j/linalg/rng/RandomTests.java @@ -906,8 +906,8 @@ public class RandomTests extends BaseNd4jTest { public void testSignatures1() { for (int x = 0; x < 100; x++) { - INDArray z1 = Nd4j.randn(128, 1, 5325235); - INDArray z2 = Nd4j.randn(128, 1, 5325235); + INDArray z1 = Nd4j.randn(new int[]{128, 1}, 5325235); + INDArray z2 = Nd4j.randn(new int[]{128, 1}, 5325235); assertEquals(z1, z2); } diff --git a/nd4s/src/main/scala/org/nd4s/Implicits.scala b/nd4s/src/main/scala/org/nd4s/Implicits.scala index 58f4f245a..fc2b08b97 100644 --- a/nd4s/src/main/scala/org/nd4s/Implicits.scala +++ b/nd4s/src/main/scala/org/nd4s/Implicits.scala @@ -50,7 +50,7 @@ object Implicits { Nd4j.create(underlying, shape, ord.value) def asNDArray(shape: Int*): INDArray = - Nd4j.create(underlying.toArray, shape.toArray: _*) + Nd4j.create(underlying.toArray, shape.toArray) def toNDArray: INDArray = Nd4j.create(underlying) } @@ -66,7 +66,7 @@ object Implicits { Nd4j.create(underlying, shape, offset, ord.value) def asNDArray(shape: Int*): INDArray = - Nd4j.create(underlying.toArray, shape.toArray: _*) + Nd4j.create(underlying.toArray, shape.toArray) def toNDArray: INDArray = Nd4j.create(underlying) } diff --git a/nd4s/src/main/scala/org/nd4s/NDArrayEvidence.scala b/nd4s/src/main/scala/org/nd4s/NDArrayEvidence.scala index 5151fcb34..bc520db55 100644 --- a/nd4s/src/main/scala/org/nd4s/NDArrayEvidence.scala +++ b/nd4s/src/main/scala/org/nd4s/NDArrayEvidence.scala @@ -110,11 +110,11 @@ trait NDArrayEvidence[NDArray <: INDArray, Value] { def put(a: NDArray, i: Array[Int], element: INDArray): NDArray - def get(a: NDArray, i: Int): Value + def get(a: NDArray, i: Long): Value - def get(a: NDArray, i: Int, j: Int): Value + //def get(a: NDArray, i: Long, j: Long): Value - def get(a: NDArray, i: Int*): Value + def get(a: NDArray, i: Long*): Value def get(a: NDArray, i: INDArrayIndex*): NDArray @@ -254,11 +254,15 @@ case object DoubleNDArrayEvidence extends RealNDArrayEvidence[Double] { override def norm1(ndarray: INDArray): Double = ndarray.norm1Number().doubleValue() - override def get(a: INDArray, i: Int): Double = a.getDouble(i.toLong) + override def get(a: INDArray, i: Long): Double = a.getDouble(i) - override def get(a: INDArray, i: Int, j: Int): Double = a.getDouble(i.toLong, j.toLong) + //override def get(a: INDArray, i: Int): Double = a.getDouble(i.toLong) - override def get(a: INDArray, i: Int*): Double = a.getDouble(i: _*) + //override def get(a: INDArray, i: Int, j: Int): Double = a.getDouble(i.toLong, j.toLong) + + //override def get(a: INDArray, i: Int*): Double = a.getDouble(i: _*) + + override def get(a: INDArray, i: Long*): Double = a.getDouble(i: _*) override def create(arr: Array[Double]): INDArray = arr.toNDArray @@ -315,11 +319,13 @@ case object FloatNDArrayEvidence extends RealNDArrayEvidence[Float] { override def norm1(ndarray: INDArray): Float = ndarray.norm1Number().floatValue() - override def get(a: INDArray, i: Int): Float = a.getFloat(i) + override def get(a: INDArray, i: Long): Float = a.getFloat(i) - override def get(a: INDArray, i: Int, j: Int): Float = a.getFloat(i, j) + //override def get(a: INDArray, i: Long, j: Long): Float = a.getFloat(i, j) - override def get(a: INDArray, i: Int*): Float = a.getFloat(i.toArray) + //override def get(a: INDArray, i: Int*): Float = a.getFloat(i: _*) + + override def get(a: INDArray, i: Long*): Float = a.getFloat(i: _*) override def create(arr: Array[Float]): INDArray = arr.toNDArray @@ -440,11 +446,14 @@ case object IntNDArrayEvidence extends IntegerNDArrayEvidence[Int] { def variance(ndarray: INDArray): Int = ndarray.varNumber().intValue() + def get(a: INDArray, i: Long): Int = a.getInt(i.toInt) + def get(a: INDArray, i: Int): Int = a.getInt(i) def get(a: INDArray, i: Int, j: Int): Int = a.getInt(i, j) - def get(a: INDArray, i: Int*): Int = a.getInt(i: _*) + def get(a: INDArray, i: Long*): Int = + a.getInt(i.map(_.toInt): _*) def create(arr: Array[Int]): INDArray = arr.toNDArray @@ -480,11 +489,13 @@ case object LongNDArrayEvidence extends IntegerNDArrayEvidence[Long] { def variance(ndarray: INDArray): Long = ndarray.varNumber().longValue() + def get(a: INDArray, i: Long): Long = a.getLong(i) + def get(a: INDArray, i: Int): Long = a.getLong(i) def get(a: INDArray, i: Int, j: Int): Long = a.getLong(i, j) - def get(a: INDArray, i: Int*): Long = a.getLong(i.map(_.toLong): _*) + def get(a: INDArray, i: Long*): Long = a.getLong(i: _*) def create(arr: Array[Long]): INDArray = arr.toNDArray @@ -523,11 +534,13 @@ case object ByteNDArrayEvidence extends IntegerNDArrayEvidence[Byte] { def variance(ndarray: INDArray): Byte = ndarray.varNumber().byteValue() + def get(a: INDArray, i: Long): Byte = a.getInt(i.toInt).toByte + def get(a: INDArray, i: Int): Byte = a.getInt(i).toByte def get(a: INDArray, i: Int, j: Int): Byte = a.getInt(i, j).toByte - def get(a: INDArray, i: Int*): Byte = a.getInt(i.map(_.toInt): _*).toByte + def get(a: INDArray, i: Long*): Byte = a.getInt(i.map(_.toInt): _*).toByte def create(arr: Array[Byte]): INDArray = arr.toNDArray diff --git a/nd4s/src/main/scala/org/nd4s/OperatableNDArray.scala b/nd4s/src/main/scala/org/nd4s/OperatableNDArray.scala index 82a227e02..4e28704b3 100644 --- a/nd4s/src/main/scala/org/nd4s/OperatableNDArray.scala +++ b/nd4s/src/main/scala/org/nd4s/OperatableNDArray.scala @@ -16,7 +16,6 @@ package org.nd4s import org.nd4j.linalg.api.ndarray.INDArray -import org.nd4j.linalg.indexing.INDArrayIndex /** * Scala DSL for arrays @@ -121,7 +120,7 @@ trait OperatableNDArray[A <: INDArray] { ev.get(underlying, i, j) def get[B](indices: Int*)(implicit ev: NDArrayEvidence[A, B]): B = - ev.get(underlying, indices: _*) + ev.get(underlying, indices.map(_.toLong): _*) def apply[B](i: Int)(implicit ev: NDArrayEvidence[A, B]): B = get(i) @@ -129,10 +128,10 @@ trait OperatableNDArray[A <: INDArray] { get(i, j) def apply[B](indices: Int*)(implicit ev: NDArrayEvidence[A, B]): B = - get(indices: _*) + ev.get(underlying, indices.map(_.toLong): _*) def get[B](indices: Array[Int])(implicit ev: NDArrayEvidence[A, B]): B = - ev.get(underlying, indices: _*) + ev.get(underlying, indices.map(_.toLong): _*) def unary_-(): INDArray = underlying.neg() diff --git a/nd4s/src/main/scala/org/nd4s/samediff/SameDiff.scala b/nd4s/src/main/scala/org/nd4s/samediff/SameDiff.scala index e43a1e86e..fc70b6d3f 100644 --- a/nd4s/src/main/scala/org/nd4s/samediff/SameDiff.scala +++ b/nd4s/src/main/scala/org/nd4s/samediff/SameDiff.scala @@ -16,8 +16,7 @@ package org.nd4s.samediff import org.nd4j.linalg.api.ndarray.INDArray -import org.nd4j.autodiff.samediff.SDVariable -import org.nd4j.autodiff.samediff.SameDiff +import org.nd4j.autodiff.samediff.{ SDIndex, SDVariable, SameDiff } import org.nd4j.linalg.api.buffer.DataType import org.nd4j.linalg.factory.Nd4j @@ -49,7 +48,7 @@ class SameDiffWrapper { sd.`var`(name, dataType, shape: _*) def placeHolder(name: String, dataType: DataType, shape: Long*): SDVariable = - sd.placeHolder("ph1", DataType.FLOAT, 3, 4) + sd.placeHolder(name, dataType, shape: _*) } class SDVariableWrapper { @@ -62,6 +61,10 @@ class SDVariableWrapper { thisVariable = variable } + def apply(index: Long): SDVariable = thisVariable.get(SDIndex.point(index)) + + def add(other: Double): Unit = thisVariable.add(other) + def *(other: SDVariable): SDVariable = thisVariable.mul(other) diff --git a/nd4s/src/test/scala/org/nd4s/DSLSpec.scala b/nd4s/src/test/scala/org/nd4s/DSLSpec.scala index 6ef290f5b..41eddfac0 100644 --- a/nd4s/src/test/scala/org/nd4s/DSLSpec.scala +++ b/nd4s/src/test/scala/org/nd4s/DSLSpec.scala @@ -29,7 +29,7 @@ class DSLSpec extends FlatSpec with Matchers { // This test just verifies that an INDArray gets wrapped with an implicit conversion - val nd = Nd4j.create(Array[Float](1, 2), Array(2, 1): _*) + val nd = Nd4j.create(Array[Float](1, 2), Array(2, 1)) val nd1 = nd + 10L // + creates new array, += modifies in place nd.get(0) should equal(1) diff --git a/nd4s/src/test/scala/org/nd4s/NDArrayExtractionTest.scala b/nd4s/src/test/scala/org/nd4s/NDArrayExtractionTest.scala index 5894e31d7..6d1f9c795 100644 --- a/nd4s/src/test/scala/org/nd4s/NDArrayExtractionTest.scala +++ b/nd4s/src/test/scala/org/nd4s/NDArrayExtractionTest.scala @@ -220,23 +220,23 @@ trait NDArrayExtractionTestBase extends FlatSpec { self: OrderingForTest => val list = (0 to 9).toNDArray val step = list(1 -> 7 by 2).reshape(-1) assert(step.length() == 3) - assert(step.getFloat(0) == 1) + assert(step.getFloat(0: Long) == 1) assert(step(0) == 1) assert(step(0, 0) == 1) - assert(step.getFloat(1) == 3) - assert(step.getFloat(2) == 5) + assert(step.getFloat(1: Long) == 3) + assert(step.getFloat(2: Long) == 5) val filtered = list(-2 -> 10).reshape(-1) assert(filtered.length() == 2) - assert(filtered.getFloat(0) == 8) - assert(filtered.getFloat(1) == 9) + assert(filtered.getFloat(0: Long) == 8) + assert(filtered.getFloat(1: Long) == 9) val nStep = list(-3 -> 3 by -1).reshape(-1) assert(nStep.length() == 4) - assert(nStep.getFloat(0) == 7) - assert(nStep.getFloat(1) == 6) - assert(nStep.getFloat(2) == 5) - assert(nStep.getFloat(3) == 4) + assert(nStep.getFloat(0: Long) == 7) + assert(nStep.getFloat(1: Long) == 6) + assert(nStep.getFloat(2: Long) == 5) + assert(nStep.getFloat(3: Long) == 4) } it should "be able to update value with specified indices" in { diff --git a/nd4s/src/test/scala/org/nd4s/OperatableNDArrayTest.scala b/nd4s/src/test/scala/org/nd4s/OperatableNDArrayTest.scala index bb6fe1a49..7f48bcce8 100644 --- a/nd4s/src/test/scala/org/nd4s/OperatableNDArrayTest.scala +++ b/nd4s/src/test/scala/org/nd4s/OperatableNDArrayTest.scala @@ -26,27 +26,27 @@ import org.scalatest.{ FlatSpec, Matchers } class OperatableNDArrayTest extends FlatSpec with Matchers { "RichNDArray" should "use the apply method to access values" in { // -- 2D array - val nd2 = Nd4j.create(Array[Double](1, 2, 3, 4), Array[Int](1, 4): _*) + val nd2 = Nd4j.create(Array[Double](1, 2, 3, 4), Array[Int](1, 4)) nd2.get(0) should be(1) nd2.get(0, 3) should be(4) // -- 3D array - val nd3 = Nd4j.create(Array[Double](1, 2, 3, 4, 5, 6, 7, 8), Array[Int](2, 2, 2): _*) + val nd3 = Nd4j.create(Array[Double](1, 2, 3, 4, 5, 6, 7, 8), Array[Int](2, 2, 2)) nd3.get(0, 0, 0) should be(1) nd3.get(1, 1, 1) should be(8) } it should "use transpose abbreviation" in { - val nd1 = Nd4j.create(Array[Double](1, 2, 3), Array(3, 1): _*) + val nd1 = Nd4j.create(Array[Double](1, 2, 3), Array(3, 1)) nd1.shape should equal(Array(3, 1)) val nd1t = nd1.T nd1t.shape should equal(Array(1, 3)) } it should "add correctly" in { - val a = Nd4j.create(Array[Double](1, 2, 3, 4, 5, 6, 7, 8), Array(2, 2, 2): _*) + val a = Nd4j.create(Array[Double](1, 2, 3, 4, 5, 6, 7, 8), Array(2, 2, 2)) val b = a + 100 a.get(0, 0, 0) should be(1) b.get(0, 0, 0) should be(101) @@ -55,7 +55,7 @@ class OperatableNDArrayTest extends FlatSpec with Matchers { } it should "subtract correctly" in { - val a = Nd4j.create(Array[Double](1, 2, 3, 4, 5, 6, 7, 8), Array(2, 2, 2): _*) + val a = Nd4j.create(Array[Double](1, 2, 3, 4, 5, 6, 7, 8), Array(2, 2, 2)) val b = a - 100 a.get(0, 0, 0) should be(1) b.get(0, 0, 0) should be(-99) @@ -69,7 +69,7 @@ class OperatableNDArrayTest extends FlatSpec with Matchers { } it should "divide correctly" in { - val a = Nd4j.create(Array[Double](1, 2, 3, 4, 5, 6, 7, 8), Array(2, 2, 2): _*) + val a = Nd4j.create(Array[Double](1, 2, 3, 4, 5, 6, 7, 8), Array(2, 2, 2)) val b = a / a a.get(1, 1, 1) should be(8) b.get(1, 1, 1) should be(1) @@ -78,7 +78,7 @@ class OperatableNDArrayTest extends FlatSpec with Matchers { } it should "element-by-element multiply correctly" in { - val a = Nd4j.create(Array[Double](1, 2, 3, 4), Array(4, 1): _*) + val a = Nd4j.create(Array[Double](1, 2, 3, 4), Array(4, 1)) val b = a * a a.get(3) should be(4) // [1.0, 2.0, 3.0, 4.0 b.get(3) should be(16) // [1.0 ,4.0 ,9.0 ,16.0] @@ -87,7 +87,7 @@ class OperatableNDArrayTest extends FlatSpec with Matchers { } it should "use the update method to mutate values" in { - val nd3 = Nd4j.create(Array[Double](1, 2, 3, 4, 5, 6, 7, 8), Array(2, 2, 2): _*) + val nd3 = Nd4j.create(Array[Double](1, 2, 3, 4, 5, 6, 7, 8), Array(2, 2, 2)) nd3(0) = 11 nd3.get(0) should be(11) diff --git a/nd4s/src/test/scala/org/nd4s/samediff/ConstructionTest.scala b/nd4s/src/test/scala/org/nd4s/samediff/ConstructionTest.scala index 700c626e4..95715ecb1 100644 --- a/nd4s/src/test/scala/org/nd4s/samediff/ConstructionTest.scala +++ b/nd4s/src/test/scala/org/nd4s/samediff/ConstructionTest.scala @@ -15,10 +15,13 @@ ******************************************************************************/ package org.nd4s.samediff -import org.nd4j.autodiff.samediff.{ SDVariable, SameDiff } +import org.nd4j.autodiff.samediff.{ SDVariable, SameDiff, TrainingConfig } import org.nd4j.linalg.api.buffer.DataType import org.nd4j.linalg.api.ndarray.INDArray +import org.nd4j.linalg.dataset.MultiDataSet +import org.nd4j.linalg.dataset.adapter.SingletonMultiDataSetIterator import org.nd4j.linalg.factory.Nd4j +import org.nd4j.linalg.learning.config.Sgd import org.nd4s.Implicits._ import org.nd4s.samediff.implicits.Implicits._ import org.scalatest.{ FlatSpec, Matchers } @@ -114,4 +117,62 @@ class ConstructionTest extends FlatSpec with Matchers { var evaluated3 = w3.eval.castTo(DataType.DOUBLE) evaluated3.toFloatVector.head shouldBe 16.0 } + + "classification example" should "work" in { + val learning_rate = 0.1 + val seed = 7 + + val target = Nd4j.createUninitialized(1000) + val rng = Nd4j.getRandom + rng.setSeed(seed) + val x1_label1 = Nd4j.randn(3.0, 1.0, target, rng) + val target1 = Nd4j.createUninitialized(1000) + val x2_label1 = Nd4j.randn(2.0, 1.0, target1, rng) + val target2 = Nd4j.createUninitialized(1000) + val x1_label2 = Nd4j.randn(7.0, 1.0, target2, rng) + val target3 = Nd4j.createUninitialized(1000) + val x2_label2 = Nd4j.randn(6.0, 1.0, target3, rng) + + // np.append, was not able to guess proper method + val x1s = Nd4j.concat(0, x1_label1, x1_label2) + val x2s = Nd4j.concat(0, x2_label1, x2_label2) + + // Must have implicit sd here for some ops + implicit val sd = SameDiff.create + val ys = (Nd4j.scalar(0.0) * x1_label1.length()) + (Nd4j.scalar(1.0) * x1_label2.length()) + + // Empty shape can't be passed vs tf behaviour + val X1 = sd.placeHolder("x1", DataType.DOUBLE, 2000) + val X2 = sd.placeHolder("x2", DataType.DOUBLE, 2000) + val y = sd.placeHolder("y", DataType.DOUBLE) + val w = sd.bind("w", DataType.DOUBLE, Array[Int](3)) + //Sample: -tf.log(y_model * Y + (1 — y_model) * (1 — Y)) + val y_model: SDVariable = + sd.nn.sigmoid(w(2) * X2 + w(1) * X1 + w(0)) + val cost_fun: SDVariable = (sd.math.neg( + sd.math.log(y_model * y + (sd.math.log(sd.constant(1.0) - y_model) * (sd.constant(1.0) - y))) + )) + val loss = sd.mean("loss", cost_fun) + + val updater = new Sgd(learning_rate) + + sd.setLossVariables("loss") + sd.createGradFunction + val conf = new TrainingConfig.Builder() + .updater(updater) + .minimize("loss") + .dataSetFeatureMapping("x1", "x2", "y") + .markLabelsUnused() + .build() + + val mds = new MultiDataSet(Array[INDArray](x1s, x2s, ys), new Array[INDArray](0)) + + sd.setTrainingConfig(conf) + sd.fit(new SingletonMultiDataSetIterator(mds), 1) + + w.eval.toDoubleVector.head shouldBe (0.0629 +- 0.0001) + w.eval.toDoubleVector.tail.head shouldBe (0.3128 +- 0.0001) + w.eval.toDoubleVector.tail.tail.head shouldBe (0.2503 +- 0.0001) + //Console.println(w.eval) + } } diff --git a/nd4s/src/test/scala/org/nd4s/samediff/MathTest.scala b/nd4s/src/test/scala/org/nd4s/samediff/MathTest.scala index 8e9f892c6..104356f24 100644 --- a/nd4s/src/test/scala/org/nd4s/samediff/MathTest.scala +++ b/nd4s/src/test/scala/org/nd4s/samediff/MathTest.scala @@ -15,7 +15,7 @@ ******************************************************************************/ package org.nd4s.samediff -import org.nd4j.autodiff.samediff.{ SDVariable, SameDiff } +import org.nd4j.autodiff.samediff.{ SDIndex, SDVariable, SameDiff } import org.nd4j.linalg.api.buffer.DataType import org.nd4j.linalg.api.ndarray.INDArray import org.nd4j.linalg.factory.Nd4j @@ -200,4 +200,14 @@ class MathTest extends FlatSpec with Matchers { val w3 = w1 >> two w3.eval.toIntVector.head shouldBe 4 } + + "SDVariable " should "be indexable" in { + implicit val sd = SameDiff.create + + val arr = Nd4j.linspace(1, 100, 100).reshape('c', 10L, 10L) + val x = sd.`var`(arr) + val y = new SDVariableWrapper(x) + + x.get(SDIndex.point(0)).getArr shouldBe y(0).getArr + } }