Index: ml/src/main/java/org/apache/hama/ml/ann/AbstractLayeredNeuralNetwork.java =================================================================== --- ml/src/main/java/org/apache/hama/ml/ann/AbstractLayeredNeuralNetwork.java (revision 1514730) +++ ml/src/main/java/org/apache/hama/ml/ann/AbstractLayeredNeuralNetwork.java (working copy) @@ -62,15 +62,23 @@ protected List layerSizeList; protected TrainingMethod trainingMethod; + + protected LearningStyle learningStyle; public static enum TrainingMethod { GRADIATE_DESCENT } - + + public static enum LearningStyle { + UNSUPERVISED, + SUPERVISED + } + public AbstractLayeredNeuralNetwork() { this.regularizationWeight = DEFAULT_REGULARIZATION_WEIGHT; this.momentumWeight = DEFAULT_MOMENTUM_WEIGHT; this.trainingMethod = TrainingMethod.GRADIATE_DESCENT; + this.learningStyle = LearningStyle.SUPERVISED; } public AbstractLayeredNeuralNetwork(String modelPath) { @@ -116,6 +124,14 @@ public TrainingMethod getTrainingMethod() { return this.trainingMethod; } + + public void setLearningStyle(LearningStyle style) { + this.learningStyle = style; + } + + public LearningStyle getLearningStyle() { + return this.learningStyle; + } /** * Set the cost function for the model. @@ -219,6 +235,7 @@ } this.trainingMethod = WritableUtils.readEnum(input, TrainingMethod.class); + this.learningStyle = WritableUtils.readEnum(input, LearningStyle.class); } @Override @@ -239,6 +256,7 @@ } WritableUtils.writeEnum(output, this.trainingMethod); + WritableUtils.writeEnum(output, this.learningStyle); } } Index: ml/src/main/java/org/apache/hama/ml/ann/AutoEncoder.java =================================================================== --- ml/src/main/java/org/apache/hama/ml/ann/AutoEncoder.java (revision 0) +++ ml/src/main/java/org/apache/hama/ml/ann/AutoEncoder.java (working copy) @@ -0,0 +1,183 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hama.ml.ann; + +import java.util.Map; + +import org.apache.hadoop.fs.Path; +import org.apache.hama.ml.ann.AbstractLayeredNeuralNetwork.LearningStyle; +import org.apache.hama.ml.math.DenseDoubleVector; +import org.apache.hama.ml.math.DoubleFunction; +import org.apache.hama.ml.math.DoubleMatrix; +import org.apache.hama.ml.math.DoubleVector; +import org.apache.hama.ml.math.FunctionFactory; + +import com.google.common.base.Preconditions; + +/** + * AutoEncoder is a model used for dimensional reduction and feature learning. + * It is a special kind of {@link NeuralNetwork} that consists of three layers + * of neurons, where the first layer and third layer contains the same number of + * neurons. + * + */ +public class AutoEncoder { + + private SmallLayeredNeuralNetwork model; + + /** + * Initialize the autoencoder. + * + * @param inputDimensions The number of dimensions for the input feature. + * @param compressedDimensions The number of dimensions for the compressed + * information. + */ + public AutoEncoder(int inputDimensions, int compressedDimensions) { + model = new SmallLayeredNeuralNetwork(); + model.addLayer(inputDimensions, false, + FunctionFactory.createDoubleFunction("Sigmoid")); + model.addLayer(compressedDimensions, false, + FunctionFactory.createDoubleFunction("Sigmoid")); + model.addLayer(inputDimensions, true, + FunctionFactory.createDoubleFunction("Sigmoid")); + model.setLearningStyle(LearningStyle.UNSUPERVISED); + model.setCostFunction(FunctionFactory + .createDoubleDoubleFunction("SquaredError")); + } + + public AutoEncoder(String modelPath) { + model = new SmallLayeredNeuralNetwork(modelPath); + } + + public AutoEncoder setLearningRate(double learningRate) { + model.setLearningRate(learningRate); + return this; + } + + public AutoEncoder setMomemtumWeight(double momentumWeight) { + model.setMomemtumWeight(momentumWeight); + return this; + } + + public AutoEncoder setRegularizationWeight(double regularizationWeight) { + model.setRegularizationWeight(regularizationWeight); + return this; + } + + public AutoEncoder setModelPath(String modelPath) { + model.setModelPath(modelPath); + return this; + } + + /** + * Train the autoencoder with given data. Note that the training data is + * pre-processed, where the features + * + * @param dataInputPath + * @param trainingParams + */ + public void train(Path dataInputPath, Map trainingParams) { + model.train(dataInputPath, trainingParams); + } + + /** + * Train the model with one instance. + * + * @param trainingInstance + */ + public void trainOnline(DoubleVector trainingInstance) { + model.trainOnline(trainingInstance); + } + + /** + * Get the matrix M used to encode the input features. + * + * @return + */ + public DoubleMatrix getEncodeWeightMatrix() { + return model.getWeightsByLayer(0); + } + + /** + * Get the matrix M used to decode the compressed information. + * + * @return + */ + public DoubleMatrix getDecodeWeightMatrix() { + return model.getWeightsByLayer(1); + } + + /** + * Transform the input features. + * + * @param inputInstance + * @return The compressed information. + */ + private DoubleVector transform(DoubleVector inputInstance, int inputLayer) { + DoubleVector internalInstance = new DenseDoubleVector(inputInstance.getDimension() + 1); + internalInstance.set(0, 1); + for (int i = 0; i < inputInstance.getDimension(); ++i) { + internalInstance.set(i + 1, inputInstance.get(i)); + } + DoubleFunction squashingFunction = model + .getSquashingFunction(inputLayer); + DoubleMatrix weightMatrix = null; + if (inputLayer == 0) { + weightMatrix = this.getEncodeWeightMatrix(); + } else { + weightMatrix = this.getDecodeWeightMatrix(); + } + DoubleVector vec = weightMatrix.multiplyVectorUnsafe(internalInstance); + vec = vec.applyToElements(squashingFunction); + return vec; + } + + /** + * Encode the input instance. + * @param inputInstance + * @return + */ + public DoubleVector encode(DoubleVector inputInstance) { + Preconditions + .checkArgument( + inputInstance.getDimension() == model.getLayerSize(0) - 1, + String.format("The dimension of input instance is %d, but the model requires dimension %d.", + inputInstance.getDimension(), model.getLayerSize(1) - 1)); + return this.transform(inputInstance, 0); + } + + /** + * Decode the input instance. + * @param inputInstance + * @return + */ + public DoubleVector decode(DoubleVector inputInstance) { + Preconditions + .checkArgument( + inputInstance.getDimension() == model.getLayerSize(1) - 1, + String.format("The dimension of input instance is %d, but the model requires dimension %d.", + inputInstance.getDimension(), model.getLayerSize(1) - 1)); + return this.transform(inputInstance, 1); + } + + public DoubleVector getOutput(DoubleVector inputInstance) { + return model.getOutput(inputInstance); + } + +} Index: ml/src/main/java/org/apache/hama/ml/ann/SmallLayeredNeuralNetwork.java =================================================================== --- ml/src/main/java/org/apache/hama/ml/ann/SmallLayeredNeuralNetwork.java (revision 1514730) +++ ml/src/main/java/org/apache/hama/ml/ann/SmallLayeredNeuralNetwork.java (working copy) @@ -288,7 +288,6 @@ // fill with instance DoubleVector intermediateOutput = instance; outputCache.add(intermediateOutput); - // System.out.printf("Input layer: %s\n", intermediateOutput.toString()); for (int i = 0; i < this.layerSizeList.size() - 1; ++i) { intermediateOutput = forward(i, intermediateOutput); @@ -308,11 +307,7 @@ DoubleMatrix weightMatrix = this.weightMatrixList.get(fromLayer); DoubleVector vec = weightMatrix.multiplyVectorUnsafe(intermediateOutput); - // System.out.printf("Before applying squashing, from Layer %d to %d: %s\n", - // fromLayer, fromLayer + 1, vec.toString()); vec = vec.applyToElements(this.squashingFunctionList.get(fromLayer)); - // System.out.printf("After applying squashing, from Layer %d to %d: %s\n", - // fromLayer, fromLayer + 1, vec.toString()); // add bias DoubleVector vecWithBias = new DenseDoubleVector(vec.getDimension() + 1); @@ -330,32 +325,51 @@ */ public void trainOnline(DoubleVector trainingInstance) { DoubleMatrix[] updateMatrices = this.trainByInstance(trainingInstance); - // System.out.printf("Sum: %f\n", updateMatrices[0].sum()); this.updateWeightMatrices(updateMatrices); } @Override public DoubleMatrix[] trainByInstance(DoubleVector trainingInstance) { - // validate training instance int inputDimension = this.layerSizeList.get(0) - 1; - int outputDimension = this.layerSizeList.get(this.layerSizeList.size() - 1); - Preconditions.checkArgument( - inputDimension + outputDimension == trainingInstance.getDimension(), - String.format( - "The dimension of training instance is %d, but requires %d.", - trainingInstance.getDimension(), inputDimension + outputDimension)); + int outputDimension; + DoubleVector inputInstance = null; + DoubleVector labels = null; + if (this.learningStyle == LearningStyle.SUPERVISED) { + outputDimension = this.layerSizeList.get(this.layerSizeList.size() - 1); + // validate training instance + Preconditions.checkArgument( + inputDimension + outputDimension == trainingInstance.getDimension(), + String + .format( + "The dimension of training instance is %d, but requires %d.", + trainingInstance.getDimension(), inputDimension + + outputDimension)); - // prepare the features and labels - DoubleVector inputInstance = new DenseDoubleVector( - this.layerSizeList.get(0)); - inputInstance.set(0, 1); // add bias - for (int i = 0; i < inputDimension; ++i) { - inputInstance.set(i + 1, trainingInstance.get(i)); + inputInstance = new DenseDoubleVector(this.layerSizeList.get(0)); + inputInstance.set(0, 1); // add bias + for (int i = 0; i < inputDimension; ++i) { + inputInstance.set(i + 1, trainingInstance.get(i)); + } + + labels = trainingInstance.sliceUnsafe(inputInstance.getDimension() - 1, + trainingInstance.getDimension() - 1); + } else if (this.learningStyle == LearningStyle.UNSUPERVISED) { + // labels are identical to input features + outputDimension = inputDimension; + // validate training instance + Preconditions.checkArgument(inputDimension == trainingInstance + .getDimension(), String.format( + "The dimension of training instance is %d, but requires %d.", + trainingInstance.getDimension(), inputDimension)); + + inputInstance = new DenseDoubleVector(this.layerSizeList.get(0)); + inputInstance.set(0, 1); // add bias + for (int i = 0; i < inputDimension; ++i) { + inputInstance.set(i + 1, trainingInstance.get(i)); + } + labels = trainingInstance.deepCopy(); } - DoubleVector labels = trainingInstance.sliceUnsafe( - inputInstance.getDimension() - 1, trainingInstance.getDimension() - 1); - List internalResults = this.getOutputInternal(inputInstance); DoubleVector output = internalResults.get(internalResults.size() - 1); @@ -391,24 +405,6 @@ DoubleVector deltaVec = new DenseDoubleVector( this.layerSizeList.get(this.layerSizeList.size() - 1)); - // // calculate norm-2 error ||t - o||^2 - // DoubleVector errorVec = output.slice(output.getDimension() - - // 1).applyToElements(labels, new DoubleDoubleFunction() { - // @Override - // public double apply(double x1, double x2) { - // double v = x1 - x2; - // return v * v; - // } - // @Override - // public double applyDerivative(double x1, double x2) { - // throw new UnsupportedOperationException(); - // } - // }); - // double error = errorVec.sum(); - // System.out.printf("Error: %f\n", error); - - // System.out.printf("Output: %s\n", output); - DoubleFunction squashingFunction = this.squashingFunctionList .get(this.squashingFunctionList.size() - 1); @@ -427,8 +423,6 @@ * squashingFunction.applyDerivative(output.get(i + 1))); } - // System.out.printf("Delta output: %s\n", deltaVec.toString()); - // start from previous layer of output layer for (int layer = this.layerSizeList.size() - 2; layer >= 0; --layer) { output = internalResults.get(layer); @@ -536,6 +530,7 @@ job.setOutputFormat(org.apache.hama.bsp.NullOutputFormat.class); int numTasks = conf.getInt("tasks", 1); + Log.info(String.format("Number of tasks: %d\n", numTasks)); job.setNumBspTask(numTasks); job.waitForCompletion(true); @@ -554,4 +549,14 @@ // System.out.printf("Training error: %s\n", errors); } + /** + * Get the squashing function of a specified layer. + * + * @param idx + * @return + */ + public DoubleFunction getSquashingFunction(int idx) { + return this.squashingFunctionList.get(idx); + } + } Index: ml/src/main/java/org/apache/hama/ml/ann/SmallLayeredNeuralNetworkTrainer.java =================================================================== --- ml/src/main/java/org/apache/hama/ml/ann/SmallLayeredNeuralNetworkTrainer.java (revision 1514730) +++ ml/src/main/java/org/apache/hama/ml/ann/SmallLayeredNeuralNetworkTrainer.java (working copy) @@ -70,7 +70,7 @@ this.modelPath = conf.get("modelPath"); this.maxIterations = conf.getLong("training.max.iterations", 100000); this.convergenceCheckInterval = conf.getLong("convergence.check.interval", - 1000); + 2000); this.modelPath = conf.get("modelPath"); this.inMemoryModel = new SmallLayeredNeuralNetwork(modelPath); this.prevAvgTrainingError = Integer.MAX_VALUE; Index: ml/src/main/java/org/apache/hama/ml/perception/SmallMLPTrainer.java =================================================================== --- ml/src/main/java/org/apache/hama/ml/perception/SmallMLPTrainer.java (revision 1514730) +++ ml/src/main/java/org/apache/hama/ml/perception/SmallMLPTrainer.java (working copy) @@ -21,8 +21,6 @@ import java.util.Arrays; import java.util.BitSet; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.NullWritable; import org.apache.hama.bsp.BSPPeer; Index: ml/src/test/java/org/apache/hama/ml/MLTestBase.java =================================================================== --- ml/src/test/java/org/apache/hama/ml/MLTestBase.java (revision 0) +++ ml/src/test/java/org/apache/hama/ml/MLTestBase.java (working copy) @@ -0,0 +1,62 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hama.ml; + +import java.util.Arrays; +import java.util.List; + +/** + * The common methods for testing machine learning algorithms + * + */ +public abstract class MLTestBase { + + /** + * Conduct the 0-1 normalization. + * @param instances + */ + protected static void zeroOneNormalization(List instanceList, int len) { + int dimension = len; + + double[] mins = new double[dimension]; + double[] maxs = new double[dimension]; + Arrays.fill(mins, Double.MAX_VALUE); + Arrays.fill(maxs, Double.MIN_VALUE); + + for (double[] instance : instanceList) { + for (int i = 0; i < len; ++i) { + if (mins[i] > instance[i]) { + mins[i] = instance[i]; + } + if (maxs[i] < instance[i]) { + maxs[i] = instance[i]; + } + } + } + + for (double[] instance : instanceList) { + for (int i = 0; i < len; ++i) { + double range = maxs[i] - mins[i]; + if (range != 0) { + instance[i] = (instance[i] - mins[i]) / range; + } + } + } + + } +} Index: ml/src/test/java/org/apache/hama/ml/ann/TestAutoEncoder.java =================================================================== --- ml/src/test/java/org/apache/hama/ml/ann/TestAutoEncoder.java (revision 0) +++ ml/src/test/java/org/apache/hama/ml/ann/TestAutoEncoder.java (working copy) @@ -0,0 +1,197 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hama.ml.ann; + +import static org.junit.Assert.assertEquals; + +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.io.LongWritable; +import org.apache.hadoop.io.SequenceFile; +import org.apache.hama.ml.MLTestBase; +import org.apache.hama.ml.math.DenseDoubleVector; +import org.apache.hama.ml.math.DoubleVector; +import org.apache.hama.ml.writable.VectorWritable; +import org.junit.Ignore; +import org.junit.Test; +import org.mortbay.log.Log; + +/** + * Test the functionality of {@link AutoEncoder}. + * + */ +public class TestAutoEncoder extends MLTestBase { + + @Test + public void testAutoEncoderSimple() { + double[][] instances = { { 0, 0, 0, 1 }, { 0, 0, 1, 0 }, { 0, 1, 0, 0 }, + { 0, 0, 0, 0 } }; + AutoEncoder encoder = new AutoEncoder(4, 2); + encoder.setLearningRate(0.5); + encoder.setMomemtumWeight(0.2); + + int maxIteration = 2000; + Random rnd = new Random(); + for (int iteration = 0; iteration < maxIteration; ++iteration) { + for (int i = 0; i < instances.length; ++i) { + encoder.trainOnline(new DenseDoubleVector(instances[rnd.nextInt(instances.length)])); + } + } + + for (int i = 0; i < instances.length; ++i) { + DoubleVector encodeVec = encoder.encode(new DenseDoubleVector( + instances[i])); + DoubleVector decodeVec = encoder.decode(encodeVec); + for (int d = 0; d < instances[i].length; ++d) { + assertEquals(instances[i][d], decodeVec.get(d), 0.1); + } + } + + } + + @Ignore + @Test + public void testAutoEncoderSwissRollDataset() { + List instanceList = new ArrayList(); + try { + BufferedReader br = new BufferedReader(new FileReader("src/test/resources/dimensional_reduction.txt")); + String line = null; + while ((line = br.readLine()) != null) { + String[] tokens = line.split("\t"); + double[] instance = new double[tokens.length]; + for (int i = 0; i < instance.length; ++i) { + instance[i] = Double.parseDouble(tokens[i]); + } + instanceList.add(instance); + } + br.close(); + // normalize instances + zeroOneNormalization(instanceList, instanceList.get(0).length); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (NumberFormatException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + + List vecInstanceList = new ArrayList(); + for (double[] instance : instanceList) { + vecInstanceList.add(new DenseDoubleVector(instance)); + } + AutoEncoder encoder = new AutoEncoder(3, 2); + encoder.setLearningRate(0.05); + encoder.setMomemtumWeight(0.1); + int maxIteration = 2000; + for (int iteration = 0; iteration < maxIteration; ++iteration) { + for (DoubleVector vector : vecInstanceList) { + encoder.trainOnline(vector); + } + } + + double errorInstance = 0; + for (DoubleVector vector : vecInstanceList) { + DoubleVector decoded = encoder.getOutput(vector); + DoubleVector diff = vector.subtract(decoded); + double error = diff.dot(diff); + if (error > 0.1) { + ++errorInstance; + } + } + Log.info(String.format("Autoecoder error rate: %f%%\n", errorInstance * 100 / vecInstanceList.size())); + + } + + @Test + public void testAutoEncoderSwissRollDatasetDistributed() { + String strDataPath = "/tmp/dimensional_reduction.txt"; + Path path = new Path(strDataPath); + List instanceList = new ArrayList(); + try { + Configuration conf = new Configuration(); + FileSystem fs = FileSystem.get(new URI(strDataPath), conf); + if (fs.exists(path)) { + fs.delete(path, true); + } + + String line = null; + BufferedReader br = new BufferedReader(new FileReader("src/test/resources/dimensional_reduction.txt")); + while ((line = br.readLine()) != null) { + String[] tokens = line.split("\t"); + double[] instance = new double[tokens.length]; + for (int i = 0; i < instance.length; ++i) { + instance[i] = Double.parseDouble(tokens[i]); + } + instanceList.add(instance); + } + br.close(); + // normalize instances + zeroOneNormalization(instanceList, instanceList.get(0).length); + + SequenceFile.Writer writer = new SequenceFile.Writer(fs, conf, path, LongWritable.class, VectorWritable.class); + for (int i = 0; i < instanceList.size(); ++i) { + DoubleVector vector = new DenseDoubleVector(instanceList.get(i)); + writer.append(new LongWritable(i), new VectorWritable(vector)); + } + + writer.close(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + + AutoEncoder encoder = new AutoEncoder(3, 2); + String modelPath = "/tmp/autoencoder-modelpath"; + encoder.setModelPath(modelPath); + Map trainingParams = new HashMap(); + encoder.setLearningRate(0.5); + trainingParams.put("tasks", "5"); + trainingParams.put("training.max.iterations", "3000"); + trainingParams.put("training.batch.size", "200"); + encoder.train(path, trainingParams); + + double errorInstance = 0; + for (double[] instance : instanceList) { + DoubleVector vector = new DenseDoubleVector(instance); + DoubleVector decoded = encoder.getOutput(vector); + DoubleVector diff = vector.subtract(decoded); + double error = diff.dot(diff); + if (error > 0.1) { + ++errorInstance; + } + } + Log.info(String.format("Autoecoder error rate: %f%%\n", errorInstance * 100 / instanceList.size())); + } + +} Index: ml/src/test/java/org/apache/hama/ml/ann/TestSmallLayeredNeuralNetwork.java =================================================================== --- ml/src/test/java/org/apache/hama/ml/ann/TestSmallLayeredNeuralNetwork.java (revision 1514730) +++ ml/src/test/java/org/apache/hama/ml/ann/TestSmallLayeredNeuralNetwork.java (working copy) @@ -27,7 +27,6 @@ import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.HashMap; @@ -39,6 +38,8 @@ import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.SequenceFile; +import org.apache.hama.ml.MLTestBase; +import org.apache.hama.ml.ann.AbstractLayeredNeuralNetwork.LearningStyle; import org.apache.hama.ml.ann.AbstractLayeredNeuralNetwork.TrainingMethod; import org.apache.hama.ml.math.DenseDoubleMatrix; import org.apache.hama.ml.math.DenseDoubleVector; @@ -53,7 +54,7 @@ * Test the functionality of SmallLayeredNeuralNetwork. * */ -public class TestSmallLayeredNeuralNetwork { +public class TestSmallLayeredNeuralNetwork extends MLTestBase { @Test public void testReadWrite() { @@ -77,6 +78,7 @@ matrices[0] = new DenseDoubleMatrix(5, 3, 0.2); matrices[1] = new DenseDoubleMatrix(1, 6, 0.8); ann.setWeightMatrices(matrices); + ann.setLearningStyle(LearningStyle.UNSUPERVISED); // write to file String modelPath = "/tmp/testSmallLayeredNeuralNetworkReadWrite"; @@ -96,6 +98,7 @@ assertEquals(regularizationWeight, annCopy.getRegularizationWeight(), 0.000001); assertEquals(TrainingMethod.GRADIATE_DESCENT, annCopy.getTrainingMethod()); + assertEquals(LearningStyle.UNSUPERVISED, annCopy.getLearningStyle()); // compare weights DoubleMatrix[] weightsMatrices = annCopy.getWeightMatrices(); @@ -291,7 +294,7 @@ DoubleVector input = new DenseDoubleVector(instances[i]).slice(2); // the expected output is the last element in array double result = instances[i][2]; - assertEquals(result, ann.getOutput(input).get(0), 0.05); + assertEquals(result, ann.getOutput(input).get(0), 0.1); } // write model into file and read out @@ -336,34 +339,10 @@ e.printStackTrace(); } + zeroOneNormalization(instanceList, instanceList.get(0).length - 1); + int dimension = instanceList.get(0).length - 1; - // min-max normalization - double[] mins = new double[dimension]; - double[] maxs = new double[dimension]; - Arrays.fill(mins, Double.MAX_VALUE); - Arrays.fill(maxs, Double.MIN_VALUE); - - for (double[] instance : instanceList) { - for (int i = 0; i < instance.length - 1; ++i) { - if (mins[i] > instance[i]) { - mins[i] = instance[i]; - } - if (maxs[i] < instance[i]) { - maxs[i] = instance[i]; - } - } - } - - for (double[] instance : instanceList) { - for (int i = 0; i < instance.length - 1; ++i) { - double range = maxs[i] - mins[i]; - if (range != 0) { - instance[i] = (instance[i] - mins[i]) / range; - } - } - } - // divide dataset into training and testing List testInstances = new ArrayList(); testInstances.addAll(instanceList.subList(instanceList.size() - 100, @@ -413,12 +392,12 @@ } @Test - public void testDistributedVersion() { + public void testLogisticRegressionDistributedVersion() { // write data into a sequence file String tmpStrDatasetPath = "/tmp/logistic_regression_data"; Path tmpDatasetPath = new Path(tmpStrDatasetPath); String strDataPath = "src/test/resources/logistic_regression_data.txt"; - String modelPath = "/tmp/distributed-model"; + String modelPath = "/tmp/logistic-regression-distributed-model"; Configuration conf = new Configuration(); List instanceList = new ArrayList(); @@ -444,30 +423,9 @@ instanceList.add(instance); } br.close(); - - int dimension = instanceList.get(0).length - 1; - // min-max normalization - double[] mins = new double[dimension]; - double[] maxs = new double[dimension]; - Arrays.fill(mins, Double.MAX_VALUE); - Arrays.fill(maxs, Double.MIN_VALUE); - - for (double[] instance : instanceList) { - for (int i = 0; i < instance.length - 1; ++i) { - mins[i] = Math.min(mins[i], instance[i]); - maxs[i] = Math.max(maxs[i], instance[i]); - } - } - - for (double[] instance : instanceList) { - for (int i = 0; i < instance.length - 1; ++i) { - double range = maxs[i] - mins[i]; - if (range != 0) { - instance[i] = (instance[i] - mins[i]) / range; - } - } - } - + + zeroOneNormalization(instanceList, instanceList.get(0).length - 1); + // write training data to temporal sequence file SequenceFile.Writer writer = new SequenceFile.Writer(fs, conf, tmpDatasetPath, LongWritable.class, VectorWritable.class); Index: ml/src/test/java/org/apache/hama/ml/ann/TestSmallLayeredNeuralNetworkMessage.java =================================================================== --- ml/src/test/java/org/apache/hama/ml/ann/TestSmallLayeredNeuralNetworkMessage.java (revision 1514730) +++ ml/src/test/java/org/apache/hama/ml/ann/TestSmallLayeredNeuralNetworkMessage.java (working copy) @@ -86,7 +86,7 @@ DoubleMatrix[] readPrevMatrices = readMessage.getPrevMatrices(); assertNull(readPrevMatrices); - + // delete fs.delete(path, true); } catch (IOException e) {