package org.deeplearning4j.convolution;
import org.deeplearning4j.berkeley.Pair;
import org.deeplearning4j.nn.api.Layer;
import org.deeplearning4j.nn.conf.ConvolutionMode;
import org.deeplearning4j.nn.conf.MultiLayerConfiguration;
import org.deeplearning4j.nn.conf.NeuralNetConfiguration;
import org.deeplearning4j.nn.conf.inputs.InputType;
import org.deeplearning4j.nn.conf.layers.ConvolutionLayer;
import org.deeplearning4j.nn.conf.layers.OutputLayer;
import org.deeplearning4j.nn.conf.layers.SubsamplingLayer;
import org.deeplearning4j.nn.gradient.Gradient;
import org.deeplearning4j.nn.multilayer.MultiLayerNetwork;
import org.deeplearning4j.nn.weights.WeightInit;
import org.junit.Test;
import org.nd4j.linalg.activations.Activation;
import org.nd4j.linalg.api.ndarray.INDArray;
import org.nd4j.linalg.factory.Nd4j;
import org.nd4j.linalg.lossfunctions.LossFunctions;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* Created by Alex on 15/11/2016.
*/
public class TestConvolution {
@Test
public void testSameModeActivationSizes() {
int inH = 3;
int inW = 4;
int inDepth = 3;
int minibatch = 5;
int sH = 2;
int sW = 2;
int kH = 3;
int kW = 3;
org.deeplearning4j.nn.conf.layers.Layer[] l = new org.deeplearning4j.nn.conf.layers.Layer[2];
l[0] = new ConvolutionLayer.Builder().nOut(4).kernelSize(kH, kW).stride(sH, sW).build();
l[1] = new SubsamplingLayer.Builder().kernelSize(kH, kW).stride(sH, sW).build();
for (int i = 0; i < l.length; i++) {
MultiLayerConfiguration conf = new NeuralNetConfiguration.Builder().convolutionMode(ConvolutionMode.Same)
.list().layer(0, l[i]).layer(1, new OutputLayer.Builder().nOut(3).build())
.setInputType(InputType.convolutional(inH, inW, inDepth)).build();
MultiLayerNetwork net = new MultiLayerNetwork(conf);
net.init();
INDArray inData = Nd4j.create(minibatch, inDepth, inH, inW);
List<INDArray> activations = net.feedForward(inData);
INDArray actL0 = activations.get(1);
int outH = (int) Math.ceil(inH / ((double) sH));
int outW = (int) Math.ceil(inW / ((double) sW));
System.out.println(Arrays.toString(actL0.shape()));
assertArrayEquals(new int[] {minibatch, (i == 0 ? 4 : inDepth), outH, outW}, actL0.shape());
}
}
@Test
public void testCompareCudnnStandardOutputsVsMode() throws Exception {
ConvolutionMode[] cm =
new ConvolutionMode[] {ConvolutionMode.Strict, ConvolutionMode.Truncate, ConvolutionMode.Same};
for (ConvolutionMode c : cm) {
for (boolean conv : new boolean[] {true, false}) {
org.deeplearning4j.nn.conf.layers.Layer l;
if (conv) {
l = new ConvolutionLayer.Builder().nOut(4).kernelSize(4, 4).stride(2, 2).build();
} else {
l = new SubsamplingLayer.Builder().kernelSize(4, 4).stride(2, 2).build();
}
MultiLayerConfiguration conf = new NeuralNetConfiguration.Builder().seed(12345).regularization(true)
.l2(0.0005).learningRate(.01).weightInit(WeightInit.XAVIER).convolutionMode(c).list()
.layer(0, l)
.layer(1, new OutputLayer.Builder(LossFunctions.LossFunction.NEGATIVELOGLIKELIHOOD)
.nOut(10).activation(Activation.SOFTMAX).build())
.setInputType(InputType.convolutionalFlat(28, 28, 1)) //See note below
.backprop(true).pretrain(false).build();
Nd4j.getRandom().setSeed(12345);
MultiLayerNetwork net1 = new MultiLayerNetwork(conf);
net1.init();
net1.initGradientsView();
Nd4j.getRandom().setSeed(12345);
MultiLayerNetwork net2 = new MultiLayerNetwork(conf);
net2.init();
net2.initGradientsView();
Layer layerCudnn = net1.getLayer(0);
Layer layerStandard = net2.getLayer(0);
Field f = layerStandard.getClass().getDeclaredField("helper");
f.setAccessible(true);
f.set(layerStandard, null);
if (f.get(layerCudnn) == null)
throw new RuntimeException();
if (f.get(layerStandard) != null)
throw new RuntimeException();
INDArray in = Nd4j.rand(new int[] {1, 1, 20, 20}); //(20-4+0)/2 +1 = 9
INDArray outCudnn = layerCudnn.activate(in);
INDArray outStd = layerStandard.activate(in);
assertEquals(outStd, outCudnn);
//Check backprop:
INDArray epsilon = Nd4j.rand(outStd.shape());
Pair<Gradient, INDArray> pCudnn = layerCudnn.backpropGradient(epsilon);
Pair<Gradient, INDArray> pStd = layerStandard.backpropGradient(epsilon);
System.out.println(Arrays.toString(pStd.getSecond().data().asFloat()));
System.out.println(Arrays.toString(pCudnn.getSecond().data().asFloat()));
INDArray epsOutStd = pStd.getSecond();
INDArray epsOutCudnn = pCudnn.getSecond();
assertTrue(epsOutStd.equalsWithEps(epsOutCudnn, 1e-4));
if (conv) {
INDArray gradStd = pStd.getFirst().gradient();
INDArray gradCudnn = pCudnn.getFirst().gradient();
assertTrue(gradStd.equalsWithEps(gradCudnn, 1e-4));
}
}
}
}
}