You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mahout.apache.org by sm...@apache.org on 2015/08/08 20:19:04 UTC
[1/2] mahout git commit: MAHOUT-1675 Remove MultiLayer Perceptron
from codebase, this closes apache/mahout#156
Repository: mahout
Updated Branches:
refs/heads/master 20be890bc -> 002943be7
http://git-wip-us.apache.org/repos/asf/mahout/blob/002943be/mr/src/test/java/org/apache/mahout/classifier/mlp/RunMultilayerPerceptronTest.java
----------------------------------------------------------------------
diff --git a/mr/src/test/java/org/apache/mahout/classifier/mlp/RunMultilayerPerceptronTest.java b/mr/src/test/java/org/apache/mahout/classifier/mlp/RunMultilayerPerceptronTest.java
deleted file mode 100644
index 8e3f7dc..0000000
--- a/mr/src/test/java/org/apache/mahout/classifier/mlp/RunMultilayerPerceptronTest.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/**
- * 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.mahout.classifier.mlp;
-
-import java.io.File;
-
-import org.apache.mahout.common.MahoutTestCase;
-import org.junit.Test;
-
-@Deprecated
-public class RunMultilayerPerceptronTest extends MahoutTestCase {
-
- @Test
- public void runMultilayerPerceptron() throws Exception {
-
- // Train a model first
- String modelFileName = "mlp.model";
- File modelFile = getTestTempFile(modelFileName);
-
- File irisDataset = getTestTempFile("iris.csv");
- writeLines(irisDataset, Datasets.IRIS);
-
- String[] argsTrain = {
- "-i", irisDataset.getAbsolutePath(),
- "-sh",
- "-labels", "setosa", "versicolor", "virginica",
- "-mo", modelFile.getAbsolutePath(),
- "-u",
- "-ls", "4", "8", "3"
- };
-
- TrainMultilayerPerceptron.main(argsTrain);
-
- assertTrue(modelFile.exists());
-
- String outputFileName = "labelResult.txt";
- File outputFile = getTestTempFile(outputFileName);
-
- String[] argsLabeling = {
- "-i", irisDataset.getAbsolutePath(),
- "-sh",
- "-cr", "0", "3",
- "-mo", modelFile.getAbsolutePath(),
- "-o", outputFile.getAbsolutePath()
- };
-
- RunMultilayerPerceptron.main(argsLabeling);
-
- assertTrue(outputFile.exists());
- }
-
-}
http://git-wip-us.apache.org/repos/asf/mahout/blob/002943be/mr/src/test/java/org/apache/mahout/classifier/mlp/TestMultilayerPerceptron.java
----------------------------------------------------------------------
diff --git a/mr/src/test/java/org/apache/mahout/classifier/mlp/TestMultilayerPerceptron.java b/mr/src/test/java/org/apache/mahout/classifier/mlp/TestMultilayerPerceptron.java
deleted file mode 100644
index 74f7f1c..0000000
--- a/mr/src/test/java/org/apache/mahout/classifier/mlp/TestMultilayerPerceptron.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/**
- * 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.mahout.classifier.mlp;
-
-import java.io.File;
-import java.io.IOException;
-
-import org.apache.mahout.common.MahoutTestCase;
-import org.apache.mahout.math.Arrays;
-import org.apache.mahout.math.DenseVector;
-import org.apache.mahout.math.Vector;
-import org.junit.Test;
-
-/**
- * Test the functionality of {@link MultilayerPerceptron}
- */
-@Deprecated
-public class TestMultilayerPerceptron extends MahoutTestCase {
-
- @Test
- public void testMLP() throws IOException {
- testMLP("testMLPXORLocal", false, false, 8000);
- testMLP("testMLPXORLocalWithMomentum", true, false, 4000);
- testMLP("testMLPXORLocalWithRegularization", true, true, 2000);
- }
-
- private void testMLP(String modelFilename, boolean useMomentum,
- boolean useRegularization, int iterations) throws IOException {
- MultilayerPerceptron mlp = new MultilayerPerceptron();
- mlp.addLayer(2, false, "Sigmoid");
- mlp.addLayer(3, false, "Sigmoid");
- mlp.addLayer(1, true, "Sigmoid");
- mlp.setCostFunction("Minus_Squared").setLearningRate(0.2);
- if (useMomentum) {
- mlp.setMomentumWeight(0.6);
- }
-
- if (useRegularization) {
- mlp.setRegularizationWeight(0.01);
- }
-
- double[][] instances = { { 0, 1, 1 }, { 0, 0, 0 }, { 1, 0, 1 }, { 1, 1, 0 } };
- for (int i = 0; i < iterations; ++i) {
- for (double[] instance : instances) {
- Vector features = new DenseVector(Arrays.copyOf(instance, instance.length - 1));
- mlp.train((int) instance[2], features);
- }
- }
-
- for (double[] instance : instances) {
- Vector input = new DenseVector(instance).viewPart(0, instance.length - 1);
- // the expected output is the last element in array
- double actual = instance[2];
- double expected = mlp.getOutput(input).get(0);
- assertTrue(actual < 0.5 && expected < 0.5 || actual >= 0.5 && expected >= 0.5);
- }
-
- // write model into file and read out
- File modelFile = this.getTestTempFile(modelFilename);
- mlp.setModelPath(modelFile.getAbsolutePath());
- mlp.writeModelToFile();
- mlp.close();
-
- MultilayerPerceptron mlpCopy = new MultilayerPerceptron(modelFile.getAbsolutePath());
- // test on instances
- for (double[] instance : instances) {
- Vector input = new DenseVector(instance).viewPart(0, instance.length - 1);
- // the expected output is the last element in array
- double actual = instance[2];
- double expected = mlpCopy.getOutput(input).get(0);
- assertTrue(actual < 0.5 && expected < 0.5 || actual >= 0.5 && expected >= 0.5);
- }
- mlpCopy.close();
- }
-}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/mahout/blob/002943be/mr/src/test/java/org/apache/mahout/classifier/mlp/TestNeuralNetwork.java
----------------------------------------------------------------------
diff --git a/mr/src/test/java/org/apache/mahout/classifier/mlp/TestNeuralNetwork.java b/mr/src/test/java/org/apache/mahout/classifier/mlp/TestNeuralNetwork.java
deleted file mode 100644
index 8946be2..0000000
--- a/mr/src/test/java/org/apache/mahout/classifier/mlp/TestNeuralNetwork.java
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * 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.mahout.classifier.mlp;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-import org.apache.commons.csv.CSVUtils;
-import org.apache.mahout.classifier.mlp.NeuralNetwork.TrainingMethod;
-import org.apache.mahout.common.MahoutTestCase;
-import org.apache.mahout.math.DenseMatrix;
-import org.apache.mahout.math.DenseVector;
-import org.apache.mahout.math.Matrix;
-import org.apache.mahout.math.Vector;
-import org.junit.Test;
-
-import com.google.common.base.Charsets;
-import com.google.common.collect.Lists;
-import com.google.common.io.Files;
-
-/** Test the functionality of {@link NeuralNetwork}. */
-@Deprecated
-public class TestNeuralNetwork extends MahoutTestCase {
-
-
- @Test
- public void testReadWrite() throws IOException {
- NeuralNetwork ann = new MultilayerPerceptron();
- ann.addLayer(2, false, "Identity");
- ann.addLayer(5, false, "Identity");
- ann.addLayer(1, true, "Identity");
- ann.setCostFunction("Minus_Squared");
- double learningRate = 0.2;
- double momentumWeight = 0.5;
- double regularizationWeight = 0.05;
- ann.setLearningRate(learningRate)
- .setMomentumWeight(momentumWeight)
- .setRegularizationWeight(regularizationWeight);
-
- // Manually set weights
- Matrix[] matrices = new DenseMatrix[2];
- matrices[0] = new DenseMatrix(5, 3);
- matrices[0].assign(0.2);
- matrices[1] = new DenseMatrix(1, 6);
- matrices[1].assign(0.8);
- ann.setWeightMatrices(matrices);
-
- // Write to file
- String modelFilename = "testNeuralNetworkReadWrite";
- File tmpModelFile = this.getTestTempFile(modelFilename);
- ann.setModelPath(tmpModelFile.getAbsolutePath());
- ann.writeModelToFile();
-
- // Read from file
- NeuralNetwork annCopy = new MultilayerPerceptron(tmpModelFile.getAbsolutePath());
- assertEquals(annCopy.getClass().getSimpleName(), annCopy.getModelType());
- assertEquals(tmpModelFile.getAbsolutePath(), annCopy.getModelPath());
- assertEquals(learningRate, annCopy.getLearningRate(), EPSILON);
- assertEquals(momentumWeight, annCopy.getMomentumWeight(), EPSILON);
- assertEquals(regularizationWeight, annCopy.getRegularizationWeight(), EPSILON);
- assertEquals(TrainingMethod.GRADIENT_DESCENT, annCopy.getTrainingMethod());
-
- // Compare weights
- Matrix[] weightsMatrices = annCopy.getWeightMatrices();
- for (int i = 0; i < weightsMatrices.length; ++i) {
- Matrix expectMat = matrices[i];
- Matrix actualMat = weightsMatrices[i];
- for (int j = 0; j < expectMat.rowSize(); ++j) {
- for (int k = 0; k < expectMat.columnSize(); ++k) {
- assertEquals(expectMat.get(j, k), actualMat.get(j, k), EPSILON);
- }
- }
- }
- }
-
- /** Test the forward functionality. */
- @Test
- public void testOutput() {
- // First network
- NeuralNetwork ann = new MultilayerPerceptron();
- ann.addLayer(2, false, "Identity");
- ann.addLayer(5, false, "Identity");
- ann.addLayer(1, true, "Identity");
- ann.setCostFunction("Minus_Squared").setLearningRate(0.1);
-
- // Intentionally initialize all weights to 0.5
- Matrix[] matrices = new Matrix[2];
- matrices[0] = new DenseMatrix(5, 3);
- matrices[0].assign(0.5);
- matrices[1] = new DenseMatrix(1, 6);
- matrices[1].assign(0.5);
- ann.setWeightMatrices(matrices);
-
- double[] arr = new double[] { 0, 1 };
- Vector training = new DenseVector(arr);
- Vector result = ann.getOutput(training);
- assertEquals(1, result.size());
-
- // Second network
- NeuralNetwork ann2 = new MultilayerPerceptron();
- ann2.addLayer(2, false, "Sigmoid");
- ann2.addLayer(3, false, "Sigmoid");
- ann2.addLayer(1, true, "Sigmoid");
- ann2.setCostFunction("Minus_Squared");
- ann2.setLearningRate(0.3);
-
- // Intentionally initialize all weights to 0.5
- Matrix[] matrices2 = new Matrix[2];
- matrices2[0] = new DenseMatrix(3, 3);
- matrices2[0].assign(0.5);
- matrices2[1] = new DenseMatrix(1, 4);
- matrices2[1].assign(0.5);
- ann2.setWeightMatrices(matrices2);
-
- double[] test = { 0, 0 };
- double[] result2 = { 0.807476 };
-
- Vector vec = ann2.getOutput(new DenseVector(test));
- double[] arrVec = new double[vec.size()];
- for (int i = 0; i < arrVec.length; ++i) {
- arrVec[i] = vec.getQuick(i);
- }
- assertArrayEquals(result2, arrVec, EPSILON);
-
- NeuralNetwork ann3 = new MultilayerPerceptron();
- ann3.addLayer(2, false, "Sigmoid");
- ann3.addLayer(3, false, "Sigmoid");
- ann3.addLayer(1, true, "Sigmoid");
- ann3.setCostFunction("Minus_Squared").setLearningRate(0.3);
-
- // Intentionally initialize all weights to 0.5
- Matrix[] initMatrices = new Matrix[2];
- initMatrices[0] = new DenseMatrix(3, 3);
- initMatrices[0].assign(0.5);
- initMatrices[1] = new DenseMatrix(1, 4);
- initMatrices[1].assign(0.5);
- ann3.setWeightMatrices(initMatrices);
-
- double[] instance = {0, 1};
- Vector output = ann3.getOutput(new DenseVector(instance));
- assertEquals(0.8315410, output.get(0), EPSILON);
- }
-
- @Test
- public void testNeuralNetwork() throws IOException {
- testNeuralNetwork("testNeuralNetworkXORLocal", false, false, 10000);
- testNeuralNetwork("testNeuralNetworkXORWithMomentum", true, false, 5000);
- testNeuralNetwork("testNeuralNetworkXORWithRegularization", true, true, 5000);
- }
-
- private void testNeuralNetwork(String modelFilename, boolean useMomentum,
- boolean useRegularization, int iterations) throws IOException {
- NeuralNetwork ann = new MultilayerPerceptron();
- ann.addLayer(2, false, "Sigmoid");
- ann.addLayer(3, false, "Sigmoid");
- ann.addLayer(1, true, "Sigmoid");
- ann.setCostFunction("Minus_Squared").setLearningRate(0.1);
-
- if (useMomentum) {
- ann.setMomentumWeight(0.6);
- }
-
- if (useRegularization) {
- ann.setRegularizationWeight(0.01);
- }
-
- double[][] instances = { { 0, 1, 1 }, { 0, 0, 0 }, { 1, 0, 1 }, { 1, 1, 0 } };
- for (int i = 0; i < iterations; ++i) {
- for (double[] instance : instances) {
- ann.trainOnline(new DenseVector(instance));
- }
- }
-
- for (double[] instance : instances) {
- Vector input = new DenseVector(instance).viewPart(0, instance.length - 1);
- // The expected output is the last element in array
- double actual = instance[2];
- double expected = ann.getOutput(input).get(0);
- assertTrue(actual < 0.5 && expected < 0.5 || actual >= 0.5 && expected >= 0.5);
- }
-
- // Write model into file and read out
- File tmpModelFile = this.getTestTempFile(modelFilename);
- ann.setModelPath(tmpModelFile.getAbsolutePath());
- ann.writeModelToFile();
-
- NeuralNetwork annCopy = new MultilayerPerceptron(tmpModelFile.getAbsolutePath());
- // Test on instances
- for (double[] instance : instances) {
- Vector input = new DenseVector(instance).viewPart(0, instance.length - 1);
- // The expected output is the last element in array
- double actual = instance[2];
- double expected = annCopy.getOutput(input).get(0);
- assertTrue(actual < 0.5 && expected < 0.5 || actual >= 0.5 && expected >= 0.5);
- }
- }
-
- @Test
- public void testWithCancerDataSet() throws IOException {
-
- File cancerDataset = getTestTempFile("cancer.csv");
- writeLines(cancerDataset, Datasets.CANCER);
-
- List<Vector> records = Lists.newArrayList();
- // Returns a mutable list of the data
- List<String> cancerDataSetList = Files.readLines(cancerDataset, Charsets.UTF_8);
- // Skip the header line, hence remove the first element in the list
- cancerDataSetList.remove(0);
- for (String line : cancerDataSetList) {
- String[] tokens = CSVUtils.parseLine(line);
- double[] values = new double[tokens.length];
- for (int i = 0; i < tokens.length; ++i) {
- values[i] = Double.parseDouble(tokens[i]);
- }
- records.add(new DenseVector(values));
- }
-
- int splitPoint = (int) (records.size() * 0.8);
- List<Vector> trainingSet = records.subList(0, splitPoint);
- List<Vector> testSet = records.subList(splitPoint, records.size());
-
- // initialize neural network model
- NeuralNetwork ann = new MultilayerPerceptron();
- int featureDimension = records.get(0).size() - 1;
- ann.addLayer(featureDimension, false, "Sigmoid");
- ann.addLayer(featureDimension * 2, false, "Sigmoid");
- ann.addLayer(1, true, "Sigmoid");
- ann.setLearningRate(0.05).setMomentumWeight(0.5).setRegularizationWeight(0.001);
-
- int iteration = 2000;
- for (int i = 0; i < iteration; ++i) {
- for (Vector trainingInstance : trainingSet) {
- ann.trainOnline(trainingInstance);
- }
- }
-
- int correctInstances = 0;
- for (Vector testInstance : testSet) {
- Vector res = ann.getOutput(testInstance.viewPart(0, testInstance.size() - 1));
- double actual = res.get(0);
- double expected = testInstance.get(testInstance.size() - 1);
- if (Math.abs(actual - expected) <= 0.1) {
- ++correctInstances;
- }
- }
- double accuracy = (double) correctInstances / testSet.size() * 100;
- assertTrue("The classifier is even worse than a random guesser!", accuracy > 50);
- System.out.printf("Cancer DataSet. Classification precision: %d/%d = %f%%\n", correctInstances, testSet.size(), accuracy);
- }
-
- @Test
- public void testWithIrisDataSet() throws IOException {
-
- File irisDataset = getTestTempFile("iris.csv");
- writeLines(irisDataset, Datasets.IRIS);
-
- int numOfClasses = 3;
- List<Vector> records = Lists.newArrayList();
- // Returns a mutable list of the data
- List<String> irisDataSetList = Files.readLines(irisDataset, Charsets.UTF_8);
- // Skip the header line, hence remove the first element in the list
- irisDataSetList.remove(0);
-
- for (String line : irisDataSetList) {
- String[] tokens = CSVUtils.parseLine(line);
- // Last three dimensions represent the labels
- double[] values = new double[tokens.length + numOfClasses - 1];
- Arrays.fill(values, 0.0);
- for (int i = 0; i < tokens.length - 1; ++i) {
- values[i] = Double.parseDouble(tokens[i]);
- }
- // Add label values
- String label = tokens[tokens.length - 1];
- if (label.equalsIgnoreCase("setosa")) {
- values[values.length - 3] = 1;
- } else if (label.equalsIgnoreCase("versicolor")) {
- values[values.length - 2] = 1;
- } else { // label 'virginica'
- values[values.length - 1] = 1;
- }
- records.add(new DenseVector(values));
- }
-
- Collections.shuffle(records);
-
- int splitPoint = (int) (records.size() * 0.8);
- List<Vector> trainingSet = records.subList(0, splitPoint);
- List<Vector> testSet = records.subList(splitPoint, records.size());
-
- // Initialize neural network model
- NeuralNetwork ann = new MultilayerPerceptron();
- int featureDimension = records.get(0).size() - numOfClasses;
- ann.addLayer(featureDimension, false, "Sigmoid");
- ann.addLayer(featureDimension * 2, false, "Sigmoid");
- ann.addLayer(3, true, "Sigmoid"); // 3-class classification
- ann.setLearningRate(0.05).setMomentumWeight(0.4).setRegularizationWeight(0.005);
-
- int iteration = 2000;
- for (int i = 0; i < iteration; ++i) {
- for (Vector trainingInstance : trainingSet) {
- ann.trainOnline(trainingInstance);
- }
- }
-
- int correctInstances = 0;
- for (Vector testInstance : testSet) {
- Vector res = ann.getOutput(testInstance.viewPart(0, testInstance.size() - numOfClasses));
- double[] actualLabels = new double[numOfClasses];
- for (int i = 0; i < numOfClasses; ++i) {
- actualLabels[i] = res.get(i);
- }
- double[] expectedLabels = new double[numOfClasses];
- for (int i = 0; i < numOfClasses; ++i) {
- expectedLabels[i] = testInstance.get(testInstance.size() - numOfClasses + i);
- }
-
- boolean allCorrect = true;
- for (int i = 0; i < numOfClasses; ++i) {
- if (Math.abs(expectedLabels[i] - actualLabels[i]) >= 0.1) {
- allCorrect = false;
- break;
- }
- }
- if (allCorrect) {
- ++correctInstances;
- }
- }
-
- double accuracy = (double) correctInstances / testSet.size() * 100;
- assertTrue("The model is even worse than a random guesser.", accuracy > 50);
-
- System.out.printf("Iris DataSet. Classification precision: %d/%d = %f%%\n",
- correctInstances, testSet.size(), accuracy);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/mahout/blob/002943be/mr/src/test/java/org/apache/mahout/classifier/mlp/TrainMultilayerPerceptronTest.java
----------------------------------------------------------------------
diff --git a/mr/src/test/java/org/apache/mahout/classifier/mlp/TrainMultilayerPerceptronTest.java b/mr/src/test/java/org/apache/mahout/classifier/mlp/TrainMultilayerPerceptronTest.java
deleted file mode 100644
index bd783f1..0000000
--- a/mr/src/test/java/org/apache/mahout/classifier/mlp/TrainMultilayerPerceptronTest.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/**
- * 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.mahout.classifier.mlp;
-
-import java.io.File;
-
-import org.apache.mahout.common.MahoutTestCase;
-import org.junit.Test;
-
-@Deprecated
-public class TrainMultilayerPerceptronTest extends MahoutTestCase {
-
- @Test
- public void testIrisDataset() throws Exception {
- String modelFileName = "mlp.model";
- File modelFile = getTestTempFile(modelFileName);
-
- File irisDataset = getTestTempFile("iris.csv");
- writeLines(irisDataset, Datasets.IRIS);
-
- String[] args = {
- "-i", irisDataset.getAbsolutePath(),
- "-sh",
- "-labels", "setosa", "versicolor", "virginica",
- "-mo", modelFile.getAbsolutePath(),
- "-u",
- "-ls", "4", "8", "3"
- };
-
- TrainMultilayerPerceptron.main(args);
-
- assertTrue(modelFile.exists());
- }
-
- @Test
- public void initializeModelWithDifferentParameters() throws Exception {
- String modelFileName = "mlp.model";
- File modelFile1 = getTestTempFile(modelFileName);
-
- File irisDataset = getTestTempFile("iris.csv");
- writeLines(irisDataset, Datasets.IRIS);
-
- String[] args1 = {
- "-i", irisDataset.getAbsolutePath(),
- "-sh",
- "-labels", "setosa", "versicolor", "virginica",
- "-mo", modelFile1.getAbsolutePath(),
- "-u",
- "-ls", "4", "8", "3",
- "-l", "0.2", "-m", "0.35", "-r", "0.0001"
- };
-
- MultilayerPerceptron mlp1 = trainModel(args1, modelFile1);
- assertEquals(0.2, mlp1.getLearningRate(), EPSILON);
- assertEquals(0.35, mlp1.getMomentumWeight(), EPSILON);
- assertEquals(0.0001, mlp1.getRegularizationWeight(), EPSILON);
-
- assertEquals(4, mlp1.getLayerSize(0) - 1);
- assertEquals(8, mlp1.getLayerSize(1) - 1);
- assertEquals(3, mlp1.getLayerSize(2)); // Final layer has no bias neuron
-
- // MLP with default learning rate, momemtum weight, and regularization weight
- File modelFile2 = this.getTestTempFile(modelFileName);
-
- String[] args2 = {
- "-i", irisDataset.getAbsolutePath(),
- "-sh",
- "-labels", "setosa", "versicolor", "virginica",
- "-mo", modelFile2.getAbsolutePath(),
- "-ls", "4", "10", "18", "3"
- };
-
- MultilayerPerceptron mlp2 = trainModel(args2, modelFile2);
- assertEquals(0.5, mlp2.getLearningRate(), EPSILON);
- assertEquals(0.1, mlp2.getMomentumWeight(), EPSILON);
- assertEquals(0, mlp2.getRegularizationWeight(), EPSILON);
-
- assertEquals(4, mlp2.getLayerSize(0) - 1);
- assertEquals(10, mlp2.getLayerSize(1) - 1);
- assertEquals(18, mlp2.getLayerSize(2) - 1);
- assertEquals(3, mlp2.getLayerSize(3)); // Final layer has no bias neuron
-
- }
-
- private MultilayerPerceptron trainModel(String[] args, File modelFile) throws Exception {
- TrainMultilayerPerceptron.main(args);
- return new MultilayerPerceptron(modelFile.getAbsolutePath());
- }
-
-}
[2/2] mahout git commit: MAHOUT-1675 Remove MultiLayer Perceptron
from codebase, this closes apache/mahout#156
Posted by sm...@apache.org.
MAHOUT-1675 Remove MultiLayer Perceptron from codebase, this closes apache/mahout#156
Project: http://git-wip-us.apache.org/repos/asf/mahout/repo
Commit: http://git-wip-us.apache.org/repos/asf/mahout/commit/002943be
Tree: http://git-wip-us.apache.org/repos/asf/mahout/tree/002943be
Diff: http://git-wip-us.apache.org/repos/asf/mahout/diff/002943be
Branch: refs/heads/master
Commit: 002943be77e9da8e7d6c0d41e55fffe8bf4ea817
Parents: 20be890
Author: smarthi <sm...@apache.org>
Authored: Sat Aug 8 14:15:56 2015 -0400
Committer: smarthi <sm...@apache.org>
Committed: Sat Aug 8 14:18:49 2015 -0400
----------------------------------------------------------------------
CHANGELOG | 2 +
.../classifier/mlp/MultilayerPerceptron.java | 93 --
.../mahout/classifier/mlp/NeuralNetwork.java | 735 ----------------
.../classifier/mlp/NeuralNetworkFunctions.java | 152 ----
.../classifier/mlp/RunMultilayerPerceptron.java | 220 -----
.../mlp/TrainMultilayerPerceptron.java | 314 -------
.../apache/mahout/classifier/mlp/Datasets.java | 866 -------------------
.../mlp/RunMultilayerPerceptronTest.java | 67 --
.../mlp/TestMultilayerPerceptron.java | 89 --
.../classifier/mlp/TestNeuralNetwork.java | 354 --------
.../mlp/TrainMultilayerPerceptronTest.java | 106 ---
11 files changed, 2 insertions(+), 2996 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mahout/blob/002943be/CHANGELOG
----------------------------------------------------------------------
diff --git a/CHANGELOG b/CHANGELOG
index 0688129..624c94b 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -2,6 +2,8 @@ Mahout Change Log
Release 0.11.1 - unreleased
+ MAHOUT-1675: Remove MLP from codebase (ZJaffe via smarthi)
+
Release 0.11.0 - 2015-08-07
MAHOUT-1744: Deprecate lucene2seq (apalumbo)
http://git-wip-us.apache.org/repos/asf/mahout/blob/002943be/mr/src/main/java/org/apache/mahout/classifier/mlp/MultilayerPerceptron.java
----------------------------------------------------------------------
diff --git a/mr/src/main/java/org/apache/mahout/classifier/mlp/MultilayerPerceptron.java b/mr/src/main/java/org/apache/mahout/classifier/mlp/MultilayerPerceptron.java
deleted file mode 100644
index aaf76bd..0000000
--- a/mr/src/main/java/org/apache/mahout/classifier/mlp/MultilayerPerceptron.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/**
- * 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.mahout.classifier.mlp;
-
-import org.apache.mahout.classifier.OnlineLearner;
-import org.apache.mahout.math.DenseVector;
-import org.apache.mahout.math.Vector;
-
-import java.io.IOException;
-
-/**
- * A Multilayer Perceptron (MLP) is a kind of feed-forward artificial neural
- * network, which is a mathematical model inspired by the biological neural
- * network. The Multilayer Perceptron can be used for various machine learning
- * tasks such as classification and regression.
- *
- * A detailed introduction about MLP can be found at
- * http://ufldl.stanford.edu/wiki/index.php/Neural_Networks.
- *
- * For this particular implementation, the users can freely control the topology
- * of the MLP, including: 1. The size of the input layer; 2. The number of
- * hidden layers; 3. The size of each hidden layer; 4. The size of the output
- * layer. 5. The cost function. 6. The squashing function.
- *
- * The model is trained in an online learning approach, where the weights of
- * neurons in the MLP is updated incremented using backPropagation algorithm
- * proposed by (Rumelhart, D. E., Hinton, G. E., and Williams, R. J. (1986)
- * Learning representations by back-propagating errors. Nature, 323, 533--536.)
- *
- * @deprecated as of as of 0.10.0.
- */
-@Deprecated
-public class MultilayerPerceptron extends NeuralNetwork implements OnlineLearner {
-
- /**
- * The default constructor.
- */
- public MultilayerPerceptron() {
- super();
- }
-
- /**
- * Initialize the MLP by specifying the location of the model.
- *
- * @param modelPath The path of the model.
- */
- public MultilayerPerceptron(String modelPath) throws IOException {
- super(modelPath);
- }
-
- @Override
- public void train(int actual, Vector instance) {
- // construct the training instance, where append the actual to instance
- Vector trainingInstance = new DenseVector(instance.size() + 1);
- for (int i = 0; i < instance.size(); ++i) {
- trainingInstance.setQuick(i, instance.getQuick(i));
- }
- trainingInstance.setQuick(instance.size(), actual);
- this.trainOnline(trainingInstance);
- }
-
- @Override
- public void train(long trackingKey, String groupKey, int actual,
- Vector instance) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void train(long trackingKey, int actual, Vector instance) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void close() {
- // DO NOTHING
- }
-
-}
http://git-wip-us.apache.org/repos/asf/mahout/blob/002943be/mr/src/main/java/org/apache/mahout/classifier/mlp/NeuralNetwork.java
----------------------------------------------------------------------
diff --git a/mr/src/main/java/org/apache/mahout/classifier/mlp/NeuralNetwork.java b/mr/src/main/java/org/apache/mahout/classifier/mlp/NeuralNetwork.java
deleted file mode 100644
index f4e765c..0000000
--- a/mr/src/main/java/org/apache/mahout/classifier/mlp/NeuralNetwork.java
+++ /dev/null
@@ -1,735 +0,0 @@
-/*
- * 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.mahout.classifier.mlp;
-
-import java.io.DataInput;
-import java.io.DataOutput;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-import com.google.common.base.Preconditions;
-import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.fs.FSDataInputStream;
-import org.apache.hadoop.fs.FSDataOutputStream;
-import org.apache.hadoop.fs.FileSystem;
-import org.apache.hadoop.fs.Path;
-import org.apache.hadoop.io.WritableUtils;
-import org.apache.mahout.common.RandomUtils;
-import org.apache.mahout.common.RandomWrapper;
-import org.apache.mahout.math.DenseMatrix;
-import org.apache.mahout.math.DenseVector;
-import org.apache.mahout.math.Matrix;
-import org.apache.mahout.math.MatrixWritable;
-import org.apache.mahout.math.Vector;
-import org.apache.mahout.math.function.DoubleDoubleFunction;
-import org.apache.mahout.math.function.DoubleFunction;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * AbstractNeuralNetwork defines the general operations for a neural network
- * based model. Typically, all derivative models such as Multilayer Perceptron
- * and Autoencoder consist of neurons and the weights between neurons.
- * @deprecated as of as of 0.10.0.
- */
-@Deprecated
-public abstract class NeuralNetwork {
-
- private static final Logger log = LoggerFactory.getLogger(NeuralNetwork.class);
-
- /* The default learning rate */
- public static final double DEFAULT_LEARNING_RATE = 0.5;
- /* The default regularization weight */
- public static final double DEFAULT_REGULARIZATION_WEIGHT = 0;
- /* The default momentum weight */
- public static final double DEFAULT_MOMENTUM_WEIGHT = 0.1;
-
- public enum TrainingMethod { GRADIENT_DESCENT }
-
- /* The name of the model */
- protected String modelType;
-
- /* The path to store the model */
- protected String modelPath;
-
- protected double learningRate;
-
- /* The weight of regularization */
- protected double regularizationWeight;
-
- /* The momentum weight */
- protected double momentumWeight;
-
- /* The cost function of the model */
- protected String costFunctionName;
-
- /* Record the size of each layer */
- protected List<Integer> layerSizeList;
-
- /* Training method used for training the model */
- protected TrainingMethod trainingMethod;
-
- /* Weights between neurons at adjacent layers */
- protected List<Matrix> weightMatrixList;
-
- /* Previous weight updates between neurons at adjacent layers */
- protected List<Matrix> prevWeightUpdatesList;
-
- /* Different layers can have different squashing function */
- protected List<String> squashingFunctionList;
-
- /* The index of the final layer */
- protected int finalLayerIndex;
-
- /**
- * The default constructor that initializes the learning rate, regularization
- * weight, and momentum weight by default.
- */
- public NeuralNetwork() {
- log.info("Initialize model...");
- learningRate = DEFAULT_LEARNING_RATE;
- regularizationWeight = DEFAULT_REGULARIZATION_WEIGHT;
- momentumWeight = DEFAULT_MOMENTUM_WEIGHT;
- trainingMethod = TrainingMethod.GRADIENT_DESCENT;
- costFunctionName = "Minus_Squared";
- modelType = getClass().getSimpleName();
-
- layerSizeList = new ArrayList<>();
- layerSizeList = new ArrayList<>();
- weightMatrixList = new ArrayList<>();
- prevWeightUpdatesList = new ArrayList<>();
- squashingFunctionList = new ArrayList<>();
- }
-
- /**
- * Initialize the NeuralNetwork by specifying learning rate, momentum weight
- * and regularization weight.
- *
- * @param learningRate The learning rate.
- * @param momentumWeight The momentum weight.
- * @param regularizationWeight The regularization weight.
- */
- public NeuralNetwork(double learningRate, double momentumWeight, double regularizationWeight) {
- this();
- setLearningRate(learningRate);
- setMomentumWeight(momentumWeight);
- setRegularizationWeight(regularizationWeight);
- }
-
- /**
- * Initialize the NeuralNetwork by specifying the location of the model.
- *
- * @param modelPath The location that the model is stored.
- */
- public NeuralNetwork(String modelPath) throws IOException {
- this.modelPath = modelPath;
- readFromModel();
- }
-
- /**
- * Get the type of the model.
- *
- * @return The name of the model.
- */
- public String getModelType() {
- return this.modelType;
- }
-
- /**
- * Set the degree of aggression during model training, a large learning rate
- * can increase the training speed, but it also decreases the chance of model
- * converge.
- *
- * @param learningRate Learning rate must be a non-negative value. Recommend in range (0, 0.5).
- * @return The model instance.
- */
- public final NeuralNetwork setLearningRate(double learningRate) {
- Preconditions.checkArgument(learningRate > 0, "Learning rate must be larger than 0.");
- this.learningRate = learningRate;
- return this;
- }
-
- /**
- * Get the value of learning rate.
- *
- * @return The value of learning rate.
- */
- public double getLearningRate() {
- return learningRate;
- }
-
- /**
- * Set the regularization weight. More complex the model is, less weight the
- * regularization is.
- *
- * @param regularizationWeight regularization must be in the range [0, 0.1).
- * @return The model instance.
- */
- public final NeuralNetwork setRegularizationWeight(double regularizationWeight) {
- Preconditions.checkArgument(regularizationWeight >= 0
- && regularizationWeight < 0.1, "Regularization weight must be in range [0, 0.1)");
- this.regularizationWeight = regularizationWeight;
- return this;
- }
-
- /**
- * Get the weight of the regularization.
- *
- * @return The weight of regularization.
- */
- public double getRegularizationWeight() {
- return regularizationWeight;
- }
-
- /**
- * Set the momentum weight for the model.
- *
- * @param momentumWeight momentumWeight must be in range [0, 0.5].
- * @return The model instance.
- */
- public final NeuralNetwork setMomentumWeight(double momentumWeight) {
- Preconditions.checkArgument(momentumWeight >= 0 && momentumWeight <= 1.0,
- "Momentum weight must be in range [0, 1.0]");
- this.momentumWeight = momentumWeight;
- return this;
- }
-
- /**
- * Get the momentum weight.
- *
- * @return The value of momentum.
- */
- public double getMomentumWeight() {
- return momentumWeight;
- }
-
- /**
- * Set the training method.
- *
- * @param method The training method, currently supports GRADIENT_DESCENT.
- * @return The instance of the model.
- */
- public NeuralNetwork setTrainingMethod(TrainingMethod method) {
- this.trainingMethod = method;
- return this;
- }
-
- /**
- * Get the training method.
- *
- * @return The training method enumeration.
- */
- public TrainingMethod getTrainingMethod() {
- return trainingMethod;
- }
-
- /**
- * Set the cost function for the model.
- *
- * @param costFunction the name of the cost function. Currently supports
- * "Minus_Squared", "Cross_Entropy".
- */
- public NeuralNetwork setCostFunction(String costFunction) {
- this.costFunctionName = costFunction;
- return this;
- }
-
- /**
- * Add a layer of neurons with specified size. If the added layer is not the
- * first layer, it will automatically connect the neurons between with the
- * previous layer.
- *
- * @param size The size of the layer. (bias neuron excluded)
- * @param isFinalLayer If false, add a bias neuron.
- * @param squashingFunctionName The squashing function for this layer, input
- * layer is f(x) = x by default.
- * @return The layer index, starts with 0.
- */
- public int addLayer(int size, boolean isFinalLayer, String squashingFunctionName) {
- Preconditions.checkArgument(size > 0, "Size of layer must be larger than 0.");
- log.info("Add layer with size {} and squashing function {}", size, squashingFunctionName);
- int actualSize = size;
- if (!isFinalLayer) {
- actualSize += 1;
- }
-
- layerSizeList.add(actualSize);
- int layerIndex = layerSizeList.size() - 1;
- if (isFinalLayer) {
- finalLayerIndex = layerIndex;
- }
-
- // Add weights between current layer and previous layer, and input layer has no squashing function
- if (layerIndex > 0) {
- int sizePrevLayer = layerSizeList.get(layerIndex - 1);
- // Row count equals to size of current size and column count equal to size of previous layer
- int row = isFinalLayer ? actualSize : actualSize - 1;
- Matrix weightMatrix = new DenseMatrix(row, sizePrevLayer);
- // Initialize weights
- final RandomWrapper rnd = RandomUtils.getRandom();
- weightMatrix.assign(new DoubleFunction() {
- @Override
- public double apply(double value) {
- return rnd.nextDouble() - 0.5;
- }
- });
- weightMatrixList.add(weightMatrix);
- prevWeightUpdatesList.add(new DenseMatrix(row, sizePrevLayer));
- squashingFunctionList.add(squashingFunctionName);
- }
- return layerIndex;
- }
-
- /**
- * Get the size of a particular layer.
- *
- * @param layer The index of the layer, starting from 0.
- * @return The size of the corresponding layer.
- */
- public int getLayerSize(int layer) {
- Preconditions.checkArgument(layer >= 0 && layer < this.layerSizeList.size(),
- String.format("Input must be in range [0, %d]\n", this.layerSizeList.size() - 1));
- return layerSizeList.get(layer);
- }
-
- /**
- * Get the layer size list.
- *
- * @return The sizes of the layers.
- */
- protected List<Integer> getLayerSizeList() {
- return layerSizeList;
- }
-
- /**
- * Get the weights between layer layerIndex and layerIndex + 1
- *
- * @param layerIndex The index of the layer.
- * @return The weights in form of {@link Matrix}.
- */
- public Matrix getWeightsByLayer(int layerIndex) {
- return weightMatrixList.get(layerIndex);
- }
-
- /**
- * Update the weight matrices with given matrices.
- *
- * @param matrices The weight matrices, must be the same dimension as the
- * existing matrices.
- */
- public void updateWeightMatrices(Matrix[] matrices) {
- for (int i = 0; i < matrices.length; ++i) {
- Matrix matrix = weightMatrixList.get(i);
- weightMatrixList.set(i, matrix.plus(matrices[i]));
- }
- }
-
- /**
- * Set the weight matrices.
- *
- * @param matrices The weight matrices, must be the same dimension of the
- * existing matrices.
- */
- public void setWeightMatrices(Matrix[] matrices) {
- weightMatrixList = new ArrayList<>();
- Collections.addAll(weightMatrixList, matrices);
- }
-
- /**
- * Set the weight matrix for a specified layer.
- *
- * @param index The index of the matrix, starting from 0 (between layer 0 and 1).
- * @param matrix The instance of {@link Matrix}.
- */
- public void setWeightMatrix(int index, Matrix matrix) {
- Preconditions.checkArgument(0 <= index && index < weightMatrixList.size(),
- String.format("index [%s] should be in range [%s, %s).", index, 0, weightMatrixList.size()));
- weightMatrixList.set(index, matrix);
- }
-
- /**
- * Get all the weight matrices.
- *
- * @return The weight matrices.
- */
- public Matrix[] getWeightMatrices() {
- Matrix[] matrices = new Matrix[weightMatrixList.size()];
- weightMatrixList.toArray(matrices);
- return matrices;
- }
-
- /**
- * Get the output calculated by the model.
- *
- * @param instance The feature instance in form of {@link Vector}, each dimension contains the value of the corresponding feature.
- * @return The output vector.
- */
- public Vector getOutput(Vector instance) {
- Preconditions.checkArgument(layerSizeList.get(0) == instance.size() + 1,
- String.format("The dimension of input instance should be %d, but the input has dimension %d.",
- layerSizeList.get(0) - 1, instance.size()));
-
- // add bias feature
- Vector instanceWithBias = new DenseVector(instance.size() + 1);
- // set bias to be a little bit less than 1.0
- instanceWithBias.set(0, 0.99999);
- for (int i = 1; i < instanceWithBias.size(); ++i) {
- instanceWithBias.set(i, instance.get(i - 1));
- }
-
- List<Vector> outputCache = getOutputInternal(instanceWithBias);
- // return the output of the last layer
- Vector result = outputCache.get(outputCache.size() - 1);
- // remove bias
- return result.viewPart(1, result.size() - 1);
- }
-
- /**
- * Calculate output internally, the intermediate output of each layer will be
- * stored.
- *
- * @param instance The feature instance in form of {@link Vector}, each dimension contains the value of the corresponding feature.
- * @return Cached output of each layer.
- */
- protected List<Vector> getOutputInternal(Vector instance) {
- List<Vector> outputCache = new ArrayList<>();
- // fill with instance
- Vector intermediateOutput = instance;
- outputCache.add(intermediateOutput);
-
- for (int i = 0; i < layerSizeList.size() - 1; ++i) {
- intermediateOutput = forward(i, intermediateOutput);
- outputCache.add(intermediateOutput);
- }
- return outputCache;
- }
-
- /**
- * Forward the calculation for one layer.
- *
- * @param fromLayer The index of the previous layer.
- * @param intermediateOutput The intermediate output of previous layer.
- * @return The intermediate results of the current layer.
- */
- protected Vector forward(int fromLayer, Vector intermediateOutput) {
- Matrix weightMatrix = weightMatrixList.get(fromLayer);
-
- Vector vec = weightMatrix.times(intermediateOutput);
- vec = vec.assign(NeuralNetworkFunctions.getDoubleFunction(squashingFunctionList.get(fromLayer)));
-
- // add bias
- Vector vecWithBias = new DenseVector(vec.size() + 1);
- vecWithBias.set(0, 1);
- for (int i = 0; i < vec.size(); ++i) {
- vecWithBias.set(i + 1, vec.get(i));
- }
- return vecWithBias;
- }
-
- /**
- * Train the neural network incrementally with given training instance.
- *
- * @param trainingInstance An training instance, including the features and the label(s). Its dimension must equals
- * to the size of the input layer (bias neuron excluded) + the size
- * of the output layer (a.k.a. the dimension of the labels).
- */
- public void trainOnline(Vector trainingInstance) {
- Matrix[] matrices = trainByInstance(trainingInstance);
- updateWeightMatrices(matrices);
- }
-
- /**
- * Get the updated weights using one training instance.
- *
- * @param trainingInstance An training instance, including the features and the label(s). Its dimension must equals
- * to the size of the input layer (bias neuron excluded) + the size
- * of the output layer (a.k.a. the dimension of the labels).
- * @return The update of each weight, in form of {@link Matrix} list.
- */
- public Matrix[] trainByInstance(Vector trainingInstance) {
- // validate training instance
- int inputDimension = layerSizeList.get(0) - 1;
- int outputDimension = layerSizeList.get(this.layerSizeList.size() - 1);
- Preconditions.checkArgument(inputDimension + outputDimension == trainingInstance.size(),
- String.format("The dimension of training instance is %d, but requires %d.", trainingInstance.size(),
- inputDimension + outputDimension));
-
- if (trainingMethod.equals(TrainingMethod.GRADIENT_DESCENT)) {
- return trainByInstanceGradientDescent(trainingInstance);
- }
- throw new IllegalArgumentException("Training method is not supported.");
- }
-
- /**
- * Train by gradient descent. Get the updated weights using one training
- * instance.
- *
- * @param trainingInstance An training instance, including the features and the label(s). Its dimension must equals
- * to the size of the input layer (bias neuron excluded) + the size
- * of the output layer (a.k.a. the dimension of the labels).
- * @return The weight update matrices.
- */
- private Matrix[] trainByInstanceGradientDescent(Vector trainingInstance) {
- int inputDimension = layerSizeList.get(0) - 1;
-
- Vector inputInstance = new DenseVector(layerSizeList.get(0));
- inputInstance.set(0, 1); // add bias
- for (int i = 0; i < inputDimension; ++i) {
- inputInstance.set(i + 1, trainingInstance.get(i));
- }
-
- Vector labels =
- trainingInstance.viewPart(inputInstance.size() - 1, trainingInstance.size() - inputInstance.size() + 1);
-
- // initialize weight update matrices
- Matrix[] weightUpdateMatrices = new Matrix[weightMatrixList.size()];
- for (int m = 0; m < weightUpdateMatrices.length; ++m) {
- weightUpdateMatrices[m] =
- new DenseMatrix(weightMatrixList.get(m).rowSize(), weightMatrixList.get(m).columnSize());
- }
-
- List<Vector> internalResults = getOutputInternal(inputInstance);
-
- Vector deltaVec = new DenseVector(layerSizeList.get(layerSizeList.size() - 1));
- Vector output = internalResults.get(internalResults.size() - 1);
-
- final DoubleFunction derivativeSquashingFunction =
- NeuralNetworkFunctions.getDerivativeDoubleFunction(squashingFunctionList.get(squashingFunctionList.size() - 1));
-
- final DoubleDoubleFunction costFunction =
- NeuralNetworkFunctions.getDerivativeDoubleDoubleFunction(costFunctionName);
-
- Matrix lastWeightMatrix = weightMatrixList.get(weightMatrixList.size() - 1);
-
- for (int i = 0; i < deltaVec.size(); ++i) {
- double costFuncDerivative = costFunction.apply(labels.get(i), output.get(i + 1));
- // Add regularization
- costFuncDerivative += regularizationWeight * lastWeightMatrix.viewRow(i).zSum();
- deltaVec.set(i, costFuncDerivative);
- deltaVec.set(i, deltaVec.get(i) * derivativeSquashingFunction.apply(output.get(i + 1)));
- }
-
- // Start from previous layer of output layer
- for (int layer = layerSizeList.size() - 2; layer >= 0; --layer) {
- deltaVec = backPropagate(layer, deltaVec, internalResults, weightUpdateMatrices[layer]);
- }
-
- prevWeightUpdatesList = Arrays.asList(weightUpdateMatrices);
-
- return weightUpdateMatrices;
- }
-
- /**
- * Back-propagate the errors to from next layer to current layer. The weight
- * updated information will be stored in the weightUpdateMatrices, and the
- * delta of the prevLayer will be returned.
- *
- * @param currentLayerIndex Index of current layer.
- * @param nextLayerDelta Delta of next layer.
- * @param outputCache The output cache to store intermediate results.
- * @param weightUpdateMatrix The weight update, in form of {@link Matrix}.
- * @return The weight updates.
- */
- private Vector backPropagate(int currentLayerIndex, Vector nextLayerDelta,
- List<Vector> outputCache, Matrix weightUpdateMatrix) {
-
- // Get layer related information
- final DoubleFunction derivativeSquashingFunction =
- NeuralNetworkFunctions.getDerivativeDoubleFunction(squashingFunctionList.get(currentLayerIndex));
- Vector curLayerOutput = outputCache.get(currentLayerIndex);
- Matrix weightMatrix = weightMatrixList.get(currentLayerIndex);
- Matrix prevWeightMatrix = prevWeightUpdatesList.get(currentLayerIndex);
-
- // Next layer is not output layer, remove the delta of bias neuron
- if (currentLayerIndex != layerSizeList.size() - 2) {
- nextLayerDelta = nextLayerDelta.viewPart(1, nextLayerDelta.size() - 1);
- }
-
- Vector delta = weightMatrix.transpose().times(nextLayerDelta);
-
- delta = delta.assign(curLayerOutput, new DoubleDoubleFunction() {
- @Override
- public double apply(double deltaElem, double curLayerOutputElem) {
- return deltaElem * derivativeSquashingFunction.apply(curLayerOutputElem);
- }
- });
-
- // Update weights
- for (int i = 0; i < weightUpdateMatrix.rowSize(); ++i) {
- for (int j = 0; j < weightUpdateMatrix.columnSize(); ++j) {
- weightUpdateMatrix.set(i, j, -learningRate * nextLayerDelta.get(i) *
- curLayerOutput.get(j) + this.momentumWeight * prevWeightMatrix.get(i, j));
- }
- }
-
- return delta;
- }
-
- /**
- * Read the model meta-data from the specified location.
- *
- * @throws IOException
- */
- protected void readFromModel() throws IOException {
- log.info("Load model from {}", modelPath);
- Preconditions.checkArgument(modelPath != null, "Model path has not been set.");
- Path path = new Path(modelPath);
- FileSystem fs = path.getFileSystem(new Configuration());
- try (FSDataInputStream is = new FSDataInputStream(fs.open(path))) {
- readFields(is);
- }
- }
-
- /**
- * Write the model data to specified location.
- *
- * @throws IOException
- */
- public void writeModelToFile() throws IOException {
- log.info("Write model to {}.", modelPath);
- Preconditions.checkArgument(modelPath != null, "Model path has not been set.");
- Path path = new Path(modelPath);
- FileSystem fs = path.getFileSystem(new Configuration());
- try (FSDataOutputStream stream = fs.create(path, true)) {
- write(stream);
- }
- }
-
- /**
- * Set the model path.
- *
- * @param modelPath The path of the model.
- */
- public void setModelPath(String modelPath) {
- this.modelPath = modelPath;
- }
-
- /**
- * Get the model path.
- *
- * @return The path of the model.
- */
- public String getModelPath() {
- return modelPath;
- }
-
- /**
- * Write the fields of the model to output.
- *
- * @param output The output instance.
- * @throws IOException
- */
- public void write(DataOutput output) throws IOException {
- // Write model type
- WritableUtils.writeString(output, modelType);
- // Write learning rate
- output.writeDouble(learningRate);
- // Write model path
- if (modelPath != null) {
- WritableUtils.writeString(output, modelPath);
- } else {
- WritableUtils.writeString(output, "null");
- }
-
- // Write regularization weight
- output.writeDouble(regularizationWeight);
- // Write momentum weight
- output.writeDouble(momentumWeight);
-
- // Write cost function
- WritableUtils.writeString(output, costFunctionName);
-
- // Write layer size list
- output.writeInt(layerSizeList.size());
- for (Integer aLayerSizeList : layerSizeList) {
- output.writeInt(aLayerSizeList);
- }
-
- WritableUtils.writeEnum(output, trainingMethod);
-
- // Write squashing functions
- output.writeInt(squashingFunctionList.size());
- for (String aSquashingFunctionList : squashingFunctionList) {
- WritableUtils.writeString(output, aSquashingFunctionList);
- }
-
- // Write weight matrices
- output.writeInt(this.weightMatrixList.size());
- for (Matrix aWeightMatrixList : weightMatrixList) {
- MatrixWritable.writeMatrix(output, aWeightMatrixList);
- }
- }
-
- /**
- * Read the fields of the model from input.
- *
- * @param input The input instance.
- * @throws IOException
- */
- public void readFields(DataInput input) throws IOException {
- // Read model type
- modelType = WritableUtils.readString(input);
- if (!modelType.equals(this.getClass().getSimpleName())) {
- throw new IllegalArgumentException("The specified location does not contains the valid NeuralNetwork model.");
- }
- // Read learning rate
- learningRate = input.readDouble();
- // Read model path
- modelPath = WritableUtils.readString(input);
- if (modelPath.equals("null")) {
- modelPath = null;
- }
-
- // Read regularization weight
- regularizationWeight = input.readDouble();
- // Read momentum weight
- momentumWeight = input.readDouble();
-
- // Read cost function
- costFunctionName = WritableUtils.readString(input);
-
- // Read layer size list
- int numLayers = input.readInt();
- layerSizeList = new ArrayList<>();
- for (int i = 0; i < numLayers; i++) {
- layerSizeList.add(input.readInt());
- }
-
- trainingMethod = WritableUtils.readEnum(input, TrainingMethod.class);
-
- // Read squash functions
- int squashingFunctionSize = input.readInt();
- squashingFunctionList = new ArrayList<>();
- for (int i = 0; i < squashingFunctionSize; i++) {
- squashingFunctionList.add(WritableUtils.readString(input));
- }
-
- // Read weights and construct matrices of previous updates
- int numOfMatrices = input.readInt();
- weightMatrixList = new ArrayList<>();
- prevWeightUpdatesList = new ArrayList<>();
- for (int i = 0; i < numOfMatrices; i++) {
- Matrix matrix = MatrixWritable.readMatrix(input);
- weightMatrixList.add(matrix);
- prevWeightUpdatesList.add(new DenseMatrix(matrix.rowSize(), matrix.columnSize()));
- }
- }
-
-}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/mahout/blob/002943be/mr/src/main/java/org/apache/mahout/classifier/mlp/NeuralNetworkFunctions.java
----------------------------------------------------------------------
diff --git a/mr/src/main/java/org/apache/mahout/classifier/mlp/NeuralNetworkFunctions.java b/mr/src/main/java/org/apache/mahout/classifier/mlp/NeuralNetworkFunctions.java
deleted file mode 100644
index 1c752d4..0000000
--- a/mr/src/main/java/org/apache/mahout/classifier/mlp/NeuralNetworkFunctions.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/**
- * 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.mahout.classifier.mlp;
-
-import org.apache.mahout.math.function.DoubleDoubleFunction;
-import org.apache.mahout.math.function.DoubleFunction;
-import org.apache.mahout.math.function.Functions;
-
-/**
- * The functions that will be used by NeuralNetwork.
- * @deprecated as of as of 0.10.0.
- */
-@Deprecated
-public class NeuralNetworkFunctions {
-
- /**
- * The derivation of identity function (f(x) = x).
- */
- public static DoubleFunction derivativeIdentityFunction = new DoubleFunction() {
- @Override
- public double apply(double x) {
- return 1;
- }
- };
-
- /**
- * The derivation of minus squared function (f(t, o) = (o - t)^2).
- */
- public static DoubleDoubleFunction derivativeMinusSquared = new DoubleDoubleFunction() {
- @Override
- public double apply(double target, double output) {
- return 2 * (output - target);
- }
- };
-
- /**
- * The cross entropy function (f(t, o) = -t * log(o) - (1 - t) * log(1 - o)).
- */
- public static DoubleDoubleFunction crossEntropy = new DoubleDoubleFunction() {
- @Override
- public double apply(double target, double output) {
- return -target * Math.log(output) - (1 - target) * Math.log(1 - output);
- }
- };
-
- /**
- * The derivation of cross entropy function (f(t, o) = -t * log(o) - (1 - t) *
- * log(1 - o)).
- */
- public static DoubleDoubleFunction derivativeCrossEntropy = new DoubleDoubleFunction() {
- @Override
- public double apply(double target, double output) {
- double adjustedTarget = target;
- double adjustedActual = output;
- if (adjustedActual == 1) {
- adjustedActual = 0.999;
- } else if (output == 0) {
- adjustedActual = 0.001;
- }
- if (adjustedTarget == 1) {
- adjustedTarget = 0.999;
- } else if (adjustedTarget == 0) {
- adjustedTarget = 0.001;
- }
- return -adjustedTarget / adjustedActual + (1 - adjustedTarget) / (1 - adjustedActual);
- }
- };
-
- /**
- * Get the corresponding function by its name.
- * Currently supports: "Identity", "Sigmoid".
- *
- * @param function The name of the function.
- * @return The corresponding double function.
- */
- public static DoubleFunction getDoubleFunction(String function) {
- if (function.equalsIgnoreCase("Identity")) {
- return Functions.IDENTITY;
- } else if (function.equalsIgnoreCase("Sigmoid")) {
- return Functions.SIGMOID;
- } else {
- throw new IllegalArgumentException("Function not supported.");
- }
- }
-
- /**
- * Get the derivation double function by the name.
- * Currently supports: "Identity", "Sigmoid".
- *
- * @param function The name of the function.
- * @return The double function.
- */
- public static DoubleFunction getDerivativeDoubleFunction(String function) {
- if (function.equalsIgnoreCase("Identity")) {
- return derivativeIdentityFunction;
- } else if (function.equalsIgnoreCase("Sigmoid")) {
- return Functions.SIGMOIDGRADIENT;
- } else {
- throw new IllegalArgumentException("Function not supported.");
- }
- }
-
- /**
- * Get the corresponding double-double function by the name.
- * Currently supports: "Minus_Squared", "Cross_Entropy".
- *
- * @param function The name of the function.
- * @return The double-double function.
- */
- public static DoubleDoubleFunction getDoubleDoubleFunction(String function) {
- if (function.equalsIgnoreCase("Minus_Squared")) {
- return Functions.MINUS_SQUARED;
- } else if (function.equalsIgnoreCase("Cross_Entropy")) {
- return derivativeCrossEntropy;
- } else {
- throw new IllegalArgumentException("Function not supported.");
- }
- }
-
- /**
- * Get the corresponding derivation of double double function by the name.
- * Currently supports: "Minus_Squared", "Cross_Entropy".
- *
- * @param function The name of the function.
- * @return The double-double-function.
- */
- public static DoubleDoubleFunction getDerivativeDoubleDoubleFunction(String function) {
- if (function.equalsIgnoreCase("Minus_Squared")) {
- return derivativeMinusSquared;
- } else if (function.equalsIgnoreCase("Cross_Entropy")) {
- return derivativeCrossEntropy;
- } else {
- throw new IllegalArgumentException("Function not supported.");
- }
- }
-
-}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/mahout/blob/002943be/mr/src/main/java/org/apache/mahout/classifier/mlp/RunMultilayerPerceptron.java
----------------------------------------------------------------------
diff --git a/mr/src/main/java/org/apache/mahout/classifier/mlp/RunMultilayerPerceptron.java b/mr/src/main/java/org/apache/mahout/classifier/mlp/RunMultilayerPerceptron.java
deleted file mode 100644
index 270ea43..0000000
--- a/mr/src/main/java/org/apache/mahout/classifier/mlp/RunMultilayerPerceptron.java
+++ /dev/null
@@ -1,220 +0,0 @@
-/**
- * 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.mahout.classifier.mlp;
-
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import org.apache.commons.cli2.CommandLine;
-import org.apache.commons.cli2.Group;
-import org.apache.commons.cli2.Option;
-import org.apache.commons.cli2.builder.ArgumentBuilder;
-import org.apache.commons.cli2.builder.DefaultOptionBuilder;
-import org.apache.commons.cli2.builder.GroupBuilder;
-import org.apache.commons.cli2.commandline.Parser;
-import org.apache.commons.csv.CSVUtils;
-import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.fs.FileSystem;
-import org.apache.hadoop.fs.Path;
-import org.apache.mahout.math.DenseVector;
-import org.apache.mahout.math.Vector;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/** Run {@link MultilayerPerceptron} classification.
- * @deprecated as of as of 0.10.0.
- * */
-@Deprecated
-public class RunMultilayerPerceptron {
-
- private static final Logger log = LoggerFactory.getLogger(RunMultilayerPerceptron.class);
-
- static class Parameters {
- String inputFilePathStr;
- String inputFileFormat;
- String modelFilePathStr;
- String outputFilePathStr;
- int columnStart;
- int columnEnd;
- boolean skipHeader;
- }
-
- public static void main(String[] args) throws Exception {
-
- Parameters parameters = new Parameters();
-
- if (parseArgs(args, parameters)) {
- log.info("Load model from {}.", parameters.modelFilePathStr);
- MultilayerPerceptron mlp = new MultilayerPerceptron(parameters.modelFilePathStr);
-
- log.info("Topology of MLP: {}.", Arrays.toString(mlp.getLayerSizeList().toArray()));
-
- // validate the data
- log.info("Read the data...");
- Path inputFilePath = new Path(parameters.inputFilePathStr);
- FileSystem inputFS = inputFilePath.getFileSystem(new Configuration());
- if (!inputFS.exists(inputFilePath)) {
- log.error("Input file '{}' does not exists!", parameters.inputFilePathStr);
- mlp.close();
- return;
- }
-
- Path outputFilePath = new Path(parameters.outputFilePathStr);
- FileSystem outputFS = inputFilePath.getFileSystem(new Configuration());
- if (outputFS.exists(outputFilePath)) {
- log.error("Output file '{}' already exists!", parameters.outputFilePathStr);
- mlp.close();
- return;
- }
-
- if (!parameters.inputFileFormat.equals("csv")) {
- log.error("Currently only supports for csv format.");
- mlp.close();
- return; // current only supports csv format
- }
-
- log.info("Read from column {} to column {}.", parameters.columnStart, parameters.columnEnd);
-
-
- try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputFS.create(outputFilePath)));
- BufferedReader reader = new BufferedReader(new InputStreamReader(inputFS.open(inputFilePath)))) {
- String line;
- if (parameters.skipHeader) {
- reader.readLine();
- }
-
- while ((line = reader.readLine()) != null) {
- String[] tokens = CSVUtils.parseLine(line);
- double[] features = new double[Math.min(parameters.columnEnd, tokens.length) - parameters.columnStart + 1];
-
- for (int i = parameters.columnStart, j = 0; i < Math.min(parameters.columnEnd + 1, tokens.length); ++i, ++j) {
- features[j] = Double.parseDouble(tokens[i]);
- }
- Vector featureVec = new DenseVector(features);
- Vector res = mlp.getOutput(featureVec);
- int mostProbablyLabelIndex = res.maxValueIndex();
- writer.write(String.valueOf(mostProbablyLabelIndex));
- }
- mlp.close();
- log.info("Labeling finished.");
- }
- }
- }
-
- /**
- * Parse the arguments.
- *
- * @param args The input arguments.
- * @param parameters The parameters need to be filled.
- * @return true or false
- * @throws Exception
- */
- private static boolean parseArgs(String[] args, Parameters parameters) throws Exception {
- // build the options
- log.info("Validate and parse arguments...");
- DefaultOptionBuilder optionBuilder = new DefaultOptionBuilder();
- GroupBuilder groupBuilder = new GroupBuilder();
- ArgumentBuilder argumentBuilder = new ArgumentBuilder();
-
- Option inputFileFormatOption = optionBuilder
- .withLongName("format")
- .withShortName("f")
- .withArgument(argumentBuilder.withName("file type").withDefault("csv").withMinimum(1).withMaximum(1).create())
- .withDescription("type of input file, currently support 'csv'")
- .create();
-
- List<Integer> columnRangeDefault = new ArrayList<>();
- columnRangeDefault.add(0);
- columnRangeDefault.add(Integer.MAX_VALUE);
-
- Option skipHeaderOption = optionBuilder.withLongName("skipHeader")
- .withShortName("sh").withRequired(false)
- .withDescription("whether to skip the first row of the input file")
- .create();
-
- Option inputColumnRangeOption = optionBuilder
- .withLongName("columnRange")
- .withShortName("cr")
- .withDescription("the column range of the input file, start from 0")
- .withArgument(argumentBuilder.withName("range").withMinimum(2).withMaximum(2)
- .withDefaults(columnRangeDefault).create()).create();
-
- Group inputFileTypeGroup = groupBuilder.withOption(skipHeaderOption)
- .withOption(inputColumnRangeOption).withOption(inputFileFormatOption)
- .create();
-
- Option inputOption = optionBuilder
- .withLongName("input")
- .withShortName("i")
- .withRequired(true)
- .withArgument(argumentBuilder.withName("file path").withMinimum(1).withMaximum(1).create())
- .withDescription("the file path of unlabelled dataset")
- .withChildren(inputFileTypeGroup).create();
-
- Option modelOption = optionBuilder
- .withLongName("model")
- .withShortName("mo")
- .withRequired(true)
- .withArgument(argumentBuilder.withName("model file").withMinimum(1).withMaximum(1).create())
- .withDescription("the file path of the model").create();
-
- Option labelsOption = optionBuilder
- .withLongName("labels")
- .withShortName("labels")
- .withArgument(argumentBuilder.withName("label-name").withMinimum(2).create())
- .withDescription("an ordered list of label names").create();
-
- Group labelsGroup = groupBuilder.withOption(labelsOption).create();
-
- Option outputOption = optionBuilder
- .withLongName("output")
- .withShortName("o")
- .withRequired(true)
- .withArgument(argumentBuilder.withConsumeRemaining("file path").withMinimum(1).withMaximum(1).create())
- .withDescription("the file path of labelled results").withChildren(labelsGroup).create();
-
- // parse the input
- Parser parser = new Parser();
- Group normalOption = groupBuilder.withOption(inputOption).withOption(modelOption).withOption(outputOption).create();
- parser.setGroup(normalOption);
- CommandLine commandLine = parser.parseAndHelp(args);
- if (commandLine == null) {
- return false;
- }
-
- // obtain the arguments
- parameters.inputFilePathStr = TrainMultilayerPerceptron.getString(commandLine, inputOption);
- parameters.inputFileFormat = TrainMultilayerPerceptron.getString(commandLine, inputFileFormatOption);
- parameters.skipHeader = commandLine.hasOption(skipHeaderOption);
- parameters.modelFilePathStr = TrainMultilayerPerceptron.getString(commandLine, modelOption);
- parameters.outputFilePathStr = TrainMultilayerPerceptron.getString(commandLine, outputOption);
-
- List<?> columnRange = commandLine.getValues(inputColumnRangeOption);
- parameters.columnStart = Integer.parseInt(columnRange.get(0).toString());
- parameters.columnEnd = Integer.parseInt(columnRange.get(1).toString());
-
- return true;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/mahout/blob/002943be/mr/src/main/java/org/apache/mahout/classifier/mlp/TrainMultilayerPerceptron.java
----------------------------------------------------------------------
diff --git a/mr/src/main/java/org/apache/mahout/classifier/mlp/TrainMultilayerPerceptron.java b/mr/src/main/java/org/apache/mahout/classifier/mlp/TrainMultilayerPerceptron.java
deleted file mode 100644
index d634aa5..0000000
--- a/mr/src/main/java/org/apache/mahout/classifier/mlp/TrainMultilayerPerceptron.java
+++ /dev/null
@@ -1,314 +0,0 @@
-/**
- * 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.mahout.classifier.mlp;
-
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import com.google.common.base.Preconditions;
-import org.apache.commons.cli2.CommandLine;
-import org.apache.commons.cli2.Group;
-import org.apache.commons.cli2.Option;
-import org.apache.commons.cli2.builder.ArgumentBuilder;
-import org.apache.commons.cli2.builder.DefaultOptionBuilder;
-import org.apache.commons.cli2.builder.GroupBuilder;
-import org.apache.commons.cli2.commandline.Parser;
-import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.fs.FileSystem;
-import org.apache.hadoop.fs.Path;
-import org.apache.mahout.math.Arrays;
-import org.apache.mahout.math.DenseVector;
-import org.apache.mahout.math.Vector;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/** Train a {@link MultilayerPerceptron}.
- * @deprecated as of as of 0.10.0.
- * */
-@Deprecated
-public final class TrainMultilayerPerceptron {
-
- private static final Logger log = LoggerFactory.getLogger(TrainMultilayerPerceptron.class);
-
- /** The parameters used by MLP. */
- static class Parameters {
- double learningRate;
- double momemtumWeight;
- double regularizationWeight;
-
- String inputFilePath;
- boolean skipHeader;
- Map<String, Integer> labelsIndex = new HashMap<>();
-
- String modelFilePath;
- boolean updateModel;
- List<Integer> layerSizeList = new ArrayList<>();
- String squashingFunctionName;
- }
-
- public static void main(String[] args) throws Exception {
- Parameters parameters = new Parameters();
-
- if (parseArgs(args, parameters)) {
- log.info("Validate model...");
- // check whether the model already exists
- Path modelPath = new Path(parameters.modelFilePath);
- FileSystem modelFs = modelPath.getFileSystem(new Configuration());
- MultilayerPerceptron mlp;
-
- if (modelFs.exists(modelPath) && parameters.updateModel) {
- // incrementally update existing model
- log.info("Build model from existing model...");
- mlp = new MultilayerPerceptron(parameters.modelFilePath);
- } else {
- if (modelFs.exists(modelPath)) {
- modelFs.delete(modelPath, true); // delete the existing file
- }
- log.info("Build model from scratch...");
- mlp = new MultilayerPerceptron();
- for (int i = 0; i < parameters.layerSizeList.size(); ++i) {
- if (i != parameters.layerSizeList.size() - 1) {
- mlp.addLayer(parameters.layerSizeList.get(i), false, parameters.squashingFunctionName);
- } else {
- mlp.addLayer(parameters.layerSizeList.get(i), true, parameters.squashingFunctionName);
- }
- mlp.setCostFunction("Minus_Squared");
- mlp.setLearningRate(parameters.learningRate)
- .setMomentumWeight(parameters.momemtumWeight)
- .setRegularizationWeight(parameters.regularizationWeight);
- }
- mlp.setModelPath(parameters.modelFilePath);
- }
-
- // set the parameters
- mlp.setLearningRate(parameters.learningRate)
- .setMomentumWeight(parameters.momemtumWeight)
- .setRegularizationWeight(parameters.regularizationWeight);
-
- // train by the training data
- Path trainingDataPath = new Path(parameters.inputFilePath);
- FileSystem dataFs = trainingDataPath.getFileSystem(new Configuration());
-
- Preconditions.checkArgument(dataFs.exists(trainingDataPath), "Training dataset %s cannot be found!",
- parameters.inputFilePath);
-
- log.info("Read data and train model...");
-
- try (BufferedReader reader = new BufferedReader(new InputStreamReader(dataFs.open(trainingDataPath)))) {
- String line;
- // read training data line by line
- if (parameters.skipHeader) {
- reader.readLine();
- }
-
- int labelDimension = parameters.labelsIndex.size();
- while ((line = reader.readLine()) != null) {
- String[] token = line.split(",");
- String label = token[token.length - 1];
- int labelIndex = parameters.labelsIndex.get(label);
-
- double[] instances = new double[token.length - 1 + labelDimension];
- for (int i = 0; i < token.length - 1; ++i) {
- instances[i] = Double.parseDouble(token[i]);
- }
- for (int i = 0; i < labelDimension; ++i) {
- instances[token.length - 1 + i] = 0;
- }
- // set the corresponding dimension
- instances[token.length - 1 + labelIndex] = 1;
-
- Vector instance = new DenseVector(instances).viewPart(0, instances.length);
- mlp.trainOnline(instance);
- }
-
- // write model back
- log.info("Write trained model to {}", parameters.modelFilePath);
- mlp.writeModelToFile();
- mlp.close();
- }
- }
- }
-
- /**
- * Parse the input arguments.
- *
- * @param args The input arguments
- * @param parameters The parameters parsed.
- * @return Whether the input arguments are valid.
- * @throws Exception
- */
- private static boolean parseArgs(String[] args, Parameters parameters) throws Exception {
- // build the options
- log.info("Validate and parse arguments...");
- DefaultOptionBuilder optionBuilder = new DefaultOptionBuilder();
- GroupBuilder groupBuilder = new GroupBuilder();
- ArgumentBuilder argumentBuilder = new ArgumentBuilder();
-
- // whether skip the first row of the input file
- Option skipHeaderOption = optionBuilder.withLongName("skipHeader")
- .withShortName("sh").create();
-
- Group skipHeaderGroup = groupBuilder.withOption(skipHeaderOption).create();
-
- Option inputOption = optionBuilder
- .withLongName("input")
- .withShortName("i")
- .withRequired(true)
- .withChildren(skipHeaderGroup)
- .withArgument(argumentBuilder.withName("path").withMinimum(1).withMaximum(1)
- .create()).withDescription("the file path of training dataset")
- .create();
-
- Option labelsOption = optionBuilder
- .withLongName("labels")
- .withShortName("labels")
- .withRequired(true)
- .withArgument(argumentBuilder.withName("label-name").withMinimum(2).create())
- .withDescription("label names").create();
-
- Option updateOption = optionBuilder
- .withLongName("update")
- .withShortName("u")
- .withDescription("whether to incrementally update model if the model exists")
- .create();
-
- Group modelUpdateGroup = groupBuilder.withOption(updateOption).create();
-
- Option modelOption = optionBuilder
- .withLongName("model")
- .withShortName("mo")
- .withRequired(true)
- .withArgument(argumentBuilder.withName("model-path").withMinimum(1).withMaximum(1).create())
- .withDescription("the path to store the trained model")
- .withChildren(modelUpdateGroup).create();
-
- Option layerSizeOption = optionBuilder
- .withLongName("layerSize")
- .withShortName("ls")
- .withRequired(true)
- .withArgument(argumentBuilder.withName("size of layer").withMinimum(2).withMaximum(5).create())
- .withDescription("the size of each layer").create();
-
- Option squashingFunctionOption = optionBuilder
- .withLongName("squashingFunction")
- .withShortName("sf")
- .withArgument(argumentBuilder.withName("squashing function").withMinimum(1).withMaximum(1)
- .withDefault("Sigmoid").create())
- .withDescription("the name of squashing function (currently only supports Sigmoid)")
- .create();
-
- Option learningRateOption = optionBuilder
- .withLongName("learningRate")
- .withShortName("l")
- .withArgument(argumentBuilder.withName("learning rate").withMaximum(1)
- .withMinimum(1).withDefault(NeuralNetwork.DEFAULT_LEARNING_RATE).create())
- .withDescription("learning rate").create();
-
- Option momemtumOption = optionBuilder
- .withLongName("momemtumWeight")
- .withShortName("m")
- .withArgument(argumentBuilder.withName("momemtum weight").withMaximum(1)
- .withMinimum(1).withDefault(NeuralNetwork.DEFAULT_MOMENTUM_WEIGHT).create())
- .withDescription("momemtum weight").create();
-
- Option regularizationOption = optionBuilder
- .withLongName("regularizationWeight")
- .withShortName("r")
- .withArgument(argumentBuilder.withName("regularization weight").withMaximum(1)
- .withMinimum(1).withDefault(NeuralNetwork.DEFAULT_REGULARIZATION_WEIGHT).create())
- .withDescription("regularization weight").create();
-
- // parse the input
- Parser parser = new Parser();
- Group normalOptions = groupBuilder.withOption(inputOption)
- .withOption(skipHeaderOption).withOption(updateOption)
- .withOption(labelsOption).withOption(modelOption)
- .withOption(layerSizeOption).withOption(squashingFunctionOption)
- .withOption(learningRateOption).withOption(momemtumOption)
- .withOption(regularizationOption).create();
-
- parser.setGroup(normalOptions);
-
- CommandLine commandLine = parser.parseAndHelp(args);
- if (commandLine == null) {
- return false;
- }
-
- parameters.learningRate = getDouble(commandLine, learningRateOption);
- parameters.momemtumWeight = getDouble(commandLine, momemtumOption);
- parameters.regularizationWeight = getDouble(commandLine, regularizationOption);
-
- parameters.inputFilePath = getString(commandLine, inputOption);
- parameters.skipHeader = commandLine.hasOption(skipHeaderOption);
-
- List<String> labelsList = getStringList(commandLine, labelsOption);
- int currentIndex = 0;
- for (String label : labelsList) {
- parameters.labelsIndex.put(label, currentIndex++);
- }
-
- parameters.modelFilePath = getString(commandLine, modelOption);
- parameters.updateModel = commandLine.hasOption(updateOption);
-
- parameters.layerSizeList = getIntegerList(commandLine, layerSizeOption);
-
- parameters.squashingFunctionName = getString(commandLine, squashingFunctionOption);
-
- System.out.printf("Input: %s, Model: %s, Update: %s, Layer size: %s, Squashing function: %s, Learning rate: %f," +
- " Momemtum weight: %f, Regularization Weight: %f\n", parameters.inputFilePath, parameters.modelFilePath,
- parameters.updateModel, Arrays.toString(parameters.layerSizeList.toArray()),
- parameters.squashingFunctionName, parameters.learningRate, parameters.momemtumWeight,
- parameters.regularizationWeight);
-
- return true;
- }
-
- static Double getDouble(CommandLine commandLine, Option option) {
- Object val = commandLine.getValue(option);
- if (val != null) {
- return Double.parseDouble(val.toString());
- }
- return null;
- }
-
- static String getString(CommandLine commandLine, Option option) {
- Object val = commandLine.getValue(option);
- if (val != null) {
- return val.toString();
- }
- return null;
- }
-
- static List<Integer> getIntegerList(CommandLine commandLine, Option option) {
- List<String> list = commandLine.getValues(option);
- List<Integer> valList = new ArrayList<>();
- for (String str : list) {
- valList.add(Integer.parseInt(str));
- }
- return valList;
- }
-
- static List<String> getStringList(CommandLine commandLine, Option option) {
- return commandLine.getValues(option);
- }
-
-}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/mahout/blob/002943be/mr/src/test/java/org/apache/mahout/classifier/mlp/Datasets.java
----------------------------------------------------------------------
diff --git a/mr/src/test/java/org/apache/mahout/classifier/mlp/Datasets.java b/mr/src/test/java/org/apache/mahout/classifier/mlp/Datasets.java
deleted file mode 100644
index 8b53720..0000000
--- a/mr/src/test/java/org/apache/mahout/classifier/mlp/Datasets.java
+++ /dev/null
@@ -1,866 +0,0 @@
-/**
- * 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.mahout.classifier.mlp;
-@Deprecated
-public class Datasets {
-
- public static final String[] IRIS = new String[] {
- "Sepal.Length,Sepal.Width,Petal.Length,Petal.Width,Species",
- "5.1,3.5,1.4,0.2,setosa",
- "4.9,3.0,1.4,0.2,setosa",
- "4.7,3.2,1.3,0.2,setosa",
- "4.6,3.1,1.5,0.2,setosa",
- "5.0,3.6,1.4,0.2,setosa",
- "5.4,3.9,1.7,0.4,setosa",
- "4.6,3.4,1.4,0.3,setosa",
- "5.0,3.4,1.5,0.2,setosa",
- "4.4,2.9,1.4,0.2,setosa",
- "4.9,3.1,1.5,0.1,setosa",
- "5.4,3.7,1.5,0.2,setosa",
- "4.8,3.4,1.6,0.2,setosa",
- "4.8,3.0,1.4,0.1,setosa",
- "4.3,3.0,1.1,0.1,setosa",
- "5.8,4.0,1.2,0.2,setosa",
- "5.7,4.4,1.5,0.4,setosa",
- "5.4,3.9,1.3,0.4,setosa",
- "5.1,3.5,1.4,0.3,setosa",
- "5.7,3.8,1.7,0.3,setosa",
- "5.1,3.8,1.5,0.3,setosa",
- "5.4,3.4,1.7,0.2,setosa",
- "5.1,3.7,1.5,0.4,setosa",
- "4.6,3.6,1.0,0.2,setosa",
- "5.1,3.3,1.7,0.5,setosa",
- "4.8,3.4,1.9,0.2,setosa",
- "5.0,3.0,1.6,0.2,setosa",
- "5.0,3.4,1.6,0.4,setosa",
- "5.2,3.5,1.5,0.2,setosa",
- "5.2,3.4,1.4,0.2,setosa",
- "4.7,3.2,1.6,0.2,setosa",
- "4.8,3.1,1.6,0.2,setosa",
- "5.4,3.4,1.5,0.4,setosa",
- "5.2,4.1,1.5,0.1,setosa",
- "5.5,4.2,1.4,0.2,setosa",
- "4.9,3.1,1.5,0.2,setosa",
- "5.0,3.2,1.2,0.2,setosa",
- "5.5,3.5,1.3,0.2,setosa",
- "4.9,3.6,1.4,0.1,setosa",
- "4.4,3.0,1.3,0.2,setosa",
- "5.1,3.4,1.5,0.2,setosa",
- "5.0,3.5,1.3,0.3,setosa",
- "4.5,2.3,1.3,0.3,setosa",
- "4.4,3.2,1.3,0.2,setosa",
- "5.0,3.5,1.6,0.6,setosa",
- "5.1,3.8,1.9,0.4,setosa",
- "4.8,3.0,1.4,0.3,setosa",
- "5.1,3.8,1.6,0.2,setosa",
- "4.6,3.2,1.4,0.2,setosa",
- "5.3,3.7,1.5,0.2,setosa",
- "5.0,3.3,1.4,0.2,setosa",
- "7.0,3.2,4.7,1.4,versicolor",
- "6.4,3.2,4.5,1.5,versicolor",
- "6.9,3.1,4.9,1.5,versicolor",
- "5.5,2.3,4.0,1.3,versicolor",
- "6.5,2.8,4.6,1.5,versicolor",
- "5.7,2.8,4.5,1.3,versicolor",
- "6.3,3.3,4.7,1.6,versicolor",
- "4.9,2.4,3.3,1.0,versicolor",
- "6.6,2.9,4.6,1.3,versicolor",
- "5.2,2.7,3.9,1.4,versicolor",
- "5.0,2.0,3.5,1.0,versicolor",
- "5.9,3.0,4.2,1.5,versicolor",
- "6.0,2.2,4.0,1.0,versicolor",
- "6.1,2.9,4.7,1.4,versicolor",
- "5.6,2.9,3.6,1.3,versicolor",
- "6.7,3.1,4.4,1.4,versicolor",
- "5.6,3.0,4.5,1.5,versicolor",
- "5.8,2.7,4.1,1.0,versicolor",
- "6.2,2.2,4.5,1.5,versicolor",
- "5.6,2.5,3.9,1.1,versicolor",
- "5.9,3.2,4.8,1.8,versicolor",
- "6.1,2.8,4.0,1.3,versicolor",
- "6.3,2.5,4.9,1.5,versicolor",
- "6.1,2.8,4.7,1.2,versicolor",
- "6.4,2.9,4.3,1.3,versicolor",
- "6.6,3.0,4.4,1.4,versicolor",
- "6.8,2.8,4.8,1.4,versicolor",
- "6.7,3.0,5.0,1.7,versicolor",
- "6.0,2.9,4.5,1.5,versicolor",
- "5.7,2.6,3.5,1.0,versicolor",
- "5.5,2.4,3.8,1.1,versicolor",
- "5.5,2.4,3.7,1.0,versicolor",
- "5.8,2.7,3.9,1.2,versicolor",
- "6.0,2.7,5.1,1.6,versicolor",
- "5.4,3.0,4.5,1.5,versicolor",
- "6.0,3.4,4.5,1.6,versicolor",
- "6.7,3.1,4.7,1.5,versicolor",
- "6.3,2.3,4.4,1.3,versicolor",
- "5.6,3.0,4.1,1.3,versicolor",
- "5.5,2.5,4.0,1.3,versicolor",
- "5.5,2.6,4.4,1.2,versicolor",
- "6.1,3.0,4.6,1.4,versicolor",
- "5.8,2.6,4.0,1.2,versicolor",
- "5.0,2.3,3.3,1.0,versicolor",
- "5.6,2.7,4.2,1.3,versicolor",
- "5.7,3.0,4.2,1.2,versicolor",
- "5.7,2.9,4.2,1.3,versicolor",
- "6.2,2.9,4.3,1.3,versicolor",
- "5.1,2.5,3.0,1.1,versicolor",
- "5.7,2.8,4.1,1.3,versicolor",
- "6.3,3.3,6.0,2.5,virginica",
- "5.8,2.7,5.1,1.9,virginica",
- "7.1,3.0,5.9,2.1,virginica",
- "6.3,2.9,5.6,1.8,virginica",
- "6.5,3.0,5.8,2.2,virginica",
- "7.6,3.0,6.6,2.1,virginica",
- "4.9,2.5,4.5,1.7,virginica",
- "7.3,2.9,6.3,1.8,virginica",
- "6.7,2.5,5.8,1.8,virginica",
- "7.2,3.6,6.1,2.5,virginica",
- "6.5,3.2,5.1,2.0,virginica",
- "6.4,2.7,5.3,1.9,virginica",
- "6.8,3.0,5.5,2.1,virginica",
- "5.7,2.5,5.0,2.0,virginica",
- "5.8,2.8,5.1,2.4,virginica",
- "6.4,3.2,5.3,2.3,virginica",
- "6.5,3.0,5.5,1.8,virginica",
- "7.7,3.8,6.7,2.2,virginica",
- "7.7,2.6,6.9,2.3,virginica",
- "6.0,2.2,5.0,1.5,virginica",
- "6.9,3.2,5.7,2.3,virginica",
- "5.6,2.8,4.9,2.0,virginica",
- "7.7,2.8,6.7,2.0,virginica",
- "6.3,2.7,4.9,1.8,virginica",
- "6.7,3.3,5.7,2.1,virginica",
- "7.2,3.2,6.0,1.8,virginica",
- "6.2,2.8,4.8,1.8,virginica",
- "6.1,3.0,4.9,1.8,virginica",
- "6.4,2.8,5.6,2.1,virginica",
- "7.2,3.0,5.8,1.6,virginica",
- "7.4,2.8,6.1,1.9,virginica",
- "7.9,3.8,6.4,2.0,virginica",
- "6.4,2.8,5.6,2.2,virginica",
- "6.3,2.8,5.1,1.5,virginica",
- "6.1,2.6,5.6,1.4,virginica",
- "7.7,3.0,6.1,2.3,virginica",
- "6.3,3.4,5.6,2.4,virginica",
- "6.4,3.1,5.5,1.8,virginica",
- "6.0,3.0,4.8,1.8,virginica",
- "6.9,3.1,5.4,2.1,virginica",
- "6.7,3.1,5.6,2.4,virginica",
- "6.9,3.1,5.1,2.3,virginica",
- "5.8,2.7,5.1,1.9,virginica",
- "6.8,3.2,5.9,2.3,virginica",
- "6.7,3.3,5.7,2.5,virginica",
- "6.7,3.0,5.2,2.3,virginica",
- "6.3,2.5,5.0,1.9,virginica",
- "6.5,3.0,5.2,2.0,virginica",
- "6.2,3.4,5.4,2.3,virginica",
- "5.9,3.0,5.1,1.8,virginica"
- };
-
- public static final String[] CANCER = new String[] {
- "\"V1\",\"V2\",\"V3\",\"V4\",\"V5\",\"V6\",\"V7\",\"V8\",\"V9\",\"target\"",
- "5,1,1,1,2,1,3,1,1,0",
- "5,4,4,5,7,10,3,2,1,0",
- "3,1,1,1,2,2,3,1,1,0",
- "6,8,8,1,3,4,3,7,1,0",
- "4,1,1,3,2,1,3,1,1,0",
- "8,10,10,8,7,10,9,7,1,1",
- "1,1,1,1,2,10,3,1,1,0",
- "2,1,2,1,2,1,3,1,1,0",
- "2,1,1,1,2,1,1,1,5,0",
- "4,2,1,1,2,1,2,1,1,0",
- "1,1,1,1,1,1,3,1,1,0",
- "2,1,1,1,2,1,2,1,1,0",
- "5,3,3,3,2,3,4,4,1,1",
- "1,1,1,1,2,3,3,1,1,0",
- "8,7,5,10,7,9,5,5,4,1",
- "7,4,6,4,6,1,4,3,1,1",
- "4,1,1,1,2,1,2,1,1,0",
- "4,1,1,1,2,1,3,1,1,0",
- "10,7,7,6,4,10,4,1,2,1",
- "6,1,1,1,2,1,3,1,1,0",
- "7,3,2,10,5,10,5,4,4,1",
- "10,5,5,3,6,7,7,10,1,1",
- "3,1,1,1,2,1,2,1,1,0",
- "1,1,1,1,2,1,3,1,1,0",
- "5,2,3,4,2,7,3,6,1,1",
- "3,2,1,1,1,1,2,1,1,0",
- "5,1,1,1,2,1,2,1,1,0",
- "2,1,1,1,2,1,2,1,1,0",
- "1,1,3,1,2,1,1,1,1,0",
- "3,1,1,1,1,1,2,1,1,0",
- "2,1,1,1,2,1,3,1,1,0",
- "10,7,7,3,8,5,7,4,3,1",
- "2,1,1,2,2,1,3,1,1,0",
- "3,1,2,1,2,1,2,1,1,0",
- "2,1,1,1,2,1,2,1,1,0",
- "10,10,10,8,6,1,8,9,1,1",
- "6,2,1,1,1,1,7,1,1,0",
- "5,4,4,9,2,10,5,6,1,1",
- "2,5,3,3,6,7,7,5,1,1",
- "10,4,3,1,3,3,6,5,2,1",
- "6,10,10,2,8,10,7,3,3,1",
- "5,6,5,6,10,1,3,1,1,1",
- "10,10,10,4,8,1,8,10,1,1",
- "1,1,1,1,2,1,2,1,2,0",
- "3,7,7,4,4,9,4,8,1,1",
- "1,1,1,1,2,1,2,1,1,0",
- "4,1,1,3,2,1,3,1,1,0",
- "7,8,7,2,4,8,3,8,2,1",
- "9,5,8,1,2,3,2,1,5,1",
- "5,3,3,4,2,4,3,4,1,1",
- "10,3,6,2,3,5,4,10,2,1",
- "5,5,5,8,10,8,7,3,7,1",
- "10,5,5,6,8,8,7,1,1,1",
- "10,6,6,3,4,5,3,6,1,1",
- "8,10,10,1,3,6,3,9,1,1",
- "8,2,4,1,5,1,5,4,4,1",
- "5,2,3,1,6,10,5,1,1,1",
- "9,5,5,2,2,2,5,1,1,1",
- "5,3,5,5,3,3,4,10,1,1",
- "1,1,1,1,2,2,2,1,1,0",
- "9,10,10,1,10,8,3,3,1,1",
- "6,3,4,1,5,2,3,9,1,1",
- "1,1,1,1,2,1,2,1,1,0",
- "10,4,2,1,3,2,4,3,10,1",
- "4,1,1,1,2,1,3,1,1,0",
- "5,3,4,1,8,10,4,9,1,1",
- "8,3,8,3,4,9,8,9,8,1",
- "1,1,1,1,2,1,3,2,1,0",
- "5,1,3,1,2,1,2,1,1,0",
- "6,10,2,8,10,2,7,8,10,1",
- "1,3,3,2,2,1,7,2,1,0",
- "9,4,5,10,6,10,4,8,1,1",
- "10,6,4,1,3,4,3,2,3,1",
- "1,1,2,1,2,2,4,2,1,0",
- "1,1,4,1,2,1,2,1,1,0",
- "5,3,1,2,2,1,2,1,1,0",
- "3,1,1,1,2,3,3,1,1,0",
- "2,1,1,1,3,1,2,1,1,0",
- "2,2,2,1,1,1,7,1,1,0",
- "4,1,1,2,2,1,2,1,1,0",
- "5,2,1,1,2,1,3,1,1,0",
- "3,1,1,1,2,2,7,1,1,0",
- "3,5,7,8,8,9,7,10,7,1",
- "5,10,6,1,10,4,4,10,10,1",
- "3,3,6,4,5,8,4,4,1,1",
- "3,6,6,6,5,10,6,8,3,1",
- "4,1,1,1,2,1,3,1,1,0",
- "2,1,1,2,3,1,2,1,1,0",
- "1,1,1,1,2,1,3,1,1,0",
- "3,1,1,2,2,1,1,1,1,0",
- "4,1,1,1,2,1,3,1,1,0",
- "1,1,1,1,2,1,2,1,1,0",
- "2,1,1,1,2,1,3,1,1,0",
- "1,1,1,1,2,1,3,1,1,0",
- "2,1,1,2,2,1,1,1,1,0",
- "5,1,1,1,2,1,3,1,1,0",
- "9,6,9,2,10,6,2,9,10,1",
- "7,5,6,10,5,10,7,9,4,1",
- "10,3,5,1,10,5,3,10,2,1",
- "2,3,4,4,2,5,2,5,1,1",
- "4,1,2,1,2,1,3,1,1,0",
- "8,2,3,1,6,3,7,1,1,1",
- "10,10,10,10,10,1,8,8,8,1",
- "7,3,4,4,3,3,3,2,7,1",
- "10,10,10,8,2,10,4,1,1,1",
- "1,6,8,10,8,10,5,7,1,1",
- "1,1,1,1,2,1,2,3,1,0",
- "6,5,4,4,3,9,7,8,3,1",
- "1,3,1,2,2,2,5,3,2,0",
- "8,6,4,3,5,9,3,1,1,1",
- "10,3,3,10,2,10,7,3,3,1",
- "10,10,10,3,10,8,8,1,1,1",
- "3,3,2,1,2,3,3,1,1,0",
- "1,1,1,1,2,5,1,1,1,0",
- "8,3,3,1,2,2,3,2,1,0",
- "4,5,5,10,4,10,7,5,8,1",
- "1,1,1,1,4,3,1,1,1,0",
- "3,2,1,1,2,2,3,1,1,0",
- "1,1,2,2,2,1,3,1,1,0",
- "4,2,1,1,2,2,3,1,1,0",
- "10,10,10,2,10,10,5,3,3,1",
- "5,3,5,1,8,10,5,3,1,1",
- "5,4,6,7,9,7,8,10,1,1",
- "1,1,1,1,2,1,2,1,1,0",
- "7,5,3,7,4,10,7,5,5,1",
- "3,1,1,1,2,1,3,1,1,0",
- "8,3,5,4,5,10,1,6,2,1",
- "1,1,1,1,10,1,1,1,1,0",
- "5,1,3,1,2,1,2,1,1,0",
- "2,1,1,1,2,1,3,1,1,0",
- "5,10,8,10,8,10,3,6,3,1",
- "3,1,1,1,2,1,2,2,1,0",
- "3,1,1,1,3,1,2,1,1,0",
- "5,1,1,1,2,2,3,3,1,0",
- "4,1,1,1,2,1,2,1,1,0",
- "3,1,1,1,2,1,1,1,1,0",
- "4,1,2,1,2,1,2,1,1,0",
- "3,1,1,1,2,1,1,1,1,0",
- "2,1,1,1,2,1,1,1,1,0",
- "9,5,5,4,4,5,4,3,3,1",
- "1,1,1,1,2,5,1,1,1,0",
- "2,1,1,1,2,1,2,1,1,0",
- "3,4,5,2,6,8,4,1,1,1",
- "1,1,1,1,3,2,2,1,1,0",
- "3,1,1,3,8,1,5,8,1,0",
- "8,8,7,4,10,10,7,8,7,1",
- "1,1,1,1,1,1,3,1,1,0",
- "7,2,4,1,6,10,5,4,3,1",
- "10,10,8,6,4,5,8,10,1,1",
- "4,1,1,1,2,3,1,1,1,0",
- "1,1,1,1,2,1,1,1,1,0",
- "5,5,5,6,3,10,3,1,1,1",
- "1,2,2,1,2,1,2,1,1,0",
- "2,1,1,1,2,1,3,1,1,0",
- "9,9,10,3,6,10,7,10,6,1",
- "10,7,7,4,5,10,5,7,2,1",
- "4,1,1,1,2,1,3,2,1,0",
- "3,1,1,1,2,1,3,1,1,0",
- "1,1,1,2,1,3,1,1,7,0",
- "4,1,1,1,2,2,3,2,1,0",
- "5,6,7,8,8,10,3,10,3,1",
- "10,8,10,10,6,1,3,1,10,1",
- "3,1,1,1,2,1,3,1,1,0",
- "1,1,1,2,1,1,1,1,1,0",
- "3,1,1,1,2,1,1,1,1,0",
- "1,1,1,1,2,1,3,1,1,0",
- "1,1,1,1,2,1,2,1,1,0",
- "6,10,10,10,8,10,10,10,7,1",
- "8,6,5,4,3,10,6,1,1,1",
- "5,8,7,7,10,10,5,7,1,1",
- "2,1,1,1,2,1,3,1,1,0",
- "5,10,10,3,8,1,5,10,3,1",
- "4,1,1,1,2,1,3,1,1,0",
- "5,3,3,3,6,10,3,1,1,1",
- "1,1,1,1,1,1,3,1,1,0",
- "1,1,1,1,2,1,1,1,1,0",
- "6,1,1,1,2,1,3,1,1,0",
- "5,8,8,8,5,10,7,8,1,1",
- "8,7,6,4,4,10,5,1,1,1",
- "2,1,1,1,1,1,3,1,1,0",
- "1,5,8,6,5,8,7,10,1,1",
- "10,5,6,10,6,10,7,7,10,1",
- "5,8,4,10,5,8,9,10,1,1",
- "1,2,3,1,2,1,3,1,1,0",
- "10,10,10,8,6,8,7,10,1,1",
- "7,5,10,10,10,10,4,10,3,1",
- "5,1,1,1,2,1,2,1,1,0",
- "1,1,1,1,2,1,3,1,1,0",
- "3,1,1,1,2,1,3,1,1,0",
- "4,1,1,1,2,1,3,1,1,0",
- "8,4,4,5,4,7,7,8,2,0",
- "5,1,1,4,2,1,3,1,1,0",
- "1,1,1,1,2,1,1,1,1,0",
- "3,1,1,1,2,1,2,1,1,0",
- "9,7,7,5,5,10,7,8,3,1",
- "10,8,8,4,10,10,8,1,1,1",
- "1,1,1,1,2,1,3,1,1,0",
- "5,1,1,1,2,1,3,1,1,0",
- "1,1,1,1,2,1,3,1,1,0",
- "5,10,10,9,6,10,7,10,5,1",
- "10,10,9,3,7,5,3,5,1,1",
- "1,1,1,1,1,1,3,1,1,0",
- "1,1,1,1,1,1,3,1,1,0",
- "5,1,1,1,1,1,3,1,1,0",
- "8,10,10,10,5,10,8,10,6,1",
- "8,10,8,8,4,8,7,7,1,1",
- "1,1,1,1,2,1,3,1,1,0",
- "10,10,10,10,7,10,7,10,4,1",
- "10,10,10,10,3,10,10,6,1,1",
- "8,7,8,7,5,5,5,10,2,1",
- "1,1,1,1,2,1,2,1,1,0",
- "1,1,1,1,2,1,3,1,1,0",
- "6,10,7,7,6,4,8,10,2,1",
- "6,1,3,1,2,1,3,1,1,0",
- "1,1,1,2,2,1,3,1,1,0",
- "10,6,4,3,10,10,9,10,1,1",
- "4,1,1,3,1,5,2,1,1,1",
- "7,5,6,3,3,8,7,4,1,1",
- "10,5,5,6,3,10,7,9,2,1",
- "1,1,1,1,2,1,2,1,1,0",
- "10,5,7,4,4,10,8,9,1,1",
- "8,9,9,5,3,5,7,7,1,1",
- "1,1,1,1,1,1,3,1,1,0",
- "10,10,10,3,10,10,9,10,1,1",
- "7,4,7,4,3,7,7,6,1,1",
- "6,8,7,5,6,8,8,9,2,1",
- "8,4,6,3,3,1,4,3,1,0",
- "10,4,5,5,5,10,4,1,1,1",
- "3,3,2,1,3,1,3,6,1,0",
- "10,8,8,2,8,10,4,8,10,1",
- "9,8,8,5,6,2,4,10,4,1",
- "8,10,10,8,6,9,3,10,10,1",
- "10,4,3,2,3,10,5,3,2,1",
- "5,1,3,3,2,2,2,3,1,0",
- "3,1,1,3,1,1,3,1,1,0",
- "2,1,1,1,2,1,3,1,1,0",
- "1,1,1,1,2,5,5,1,1,0",
- "1,1,1,1,2,1,3,1,1,0",
- "5,1,1,2,2,2,3,1,1,0",
- "8,10,10,8,5,10,7,8,1,1",
- "8,4,4,1,2,9,3,3,1,1",
- "4,1,1,1,2,1,3,6,1,0",
- "1,2,2,1,2,1,1,1,1,0",
- "10,4,4,10,2,10,5,3,3,1",
- "6,3,3,5,3,10,3,5,3,0",
- "6,10,10,2,8,10,7,3,3,1",
- "9,10,10,1,10,8,3,3,1,1",
- "5,6,6,2,4,10,3,6,1,1",
- "3,1,1,1,2,1,1,1,1,0",
- "3,1,1,1,2,1,2,1,1,0",
- "3,1,1,1,2,1,3,1,1,0",
- "5,7,7,1,5,8,3,4,1,0",
- "10,5,8,10,3,10,5,1,3,1",
- "5,10,10,6,10,10,10,6,5,1",
- "8,8,9,4,5,10,7,8,1,1",
- "10,4,4,10,6,10,5,5,1,1",
- "7,9,4,10,10,3,5,3,3,1",
- "5,1,4,1,2,1,3,2,1,0",
- "10,10,6,3,3,10,4,3,2,1",
- "3,3,5,2,3,10,7,1,1,1",
- "10,8,8,2,3,4,8,7,8,1",
- "1,1,1,1,2,1,3,1,1,0",
- "8,4,7,1,3,10,3,9,2,1",
- "5,1,1,1,2,1,3,1,1,0",
- "3,3,5,2,3,10,7,1,1,1",
- "7,2,4,1,3,4,3,3,1,1",
- "3,1,1,1,2,1,3,2,1,0",
- "3,1,1,1,2,1,2,1,1,0",
- "1,1,1,1,2,1,2,1,1,0",
- "1,1,1,1,2,1,3,1,1,0",
- "10,5,7,3,3,7,3,3,8,1",
- "3,1,1,1,2,1,3,1,1,0",
- "2,1,1,2,2,1,3,1,1,0",
- "1,4,3,10,4,10,5,6,1,1",
- "10,4,6,1,2,10,5,3,1,1",
- "7,4,5,10,2,10,3,8,2,1",
- "8,10,10,10,8,10,10,7,3,1",
- "10,10,10,10,10,10,4,10,10,1",
- "3,1,1,1,3,1,2,1,1,0",
- "6,1,3,1,4,5,5,10,1,1",
- "5,6,6,8,6,10,4,10,4,1",
- "1,1,1,1,2,1,1,1,1,0",
- "1,1,1,1,2,1,3,1,1,0",
- "10,4,4,6,2,10,2,3,1,1",
- "5,5,7,8,6,10,7,4,1,1",
- "5,3,4,3,4,5,4,7,1,0",
- "8,2,1,1,5,1,1,1,1,0",
- "9,1,2,6,4,10,7,7,2,1",
- "8,4,10,5,4,4,7,10,1,1",
- "1,1,1,1,2,1,3,1,1,0",
- "10,10,10,7,9,10,7,10,10,1",
- "1,1,1,1,2,1,3,1,1,0",
- "8,3,4,9,3,10,3,3,1,1",
- "10,8,4,4,4,10,3,10,4,1",
- "1,1,1,1,2,1,3,1,1,0",
- "1,1,1,1,2,1,3,1,1,0",
- "7,8,7,6,4,3,8,8,4,1",
- "3,1,1,1,2,5,5,1,1,0",
- "2,1,1,1,3,1,2,1,1,0",
- "1,1,1,1,2,1,1,1,1,0",
- "8,6,4,10,10,1,3,5,1,1",
- "1,1,1,1,2,1,1,1,1,0",
- "1,1,1,1,1,1,2,1,1,0",
- "5,5,5,2,5,10,4,3,1,1",
- "6,8,7,8,6,8,8,9,1,1",
- "1,1,1,1,5,1,3,1,1,0",
- "4,4,4,4,6,5,7,3,1,0",
- "7,6,3,2,5,10,7,4,6,1",
- "3,1,1,1,2,1,3,1,1,0",
- "5,4,6,10,2,10,4,1,1,1",
- "1,1,1,1,2,1,3,1,1,0",
- "3,2,2,1,2,1,2,3,1,0",
- "10,1,1,1,2,10,5,4,1,1",
- "1,1,1,1,2,1,2,1,1,0",
- "8,10,3,2,6,4,3,10,1,1",
- "10,4,6,4,5,10,7,1,1,1",
- "10,4,7,2,2,8,6,1,1,1",
- "5,1,1,1,2,1,3,1,2,0",
- "5,2,2,2,2,1,2,2,1,0",
- "5,4,6,6,4,10,4,3,1,1",
- "8,6,7,3,3,10,3,4,2,1",
- "1,1,1,1,2,1,1,1,1,0",
- "6,5,5,8,4,10,3,4,1,1",
- "1,1,1,1,2,1,3,1,1,0",
- "1,1,1,1,1,1,2,1,1,0",
- "8,5,5,5,2,10,4,3,1,1",
- "10,3,3,1,2,10,7,6,1,1",
- "1,1,1,1,2,1,3,1,1,0",
- "2,1,1,1,2,1,1,1,1,0",
- "1,1,1,1,2,1,1,1,1,0",
- "7,6,4,8,10,10,9,5,3,1",
- "1,1,1,1,2,1,1,1,1,0",
- "5,2,2,2,3,1,1,3,1,0",
- "1,1,1,1,1,1,1,3,1,0",
- "3,4,4,10,5,1,3,3,1,1",
- "4,2,3,5,3,8,7,6,1,1",
- "5,1,1,3,2,1,1,1,1,0",
- "2,1,1,1,2,1,3,1,1,0",
- "3,4,5,3,7,3,4,6,1,0",
- "2,7,10,10,7,10,4,9,4,1",
- "1,1,1,1,2,1,2,1,1,0",
- "4,1,1,1,3,1,2,2,1,0",
- "5,3,3,1,3,3,3,3,3,1",
- "8,10,10,7,10,10,7,3,8,1",
- "8,10,5,3,8,4,4,10,3,1",
- "10,3,5,4,3,7,3,5,3,1",
- "6,10,10,10,10,10,8,10,10,1",
- "3,10,3,10,6,10,5,1,4,1",
- "3,2,2,1,4,3,2,1,1,0",
- "4,4,4,2,2,3,2,1,1,0",
- "2,1,1,1,2,1,3,1,1,0",
- "2,1,1,1,2,1,2,1,1,0",
- "6,10,10,10,8,10,7,10,7,1",
- "5,8,8,10,5,10,8,10,3,1",
- "1,1,3,1,2,1,1,1,1,0",
- "1,1,3,1,1,1,2,1,1,0",
- "4,3,2,1,3,1,2,1,1,0",
- "1,1,3,1,2,1,1,1,1,0",
- "4,1,2,1,2,1,2,1,1,0",
- "5,1,1,2,2,1,2,1,1,0",
- "3,1,2,1,2,1,2,1,1,0",
- "1,1,1,1,2,1,1,1,1,0",
- "1,1,1,1,2,1,2,1,1,0",
- "1,1,1,1,1,1,2,1,1,0",
- "3,1,1,4,3,1,2,2,1,0",
- "5,3,4,1,4,1,3,1,1,0",
- "1,1,1,1,2,1,1,1,1,0",
- "10,6,3,6,4,10,7,8,4,1",
- "3,2,2,2,2,1,3,2,1,0",
- "2,1,1,1,2,1,1,1,1,0",
- "2,1,1,1,2,1,1,1,1,0",
- "3,3,2,2,3,1,1,2,3,0",
- "7,6,6,3,2,10,7,1,1,1",
- "5,3,3,2,3,1,3,1,1,0",
- "2,1,1,1,2,1,2,2,1,0",
- "5,1,1,1,3,2,2,2,1,0",
- "1,1,1,2,2,1,2,1,1,0",
- "10,8,7,4,3,10,7,9,1,1",
- "3,1,1,1,2,1,2,1,1,0",
- "1,1,1,1,1,1,1,1,1,0",
- "1,2,3,1,2,1,2,1,1,0",
- "3,1,1,1,2,1,2,1,1,0",
- "3,1,1,1,2,1,3,1,1,0",
- "4,1,1,1,2,1,1,1,1,0",
- "3,2,1,1,2,1,2,2,1,0",
- "1,2,3,1,2,1,1,1,1,0",
- "3,10,8,7,6,9,9,3,8,1",
- "3,1,1,1,2,1,1,1,1,0",
- "5,3,3,1,2,1,2,1,1,0",
- "3,1,1,1,2,4,1,1,1,0",
- "1,2,1,3,2,1,1,2,1,0",
- "1,1,1,1,2,1,2,1,1,0",
- "4,2,2,1,2,1,2,1,1,0",
- "1,1,1,1,2,1,2,1,1,0",
- "2,3,2,2,2,2,3,1,1,0",
- "3,1,2,1,2,1,2,1,1,0",
- "1,1,1,1,2,1,2,1,1,0",
- "10,10,10,6,8,4,8,5,1,1",
- "5,1,2,1,2,1,3,1,1,0",
- "8,5,6,2,3,10,6,6,1,1",
- "3,3,2,6,3,3,3,5,1,0",
- "8,7,8,5,10,10,7,2,1,1",
- "1,1,1,1,2,1,2,1,1,0",
- "5,2,2,2,2,2,3,2,2,0",
- "2,3,1,1,5,1,1,1,1,0",
- "3,2,2,3,2,3,3,1,1,0",
- "10,10,10,7,10,10,8,2,1,1",
- "4,3,3,1,2,1,3,3,1,0",
- "5,1,3,1,2,1,2,1,1,0",
- "3,1,1,1,2,1,1,1,1,0",
- "9,10,10,10,10,10,10,10,1,1",
- "5,3,6,1,2,1,1,1,1,0",
- "8,7,8,2,4,2,5,10,1,1",
- "1,1,1,1,2,1,2,1,1,0",
- "2,1,1,1,2,1,2,1,1,0",
- "1,3,1,1,2,1,2,2,1,0",
- "5,1,1,3,4,1,3,2,1,0",
- "5,1,1,1,2,1,2,2,1,0",
- "3,2,2,3,2,1,1,1,1,0",
- "6,9,7,5,5,8,4,2,1,0",
- "10,8,10,1,3,10,5,1,1,1",
- "10,10,10,1,6,1,2,8,1,1",
- "4,1,1,1,2,1,1,1,1,0",
- "4,1,3,3,2,1,1,1,1,0",
- "5,1,1,1,2,1,1,1,1,0",
- "10,4,3,10,4,10,10,1,1,1",
- "5,2,2,4,2,4,1,1,1,0",
- "1,1,1,3,2,3,1,1,1,0",
- "1,1,1,1,2,2,1,1,1,0",
- "5,1,1,6,3,1,2,1,1,0",
- "2,1,1,1,2,1,1,1,1,0",
- "1,1,1,1,2,1,1,1,1,0",
- "5,1,1,1,2,1,1,1,1,0",
- "1,1,1,1,1,1,1,1,1,0",
- "5,7,9,8,6,10,8,10,1,1",
- "4,1,1,3,1,1,2,1,1,0",
- "5,1,1,1,2,1,1,1,1,0",
- "3,1,1,3,2,1,1,1,1,0",
- "4,5,5,8,6,10,10,7,1,1",
- "2,3,1,1,3,1,1,1,1,0",
- "10,2,2,1,2,6,1,1,2,1",
- "10,6,5,8,5,10,8,6,1,1",
- "8,8,9,6,6,3,10,10,1,1",
- "5,1,2,1,2,1,1,1,1,0",
- "5,1,3,1,2,1,1,1,1,0",
- "5,1,1,3,2,1,1,1,1,0",
- "3,1,1,1,2,5,1,1,1,0",
- "6,1,1,3,2,1,1,1,1,0",
- "4,1,1,1,2,1,1,2,1,0",
- "4,1,1,1,2,1,1,1,1,0",
- "10,9,8,7,6,4,7,10,3,1",
- "10,6,6,2,4,10,9,7,1,1",
- "6,6,6,5,4,10,7,6,2,1",
- "4,1,1,1,2,1,1,1,1,0",
- "1,1,2,1,2,1,2,1,1,0",
- "3,1,1,1,1,1,2,1,1,0",
- "6,1,1,3,2,1,1,1,1,0",
- "6,1,1,1,1,1,1,1,1,0",
- "4,1,1,1,2,1,1,1,1,0",
- "5,1,1,1,2,1,1,1,1,0",
- "3,1,1,1,2,1,1,1,1,0",
- "4,1,2,1,2,1,1,1,1,0",
- "4,1,1,1,2,1,1,1,1,0",
- "5,2,1,1,2,1,1,1,1,0",
- "4,8,7,10,4,10,7,5,1,1",
- "5,1,1,1,1,1,1,1,1,0",
- "5,3,2,4,2,1,1,1,1,0",
- "9,10,10,10,10,5,10,10,10,1",
- "8,7,8,5,5,10,9,10,1,1",
- "5,1,2,1,2,1,1,1,1,0",
- "1,1,1,3,1,3,1,1,1,0",
- "3,1,1,1,1,1,2,1,1,0",
- "10,10,10,10,6,10,8,1,5,1",
- "3,6,4,10,3,3,3,4,1,1",
- "6,3,2,1,3,4,4,1,1,1",
- "1,1,1,1,2,1,1,1,1,0",
- "5,8,9,4,3,10,7,1,1,1",
- "4,1,1,1,1,1,2,1,1,0",
- "5,10,10,10,6,10,6,5,2,1",
- "5,1,2,10,4,5,2,1,1,0",
- "3,1,1,1,1,1,2,1,1,0",
- "1,1,1,1,1,1,1,1,1,0",
- "4,2,1,1,2,1,1,1,1,0",
- "4,1,1,1,2,1,2,1,1,0",
- "4,1,1,1,2,1,2,1,1,0",
- "6,1,1,1,2,1,3,1,1,0",
- "4,1,1,1,2,1,2,1,1,0",
- "4,1,1,2,2,1,2,1,1,0",
- "4,1,1,1,2,1,3,1,1,0",
- "1,1,1,1,2,1,1,1,1,0",
- "3,3,1,1,2,1,1,1,1,0",
- "8,10,10,10,7,5,4,8,7,1",
- "1,1,1,1,2,4,1,1,1,0",
- "5,1,1,1,2,1,1,1,1,0",
- "2,1,1,1,2,1,1,1,1,0",
- "1,1,1,1,2,1,1,1,1,0",
- "5,1,1,1,2,1,2,1,1,0",
- "5,1,1,1,2,1,1,1,1,0",
- "3,1,1,1,1,1,2,1,1,0",
- "6,6,7,10,3,10,8,10,2,1",
- "4,10,4,7,3,10,9,10,1,1",
- "1,1,1,1,1,1,1,1,1,0",
- "1,1,1,1,1,1,2,1,1,0",
- "3,1,2,2,2,1,1,1,1,0",
- "4,7,8,3,4,10,9,1,1,1",
- "1,1,1,1,3,1,1,1,1,0",
- "4,1,1,1,3,1,1,1,1,0",
- "10,4,5,4,3,5,7,3,1,1",
- "7,5,6,10,4,10,5,3,1,1",
- "3,1,1,1,2,1,2,1,1,0",
- "3,1,1,2,2,1,1,1,1,0",
- "4,1,1,1,2,1,1,1,1,0",
- "4,1,1,1,2,1,3,1,1,0",
- "6,1,3,2,2,1,1,1,1,0",
- "4,1,1,1,1,1,2,1,1,0",
- "7,4,4,3,4,10,6,9,1,1",
- "4,2,2,1,2,1,2,1,1,0",
- "1,1,1,1,1,1,3,1,1,0",
- "3,1,1,1,2,1,2,1,1,0",
- "2,1,1,1,2,1,2,1,1,0",
- "1,1,3,2,2,1,3,1,1,0",
- "5,1,1,1,2,1,3,1,1,0",
- "5,1,2,1,2,1,3,1,1,0",
- "4,1,1,1,2,1,2,1,1,0",
- "6,1,1,1,2,1,2,1,1,0",
- "5,1,1,1,2,2,2,1,1,0",
- "3,1,1,1,2,1,1,1,1,0",
- "5,3,1,1,2,1,1,1,1,0",
- "4,1,1,1,2,1,2,1,1,0",
- "2,1,3,2,2,1,2,1,1,0",
- "5,1,1,1,2,1,2,1,1,0",
- "6,10,10,10,4,10,7,10,1,1",
- "2,1,1,1,1,1,1,1,1,0",
- "3,1,1,1,1,1,1,1,1,0",
- "7,8,3,7,4,5,7,8,2,1",
- "3,1,1,1,2,1,2,1,1,0",
- "1,1,1,1,2,1,3,1,1,0",
- "3,2,2,2,2,1,4,2,1,0",
- "4,4,2,1,2,5,2,1,2,0",
- "3,1,1,1,2,1,1,1,1,0",
- "4,3,1,1,2,1,4,8,1,0",
- "5,2,2,2,1,1,2,1,1,0",
- "5,1,1,3,2,1,1,1,1,0",
- "2,1,1,1,2,1,2,1,1,0",
- "5,1,1,1,2,1,2,1,1,0",
- "5,1,1,1,2,1,3,1,1,0",
- "5,1,1,1,2,1,3,1,1,0",
- "1,1,1,1,2,1,3,1,1,0",
- "3,1,1,1,2,1,2,1,1,0",
- "4,1,1,1,2,1,3,2,1,0",
- "5,7,10,10,5,10,10,10,1,1",
- "3,1,2,1,2,1,3,1,1,0",
- "4,1,1,1,2,3,2,1,1,0",
- "8,4,4,1,6,10,2,5,2,1",
- "10,10,8,10,6,5,10,3,1,1",
- "8,10,4,4,8,10,8,2,1,1",
- "7,6,10,5,3,10,9,10,2,1",
- "3,1,1,1,2,1,2,1,1,0",
- "1,1,1,1,2,1,2,1,1,0",
- "10,9,7,3,4,2,7,7,1,1",
- "5,1,2,1,2,1,3,1,1,0",
- "5,1,1,1,2,1,2,1,1,0",
- "1,1,1,1,2,1,2,1,1,0",
- "1,1,1,1,2,1,2,1,1,0",
- "1,1,1,1,2,1,3,1,1,0",
- "5,1,2,1,2,1,2,1,1,0",
- "5,7,10,6,5,10,7,5,1,1",
- "6,10,5,5,4,10,6,10,1,1",
- "3,1,1,1,2,1,1,1,1,0",
- "5,1,1,6,3,1,1,1,1,0",
- "1,1,1,1,2,1,1,1,1,0",
- "8,10,10,10,6,10,10,10,1,1",
- "5,1,1,1,2,1,2,2,1,0",
- "9,8,8,9,6,3,4,1,1,1",
- "5,1,1,1,2,1,1,1,1,0",
- "4,10,8,5,4,1,10,1,1,1",
- "2,5,7,6,4,10,7,6,1,1",
- "10,3,4,5,3,10,4,1,1,1",
- "5,1,2,1,2,1,1,1,1,0",
- "4,8,6,3,4,10,7,1,1,1",
- "5,1,1,1,2,1,2,1,1,0",
- "4,1,2,1,2,1,2,1,1,0",
- "5,1,3,1,2,1,3,1,1,0",
- "3,1,1,1,2,1,2,1,1,0",
- "5,2,4,1,1,1,1,1,1,0",
- "3,1,1,1,2,1,2,1,1,0",
- "1,1,1,1,1,1,2,1,1,0",
- "4,1,1,1,2,1,2,1,1,0",
- "5,4,6,8,4,1,8,10,1,1",
- "5,3,2,8,5,10,8,1,2,1",
- "10,5,10,3,5,8,7,8,3,1",
- "4,1,1,2,2,1,1,1,1,0",
- "1,1,1,1,2,1,1,1,1,0",
- "5,10,10,10,10,10,10,1,1,1",
- "5,1,1,1,2,1,1,1,1,0",
- "10,4,3,10,3,10,7,1,2,1",
- "5,10,10,10,5,2,8,5,1,1",
- "8,10,10,10,6,10,10,10,10,1",
- "2,3,1,1,2,1,2,1,1,0",
- "2,1,1,1,1,1,2,1,1,0",
- "4,1,3,1,2,1,2,1,1,0",
- "3,1,1,1,2,1,2,1,1,0",
- "4,1,1,1,2,1,2,1,1,0",
- "5,1,1,1,2,1,2,1,1,0",
- "3,1,1,1,2,1,2,1,1,0",
- "6,3,3,3,3,2,6,1,1,0",
- "7,1,2,3,2,1,2,1,1,0",
- "1,1,1,1,2,1,1,1,1,0",
- "5,1,1,2,1,1,2,1,1,0",
- "3,1,3,1,3,4,1,1,1,0",
- "4,6,6,5,7,6,7,7,3,1",
- "2,1,1,1,2,5,1,1,1,0",
- "2,1,1,1,2,1,1,1,1,0",
- "4,1,1,1,2,1,1,1,1,0",
- "6,2,3,1,2,1,1,1,1,0",
- "5,1,1,1,2,1,2,1,1,0",
- "1,1,1,1,2,1,1,1,1,0",
- "8,7,4,4,5,3,5,10,1,1",
- "3,1,1,1,2,1,1,1,1,0",
- "3,1,4,1,2,1,1,1,1,0",
- "10,10,7,8,7,1,10,10,3,1",
- "4,2,4,3,2,2,2,1,1,0",
- "4,1,1,1,2,1,1,1,1,0",
- "5,1,1,3,2,1,1,1,1,0",
- "4,1,1,3,2,1,1,1,1,0",
- "3,1,1,1,2,1,2,1,1,0",
- "3,1,1,1,2,1,2,1,1,0",
- "1,1,1,1,2,1,1,1,1,0",
- "2,1,1,1,2,1,1,1,1,0",
- "3,1,1,1,2,1,2,1,1,0",
- "1,2,2,1,2,1,1,1,1,0",
- "1,1,1,3,2,1,1,1,1,0",
- "5,10,10,10,10,2,10,10,10,1",
- "3,1,1,1,2,1,2,1,1,0",
- "3,1,1,2,3,4,1,1,1,0",
- "1,2,1,3,2,1,2,1,1,0",
- "5,1,1,1,2,1,2,2,1,0",
- "4,1,1,1,2,1,2,1,1,0",
- "3,1,1,1,2,1,3,1,1,0",
- "3,1,1,1,2,1,2,1,1,0",
- "5,1,1,1,2,1,2,1,1,0",
- "5,4,5,1,8,1,3,6,1,0",
- "7,8,8,7,3,10,7,2,3,1",
- "1,1,1,1,2,1,1,1,1,0",
- "1,1,1,1,2,1,2,1,1,0",
- "4,1,1,1,2,1,3,1,1,0",
- "1,1,3,1,2,1,2,1,1,0",
- "1,1,3,1,2,1,2,1,1,0",
- "3,1,1,3,2,1,2,1,1,0",
- "1,1,1,1,2,1,1,1,1,0",
- "5,2,2,2,2,1,1,1,2,0",
- "3,1,1,1,2,1,3,1,1,0",
- "5,7,4,1,6,1,7,10,3,1",
- "5,10,10,8,5,5,7,10,1,1",
- "3,10,7,8,5,8,7,4,1,1",
- "3,2,1,2,2,1,3,1,1,0",
- "2,1,1,1,2,1,3,1,1,0",
- "5,3,2,1,3,1,1,1,1,0",
- "1,1,1,1,2,1,2,1,1,0",
- "4,1,4,1,2,1,1,1,1,0",
- "1,1,2,1,2,1,2,1,1,0",
- "5,1,1,1,2,1,1,1,1,0",
- "1,1,1,1,2,1,1,1,1,0",
- "2,1,1,1,2,1,1,1,1,0",
- "10,10,10,10,5,10,10,10,7,1",
- "5,10,10,10,4,10,5,6,3,1",
- "5,1,1,1,2,1,3,2,1,0",
- "1,1,1,1,2,1,1,1,1,0",
- "1,1,1,1,2,1,1,1,1,0",
- "1,1,1,1,2,1,1,1,1,0",
- "1,1,1,1,2,1,1,1,1,0",
- "3,1,1,1,2,1,2,3,1,0",
- "4,1,1,1,2,1,1,1,1,0",
- "1,1,1,1,2,1,1,1,8,0",
- "1,1,1,3,2,1,1,1,1,0",
- "5,10,10,5,4,5,4,4,1,1",
- "3,1,1,1,2,1,1,1,1,0",
- "3,1,1,1,2,1,2,1,2,0",
- "3,1,1,1,3,2,1,1,1,0",
- "2,1,1,1,2,1,1,1,1,0",
- "5,10,10,3,7,3,8,10,2,1",
- "4,8,6,4,3,4,10,6,1,1",
- "4,8,8,5,4,5,10,4,1,1"
- };
-
- private Datasets() {}
-
-}