From d44e377513d254ddef72640bfcb9f5fac5d23ff3 Mon Sep 17 00:00:00 2001 From: Kevin Berendsen Date: Tue, 11 Jun 2019 17:56:27 +0200 Subject: [PATCH 01/87] Fixed compile error --- .../javax/visrec/AbstractImageClassifier.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/main/java/javax/visrec/AbstractImageClassifier.java b/src/main/java/javax/visrec/AbstractImageClassifier.java index b955a67..192f431 100644 --- a/src/main/java/javax/visrec/AbstractImageClassifier.java +++ b/src/main/java/javax/visrec/AbstractImageClassifier.java @@ -1,5 +1,6 @@ package javax.visrec; +import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -27,35 +28,35 @@ * * */ -public abstract class AbstractImageClassifier implements ImageClassifier { // could also implement binary classifier +public abstract class AbstractImageClassifier implements ImageClassifier { // could also implement binary classifier - private ImageFactory imageFactory; // image factory impl for the specified image class + private ImageFactory imageFactory; // image factory impl for the specified image class private MODEL_CLASS model; // the model could be injected from machine learning container? private float threshold; // this should ba a part of every classifier - protected AbstractImageClassifier(final Class cls, final MODEL_CLASS model) { - final Optional> optionalImageFactory = ServiceProvider.current() + protected AbstractImageClassifier(@Deprecated final Class cls, final MODEL_CLASS model) { + final Optional> optionalImageFactory = ServiceProvider.current() .getImageFactoryService() - .getByImageType(cls); + .getByImageType(BufferedImage.class); if (!optionalImageFactory.isPresent()) { - throw new IllegalArgumentException(String.format("Could not find ImageFactory by '%s'", cls.getName())); + throw new IllegalArgumentException(String.format("Could not find ImageFactory by '%s'", BufferedImage.class.getName())); } imageFactory = optionalImageFactory.get(); setModel(model); } - public ImageFactory getImageFactory() { + public ImageFactory getImageFactory() { return imageFactory; } public Map classify(File file) throws IOException { - IMAGE_CLASS image = imageFactory.getImage(file); + BufferedImage image = imageFactory.getImage(file); return classify(image); } public Map classify(InputStream inStream) throws IOException { - IMAGE_CLASS image = imageFactory.getImage(inStream); + BufferedImage image = imageFactory.getImage(inStream); return classify(image); } From e48be9d3e44dc7f674b4db9a013189b5d153ef6f Mon Sep 17 00:00:00 2001 From: Zoran Sevarac Date: Wed, 21 Aug 2019 17:12:37 +0200 Subject: [PATCH 02/87] fixed pom and compile errors --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index ca2179b..0a28b09 100644 --- a/pom.xml +++ b/pom.xml @@ -99,7 +99,7 @@ - + org.apache.maven.plugins From f885ff3a40f48e6792ffab95eca0aaa28e3a14d7 Mon Sep 17 00:00:00 2001 From: Zoran Sevarac Date: Thu, 22 Aug 2019 22:19:02 +0200 Subject: [PATCH 03/87] Fixed contstanerror, zero likes bug, nlp processing etc. --- .../javax/visrec/ml/data/BasicDataSet.java | 18 +++++++++- .../java/javax/visrec/ml/data/DataSet.java | 36 +++++++++++++++---- 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/src/main/java/javax/visrec/ml/data/BasicDataSet.java b/src/main/java/javax/visrec/ml/data/BasicDataSet.java index 47a926c..67c3fb4 100644 --- a/src/main/java/javax/visrec/ml/data/BasicDataSet.java +++ b/src/main/java/javax/visrec/ml/data/BasicDataSet.java @@ -14,7 +14,7 @@ */ public class BasicDataSet implements DataSet{ - private List items; + private List items; //this should be a data frame map of lists, even better us evalue types! private Column[] columns; /** @@ -110,6 +110,22 @@ public List getItems() { return items; } + @Override + public String[] getOutputLabels() { + // get onlu columns marked as target / output + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public void setColumnNames(String[] columnNames) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public String[] getColumnNames() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + } diff --git a/src/main/java/javax/visrec/ml/data/DataSet.java b/src/main/java/javax/visrec/ml/data/DataSet.java index df28887..69a544e 100644 --- a/src/main/java/javax/visrec/ml/data/DataSet.java +++ b/src/main/java/javax/visrec/ml/data/DataSet.java @@ -81,11 +81,20 @@ default int size() { /** * Split dataset into specified number of equally sized parts. - * + * Moze d abude defaultna , podeli na jednkae delove/decimalne i pozovi onu jednu * @param numParts number of parts to be returned * @return multiple {@link DataSet} in an array. */ - DataSet[] split(int numParts); + default DataSet[] split(int numParts) { + double part = 1.0 / (double)numParts; + double[] parts = new double[numParts]; + + for (int i=0; i[] split(int numParts, Random rnd); + default DataSet[] split(int numParts, Random rnd) { + double part = 1.0 / (double)numParts; + double[] parts = new double[numParts]; + + for (int i=0; i[] split(double part) { * @param parts specific sizes of {@link DataSet} * @return array of {@link DataSet} */ - DataSet[] split(Random rnd, double... parts); + default DataSet[] split(Random rnd, double... parts) { + shuffle(rnd); + return split(parts); + } /** @@ -136,8 +157,11 @@ default void shuffle(Random rnd) { Collections.shuffle(getItems(), rnd); } -// TODO String[] getOutputLabels(); -// TODO void setColumnNames(String[] labels); + public String[] getOutputLabels(); + + public void setColumnNames(String[] columnNames); + public String[] getColumnNames(); + class Column { private final String name; From 5ef48daa2c94d337d5e0da80ceef800f25459a1b Mon Sep 17 00:00:00 2001 From: Zoran Sevarac Date: Fri, 23 Aug 2019 14:14:14 +0200 Subject: [PATCH 04/87] Fixed contstanerror, zero likes bug, nlp processing etc. --- .../javax/visrec/AbstractImageClassifier.java | 14 +-- .../ml/classification/ImageClassifier.java | 2 +- .../javax/visrec/ml/data/BasicDataSet.java | 110 +++++------------- .../java/javax/visrec/ml/data/DataSet.java | 43 ++++--- .../java/javax/visrec/ml/data/Normalizer.java | 15 +++ .../javax/visrec/ml/data/norm/Normalizer.java | 17 --- .../visrec/ml/eval/EvaluationMetrics.java | 90 ++++++++++++++ .../java/javax/visrec/ml/eval/Evaluator.java | 19 ++- .../visrec/ml/eval/PerformanceMeasure.java | 36 ------ .../regression/LogisticRegression.java | 2 +- .../visrec/{ => ml}/regression/Regressor.java | 2 +- .../regression/SimpleLinearRegression.java | 4 +- .../visrec/{ml/data => thrash}/DataSets.java | 18 +-- src/main/java/javax/visrec/util/Model.java | 3 +- 14 files changed, 198 insertions(+), 177 deletions(-) create mode 100644 src/main/java/javax/visrec/ml/data/Normalizer.java delete mode 100644 src/main/java/javax/visrec/ml/data/norm/Normalizer.java create mode 100644 src/main/java/javax/visrec/ml/eval/EvaluationMetrics.java delete mode 100644 src/main/java/javax/visrec/ml/eval/PerformanceMeasure.java rename src/main/java/javax/visrec/{ => ml}/regression/LogisticRegression.java (94%) rename src/main/java/javax/visrec/{ => ml}/regression/Regressor.java (86%) rename src/main/java/javax/visrec/{ => ml}/regression/SimpleLinearRegression.java (93%) rename src/main/java/javax/visrec/{ml/data => thrash}/DataSets.java (82%) diff --git a/src/main/java/javax/visrec/AbstractImageClassifier.java b/src/main/java/javax/visrec/AbstractImageClassifier.java index 192f431..b247dd2 100644 --- a/src/main/java/javax/visrec/AbstractImageClassifier.java +++ b/src/main/java/javax/visrec/AbstractImageClassifier.java @@ -28,17 +28,17 @@ * * */ -public abstract class AbstractImageClassifier implements ImageClassifier { // could also implement binary classifier +public abstract class AbstractImageClassifier implements ImageClassifier { // could also implement binary classifier - private ImageFactory imageFactory; // image factory impl for the specified image class + private ImageFactory imageFactory; // image factory impl for the specified image class private MODEL_CLASS model; // the model could be injected from machine learning container? private float threshold; // this should ba a part of every classifier protected AbstractImageClassifier(@Deprecated final Class cls, final MODEL_CLASS model) { - final Optional> optionalImageFactory = ServiceProvider.current() + final Optional> optionalImageFactory = ServiceProvider.current() .getImageFactoryService() - .getByImageType(BufferedImage.class); + .getByImageType(cls); // BufferedImage.class if (!optionalImageFactory.isPresent()) { throw new IllegalArgumentException(String.format("Could not find ImageFactory by '%s'", BufferedImage.class.getName())); } @@ -46,17 +46,17 @@ protected AbstractImageClassifier(@Deprecated final Class cls, fina setModel(model); } - public ImageFactory getImageFactory() { + public ImageFactory getImageFactory() { return imageFactory; } public Map classify(File file) throws IOException { - BufferedImage image = imageFactory.getImage(file); + IMAGE_CLASS image = imageFactory.getImage(file); return classify(image); } public Map classify(InputStream inStream) throws IOException { - BufferedImage image = imageFactory.getImage(inStream); + IMAGE_CLASS image = imageFactory.getImage(inStream); return classify(image); } diff --git a/src/main/java/javax/visrec/ml/classification/ImageClassifier.java b/src/main/java/javax/visrec/ml/classification/ImageClassifier.java index df8ceae..239a0bd 100644 --- a/src/main/java/javax/visrec/ml/classification/ImageClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/ImageClassifier.java @@ -4,7 +4,7 @@ import java.awt.image.BufferedImage; import java.io.File; -public interface ImageClassifier extends Classifier { +public interface ImageClassifier extends Classifier { static ImageClassifier.Builder newBuilder() { return new Builder(); diff --git a/src/main/java/javax/visrec/ml/data/BasicDataSet.java b/src/main/java/javax/visrec/ml/data/BasicDataSet.java index 67c3fb4..cdcb26f 100644 --- a/src/main/java/javax/visrec/ml/data/BasicDataSet.java +++ b/src/main/java/javax/visrec/ml/data/BasicDataSet.java @@ -8,15 +8,24 @@ import java.util.stream.Collectors; /** - * Basic implementation of {@link DataSet} interface - * + * Basic implementation of {@link DataSet} interface. + * Provides a list of data set items with column info. + * + * @param Type of elements in data set * @author Zoran Sevarac */ -public class BasicDataSet implements DataSet{ +public class BasicDataSet implements DataSet { - private List items; //this should be a data frame map of lists, even better us evalue types! + /** + * List of data set items in this data set + */ + protected List items; //this should be a data frame map of lists, even better us evalue types! private Column[] columns; + protected BasicDataSet() { + items = new ArrayList<>(); + } + /** * Creates an instance of {@link BasicDataSet} * @param cols columns of the data set. @@ -33,62 +42,15 @@ public BasicDataSet(Column[] cols) { public BasicDataSet(List elements) { this.items = elements; } - - @Override - public DataSet add(E item) { - items.add(item); - return this; - } - - @Override - public DataSet addAll(DataSet items) { - this.items.addAll(this.items); - return this; - } - - @Override - public E get(int index) { - return items.get(index); - } - - @Override - public void clear() { - items.clear(); - } - - @Override - public boolean isEmpty() { - return items.isEmpty(); - } - - @Override - public int size() { - return items.size(); - } - - @Override - public DataSet[] split(int parts) { - throw new UnsupportedOperationException("not implemented"); - } - - @Override - public DataSet[] split(int parts, Random rnd) { - throw new UnsupportedOperationException("not implemented"); - } - + @Override - public DataSet[] split(double... parts) { - throw new UnsupportedOperationException("not implemented"); - } + public List getItems() { + return items; + } + @Override - public DataSet[] split(Random rnd, double... parts) { - throw new UnsupportedOperationException("not implemented"); - } - - - // this shuld go to utilities class or default method? - public String[] getTargetLabels() { + public String[] getTargetNames() { List targetLabels = Arrays.asList(columns).stream() .filter((col) -> col.isTarget()) .map((col) -> col.getName() ) @@ -96,36 +58,26 @@ public String[] getTargetLabels() { return targetLabels.toArray(new String[0]); } -// public void setColumnNames(String[] labels) { -// throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. -// } - - @Override - public Iterator iterator() { - return items.iterator(); - } - @Override - public List getItems() { - return items; + public void setColumnNames(String[] columnNames) { + for(int i=0; i[] split(double... parts) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } - - -} +} \ No newline at end of file diff --git a/src/main/java/javax/visrec/ml/data/DataSet.java b/src/main/java/javax/visrec/ml/data/DataSet.java index 69a544e..f35b39c 100644 --- a/src/main/java/javax/visrec/ml/data/DataSet.java +++ b/src/main/java/javax/visrec/ml/data/DataSet.java @@ -2,6 +2,7 @@ import java.util.Collection; import java.util.Collections; +import java.util.Iterator; import java.util.List; import java.util.Objects; import java.util.Random; @@ -48,12 +49,12 @@ default DataSet addAll(DataSet dataSet) { /** * Get an item from the {@link DataSet} - * @param index index as {@code int} which corresponds with + * @param idx index as {@code int} which corresponds with * the index of the {@link DataSet} * @return item from the {@link DataSet} */ - default E get(int index) { - return getItems().get(index); + default E get(int idx) { + return getItems().get(idx); } /** @@ -62,7 +63,7 @@ default E get(int index) { default void clear() { getItems().clear(); } - + /** * Determines whether the {@link DataSet} is empty or not. * @return {@code true} if the {@link DataSet} is empty, otherwise {@code false} @@ -78,10 +79,14 @@ default boolean isEmpty() { default int size() { return getItems().size(); } - + + @Override + default Iterator iterator() { + return getItems().iterator(); + } + /** * Split dataset into specified number of equally sized parts. - * Moze d abude defaultna , podeli na jednkae delove/decimalne i pozovi onu jednu * @param numParts number of parts to be returned * @return multiple {@link DataSet} in an array. */ @@ -157,18 +162,30 @@ default void shuffle(Random rnd) { Collections.shuffle(getItems(), rnd); } - public String[] getOutputLabels(); + /** + * Get labels of target/output columns. + * @return array with labels of target/output columns + */ + public String[] getTargetNames(); + // also add setTargetNames(String ...) and setTargetColumns(int ...) public void setColumnNames(String[] columnNames); + public String[] getColumnNames(); - class Column { + public static class Column { private final String name; - private final ColumnType type; + private final Type type; private final boolean isTarget; - public Column(String name, ColumnType type, boolean isTarget) { + public Column(String name) { + this.name = name; + this.type = null; + this.isTarget = false; + } + + public Column(String name, Type type, boolean isTarget) { this.name = name; this.type = type; this.isTarget = isTarget; @@ -178,7 +195,7 @@ public String getName() { return name; } - public ColumnType getType() { + public Type getType() { return type; } @@ -187,8 +204,8 @@ public boolean isTarget() { } } - enum ColumnType { - DECIMAL, INTEGER, BINARY, STRING; + public static enum Type { + DECIMAL, INTEGER, BINARY, STRING; // ENUM? } } \ No newline at end of file diff --git a/src/main/java/javax/visrec/ml/data/Normalizer.java b/src/main/java/javax/visrec/ml/data/Normalizer.java new file mode 100644 index 0000000..6e30064 --- /dev/null +++ b/src/main/java/javax/visrec/ml/data/Normalizer.java @@ -0,0 +1,15 @@ +package javax.visrec.ml.data; + +import javax.visrec.ml.data.DataSet; + +/** + * Interface to perform normalization/scaling of data set + * + * @author Zoran Sevarac + * @param Data set class (that implements DataSet interface) + */ +public interface Normalizer> { + public void normalize(T dataSet); + // public T normalize(T dataSet); // should we return normalized data set or perfrom inplace normalization in this interface +} + diff --git a/src/main/java/javax/visrec/ml/data/norm/Normalizer.java b/src/main/java/javax/visrec/ml/data/norm/Normalizer.java deleted file mode 100644 index af2e4a0..0000000 --- a/src/main/java/javax/visrec/ml/data/norm/Normalizer.java +++ /dev/null @@ -1,17 +0,0 @@ -package javax.visrec.ml.data.norm; - -import javax.visrec.ml.data.DataSet; - -/** - * Interface to perform normalization/scaling of columns in data set - * - * @author zoran - */ -public interface Normalizer { - // specify param to determine inplace or copy normalization? - public DataSet normalize(DataSet dataSet, boolean inplace); - - default DataSet normalize(DataSet dataSet) { - return normalize(dataSet, true); - } -} diff --git a/src/main/java/javax/visrec/ml/eval/EvaluationMetrics.java b/src/main/java/javax/visrec/ml/eval/EvaluationMetrics.java new file mode 100644 index 0000000..22586e6 --- /dev/null +++ b/src/main/java/javax/visrec/ml/eval/EvaluationMetrics.java @@ -0,0 +1,90 @@ +/** + * DeepNetts is pure Java Deep Learning Library with support for Backpropagation + * based learning and image recognition. + * + * Copyright (C) 2017 Zoran Sevarac + * + * This file is part of DeepNetts. + * + * DeepNetts is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see .package + * deepnetts.core; + */ + +package javax.visrec.ml.eval; + +import java.util.HashMap; + +/** + * Wrapper for constants and values for classifier and regressor evaluation metrics. + * + * @author Zoran Sevarac + */ +public class EvaluationMetrics { + + /** + * Mean value of sum of squared errors. + * Errors are squared in order to better explain variability, and take into account positive and negative errors. + * Regression metrics + */ + public final static String MEAN_ABSOLUTE_ERROR = "MeanAbsoluteError"; + public final static String MEAN_SQUARED_ERROR = "MeanSquaredError"; + public final static String ROOT_MEAN_SQUARED_ERROR = "RootMeanSquaredError"; + public final static String RESIDUAL_SQUARE_SUM = "ResidualSquareSum"; // RSS + + /** + * Estimation of standard deviation of prediction errors for some given data set. + * Smaller is better. + */ + public final static String RESIDUAL_STANDARD_ERROR = "ResidualStandardError"; + + /** + * Percent of variation explained by the regression model. + * 1 is good , 0 is bad, bigger is better. + */ + public final static String R_SQUARED = "RSquared"; + + /** + * Is there a relationship between inputs and predictions(outputs) at all. + * If there is a relationship, this value is greater then 1. + * When there is now relationship, this value is around 1. + */ + public final static String F_STAT = "FStatistics"; + + // p value? t statistics + + // Classification Metrics + public final static String ACCURACY = "Accuracy"; + public final static String PRECISION = "Precision"; + public final static String RECALL = "Recall"; + public final static String F1SCORE = "F1Score"; + + + private final HashMap values = new HashMap(); + + public float get(String key) { + return values.get(key); + } + + public void set(String key, float value) { + values.put(key, value); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + values.entrySet().stream().forEach((e) -> sb.append(e.getKey()).append(": ").append(e.getValue()).append(System.lineSeparator()) ); + + return sb.toString(); + } + +} diff --git a/src/main/java/javax/visrec/ml/eval/Evaluator.java b/src/main/java/javax/visrec/ml/eval/Evaluator.java index 50e3088..def121f 100644 --- a/src/main/java/javax/visrec/ml/eval/Evaluator.java +++ b/src/main/java/javax/visrec/ml/eval/Evaluator.java @@ -22,28 +22,25 @@ package javax.visrec.ml.eval; /** + * Evaluation method for specified types of machine learning model and data set. * All evaluators implement this interface. - * Maybe move to visrec.ml.eval - * CONSIDER: using more specific model type instead of general model class? Classifier, Regressor? * - * @param Model class - * @param Data set class + * @param Model class + * @param Data set class * * @author Zoran Sevarac * @since 1.0 */ @FunctionalInterface -public interface Evaluator { +public interface Evaluator { /** - * Evaluate model with specified data set. - * Return Map with performance metrics and values? - * {@code Map} ili {@code Map} + * Evaluate a model with specified test set. * * @param model A model to evaluate * @param testSet Data to use for evaluation - * @return performance measures of a model for the specified test set - */ // evaluatePerformance testDataSet - PerformanceMeasure evaluatePerformance(T1 model, T2 testSet); // kako ce da vrati rezultate testiranja - napraviti neku klasu za to? + * @return evaluation metrics for the model for the specified test set + */ + public EvaluationMetrics evaluate(MODEL_CLASS model, DATASET_CLASS testSet); } diff --git a/src/main/java/javax/visrec/ml/eval/PerformanceMeasure.java b/src/main/java/javax/visrec/ml/eval/PerformanceMeasure.java deleted file mode 100644 index 1ffcf83..0000000 --- a/src/main/java/javax/visrec/ml/eval/PerformanceMeasure.java +++ /dev/null @@ -1,36 +0,0 @@ -package javax.visrec.ml.eval; - -import java.util.HashMap; - -/** - * This class holds information about various classification performance measures. - * - * @author Zoran Sevarac - * @since 1.0 - */ -public class PerformanceMeasure { - public final static String MSE = "MSE"; - public final static String ACCURACY = "Accuracy"; - public final static String PRECISION = "Precision"; - public final static String RECALL = "Recall"; - public final static String F1SCORE = "F1Score"; - - private final HashMap values = new HashMap<>(); - - public float get(String key) { - return values.get(key); - } - - public void set(String key, float value) { - values.put(key, value); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - values.entrySet().stream().forEach((e) -> sb.append(e.getKey() + ": "+e.getValue() + System.lineSeparator()) ); - - return sb.toString(); - } - -} diff --git a/src/main/java/javax/visrec/regression/LogisticRegression.java b/src/main/java/javax/visrec/ml/regression/LogisticRegression.java similarity index 94% rename from src/main/java/javax/visrec/regression/LogisticRegression.java rename to src/main/java/javax/visrec/ml/regression/LogisticRegression.java index 56ce044..a4aa4c0 100644 --- a/src/main/java/javax/visrec/regression/LogisticRegression.java +++ b/src/main/java/javax/visrec/ml/regression/LogisticRegression.java @@ -1,4 +1,4 @@ -package javax.visrec.regression; +package javax.visrec.ml.regression; import javax.visrec.ml.classification.Classifier; diff --git a/src/main/java/javax/visrec/regression/Regressor.java b/src/main/java/javax/visrec/ml/regression/Regressor.java similarity index 86% rename from src/main/java/javax/visrec/regression/Regressor.java rename to src/main/java/javax/visrec/ml/regression/Regressor.java index 50dd681..8534d69 100644 --- a/src/main/java/javax/visrec/regression/Regressor.java +++ b/src/main/java/javax/visrec/ml/regression/Regressor.java @@ -1,4 +1,4 @@ -package javax.visrec.regression; +package javax.visrec.ml.regression; /** * Base interface for all regressors. diff --git a/src/main/java/javax/visrec/regression/SimpleLinearRegression.java b/src/main/java/javax/visrec/ml/regression/SimpleLinearRegression.java similarity index 93% rename from src/main/java/javax/visrec/regression/SimpleLinearRegression.java rename to src/main/java/javax/visrec/ml/regression/SimpleLinearRegression.java index 2e74a16..3497161 100644 --- a/src/main/java/javax/visrec/regression/SimpleLinearRegression.java +++ b/src/main/java/javax/visrec/ml/regression/SimpleLinearRegression.java @@ -1,6 +1,6 @@ -package javax.visrec.regression; +package javax.visrec.ml.regression; -import javax.visrec.regression.Regressor; +import javax.visrec.ml.regression.Regressor; /** * Simple linear regression finds the best possible straight line that tries to explain given training set. diff --git a/src/main/java/javax/visrec/ml/data/DataSets.java b/src/main/java/javax/visrec/thrash/DataSets.java similarity index 82% rename from src/main/java/javax/visrec/ml/data/DataSets.java rename to src/main/java/javax/visrec/thrash/DataSets.java index 7628cf3..335c760 100644 --- a/src/main/java/javax/visrec/ml/data/DataSets.java +++ b/src/main/java/javax/visrec/thrash/DataSets.java @@ -1,10 +1,12 @@ -package javax.visrec.ml.data; +package javax.visrec.thrash; -import javax.visrec.ml.data.norm.Normalizer; +import javax.visrec.ml.data.DataSet; +import javax.visrec.ml.data.Normalizer; /** - * Utility class that provides commmon operations on data sets - * @author zoran + * Utility methods that provides common operations on data sets. + * + * @author Zoran Sevarac */ public class DataSets { @@ -14,12 +16,12 @@ private DataSets() { } // maybe just provide DataSet.normalize(new MaxNormalizer) , and dataSet injects itself into normalizer // or even better norm= new MaxNormalizer(dataSet); norm.normalize(); also separate construction from analysis - public static DataSet normalize(DataSet dataSet, Normalizer norm) { - return norm.normalize(dataSet, false); + public static > void normalize(T dataSet, Normalizer norm) { + norm.normalize(dataSet); } // how about moving thes estatic methods to coresponding interface? -// public static DataSet normalizeMax(DataSet dataSet) { +// public static > void normalizeMax(DataSet dataSet) { // Normalizer norm = new MaxNormalizer(dataSet); // perform analysys of data set (find max values) // return norm.normalize(dataSet, false); // perfrom normalization and return as new data set // } @@ -41,7 +43,7 @@ public static DataSet normalize(DataSet dataSet, Normalizer norm) { // retrun data set whith ddesired statistical properties // zero mean, one std - public static DataSet standardize(DataSet dataSet) { // apply to all numer columns + public static > void standardize(T dataSet) { // apply to all numer columns // how will this method know about how to normalize specific type of elemeents? throw new UnsupportedOperationException("not implemented"); } diff --git a/src/main/java/javax/visrec/util/Model.java b/src/main/java/javax/visrec/util/Model.java index 5401872..a7946c8 100644 --- a/src/main/java/javax/visrec/util/Model.java +++ b/src/main/java/javax/visrec/util/Model.java @@ -18,7 +18,8 @@ import javax.visrec.ml.data.DataSet; /** - * + * Every model should provide methods for training and testing. + * Not used anywhere at the moment. * @author zoran */ public interface Model { From 3bf2426bc614dc702e338cdc54a83cdf6f1ac47e Mon Sep 17 00:00:00 2001 From: Zoran Sevarac Date: Mon, 2 Sep 2019 09:43:42 +0200 Subject: [PATCH 05/87] Added model provider --- .../java/javax/visrec/ml/data/BasicDataSet.java | 1 + .../javax/visrec/ml/regression/Regressor.java | 3 +-- .../ml/regression/SimpleLinearRegression.java | 4 ++-- src/main/java/javax/visrec/thrash/DataSets.java | 3 ++- .../visrec/{ml/data => thrash}/Normalizer.java | 3 ++- src/main/java/javax/visrec/util/Model.java | 15 --------------- .../java/javax/visrec/util/ModelProvider.java | 13 +++++++++++++ 7 files changed, 21 insertions(+), 21 deletions(-) rename src/main/java/javax/visrec/{ml/data => thrash}/Normalizer.java (83%) create mode 100644 src/main/java/javax/visrec/util/ModelProvider.java diff --git a/src/main/java/javax/visrec/ml/data/BasicDataSet.java b/src/main/java/javax/visrec/ml/data/BasicDataSet.java index cdcb26f..088cc25 100644 --- a/src/main/java/javax/visrec/ml/data/BasicDataSet.java +++ b/src/main/java/javax/visrec/ml/data/BasicDataSet.java @@ -80,4 +80,5 @@ public DataSet[] split(double... parts) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } + } \ No newline at end of file diff --git a/src/main/java/javax/visrec/ml/regression/Regressor.java b/src/main/java/javax/visrec/ml/regression/Regressor.java index 8534d69..62c8c81 100644 --- a/src/main/java/javax/visrec/ml/regression/Regressor.java +++ b/src/main/java/javax/visrec/ml/regression/Regressor.java @@ -3,14 +3,13 @@ /** * Base interface for all regressors. * Regressors try to predict a continual value(s) (a decimal number) based on a set of inputs. - * + * Rename to ValueEstimator? * @author Zoran Sevarac * @param type of inputs / features * @param return/result type */ public interface Regressor { - // rename to estimate? R predict(I inputs); } diff --git a/src/main/java/javax/visrec/ml/regression/SimpleLinearRegression.java b/src/main/java/javax/visrec/ml/regression/SimpleLinearRegression.java index 3497161..5960d69 100644 --- a/src/main/java/javax/visrec/ml/regression/SimpleLinearRegression.java +++ b/src/main/java/javax/visrec/ml/regression/SimpleLinearRegression.java @@ -1,13 +1,13 @@ package javax.visrec.ml.regression; -import javax.visrec.ml.regression.Regressor; +import javax.visrec.util.ModelProvider; /** * Simple linear regression finds the best possible straight line that tries to explain given training set. * * @author zoran */ -public abstract class SimpleLinearRegression implements Regressor { +public abstract class SimpleLinearRegression implements Regressor, ModelProvider { private MODEL_CLASS model; diff --git a/src/main/java/javax/visrec/thrash/DataSets.java b/src/main/java/javax/visrec/thrash/DataSets.java index 335c760..175cb8c 100644 --- a/src/main/java/javax/visrec/thrash/DataSets.java +++ b/src/main/java/javax/visrec/thrash/DataSets.java @@ -1,7 +1,6 @@ package javax.visrec.thrash; import javax.visrec.ml.data.DataSet; -import javax.visrec.ml.data.Normalizer; /** * Utility methods that provides common operations on data sets. @@ -12,6 +11,8 @@ public class DataSets { private DataSets() { } + // method to get basic statistics - summary() mead median, mi , max std, qt + // scale values // maybe just provide DataSet.normalize(new MaxNormalizer) , and dataSet injects itself into normalizer // or even better norm= new MaxNormalizer(dataSet); norm.normalize(); also separate construction from analysis diff --git a/src/main/java/javax/visrec/ml/data/Normalizer.java b/src/main/java/javax/visrec/thrash/Normalizer.java similarity index 83% rename from src/main/java/javax/visrec/ml/data/Normalizer.java rename to src/main/java/javax/visrec/thrash/Normalizer.java index 6e30064..95ce23f 100644 --- a/src/main/java/javax/visrec/ml/data/Normalizer.java +++ b/src/main/java/javax/visrec/thrash/Normalizer.java @@ -1,5 +1,6 @@ -package javax.visrec.ml.data; +package javax.visrec.thrash; +import javax.visrec.ml.data.DataSet; import javax.visrec.ml.data.DataSet; /** diff --git a/src/main/java/javax/visrec/util/Model.java b/src/main/java/javax/visrec/util/Model.java index a7946c8..19b4e1e 100644 --- a/src/main/java/javax/visrec/util/Model.java +++ b/src/main/java/javax/visrec/util/Model.java @@ -1,18 +1,3 @@ -/* - * Copyright 2019 zoran. - * - * Licensed 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 javax.visrec.util; import javax.visrec.ml.data.DataSet; diff --git a/src/main/java/javax/visrec/util/ModelProvider.java b/src/main/java/javax/visrec/util/ModelProvider.java new file mode 100644 index 0000000..b2537ba --- /dev/null +++ b/src/main/java/javax/visrec/util/ModelProvider.java @@ -0,0 +1,13 @@ +package javax.visrec.util; + +/** + * This interface should be implemented if we want to allow access to underlying ML model + * @author Zoran + * @param + */ +public interface ModelProvider { + + M getModel(); + // also provide setModel to allow model injection? + +} From 9ba9ca77890d96717503e2b002165ba6921651b6 Mon Sep 17 00:00:00 2001 From: Kevin Berendsen Date: Tue, 3 Sep 2019 08:28:22 +0200 Subject: [PATCH 06/87] Marked interfaces and methods for removal --- .../java/javax/visrec/ml/classification/ClassifierBuilder.java | 2 ++ src/main/java/javax/visrec/spi/BuilderService.java | 2 ++ src/main/java/javax/visrec/spi/ServiceProvider.java | 2 ++ 3 files changed, 6 insertions(+) diff --git a/src/main/java/javax/visrec/ml/classification/ClassifierBuilder.java b/src/main/java/javax/visrec/ml/classification/ClassifierBuilder.java index 6d83d4a..f8e609d 100644 --- a/src/main/java/javax/visrec/ml/classification/ClassifierBuilder.java +++ b/src/main/java/javax/visrec/ml/classification/ClassifierBuilder.java @@ -7,7 +7,9 @@ * * @author Kevin Berendsen * @since 1.0 + * @Deprecated for removal */ +@Deprecated public abstract class ClassifierBuilder { protected ClassifierBuilder() { diff --git a/src/main/java/javax/visrec/spi/BuilderService.java b/src/main/java/javax/visrec/spi/BuilderService.java index ac8495d..fc147a5 100644 --- a/src/main/java/javax/visrec/spi/BuilderService.java +++ b/src/main/java/javax/visrec/spi/BuilderService.java @@ -7,7 +7,9 @@ * * @author Kevin Berendsen * @since 1.0 + * @Deprecated for removal */ +@Deprecated public interface BuilderService { /** diff --git a/src/main/java/javax/visrec/spi/ServiceProvider.java b/src/main/java/javax/visrec/spi/ServiceProvider.java index 5599026..80b2049 100644 --- a/src/main/java/javax/visrec/spi/ServiceProvider.java +++ b/src/main/java/javax/visrec/spi/ServiceProvider.java @@ -38,7 +38,9 @@ public int getPriority() { /** * Get the {@link BuilderService} * @return builder service. + * @Deprecated for removal */ + @Deprecated public abstract BuilderService getBuilderService(); /** From 759d61d0680c5c876a394fe00b56fed455a6516c Mon Sep 17 00:00:00 2001 From: Kevin Berendsen Date: Tue, 3 Sep 2019 19:48:16 +0200 Subject: [PATCH 07/87] Refactored newBuilder() to builder() --- pom.xml | 4 ++-- .../java/javax/visrec/ml/classification/ImageClassifier.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 0a28b09..c16e4c5 100644 --- a/pom.xml +++ b/pom.xml @@ -72,7 +72,7 @@ - + org.sonatype.plugins diff --git a/src/main/java/javax/visrec/ml/classification/ImageClassifier.java b/src/main/java/javax/visrec/ml/classification/ImageClassifier.java index df8ceae..462830c 100644 --- a/src/main/java/javax/visrec/ml/classification/ImageClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/ImageClassifier.java @@ -6,7 +6,7 @@ public interface ImageClassifier extends Classifier { - static ImageClassifier.Builder newBuilder() { + static ImageClassifier.Builder builder() { return new Builder(); } From bf444b391664c7c1fedbaf2a9b49e215ea40d80e Mon Sep 17 00:00:00 2001 From: Zoran Sevarac Date: Thu, 5 Sep 2019 08:59:05 +0200 Subject: [PATCH 08/87] Add BinaryClassifier and MultiClassClassifier and refctored --- .../AbstractMultiClassClassifier.java | 15 +++++++++++++ .../ml/classification/BinaryClassifier.java | 10 +++++++++ .../visrec/ml/classification/Classifier.java | 5 ++--- .../ml/classification/EnsambleClassifier.java | 2 +- .../ml/classification/ImageClassifier.java | 6 ++--- .../classification/MultiClassClassifier.java | 22 ++++++------------- 6 files changed, 38 insertions(+), 22 deletions(-) create mode 100644 src/main/java/javax/visrec/ml/classification/AbstractMultiClassClassifier.java create mode 100644 src/main/java/javax/visrec/ml/classification/BinaryClassifier.java diff --git a/src/main/java/javax/visrec/ml/classification/AbstractMultiClassClassifier.java b/src/main/java/javax/visrec/ml/classification/AbstractMultiClassClassifier.java new file mode 100644 index 0000000..08acb1e --- /dev/null +++ b/src/main/java/javax/visrec/ml/classification/AbstractMultiClassClassifier.java @@ -0,0 +1,15 @@ +package javax.visrec.ml.classification; + +public abstract class AbstractMultiClassClassifier implements MultiClassClassifier { + + private MODEL_CLASS model; + + public MODEL_CLASS getModel() { + return model; + } + + protected void setModel(MODEL_CLASS model) { + this.model = model; + } + +} diff --git a/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java b/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java new file mode 100644 index 0000000..612347a --- /dev/null +++ b/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java @@ -0,0 +1,10 @@ +package javax.visrec.ml.classification; + +/** + * + * @author Zoran + */ +public interface BinaryClassifier extends Classifier { + + +} diff --git a/src/main/java/javax/visrec/ml/classification/Classifier.java b/src/main/java/javax/visrec/ml/classification/Classifier.java index 158dd1a..ee750a2 100644 --- a/src/main/java/javax/visrec/ml/classification/Classifier.java +++ b/src/main/java/javax/visrec/ml/classification/Classifier.java @@ -17,12 +17,11 @@ public interface Classifier { /** - * Classifies specified instance and returns classification results as - * map with class names and corresponding classification scores. + * Classifies specified instance of type T and returns classification results of type R. * * @param input some instance to classify * @return classification results for the specified instance */ - Map classify(T input); + R classify(T input); } diff --git a/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java b/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java index f9b7b2b..484e775 100644 --- a/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java @@ -18,7 +18,7 @@ public final class EnsambleClassifier implements Classifier { private final Map> classifiers = new HashMap<>(); @Override - public Map classify(T input) { + public R classify(T input) { classifiers.values().stream() // or parallelStream .forEach(c -> c.classify(input)); // get the highest class frequency diff --git a/src/main/java/javax/visrec/ml/classification/ImageClassifier.java b/src/main/java/javax/visrec/ml/classification/ImageClassifier.java index 239a0bd..810287d 100644 --- a/src/main/java/javax/visrec/ml/classification/ImageClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/ImageClassifier.java @@ -1,12 +1,12 @@ package javax.visrec.ml.classification; import javax.visrec.spi.ServiceProvider; -import java.awt.image.BufferedImage; import java.io.File; +import java.util.Map; -public interface ImageClassifier extends Classifier { +public interface ImageClassifier extends Classifier> { - static ImageClassifier.Builder newBuilder() { + static ImageClassifier.Builder builder() { return new Builder(); } diff --git a/src/main/java/javax/visrec/ml/classification/MultiClassClassifier.java b/src/main/java/javax/visrec/ml/classification/MultiClassClassifier.java index 7269a96..7671902 100644 --- a/src/main/java/javax/visrec/ml/classification/MultiClassClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/MultiClassClassifier.java @@ -1,15 +1,7 @@ -package javax.visrec.ml.classification; - -public abstract class MultiClassClassifier implements Classifier { - - private MODEL_CLASS model; - - public MODEL_CLASS getModel() { - return model; - } - - protected void setModel(MODEL_CLASS model) { - this.model = model; - } - -} +package javax.visrec.ml.classification; + +import java.util.Map; + +public interface MultiClassClassifier extends Classifier> { + +} From 4b3e3b7433c1a67684c51240849cba360a7537f9 Mon Sep 17 00:00:00 2001 From: Zoran Sevarac Date: Thu, 5 Sep 2019 09:36:10 +0200 Subject: [PATCH 09/87] Fixes in api after introducing BinaryClassifier and MultiClassClassifier --- .../java/javax/visrec/ml/classification/BinaryClassifier.java | 4 +++- .../javax/visrec/ml/classification/MultiClassClassifier.java | 2 +- .../java/javax/visrec/ml/regression/LogisticRegression.java | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java b/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java index 612347a..1abd9aa 100644 --- a/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java @@ -1,8 +1,10 @@ package javax.visrec.ml.classification; /** - * + * Binary classifier classifies object into one of two categories (for example: true/false, yes/no, red/blue, spam/not-spam, fraud/not-fraud) + * * @author Zoran + * @param type of object to classify */ public interface BinaryClassifier extends Classifier { diff --git a/src/main/java/javax/visrec/ml/classification/MultiClassClassifier.java b/src/main/java/javax/visrec/ml/classification/MultiClassClassifier.java index 7671902..621cd54 100644 --- a/src/main/java/javax/visrec/ml/classification/MultiClassClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/MultiClassClassifier.java @@ -2,6 +2,6 @@ import java.util.Map; -public interface MultiClassClassifier extends Classifier> { +public interface MultiClassClassifier extends Classifier> { } diff --git a/src/main/java/javax/visrec/ml/regression/LogisticRegression.java b/src/main/java/javax/visrec/ml/regression/LogisticRegression.java index a4aa4c0..4cc6201 100644 --- a/src/main/java/javax/visrec/ml/regression/LogisticRegression.java +++ b/src/main/java/javax/visrec/ml/regression/LogisticRegression.java @@ -1,6 +1,6 @@ package javax.visrec.ml.regression; -import javax.visrec.ml.classification.Classifier; +import javax.visrec.ml.classification.BinaryClassifier; /** * This class performs basic binary classification - mapping of specified input to true/false with probability. @@ -8,7 +8,7 @@ * @author Zoran Sevarac * @param Implementation class of underlying machine learning model */ -public abstract class LogisticRegression implements Classifier{ +public abstract class LogisticRegression implements BinaryClassifier{ private MODEL_CLASS model; From 8f76c01b08edf3a6f79f8b4504b73e877fb3e80d Mon Sep 17 00:00:00 2001 From: Zoran Sevarac Date: Thu, 5 Sep 2019 10:32:33 +0200 Subject: [PATCH 10/87] restored normaelizer --- .../java/javax/visrec/{thrash => ml/data}/Normalizer.java | 6 +----- src/main/java/javax/visrec/thrash/DataSets.java | 1 + 2 files changed, 2 insertions(+), 5 deletions(-) rename src/main/java/javax/visrec/{thrash => ml/data}/Normalizer.java (50%) diff --git a/src/main/java/javax/visrec/thrash/Normalizer.java b/src/main/java/javax/visrec/ml/data/Normalizer.java similarity index 50% rename from src/main/java/javax/visrec/thrash/Normalizer.java rename to src/main/java/javax/visrec/ml/data/Normalizer.java index 95ce23f..4470cc1 100644 --- a/src/main/java/javax/visrec/thrash/Normalizer.java +++ b/src/main/java/javax/visrec/ml/data/Normalizer.java @@ -1,7 +1,4 @@ -package javax.visrec.thrash; - -import javax.visrec.ml.data.DataSet; -import javax.visrec.ml.data.DataSet; +package javax.visrec.ml.data; /** * Interface to perform normalization/scaling of data set @@ -11,6 +8,5 @@ */ public interface Normalizer> { public void normalize(T dataSet); - // public T normalize(T dataSet); // should we return normalized data set or perfrom inplace normalization in this interface } diff --git a/src/main/java/javax/visrec/thrash/DataSets.java b/src/main/java/javax/visrec/thrash/DataSets.java index 175cb8c..e275aea 100644 --- a/src/main/java/javax/visrec/thrash/DataSets.java +++ b/src/main/java/javax/visrec/thrash/DataSets.java @@ -1,5 +1,6 @@ package javax.visrec.thrash; +import javax.visrec.ml.data.Normalizer; import javax.visrec.ml.data.DataSet; /** From da7302efae28d015b39acb4515e983423433e934 Mon Sep 17 00:00:00 2001 From: Zoran Sevarac Date: Sat, 7 Sep 2019 11:11:12 +0200 Subject: [PATCH 11/87] few comments and polishing --- pom.xml | 7 ++-- .../AbstractMultiClassClassifier.java | 11 ++++++- .../visrec/ml/classification/Classifier.java | 7 ++-- .../classification/MultiClassClassifier.java | 9 ++++++ .../visrec/ml/eval/EvaluationMetrics.java | 32 ++++++++++++++----- .../java/javax/visrec/util/ModelProvider.java | 5 +-- 6 files changed, 53 insertions(+), 18 deletions(-) diff --git a/pom.xml b/pom.xml index c16e4c5..3efcb26 100644 --- a/pom.xml +++ b/pom.xml @@ -72,12 +72,13 @@ - + org.sonatype.plugins diff --git a/src/main/java/javax/visrec/ml/classification/AbstractMultiClassClassifier.java b/src/main/java/javax/visrec/ml/classification/AbstractMultiClassClassifier.java index 08acb1e..581e443 100644 --- a/src/main/java/javax/visrec/ml/classification/AbstractMultiClassClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/AbstractMultiClassClassifier.java @@ -1,6 +1,15 @@ package javax.visrec.ml.classification; -public abstract class AbstractMultiClassClassifier implements MultiClassClassifier { +import javax.visrec.util.ModelProvider; + +/** + * + * @author Zoran + * @param class of machine learning model backend + * @param + * @param + */ +public abstract class AbstractMultiClassClassifier implements MultiClassClassifier, ModelProvider { private MODEL_CLASS model; diff --git a/src/main/java/javax/visrec/ml/classification/Classifier.java b/src/main/java/javax/visrec/ml/classification/Classifier.java index ee750a2..c500567 100644 --- a/src/main/java/javax/visrec/ml/classification/Classifier.java +++ b/src/main/java/javax/visrec/ml/classification/Classifier.java @@ -1,7 +1,5 @@ package javax.visrec.ml.classification; -import java.util.Map; - /** * Generic classifier interface, that all classifiers should implement. Provides * a method to classify instances of some class. Implementations should specify @@ -9,8 +7,9 @@ * * @author Zoran Sevarac * @param type of input objects to classify (eg. User, Product, Transaction, Image, etc.) - * @param type of classification result map eg. String is commonly used , but Enum or Boolean as well. - * In general Enums should be used when there is a small number of categories and String for more categories. + * @param type of classification result. + * @see BinaryClassifier + * @see MultiClassClassifier * @since 1.0 */ @FunctionalInterface diff --git a/src/main/java/javax/visrec/ml/classification/MultiClassClassifier.java b/src/main/java/javax/visrec/ml/classification/MultiClassClassifier.java index 621cd54..e1f070c 100644 --- a/src/main/java/javax/visrec/ml/classification/MultiClassClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/MultiClassClassifier.java @@ -2,6 +2,15 @@ import java.util.Map; +/** + * Machine learning algorithms that provide multi class classification. + * Multi class classification assigns input object to one of several possible category/class. + * For example: is it a cat, a dog or a bird? + * + * @author Zoran Sevarac + * @param Type of input objects (which are being classified) + * @param Type of classifier return value - type of object which represent category class. + */ public interface MultiClassClassifier extends Classifier> { } diff --git a/src/main/java/javax/visrec/ml/eval/EvaluationMetrics.java b/src/main/java/javax/visrec/ml/eval/EvaluationMetrics.java index 22586e6..0e429c8 100644 --- a/src/main/java/javax/visrec/ml/eval/EvaluationMetrics.java +++ b/src/main/java/javax/visrec/ml/eval/EvaluationMetrics.java @@ -60,16 +60,25 @@ public class EvaluationMetrics { */ public final static String F_STAT = "FStatistics"; - // p value? t statistics + // TODO: p value, t statistics // Classification Metrics - public final static String ACCURACY = "Accuracy"; - public final static String PRECISION = "Precision"; - public final static String RECALL = "Recall"; - public final static String F1SCORE = "F1Score"; - + public final static String ACCURACY = "Accuracy"; + public final static String PRECISION = "Precision"; + public final static String RECALL = "Recall"; + public final static String F1SCORE = "F1Score"; + // private final HashMap values = new HashMap(); + + private final static HashMap description = new HashMap(); + static { + description.put(ACCURACY, "How often is classifier correct in total"); + description.put(PRECISION, "How often is classifier correct when it gives positive prediction"); + description.put(RECALL, "When it is actually positive class, how often does it give positive prediction"); + description.put(F1SCORE, "Average of precision and recall"); + } + public float get(String key) { return values.get(key); @@ -82,8 +91,15 @@ public void set(String key, float value) { @Override public String toString() { StringBuilder sb = new StringBuilder(); - values.entrySet().stream().forEach((e) -> sb.append(e.getKey()).append(": ").append(e.getValue()).append(System.lineSeparator()) ); - + values.entrySet().stream().forEach((e) -> { sb.append(e.getKey()).append(": ") + .append(e.getValue()); + if (description.get(e.getKey())!=null) + sb.append(" (") + .append(description.get(e.getKey())) + .append(")"); + sb.append(System.lineSeparator()); + }); + // todo: also append decsripton return sb.toString(); } diff --git a/src/main/java/javax/visrec/util/ModelProvider.java b/src/main/java/javax/visrec/util/ModelProvider.java index b2537ba..6c1b9b6 100644 --- a/src/main/java/javax/visrec/util/ModelProvider.java +++ b/src/main/java/javax/visrec/util/ModelProvider.java @@ -8,6 +8,7 @@ public interface ModelProvider { M getModel(); - // also provide setModel to allow model injection? - + + // also provide public setModel to allow model injection? + } From 59ec2d583abafd2009c084a150d6925ba2dcfe68 Mon Sep 17 00:00:00 2001 From: Zoran Sevarac Date: Tue, 10 Sep 2019 15:29:32 +0200 Subject: [PATCH 12/87] minor polishing --- .../javax/visrec/ml/classification/BinaryClassifier.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java b/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java index 1abd9aa..0f0c21c 100644 --- a/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java @@ -1,12 +1,13 @@ package javax.visrec.ml.classification; /** - * Binary classifier classifies object into one of two categories (for example: true/false, yes/no, red/blue, spam/not-spam, fraud/not-fraud) + * Binary classifier classifies object into one of two categories (for example: true/false, yes/no, red/blue, spam/not-spam, fraud/not-fraud). + * Returns a probability that input object belongs to one of two classes. * - * @author Zoran + * @author Zoran Sevarac * @param type of object to classify */ public interface BinaryClassifier extends Classifier { - + } From a403a85ece36752a4a435ce2adbe8b31d48e2de4 Mon Sep 17 00:00:00 2001 From: Zoran Sevarac Date: Tue, 22 Oct 2019 20:33:27 +0200 Subject: [PATCH 13/87] Added service registry --- .../javax/visrec/AbstractImageClassifier.java | 6 +-- .../javax/visrec/ml/data/BasicDataSet.java | 6 +-- .../javax/visrec/spi/ServiceRegistry.java | 46 +++++++++++++++++++ 3 files changed, 51 insertions(+), 7 deletions(-) create mode 100644 src/main/java/javax/visrec/spi/ServiceRegistry.java diff --git a/src/main/java/javax/visrec/AbstractImageClassifier.java b/src/main/java/javax/visrec/AbstractImageClassifier.java index b247dd2..fda970b 100644 --- a/src/main/java/javax/visrec/AbstractImageClassifier.java +++ b/src/main/java/javax/visrec/AbstractImageClassifier.java @@ -10,7 +10,6 @@ import javax.visrec.ml.classification.Classifier; import javax.visrec.ml.classification.ImageClassifier; import javax.visrec.spi.ServiceProvider; -import javax.visrec.util.Builder; /** * Skeleton abstract class to make it easier to implement image classifier. @@ -59,6 +58,8 @@ public Map classify(InputStream inStream) throws IOException { IMAGE_CLASS image = imageFactory.getImage(inStream); return classify(image); } + + // todo: provide get top 1, 3, 5 results; sort and get // do we need this now, when impl is loaded using service provider? // Kevin and Zoran disussed: probably not needed now when we have service provider impl, and we dont want to allow user to mess with it @@ -71,8 +72,7 @@ public MODEL_CLASS getModel() { } protected void setModel(MODEL_CLASS model) { - Objects.requireNonNull(model, "Model cannot bu null!"); - this.model = model; + this.model = Objects.requireNonNull(model, "Model cannot bu null!"); } public float getThreshold() { diff --git a/src/main/java/javax/visrec/ml/data/BasicDataSet.java b/src/main/java/javax/visrec/ml/data/BasicDataSet.java index 088cc25..8b17038 100644 --- a/src/main/java/javax/visrec/ml/data/BasicDataSet.java +++ b/src/main/java/javax/visrec/ml/data/BasicDataSet.java @@ -2,9 +2,7 @@ import java.util.ArrayList; import java.util.Arrays; -import java.util.Iterator; import java.util.List; -import java.util.Random; import java.util.stream.Collectors; /** @@ -19,8 +17,8 @@ public class BasicDataSet implements DataSet { /** * List of data set items in this data set */ - protected List items; //this should be a data frame map of lists, even better us evalue types! - private Column[] columns; + protected List items; //this should be a data frame map of lists, even better use value types! + private Column[] columns; // this should be a list protected BasicDataSet() { items = new ArrayList<>(); diff --git a/src/main/java/javax/visrec/spi/ServiceRegistry.java b/src/main/java/javax/visrec/spi/ServiceRegistry.java new file mode 100644 index 0000000..85f07d5 --- /dev/null +++ b/src/main/java/javax/visrec/spi/ServiceRegistry.java @@ -0,0 +1,46 @@ +/* + * Copyright 2019 Zoran. + * + * Licensed 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 javax.visrec.spi; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * Registry for all ML algorithms provided by this implementation. + * + * @author Zoran Sevarac + */ +public class ServiceRegistry { + + private final Map, Object> providers = new HashMap(); + + public void registerServiceProvider(Class service, T provider) { + providers.put(service, provider); + } + + public void deregisterServiceProvider(Class service, T provider) { + providers.remove(service, provider); + } + + public Iterator getAllProviders() { + return providers.values().iterator(); + } + + public T getProvider(Class service) { + return service.cast(providers.get(service)); + } +} From c74233d453498590e1cba3579c675c44e37d27e5 Mon Sep 17 00:00:00 2001 From: Zoran Sevarac Date: Sun, 27 Oct 2019 12:17:01 +0100 Subject: [PATCH 14/87] deprecating DataSets --- src/main/java/javax/visrec/{thrash => util}/DataSets.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) rename src/main/java/javax/visrec/{thrash => util}/DataSets.java (93%) diff --git a/src/main/java/javax/visrec/thrash/DataSets.java b/src/main/java/javax/visrec/util/DataSets.java similarity index 93% rename from src/main/java/javax/visrec/thrash/DataSets.java rename to src/main/java/javax/visrec/util/DataSets.java index e275aea..d43c25d 100644 --- a/src/main/java/javax/visrec/thrash/DataSets.java +++ b/src/main/java/javax/visrec/util/DataSets.java @@ -1,13 +1,15 @@ -package javax.visrec.thrash; +package javax.visrec.util; import javax.visrec.ml.data.Normalizer; import javax.visrec.ml.data.DataSet; /** * Utility methods that provides common operations on data sets. + * Will probably be deprecated or figure out how to expose implementation specific operations * * @author Zoran Sevarac */ +@Deprecated public class DataSets { private DataSets() { } From 7a7bc8ce3187919f5ca2886d866b3801cd4a22df Mon Sep 17 00:00:00 2001 From: Deep Netts Date: Tue, 12 Nov 2019 19:34:14 +0100 Subject: [PATCH 15/87] Update README.md --- README.md | 40 ++-------------------------------------- 1 file changed, 2 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 064b73a..ffc4880 100644 --- a/README.md +++ b/README.md @@ -1,41 +1,5 @@ # visrec-api Specification of standard Visual Recognition API for Java (JSR work in progress) -## Examples -TODO General example text - -There's support for the following build tools: -* Maven -* Gradle -* Gradle Wrapper - -It's mandatory for the `visrec-deepnetts-impl` to install DeepNetts in your local maven repository which -can be done by cloning the [GitHub repository](https://github.com/sevarac/deepnetts) and `mvn install` in the `deepnetts-core/` directory of the project. -It's required to have maven installed on your machine. - -Note: Some of the examples are using specific maven repositories for specific libraries. If you're -behind a cooperate firewall, some example implementations may not work. - -### Maven -TODO Instructions here. - -### Gradle -Gradle 4.7 has been actively used to test the examples. We recommend to use Gradle 4.7 or higher to -run the examples. - -Go to directory of the example and perform the following command: -> `gradle run` - -OR remain in the root directory of the project and perform the following command: -> `gradle :visrec-deepnetts-impl:run` - -You can change `visrec-deepnetts-impl` into any of the other examples' directory. - -### Gradle Wrapper -Gradle 4.7 Wrapper has been actively used to test the examples. We recommend to use Gradle 4.7 Wrapper or higher to -run the examples. Gradle Wrapper is included into the project. - -Remain in the root directory of the project and perform the following command: -> `gradlew :visrec-deepnetts-impl:run` - -You can change `visrec-deepnetts-impl` into any of the other examples' directory. \ No newline at end of file +# Getting Started +https://github.com/JavaVisRec/visrec-api/wiki/Getting-Started-Guide From ce2426722ae25cdfd52222b92a3b42cabe8541b1 Mon Sep 17 00:00:00 2001 From: Zoran Sevarac Date: Sat, 16 Nov 2019 19:21:40 +0100 Subject: [PATCH 16/87] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ffc4880..7f0c7f4 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ # visrec-api -Specification of standard Visual Recognition API for Java (JSR work in progress) +This repo contains specification of standard Visual Recognition API for Java (JSR381) # Getting Started +For step by step guide and additional info see getting started guide at https://github.com/JavaVisRec/visrec-api/wiki/Getting-Started-Guide From 110dbc31596b26854bcd9be7e90bf36bafd444ef Mon Sep 17 00:00:00 2001 From: Zoran Sevarac Date: Sat, 16 Nov 2019 19:21:53 +0100 Subject: [PATCH 17/87] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 7f0c7f4..40c54d4 100644 --- a/README.md +++ b/README.md @@ -3,4 +3,5 @@ This repo contains specification of standard Visual Recognition API for Java (JS # Getting Started For step by step guide and additional info see getting started guide at + https://github.com/JavaVisRec/visrec-api/wiki/Getting-Started-Guide From e14a6998ecc6237d16bbdf5259b42e8f715067cf Mon Sep 17 00:00:00 2001 From: Zoran Sevarac Date: Sat, 16 Nov 2019 19:22:13 +0100 Subject: [PATCH 18/87] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 40c54d4..d41c52f 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # visrec-api This repo contains specification of standard Visual Recognition API for Java (JSR381) -# Getting Started +## Getting Started For step by step guide and additional info see getting started guide at https://github.com/JavaVisRec/visrec-api/wiki/Getting-Started-Guide From c76f4d90b61ff95fa89eaf361da34b6fe6537d21 Mon Sep 17 00:00:00 2001 From: Kevin Berendsen Date: Mon, 18 Nov 2019 16:43:17 +0100 Subject: [PATCH 19/87] Implemented building blocks and refactored the way of initialising image classifiers --- .../javax/visrec/AbstractImageClassifier.java | 44 ++++++++------- .../visrec/ml/ClassificationException.java | 20 +++++++ .../ml/ClassifierCreationException.java | 20 +++++++ .../ml/classification/ImageClassifier.java | 54 +++++++++++++++++-- .../visrec/ml/detection/ObjectDetector.java | 3 +- .../javax/visrec/spi/ClassifierService.java | 4 +- src/main/java/javax/visrec/util/Builder.java | 5 +- 7 files changed, 124 insertions(+), 26 deletions(-) create mode 100644 src/main/java/javax/visrec/ml/ClassificationException.java create mode 100644 src/main/java/javax/visrec/ml/ClassifierCreationException.java diff --git a/src/main/java/javax/visrec/AbstractImageClassifier.java b/src/main/java/javax/visrec/AbstractImageClassifier.java index b247dd2..a8582bb 100644 --- a/src/main/java/javax/visrec/AbstractImageClassifier.java +++ b/src/main/java/javax/visrec/AbstractImageClassifier.java @@ -1,5 +1,8 @@ package javax.visrec; +import javax.visrec.ml.ClassificationException; +import javax.visrec.ml.classification.ImageClassifier; +import javax.visrec.spi.ServiceProvider; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; @@ -7,10 +10,6 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; -import javax.visrec.ml.classification.Classifier; -import javax.visrec.ml.classification.ImageClassifier; -import javax.visrec.spi.ServiceProvider; -import javax.visrec.util.Builder; /** * Skeleton abstract class to make it easier to implement image classifier. @@ -19,26 +18,23 @@ * This class solves the problem of using various implementation of images and machine learning models in Java, * and provides standard Classifier API for clients. * - * By default the type of key in the Map the {@link Classifier} is {@code String} + * By default the type of key in the Map the {@link ImageClassifier} is {@code String} * * @author Zoran Sevarac * - * @param class of images * @param class of machine learning model - * - * */ -public abstract class AbstractImageClassifier implements ImageClassifier { // could also implement binary classifier +public abstract class AbstractImageClassifier implements ImageClassifier { // could also implement binary classifier - private ImageFactory imageFactory; // image factory impl for the specified image class + private ImageFactory imageFactory; // image factory impl for the specified image class private MODEL_CLASS model; // the model could be injected from machine learning container? private float threshold; // this should ba a part of every classifier - protected AbstractImageClassifier(@Deprecated final Class cls, final MODEL_CLASS model) { - final Optional> optionalImageFactory = ServiceProvider.current() + protected AbstractImageClassifier(final MODEL_CLASS model) { + final Optional> optionalImageFactory = ServiceProvider.current() .getImageFactoryService() - .getByImageType(cls); // BufferedImage.class + .getByImageType(BufferedImage.class); if (!optionalImageFactory.isPresent()) { throw new IllegalArgumentException(String.format("Could not find ImageFactory by '%s'", BufferedImage.class.getName())); } @@ -46,17 +42,29 @@ protected AbstractImageClassifier(@Deprecated final Class cls, fina setModel(model); } - public ImageFactory getImageFactory() { + public ImageFactory getImageFactory() { return imageFactory; } - public Map classify(File file) throws IOException { - IMAGE_CLASS image = imageFactory.getImage(file); + @Override + public Map classify(File file) throws ClassificationException { + BufferedImage image; + try { + image = imageFactory.getImage(file); + } catch (IOException e) { + throw new ClassificationException("Couldn't transform input into a BufferedImage", e); + } return classify(image); } - public Map classify(InputStream inStream) throws IOException { - IMAGE_CLASS image = imageFactory.getImage(inStream); + @Override + public Map classify(InputStream inputStream) throws ClassificationException { + BufferedImage image; + try { + image = imageFactory.getImage(inputStream); + } catch (IOException e) { + throw new ClassificationException("Couldn't transform input into a BufferedImage", e); + } return classify(image); } diff --git a/src/main/java/javax/visrec/ml/ClassificationException.java b/src/main/java/javax/visrec/ml/ClassificationException.java new file mode 100644 index 0000000..6cd6b31 --- /dev/null +++ b/src/main/java/javax/visrec/ml/ClassificationException.java @@ -0,0 +1,20 @@ +package javax.visrec.ml; + +/** + * Exception thrown if anything fails in classifying input using a classifier. + * + * @author Kevin Berendsen + * @since 1.0 + */ +public class ClassificationException extends Exception { + + /** + * Creates a new instance of the exception + * @param message additional message of the cause. + * @param throwable caused by throwable. + */ + public ClassificationException(String message, Throwable throwable) { + super(message, throwable); + } + +} diff --git a/src/main/java/javax/visrec/ml/ClassifierCreationException.java b/src/main/java/javax/visrec/ml/ClassifierCreationException.java new file mode 100644 index 0000000..96b4e9e --- /dev/null +++ b/src/main/java/javax/visrec/ml/ClassifierCreationException.java @@ -0,0 +1,20 @@ +package javax.visrec.ml; + +/** + * Exception thrown if anything fails in the creation of a classifier. + * + * @author Kevin Berendsen + * @since 1.0 + */ +public class ClassifierCreationException extends Exception { + + /** + * Creates a new instance of the exception + * @param message additional message of the cause. + * @param throwable caused by throwable. + */ + public ClassifierCreationException(String message, Throwable throwable) { + super(message, throwable); + } + +} diff --git a/src/main/java/javax/visrec/ml/classification/ImageClassifier.java b/src/main/java/javax/visrec/ml/classification/ImageClassifier.java index 810287d..092f6b7 100644 --- a/src/main/java/javax/visrec/ml/classification/ImageClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/ImageClassifier.java @@ -1,10 +1,22 @@ package javax.visrec.ml.classification; +import javax.visrec.ml.ClassificationException; +import javax.visrec.ml.ClassifierCreationException; import javax.visrec.spi.ServiceProvider; +import java.awt.image.BufferedImage; import java.io.File; +import java.io.InputStream; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.Map; -public interface ImageClassifier extends Classifier> { +public interface ImageClassifier { + + Map classify(BufferedImage input) throws ClassificationException; + + Map classify(File input) throws ClassificationException; + + Map classify(InputStream input) throws ClassificationException; static ImageClassifier.Builder builder() { return new Builder(); @@ -14,15 +26,21 @@ class BuildingBlock { private int imageWidth; private int imageHeight; + private File networkArchitecture; private File trainingsFile; private File labelsFile; private float maxError; private float learningRate; private File modelFile; + private int maxEpochs; private BuildingBlock() { } + public File getNetworkArchitecture() { + return networkArchitecture; + } + public int getImageWidth() { return imageWidth; } @@ -50,9 +68,13 @@ public float getLearningRate() { public File getModelFile() { return modelFile; } + + public int getMaxEpochs() { + return maxEpochs; + } } - class Builder implements javax.visrec.util.Builder { + class Builder { private BuildingBlock block; @@ -85,6 +107,11 @@ public Builder maxError(float maxError) { return this; } + public Builder maxEpochs(int epochs) { + block.maxEpochs = epochs; + return this; + } + public Builder learningRate(float learningRate) { block.learningRate = learningRate; return this; @@ -95,10 +122,29 @@ public Builder modelFile(File modelFile) { return this; } - @Override - public ImageClassifier build() { + public Builder networkArchitecture(File architecture) { + block.networkArchitecture = architecture; + return this; + } + + public ImageClassifier build() throws ClassifierCreationException { return ServiceProvider.current().getClassifierService().createImageClassifier(block); } + + public ImageClassifier build(Map configuration) throws ClassifierCreationException { + Method[] methods = this.getClass().getDeclaredMethods(); + for (Method method : methods) { + if (!method.getName().equals("build") && method.getParameterCount() == 1 + && configuration.containsKey(method.getName())) { + try { + method.invoke(this, configuration.get(method.getName())); + } catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException e) { + throw new ClassifierCreationException("Couldn't invoke '" + method.getName() + "'", e); + } + } + } + return build(); + } } } diff --git a/src/main/java/javax/visrec/ml/detection/ObjectDetector.java b/src/main/java/javax/visrec/ml/detection/ObjectDetector.java index 982f29b..accd2e2 100644 --- a/src/main/java/javax/visrec/ml/detection/ObjectDetector.java +++ b/src/main/java/javax/visrec/ml/detection/ObjectDetector.java @@ -1,5 +1,6 @@ package javax.visrec.ml.detection; +import javax.visrec.ml.ClassificationException; import javax.visrec.util.BoundingBox; import java.util.List; import java.util.Map; @@ -21,6 +22,6 @@ public interface ObjectDetector { * @param image image to search for object * @return a map of multiple {@link BoundingBox} */ - Map> detectObject(T image); + Map> detectObject(T image) throws ClassificationException; } diff --git a/src/main/java/javax/visrec/spi/ClassifierService.java b/src/main/java/javax/visrec/spi/ClassifierService.java index ac86d92..fd2fcd3 100644 --- a/src/main/java/javax/visrec/spi/ClassifierService.java +++ b/src/main/java/javax/visrec/spi/ClassifierService.java @@ -1,5 +1,6 @@ package javax.visrec.spi; +import javax.visrec.ml.ClassifierCreationException; import javax.visrec.ml.classification.Classifier; import javax.visrec.ml.classification.ImageClassifier; @@ -16,6 +17,7 @@ public interface ClassifierService { * the implementation's image classifier. * @param block {@link ImageClassifier.BuildingBlock} is provided to tune the building of the image classifier. * @return {@link ImageClassifier} + * @throws ClassifierCreationException if the classifier can not be created due to any reason. */ - ImageClassifier createImageClassifier(ImageClassifier.BuildingBlock block); + ImageClassifier createImageClassifier(ImageClassifier.BuildingBlock block) throws ClassifierCreationException; } diff --git a/src/main/java/javax/visrec/util/Builder.java b/src/main/java/javax/visrec/util/Builder.java index ecea7bc..56950ed 100644 --- a/src/main/java/javax/visrec/util/Builder.java +++ b/src/main/java/javax/visrec/util/Builder.java @@ -1,5 +1,6 @@ package javax.visrec.util; +import javax.visrec.ml.ClassifierCreationException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Map; @@ -19,7 +20,7 @@ public interface Builder { * * @return object specified by the builder to build */ - T build(); + T build() throws ClassifierCreationException; /** * Builds an object using properties from the specified input argument @@ -27,7 +28,7 @@ public interface Builder { * @param configuration properties for the builder, a map of key, value pairs. * @return object specified by the builder to build */ - default T build(Map configuration) { + default T build(Map configuration) throws ClassifierCreationException { Method[] methods = this.getClass().getDeclaredMethods(); for (Method method : methods) { if (!method.getName().equals("build") && method.getParameterCount() == 1 From 4444158763a491d7863036326f4edc960d50f9d3 Mon Sep 17 00:00:00 2001 From: Kevin Berendsen Date: Tue, 19 Nov 2019 09:59:35 +0100 Subject: [PATCH 20/87] Automatic casting of simple parameters in the image classifier builder --- .../ml/classification/ImageClassifier.java | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/main/java/javax/visrec/ml/classification/ImageClassifier.java b/src/main/java/javax/visrec/ml/classification/ImageClassifier.java index 092f6b7..e9de72d 100644 --- a/src/main/java/javax/visrec/ml/classification/ImageClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/ImageClassifier.java @@ -137,7 +137,34 @@ public ImageClassifier build(Map configuration) throws Classifie if (!method.getName().equals("build") && method.getParameterCount() == 1 && configuration.containsKey(method.getName())) { try { - method.invoke(this, configuration.get(method.getName())); + Object value = configuration.get(method.getName()); + Class expectedParameterType = method.getParameterTypes()[0]; + // Integer casting + if (expectedParameterType.equals(int.class) || expectedParameterType.equals(Integer.class)) { + if (value instanceof String) { + method.invoke(this, Integer.parseInt((String) value)); + continue; + } + } + + // Float casting + if (expectedParameterType.equals(float.class) || expectedParameterType.equals(Integer.class)) { + if (value instanceof String) { + method.invoke(this, Float.parseFloat((String) value)); + continue; + } + } + + // File casting + if (expectedParameterType.equals(File.class)) { + if (value instanceof String) { + method.invoke(this, new File((String) value)); + continue; + } + } + + // Others + method.invoke(this, value); } catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException e) { throw new ClassifierCreationException("Couldn't invoke '" + method.getName() + "'", e); } From 9d36db1df8443ea23b19a17a028781cdc1fe86a3 Mon Sep 17 00:00:00 2001 From: Kevin Berendsen Date: Tue, 19 Nov 2019 10:00:54 +0100 Subject: [PATCH 21/87] Fix correct Float type instanceof check --- .../java/javax/visrec/ml/classification/ImageClassifier.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/javax/visrec/ml/classification/ImageClassifier.java b/src/main/java/javax/visrec/ml/classification/ImageClassifier.java index e9de72d..17483d7 100644 --- a/src/main/java/javax/visrec/ml/classification/ImageClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/ImageClassifier.java @@ -148,7 +148,7 @@ public ImageClassifier build(Map configuration) throws Classifie } // Float casting - if (expectedParameterType.equals(float.class) || expectedParameterType.equals(Integer.class)) { + if (expectedParameterType.equals(float.class) || expectedParameterType.equals(Float.class)) { if (value instanceof String) { method.invoke(this, Float.parseFloat((String) value)); continue; From 285db19885d07d2e55a456032e4ce1acb7fc7999 Mon Sep 17 00:00:00 2001 From: Zoran Sevarac Date: Tue, 19 Nov 2019 17:03:14 +0100 Subject: [PATCH 22/87] Delete quickstart.txt --- quickstart.txt | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 quickstart.txt diff --git a/quickstart.txt b/quickstart.txt deleted file mode 100644 index 4565fca..0000000 --- a/quickstart.txt +++ /dev/null @@ -1,14 +0,0 @@ - - Clone https://github.com/sevarac/VisualRecognitionApi - use branch separate_impl - this is the vis rec api - - Clone https://github.com/sevarac/deepnetts - this is the deep netts library which is a deep learning library used to implement visrec api - - Run Mnist Typical hello world classification example - recognize hand written letter didgit - - TODO: - move data set txt file to resources dir - where to put images? 20 MB of images for mnist and also for other data set that will be used? - Also github, some cloud? How to download them, using some utility classes like in Dl4J? From 3afe488127f1f283d71aeb4279949e7e46ec8c85 Mon Sep 17 00:00:00 2001 From: Zoran Sevarac Date: Tue, 19 Nov 2019 17:04:05 +0100 Subject: [PATCH 23/87] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index d41c52f..943a2c7 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # visrec-api This repo contains specification of standard Visual Recognition API for Java (JSR381) +The VisRec API JSR #381 is a software development standard recognized by the Java Community Process (JCP) that simplifies and standardizes a set of APIs familiar to Java developers for classifying and recognizing objects in images using machine learning. + ## Getting Started For step by step guide and additional info see getting started guide at From 4995d8fc2f553873dc3136edbb9119e73f4c2d1b Mon Sep 17 00:00:00 2001 From: Zoran Sevarac Date: Tue, 19 Nov 2019 17:08:57 +0100 Subject: [PATCH 24/87] Update README.md --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 943a2c7..5f74794 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,11 @@ # visrec-api This repo contains specification of standard Visual Recognition API for Java (JSR381) -The VisRec API JSR #381 is a software development standard recognized by the Java Community Process (JCP) that simplifies and standardizes a set of APIs familiar to Java developers for classifying and recognizing objects in images using machine learning. +The Visual Recognition API JSR #381 is a software development standard recognized by the Java Community Process (JCP) that simplifies and standardizes a set of APIs familiar to Java developers for classifying and recognizing objects in images using machine learning. Beside classes specific for visual recognition tasks, it provides general abstractions for machine learning tasks like classification, regression and data set, and reusable design which can be applied for machine learning systems in other domains. + +Reference implementation of specification is available at + +https://github.com/JavaVisRec/visrec-ri/ ## Getting Started For step by step guide and additional info see getting started guide at From a136f02557409f7deefe8659ac54563a461b86b1 Mon Sep 17 00:00:00 2001 From: Zoran Sevarac Date: Tue, 19 Nov 2019 17:11:19 +0100 Subject: [PATCH 25/87] Update README.md --- README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5f74794..e46a37e 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,16 @@ Reference implementation of specification is available at https://github.com/JavaVisRec/visrec-ri/ -## Getting Started +## Getting Started Guide For step by step guide and additional info see getting started guide at https://github.com/JavaVisRec/visrec-api/wiki/Getting-Started-Guide + +## Quick Start with Examples + + + git clone https://github.com/JavaVisRec/jsr381-examples.git + cd jsr381-examples + mvn clean install + mvn exec:java -Dexec.mainClass=jsr381.example.ImplementationExample + From 0171060582686a1b6f2c7747d32fec4ce426ee2a Mon Sep 17 00:00:00 2001 From: Zoran Sevarac Date: Tue, 19 Nov 2019 17:13:14 +0100 Subject: [PATCH 26/87] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e46a37e..e4e329b 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ This repo contains specification of standard Visual Recognition API for Java (JSR381) The Visual Recognition API JSR #381 is a software development standard recognized by the Java Community Process (JCP) that simplifies and standardizes a set of APIs familiar to Java developers for classifying and recognizing objects in images using machine learning. Beside classes specific for visual recognition tasks, it provides general abstractions for machine learning tasks like classification, regression and data set, and reusable design which can be applied for machine learning systems in other domains. +At the current stage it provides basic hello world examples for supported machine learning tasks (classification and regression) and image classification. Reference implementation of specification is available at @@ -14,7 +15,6 @@ https://github.com/JavaVisRec/visrec-api/wiki/Getting-Started-Guide ## Quick Start with Examples - git clone https://github.com/JavaVisRec/jsr381-examples.git cd jsr381-examples mvn clean install From 855122338e44c8ec1cf8d739682ebffff41a5024 Mon Sep 17 00:00:00 2001 From: Zoran Sevarac Date: Tue, 19 Nov 2019 17:17:22 +0100 Subject: [PATCH 27/87] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index e4e329b..4c3a334 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,10 @@ Reference implementation of specification is available at https://github.com/JavaVisRec/visrec-ri/ +Introductory examples are available at + +https://github.com/JavaVisRec/jsr381-examples + ## Getting Started Guide For step by step guide and additional info see getting started guide at From 9e9ac447ea1da692e094f569e716343d207b8158 Mon Sep 17 00:00:00 2001 From: Zoran Sevarac Date: Tue, 19 Nov 2019 17:25:42 +0100 Subject: [PATCH 28/87] Update README.md --- README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 4c3a334..3c00e40 100644 --- a/README.md +++ b/README.md @@ -8,10 +8,6 @@ Reference implementation of specification is available at https://github.com/JavaVisRec/visrec-ri/ -Introductory examples are available at - -https://github.com/JavaVisRec/jsr381-examples - ## Getting Started Guide For step by step guide and additional info see getting started guide at @@ -19,6 +15,12 @@ https://github.com/JavaVisRec/visrec-api/wiki/Getting-Started-Guide ## Quick Start with Examples +Introductory examples are available at + +https://github.com/JavaVisRec/jsr381-examples + +Quick start with commands: + git clone https://github.com/JavaVisRec/jsr381-examples.git cd jsr381-examples mvn clean install From f1b55a8980c5400963fd3962e4d45f9badb7b847 Mon Sep 17 00:00:00 2001 From: Shreya_Gupta Date: Tue, 19 Nov 2019 11:03:42 -0800 Subject: [PATCH 29/87] Create LICENSE.md --- LICENSE.md | 203 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 203 insertions(+) create mode 100644 LICENSE.md diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..f8512ad --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,203 @@ +Copyright 2019 The VisRec Expert Group, Contributors and Advisors. All rights reserved. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. From 23a17ffa26feb1162d60007b9f7b4f0992b57577 Mon Sep 17 00:00:00 2001 From: Kevin Berendsen Date: Wed, 4 Dec 2019 08:18:39 +0100 Subject: [PATCH 30/87] Modified ImplementationService to have a single method to return the version as a more flexible value rather than forcing major.minor --- .../java/javax/visrec/AbstractImageClassifier.java | 2 +- .../javax/visrec/spi/ImplementationService.java | 14 ++++---------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/main/java/javax/visrec/AbstractImageClassifier.java b/src/main/java/javax/visrec/AbstractImageClassifier.java index c85a8d7..07cc2ef 100644 --- a/src/main/java/javax/visrec/AbstractImageClassifier.java +++ b/src/main/java/javax/visrec/AbstractImageClassifier.java @@ -80,7 +80,7 @@ public MODEL_CLASS getModel() { return model; } - protected void setModel(MODEL_CLASS model) { + public void setModel(MODEL_CLASS model) { this.model = Objects.requireNonNull(model, "Model cannot bu null!"); } diff --git a/src/main/java/javax/visrec/spi/ImplementationService.java b/src/main/java/javax/visrec/spi/ImplementationService.java index be14f5d..0150a1f 100644 --- a/src/main/java/javax/visrec/spi/ImplementationService.java +++ b/src/main/java/javax/visrec/spi/ImplementationService.java @@ -14,16 +14,10 @@ public abstract class ImplementationService { public abstract String getName(); /** - * Get the major version of the implementation - * @return major version as {@code int} + * Get the version of the implementation + * @return version as {@code String} */ - public abstract int getMajorVersion(); - - /** - * Get the minor version of the implementation - * @return minor version as {@code int} - */ - public abstract int getMinorVersion(); + public abstract String getVersion(); /** * Returns the name, major and minor version of the implementation @@ -31,6 +25,6 @@ public abstract class ImplementationService { */ @Override public final String toString() { - return getName() + " " + getMajorVersion() + "." + getMinorVersion(); + return getName() + " " + getVersion(); } } From b734dac5371b0f2c35ba35f8468c826e8f3086a8 Mon Sep 17 00:00:00 2001 From: Kevin Berendsen Date: Wed, 11 Dec 2019 10:04:23 +0100 Subject: [PATCH 31/87] Support to return the BuildingBlock --- .../java/javax/visrec/ml/classification/ImageClassifier.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/javax/visrec/ml/classification/ImageClassifier.java b/src/main/java/javax/visrec/ml/classification/ImageClassifier.java index 17483d7..6f9b4af 100644 --- a/src/main/java/javax/visrec/ml/classification/ImageClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/ImageClassifier.java @@ -127,6 +127,10 @@ public Builder networkArchitecture(File architecture) { return this; } + public BuildingBlock getBuildingBlock() { + return block; + } + public ImageClassifier build() throws ClassifierCreationException { return ServiceProvider.current().getClassifierService().createImageClassifier(block); } From 7db6983402f845d951941d3364bfcb992fdaf3a7 Mon Sep 17 00:00:00 2001 From: Kevin Berendsen Date: Fri, 13 Dec 2019 16:13:52 +0100 Subject: [PATCH 32/87] Added new empty BinaryClassifier --- .../ml/classification/BinaryClassifier.java | 62 +++++++++++++++---- .../visrec/ml/classification/Classifier.java | 2 +- .../DeprecatedBinaryClassifier.java | 13 ++++ .../ml/regression/LogisticRegression.java | 4 +- .../javax/visrec/spi/ClassifierService.java | 10 +++ 5 files changed, 75 insertions(+), 16 deletions(-) create mode 100644 src/main/java/javax/visrec/ml/classification/DeprecatedBinaryClassifier.java diff --git a/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java b/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java index 0f0c21c..a696444 100644 --- a/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java @@ -1,13 +1,49 @@ -package javax.visrec.ml.classification; - -/** - * Binary classifier classifies object into one of two categories (for example: true/false, yes/no, red/blue, spam/not-spam, fraud/not-fraud). - * Returns a probability that input object belongs to one of two classes. - * - * @author Zoran Sevarac - * @param type of object to classify - */ -public interface BinaryClassifier extends Classifier { - - -} +package javax.visrec.ml.classification; + +import javax.visrec.ml.ClassificationException; +import javax.visrec.ml.ClassifierCreationException; +import javax.visrec.spi.ServiceProvider; +import java.util.Map; + +/** + * Binary classifier classifies object into one of two categories (for example: true/false, yes/no, red/blue, spam/not-spam, fraud/not-fraud). + * Returns a probability that input object belongs to one of two classes. + * + * @author Zoran Sevarac + */ +public interface BinaryClassifier { + + boolean classify(byte[] input) throws ClassificationException; + + static BinaryClassifier.Builder builder() { + return new BinaryClassifier.Builder(); + } + + class BuildingBlock { + + private BuildingBlock() { + } + } + + class Builder { + + private BinaryClassifier.BuildingBlock block; + + private Builder() { + block = new BinaryClassifier.BuildingBlock(); + } + + public BinaryClassifier.BuildingBlock getBuildingBlock() { + return block; + } + + public BinaryClassifier build() throws ClassifierCreationException { + return ServiceProvider.current().getClassifierService().createBinaryClassifier(block); + } + + public ImageClassifier build(Map configuration) throws ClassifierCreationException { + throw new IllegalStateException("not implemented yet"); + } + } + +} diff --git a/src/main/java/javax/visrec/ml/classification/Classifier.java b/src/main/java/javax/visrec/ml/classification/Classifier.java index c500567..200b1ec 100644 --- a/src/main/java/javax/visrec/ml/classification/Classifier.java +++ b/src/main/java/javax/visrec/ml/classification/Classifier.java @@ -8,7 +8,7 @@ * @author Zoran Sevarac * @param type of input objects to classify (eg. User, Product, Transaction, Image, etc.) * @param type of classification result. - * @see BinaryClassifier + * @see DeprecatedBinaryClassifier * @see MultiClassClassifier * @since 1.0 */ diff --git a/src/main/java/javax/visrec/ml/classification/DeprecatedBinaryClassifier.java b/src/main/java/javax/visrec/ml/classification/DeprecatedBinaryClassifier.java new file mode 100644 index 0000000..1fb258c --- /dev/null +++ b/src/main/java/javax/visrec/ml/classification/DeprecatedBinaryClassifier.java @@ -0,0 +1,13 @@ +package javax.visrec.ml.classification; + +/** + * Binary classifier classifies object into one of two categories (for example: true/false, yes/no, red/blue, spam/not-spam, fraud/not-fraud). + * Returns a probability that input object belongs to one of two classes. + * + * @author Zoran Sevarac + * @param type of object to classify + */ +public interface DeprecatedBinaryClassifier extends Classifier { + + +} diff --git a/src/main/java/javax/visrec/ml/regression/LogisticRegression.java b/src/main/java/javax/visrec/ml/regression/LogisticRegression.java index 4cc6201..7613c19 100644 --- a/src/main/java/javax/visrec/ml/regression/LogisticRegression.java +++ b/src/main/java/javax/visrec/ml/regression/LogisticRegression.java @@ -1,6 +1,6 @@ package javax.visrec.ml.regression; -import javax.visrec.ml.classification.BinaryClassifier; +import javax.visrec.ml.classification.DeprecatedBinaryClassifier; /** * This class performs basic binary classification - mapping of specified input to true/false with probability. @@ -8,7 +8,7 @@ * @author Zoran Sevarac * @param Implementation class of underlying machine learning model */ -public abstract class LogisticRegression implements BinaryClassifier{ +public abstract class LogisticRegression implements DeprecatedBinaryClassifier { private MODEL_CLASS model; diff --git a/src/main/java/javax/visrec/spi/ClassifierService.java b/src/main/java/javax/visrec/spi/ClassifierService.java index fd2fcd3..38f108d 100644 --- a/src/main/java/javax/visrec/spi/ClassifierService.java +++ b/src/main/java/javax/visrec/spi/ClassifierService.java @@ -1,6 +1,7 @@ package javax.visrec.spi; import javax.visrec.ml.ClassifierCreationException; +import javax.visrec.ml.classification.BinaryClassifier; import javax.visrec.ml.classification.Classifier; import javax.visrec.ml.classification.ImageClassifier; @@ -20,4 +21,13 @@ public interface ClassifierService { * @throws ClassifierCreationException if the classifier can not be created due to any reason. */ ImageClassifier createImageClassifier(ImageClassifier.BuildingBlock block) throws ClassifierCreationException; + + /** + * Creates a new {@link BinaryClassifier} by providing the {@link BinaryClassifier.BuildingBlock} to tune + * the implementation's binary classifier. + * @param block {@link BinaryClassifier.BuildingBlock} is provided to tune the building of the binary classifier. + * @return {@link BinaryClassifier} + * @throws ClassifierCreationException if the classifier can not be created due to any reason. + */ + BinaryClassifier createBinaryClassifier(BinaryClassifier.BuildingBlock block) throws ClassifierCreationException; } From beb4939ef9df0f1c3e64340f6eb6e88865435430 Mon Sep 17 00:00:00 2001 From: Kevin Berendsen Date: Fri, 10 Jan 2020 10:18:25 +0100 Subject: [PATCH 33/87] Added generic types cascading through to classifier from image classifier --- .../javax/visrec/AbstractImageClassifier.java | 16 +++---- .../ml/ClassifierCreationException.java | 8 ++++ .../ml/classification/BinaryClassifier.java | 5 +-- .../visrec/ml/classification/Classifier.java | 4 +- .../ml/classification/ImageClassifier.java | 43 ++++++++++--------- .../javax/visrec/spi/ClassifierService.java | 2 +- 6 files changed, 44 insertions(+), 34 deletions(-) diff --git a/src/main/java/javax/visrec/AbstractImageClassifier.java b/src/main/java/javax/visrec/AbstractImageClassifier.java index 07cc2ef..e5e0f73 100644 --- a/src/main/java/javax/visrec/AbstractImageClassifier.java +++ b/src/main/java/javax/visrec/AbstractImageClassifier.java @@ -24,17 +24,17 @@ * * @param class of machine learning model */ -public abstract class AbstractImageClassifier implements ImageClassifier { // could also implement binary classifier +public abstract class AbstractImageClassifier implements ImageClassifier { // could also implement binary classifier - private ImageFactory imageFactory; // image factory impl for the specified image class + private ImageFactory imageFactory; // image factory impl for the specified image class private MODEL_CLASS model; // the model could be injected from machine learning container? private float threshold; // this should ba a part of every classifier - protected AbstractImageClassifier(final MODEL_CLASS model) { - final Optional> optionalImageFactory = ServiceProvider.current() + protected AbstractImageClassifier(final Class imgCls, final MODEL_CLASS model) { + final Optional> optionalImageFactory = ServiceProvider.current() .getImageFactoryService() - .getByImageType(BufferedImage.class); + .getByImageType(imgCls); if (!optionalImageFactory.isPresent()) { throw new IllegalArgumentException(String.format("Could not find ImageFactory by '%s'", BufferedImage.class.getName())); } @@ -42,13 +42,13 @@ protected AbstractImageClassifier(final MODEL_CLASS model) { setModel(model); } - public ImageFactory getImageFactory() { + public ImageFactory getImageFactory() { return imageFactory; } @Override public Map classify(File file) throws ClassificationException { - BufferedImage image; + IMAGE_CLASS image; try { image = imageFactory.getImage(file); } catch (IOException e) { @@ -59,7 +59,7 @@ public Map classify(File file) throws ClassificationException { @Override public Map classify(InputStream inputStream) throws ClassificationException { - BufferedImage image; + IMAGE_CLASS image; try { image = imageFactory.getImage(inputStream); } catch (IOException e) { diff --git a/src/main/java/javax/visrec/ml/ClassifierCreationException.java b/src/main/java/javax/visrec/ml/ClassifierCreationException.java index 96b4e9e..964ef82 100644 --- a/src/main/java/javax/visrec/ml/ClassifierCreationException.java +++ b/src/main/java/javax/visrec/ml/ClassifierCreationException.java @@ -8,6 +8,14 @@ */ public class ClassifierCreationException extends Exception { + /** + * Creates a new instance of the exception + * @param message additional message of the cause. + */ + public ClassifierCreationException(String message) { + super(message); + } + /** * Creates a new instance of the exception * @param message additional message of the cause. diff --git a/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java b/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java index a696444..bbbba03 100644 --- a/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java @@ -1,6 +1,5 @@ package javax.visrec.ml.classification; -import javax.visrec.ml.ClassificationException; import javax.visrec.ml.ClassifierCreationException; import javax.visrec.spi.ServiceProvider; import java.util.Map; @@ -11,9 +10,9 @@ * * @author Zoran Sevarac */ -public interface BinaryClassifier { +public interface BinaryClassifier extends Classifier { + - boolean classify(byte[] input) throws ClassificationException; static BinaryClassifier.Builder builder() { return new BinaryClassifier.Builder(); diff --git a/src/main/java/javax/visrec/ml/classification/Classifier.java b/src/main/java/javax/visrec/ml/classification/Classifier.java index 200b1ec..b89ac08 100644 --- a/src/main/java/javax/visrec/ml/classification/Classifier.java +++ b/src/main/java/javax/visrec/ml/classification/Classifier.java @@ -1,5 +1,7 @@ package javax.visrec.ml.classification; +import javax.visrec.ml.ClassificationException; + /** * Generic classifier interface, that all classifiers should implement. Provides * a method to classify instances of some class. Implementations should specify @@ -21,6 +23,6 @@ public interface Classifier { * @param input some instance to classify * @return classification results for the specified instance */ - R classify(T input); + R classify(T input) throws ClassificationException; } diff --git a/src/main/java/javax/visrec/ml/classification/ImageClassifier.java b/src/main/java/javax/visrec/ml/classification/ImageClassifier.java index 6f9b4af..d5fd366 100644 --- a/src/main/java/javax/visrec/ml/classification/ImageClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/ImageClassifier.java @@ -3,26 +3,23 @@ import javax.visrec.ml.ClassificationException; import javax.visrec.ml.ClassifierCreationException; import javax.visrec.spi.ServiceProvider; -import java.awt.image.BufferedImage; import java.io.File; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Map; -public interface ImageClassifier { - - Map classify(BufferedImage input) throws ClassificationException; +public interface ImageClassifier extends Classifier>{ Map classify(File input) throws ClassificationException; Map classify(InputStream input) throws ClassificationException; - static ImageClassifier.Builder builder() { - return new Builder(); + static ImageClassifier.Builder builder(Class imgCls) { + return new Builder<>(imgCls); } - class BuildingBlock { + class BuildingBlock { private int imageWidth; private int imageHeight; @@ -33,6 +30,7 @@ class BuildingBlock { private float learningRate; private File modelFile; private int maxEpochs; + private Class imageClass; private BuildingBlock() { } @@ -72,57 +70,60 @@ public File getModelFile() { public int getMaxEpochs() { return maxEpochs; } + + public Class getImageClass() { return imageClass; } } - class Builder { + class Builder { private BuildingBlock block; - private Builder() { - block = new BuildingBlock(); + private Builder(Class imgCls) { + block = new BuildingBlock(); + block.imageClass = imgCls; } - public Builder imageWidth(int imageWidth) { + public Builder imageWidth(int imageWidth) { block.imageWidth = imageWidth; return this; } - public Builder imageHeight(int imageHeight) { + public Builder imageHeight(int imageHeight) { block.imageHeight = imageHeight; return this; } - public Builder trainingsFile(File trainingsFile) { + public Builder trainingsFile(File trainingsFile) { block.trainingsFile = trainingsFile; return this; } - public Builder labelsFile(File labelsFile) { + public Builder labelsFile(File labelsFile) { block.labelsFile = labelsFile; return this; } - public Builder maxError(float maxError) { + public Builder maxError(float maxError) { block.maxError = maxError; return this; } - public Builder maxEpochs(int epochs) { + public Builder maxEpochs(int epochs) { block.maxEpochs = epochs; return this; } - public Builder learningRate(float learningRate) { + public Builder learningRate(float learningRate) { block.learningRate = learningRate; return this; } - public Builder modelFile(File modelFile) { + public Builder modelFile(File modelFile) { block.modelFile = modelFile; return this; } - public Builder networkArchitecture(File architecture) { + public Builder networkArchitecture(File architecture) { block.networkArchitecture = architecture; return this; } @@ -131,11 +132,11 @@ public BuildingBlock getBuildingBlock() { return block; } - public ImageClassifier build() throws ClassifierCreationException { + public ImageClassifier build() throws ClassifierCreationException { return ServiceProvider.current().getClassifierService().createImageClassifier(block); } - public ImageClassifier build(Map configuration) throws ClassifierCreationException { + public ImageClassifier build(Map configuration) throws ClassifierCreationException { Method[] methods = this.getClass().getDeclaredMethods(); for (Method method : methods) { if (!method.getName().equals("build") && method.getParameterCount() == 1 diff --git a/src/main/java/javax/visrec/spi/ClassifierService.java b/src/main/java/javax/visrec/spi/ClassifierService.java index 38f108d..e89e0f7 100644 --- a/src/main/java/javax/visrec/spi/ClassifierService.java +++ b/src/main/java/javax/visrec/spi/ClassifierService.java @@ -20,7 +20,7 @@ public interface ClassifierService { * @return {@link ImageClassifier} * @throws ClassifierCreationException if the classifier can not be created due to any reason. */ - ImageClassifier createImageClassifier(ImageClassifier.BuildingBlock block) throws ClassifierCreationException; + ImageClassifier createImageClassifier(ImageClassifier.BuildingBlock block) throws ClassifierCreationException; /** * Creates a new {@link BinaryClassifier} by providing the {@link BinaryClassifier.BuildingBlock} to tune From e05b4ec8695a40f17f8ad7ccc3afb398c254d063 Mon Sep 17 00:00:00 2001 From: Kevin Berendsen Date: Fri, 10 Jan 2020 10:19:48 +0100 Subject: [PATCH 34/87] Added generic type to BuildingBlock object --- .../java/javax/visrec/ml/classification/ImageClassifier.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/javax/visrec/ml/classification/ImageClassifier.java b/src/main/java/javax/visrec/ml/classification/ImageClassifier.java index d5fd366..736b8b5 100644 --- a/src/main/java/javax/visrec/ml/classification/ImageClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/ImageClassifier.java @@ -76,10 +76,10 @@ public int getMaxEpochs() { class Builder { - private BuildingBlock block; + private BuildingBlock block; private Builder(Class imgCls) { - block = new BuildingBlock(); + block = new BuildingBlock<>(); block.imageClass = imgCls; } From 633681d0b37de4a7958974140e680dda6120a4a2 Mon Sep 17 00:00:00 2001 From: Kevin Berendsen Date: Fri, 10 Jan 2020 10:35:46 +0100 Subject: [PATCH 35/87] Renamed ImageClassifier.builder(...) to ImageClassifier.builderOf(...). --- .../java/javax/visrec/ml/classification/ImageClassifier.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/javax/visrec/ml/classification/ImageClassifier.java b/src/main/java/javax/visrec/ml/classification/ImageClassifier.java index 736b8b5..c4e1614 100644 --- a/src/main/java/javax/visrec/ml/classification/ImageClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/ImageClassifier.java @@ -15,7 +15,7 @@ public interface ImageClassifier extends Classifier classify(InputStream input) throws ClassificationException; - static ImageClassifier.Builder builder(Class imgCls) { + static ImageClassifier.Builder builderOf(Class imgCls) { return new Builder<>(imgCls); } From 2ebb0a63e8fe34526f0e9387dcb19dbc2f59cf4f Mon Sep 17 00:00:00 2001 From: Kevin Berendsen Date: Fri, 10 Jan 2020 13:13:43 +0100 Subject: [PATCH 36/87] Created ImageClassifierCreator and BinaryClassifierCreator as new interfaces to create specific objects of classifiers with specific target classes or image classes to be able to support generic types for usage. --- .../ml/classification/BinaryClassifier.java | 29 ++++--- .../ml/classification/EnsambleClassifier.java | 8 +- .../ml/classification/ImageClassifier.java | 2 +- .../visrec/spi/BinaryClassifierCreator.java | 11 +++ .../visrec/spi/ClassifierCreatorService.java | 85 +++++++++++++++++++ .../javax/visrec/spi/ClassifierService.java | 33 ------- .../visrec/spi/ImageClassifierCreator.java | 12 +++ .../javax/visrec/spi/ServiceProvider.java | 8 +- 8 files changed, 137 insertions(+), 51 deletions(-) create mode 100644 src/main/java/javax/visrec/spi/BinaryClassifierCreator.java create mode 100644 src/main/java/javax/visrec/spi/ClassifierCreatorService.java delete mode 100644 src/main/java/javax/visrec/spi/ClassifierService.java create mode 100644 src/main/java/javax/visrec/spi/ImageClassifierCreator.java diff --git a/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java b/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java index bbbba03..dc6f2cb 100644 --- a/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java @@ -14,33 +14,40 @@ public interface BinaryClassifier extends Classifier { - static BinaryClassifier.Builder builder() { - return new BinaryClassifier.Builder(); + static BinaryClassifier.Builder builderOf(Class targetCls) { + return new BinaryClassifier.Builder<>(targetCls); } - class BuildingBlock { + class BuildingBlock { + + private Class targetCls; private BuildingBlock() { } + + public Class getTargetClass() { + return targetCls; + } } - class Builder { + class Builder { - private BinaryClassifier.BuildingBlock block; + private BinaryClassifier.BuildingBlock block; - private Builder() { - block = new BinaryClassifier.BuildingBlock(); + private Builder(Class targetCls) { + block = new BinaryClassifier.BuildingBlock<>(); + block.targetCls = targetCls; } - public BinaryClassifier.BuildingBlock getBuildingBlock() { + public BinaryClassifier.BuildingBlock getBuildingBlock() { return block; } - public BinaryClassifier build() throws ClassifierCreationException { - return ServiceProvider.current().getClassifierService().createBinaryClassifier(block); + public BinaryClassifier build() throws ClassifierCreationException { + return ServiceProvider.current().getClassifierCreatorService().createBinaryClassifier(block); } - public ImageClassifier build(Map configuration) throws ClassifierCreationException { + public BinaryClassifier build(Map configuration) throws ClassifierCreationException { throw new IllegalStateException("not implemented yet"); } } diff --git a/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java b/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java index 484e775..7c45edf 100644 --- a/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java @@ -1,5 +1,6 @@ package javax.visrec.ml.classification; +import javax.visrec.ml.ClassificationException; import java.util.HashMap; import java.util.Map; @@ -18,9 +19,10 @@ public final class EnsambleClassifier implements Classifier { private final Map> classifiers = new HashMap<>(); @Override - public R classify(T input) { - classifiers.values().stream() // or parallelStream - .forEach(c -> c.classify(input)); + public R classify(T input) throws ClassificationException { + for (Map.Entry> classifier : classifiers.entrySet()) { + classifier.getValue().classify(input); + } // get the highest class frequency //.collect(); // get average scores? This method can be overriden, provide default impl here // return merged classification result of all classifiers - mean or most frequent? diff --git a/src/main/java/javax/visrec/ml/classification/ImageClassifier.java b/src/main/java/javax/visrec/ml/classification/ImageClassifier.java index c4e1614..0bf41fa 100644 --- a/src/main/java/javax/visrec/ml/classification/ImageClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/ImageClassifier.java @@ -133,7 +133,7 @@ public BuildingBlock getBuildingBlock() { } public ImageClassifier build() throws ClassifierCreationException { - return ServiceProvider.current().getClassifierService().createImageClassifier(block); + return ServiceProvider.current().getClassifierCreatorService().createImageClassifier(block); } public ImageClassifier build(Map configuration) throws ClassifierCreationException { diff --git a/src/main/java/javax/visrec/spi/BinaryClassifierCreator.java b/src/main/java/javax/visrec/spi/BinaryClassifierCreator.java new file mode 100644 index 0000000..6bb043b --- /dev/null +++ b/src/main/java/javax/visrec/spi/BinaryClassifierCreator.java @@ -0,0 +1,11 @@ +package javax.visrec.spi; + +import javax.visrec.ml.classification.BinaryClassifier; + +public interface BinaryClassifierCreator { + + Class getTargetClass(); + + BinaryClassifier create(BinaryClassifier.BuildingBlock block); + +} diff --git a/src/main/java/javax/visrec/spi/ClassifierCreatorService.java b/src/main/java/javax/visrec/spi/ClassifierCreatorService.java new file mode 100644 index 0000000..497c83f --- /dev/null +++ b/src/main/java/javax/visrec/spi/ClassifierCreatorService.java @@ -0,0 +1,85 @@ +package javax.visrec.spi; + +import javax.visrec.ml.ClassifierCreationException; +import javax.visrec.ml.classification.BinaryClassifier; +import javax.visrec.ml.classification.Classifier; +import javax.visrec.ml.classification.ImageClassifier; +import java.util.HashMap; +import java.util.Map; +import java.util.ServiceLoader; + +/** + * Service to provide the correct {@link Classifier} implementation. + * + * @author Kevin Berendsen + * @since 1.0 + */ +public final class ClassifierCreatorService { + + private Map, ImageClassifierCreator> imageClassifierCreators; + private Map, BinaryClassifierCreator> binaryClassifierCreators; + + private static ClassifierCreatorService instance; + static ClassifierCreatorService getInstance() { + if (instance == null) { + instance = new ClassifierCreatorService(); + } + return instance; + } + + private ClassifierCreatorService() { + // Prevent instantiation + } + + /** + * Creates a new {@link ImageClassifier} by providing the {@link ImageClassifier.BuildingBlock} to tune + * the implementation's image classifier. + * + * @param block {@link ImageClassifier.BuildingBlock} is provided to tune the building of the image classifier. + * @return {@link ImageClassifier} + * @throws ClassifierCreationException if the classifier can not be created due to any reason. + */ + public ImageClassifier createImageClassifier(ImageClassifier.BuildingBlock block) throws ClassifierCreationException { + if (imageClassifierCreators == null) { + imageClassifierCreators = new HashMap<>(); + for (ImageClassifierCreator classifierCreator : ServiceLoader.load(ImageClassifierCreator.class)) { + imageClassifierCreators.put(classifierCreator.getImageClass(), classifierCreator); + } + } + + ImageClassifierCreator creator = imageClassifierCreators.get(block.getImageClass()); + if (creator == null) { + throw new ClassifierCreationException("Unsupported image class"); + } + + @SuppressWarnings("unchecked") + ImageClassifierCreator castedCreator = (ImageClassifierCreator) creator; + return castedCreator.create(block); + } + + /** + * Creates a new {@link BinaryClassifier} by providing the {@link BinaryClassifier.BuildingBlock} to tune + * the implementation's binary classifier. + * + * @param block {@link BinaryClassifier.BuildingBlock} is provided to tune the building of the binary classifier. + * @return {@link BinaryClassifier} + * @throws ClassifierCreationException if the classifier can not be created due to any reason. + */ + public BinaryClassifier createBinaryClassifier(BinaryClassifier.BuildingBlock block) throws ClassifierCreationException { + if (binaryClassifierCreators == null) { + binaryClassifierCreators = new HashMap<>(); + for (BinaryClassifierCreator classifierCreator : ServiceLoader.load(BinaryClassifierCreator.class)) { + binaryClassifierCreators.put(classifierCreator.getTargetClass(), classifierCreator); + } + } + + BinaryClassifierCreator creator = binaryClassifierCreators.get(block.getTargetClass()); + if (creator == null) { + throw new ClassifierCreationException("Unsupported target class"); + } + + @SuppressWarnings("unchecked") + BinaryClassifierCreator castedCreator = (BinaryClassifierCreator) creator; + return castedCreator.create(block); + } +} diff --git a/src/main/java/javax/visrec/spi/ClassifierService.java b/src/main/java/javax/visrec/spi/ClassifierService.java deleted file mode 100644 index e89e0f7..0000000 --- a/src/main/java/javax/visrec/spi/ClassifierService.java +++ /dev/null @@ -1,33 +0,0 @@ -package javax.visrec.spi; - -import javax.visrec.ml.ClassifierCreationException; -import javax.visrec.ml.classification.BinaryClassifier; -import javax.visrec.ml.classification.Classifier; -import javax.visrec.ml.classification.ImageClassifier; - -/** - * Service to provide the correct {@link Classifier} implementation. - * - * @author Kevin Berendsen - * @since 1.0 - */ -public interface ClassifierService { - - /** - * Creates a new {@link ImageClassifier} by providing the {@link ImageClassifier.BuildingBlock} to tune - * the implementation's image classifier. - * @param block {@link ImageClassifier.BuildingBlock} is provided to tune the building of the image classifier. - * @return {@link ImageClassifier} - * @throws ClassifierCreationException if the classifier can not be created due to any reason. - */ - ImageClassifier createImageClassifier(ImageClassifier.BuildingBlock block) throws ClassifierCreationException; - - /** - * Creates a new {@link BinaryClassifier} by providing the {@link BinaryClassifier.BuildingBlock} to tune - * the implementation's binary classifier. - * @param block {@link BinaryClassifier.BuildingBlock} is provided to tune the building of the binary classifier. - * @return {@link BinaryClassifier} - * @throws ClassifierCreationException if the classifier can not be created due to any reason. - */ - BinaryClassifier createBinaryClassifier(BinaryClassifier.BuildingBlock block) throws ClassifierCreationException; -} diff --git a/src/main/java/javax/visrec/spi/ImageClassifierCreator.java b/src/main/java/javax/visrec/spi/ImageClassifierCreator.java new file mode 100644 index 0000000..bf995fc --- /dev/null +++ b/src/main/java/javax/visrec/spi/ImageClassifierCreator.java @@ -0,0 +1,12 @@ +package javax.visrec.spi; + +import javax.visrec.ml.ClassifierCreationException; +import javax.visrec.ml.classification.ImageClassifier; + +public interface ImageClassifierCreator { + + Class getImageClass(); + + ImageClassifier create(ImageClassifier.BuildingBlock block) throws ClassifierCreationException; + +} diff --git a/src/main/java/javax/visrec/spi/ServiceProvider.java b/src/main/java/javax/visrec/spi/ServiceProvider.java index 80b2049..8af181c 100644 --- a/src/main/java/javax/visrec/spi/ServiceProvider.java +++ b/src/main/java/javax/visrec/spi/ServiceProvider.java @@ -44,10 +44,12 @@ public int getPriority() { public abstract BuilderService getBuilderService(); /** - * Get the {@link ClassifierService} - * @return classifier service + * Get the {@link ClassifierCreatorService} + * @return classifier creator service */ - public abstract ClassifierService getClassifierService(); + public ClassifierCreatorService getClassifierCreatorService() { + return ClassifierCreatorService.getInstance(); + } /** * Get the {@link ImageFactoryService} From 24942875f06cc26593f2f74d5bdf78c0bf5069c5 Mon Sep 17 00:00:00 2001 From: Kevin Berendsen Date: Tue, 14 Jan 2020 10:38:48 +0100 Subject: [PATCH 37/87] Removed DeprecatedBinaryClassifier and finished feedback on BinaryClassifier --- .../ml/classification/BinaryClassifier.java | 65 ++++++++++++++++++- .../visrec/ml/classification/Classifier.java | 3 +- .../DeprecatedBinaryClassifier.java | 13 ---- .../ml/regression/LogisticRegression.java | 4 +- .../visrec/spi/BinaryClassifierCreator.java | 3 +- 5 files changed, 68 insertions(+), 20 deletions(-) delete mode 100644 src/main/java/javax/visrec/ml/classification/DeprecatedBinaryClassifier.java diff --git a/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java b/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java index dc6f2cb..4edcef3 100644 --- a/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java @@ -2,6 +2,7 @@ import javax.visrec.ml.ClassifierCreationException; import javax.visrec.spi.ServiceProvider; +import java.io.File; import java.util.Map; /** @@ -10,9 +11,7 @@ * * @author Zoran Sevarac */ -public interface BinaryClassifier extends Classifier { - - +public interface BinaryClassifier extends Classifier> { static BinaryClassifier.Builder builderOf(Class targetCls) { return new BinaryClassifier.Builder<>(targetCls); @@ -21,6 +20,12 @@ static BinaryClassifier.Builder builderOf(Class targetCls) { class BuildingBlock { private Class targetCls; + private int inputsNum; + private int[] hiddenLayers; + private float maxError; + private int maxEpochs; + private float learningRate; + private File trainingFile; private BuildingBlock() { } @@ -28,6 +33,30 @@ private BuildingBlock() { public Class getTargetClass() { return targetCls; } + + public int getInputsNum() { + return inputsNum; + } + + public int[] getHiddenLayers() { + return hiddenLayers; + } + + public float getMaxError() { + return maxError; + } + + public int getMaxEpochs() { + return maxEpochs; + } + + public float getLearningRate() { + return learningRate; + } + + public File getTrainingFile() { + return trainingFile; + } } class Builder { @@ -39,6 +68,36 @@ private Builder(Class targetCls) { block.targetCls = targetCls; } + public Builder inputsNum(int inputsNum) { + block.inputsNum = inputsNum; + return this; + } + + public Builder hiddenLayers(int... hiddenLayers) { + block.hiddenLayers = hiddenLayers; + return this; + } + + public Builder maxError(float maxError) { + block.maxError = maxError; + return this; + } + + public Builder maxEpochs(int maxEpochs) { + block.maxEpochs = maxEpochs; + return this; + } + + public Builder learningRate(float learningRate) { + block.learningRate = learningRate; + return this; + } + + public Builder trainingFile(File trainingFile) { + block.trainingFile = trainingFile; + return this; + } + public BinaryClassifier.BuildingBlock getBuildingBlock() { return block; } diff --git a/src/main/java/javax/visrec/ml/classification/Classifier.java b/src/main/java/javax/visrec/ml/classification/Classifier.java index b89ac08..78d083e 100644 --- a/src/main/java/javax/visrec/ml/classification/Classifier.java +++ b/src/main/java/javax/visrec/ml/classification/Classifier.java @@ -10,8 +10,9 @@ * @author Zoran Sevarac * @param type of input objects to classify (eg. User, Product, Transaction, Image, etc.) * @param type of classification result. - * @see DeprecatedBinaryClassifier + * @see BinaryClassifier * @see MultiClassClassifier + * @see ImageClassifier * @since 1.0 */ @FunctionalInterface diff --git a/src/main/java/javax/visrec/ml/classification/DeprecatedBinaryClassifier.java b/src/main/java/javax/visrec/ml/classification/DeprecatedBinaryClassifier.java deleted file mode 100644 index 1fb258c..0000000 --- a/src/main/java/javax/visrec/ml/classification/DeprecatedBinaryClassifier.java +++ /dev/null @@ -1,13 +0,0 @@ -package javax.visrec.ml.classification; - -/** - * Binary classifier classifies object into one of two categories (for example: true/false, yes/no, red/blue, spam/not-spam, fraud/not-fraud). - * Returns a probability that input object belongs to one of two classes. - * - * @author Zoran Sevarac - * @param type of object to classify - */ -public interface DeprecatedBinaryClassifier extends Classifier { - - -} diff --git a/src/main/java/javax/visrec/ml/regression/LogisticRegression.java b/src/main/java/javax/visrec/ml/regression/LogisticRegression.java index 7613c19..355aba7 100644 --- a/src/main/java/javax/visrec/ml/regression/LogisticRegression.java +++ b/src/main/java/javax/visrec/ml/regression/LogisticRegression.java @@ -1,6 +1,6 @@ package javax.visrec.ml.regression; -import javax.visrec.ml.classification.DeprecatedBinaryClassifier; +import javax.visrec.ml.classification.BinaryClassifier; /** * This class performs basic binary classification - mapping of specified input to true/false with probability. @@ -8,7 +8,7 @@ * @author Zoran Sevarac * @param Implementation class of underlying machine learning model */ -public abstract class LogisticRegression implements DeprecatedBinaryClassifier { +public abstract class LogisticRegression implements BinaryClassifier { private MODEL_CLASS model; diff --git a/src/main/java/javax/visrec/spi/BinaryClassifierCreator.java b/src/main/java/javax/visrec/spi/BinaryClassifierCreator.java index 6bb043b..7ca7d42 100644 --- a/src/main/java/javax/visrec/spi/BinaryClassifierCreator.java +++ b/src/main/java/javax/visrec/spi/BinaryClassifierCreator.java @@ -1,11 +1,12 @@ package javax.visrec.spi; +import javax.visrec.ml.ClassifierCreationException; import javax.visrec.ml.classification.BinaryClassifier; public interface BinaryClassifierCreator { Class getTargetClass(); - BinaryClassifier create(BinaryClassifier.BuildingBlock block); + BinaryClassifier create(BinaryClassifier.BuildingBlock block) throws ClassifierCreationException; } From ad7f79922fc14d4884d947fb02a6c6cd884ebb5c Mon Sep 17 00:00:00 2001 From: Zoran Sevarac Date: Sat, 1 Feb 2020 13:09:03 +0100 Subject: [PATCH 38/87] annotations --- .../visrec/ml/classification/AbstractMultiClassClassifier.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/javax/visrec/ml/classification/AbstractMultiClassClassifier.java b/src/main/java/javax/visrec/ml/classification/AbstractMultiClassClassifier.java index 581e443..7faeda5 100644 --- a/src/main/java/javax/visrec/ml/classification/AbstractMultiClassClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/AbstractMultiClassClassifier.java @@ -13,6 +13,7 @@ public abstract class AbstractMultiClassClassifier implements private MODEL_CLASS model; + @Override public MODEL_CLASS getModel() { return model; } From 18cfeb02d16ee94e15ce7b4d41aa25861a074a76 Mon Sep 17 00:00:00 2001 From: Kevin Berendsen Date: Sat, 1 Feb 2020 13:49:16 +0100 Subject: [PATCH 39/87] Refactored Creator into Factory. Created new interface NeuralNetBinaryClassifier which contains the previous BinaryClassifier Builder and Building to create a BinaryClassifier with a neural network as underlying model. --- .../ml/classification/BinaryClassifier.java | 105 +-------------- .../ml/classification/ImageClassifier.java | 2 +- .../NeuralNetBinaryClassifier.java | 126 ++++++++++++++++++ .../visrec/spi/BinaryClassifierCreator.java | 12 -- .../visrec/spi/BinaryClassifierFactory.java | 13 ++ .../visrec/spi/ClassifierCreatorService.java | 85 ------------ .../visrec/spi/ClassifierFactoryService.java | 86 ++++++++++++ ...eator.java => ImageClassifierFactory.java} | 2 +- .../javax/visrec/spi/ServiceProvider.java | 6 +- 9 files changed, 231 insertions(+), 206 deletions(-) create mode 100644 src/main/java/javax/visrec/ml/classification/NeuralNetBinaryClassifier.java delete mode 100644 src/main/java/javax/visrec/spi/BinaryClassifierCreator.java create mode 100644 src/main/java/javax/visrec/spi/BinaryClassifierFactory.java delete mode 100644 src/main/java/javax/visrec/spi/ClassifierCreatorService.java create mode 100644 src/main/java/javax/visrec/spi/ClassifierFactoryService.java rename src/main/java/javax/visrec/spi/{ImageClassifierCreator.java => ImageClassifierFactory.java} (85%) diff --git a/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java b/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java index 4edcef3..9c36954 100644 --- a/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java @@ -1,114 +1,11 @@ package javax.visrec.ml.classification; -import javax.visrec.ml.ClassifierCreationException; -import javax.visrec.spi.ServiceProvider; -import java.io.File; -import java.util.Map; - /** * Binary classifier classifies object into one of two categories (for example: true/false, yes/no, red/blue, spam/not-spam, fraud/not-fraud). * Returns a probability that input object belongs to one of two classes. * * @author Zoran Sevarac */ -public interface BinaryClassifier extends Classifier> { - - static BinaryClassifier.Builder builderOf(Class targetCls) { - return new BinaryClassifier.Builder<>(targetCls); - } - - class BuildingBlock { - - private Class targetCls; - private int inputsNum; - private int[] hiddenLayers; - private float maxError; - private int maxEpochs; - private float learningRate; - private File trainingFile; - - private BuildingBlock() { - } - - public Class getTargetClass() { - return targetCls; - } - - public int getInputsNum() { - return inputsNum; - } - - public int[] getHiddenLayers() { - return hiddenLayers; - } - - public float getMaxError() { - return maxError; - } - - public int getMaxEpochs() { - return maxEpochs; - } - - public float getLearningRate() { - return learningRate; - } - - public File getTrainingFile() { - return trainingFile; - } - } - - class Builder { - - private BinaryClassifier.BuildingBlock block; - - private Builder(Class targetCls) { - block = new BinaryClassifier.BuildingBlock<>(); - block.targetCls = targetCls; - } - - public Builder inputsNum(int inputsNum) { - block.inputsNum = inputsNum; - return this; - } - - public Builder hiddenLayers(int... hiddenLayers) { - block.hiddenLayers = hiddenLayers; - return this; - } - - public Builder maxError(float maxError) { - block.maxError = maxError; - return this; - } - - public Builder maxEpochs(int maxEpochs) { - block.maxEpochs = maxEpochs; - return this; - } - - public Builder learningRate(float learningRate) { - block.learningRate = learningRate; - return this; - } - - public Builder trainingFile(File trainingFile) { - block.trainingFile = trainingFile; - return this; - } - - public BinaryClassifier.BuildingBlock getBuildingBlock() { - return block; - } - - public BinaryClassifier build() throws ClassifierCreationException { - return ServiceProvider.current().getClassifierCreatorService().createBinaryClassifier(block); - } - - public BinaryClassifier build(Map configuration) throws ClassifierCreationException { - throw new IllegalStateException("not implemented yet"); - } - } +public interface BinaryClassifier extends Classifier { } diff --git a/src/main/java/javax/visrec/ml/classification/ImageClassifier.java b/src/main/java/javax/visrec/ml/classification/ImageClassifier.java index 0bf41fa..36194fe 100644 --- a/src/main/java/javax/visrec/ml/classification/ImageClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/ImageClassifier.java @@ -133,7 +133,7 @@ public BuildingBlock getBuildingBlock() { } public ImageClassifier build() throws ClassifierCreationException { - return ServiceProvider.current().getClassifierCreatorService().createImageClassifier(block); + return ServiceProvider.current().getClassifierFactoryService().createImageClassifier(block); } public ImageClassifier build(Map configuration) throws ClassifierCreationException { diff --git a/src/main/java/javax/visrec/ml/classification/NeuralNetBinaryClassifier.java b/src/main/java/javax/visrec/ml/classification/NeuralNetBinaryClassifier.java new file mode 100644 index 0000000..d7e82cd --- /dev/null +++ b/src/main/java/javax/visrec/ml/classification/NeuralNetBinaryClassifier.java @@ -0,0 +1,126 @@ +package javax.visrec.ml.classification; + +import javax.visrec.ml.ClassifierCreationException; +import javax.visrec.spi.ServiceProvider; +import java.io.File; +import java.util.Map; + +public interface NeuralNetBinaryClassifier extends BinaryClassifier { + + static NeuralNetBinaryClassifier.Builder builder() { + return new NeuralNetBinaryClassifier.Builder<>(); + } + + class BuildingBlock { + private Class targetCls; + private int inputsNum; + private int[] hiddenLayers; + private float maxError; + private int maxEpochs; + private float learningRate; + private File trainingFile; + + private BuildingBlock() { + } + + public Class getTargetClass() { + return targetCls; + } + + public int getInputsNum() { + return inputsNum; + } + + public int[] getHiddenLayers() { + return hiddenLayers; + } + + public float getMaxError() { + return maxError; + } + + public int getMaxEpochs() { + return maxEpochs; + } + + public float getLearningRate() { + return learningRate; + } + + public File getTrainingFile() { + return trainingFile; + } + + private static BuildingBlock copyWithNewTargetClass(BuildingBlock block, Class cls) { + BuildingBlock newBlock = new BuildingBlock<>(); + newBlock.targetCls = cls; + newBlock.inputsNum = block.inputsNum; + newBlock.hiddenLayers = block.hiddenLayers; + newBlock.maxError = block.maxError; + newBlock.maxEpochs = block.maxEpochs; + newBlock.learningRate = block.learningRate; + newBlock.trainingFile = block.trainingFile; + return newBlock; + } + } + + class Builder { + + private NeuralNetBinaryClassifier.BuildingBlock block; + + private Builder() { + this(new NeuralNetBinaryClassifier.BuildingBlock<>()); + } + + private Builder(BuildingBlock block) { + this.block = block; + } + + public Builder inputClass(Class cls) { + BuildingBlock newBlock = BuildingBlock.copyWithNewTargetClass(block, cls); + return new Builder<>(newBlock); + } + + public Builder inputsNum(int inputsNum) { + block.inputsNum = inputsNum; + return this; + } + + public Builder hiddenLayers(int... hiddenLayers) { + block.hiddenLayers = hiddenLayers; + return this; + } + + public Builder maxError(float maxError) { + block.maxError = maxError; + return this; + } + + public Builder maxEpochs(int maxEpochs) { + block.maxEpochs = maxEpochs; + return this; + } + + public Builder learningRate(float learningRate) { + block.learningRate = learningRate; + return this; + } + + public Builder trainingFile(File trainingFile) { + block.trainingFile = trainingFile; + return this; + } + + public NeuralNetBinaryClassifier.BuildingBlock getBuildingBlock() { + return block; + } + + public BinaryClassifier build() throws ClassifierCreationException { + return ServiceProvider.current().getClassifierFactoryService().createNeuralNetBinaryClassifier(block); + } + + public BinaryClassifier build(Map configuration) throws ClassifierCreationException { + throw new IllegalStateException("not implemented yet"); + } + } +} diff --git a/src/main/java/javax/visrec/spi/BinaryClassifierCreator.java b/src/main/java/javax/visrec/spi/BinaryClassifierCreator.java deleted file mode 100644 index 7ca7d42..0000000 --- a/src/main/java/javax/visrec/spi/BinaryClassifierCreator.java +++ /dev/null @@ -1,12 +0,0 @@ -package javax.visrec.spi; - -import javax.visrec.ml.ClassifierCreationException; -import javax.visrec.ml.classification.BinaryClassifier; - -public interface BinaryClassifierCreator { - - Class getTargetClass(); - - BinaryClassifier create(BinaryClassifier.BuildingBlock block) throws ClassifierCreationException; - -} diff --git a/src/main/java/javax/visrec/spi/BinaryClassifierFactory.java b/src/main/java/javax/visrec/spi/BinaryClassifierFactory.java new file mode 100644 index 0000000..337eb31 --- /dev/null +++ b/src/main/java/javax/visrec/spi/BinaryClassifierFactory.java @@ -0,0 +1,13 @@ +package javax.visrec.spi; + +import javax.visrec.ml.ClassifierCreationException; +import javax.visrec.ml.classification.BinaryClassifier; +import javax.visrec.ml.classification.NeuralNetBinaryClassifier; + +public interface BinaryClassifierFactory { + + Class getTargetClass(); + + BinaryClassifier create(NeuralNetBinaryClassifier.BuildingBlock block) throws ClassifierCreationException; + +} diff --git a/src/main/java/javax/visrec/spi/ClassifierCreatorService.java b/src/main/java/javax/visrec/spi/ClassifierCreatorService.java deleted file mode 100644 index 497c83f..0000000 --- a/src/main/java/javax/visrec/spi/ClassifierCreatorService.java +++ /dev/null @@ -1,85 +0,0 @@ -package javax.visrec.spi; - -import javax.visrec.ml.ClassifierCreationException; -import javax.visrec.ml.classification.BinaryClassifier; -import javax.visrec.ml.classification.Classifier; -import javax.visrec.ml.classification.ImageClassifier; -import java.util.HashMap; -import java.util.Map; -import java.util.ServiceLoader; - -/** - * Service to provide the correct {@link Classifier} implementation. - * - * @author Kevin Berendsen - * @since 1.0 - */ -public final class ClassifierCreatorService { - - private Map, ImageClassifierCreator> imageClassifierCreators; - private Map, BinaryClassifierCreator> binaryClassifierCreators; - - private static ClassifierCreatorService instance; - static ClassifierCreatorService getInstance() { - if (instance == null) { - instance = new ClassifierCreatorService(); - } - return instance; - } - - private ClassifierCreatorService() { - // Prevent instantiation - } - - /** - * Creates a new {@link ImageClassifier} by providing the {@link ImageClassifier.BuildingBlock} to tune - * the implementation's image classifier. - * - * @param block {@link ImageClassifier.BuildingBlock} is provided to tune the building of the image classifier. - * @return {@link ImageClassifier} - * @throws ClassifierCreationException if the classifier can not be created due to any reason. - */ - public ImageClassifier createImageClassifier(ImageClassifier.BuildingBlock block) throws ClassifierCreationException { - if (imageClassifierCreators == null) { - imageClassifierCreators = new HashMap<>(); - for (ImageClassifierCreator classifierCreator : ServiceLoader.load(ImageClassifierCreator.class)) { - imageClassifierCreators.put(classifierCreator.getImageClass(), classifierCreator); - } - } - - ImageClassifierCreator creator = imageClassifierCreators.get(block.getImageClass()); - if (creator == null) { - throw new ClassifierCreationException("Unsupported image class"); - } - - @SuppressWarnings("unchecked") - ImageClassifierCreator castedCreator = (ImageClassifierCreator) creator; - return castedCreator.create(block); - } - - /** - * Creates a new {@link BinaryClassifier} by providing the {@link BinaryClassifier.BuildingBlock} to tune - * the implementation's binary classifier. - * - * @param block {@link BinaryClassifier.BuildingBlock} is provided to tune the building of the binary classifier. - * @return {@link BinaryClassifier} - * @throws ClassifierCreationException if the classifier can not be created due to any reason. - */ - public BinaryClassifier createBinaryClassifier(BinaryClassifier.BuildingBlock block) throws ClassifierCreationException { - if (binaryClassifierCreators == null) { - binaryClassifierCreators = new HashMap<>(); - for (BinaryClassifierCreator classifierCreator : ServiceLoader.load(BinaryClassifierCreator.class)) { - binaryClassifierCreators.put(classifierCreator.getTargetClass(), classifierCreator); - } - } - - BinaryClassifierCreator creator = binaryClassifierCreators.get(block.getTargetClass()); - if (creator == null) { - throw new ClassifierCreationException("Unsupported target class"); - } - - @SuppressWarnings("unchecked") - BinaryClassifierCreator castedCreator = (BinaryClassifierCreator) creator; - return castedCreator.create(block); - } -} diff --git a/src/main/java/javax/visrec/spi/ClassifierFactoryService.java b/src/main/java/javax/visrec/spi/ClassifierFactoryService.java new file mode 100644 index 0000000..d9ab51a --- /dev/null +++ b/src/main/java/javax/visrec/spi/ClassifierFactoryService.java @@ -0,0 +1,86 @@ +package javax.visrec.spi; + +import javax.visrec.ml.ClassifierCreationException; +import javax.visrec.ml.classification.BinaryClassifier; +import javax.visrec.ml.classification.Classifier; +import javax.visrec.ml.classification.ImageClassifier; +import javax.visrec.ml.classification.NeuralNetBinaryClassifier; +import java.util.HashMap; +import java.util.Map; +import java.util.ServiceLoader; + +/** + * Service to provide the correct {@link Classifier} implementation. + * + * @author Kevin Berendsen + * @since 1.0 + */ +public final class ClassifierFactoryService { + + private Map, ImageClassifierFactory> imageClassifierFactories; + private Map, BinaryClassifierFactory> binaryClassifierFactories; + + private static ClassifierFactoryService instance; + static ClassifierFactoryService getInstance() { + if (instance == null) { + instance = new ClassifierFactoryService(); + } + return instance; + } + + private ClassifierFactoryService() { + // Prevent instantiation + } + + /** + * Creates a new {@link ImageClassifier} by providing the {@link ImageClassifier.BuildingBlock} to tune + * the implementation's image classifier. + * + * @param block {@link ImageClassifier.BuildingBlock} is provided to tune the building of the image classifier. + * @return {@link ImageClassifier} + * @throws ClassifierCreationException if the classifier can not be created due to any reason. + */ + public ImageClassifier createImageClassifier(ImageClassifier.BuildingBlock block) throws ClassifierCreationException { + if (imageClassifierFactories == null) { + imageClassifierFactories = new HashMap<>(); + for (ImageClassifierFactory classifierCreator : ServiceLoader.load(ImageClassifierFactory.class)) { + imageClassifierFactories.put(classifierCreator.getImageClass(), classifierCreator); + } + } + + ImageClassifierFactory creator = imageClassifierFactories.get(block.getImageClass()); + if (creator == null) { + throw new ClassifierCreationException("Unsupported image class"); + } + + @SuppressWarnings("unchecked") + ImageClassifierFactory castedCreator = (ImageClassifierFactory) creator; + return castedCreator.create(block); + } + + /** + * Creates a new {@link BinaryClassifier} by providing the {@link NeuralNetBinaryClassifier.BuildingBlock} to tune + * the implementation's binary classifier. + * + * @param block {@link NeuralNetBinaryClassifier.BuildingBlock} is provided to tune the building of the binary classifier. + * @return {@link BinaryClassifier} + * @throws ClassifierCreationException if the classifier can not be created due to any reason. + */ + public BinaryClassifier createNeuralNetBinaryClassifier(NeuralNetBinaryClassifier.BuildingBlock block) throws ClassifierCreationException { + if (binaryClassifierFactories == null) { + binaryClassifierFactories = new HashMap<>(); + for (BinaryClassifierFactory classifierCreator : ServiceLoader.load(BinaryClassifierFactory.class)) { + binaryClassifierFactories.put(classifierCreator.getTargetClass(), classifierCreator); + } + } + + BinaryClassifierFactory creator = binaryClassifierFactories.get(block.getTargetClass()); + if (creator == null) { + throw new ClassifierCreationException("Unsupported target class"); + } + + @SuppressWarnings("unchecked") + BinaryClassifierFactory castedCreator = (BinaryClassifierFactory) creator; + return castedCreator.create(block); + } +} diff --git a/src/main/java/javax/visrec/spi/ImageClassifierCreator.java b/src/main/java/javax/visrec/spi/ImageClassifierFactory.java similarity index 85% rename from src/main/java/javax/visrec/spi/ImageClassifierCreator.java rename to src/main/java/javax/visrec/spi/ImageClassifierFactory.java index bf995fc..32658d5 100644 --- a/src/main/java/javax/visrec/spi/ImageClassifierCreator.java +++ b/src/main/java/javax/visrec/spi/ImageClassifierFactory.java @@ -3,7 +3,7 @@ import javax.visrec.ml.ClassifierCreationException; import javax.visrec.ml.classification.ImageClassifier; -public interface ImageClassifierCreator { +public interface ImageClassifierFactory { Class getImageClass(); diff --git a/src/main/java/javax/visrec/spi/ServiceProvider.java b/src/main/java/javax/visrec/spi/ServiceProvider.java index 8af181c..a4c9b88 100644 --- a/src/main/java/javax/visrec/spi/ServiceProvider.java +++ b/src/main/java/javax/visrec/spi/ServiceProvider.java @@ -44,11 +44,11 @@ public int getPriority() { public abstract BuilderService getBuilderService(); /** - * Get the {@link ClassifierCreatorService} + * Get the {@link ClassifierFactoryService} * @return classifier creator service */ - public ClassifierCreatorService getClassifierCreatorService() { - return ClassifierCreatorService.getInstance(); + public ClassifierFactoryService getClassifierFactoryService() { + return ClassifierFactoryService.getInstance(); } /** From 9476a0fc4e6109270e1b239ec9cea24da0657aee Mon Sep 17 00:00:00 2001 From: Kevin Berendsen Date: Sat, 1 Feb 2020 14:16:57 +0100 Subject: [PATCH 40/87] Created NeuralNetImageClassifier to contain the builder and building block for creating an image classifier with neural networks as underlying model --- .../ml/classification/ImageClassifier.java | 164 --------------- .../NeuralNetBinaryClassifier.java | 8 +- .../NeuralNetImageClassifier.java | 198 ++++++++++++++++++ .../visrec/spi/ClassifierFactoryService.java | 15 +- .../visrec/spi/ImageClassifierFactory.java | 3 +- 5 files changed, 210 insertions(+), 178 deletions(-) create mode 100644 src/main/java/javax/visrec/ml/classification/NeuralNetImageClassifier.java diff --git a/src/main/java/javax/visrec/ml/classification/ImageClassifier.java b/src/main/java/javax/visrec/ml/classification/ImageClassifier.java index 36194fe..149b931 100644 --- a/src/main/java/javax/visrec/ml/classification/ImageClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/ImageClassifier.java @@ -15,168 +15,4 @@ public interface ImageClassifier extends Classifier classify(InputStream input) throws ClassificationException; - static ImageClassifier.Builder builderOf(Class imgCls) { - return new Builder<>(imgCls); - } - - class BuildingBlock { - - private int imageWidth; - private int imageHeight; - private File networkArchitecture; - private File trainingsFile; - private File labelsFile; - private float maxError; - private float learningRate; - private File modelFile; - private int maxEpochs; - private Class imageClass; - - private BuildingBlock() { - } - - public File getNetworkArchitecture() { - return networkArchitecture; - } - - public int getImageWidth() { - return imageWidth; - } - - public int getImageHeight() { - return imageHeight; - } - - public File getTrainingsFile() { - return trainingsFile; - } - - public File getLabelsFile() { - return labelsFile; - } - - public float getMaxError() { - return maxError; - } - - public float getLearningRate() { - return learningRate; - } - - public File getModelFile() { - return modelFile; - } - - public int getMaxEpochs() { - return maxEpochs; - } - - public Class getImageClass() { return imageClass; } - } - - class Builder { - - private BuildingBlock block; - - private Builder(Class imgCls) { - block = new BuildingBlock<>(); - block.imageClass = imgCls; - } - - public Builder imageWidth(int imageWidth) { - block.imageWidth = imageWidth; - return this; - } - - public Builder imageHeight(int imageHeight) { - block.imageHeight = imageHeight; - return this; - } - - public Builder trainingsFile(File trainingsFile) { - block.trainingsFile = trainingsFile; - return this; - } - - public Builder labelsFile(File labelsFile) { - block.labelsFile = labelsFile; - return this; - } - - public Builder maxError(float maxError) { - block.maxError = maxError; - return this; - } - - public Builder maxEpochs(int epochs) { - block.maxEpochs = epochs; - return this; - } - - public Builder learningRate(float learningRate) { - block.learningRate = learningRate; - return this; - } - - public Builder modelFile(File modelFile) { - block.modelFile = modelFile; - return this; - } - - public Builder networkArchitecture(File architecture) { - block.networkArchitecture = architecture; - return this; - } - - public BuildingBlock getBuildingBlock() { - return block; - } - - public ImageClassifier build() throws ClassifierCreationException { - return ServiceProvider.current().getClassifierFactoryService().createImageClassifier(block); - } - - public ImageClassifier build(Map configuration) throws ClassifierCreationException { - Method[] methods = this.getClass().getDeclaredMethods(); - for (Method method : methods) { - if (!method.getName().equals("build") && method.getParameterCount() == 1 - && configuration.containsKey(method.getName())) { - try { - Object value = configuration.get(method.getName()); - Class expectedParameterType = method.getParameterTypes()[0]; - // Integer casting - if (expectedParameterType.equals(int.class) || expectedParameterType.equals(Integer.class)) { - if (value instanceof String) { - method.invoke(this, Integer.parseInt((String) value)); - continue; - } - } - - // Float casting - if (expectedParameterType.equals(float.class) || expectedParameterType.equals(Float.class)) { - if (value instanceof String) { - method.invoke(this, Float.parseFloat((String) value)); - continue; - } - } - - // File casting - if (expectedParameterType.equals(File.class)) { - if (value instanceof String) { - method.invoke(this, new File((String) value)); - continue; - } - } - - // Others - method.invoke(this, value); - } catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException e) { - throw new ClassifierCreationException("Couldn't invoke '" + method.getName() + "'", e); - } - } - } - return build(); - } - } - } diff --git a/src/main/java/javax/visrec/ml/classification/NeuralNetBinaryClassifier.java b/src/main/java/javax/visrec/ml/classification/NeuralNetBinaryClassifier.java index d7e82cd..3e037c5 100644 --- a/src/main/java/javax/visrec/ml/classification/NeuralNetBinaryClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/NeuralNetBinaryClassifier.java @@ -12,7 +12,7 @@ static NeuralNetBinaryClassifier.Builder builder() { } class BuildingBlock { - private Class targetCls; + private Class inputCls; private int inputsNum; private int[] hiddenLayers; private float maxError; @@ -23,8 +23,8 @@ class BuildingBlock { private BuildingBlock() { } - public Class getTargetClass() { - return targetCls; + public Class getInputClass() { + return inputCls; } public int getInputsNum() { @@ -53,7 +53,7 @@ public File getTrainingFile() { private static BuildingBlock copyWithNewTargetClass(BuildingBlock block, Class cls) { BuildingBlock newBlock = new BuildingBlock<>(); - newBlock.targetCls = cls; + newBlock.inputCls = cls; newBlock.inputsNum = block.inputsNum; newBlock.hiddenLayers = block.hiddenLayers; newBlock.maxError = block.maxError; diff --git a/src/main/java/javax/visrec/ml/classification/NeuralNetImageClassifier.java b/src/main/java/javax/visrec/ml/classification/NeuralNetImageClassifier.java new file mode 100644 index 0000000..1ac61b9 --- /dev/null +++ b/src/main/java/javax/visrec/ml/classification/NeuralNetImageClassifier.java @@ -0,0 +1,198 @@ +package javax.visrec.ml.classification; + +import javax.visrec.ml.ClassifierCreationException; +import javax.visrec.spi.ServiceProvider; +import java.io.File; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Map; + +public interface NeuralNetImageClassifier extends ImageClassifier { + + static NeuralNetImageClassifier.Builder builder() { + return new Builder<>(); + } + + class BuildingBlock { + + private int imageWidth; + private int imageHeight; + private File networkArchitecture; + private File trainingFile; + private File labelsFile; + private float maxError; + private float learningRate; + private File modelFile; + private int maxEpochs; + private Class inputCls; + + private BuildingBlock() { + } + + public File getNetworkArchitecture() { + return networkArchitecture; + } + + public int getImageWidth() { + return imageWidth; + } + + public int getImageHeight() { + return imageHeight; + } + + public File getTrainingFile() { + return trainingFile; + } + + public File getLabelsFile() { + return labelsFile; + } + + public float getMaxError() { + return maxError; + } + + public float getLearningRate() { + return learningRate; + } + + public File getModelFile() { + return modelFile; + } + + public int getMaxEpochs() { + return maxEpochs; + } + + public Class getInputClass() { return inputCls; } + + private static BuildingBlock copyWithNewInputClass(BuildingBlock block, Class cls) { + BuildingBlock newBlock = new BuildingBlock<>(); + newBlock.inputCls = cls; + newBlock.imageHeight = block.imageHeight; + newBlock.imageWidth = block.imageWidth; + newBlock.labelsFile = block.labelsFile; + newBlock.modelFile = block.modelFile; + newBlock.networkArchitecture = block.networkArchitecture; + newBlock.maxError = block.maxError; + newBlock.maxEpochs = block.maxEpochs; + newBlock.learningRate = block.learningRate; + newBlock.trainingFile = block.trainingFile; + return newBlock; + } + } + + class Builder { + + private BuildingBlock block; + + private Builder() { + block = new BuildingBlock<>(); + } + + private Builder(BuildingBlock block) { + this.block = block; + } + + public Builder inputClass(Class cls) { + BuildingBlock newBlock = BuildingBlock.copyWithNewInputClass(block, cls); + return new Builder<>(newBlock); + } + + public Builder imageWidth(int imageWidth) { + block.imageWidth = imageWidth; + return this; + } + + public Builder imageHeight(int imageHeight) { + block.imageHeight = imageHeight; + return this; + } + + public Builder trainingFile(File trainingFile) { + block.trainingFile = trainingFile; + return this; + } + + public Builder labelsFile(File labelsFile) { + block.labelsFile = labelsFile; + return this; + } + + public Builder maxError(float maxError) { + block.maxError = maxError; + return this; + } + + public Builder maxEpochs(int epochs) { + block.maxEpochs = epochs; + return this; + } + + public Builder learningRate(float learningRate) { + block.learningRate = learningRate; + return this; + } + + public Builder modelFile(File modelFile) { + block.modelFile = modelFile; + return this; + } + + public Builder networkArchitecture(File architecture) { + block.networkArchitecture = architecture; + return this; + } + + public BuildingBlock getBuildingBlock() { + return block; + } + + public ImageClassifier build() throws ClassifierCreationException { + return ServiceProvider.current().getClassifierFactoryService().createNeuralNetImageClassifier(block); + } + + public ImageClassifier build(Map configuration) throws ClassifierCreationException { + Method[] methods = this.getClass().getDeclaredMethods(); + for (Method method : methods) { + if (!method.getName().equals("build") && method.getParameterCount() == 1 + && configuration.containsKey(method.getName())) { + try { + Object value = configuration.get(method.getName()); + Class expectedParameterType = method.getParameterTypes()[0]; + // Integer casting + if (expectedParameterType.equals(int.class) || expectedParameterType.equals(Integer.class)) { + if (value instanceof String) { + method.invoke(this, Integer.parseInt((String) value)); + continue; + } + } + + // Float casting + if (expectedParameterType.equals(float.class) || expectedParameterType.equals(Float.class)) { + if (value instanceof String) { + method.invoke(this, Float.parseFloat((String) value)); + continue; + } + } + + // File casting + if (expectedParameterType.equals(File.class)) { + if (value instanceof String) { + method.invoke(this, new File((String) value)); + continue; + } + } + + // Others + method.invoke(this, value); + } catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException e) { + throw new ClassifierCreationException("Couldn't invoke '" + method.getName() + "'", e); + } + } + } + return build(); + } + } +} diff --git a/src/main/java/javax/visrec/spi/ClassifierFactoryService.java b/src/main/java/javax/visrec/spi/ClassifierFactoryService.java index d9ab51a..b01e959 100644 --- a/src/main/java/javax/visrec/spi/ClassifierFactoryService.java +++ b/src/main/java/javax/visrec/spi/ClassifierFactoryService.java @@ -1,10 +1,7 @@ package javax.visrec.spi; import javax.visrec.ml.ClassifierCreationException; -import javax.visrec.ml.classification.BinaryClassifier; -import javax.visrec.ml.classification.Classifier; -import javax.visrec.ml.classification.ImageClassifier; -import javax.visrec.ml.classification.NeuralNetBinaryClassifier; +import javax.visrec.ml.classification.*; import java.util.HashMap; import java.util.Map; import java.util.ServiceLoader; @@ -33,14 +30,14 @@ private ClassifierFactoryService() { } /** - * Creates a new {@link ImageClassifier} by providing the {@link ImageClassifier.BuildingBlock} to tune + * Creates a new {@link ImageClassifier} by providing the {@link NeuralNetImageClassifier.BuildingBlock} to tune * the implementation's image classifier. * - * @param block {@link ImageClassifier.BuildingBlock} is provided to tune the building of the image classifier. + * @param block {@link NeuralNetImageClassifier.BuildingBlock} is provided to tune the building of the image classifier. * @return {@link ImageClassifier} * @throws ClassifierCreationException if the classifier can not be created due to any reason. */ - public ImageClassifier createImageClassifier(ImageClassifier.BuildingBlock block) throws ClassifierCreationException { + public ImageClassifier createNeuralNetImageClassifier(NeuralNetImageClassifier.BuildingBlock block) throws ClassifierCreationException { if (imageClassifierFactories == null) { imageClassifierFactories = new HashMap<>(); for (ImageClassifierFactory classifierCreator : ServiceLoader.load(ImageClassifierFactory.class)) { @@ -48,7 +45,7 @@ public ImageClassifier createImageClassifier(ImageClassifier.BuildingBloc } } - ImageClassifierFactory creator = imageClassifierFactories.get(block.getImageClass()); + ImageClassifierFactory creator = imageClassifierFactories.get(block.getInputClass()); if (creator == null) { throw new ClassifierCreationException("Unsupported image class"); } @@ -74,7 +71,7 @@ public BinaryClassifier createNeuralNetBinaryClassifier(NeuralNetBinaryCl } } - BinaryClassifierFactory creator = binaryClassifierFactories.get(block.getTargetClass()); + BinaryClassifierFactory creator = binaryClassifierFactories.get(block.getInputClass()); if (creator == null) { throw new ClassifierCreationException("Unsupported target class"); } diff --git a/src/main/java/javax/visrec/spi/ImageClassifierFactory.java b/src/main/java/javax/visrec/spi/ImageClassifierFactory.java index 32658d5..04b1e36 100644 --- a/src/main/java/javax/visrec/spi/ImageClassifierFactory.java +++ b/src/main/java/javax/visrec/spi/ImageClassifierFactory.java @@ -2,11 +2,12 @@ import javax.visrec.ml.ClassifierCreationException; import javax.visrec.ml.classification.ImageClassifier; +import javax.visrec.ml.classification.NeuralNetImageClassifier; public interface ImageClassifierFactory { Class getImageClass(); - ImageClassifier create(ImageClassifier.BuildingBlock block) throws ClassifierCreationException; + ImageClassifier create(NeuralNetImageClassifier.BuildingBlock block) throws ClassifierCreationException; } From dc3a661c4bf67d000d6cd89bfc7da626b9cbebdf Mon Sep 17 00:00:00 2001 From: Zoran Sevarac Date: Wed, 5 Feb 2020 11:33:05 +0100 Subject: [PATCH 41/87] ClassificationException to RuntimeException --- src/main/java/javax/visrec/ml/ClassificationException.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/javax/visrec/ml/ClassificationException.java b/src/main/java/javax/visrec/ml/ClassificationException.java index 6cd6b31..b02f8e7 100644 --- a/src/main/java/javax/visrec/ml/ClassificationException.java +++ b/src/main/java/javax/visrec/ml/ClassificationException.java @@ -6,7 +6,7 @@ * @author Kevin Berendsen * @since 1.0 */ -public class ClassificationException extends Exception { +public class ClassificationException extends RuntimeException { /** * Creates a new instance of the exception From f51657a792186c5ab3d95571212b776464d16bc1 Mon Sep 17 00:00:00 2001 From: Kevin Berendsen Date: Wed, 25 Mar 2020 11:17:31 +0100 Subject: [PATCH 42/87] Create snapshot on each commit on master. --- .github/workflows/snapshot.yml | 41 ++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 .github/workflows/snapshot.yml diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml new file mode 100644 index 0000000..dfd97ec --- /dev/null +++ b/.github/workflows/snapshot.yml @@ -0,0 +1,41 @@ +name: Maven Package + +on: + push: + branches: + - master + pull_request: + branches: + - master + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 1.8 + uses: actions/setup-java@v1 + with: + java-version: 1.8 + #settings-path: ${{ github.workspace }} # location for the settings.xml + #server-id: github # Value of the distributionManagement/repository/id field of the pom.xml + + - name: Override version and build with Maven + run: ./mvnw versions:set -DnewVersion= package + + - name: Persist private key to local file + run: echo $PRIVATE_KEY > private.key + env: + PRIVATE_KEY: ${{ secrets.GPG_SECRET_KEY }} + + - name: Add secret key to GPG keyring + run: gpg --import --batch private.key + + - name: Publish to snapshot repository + run: ./mvnw deploy -s $GITHUB_WORKSPACE/settings.xml + env: + OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} + OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} + GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} From cd45c64bcbfec3200fbaf97d756c6da16d0b9d94 Mon Sep 17 00:00:00 2001 From: Kevin Berendsen Date: Wed, 25 Mar 2020 11:20:35 +0100 Subject: [PATCH 43/87] Added maven wrapper and support for suffix in version. --- .github/workflows/settings.xml | 29 +++ .mvn/wrapper/MavenWrapperDownloader.java | 117 +++++++++ .mvn/wrapper/maven-wrapper.jar | Bin 0 -> 50710 bytes .mvn/wrapper/maven-wrapper.properties | 2 + build.gradle | 9 - gradlew | 172 ------------- gradlew.bat | 84 ------ mvnw | 310 +++++++++++++++++++++++ mvnw.cmd | 182 +++++++++++++ pom.xml | 35 ++- 10 files changed, 656 insertions(+), 284 deletions(-) create mode 100644 .github/workflows/settings.xml create mode 100644 .mvn/wrapper/MavenWrapperDownloader.java create mode 100644 .mvn/wrapper/maven-wrapper.jar create mode 100644 .mvn/wrapper/maven-wrapper.properties delete mode 100644 build.gradle delete mode 100644 gradlew delete mode 100644 gradlew.bat create mode 100755 mvnw create mode 100644 mvnw.cmd diff --git a/.github/workflows/settings.xml b/.github/workflows/settings.xml new file mode 100644 index 0000000..52e7d0b --- /dev/null +++ b/.github/workflows/settings.xml @@ -0,0 +1,29 @@ + + + + + + ossrh + ${env.OSSRH_USERNAME} + ${env.OSSRH_PASSWORD} + + + + + + ossrh + + true + + + gpg + + + + + + ossrh + + \ No newline at end of file diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java new file mode 100644 index 0000000..b901097 --- /dev/null +++ b/.mvn/wrapper/MavenWrapperDownloader.java @@ -0,0 +1,117 @@ +/* + * Copyright 2007-present the original author or authors. + * + * Licensed 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. + */ +import java.net.*; +import java.io.*; +import java.nio.channels.*; +import java.util.Properties; + +public class MavenWrapperDownloader { + + private static final String WRAPPER_VERSION = "0.5.6"; + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" + + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to + * use instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = + ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = + ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main(String args[]) { + System.out.println("- Downloader started"); + File baseDirectory = new File(args[0]); + System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); + + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); + String url = DEFAULT_DOWNLOAD_URL; + if(mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); + url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); + } catch (IOException e) { + System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); + } finally { + try { + if(mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } catch (IOException e) { + // Ignore ... + } + } + } + System.out.println("- Downloading from: " + url); + + File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); + if(!outputFile.getParentFile().exists()) { + if(!outputFile.getParentFile().mkdirs()) { + System.out.println( + "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); + } + } + System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + try { + downloadFileFromURL(url, outputFile); + System.out.println("Done"); + System.exit(0); + } catch (Throwable e) { + System.out.println("- Error downloading"); + e.printStackTrace(); + System.exit(1); + } + } + + private static void downloadFileFromURL(String urlString, File destination) throws Exception { + if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { + String username = System.getenv("MVNW_USERNAME"); + char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); + Authenticator.setDefault(new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password); + } + }); + } + URL website = new URL(urlString); + ReadableByteChannel rbc; + rbc = Channels.newChannel(website.openStream()); + FileOutputStream fos = new FileOutputStream(destination); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + rbc.close(); + } + +} diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..2cc7d4a55c0cd0092912bf49ae38b3a9e3fd0054 GIT binary patch literal 50710 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 EfAhh=DF6Tf literal 0 HcmV?d00001 diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..1191fde --- /dev/null +++ b/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.1/apache-maven-3.6.1-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 5fda024..0000000 --- a/build.gradle +++ /dev/null @@ -1,9 +0,0 @@ -apply plugin: 'java' - -sourceCompatibility = 1.8 - -dependencies { - compile 'org.json:json:20160212' - - testCompile 'junit:junit:4.0' -} \ No newline at end of file diff --git a/gradlew b/gradlew deleted file mode 100644 index 518efff..0000000 --- a/gradlew +++ /dev/null @@ -1,172 +0,0 @@ -#!/usr/bin/env sh - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn () { - echo "$*" -} - -die () { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - -exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat deleted file mode 100644 index e95643d..0000000 --- a/gradlew.bat +++ /dev/null @@ -1,84 +0,0 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/mvnw b/mvnw new file mode 100755 index 0000000..41c0f0c --- /dev/null +++ b/mvnw @@ -0,0 +1,310 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# 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. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/mvnw.cmd b/mvnw.cmd new file mode 100644 index 0000000..8611571 --- /dev/null +++ b/mvnw.cmd @@ -0,0 +1,182 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + +FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/pom.xml b/pom.xml index 3efcb26..83326dd 100644 --- a/pom.xml +++ b/pom.xml @@ -1,9 +1,10 @@ - + 4.0.0 javax.visrec visrec-api - 1.0-SNAPSHOT + 1.0.0${version.suffix} jar javax.visrec:visrec-api @@ -42,20 +43,15 @@ UTF-8 1.8 1.8 + -SNAPSHOT - - org.json - json - 20160212 - jar - - junit junit 4.0 + test @@ -64,21 +60,21 @@ ossrh https://oss.sonatype.org/content/repositories/snapshots - - - - + + ossrh + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + - + org.sonatype.plugins @@ -100,13 +96,14 @@ - @@ -116,7 +113,7 @@ - + org.apache.maven.plugins From 4ba5241950132e12601d8dcd94da4f33dfb898ce Mon Sep 17 00:00:00 2001 From: Kevin Berendsen Date: Wed, 25 Mar 2020 11:22:11 +0100 Subject: [PATCH 44/87] Removed overriding of version in workflow. --- .github/workflows/snapshot.yml | 52 +++++++++++++++++----------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index dfd97ec..ebe1238 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -7,35 +7,35 @@ on: pull_request: branches: - master - + jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - name: Set up JDK 1.8 - uses: actions/setup-java@v1 - with: - java-version: 1.8 - #settings-path: ${{ github.workspace }} # location for the settings.xml - #server-id: github # Value of the distributionManagement/repository/id field of the pom.xml - - - name: Override version and build with Maven - run: ./mvnw versions:set -DnewVersion= package - - - name: Persist private key to local file - run: echo $PRIVATE_KEY > private.key - env: - PRIVATE_KEY: ${{ secrets.GPG_SECRET_KEY }} - - - name: Add secret key to GPG keyring - run: gpg --import --batch private.key - - - name: Publish to snapshot repository - run: ./mvnw deploy -s $GITHUB_WORKSPACE/settings.xml - env: - OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} - OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} - GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} + - uses: actions/checkout@v2 + - name: Set up JDK 1.8 + uses: actions/setup-java@v1 + with: + java-version: 1.8 + #settings-path: ${{ github.workspace }} # location for the settings.xml + #server-id: github # Value of the distributionManagement/repository/id field of the pom.xml + + - name: Build with Maven + run: ./mvnw package + + - name: Persist private key to local file + run: echo $PRIVATE_KEY > private.key + env: + PRIVATE_KEY: ${{ secrets.GPG_SECRET_KEY }} + + - name: Add secret key to GPG keyring + run: gpg --import --batch private.key + + - name: Publish to snapshot repository + run: ./mvnw deploy -s $GITHUB_WORKSPACE/settings.xml + env: + OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} + OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} + GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} From a1543667bd7a63373c08da43fbbe0497a59651f5 Mon Sep 17 00:00:00 2001 From: Kevin Berendsen Date: Wed, 25 Mar 2020 11:29:18 +0100 Subject: [PATCH 45/87] Combining two steps in workflow. --- .github/workflows/snapshot.yml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index ebe1238..be2fd91 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -25,14 +25,13 @@ jobs: - name: Build with Maven run: ./mvnw package - - name: Persist private key to local file - run: echo $PRIVATE_KEY > private.key + - name: Add private key to keyring + run: | + echo "${PRIVATE_KEY}" > private.key + gpg --import --batch private.key env: PRIVATE_KEY: ${{ secrets.GPG_SECRET_KEY }} - - name: Add secret key to GPG keyring - run: gpg --import --batch private.key - - name: Publish to snapshot repository run: ./mvnw deploy -s $GITHUB_WORKSPACE/settings.xml env: From eee975fd5a02c4056f88c16f40b96f2cf44ddb7f Mon Sep 17 00:00:00 2001 From: Kevin Berendsen Date: Wed, 25 Mar 2020 11:36:42 +0100 Subject: [PATCH 46/87] Moving settings.xml to root --- .github/workflows/settings.xml => settings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename .github/workflows/settings.xml => settings.xml (92%) diff --git a/.github/workflows/settings.xml b/settings.xml similarity index 92% rename from .github/workflows/settings.xml rename to settings.xml index 52e7d0b..57135b5 100644 --- a/.github/workflows/settings.xml +++ b/settings.xml @@ -19,7 +19,7 @@ gpg - + ${env.GPG_PASSPHRASE} From 285dfe9528b3ed489532669cc706563e7c5825f2 Mon Sep 17 00:00:00 2001 From: Kevin Berendsen Date: Wed, 25 Mar 2020 11:52:44 +0100 Subject: [PATCH 47/87] Small enhancements to pom and workflow. --- .github/workflows/snapshot.yml | 3 +-- pom.xml | 8 +++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index be2fd91..51dcb3a 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -21,7 +21,6 @@ jobs: java-version: 1.8 #settings-path: ${{ github.workspace }} # location for the settings.xml #server-id: github # Value of the distributionManagement/repository/id field of the pom.xml - - name: Build with Maven run: ./mvnw package @@ -33,7 +32,7 @@ jobs: PRIVATE_KEY: ${{ secrets.GPG_SECRET_KEY }} - name: Publish to snapshot repository - run: ./mvnw deploy -s $GITHUB_WORKSPACE/settings.xml + run: ./mvnw deploy -s settings.xml env: OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} diff --git a/pom.xml b/pom.xml index 83326dd..a3b3656 100644 --- a/pom.xml +++ b/pom.xml @@ -72,7 +72,6 @@ org.apache.maven.plugins maven-gpg-plugin 1.5 - sign-artifacts @@ -80,6 +79,13 @@ sign + + + + --pinentry-mode + loopback + + From 511e6beb49392be5d17efd78a34d8733b20502b3 Mon Sep 17 00:00:00 2001 From: Kevin Berendsen Date: Wed, 25 Mar 2020 12:25:08 +0100 Subject: [PATCH 48/87] Added staging profile in workflow. --- .github/workflows/staging.yml | 44 +++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 .github/workflows/staging.yml diff --git a/.github/workflows/staging.yml b/.github/workflows/staging.yml new file mode 100644 index 0000000..934c165 --- /dev/null +++ b/.github/workflows/staging.yml @@ -0,0 +1,44 @@ +name: Maven Package + +on: + # To trigger this workflow manually, you can use the following curl command: + # curl -XPOST -u "USERNAME:PERSONAL_TOKEN" -H "Accept: application/vnd.github.everest-preview+json" -H "Content-Type: application/json" https://api.github.com/repos/JavaVisRec/visrec-api/dispatches --data '{"event_type": "staging-pub"}' + + # Make sure you create your personal token with repo access. Follow steps in + # https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line + # to create your personal token. + + # Special thanks to AWS Labs & AWS DJL project for this approach + repository_dispatch: + types: [staging-pub] + + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 1.8 + uses: actions/setup-java@v1 + with: + java-version: 1.8 + #settings-path: ${{ github.workspace }} # location for the settings.xml + #server-id: github # Value of the distributionManagement/repository/id field of the pom.xml + - name: Build with Maven + run: ./mvnw package + + - name: Add private key to keyring + run: | + echo "${PRIVATE_KEY}" > private.key + gpg --import --batch private.key + env: + PRIVATE_KEY: ${{ secrets.GPG_SECRET_KEY }} + + - name: Publish to snapshot repository + run: ./mvnw deploy -s settings.xml -Dversion.suffix= + env: + OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} + OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} + GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} From 7ef25eb82b386d155b2a6bdec2c17bbfc5163f2a Mon Sep 17 00:00:00 2001 From: Kevin Berendsen Date: Wed, 25 Mar 2020 13:18:24 +0100 Subject: [PATCH 49/87] Updated workflows --- .github/workflows/snapshot.yml | 4 ++-- .github/workflows/staging.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index 51dcb3a..aadc38c 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -1,4 +1,4 @@ -name: Maven Package +name: snapshot on: push: @@ -31,7 +31,7 @@ jobs: env: PRIVATE_KEY: ${{ secrets.GPG_SECRET_KEY }} - - name: Publish to snapshot repository + - name: Publish to repository run: ./mvnw deploy -s settings.xml env: OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} diff --git a/.github/workflows/staging.yml b/.github/workflows/staging.yml index 934c165..fc900f9 100644 --- a/.github/workflows/staging.yml +++ b/.github/workflows/staging.yml @@ -1,4 +1,4 @@ -name: Maven Package +name: staging on: # To trigger this workflow manually, you can use the following curl command: @@ -36,7 +36,7 @@ jobs: env: PRIVATE_KEY: ${{ secrets.GPG_SECRET_KEY }} - - name: Publish to snapshot repository + - name: Publish to repository run: ./mvnw deploy -s settings.xml -Dversion.suffix= env: OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} From 15ceec132482ae281610328b1fce02dc87818285 Mon Sep 17 00:00:00 2001 From: Kevin Berendsen Date: Sat, 11 Apr 2020 11:07:51 +0200 Subject: [PATCH 50/87] Added github action to build the API on every commit --- .github/workflows/build.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..65f0b58 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,22 @@ +name: build + +on: + push: + branches: + - master + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 1.8 + uses: actions/setup-java@v1 + with: + java-version: 1.8 + #settings-path: ${{ github.workspace }} # location for the settings.xml + #server-id: github # Value of the distributionManagement/repository/id field of the pom.xml + - name: Build with Maven + run: ./mvnw install From d2bac78812c778491eca1114fbd79474a0bd88c0 Mon Sep 17 00:00:00 2001 From: Kevin Berendsen Date: Sat, 11 Apr 2020 11:24:56 +0200 Subject: [PATCH 51/87] modified github actions --- .github/workflows/snapshot.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index aadc38c..6bff773 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -1,9 +1,11 @@ name: snapshot + # To trigger this workflow manually, you can use the following curl command: + # curl -XPOST -u "USERNAME:PERSONAL_TOKEN" -H "Accept: application/vnd.github.everest-preview+json" -H "Content-Type: application/json" https://api.github.com/repos/JavaVisRec/visrec-api/dispatches --data '{"event_type": "snapshot-pub"}' + on: - push: - branches: - - master + repository_dispatch: + types: [snapshot-pub] pull_request: branches: - master From 524568a9f38b9fefe49c51b8e719393c3bf57cea Mon Sep 17 00:00:00 2001 From: Kevin Berendsen Date: Sat, 11 Apr 2020 11:31:13 +0200 Subject: [PATCH 52/87] modified build github action --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 65f0b58..c442be9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,4 +19,4 @@ jobs: #settings-path: ${{ github.workspace }} # location for the settings.xml #server-id: github # Value of the distributionManagement/repository/id field of the pom.xml - name: Build with Maven - run: ./mvnw install + run: ./mvnw package From 237b81ac69a03e5cd15f682233d5f315b532ddd0 Mon Sep 17 00:00:00 2001 From: Kevin Berendsen Date: Sat, 11 Apr 2020 12:04:12 +0200 Subject: [PATCH 53/87] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 3c00e40..9370027 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,7 @@ # visrec-api +![build](https://github.com/JavaVisRec/visrec-api/workflows/build/badge.svg) +![Sonatype Nexus (Releases)](https://img.shields.io/nexus/r/javax.visrec/visrec-api?label=maven%20central&server=https%3A%2F%2Foss.sonatype.org%2F) + This repo contains specification of standard Visual Recognition API for Java (JSR381) The Visual Recognition API JSR #381 is a software development standard recognized by the Java Community Process (JCP) that simplifies and standardizes a set of APIs familiar to Java developers for classifying and recognizing objects in images using machine learning. Beside classes specific for visual recognition tasks, it provides general abstractions for machine learning tasks like classification, regression and data set, and reusable design which can be applied for machine learning systems in other domains. From ead52af3512eac3fcf389da944080687ab4e938f Mon Sep 17 00:00:00 2001 From: Zoran Sevarac Date: Sun, 19 Apr 2020 08:28:18 +0200 Subject: [PATCH 54/87] added exportPath importPath methods --- .../javax/visrec/AbstractImageClassifier.java | 10 ++----- .../ml/classification/ImageClassifier.java | 4 --- .../NeuralNetImageClassifier.java | 26 ++++++++++++++----- .../visrec/ml/eval/EvaluationMetrics.java | 3 +-- 4 files changed, 23 insertions(+), 20 deletions(-) diff --git a/src/main/java/javax/visrec/AbstractImageClassifier.java b/src/main/java/javax/visrec/AbstractImageClassifier.java index e5e0f73..ed9f624 100644 --- a/src/main/java/javax/visrec/AbstractImageClassifier.java +++ b/src/main/java/javax/visrec/AbstractImageClassifier.java @@ -29,7 +29,7 @@ public abstract class AbstractImageClassifier implemen private ImageFactory imageFactory; // image factory impl for the specified image class private MODEL_CLASS model; // the model could be injected from machine learning container? - private float threshold; // this should ba a part of every classifier + private float threshold=0.5f; // this should ba a part of every classifier protected AbstractImageClassifier(final Class imgCls, final MODEL_CLASS model) { final Optional> optionalImageFactory = ServiceProvider.current() @@ -70,17 +70,11 @@ public Map classify(InputStream inputStream) throws Classificatio // todo: provide get top 1, 3, 5 results; sort and get - // do we need this now, when impl is loaded using service provider? - // Kevin and Zoran disussed: probably not needed now when we have service provider impl, and we dont want to allow user to mess with it -// public void setImageFactory(ImageFactory imageFactory) { -// this.imageFactory = imageFactory; -// } - public MODEL_CLASS getModel() { return model; } - public void setModel(MODEL_CLASS model) { + public final void setModel(MODEL_CLASS model) { this.model = Objects.requireNonNull(model, "Model cannot bu null!"); } diff --git a/src/main/java/javax/visrec/ml/classification/ImageClassifier.java b/src/main/java/javax/visrec/ml/classification/ImageClassifier.java index 149b931..af17643 100644 --- a/src/main/java/javax/visrec/ml/classification/ImageClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/ImageClassifier.java @@ -1,12 +1,8 @@ package javax.visrec.ml.classification; import javax.visrec.ml.ClassificationException; -import javax.visrec.ml.ClassifierCreationException; -import javax.visrec.spi.ServiceProvider; import java.io.File; import java.io.InputStream; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.util.Map; public interface ImageClassifier extends Classifier>{ diff --git a/src/main/java/javax/visrec/ml/classification/NeuralNetImageClassifier.java b/src/main/java/javax/visrec/ml/classification/NeuralNetImageClassifier.java index 1ac61b9..b1b5e50 100644 --- a/src/main/java/javax/visrec/ml/classification/NeuralNetImageClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/NeuralNetImageClassifier.java @@ -5,6 +5,7 @@ import java.io.File; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.nio.file.Path; import java.util.Map; public interface NeuralNetImageClassifier extends ImageClassifier { @@ -22,7 +23,8 @@ class BuildingBlock { private File labelsFile; private float maxError; private float learningRate; - private File modelFile; + private Path exportPath; + private Path importPath; private int maxEpochs; private Class inputCls; @@ -57,10 +59,16 @@ public float getLearningRate() { return learningRate; } - public File getModelFile() { - return modelFile; + public Path getExportPath() { + return exportPath; } + public Path getImportPath() { + return importPath; + } + + + public int getMaxEpochs() { return maxEpochs; } @@ -73,7 +81,8 @@ private static BuildingBlock copyWithNewInputClass(BuildingBlock block newBlock.imageHeight = block.imageHeight; newBlock.imageWidth = block.imageWidth; newBlock.labelsFile = block.labelsFile; - newBlock.modelFile = block.modelFile; + newBlock.exportPath = block.exportPath; + newBlock.importPath = block.importPath; newBlock.networkArchitecture = block.networkArchitecture; newBlock.maxError = block.maxError; newBlock.maxEpochs = block.maxEpochs; @@ -135,11 +144,16 @@ public Builder learningRate(float learningRate) { return this; } - public Builder modelFile(File modelFile) { - block.modelFile = modelFile; + public Builder exportModel(Path path) { + block.exportPath = path; return this; } + public Builder importModel(Path path) { + block.importPath = path; + return this; + } + public Builder networkArchitecture(File architecture) { block.networkArchitecture = architecture; return this; diff --git a/src/main/java/javax/visrec/ml/eval/EvaluationMetrics.java b/src/main/java/javax/visrec/ml/eval/EvaluationMetrics.java index 0e429c8..fdbb04a 100644 --- a/src/main/java/javax/visrec/ml/eval/EvaluationMetrics.java +++ b/src/main/java/javax/visrec/ml/eval/EvaluationMetrics.java @@ -68,7 +68,7 @@ public class EvaluationMetrics { public final static String RECALL = "Recall"; public final static String F1SCORE = "F1Score"; - // + // Hold values of relevant evaluation metrics private final HashMap values = new HashMap(); private final static HashMap description = new HashMap(); @@ -99,7 +99,6 @@ public String toString() { .append(")"); sb.append(System.lineSeparator()); }); - // todo: also append decsripton return sb.toString(); } From 7630b0dc72a1740d2a81c80a1ce2676181e0d90b Mon Sep 17 00:00:00 2001 From: Frank Liu Date: Sun, 19 Apr 2020 20:43:14 -0700 Subject: [PATCH 55/87] Workaround invalid matdata file published by maven 1. increase version to 1.0.1 2. use constant in version 3. use sed to remove -SNAPSHOT in Actions yml file 4. only requires sign at deploy stage --- .github/workflows/staging.yml | 4 +++- pom.xml | 5 ++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/staging.yml b/.github/workflows/staging.yml index fc900f9..d860d41 100644 --- a/.github/workflows/staging.yml +++ b/.github/workflows/staging.yml @@ -37,7 +37,9 @@ jobs: PRIVATE_KEY: ${{ secrets.GPG_SECRET_KEY }} - name: Publish to repository - run: ./mvnw deploy -s settings.xml -Dversion.suffix= + run: | + sed -i "s/-SNAPSHOT//g" pom.xml + ./mvnw deploy -s settings.xml env: OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} diff --git a/pom.xml b/pom.xml index a3b3656..8e014b2 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 javax.visrec visrec-api - 1.0.0${version.suffix} + 1.0.1-SNAPSHOT jar javax.visrec:visrec-api @@ -43,7 +43,6 @@ UTF-8 1.8 1.8 - -SNAPSHOT @@ -75,7 +74,7 @@ sign-artifacts - verify + deploy sign From fe2fd6249f3e06d96243a5a6fdab827060bdf846 Mon Sep 17 00:00:00 2001 From: Kevin Berendsen Date: Wed, 22 Apr 2020 10:04:57 +0200 Subject: [PATCH 56/87] Update README.md --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 9370027..76a5a5a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,5 @@ # visrec-api -![build](https://github.com/JavaVisRec/visrec-api/workflows/build/badge.svg) -![Sonatype Nexus (Releases)](https://img.shields.io/nexus/r/javax.visrec/visrec-api?label=maven%20central&server=https%3A%2F%2Foss.sonatype.org%2F) +![build](https://github.com/JavaVisRec/visrec-api/workflows/build/badge.svg) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/javax.visrec/visrec-api/badge.svg)](https://maven-badges.herokuapp.com/maven-central/javax.visrec/visrec-api) This repo contains specification of standard Visual Recognition API for Java (JSR381) From b2ac8da8fecefe182086b8c4b8d6428b7f43b126 Mon Sep 17 00:00:00 2001 From: Zoran Sevarac Date: Tue, 14 Jul 2020 13:56:24 +0200 Subject: [PATCH 57/87] Moved LogisticRegression to classification package --- .../ml/{regression => classification}/LogisticRegression.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/main/java/javax/visrec/ml/{regression => classification}/LogisticRegression.java (93%) diff --git a/src/main/java/javax/visrec/ml/regression/LogisticRegression.java b/src/main/java/javax/visrec/ml/classification/LogisticRegression.java similarity index 93% rename from src/main/java/javax/visrec/ml/regression/LogisticRegression.java rename to src/main/java/javax/visrec/ml/classification/LogisticRegression.java index 355aba7..9192f7f 100644 --- a/src/main/java/javax/visrec/ml/regression/LogisticRegression.java +++ b/src/main/java/javax/visrec/ml/classification/LogisticRegression.java @@ -1,4 +1,4 @@ -package javax.visrec.ml.regression; +package javax.visrec.ml.classification; import javax.visrec.ml.classification.BinaryClassifier; From 90bc75c349e4657968fe9743482f82ebef90b400 Mon Sep 17 00:00:00 2001 From: Zoran Sevarac Date: Tue, 14 Jul 2020 14:01:38 +0200 Subject: [PATCH 58/87] Added ModelProvider to LogisticRegression --- .../visrec/ml/classification/LogisticRegression.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/javax/visrec/ml/classification/LogisticRegression.java b/src/main/java/javax/visrec/ml/classification/LogisticRegression.java index 9192f7f..95095f2 100644 --- a/src/main/java/javax/visrec/ml/classification/LogisticRegression.java +++ b/src/main/java/javax/visrec/ml/classification/LogisticRegression.java @@ -1,17 +1,20 @@ package javax.visrec.ml.classification; -import javax.visrec.ml.classification.BinaryClassifier; +import javax.visrec.util.ModelProvider; /** - * This class performs basic binary classification - mapping of specified input to true/false with probability. + * This class performs basic binary classification - mapping of specified input to true/false with probability + * using logistic regression algorithm. + * Subclasses should use specific logistic regression implementation to provide that functionality. * * @author Zoran Sevarac * @param Implementation class of underlying machine learning model */ -public abstract class LogisticRegression implements BinaryClassifier { +public abstract class LogisticRegression implements BinaryClassifier, ModelProvider { private MODEL_CLASS model; + @Override public MODEL_CLASS getModel() { return model; } @@ -20,5 +23,4 @@ protected void setModel(MODEL_CLASS model) { this.model = model; } - // add train method here so we can dow model.train() } From 85feaf85fb274127763071222c4d3449da97713a Mon Sep 17 00:00:00 2001 From: Zoran Sevarac Date: Tue, 14 Jul 2020 15:28:16 +0200 Subject: [PATCH 59/87] Renaming type param to conform convention in ModelProvider --- src/main/java/javax/visrec/util/ModelProvider.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/main/java/javax/visrec/util/ModelProvider.java b/src/main/java/javax/visrec/util/ModelProvider.java index 6c1b9b6..eb3e3f0 100644 --- a/src/main/java/javax/visrec/util/ModelProvider.java +++ b/src/main/java/javax/visrec/util/ModelProvider.java @@ -1,14 +1,12 @@ package javax.visrec.util; /** - * This interface should be implemented if we want to allow access to underlying ML model - * @author Zoran - * @param + * This interface should be implemented by classes which expose access to underlying ML model + * + * @param Type of underlying ML model */ -public interface ModelProvider { +public interface ModelProvider { - M getModel(); - - // also provide public setModel to allow model injection? + T getModel(); } From 31b7e42d2fc50f83f584664145d59dab5cd7ec2d Mon Sep 17 00:00:00 2001 From: Zoran Sevarac Date: Tue, 14 Jul 2020 15:29:12 +0200 Subject: [PATCH 60/87] javadoc fixes --- src/main/java/javax/visrec/util/ModelProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/javax/visrec/util/ModelProvider.java b/src/main/java/javax/visrec/util/ModelProvider.java index eb3e3f0..de5f964 100644 --- a/src/main/java/javax/visrec/util/ModelProvider.java +++ b/src/main/java/javax/visrec/util/ModelProvider.java @@ -3,7 +3,7 @@ /** * This interface should be implemented by classes which expose access to underlying ML model * - * @param Type of underlying ML model + * @param Type of the underlying ML model */ public interface ModelProvider { From b198f0b17a9b5e240c9b98d23f0fafbd271a92b1 Mon Sep 17 00:00:00 2001 From: Zoran Sevarac Date: Fri, 17 Jul 2020 09:49:45 +0200 Subject: [PATCH 61/87] Removed ClassifierExcption --- .../javax/visrec/AbstractImageClassifier.java | 9 ++++----- .../visrec/ml/ClassificationException.java | 20 ------------------- .../visrec/ml/classification/Classifier.java | 4 +--- .../ml/classification/EnsambleClassifier.java | 3 +-- .../ml/classification/ImageClassifier.java | 6 +++--- .../visrec/ml/detection/ObjectDetector.java | 3 +-- 6 files changed, 10 insertions(+), 35 deletions(-) delete mode 100644 src/main/java/javax/visrec/ml/ClassificationException.java diff --git a/src/main/java/javax/visrec/AbstractImageClassifier.java b/src/main/java/javax/visrec/AbstractImageClassifier.java index ed9f624..b8a92bf 100644 --- a/src/main/java/javax/visrec/AbstractImageClassifier.java +++ b/src/main/java/javax/visrec/AbstractImageClassifier.java @@ -1,6 +1,5 @@ package javax.visrec; -import javax.visrec.ml.ClassificationException; import javax.visrec.ml.classification.ImageClassifier; import javax.visrec.spi.ServiceProvider; import java.awt.image.BufferedImage; @@ -47,23 +46,23 @@ public ImageFactory getImageFactory() { } @Override - public Map classify(File file) throws ClassificationException { + public Map classify(File file) { IMAGE_CLASS image; try { image = imageFactory.getImage(file); } catch (IOException e) { - throw new ClassificationException("Couldn't transform input into a BufferedImage", e); + throw new RuntimeException("Couldn't transform input into a BufferedImage", e); } return classify(image); } @Override - public Map classify(InputStream inputStream) throws ClassificationException { + public Map classify(InputStream inputStream) { IMAGE_CLASS image; try { image = imageFactory.getImage(inputStream); } catch (IOException e) { - throw new ClassificationException("Couldn't transform input into a BufferedImage", e); + throw new RuntimeException("Couldn't transform input into a BufferedImage", e); } return classify(image); } diff --git a/src/main/java/javax/visrec/ml/ClassificationException.java b/src/main/java/javax/visrec/ml/ClassificationException.java deleted file mode 100644 index b02f8e7..0000000 --- a/src/main/java/javax/visrec/ml/ClassificationException.java +++ /dev/null @@ -1,20 +0,0 @@ -package javax.visrec.ml; - -/** - * Exception thrown if anything fails in classifying input using a classifier. - * - * @author Kevin Berendsen - * @since 1.0 - */ -public class ClassificationException extends RuntimeException { - - /** - * Creates a new instance of the exception - * @param message additional message of the cause. - * @param throwable caused by throwable. - */ - public ClassificationException(String message, Throwable throwable) { - super(message, throwable); - } - -} diff --git a/src/main/java/javax/visrec/ml/classification/Classifier.java b/src/main/java/javax/visrec/ml/classification/Classifier.java index 78d083e..8b21e3c 100644 --- a/src/main/java/javax/visrec/ml/classification/Classifier.java +++ b/src/main/java/javax/visrec/ml/classification/Classifier.java @@ -1,7 +1,5 @@ package javax.visrec.ml.classification; -import javax.visrec.ml.ClassificationException; - /** * Generic classifier interface, that all classifiers should implement. Provides * a method to classify instances of some class. Implementations should specify @@ -24,6 +22,6 @@ public interface Classifier { * @param input some instance to classify * @return classification results for the specified instance */ - R classify(T input) throws ClassificationException; + R classify(T input); } diff --git a/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java b/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java index 7c45edf..9902610 100644 --- a/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java @@ -1,6 +1,5 @@ package javax.visrec.ml.classification; -import javax.visrec.ml.ClassificationException; import java.util.HashMap; import java.util.Map; @@ -19,7 +18,7 @@ public final class EnsambleClassifier implements Classifier { private final Map> classifiers = new HashMap<>(); @Override - public R classify(T input) throws ClassificationException { + public R classify(T input) { for (Map.Entry> classifier : classifiers.entrySet()) { classifier.getValue().classify(input); } diff --git a/src/main/java/javax/visrec/ml/classification/ImageClassifier.java b/src/main/java/javax/visrec/ml/classification/ImageClassifier.java index af17643..7575b17 100644 --- a/src/main/java/javax/visrec/ml/classification/ImageClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/ImageClassifier.java @@ -1,14 +1,14 @@ package javax.visrec.ml.classification; -import javax.visrec.ml.ClassificationException; + import java.io.File; import java.io.InputStream; import java.util.Map; public interface ImageClassifier extends Classifier>{ - Map classify(File input) throws ClassificationException; + Map classify(File input); - Map classify(InputStream input) throws ClassificationException; + Map classify(InputStream input); } diff --git a/src/main/java/javax/visrec/ml/detection/ObjectDetector.java b/src/main/java/javax/visrec/ml/detection/ObjectDetector.java index accd2e2..982f29b 100644 --- a/src/main/java/javax/visrec/ml/detection/ObjectDetector.java +++ b/src/main/java/javax/visrec/ml/detection/ObjectDetector.java @@ -1,6 +1,5 @@ package javax.visrec.ml.detection; -import javax.visrec.ml.ClassificationException; import javax.visrec.util.BoundingBox; import java.util.List; import java.util.Map; @@ -22,6 +21,6 @@ public interface ObjectDetector { * @param image image to search for object * @return a map of multiple {@link BoundingBox} */ - Map> detectObject(T image) throws ClassificationException; + Map> detectObject(T image); } From 793ac3c1a103344d339ad2d0c6ccb24b6194a45d Mon Sep 17 00:00:00 2001 From: Zoran Sevarac Date: Fri, 17 Jul 2020 10:03:34 +0200 Subject: [PATCH 62/87] Removed ClassifierExcption --- .../AbstractMultiClassClassifier.java | 2 +- .../ClassifierCreationException.java | 2 +- .../ml/classification/LogisticRegression.java | 2 +- .../NeuralNetBinaryClassifier.java | 1 - .../NeuralNetImageClassifier.java | 1 - .../{util => ml/detection}/BoundingBox.java | 2 +- .../visrec/ml/detection/ObjectDetector.java | 1 - .../visrec/{util => ml/model}/Model.java | 2 +- .../{util => ml/model}/ModelProvider.java | 2 +- .../ml/regression/SimpleLinearRegression.java | 2 +- .../visrec/spi/BinaryClassifierFactory.java | 2 +- .../visrec/spi/ClassifierFactoryService.java | 2 +- .../visrec/spi/ImageClassifierFactory.java | 2 +- src/main/java/javax/visrec/util/Builder.java | 2 +- src/main/java/javax/visrec/util/DataSets.java | 78 ------------------- 15 files changed, 11 insertions(+), 92 deletions(-) rename src/main/java/javax/visrec/ml/{ => classification}/ClassifierCreationException.java (94%) rename src/main/java/javax/visrec/{util => ml/detection}/BoundingBox.java (92%) rename src/main/java/javax/visrec/{util => ml/model}/Model.java (86%) rename src/main/java/javax/visrec/{util => ml/model}/ModelProvider.java (83%) delete mode 100644 src/main/java/javax/visrec/util/DataSets.java diff --git a/src/main/java/javax/visrec/ml/classification/AbstractMultiClassClassifier.java b/src/main/java/javax/visrec/ml/classification/AbstractMultiClassClassifier.java index 7faeda5..41cc047 100644 --- a/src/main/java/javax/visrec/ml/classification/AbstractMultiClassClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/AbstractMultiClassClassifier.java @@ -1,6 +1,6 @@ package javax.visrec.ml.classification; -import javax.visrec.util.ModelProvider; +import javax.visrec.ml.model.ModelProvider; /** * diff --git a/src/main/java/javax/visrec/ml/ClassifierCreationException.java b/src/main/java/javax/visrec/ml/classification/ClassifierCreationException.java similarity index 94% rename from src/main/java/javax/visrec/ml/ClassifierCreationException.java rename to src/main/java/javax/visrec/ml/classification/ClassifierCreationException.java index 964ef82..97ffe7c 100644 --- a/src/main/java/javax/visrec/ml/ClassifierCreationException.java +++ b/src/main/java/javax/visrec/ml/classification/ClassifierCreationException.java @@ -1,4 +1,4 @@ -package javax.visrec.ml; +package javax.visrec.ml.classification; /** * Exception thrown if anything fails in the creation of a classifier. diff --git a/src/main/java/javax/visrec/ml/classification/LogisticRegression.java b/src/main/java/javax/visrec/ml/classification/LogisticRegression.java index 95095f2..39060d4 100644 --- a/src/main/java/javax/visrec/ml/classification/LogisticRegression.java +++ b/src/main/java/javax/visrec/ml/classification/LogisticRegression.java @@ -1,6 +1,6 @@ package javax.visrec.ml.classification; -import javax.visrec.util.ModelProvider; +import javax.visrec.ml.model.ModelProvider; /** * This class performs basic binary classification - mapping of specified input to true/false with probability diff --git a/src/main/java/javax/visrec/ml/classification/NeuralNetBinaryClassifier.java b/src/main/java/javax/visrec/ml/classification/NeuralNetBinaryClassifier.java index 3e037c5..5d44221 100644 --- a/src/main/java/javax/visrec/ml/classification/NeuralNetBinaryClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/NeuralNetBinaryClassifier.java @@ -1,6 +1,5 @@ package javax.visrec.ml.classification; -import javax.visrec.ml.ClassifierCreationException; import javax.visrec.spi.ServiceProvider; import java.io.File; import java.util.Map; diff --git a/src/main/java/javax/visrec/ml/classification/NeuralNetImageClassifier.java b/src/main/java/javax/visrec/ml/classification/NeuralNetImageClassifier.java index b1b5e50..6c8d935 100644 --- a/src/main/java/javax/visrec/ml/classification/NeuralNetImageClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/NeuralNetImageClassifier.java @@ -1,6 +1,5 @@ package javax.visrec.ml.classification; -import javax.visrec.ml.ClassifierCreationException; import javax.visrec.spi.ServiceProvider; import java.io.File; import java.lang.reflect.InvocationTargetException; diff --git a/src/main/java/javax/visrec/util/BoundingBox.java b/src/main/java/javax/visrec/ml/detection/BoundingBox.java similarity index 92% rename from src/main/java/javax/visrec/util/BoundingBox.java rename to src/main/java/javax/visrec/ml/detection/BoundingBox.java index ba208e3..029b192 100644 --- a/src/main/java/javax/visrec/util/BoundingBox.java +++ b/src/main/java/javax/visrec/ml/detection/BoundingBox.java @@ -1,4 +1,4 @@ -package javax.visrec.util; +package javax.visrec.ml.detection; /** * This class represents a bounding box over image at specified position, dimensions, label and score. diff --git a/src/main/java/javax/visrec/ml/detection/ObjectDetector.java b/src/main/java/javax/visrec/ml/detection/ObjectDetector.java index 982f29b..d1a5247 100644 --- a/src/main/java/javax/visrec/ml/detection/ObjectDetector.java +++ b/src/main/java/javax/visrec/ml/detection/ObjectDetector.java @@ -1,6 +1,5 @@ package javax.visrec.ml.detection; -import javax.visrec.util.BoundingBox; import java.util.List; import java.util.Map; diff --git a/src/main/java/javax/visrec/util/Model.java b/src/main/java/javax/visrec/ml/model/Model.java similarity index 86% rename from src/main/java/javax/visrec/util/Model.java rename to src/main/java/javax/visrec/ml/model/Model.java index 19b4e1e..b3327ec 100644 --- a/src/main/java/javax/visrec/util/Model.java +++ b/src/main/java/javax/visrec/ml/model/Model.java @@ -1,4 +1,4 @@ -package javax.visrec.util; +package javax.visrec.ml.model; import javax.visrec.ml.data.DataSet; diff --git a/src/main/java/javax/visrec/util/ModelProvider.java b/src/main/java/javax/visrec/ml/model/ModelProvider.java similarity index 83% rename from src/main/java/javax/visrec/util/ModelProvider.java rename to src/main/java/javax/visrec/ml/model/ModelProvider.java index de5f964..3fb5440 100644 --- a/src/main/java/javax/visrec/util/ModelProvider.java +++ b/src/main/java/javax/visrec/ml/model/ModelProvider.java @@ -1,4 +1,4 @@ -package javax.visrec.util; +package javax.visrec.ml.model; /** * This interface should be implemented by classes which expose access to underlying ML model diff --git a/src/main/java/javax/visrec/ml/regression/SimpleLinearRegression.java b/src/main/java/javax/visrec/ml/regression/SimpleLinearRegression.java index 5960d69..1e62721 100644 --- a/src/main/java/javax/visrec/ml/regression/SimpleLinearRegression.java +++ b/src/main/java/javax/visrec/ml/regression/SimpleLinearRegression.java @@ -1,6 +1,6 @@ package javax.visrec.ml.regression; -import javax.visrec.util.ModelProvider; +import javax.visrec.ml.model.ModelProvider; /** * Simple linear regression finds the best possible straight line that tries to explain given training set. diff --git a/src/main/java/javax/visrec/spi/BinaryClassifierFactory.java b/src/main/java/javax/visrec/spi/BinaryClassifierFactory.java index 337eb31..f80d770 100644 --- a/src/main/java/javax/visrec/spi/BinaryClassifierFactory.java +++ b/src/main/java/javax/visrec/spi/BinaryClassifierFactory.java @@ -1,6 +1,6 @@ package javax.visrec.spi; -import javax.visrec.ml.ClassifierCreationException; +import javax.visrec.ml.classification.ClassifierCreationException; import javax.visrec.ml.classification.BinaryClassifier; import javax.visrec.ml.classification.NeuralNetBinaryClassifier; diff --git a/src/main/java/javax/visrec/spi/ClassifierFactoryService.java b/src/main/java/javax/visrec/spi/ClassifierFactoryService.java index b01e959..3f1ed34 100644 --- a/src/main/java/javax/visrec/spi/ClassifierFactoryService.java +++ b/src/main/java/javax/visrec/spi/ClassifierFactoryService.java @@ -1,6 +1,6 @@ package javax.visrec.spi; -import javax.visrec.ml.ClassifierCreationException; +import javax.visrec.ml.classification.ClassifierCreationException; import javax.visrec.ml.classification.*; import java.util.HashMap; import java.util.Map; diff --git a/src/main/java/javax/visrec/spi/ImageClassifierFactory.java b/src/main/java/javax/visrec/spi/ImageClassifierFactory.java index 04b1e36..252a38b 100644 --- a/src/main/java/javax/visrec/spi/ImageClassifierFactory.java +++ b/src/main/java/javax/visrec/spi/ImageClassifierFactory.java @@ -1,6 +1,6 @@ package javax.visrec.spi; -import javax.visrec.ml.ClassifierCreationException; +import javax.visrec.ml.classification.ClassifierCreationException; import javax.visrec.ml.classification.ImageClassifier; import javax.visrec.ml.classification.NeuralNetImageClassifier; diff --git a/src/main/java/javax/visrec/util/Builder.java b/src/main/java/javax/visrec/util/Builder.java index 56950ed..b5641fe 100644 --- a/src/main/java/javax/visrec/util/Builder.java +++ b/src/main/java/javax/visrec/util/Builder.java @@ -1,6 +1,6 @@ package javax.visrec.util; -import javax.visrec.ml.ClassifierCreationException; +import javax.visrec.ml.classification.ClassifierCreationException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Map; diff --git a/src/main/java/javax/visrec/util/DataSets.java b/src/main/java/javax/visrec/util/DataSets.java deleted file mode 100644 index d43c25d..0000000 --- a/src/main/java/javax/visrec/util/DataSets.java +++ /dev/null @@ -1,78 +0,0 @@ -package javax.visrec.util; - -import javax.visrec.ml.data.Normalizer; -import javax.visrec.ml.data.DataSet; - -/** - * Utility methods that provides common operations on data sets. - * Will probably be deprecated or figure out how to expose implementation specific operations - * - * @author Zoran Sevarac - */ -@Deprecated -public class DataSets { - - private DataSets() { } - - // method to get basic statistics - summary() mead median, mi , max std, qt - - // scale values - // maybe just provide DataSet.normalize(new MaxNormalizer) , and dataSet injects itself into normalizer - // or even better norm= new MaxNormalizer(dataSet); norm.normalize(); also separate construction from analysis - - public static > void normalize(T dataSet, Normalizer norm) { - norm.normalize(dataSet); - } - - // how about moving thes estatic methods to coresponding interface? -// public static > void normalizeMax(DataSet dataSet) { -// Normalizer norm = new MaxNormalizer(dataSet); // perform analysys of data set (find max values) -// return norm.normalize(dataSet, false); // perfrom normalization and return as new data set -// } - -// public static DataSet normalizeMinMax(DataSet dataSet) { -// Normalizer norm = new MinMaxNormalizer(dataSet); // perform analysys of data set (find max values) -// return norm.normalize(dataSet, false); // perfrom normalization and return as new data set -// } - -// public static DataSet normalizeRange(DataSet dataSet, float low, float high) { -// Normalizer norm = new MinMaxNormalizer(dataSet); // perform analysys of data set (find max values) -// return norm.normalize(dataSet, false); // perfrom normalization and return as new data set -// } - - - // how to specify which columns to normalize? do we need to? just normalize all - // how will this method know about how to normalize specific type of elemeents? eg. User? or this assumes only numeric values - - - // retrun data set whith ddesired statistical properties - // zero mean, one std - public static > void standardize(T dataSet) { // apply to all numer columns - // how will this method know about how to normalize specific type of elemeents? - throw new UnsupportedOperationException("not implemented"); - } - - // this shoul ddefinitely be utility method - public static DataSet removeDuplicates() { - throw new UnsupportedOperationException("not implemented"); - } - - //transform() - maybe can transorm into datas set whsle elements ar eof another type - -// statisticsSummary () - mean std freq by cols, maybe better go put it in dat aset class? - // max, min, mean, std - // returns true if data set is balanced (only needed for classification problems, not to go in Dataset interface) - public static boolean isBalanced(DataSet dataSet) { //use generic method to infer type of data set elements - throw new UnsupportedOperationException("not implemented"); - } - - // summary - return basic statistics for each column in dat aset min, max, mean , mode, std, 1q, 3q - - /** - addNoise with some noice generator - balance(BalanceStrtegy) - - dimensionalityreuction - */ - -} From a3a1d6fa1706258d563cc94c04ca8120dc3933c9 Mon Sep 17 00:00:00 2001 From: kevto Date: Fri, 17 Jul 2020 10:07:52 +0200 Subject: [PATCH 63/87] Fixing merge conflict --- gradlew | 183 ++++++++++++++++++ gradlew.bat | 100 ++++++++++ .../NeuralNetBinaryClassifier.java | 7 +- src/main/java/javax/visrec/util/Builder.java | 11 +- 4 files changed, 289 insertions(+), 12 deletions(-) create mode 100755 gradlew create mode 100644 gradlew.bat diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..2fe81a7 --- /dev/null +++ b/gradlew @@ -0,0 +1,183 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed 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 +# +# https://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. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..24467a1 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,100 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/src/main/java/javax/visrec/ml/classification/NeuralNetBinaryClassifier.java b/src/main/java/javax/visrec/ml/classification/NeuralNetBinaryClassifier.java index 5d44221..c4e3a11 100644 --- a/src/main/java/javax/visrec/ml/classification/NeuralNetBinaryClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/NeuralNetBinaryClassifier.java @@ -2,7 +2,6 @@ import javax.visrec.spi.ServiceProvider; import java.io.File; -import java.util.Map; public interface NeuralNetBinaryClassifier extends BinaryClassifier { @@ -63,7 +62,7 @@ private static BuildingBlock copyWithNewTargetClass(BuildingBlock bloc } } - class Builder { + class Builder implements javax.visrec.util.Builder, ClassifierCreationException> { private NeuralNetBinaryClassifier.BuildingBlock block; @@ -117,9 +116,5 @@ public NeuralNetBinaryClassifier.BuildingBlock getBuildingBlock() { public BinaryClassifier build() throws ClassifierCreationException { return ServiceProvider.current().getClassifierFactoryService().createNeuralNetBinaryClassifier(block); } - - public BinaryClassifier build(Map configuration) throws ClassifierCreationException { - throw new IllegalStateException("not implemented yet"); - } } } diff --git a/src/main/java/javax/visrec/util/Builder.java b/src/main/java/javax/visrec/util/Builder.java index b5641fe..cf81e42 100644 --- a/src/main/java/javax/visrec/util/Builder.java +++ b/src/main/java/javax/visrec/util/Builder.java @@ -1,6 +1,5 @@ package javax.visrec.util; -import javax.visrec.ml.classification.ClassifierCreationException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Map; @@ -8,19 +7,19 @@ /** * Generic builder interface, that all builders for machine learning algorithms implement. * + * @param type of the object to be returned by the builder. * @author Zoran Sevarac * @author Kevin Berendsen - * @param type of the object to be returned by the builder. * @since 1.0 */ -public interface Builder { +public interface Builder { /** * Builds and returns an object using properties set using available builder methods. * * @return object specified by the builder to build */ - T build() throws ClassifierCreationException; + T build() throws E; /** * Builds an object using properties from the specified input argument @@ -28,7 +27,7 @@ public interface Builder { * @param configuration properties for the builder, a map of key, value pairs. * @return object specified by the builder to build */ - default T build(Map configuration) throws ClassifierCreationException { + default T build(Map configuration) throws E, InvalidBuilderConfigurationException { Method[] methods = this.getClass().getDeclaredMethods(); for (Method method : methods) { if (!method.getName().equals("build") && method.getParameterCount() == 1 @@ -43,4 +42,4 @@ default T build(Map configuration) throws ClassifierCreationExce return build(); } -} \ No newline at end of file +} From 0d58a1da603f773be61336359ac22843602ed11d Mon Sep 17 00:00:00 2001 From: Zoran Sevarac Date: Fri, 17 Jul 2020 10:11:27 +0200 Subject: [PATCH 64/87] Moved AbstractImageClassifier to classification --- .../AbstractImageClassifier.java | 3 +- .../javax/visrec/util/VisRecConstants.java | 29 ------------------- 2 files changed, 2 insertions(+), 30 deletions(-) rename src/main/java/javax/visrec/{ => ml/classification}/AbstractImageClassifier.java (94%) delete mode 100644 src/main/java/javax/visrec/util/VisRecConstants.java diff --git a/src/main/java/javax/visrec/AbstractImageClassifier.java b/src/main/java/javax/visrec/ml/classification/AbstractImageClassifier.java similarity index 94% rename from src/main/java/javax/visrec/AbstractImageClassifier.java rename to src/main/java/javax/visrec/ml/classification/AbstractImageClassifier.java index b8a92bf..97d216f 100644 --- a/src/main/java/javax/visrec/AbstractImageClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/AbstractImageClassifier.java @@ -1,4 +1,4 @@ -package javax.visrec; +package javax.visrec.ml.classification; import javax.visrec.ml.classification.ImageClassifier; import javax.visrec.spi.ServiceProvider; @@ -9,6 +9,7 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; +import javax.visrec.ImageFactory; /** * Skeleton abstract class to make it easier to implement image classifier. diff --git a/src/main/java/javax/visrec/util/VisRecConstants.java b/src/main/java/javax/visrec/util/VisRecConstants.java deleted file mode 100644 index 7f7c705..0000000 --- a/src/main/java/javax/visrec/util/VisRecConstants.java +++ /dev/null @@ -1,29 +0,0 @@ -package javax.visrec.util; - -/** - * Shared constants to retrieve and set values in properties. - * - * TODO Kevin: "Zoran do we still need this?" - * Zoran: Yes - * - * @author Zoran Sevarac - * @since 1.0 - */ -public final class VisRecConstants { - - private VisRecConstants() { - // Prevent instantiation. - } - - public static final String IMAGE_WIDTH = "visrec.imageWidth"; - public static final String IMAGE_HEIGHT = "visrec.imageHeight"; - public static final String SGD_LEARNING_RATE = "visrec.sgd.learningRate"; - public static final String SGD_MAX_ERROR = "visrec.sgd.maxError"; - public static final String SGD_MAX_EPOCHS = "visrec.sgd.maxEpochs"; - - public static final String LABELS_FILE = "visrec.labelsFile"; - public static final String TRAINING_FILE = "visrec.trainingFile"; - public static final String TEST_FILE = "visrec.testFile"; - - public static final String MODEL_SAVE_TO = "visrec.model.saveTo"; -} From b9cce592d0695e0608ee0d3b3ca1521578d482f9 Mon Sep 17 00:00:00 2001 From: kevto Date: Fri, 17 Jul 2020 10:11:29 +0200 Subject: [PATCH 65/87] Implementing utility builder interface in neuralnetimageclassifier --- .../NeuralNetImageClassifier.java | 60 +++---------------- 1 file changed, 8 insertions(+), 52 deletions(-) diff --git a/src/main/java/javax/visrec/ml/classification/NeuralNetImageClassifier.java b/src/main/java/javax/visrec/ml/classification/NeuralNetImageClassifier.java index 6c8d935..d2cfc44 100644 --- a/src/main/java/javax/visrec/ml/classification/NeuralNetImageClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/NeuralNetImageClassifier.java @@ -2,10 +2,7 @@ import javax.visrec.spi.ServiceProvider; import java.io.File; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.nio.file.Path; -import java.util.Map; public interface NeuralNetImageClassifier extends ImageClassifier { @@ -65,14 +62,15 @@ public Path getExportPath() { public Path getImportPath() { return importPath; } - - + public int getMaxEpochs() { return maxEpochs; } - public Class getInputClass() { return inputCls; } + public Class getInputClass() { + return inputCls; + } private static BuildingBlock copyWithNewInputClass(BuildingBlock block, Class cls) { BuildingBlock newBlock = new BuildingBlock<>(); @@ -91,7 +89,7 @@ private static BuildingBlock copyWithNewInputClass(BuildingBlock block } } - class Builder { + class Builder implements javax.visrec.util.Builder, ClassifierCreationException> { private BuildingBlock block; @@ -151,61 +149,19 @@ public Builder exportModel(Path path) { public Builder importModel(Path path) { block.importPath = path; return this; - } - + } + public Builder networkArchitecture(File architecture) { block.networkArchitecture = architecture; return this; } - public BuildingBlock getBuildingBlock() { + public BuildingBlock getBuildingBlock() { return block; } public ImageClassifier build() throws ClassifierCreationException { return ServiceProvider.current().getClassifierFactoryService().createNeuralNetImageClassifier(block); } - - public ImageClassifier build(Map configuration) throws ClassifierCreationException { - Method[] methods = this.getClass().getDeclaredMethods(); - for (Method method : methods) { - if (!method.getName().equals("build") && method.getParameterCount() == 1 - && configuration.containsKey(method.getName())) { - try { - Object value = configuration.get(method.getName()); - Class expectedParameterType = method.getParameterTypes()[0]; - // Integer casting - if (expectedParameterType.equals(int.class) || expectedParameterType.equals(Integer.class)) { - if (value instanceof String) { - method.invoke(this, Integer.parseInt((String) value)); - continue; - } - } - - // Float casting - if (expectedParameterType.equals(float.class) || expectedParameterType.equals(Float.class)) { - if (value instanceof String) { - method.invoke(this, Float.parseFloat((String) value)); - continue; - } - } - - // File casting - if (expectedParameterType.equals(File.class)) { - if (value instanceof String) { - method.invoke(this, new File((String) value)); - continue; - } - } - - // Others - method.invoke(this, value); - } catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException e) { - throw new ClassifierCreationException("Couldn't invoke '" + method.getName() + "'", e); - } - } - } - return build(); - } } } From 12ed1bab428f9d6feede34f2775d470fc35b4252 Mon Sep 17 00:00:00 2001 From: Zoran Sevarac Date: Tue, 8 Dec 2020 17:32:17 +0100 Subject: [PATCH 66/87] Final polishing: classifier threshold, data set columns, normalizer to scaler, javadoc --- .../AbstractImageClassifier.java | 12 +-- .../visrec/ml/classification/Classifier.java | 18 +++-- .../ml/classification/LogisticRegression.java | 4 - .../javax/visrec/ml/data/BasicDataSet.java | 75 +++++++++++++------ .../java/javax/visrec/ml/data/Column.java | 61 +++++++++++++++ .../java/javax/visrec/ml/data/DataSet.java | 60 ++++----------- .../java/javax/visrec/ml/data/Normalizer.java | 12 --- .../java/javax/visrec/ml/data/Scaler.java | 14 ++++ .../visrec/ml/eval/ClassificationMetrics.java | 25 +++++++ .../visrec/ml/eval/EvaluationMetrics.java | 2 - .../visrec/ml/eval/RegressionMetrics.java | 35 +++++++++ .../java/javax/visrec/ml/model/Model.java | 8 +- .../javax/visrec/ml/regression/Regressor.java | 8 +- .../ml/regression/SimpleLinearRegression.java | 29 +++---- 14 files changed, 242 insertions(+), 121 deletions(-) create mode 100644 src/main/java/javax/visrec/ml/data/Column.java delete mode 100644 src/main/java/javax/visrec/ml/data/Normalizer.java create mode 100644 src/main/java/javax/visrec/ml/data/Scaler.java create mode 100644 src/main/java/javax/visrec/ml/eval/ClassificationMetrics.java create mode 100644 src/main/java/javax/visrec/ml/eval/RegressionMetrics.java diff --git a/src/main/java/javax/visrec/ml/classification/AbstractImageClassifier.java b/src/main/java/javax/visrec/ml/classification/AbstractImageClassifier.java index 97d216f..3a78b6e 100644 --- a/src/main/java/javax/visrec/ml/classification/AbstractImageClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/AbstractImageClassifier.java @@ -10,6 +10,7 @@ import java.util.Objects; import java.util.Optional; import javax.visrec.ImageFactory; +import javax.visrec.ml.model.ModelProvider; /** * Skeleton abstract class to make it easier to implement image classifier. @@ -24,7 +25,7 @@ * * @param class of machine learning model */ -public abstract class AbstractImageClassifier implements ImageClassifier { // could also implement binary classifier +public abstract class AbstractImageClassifier implements ImageClassifier, ModelProvider { // could also implement binary classifier private ImageFactory imageFactory; // image factory impl for the specified image class private MODEL_CLASS model; // the model could be injected from machine learning container? @@ -51,10 +52,10 @@ public Map classify(File file) { IMAGE_CLASS image; try { image = imageFactory.getImage(file); + return classify(image); } catch (IOException e) { throw new RuntimeException("Couldn't transform input into a BufferedImage", e); } - return classify(image); } @Override @@ -62,19 +63,20 @@ public Map classify(InputStream inputStream) { IMAGE_CLASS image; try { image = imageFactory.getImage(inputStream); + return classify(image); } catch (IOException e) { throw new RuntimeException("Couldn't transform input into a BufferedImage", e); - } - return classify(image); + } } // todo: provide get top 1, 3, 5 results; sort and get + @Override public MODEL_CLASS getModel() { return model; } - public final void setModel(MODEL_CLASS model) { + protected final void setModel(MODEL_CLASS model) { this.model = Objects.requireNonNull(model, "Model cannot bu null!"); } diff --git a/src/main/java/javax/visrec/ml/classification/Classifier.java b/src/main/java/javax/visrec/ml/classification/Classifier.java index 8b21e3c..9428c03 100644 --- a/src/main/java/javax/visrec/ml/classification/Classifier.java +++ b/src/main/java/javax/visrec/ml/classification/Classifier.java @@ -1,13 +1,21 @@ package javax.visrec.ml.classification; /** - * Generic classifier interface, that all classifiers should implement. Provides - * a method to classify instances of some class. Implementations should specify - * type of objects (class) that are classified. + * Classifier answers the question what is the category/type of an input object. + * Each category/type has corresponding label or class name, which can be String, Enum or custom user defined class. + * This is a generic classifier interface, that all classifiers should implement, and + * it provides a method to classify given instances of some class. + * + * Implementations should specify input type of instances that are classified, + * and type of the returned vales . + * + * Usually implementations predict category of instances with some probability, + * and cannot guarantee 100% accuracy. * * @author Zoran Sevarac * @param type of input objects to classify (eg. User, Product, Transaction, Image, etc.) - * @param type of classification result. + * @param type of classification result (String, Enum, custom class). + * * @see BinaryClassifier * @see MultiClassClassifier * @see ImageClassifier @@ -17,7 +25,7 @@ public interface Classifier { /** - * Classifies specified instance of type T and returns classification results of type R. + * Classifies specified input instance of type T and returns classification results of type R. * * @param input some instance to classify * @return classification results for the specified instance diff --git a/src/main/java/javax/visrec/ml/classification/LogisticRegression.java b/src/main/java/javax/visrec/ml/classification/LogisticRegression.java index 39060d4..650a075 100644 --- a/src/main/java/javax/visrec/ml/classification/LogisticRegression.java +++ b/src/main/java/javax/visrec/ml/classification/LogisticRegression.java @@ -19,8 +19,4 @@ public MODEL_CLASS getModel() { return model; } - protected void setModel(MODEL_CLASS model) { - this.model = model; - } - } diff --git a/src/main/java/javax/visrec/ml/data/BasicDataSet.java b/src/main/java/javax/visrec/ml/data/BasicDataSet.java index 8b17038..d5592d4 100644 --- a/src/main/java/javax/visrec/ml/data/BasicDataSet.java +++ b/src/main/java/javax/visrec/ml/data/BasicDataSet.java @@ -1,7 +1,6 @@ package javax.visrec.ml.data; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @@ -15,10 +14,14 @@ public class BasicDataSet implements DataSet { /** - * List of data set items in this data set + * List of data set items in this data set. */ - protected List items; //this should be a data frame map of lists, even better use value types! - private Column[] columns; // this should be a list + protected List items; + + /** + * List of data set columns. Each column provides info about it's name, type. + */ + private List columns; // a sta ak oovo napravim da bud emapa sa nazivima kolona kao kljucevima protected BasicDataSet() { items = new ArrayList<>(); @@ -28,8 +31,8 @@ protected BasicDataSet() { * Creates an instance of {@link BasicDataSet} * @param cols columns of the data set. */ - public BasicDataSet(Column[] cols) { - this.columns = cols; + public BasicDataSet(Column... cols) { // ??? is thi sconstructir used anywhere? + this.columns = new ArrayList(); items = new ArrayList<>(); } @@ -46,36 +49,62 @@ public List getItems() { return items; } - @Override - public String[] getTargetNames() { - List targetLabels = Arrays.asList(columns).stream() - .filter((col) -> col.isTarget()) - .map((col) -> col.getName() ) - .collect(Collectors.toList()); - return targetLabels.toArray(new String[0]); + public List getColumns() { + return columns; } - - @Override + public void setColumnNames(String[] columnNames) { - for(int i=0; ic.setTarget(false)); + + for(int idx : targetIdxs) { + columns.get(idx).setTarget(true); + } + } + + public void setTargetColumns(String... targetColNames) { + columns.stream().forEach( c->c.setTarget(false)); + + columns.stream().forEach(col-> { + for(String name : targetColNames) { + if (col.getName().equals(name)) col.setTarget(true); + } + }); + } + + public String[] getTargetColumnsNames() { + List targetLabels = columns.stream() + .filter((col) -> col.isTarget()) + .map((col) -> col.getName() ) + .collect(Collectors.toList()); + return targetLabels.toArray(new String[0]); + } + + // remove? @Override public DataSet[] split(double... parts) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void setColumns(List columns) { + this.columns = columns; } diff --git a/src/main/java/javax/visrec/ml/data/Column.java b/src/main/java/javax/visrec/ml/data/Column.java new file mode 100644 index 0000000..f7de435 --- /dev/null +++ b/src/main/java/javax/visrec/ml/data/Column.java @@ -0,0 +1,61 @@ +package javax.visrec.ml.data; + +/** + * Column in a data set. + * + * @see DataSet + */ + public class Column { + private String name; + private Type type; + private boolean isTarget; + + public Column(String name) { + this.name = name; + this.type = null; + this.isTarget = false; + } + + public Column(String name, Type type) { + this.name = name; + this.type = type; + this.isTarget = false; + } + + public Column(String name, Type type, boolean isTarget) { + this.name = name; + this.type = type; + this.isTarget = isTarget; + } + + public String getName() { + return name; + } + + public Type getType() { + return type; + } + + public boolean isTarget() { + return isTarget; + } + + public void setName(String name) { + this.name = name; + } + + public void setType(Type type) { + this.type = type; + } + + public void setTarget(boolean isTarget) { + this.isTarget = isTarget; + } + + /** + * Column data type + */ + public static enum Type { + DECIMAL, INTEGER, BINARY, ENUM, STRING; + } + } \ No newline at end of file diff --git a/src/main/java/javax/visrec/ml/data/DataSet.java b/src/main/java/javax/visrec/ml/data/DataSet.java index f35b39c..c0046cf 100644 --- a/src/main/java/javax/visrec/ml/data/DataSet.java +++ b/src/main/java/javax/visrec/ml/data/DataSet.java @@ -6,6 +6,7 @@ import java.util.List; import java.util.Objects; import java.util.Random; +import java.util.stream.Stream; /** * Generic interface for all data sets for machine learning, independent of type of elements. @@ -16,8 +17,6 @@ */ public interface DataSet extends Iterable { - // TODO: add stream for filtering elements in data set - /** * Get a collection of the items in the {@link DataSet} * @return {@link Collection} @@ -86,7 +85,7 @@ default Iterator iterator() { } /** - * Split dataset into specified number of equally sized parts. + * Split data set into specified number of equally sized parts. * @param numParts number of parts to be returned * @return multiple {@link DataSet} in an array. */ @@ -102,7 +101,7 @@ default DataSet[] split(int numParts) { } /** - * Split dataset into specified number of equally sized parts, using specified random generator. + * Split data set into specified number of equally sized parts, using specified random generator. * @param numParts number of parts/subsets to return * @param rnd random number generator * @return multiple {@link DataSet} in an array. @@ -161,51 +160,24 @@ default void shuffle() { default void shuffle(Random rnd) { Collections.shuffle(getItems(), rnd); } + + /** + * Sets the columns of this data set. + * + * @param columns + */ + public void setColumns(List columns); /** - * Get labels of target/output columns. - * @return array with labels of target/output columns + * Returns the columns of the data set. + * + * @return */ - public String[] getTargetNames(); - // also add setTargetNames(String ...) and setTargetColumns(int ...) + public List getColumns(); - public void setColumnNames(String[] columnNames); - public String[] getColumnNames(); - - - public static class Column { - private final String name; - private final Type type; - private final boolean isTarget; - - public Column(String name) { - this.name = name; - this.type = null; - this.isTarget = false; - } - - public Column(String name, Type type, boolean isTarget) { - this.name = name; - this.type = type; - this.isTarget = isTarget; - } - - public String getName() { - return name; - } - - public Type getType() { - return type; - } - - public boolean isTarget() { - return isTarget; - } - } - - public static enum Type { - DECIMAL, INTEGER, BINARY, STRING; // ENUM? + default public Stream stream() { + return getItems().stream(); } } \ No newline at end of file diff --git a/src/main/java/javax/visrec/ml/data/Normalizer.java b/src/main/java/javax/visrec/ml/data/Normalizer.java deleted file mode 100644 index 4470cc1..0000000 --- a/src/main/java/javax/visrec/ml/data/Normalizer.java +++ /dev/null @@ -1,12 +0,0 @@ -package javax.visrec.ml.data; - -/** - * Interface to perform normalization/scaling of data set - * - * @author Zoran Sevarac - * @param Data set class (that implements DataSet interface) - */ -public interface Normalizer> { - public void normalize(T dataSet); -} - diff --git a/src/main/java/javax/visrec/ml/data/Scaler.java b/src/main/java/javax/visrec/ml/data/Scaler.java new file mode 100644 index 0000000..4a59cef --- /dev/null +++ b/src/main/java/javax/visrec/ml/data/Scaler.java @@ -0,0 +1,14 @@ +package javax.visrec.ml.data; + +/** + * Interface to perform scaling of a data set. + * Scaling data set features to range [0, 1] or similar is a common practice + * in order to prepare data for machine learning training and reduce influence of different scale among data. + * + * @author Zoran Sevarac + * @param Data set class (that implements DataSet interface) + */ +public interface Scaler> { + public void scale(T dataSet); +} + diff --git a/src/main/java/javax/visrec/ml/eval/ClassificationMetrics.java b/src/main/java/javax/visrec/ml/eval/ClassificationMetrics.java new file mode 100644 index 0000000..3bb59ef --- /dev/null +++ b/src/main/java/javax/visrec/ml/eval/ClassificationMetrics.java @@ -0,0 +1,25 @@ +package javax.visrec.ml.eval; + +/** + * Commonly used metrics to estimate how good machine learning model solves some classification task. + * + */ +public class ClassificationMetrics extends EvaluationMetrics { + + public double getAccuracy() { + return get(ACCURACY); + } + + public double getPrecision() { + return get(PRECISION); + } + + public double getRecall() { + return get(RECALL); + } + + public double getF1score() { + return get(F1SCORE); + } + +} \ No newline at end of file diff --git a/src/main/java/javax/visrec/ml/eval/EvaluationMetrics.java b/src/main/java/javax/visrec/ml/eval/EvaluationMetrics.java index fdbb04a..bedb0e6 100644 --- a/src/main/java/javax/visrec/ml/eval/EvaluationMetrics.java +++ b/src/main/java/javax/visrec/ml/eval/EvaluationMetrics.java @@ -60,8 +60,6 @@ public class EvaluationMetrics { */ public final static String F_STAT = "FStatistics"; - // TODO: p value, t statistics - // Classification Metrics public final static String ACCURACY = "Accuracy"; public final static String PRECISION = "Precision"; diff --git a/src/main/java/javax/visrec/ml/eval/RegressionMetrics.java b/src/main/java/javax/visrec/ml/eval/RegressionMetrics.java new file mode 100644 index 0000000..bed3f56 --- /dev/null +++ b/src/main/java/javax/visrec/ml/eval/RegressionMetrics.java @@ -0,0 +1,35 @@ +package javax.visrec.ml.eval; + +/** + * Commonly used metrics to estimate how good machine learning model solves some regression task. + * This class is typed wrapper for EvaluationMetrics which uses map to store metrics, + * and allows storing and accessing of custom metrics. + */ +public class RegressionMetrics extends EvaluationMetrics { + + /** + * Portion of variation explained. + * How much better is this than the average. + * @return + */ + public double getRSquared() { + return get(R_SQUARED); + } + + public double getResidualSquareSum() { + return get(RESIDUAL_SQUARE_SUM); + } + + public double getFstat() { + return get(F_STAT); + } + + public double getMeanSquaredError() { + return get(MEAN_SQUARED_ERROR); + } + + public double getResidualStandardError() { + return get(RESIDUAL_STANDARD_ERROR); + } + +} diff --git a/src/main/java/javax/visrec/ml/model/Model.java b/src/main/java/javax/visrec/ml/model/Model.java index b3327ec..512b388 100644 --- a/src/main/java/javax/visrec/ml/model/Model.java +++ b/src/main/java/javax/visrec/ml/model/Model.java @@ -1,13 +1,9 @@ package javax.visrec.ml.model; -import javax.visrec.ml.data.DataSet; - /** + * Marker interface, a common type for all machine learning models. * Every model should provide methods for training and testing. - * Not used anywhere at the moment. - * @author zoran */ public interface Model { - void train(DataSet trainingSet); - void test(DataSet testSet); // evaluate + } diff --git a/src/main/java/javax/visrec/ml/regression/Regressor.java b/src/main/java/javax/visrec/ml/regression/Regressor.java index 62c8c81..0a4d05a 100644 --- a/src/main/java/javax/visrec/ml/regression/Regressor.java +++ b/src/main/java/javax/visrec/ml/regression/Regressor.java @@ -1,9 +1,11 @@ package javax.visrec.ml.regression; /** - * Base interface for all regressors. - * Regressors try to predict a continual value(s) (a decimal number) based on a set of inputs. - * Rename to ValueEstimator? + * Regressor tries to predict a numeric value based on a given set of inputs. + * This is a base interface for all regressors. + * Implementations should specify specific type of inputs and outputs that + * specific algorithm expects and returns. + * * @author Zoran Sevarac * @param type of inputs / features * @param return/result type diff --git a/src/main/java/javax/visrec/ml/regression/SimpleLinearRegression.java b/src/main/java/javax/visrec/ml/regression/SimpleLinearRegression.java index 1e62721..6131dd0 100644 --- a/src/main/java/javax/visrec/ml/regression/SimpleLinearRegression.java +++ b/src/main/java/javax/visrec/ml/regression/SimpleLinearRegression.java @@ -4,48 +4,43 @@ /** * Simple linear regression finds the best possible straight line that tries to explain given training set. + * Mathematical formula for linear regression is: prediction = slope * x + intercept + * which is a formula for linear function (straight line) and that's where the names comes from. * - * @author zoran + * @param Implementation class of the background model */ public abstract class SimpleLinearRegression implements Regressor, ModelProvider { private MODEL_CLASS model; + @Override public MODEL_CLASS getModel() { return model; } - protected void setModel(MODEL_CLASS model) { - this.model = model; - } +// protected void setModel(MODEL_CLASS model) { +// this.model = model; +// } @Override - public abstract Float predict(Float inputs); + public abstract Float predict(Float input); /** - * How much on average output change when input changes by one. + * Slope tells how much on average output change when input changes by one. + * * If it is zero there is no linear dependency between input and output, and data is probably scattered. * If it is less then one output grows slower then input. * If it is greater than one, then output is growing faster than input. * If its negative, then output is lowering as input grows. * - * @return + * @return slope of the line produced by linear regression. */ public abstract float getSlope(); /** - * The value of output when input is zero + * Intercept tells us the value of prediction when input is zero * @return */ public abstract float getIntercept(); - // ili da vracam parametre modela u mapi? - // ili kao niz koeficijenata? - - // performance measures - // RSE - // R2 - - -// Map.new().put() } From 4f19045a43d65dc2d577c9fa17b7017eee64daa3 Mon Sep 17 00:00:00 2001 From: Zoran Sevarac Date: Tue, 22 Dec 2020 19:52:44 +0100 Subject: [PATCH 67/87] api doc for claassifiers --- .../javax/visrec/ml/data/BasicDataSet.java | 28 +++++++++++------- .../java/javax/visrec/ml/data/Column.java | 2 +- .../java/javax/visrec/ml/data/DataSet.java | 2 +- .../ml/data/{ => preprocessing}/Scaler.java | 8 +++-- .../visrec/ml/eval/ClassificationMetrics.java | 29 ++++++++++++++++++- .../visrec/ml/eval/EvaluationMetrics.java | 2 +- .../java/javax/visrec/ml/model/Model.java | 1 - .../ml/regression/SimpleLinearRegression.java | 2 +- 8 files changed, 55 insertions(+), 19 deletions(-) rename src/main/java/javax/visrec/ml/data/{ => preprocessing}/Scaler.java (56%) diff --git a/src/main/java/javax/visrec/ml/data/BasicDataSet.java b/src/main/java/javax/visrec/ml/data/BasicDataSet.java index d5592d4..2ef49e1 100644 --- a/src/main/java/javax/visrec/ml/data/BasicDataSet.java +++ b/src/main/java/javax/visrec/ml/data/BasicDataSet.java @@ -1,6 +1,7 @@ package javax.visrec.ml.data; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @@ -16,12 +17,12 @@ public class BasicDataSet implements DataSet { /** * List of data set items in this data set. */ - protected List items; + protected List items; /** * List of data set columns. Each column provides info about it's name, type. */ - private List columns; // a sta ak oovo napravim da bud emapa sa nazivima kolona kao kljucevima + private List columns; protected BasicDataSet() { items = new ArrayList<>(); @@ -31,10 +32,17 @@ protected BasicDataSet() { * Creates an instance of {@link BasicDataSet} * @param cols columns of the data set. */ - public BasicDataSet(Column... cols) { // ??? is thi sconstructir used anywhere? + public BasicDataSet(Column... cols) { this.columns = new ArrayList(); + Arrays.stream(cols).forEach(col->columns.add(col)); items = new ArrayList<>(); } + + public BasicDataSet(String... cols) { + this.columns = new ArrayList(); + Arrays.stream(cols).forEach(col->columns.add(new Column(col))); + items = new ArrayList<>(); + } /** * Creates an instance of {@link BasicDataSet} @@ -50,7 +58,7 @@ public List getItems() { } @Override - public List getColumns() { + public List columns() { return columns; } @@ -68,21 +76,21 @@ public String[] getColumnNames() { return colNames; } - public void setTargetColumns(int... targetIdxs) { + public void setAsTargetColumns(int... targetIdxs) { // reset all cureent target columns - columns.stream().forEach( c->c.setTarget(false)); + columns.stream().forEach( c->c.setAsTarget(false)); for(int idx : targetIdxs) { - columns.get(idx).setTarget(true); + columns.get(idx).setAsTarget(true); } } - public void setTargetColumns(String... targetColNames) { - columns.stream().forEach( c->c.setTarget(false)); + public void setAsTargetColumns(String... targetColNames) { + columns.stream().forEach( c->c.setAsTarget(false)); columns.stream().forEach(col-> { for(String name : targetColNames) { - if (col.getName().equals(name)) col.setTarget(true); + if (col.getName().equals(name)) col.setAsTarget(true); } }); } diff --git a/src/main/java/javax/visrec/ml/data/Column.java b/src/main/java/javax/visrec/ml/data/Column.java index f7de435..6e927cd 100644 --- a/src/main/java/javax/visrec/ml/data/Column.java +++ b/src/main/java/javax/visrec/ml/data/Column.java @@ -48,7 +48,7 @@ public void setType(Type type) { this.type = type; } - public void setTarget(boolean isTarget) { + public void setAsTarget(boolean isTarget) { this.isTarget = isTarget; } diff --git a/src/main/java/javax/visrec/ml/data/DataSet.java b/src/main/java/javax/visrec/ml/data/DataSet.java index c0046cf..32a1e49 100644 --- a/src/main/java/javax/visrec/ml/data/DataSet.java +++ b/src/main/java/javax/visrec/ml/data/DataSet.java @@ -173,7 +173,7 @@ default void shuffle(Random rnd) { * * @return */ - public List getColumns(); + public List columns(); default public Stream stream() { diff --git a/src/main/java/javax/visrec/ml/data/Scaler.java b/src/main/java/javax/visrec/ml/data/preprocessing/Scaler.java similarity index 56% rename from src/main/java/javax/visrec/ml/data/Scaler.java rename to src/main/java/javax/visrec/ml/data/preprocessing/Scaler.java index 4a59cef..e1999a5 100644 --- a/src/main/java/javax/visrec/ml/data/Scaler.java +++ b/src/main/java/javax/visrec/ml/data/preprocessing/Scaler.java @@ -1,11 +1,13 @@ -package javax.visrec.ml.data; +package javax.visrec.ml.data.preprocessing; + +import javax.visrec.ml.data.DataSet; /** * Interface to perform scaling of a data set. + * Scaling generally means to change the range of the values, while the shape of the distribution doesn’t change. * Scaling data set features to range [0, 1] or similar is a common practice - * in order to prepare data for machine learning training and reduce influence of different scale among data. + * in order to prepare data for machine learning training and reduce influence of different value ranges among data. * - * @author Zoran Sevarac * @param Data set class (that implements DataSet interface) */ public interface Scaler> { diff --git a/src/main/java/javax/visrec/ml/eval/ClassificationMetrics.java b/src/main/java/javax/visrec/ml/eval/ClassificationMetrics.java index 3bb59ef..3bd5b2f 100644 --- a/src/main/java/javax/visrec/ml/eval/ClassificationMetrics.java +++ b/src/main/java/javax/visrec/ml/eval/ClassificationMetrics.java @@ -2,22 +2,49 @@ /** * Commonly used metrics to estimate how good machine learning model solves some classification task. - * */ public class ClassificationMetrics extends EvaluationMetrics { + /** + * The percent of correct predictions of a classifier in total. + * Tells how often the classifier is correct for some given test set. + * Note that accuracy can be a misleading metric for imbalanced data sets. + * + * Formula: Accuracy = (TP+TN) / (TP+TN+FP+FN) + * + * @return classification accuracy metric + */ public double getAccuracy() { return get(ACCURACY); } + /** + * The percent of correct positive predictions. + * This metrics answers the question: when classifier gives positive prediction, how often is it correct? + * Formula: Precision = TP/(TP+FP) + * + * @return classification precision metric + */ public double getPrecision() { return get(PRECISION); } + /** + * The percent of the positive examples that were not recognized by the classifier. + * This metric answers the question: when it is actually positive class, how often does it give positive prediction + * Formula: Recall = TP / (TP+FN) + * + * @return classification recall + */ public double getRecall() { return get(RECALL); } + /** + * The mean/balance of the recall and precision metrics. + * + * @return classification f score + */ public double getF1score() { return get(F1SCORE); } diff --git a/src/main/java/javax/visrec/ml/eval/EvaluationMetrics.java b/src/main/java/javax/visrec/ml/eval/EvaluationMetrics.java index bedb0e6..4aa4861 100644 --- a/src/main/java/javax/visrec/ml/eval/EvaluationMetrics.java +++ b/src/main/java/javax/visrec/ml/eval/EvaluationMetrics.java @@ -74,7 +74,7 @@ public class EvaluationMetrics { description.put(ACCURACY, "How often is classifier correct in total"); description.put(PRECISION, "How often is classifier correct when it gives positive prediction"); description.put(RECALL, "When it is actually positive class, how often does it give positive prediction"); - description.put(F1SCORE, "Average of precision and recall"); + description.put(F1SCORE, "Harmonic average (balance) of precision and recall"); } diff --git a/src/main/java/javax/visrec/ml/model/Model.java b/src/main/java/javax/visrec/ml/model/Model.java index 512b388..9db4585 100644 --- a/src/main/java/javax/visrec/ml/model/Model.java +++ b/src/main/java/javax/visrec/ml/model/Model.java @@ -2,7 +2,6 @@ /** * Marker interface, a common type for all machine learning models. - * Every model should provide methods for training and testing. */ public interface Model { diff --git a/src/main/java/javax/visrec/ml/regression/SimpleLinearRegression.java b/src/main/java/javax/visrec/ml/regression/SimpleLinearRegression.java index 6131dd0..7c7408d 100644 --- a/src/main/java/javax/visrec/ml/regression/SimpleLinearRegression.java +++ b/src/main/java/javax/visrec/ml/regression/SimpleLinearRegression.java @@ -3,7 +3,7 @@ import javax.visrec.ml.model.ModelProvider; /** - * Simple linear regression finds the best possible straight line that tries to explain given training set. + * Simple linear regression finds the best possible straight line that tries to roughly describe given training set. * Mathematical formula for linear regression is: prediction = slope * x + intercept * which is a formula for linear function (straight line) and that's where the names comes from. * From 36a1e80978f05519407f91bbac3a2c85821b879e Mon Sep 17 00:00:00 2001 From: Zoran Sevarac Date: Tue, 19 Jan 2021 09:08:49 +0100 Subject: [PATCH 68/87] Changed File to Path params --- .../AbstractImageClassifier.java | 2 +- .../NeuralNetImageClassifier.java | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/main/java/javax/visrec/ml/classification/AbstractImageClassifier.java b/src/main/java/javax/visrec/ml/classification/AbstractImageClassifier.java index 3a78b6e..6fba4d2 100644 --- a/src/main/java/javax/visrec/ml/classification/AbstractImageClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/AbstractImageClassifier.java @@ -30,7 +30,7 @@ public abstract class AbstractImageClassifier implemen private ImageFactory imageFactory; // image factory impl for the specified image class private MODEL_CLASS model; // the model could be injected from machine learning container? - private float threshold=0.5f; // this should ba a part of every classifier + private float threshold=0.0f; // this should ba a part of every classifier protected AbstractImageClassifier(final Class imgCls, final MODEL_CLASS model) { final Optional> optionalImageFactory = ServiceProvider.current() diff --git a/src/main/java/javax/visrec/ml/classification/NeuralNetImageClassifier.java b/src/main/java/javax/visrec/ml/classification/NeuralNetImageClassifier.java index d2cfc44..6498b82 100644 --- a/src/main/java/javax/visrec/ml/classification/NeuralNetImageClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/NeuralNetImageClassifier.java @@ -14,9 +14,9 @@ class BuildingBlock { private int imageWidth; private int imageHeight; - private File networkArchitecture; - private File trainingFile; - private File labelsFile; + private Path networkArchitecture; + private Path trainingFile; + private Path labelsFile; private float maxError; private float learningRate; private Path exportPath; @@ -27,7 +27,7 @@ class BuildingBlock { private BuildingBlock() { } - public File getNetworkArchitecture() { + public Path getNetworkArchitecture() { return networkArchitecture; } @@ -39,11 +39,11 @@ public int getImageHeight() { return imageHeight; } - public File getTrainingFile() { + public Path getTrainingFile() { return trainingFile; } - public File getLabelsFile() { + public Path getLabelsFile() { return labelsFile; } @@ -116,12 +116,12 @@ public Builder imageHeight(int imageHeight) { return this; } - public Builder trainingFile(File trainingFile) { + public Builder trainingFile(Path trainingFile) { block.trainingFile = trainingFile; return this; } - public Builder labelsFile(File labelsFile) { + public Builder labelsFile(Path labelsFile) { block.labelsFile = labelsFile; return this; } @@ -151,7 +151,7 @@ public Builder importModel(Path path) { return this; } - public Builder networkArchitecture(File architecture) { + public Builder networkArchitecture(Path architecture) { block.networkArchitecture = architecture; return this; } From 7261753a2978746d619e61cfc9af84be0dd71ce6 Mon Sep 17 00:00:00 2001 From: kevto Date: Tue, 2 Feb 2021 18:18:19 +0100 Subject: [PATCH 69/87] Adding classification exception and adding extra javadoc --- .../AbstractImageClassifier.java | 35 +++++++------ .../ClassificationException.java | 30 +++++++++++ .../visrec/ml/classification/Classifier.java | 16 +++--- .../ml/classification/ClassifierBuilder.java | 52 ------------------- .../ml/classification/ImageClassifier.java | 27 ++++++++-- 5 files changed, 80 insertions(+), 80 deletions(-) create mode 100644 src/main/java/javax/visrec/ml/classification/ClassificationException.java delete mode 100644 src/main/java/javax/visrec/ml/classification/ClassifierBuilder.java diff --git a/src/main/java/javax/visrec/ml/classification/AbstractImageClassifier.java b/src/main/java/javax/visrec/ml/classification/AbstractImageClassifier.java index 6fba4d2..5f8b32a 100644 --- a/src/main/java/javax/visrec/ml/classification/AbstractImageClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/AbstractImageClassifier.java @@ -1,6 +1,7 @@ package javax.visrec.ml.classification; -import javax.visrec.ml.classification.ImageClassifier; +import javax.visrec.ImageFactory; +import javax.visrec.ml.model.ModelProvider; import javax.visrec.spi.ServiceProvider; import java.awt.image.BufferedImage; import java.io.File; @@ -9,8 +10,6 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; -import javax.visrec.ImageFactory; -import javax.visrec.ml.model.ModelProvider; /** * Skeleton abstract class to make it easier to implement image classifier. @@ -18,19 +17,21 @@ * image factory for specific type of images. * This class solves the problem of using various implementation of images and machine learning models in Java, * and provides standard Classifier API for clients. - * + *

* By default the type of key in the Map the {@link ImageClassifier} is {@code String} * - * @author Zoran Sevarac - * + * @param class to classify * @param class of machine learning model + * @author Zoran Sevarac + * @since 1.0 */ -public abstract class AbstractImageClassifier implements ImageClassifier, ModelProvider { // could also implement binary classifier +public abstract class AbstractImageClassifier implements ImageClassifier, ModelProvider { - private ImageFactory imageFactory; // image factory impl for the specified image class - private MODEL_CLASS model; // the model could be injected from machine learning container? + private final ImageFactory imageFactory; + private MODEL_CLASS model; - private float threshold=0.0f; // this should ba a part of every classifier + // TODO: this should ba a part of every classifier + private float threshold = 0.0f; protected AbstractImageClassifier(final Class imgCls, final MODEL_CLASS model) { final Optional> optionalImageFactory = ServiceProvider.current() @@ -48,27 +49,27 @@ public ImageFactory getImageFactory() { } @Override - public Map classify(File file) { + public Map classify(File file) throws ClassificationException { IMAGE_CLASS image; try { image = imageFactory.getImage(file); return classify(image); } catch (IOException e) { - throw new RuntimeException("Couldn't transform input into a BufferedImage", e); + throw new ClassificationException("Failed to transform input into a BufferedImage", e); } } @Override - public Map classify(InputStream inputStream) { + public Map classify(InputStream inputStream) throws ClassificationException { IMAGE_CLASS image; try { image = imageFactory.getImage(inputStream); return classify(image); } catch (IOException e) { - throw new RuntimeException("Couldn't transform input into a BufferedImage", e); - } + throw new RuntimeException("Failed to transform input into a BufferedImage", e); + } } - + // todo: provide get top 1, 3, 5 results; sort and get @Override @@ -77,7 +78,7 @@ public MODEL_CLASS getModel() { } protected final void setModel(MODEL_CLASS model) { - this.model = Objects.requireNonNull(model, "Model cannot bu null!"); + this.model = Objects.requireNonNull(model, "Model cannot bu null!"); } public float getThreshold() { diff --git a/src/main/java/javax/visrec/ml/classification/ClassificationException.java b/src/main/java/javax/visrec/ml/classification/ClassificationException.java new file mode 100644 index 0000000..583fbc3 --- /dev/null +++ b/src/main/java/javax/visrec/ml/classification/ClassificationException.java @@ -0,0 +1,30 @@ +package javax.visrec.ml.classification; + +/** + * Exception thrown if anything fails in the execution of a classifier. + * + * @author Kevin Berendsen + * @since 1.0 + */ +public class ClassificationException extends RuntimeException { + + /** + * Creates a new instance of the exception + * + * @param message additional message of the cause. + */ + public ClassificationException(String message) { + super(message); + } + + /** + * Creates a new instance of the exception + * + * @param message additional message of the cause. + * @param throwable caused by throwable. + */ + public ClassificationException(String message, Throwable throwable) { + super(message, throwable); + } + +} diff --git a/src/main/java/javax/visrec/ml/classification/Classifier.java b/src/main/java/javax/visrec/ml/classification/Classifier.java index 9428c03..0a524d0 100644 --- a/src/main/java/javax/visrec/ml/classification/Classifier.java +++ b/src/main/java/javax/visrec/ml/classification/Classifier.java @@ -3,19 +3,18 @@ /** * Classifier answers the question what is the category/type of an input object. * Each category/type has corresponding label or class name, which can be String, Enum or custom user defined class. - * This is a generic classifier interface, that all classifiers should implement, and - * it provides a method to classify given instances of some class. - * + * This is a generic classifier interface, that all classifiers should implement, and + * it provides a method to classify given instances of some class. + *

* Implementations should specify input type of instances that are classified, * and type of the returned vales . - * + *

* Usually implementations predict category of instances with some probability, * and cannot guarantee 100% accuracy. * - * @author Zoran Sevarac * @param type of input objects to classify (eg. User, Product, Transaction, Image, etc.) * @param type of classification result (String, Enum, custom class). - * + * @author Zoran Sevarac * @see BinaryClassifier * @see MultiClassClassifier * @see ImageClassifier @@ -29,7 +28,8 @@ public interface Classifier { * * @param input some instance to classify * @return classification results for the specified instance + * @throws ClassificationException if the input could not be classified */ - R classify(T input); - + R classify(T input) throws ClassificationException; + } diff --git a/src/main/java/javax/visrec/ml/classification/ClassifierBuilder.java b/src/main/java/javax/visrec/ml/classification/ClassifierBuilder.java deleted file mode 100644 index f8e609d..0000000 --- a/src/main/java/javax/visrec/ml/classification/ClassifierBuilder.java +++ /dev/null @@ -1,52 +0,0 @@ -package javax.visrec.ml.classification; - -import javax.visrec.spi.ServiceProvider; - -/** - * Builder to create @{link Classifier} - * - * @author Kevin Berendsen - * @since 1.0 - * @Deprecated for removal - */ -@Deprecated -public abstract class ClassifierBuilder { - - protected ClassifierBuilder() { - // Prevent instantiation outside of subclasses. - } - - /** - * Set the trained model to be used during the image classification. - * - * TODO Add the proper class to the method signature. - * - * @param trainedModel the object of the trained model. - * @return current builder instance - */ - public abstract ClassifierBuilder trainedModel(Object trainedModel); - - /** - * Create the {@link Classifier} that is able to use {@code sourceClss} as input/source type and - * {@code returnCls} as return type of the {@link Classifier} - * - * @param sourceCls {@link Class} object of the incoming input/source. - * @param returnCls {@link Class} object of the return type of the {@link Classifier} - * @param source type class of the {@link Classifier} - * @param return type class of the {@link Classifier} - * @return {@link Classifier} object. - */ - public abstract Classifier buildWithSourceType(final Class sourceCls, final Class returnCls); - - /** - * Create the {@link Classifier} that is able to use {@code sourceClss} as input/source type and - * {@link String} as default return type of the {@link Classifier} - * - * @param sourceCls {@link Class} object of the incoming input/source. - * @param source type class of the {@link Classifier} - * @return {@link Classifier} object. - */ - public final Classifier buildWithSourceType(final Class sourceCls) { - return buildWithSourceType(sourceCls, String.class); - } -} diff --git a/src/main/java/javax/visrec/ml/classification/ImageClassifier.java b/src/main/java/javax/visrec/ml/classification/ImageClassifier.java index 7575b17..a764fe1 100644 --- a/src/main/java/javax/visrec/ml/classification/ImageClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/ImageClassifier.java @@ -5,10 +5,31 @@ import java.io.InputStream; import java.util.Map; -public interface ImageClassifier extends Classifier>{ +/** + * Classifier interface specialized in image classification + * + * @param type of input objects to classify (eg. User, Product, Transaction, Image, etc.) + * @author Zoran Sevarac + * @since 1.0 + */ +public interface ImageClassifier extends Classifier> { - Map classify(File input); + /** + * Classify the input and get a map of classification results as output + * + * @param input {@link File} to use as input + * @return {@code Map} with key as classification label and with value as accuracy percentage of likelihood + * @throws ClassificationException if the file couldn't be found or classified + */ + Map classify(File input) throws ClassificationException; - Map classify(InputStream input); + /** + * Classify the input and get a map of classification results as output + * + * @param input {@link InputStream} to use as input + * @return {@code Map} with key as classification label and with value as accuracy percentage of likelihood + * @throws ClassificationException if input couldn't be classified + */ + Map classify(InputStream input) throws ClassificationException; } From a914010b09d186cf46dfb5ba005afaa0f4695ffd Mon Sep 17 00:00:00 2001 From: kevto Date: Tue, 2 Feb 2021 18:25:18 +0100 Subject: [PATCH 70/87] Transforming last bit of pieces of File usage into Path --- src/main/java/javax/visrec/ImageFactory.java | 21 +++++++++++-------- .../AbstractImageClassifier.java | 6 +++--- .../ml/classification/ImageClassifier.java | 6 +++--- .../NeuralNetBinaryClassifier.java | 14 ++++++------- .../NeuralNetImageClassifier.java | 13 ++++++------ .../java/javax/visrec/spi/BuilderService.java | 21 ------------------- .../javax/visrec/spi/ImageFactoryService.java | 5 +++-- .../javax/visrec/spi/ServiceProvider.java | 8 ------- 8 files changed, 34 insertions(+), 60 deletions(-) delete mode 100644 src/main/java/javax/visrec/spi/BuilderService.java diff --git a/src/main/java/javax/visrec/ImageFactory.java b/src/main/java/javax/visrec/ImageFactory.java index a221b6a..fef62ac 100644 --- a/src/main/java/javax/visrec/ImageFactory.java +++ b/src/main/java/javax/visrec/ImageFactory.java @@ -1,44 +1,47 @@ package javax.visrec; -import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URL; +import java.nio.file.Path; /** * This interface provides a standard way to get/read different(specified) kinds of image from file, url or input stream. * + * @param the type of object to be returned after getting image from {@link Path}, {@link URL} or {@link InputStream} * @author Zoran Sevarac - * @param the type of object to be returned after getting image from {@link File}, {@link URL} or {@link InputStream} * @since 1.0 */ public interface ImageFactory { /** - * Retrieve the source through a {@link File} object and transform it into T. - * @param file The source file. + * Retrieve the source through a {@link Path} object and transform it into T. + * + * @param path The source file. * @return T object. * @throws IOException If the file I/O went wrong or couldn't transform - * the source into a T object. + * the source into a T object. */ - T getImage(File file) throws IOException; + T getImage(Path path) throws IOException; /** * Retrieve the source through a {@link URL} object and transform it into T. + * * @param file The source. * @return T object. * @throws IOException If the I/O went wrong or couldn't transform - * the source into a T object. + * the source into a T object. */ T getImage(URL file) throws IOException; /** * Retrieve the source through an {@link InputStream} object and transform it into T. + * * @param file The source. * @return T object. * @throws IOException If the I/O went wrong or couldn't transform - * the source into a T object. + * the source into a T object. */ T getImage(InputStream file) throws IOException; - + } diff --git a/src/main/java/javax/visrec/ml/classification/AbstractImageClassifier.java b/src/main/java/javax/visrec/ml/classification/AbstractImageClassifier.java index 5f8b32a..8bd0ec3 100644 --- a/src/main/java/javax/visrec/ml/classification/AbstractImageClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/AbstractImageClassifier.java @@ -4,9 +4,9 @@ import javax.visrec.ml.model.ModelProvider; import javax.visrec.spi.ServiceProvider; import java.awt.image.BufferedImage; -import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.nio.file.Path; import java.util.Map; import java.util.Objects; import java.util.Optional; @@ -49,10 +49,10 @@ public ImageFactory getImageFactory() { } @Override - public Map classify(File file) throws ClassificationException { + public Map classify(Path path) throws ClassificationException { IMAGE_CLASS image; try { - image = imageFactory.getImage(file); + image = imageFactory.getImage(path); return classify(image); } catch (IOException e) { throw new ClassificationException("Failed to transform input into a BufferedImage", e); diff --git a/src/main/java/javax/visrec/ml/classification/ImageClassifier.java b/src/main/java/javax/visrec/ml/classification/ImageClassifier.java index a764fe1..7a4b9af 100644 --- a/src/main/java/javax/visrec/ml/classification/ImageClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/ImageClassifier.java @@ -1,8 +1,8 @@ package javax.visrec.ml.classification; -import java.io.File; import java.io.InputStream; +import java.nio.file.Path; import java.util.Map; /** @@ -17,11 +17,11 @@ public interface ImageClassifier extends Classifier classify(File input) throws ClassificationException; + Map classify(Path input) throws ClassificationException; /** * Classify the input and get a map of classification results as output diff --git a/src/main/java/javax/visrec/ml/classification/NeuralNetBinaryClassifier.java b/src/main/java/javax/visrec/ml/classification/NeuralNetBinaryClassifier.java index c4e3a11..277a8e5 100644 --- a/src/main/java/javax/visrec/ml/classification/NeuralNetBinaryClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/NeuralNetBinaryClassifier.java @@ -1,7 +1,7 @@ package javax.visrec.ml.classification; import javax.visrec.spi.ServiceProvider; -import java.io.File; +import java.nio.file.Path; public interface NeuralNetBinaryClassifier extends BinaryClassifier { @@ -16,7 +16,7 @@ class BuildingBlock { private float maxError; private int maxEpochs; private float learningRate; - private File trainingFile; + private Path trainingPath; private BuildingBlock() { } @@ -45,8 +45,8 @@ public float getLearningRate() { return learningRate; } - public File getTrainingFile() { - return trainingFile; + public Path getTrainingPath() { + return trainingPath; } private static BuildingBlock copyWithNewTargetClass(BuildingBlock block, Class cls) { @@ -57,7 +57,7 @@ private static BuildingBlock copyWithNewTargetClass(BuildingBlock bloc newBlock.maxError = block.maxError; newBlock.maxEpochs = block.maxEpochs; newBlock.learningRate = block.learningRate; - newBlock.trainingFile = block.trainingFile; + newBlock.trainingPath = block.trainingPath; return newBlock; } } @@ -104,8 +104,8 @@ public Builder learningRate(float learningRate) { return this; } - public Builder trainingFile(File trainingFile) { - block.trainingFile = trainingFile; + public Builder trainingPath(Path trainingPath) { + block.trainingPath = trainingPath; return this; } diff --git a/src/main/java/javax/visrec/ml/classification/NeuralNetImageClassifier.java b/src/main/java/javax/visrec/ml/classification/NeuralNetImageClassifier.java index 6498b82..56ec02a 100644 --- a/src/main/java/javax/visrec/ml/classification/NeuralNetImageClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/NeuralNetImageClassifier.java @@ -1,7 +1,6 @@ package javax.visrec.ml.classification; import javax.visrec.spi.ServiceProvider; -import java.io.File; import java.nio.file.Path; public interface NeuralNetImageClassifier extends ImageClassifier { @@ -15,7 +14,7 @@ class BuildingBlock { private int imageWidth; private int imageHeight; private Path networkArchitecture; - private Path trainingFile; + private Path trainingPath; private Path labelsFile; private float maxError; private float learningRate; @@ -39,11 +38,11 @@ public int getImageHeight() { return imageHeight; } - public Path getTrainingFile() { - return trainingFile; + public Path getTrainingPath() { + return trainingPath; } - public Path getLabelsFile() { + public Path getLabelsPath() { return labelsFile; } @@ -84,7 +83,7 @@ private static BuildingBlock copyWithNewInputClass(BuildingBlock block newBlock.maxError = block.maxError; newBlock.maxEpochs = block.maxEpochs; newBlock.learningRate = block.learningRate; - newBlock.trainingFile = block.trainingFile; + newBlock.trainingPath = block.trainingPath; return newBlock; } } @@ -117,7 +116,7 @@ public Builder imageHeight(int imageHeight) { } public Builder trainingFile(Path trainingFile) { - block.trainingFile = trainingFile; + block.trainingPath = trainingFile; return this; } diff --git a/src/main/java/javax/visrec/spi/BuilderService.java b/src/main/java/javax/visrec/spi/BuilderService.java deleted file mode 100644 index fc147a5..0000000 --- a/src/main/java/javax/visrec/spi/BuilderService.java +++ /dev/null @@ -1,21 +0,0 @@ -package javax.visrec.spi; - -import javax.visrec.ml.classification.ClassifierBuilder; - -/** - * Service to provide builders. - * - * @author Kevin Berendsen - * @since 1.0 - * @Deprecated for removal - */ -@Deprecated -public interface BuilderService { - - /** - * Creates a new instance of the {@link ClassifierBuilder} - * @return classifier builder. - */ - ClassifierBuilder newClassifierBuilder(); - -} diff --git a/src/main/java/javax/visrec/spi/ImageFactoryService.java b/src/main/java/javax/visrec/spi/ImageFactoryService.java index 32dbf1a..b64b91a 100644 --- a/src/main/java/javax/visrec/spi/ImageFactoryService.java +++ b/src/main/java/javax/visrec/spi/ImageFactoryService.java @@ -13,12 +13,13 @@ public interface ImageFactoryService { /** * Get the {@link ImageFactory} implementation by its image type. + * * @param imageCls image type in {@link Class} object which is able to * be processed by the image factory implementation. - * @param image type + * @param image type * @return {@link Optional} with possible {@link ImageFactory} implementation * if found. */ - Optional> getByImageType(final Class imageCls); + Optional> getByImageType(Class imageCls); } diff --git a/src/main/java/javax/visrec/spi/ServiceProvider.java b/src/main/java/javax/visrec/spi/ServiceProvider.java index a4c9b88..ec72f54 100644 --- a/src/main/java/javax/visrec/spi/ServiceProvider.java +++ b/src/main/java/javax/visrec/spi/ServiceProvider.java @@ -35,14 +35,6 @@ public int getPriority() { return 0; } - /** - * Get the {@link BuilderService} - * @return builder service. - * @Deprecated for removal - */ - @Deprecated - public abstract BuilderService getBuilderService(); - /** * Get the {@link ClassifierFactoryService} * @return classifier creator service From 21a21d9f0c5444df573a80674c5bcc1c5e902edd Mon Sep 17 00:00:00 2001 From: deepnetts Date: Tue, 2 Feb 2021 19:45:26 +0100 Subject: [PATCH 71/87] removed Model interfacse sine it's not used anywhere --- src/main/java/javax/visrec/ml/model/Model.java | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 src/main/java/javax/visrec/ml/model/Model.java diff --git a/src/main/java/javax/visrec/ml/model/Model.java b/src/main/java/javax/visrec/ml/model/Model.java deleted file mode 100644 index 9db4585..0000000 --- a/src/main/java/javax/visrec/ml/model/Model.java +++ /dev/null @@ -1,8 +0,0 @@ -package javax.visrec.ml.model; - -/** - * Marker interface, a common type for all machine learning models. - */ -public interface Model { - -} From 25124569ddbb238ee35a8b4590e516c268c02d7a Mon Sep 17 00:00:00 2001 From: deepnetts Date: Fri, 5 Feb 2021 13:54:43 +0100 Subject: [PATCH 72/87] fixed a bunch of stuff :) mostly exceptions. builders, removed util package --- .../ml/classification/LogisticRegression.java | 5 +++++ .../classification/NeuralNetBinaryClassifier.java | 5 +++-- .../classification/NeuralNetImageClassifier.java | 5 +++-- .../model/InvalidConfigurationException.java} | 6 +++--- .../Builder.java => ml/model/ModelBuilder.java} | 10 +++++----- .../ModelCreationException.java} | 8 ++++---- .../ml/regression/SimpleLinearRegression.java | 7 ++++--- .../javax/visrec/spi/BinaryClassifierFactory.java | 4 ++-- .../javax/visrec/spi/ClassifierFactoryService.java | 14 +++++++------- .../javax/visrec/spi/ImageClassifierFactory.java | 4 ++-- 10 files changed, 38 insertions(+), 30 deletions(-) rename src/main/java/javax/visrec/{util/InvalidBuilderConfigurationException.java => ml/model/InvalidConfigurationException.java} (64%) rename src/main/java/javax/visrec/{util/Builder.java => ml/model/ModelBuilder.java} (77%) rename src/main/java/javax/visrec/ml/{classification/ClassifierCreationException.java => model/ModelCreationException.java} (67%) diff --git a/src/main/java/javax/visrec/ml/classification/LogisticRegression.java b/src/main/java/javax/visrec/ml/classification/LogisticRegression.java index 650a075..530001e 100644 --- a/src/main/java/javax/visrec/ml/classification/LogisticRegression.java +++ b/src/main/java/javax/visrec/ml/classification/LogisticRegression.java @@ -1,5 +1,6 @@ package javax.visrec.ml.classification; +import java.util.Objects; import javax.visrec.ml.model.ModelProvider; /** @@ -18,5 +19,9 @@ public abstract class LogisticRegression implements BinaryClassifie public MODEL_CLASS getModel() { return model; } + + protected final void setModel(MODEL_CLASS model) { + this.model = Objects.requireNonNull(model, "Model cannot be null!"); + } } diff --git a/src/main/java/javax/visrec/ml/classification/NeuralNetBinaryClassifier.java b/src/main/java/javax/visrec/ml/classification/NeuralNetBinaryClassifier.java index 277a8e5..27c5e22 100644 --- a/src/main/java/javax/visrec/ml/classification/NeuralNetBinaryClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/NeuralNetBinaryClassifier.java @@ -1,5 +1,6 @@ package javax.visrec.ml.classification; +import javax.visrec.ml.model.ModelCreationException; import javax.visrec.spi.ServiceProvider; import java.nio.file.Path; @@ -62,7 +63,7 @@ private static BuildingBlock copyWithNewTargetClass(BuildingBlock bloc } } - class Builder implements javax.visrec.util.Builder, ClassifierCreationException> { + class Builder implements javax.visrec.ml.model.ModelBuilder> { private NeuralNetBinaryClassifier.BuildingBlock block; @@ -113,7 +114,7 @@ public NeuralNetBinaryClassifier.BuildingBlock getBuildingBlock() { return block; } - public BinaryClassifier build() throws ClassifierCreationException { + public BinaryClassifier build() throws ModelCreationException { return ServiceProvider.current().getClassifierFactoryService().createNeuralNetBinaryClassifier(block); } } diff --git a/src/main/java/javax/visrec/ml/classification/NeuralNetImageClassifier.java b/src/main/java/javax/visrec/ml/classification/NeuralNetImageClassifier.java index 56ec02a..755164a 100644 --- a/src/main/java/javax/visrec/ml/classification/NeuralNetImageClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/NeuralNetImageClassifier.java @@ -1,5 +1,6 @@ package javax.visrec.ml.classification; +import javax.visrec.ml.model.ModelCreationException; import javax.visrec.spi.ServiceProvider; import java.nio.file.Path; @@ -88,7 +89,7 @@ private static BuildingBlock copyWithNewInputClass(BuildingBlock block } } - class Builder implements javax.visrec.util.Builder, ClassifierCreationException> { + class Builder implements javax.visrec.ml.model.ModelBuilder> { private BuildingBlock block; @@ -159,7 +160,7 @@ public BuildingBlock getBuildingBlock() { return block; } - public ImageClassifier build() throws ClassifierCreationException { + public ImageClassifier build() throws ModelCreationException { return ServiceProvider.current().getClassifierFactoryService().createNeuralNetImageClassifier(block); } } diff --git a/src/main/java/javax/visrec/util/InvalidBuilderConfigurationException.java b/src/main/java/javax/visrec/ml/model/InvalidConfigurationException.java similarity index 64% rename from src/main/java/javax/visrec/util/InvalidBuilderConfigurationException.java rename to src/main/java/javax/visrec/ml/model/InvalidConfigurationException.java index a686489..64f6322 100644 --- a/src/main/java/javax/visrec/util/InvalidBuilderConfigurationException.java +++ b/src/main/java/javax/visrec/ml/model/InvalidConfigurationException.java @@ -1,4 +1,4 @@ -package javax.visrec.util; +package javax.visrec.ml.model; /** * The Builder is able to attempt to invoke setter methods of the implemented Builder interface. If the @@ -7,9 +7,9 @@ * * @author Kevin Berendsen */ -public class InvalidBuilderConfigurationException extends RuntimeException { +public class InvalidConfigurationException extends ModelCreationException { - InvalidBuilderConfigurationException(String msg, Throwable throwable) { + InvalidConfigurationException(String msg, Throwable throwable) { super(msg, throwable); } diff --git a/src/main/java/javax/visrec/util/Builder.java b/src/main/java/javax/visrec/ml/model/ModelBuilder.java similarity index 77% rename from src/main/java/javax/visrec/util/Builder.java rename to src/main/java/javax/visrec/ml/model/ModelBuilder.java index cf81e42..279980d 100644 --- a/src/main/java/javax/visrec/util/Builder.java +++ b/src/main/java/javax/visrec/ml/model/ModelBuilder.java @@ -1,4 +1,4 @@ -package javax.visrec.util; +package javax.visrec.ml.model; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -12,14 +12,14 @@ * @author Kevin Berendsen * @since 1.0 */ -public interface Builder { +public interface ModelBuilder { /** * Builds and returns an object using properties set using available builder methods. * * @return object specified by the builder to build */ - T build() throws E; + T build() throws ModelCreationException; /** * Builds an object using properties from the specified input argument @@ -27,7 +27,7 @@ public interface Builder { * @param configuration properties for the builder, a map of key, value pairs. * @return object specified by the builder to build */ - default T build(Map configuration) throws E, InvalidBuilderConfigurationException { + default T build(Map configuration) throws ModelCreationException { Method[] methods = this.getClass().getDeclaredMethods(); for (Method method : methods) { if (!method.getName().equals("build") && method.getParameterCount() == 1 @@ -35,7 +35,7 @@ default T build(Map configuration) throws E, InvalidBuilderConfi try { method.invoke(this, configuration.get(method.getName())); } catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException e) { - throw new InvalidBuilderConfigurationException("Couldn't invoke '" + method.getName() + "'", e); + throw new InvalidConfigurationException("Couldn't invoke '" + method.getName() + "'", e); } } } diff --git a/src/main/java/javax/visrec/ml/classification/ClassifierCreationException.java b/src/main/java/javax/visrec/ml/model/ModelCreationException.java similarity index 67% rename from src/main/java/javax/visrec/ml/classification/ClassifierCreationException.java rename to src/main/java/javax/visrec/ml/model/ModelCreationException.java index 97ffe7c..eff258e 100644 --- a/src/main/java/javax/visrec/ml/classification/ClassifierCreationException.java +++ b/src/main/java/javax/visrec/ml/model/ModelCreationException.java @@ -1,4 +1,4 @@ -package javax.visrec.ml.classification; +package javax.visrec.ml.model; /** * Exception thrown if anything fails in the creation of a classifier. @@ -6,13 +6,13 @@ * @author Kevin Berendsen * @since 1.0 */ -public class ClassifierCreationException extends Exception { +public class ModelCreationException extends Exception { /** * Creates a new instance of the exception * @param message additional message of the cause. */ - public ClassifierCreationException(String message) { + public ModelCreationException(String message) { super(message); } @@ -21,7 +21,7 @@ public ClassifierCreationException(String message) { * @param message additional message of the cause. * @param throwable caused by throwable. */ - public ClassifierCreationException(String message, Throwable throwable) { + public ModelCreationException(String message, Throwable throwable) { super(message, throwable); } diff --git a/src/main/java/javax/visrec/ml/regression/SimpleLinearRegression.java b/src/main/java/javax/visrec/ml/regression/SimpleLinearRegression.java index 7c7408d..bc8ab84 100644 --- a/src/main/java/javax/visrec/ml/regression/SimpleLinearRegression.java +++ b/src/main/java/javax/visrec/ml/regression/SimpleLinearRegression.java @@ -1,5 +1,6 @@ package javax.visrec.ml.regression; +import java.util.Objects; import javax.visrec.ml.model.ModelProvider; /** @@ -18,9 +19,9 @@ public MODEL_CLASS getModel() { return model; } -// protected void setModel(MODEL_CLASS model) { -// this.model = model; -// } + protected final void setModel(MODEL_CLASS model) { + this.model = Objects.requireNonNull(model, "Model cannot bu null!"); + } @Override public abstract Float predict(Float input); diff --git a/src/main/java/javax/visrec/spi/BinaryClassifierFactory.java b/src/main/java/javax/visrec/spi/BinaryClassifierFactory.java index f80d770..b1c9d26 100644 --- a/src/main/java/javax/visrec/spi/BinaryClassifierFactory.java +++ b/src/main/java/javax/visrec/spi/BinaryClassifierFactory.java @@ -1,6 +1,6 @@ package javax.visrec.spi; -import javax.visrec.ml.classification.ClassifierCreationException; +import javax.visrec.ml.model.ModelCreationException; import javax.visrec.ml.classification.BinaryClassifier; import javax.visrec.ml.classification.NeuralNetBinaryClassifier; @@ -8,6 +8,6 @@ public interface BinaryClassifierFactory { Class getTargetClass(); - BinaryClassifier create(NeuralNetBinaryClassifier.BuildingBlock block) throws ClassifierCreationException; + BinaryClassifier create(NeuralNetBinaryClassifier.BuildingBlock block) throws ModelCreationException; } diff --git a/src/main/java/javax/visrec/spi/ClassifierFactoryService.java b/src/main/java/javax/visrec/spi/ClassifierFactoryService.java index 3f1ed34..4280874 100644 --- a/src/main/java/javax/visrec/spi/ClassifierFactoryService.java +++ b/src/main/java/javax/visrec/spi/ClassifierFactoryService.java @@ -1,6 +1,6 @@ package javax.visrec.spi; -import javax.visrec.ml.classification.ClassifierCreationException; +import javax.visrec.ml.model.ModelCreationException; import javax.visrec.ml.classification.*; import java.util.HashMap; import java.util.Map; @@ -35,9 +35,9 @@ private ClassifierFactoryService() { * * @param block {@link NeuralNetImageClassifier.BuildingBlock} is provided to tune the building of the image classifier. * @return {@link ImageClassifier} - * @throws ClassifierCreationException if the classifier can not be created due to any reason. + * @throws ModelCreationException if the classifier can not be created due to any reason. */ - public ImageClassifier createNeuralNetImageClassifier(NeuralNetImageClassifier.BuildingBlock block) throws ClassifierCreationException { + public ImageClassifier createNeuralNetImageClassifier(NeuralNetImageClassifier.BuildingBlock block) throws ModelCreationException { if (imageClassifierFactories == null) { imageClassifierFactories = new HashMap<>(); for (ImageClassifierFactory classifierCreator : ServiceLoader.load(ImageClassifierFactory.class)) { @@ -47,7 +47,7 @@ public ImageClassifier createNeuralNetImageClassifier(NeuralNetImageClass ImageClassifierFactory creator = imageClassifierFactories.get(block.getInputClass()); if (creator == null) { - throw new ClassifierCreationException("Unsupported image class"); + throw new ModelCreationException("Unsupported image class"); } @SuppressWarnings("unchecked") @@ -61,9 +61,9 @@ public ImageClassifier createNeuralNetImageClassifier(NeuralNetImageClass * * @param block {@link NeuralNetBinaryClassifier.BuildingBlock} is provided to tune the building of the binary classifier. * @return {@link BinaryClassifier} - * @throws ClassifierCreationException if the classifier can not be created due to any reason. + * @throws ModelCreationException if the classifier can not be created due to any reason. */ - public BinaryClassifier createNeuralNetBinaryClassifier(NeuralNetBinaryClassifier.BuildingBlock block) throws ClassifierCreationException { + public BinaryClassifier createNeuralNetBinaryClassifier(NeuralNetBinaryClassifier.BuildingBlock block) throws ModelCreationException { if (binaryClassifierFactories == null) { binaryClassifierFactories = new HashMap<>(); for (BinaryClassifierFactory classifierCreator : ServiceLoader.load(BinaryClassifierFactory.class)) { @@ -73,7 +73,7 @@ public BinaryClassifier createNeuralNetBinaryClassifier(NeuralNetBinaryCl BinaryClassifierFactory creator = binaryClassifierFactories.get(block.getInputClass()); if (creator == null) { - throw new ClassifierCreationException("Unsupported target class"); + throw new ModelCreationException("Unsupported target class"); } @SuppressWarnings("unchecked") diff --git a/src/main/java/javax/visrec/spi/ImageClassifierFactory.java b/src/main/java/javax/visrec/spi/ImageClassifierFactory.java index 252a38b..533cb1a 100644 --- a/src/main/java/javax/visrec/spi/ImageClassifierFactory.java +++ b/src/main/java/javax/visrec/spi/ImageClassifierFactory.java @@ -1,6 +1,6 @@ package javax.visrec.spi; -import javax.visrec.ml.classification.ClassifierCreationException; +import javax.visrec.ml.model.ModelCreationException; import javax.visrec.ml.classification.ImageClassifier; import javax.visrec.ml.classification.NeuralNetImageClassifier; @@ -8,6 +8,6 @@ public interface ImageClassifierFactory { Class getImageClass(); - ImageClassifier create(NeuralNetImageClassifier.BuildingBlock block) throws ClassifierCreationException; + ImageClassifier create(NeuralNetImageClassifier.BuildingBlock block) throws ModelCreationException; } From 6cc10f24577bf0e8249113d995275bd1990b0dbc Mon Sep 17 00:00:00 2001 From: deepnetts Date: Fri, 5 Feb 2021 14:11:37 +0100 Subject: [PATCH 73/87] added threshold to interfaces and building blocks --- .../classification/NeuralNetBinaryClassifier.java | 15 +++++++++++++++ .../classification/NeuralNetImageClassifier.java | 13 +++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/main/java/javax/visrec/ml/classification/NeuralNetBinaryClassifier.java b/src/main/java/javax/visrec/ml/classification/NeuralNetBinaryClassifier.java index 27c5e22..3840f9a 100644 --- a/src/main/java/javax/visrec/ml/classification/NeuralNetBinaryClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/NeuralNetBinaryClassifier.java @@ -18,6 +18,7 @@ class BuildingBlock { private int maxEpochs; private float learningRate; private Path trainingPath; + private float threshold; private BuildingBlock() { } @@ -50,6 +51,12 @@ public Path getTrainingPath() { return trainingPath; } + public float getThreshold() { + return threshold; + } + + + private static BuildingBlock copyWithNewTargetClass(BuildingBlock block, Class cls) { BuildingBlock newBlock = new BuildingBlock<>(); newBlock.inputCls = cls; @@ -59,6 +66,7 @@ private static BuildingBlock copyWithNewTargetClass(BuildingBlock bloc newBlock.maxEpochs = block.maxEpochs; newBlock.learningRate = block.learningRate; newBlock.trainingPath = block.trainingPath; + newBlock.threshold = block.threshold; return newBlock; } } @@ -109,6 +117,13 @@ public Builder trainingPath(Path trainingPath) { block.trainingPath = trainingPath; return this; } + + public Builder threshold(float threshold) { + block.threshold = threshold; + return this; + } + + public NeuralNetBinaryClassifier.BuildingBlock getBuildingBlock() { return block; diff --git a/src/main/java/javax/visrec/ml/classification/NeuralNetImageClassifier.java b/src/main/java/javax/visrec/ml/classification/NeuralNetImageClassifier.java index 755164a..c612f5f 100644 --- a/src/main/java/javax/visrec/ml/classification/NeuralNetImageClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/NeuralNetImageClassifier.java @@ -22,6 +22,7 @@ class BuildingBlock { private Path exportPath; private Path importPath; private int maxEpochs; + private float threshold; private Class inputCls; private BuildingBlock() { @@ -68,6 +69,12 @@ public int getMaxEpochs() { return maxEpochs; } + public float getThreshold() { + return threshold; + } + + + public Class getInputClass() { return inputCls; } @@ -85,6 +92,7 @@ private static BuildingBlock copyWithNewInputClass(BuildingBlock block newBlock.maxEpochs = block.maxEpochs; newBlock.learningRate = block.learningRate; newBlock.trainingPath = block.trainingPath; + newBlock.threshold = block.threshold; return newBlock; } } @@ -140,6 +148,11 @@ public Builder learningRate(float learningRate) { block.learningRate = learningRate; return this; } + + public Builder threshold(float threshold) { + block.threshold = threshold; + return this; + } public Builder exportModel(Path path) { block.exportPath = path; From fb71a31f806b2707ae7bfe3650950a508432f8d9 Mon Sep 17 00:00:00 2001 From: deepnetts Date: Fri, 5 Feb 2021 14:19:40 +0100 Subject: [PATCH 74/87] fixed ensamble --- .../ml/classification/EnsambleClassifier.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java b/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java index 9902610..7d49aa2 100644 --- a/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java @@ -1,6 +1,8 @@ package javax.visrec.ml.classification; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; /** @@ -19,13 +21,14 @@ public final class EnsambleClassifier implements Classifier { @Override public R classify(T input) { + List results = new ArrayList<>(); for (Map.Entry> classifier : classifiers.entrySet()) { - classifier.getValue().classify(input); + R result = classifier.getValue().classify(input); + results.add(result); } - // get the highest class frequency - //.collect(); // get average scores? This method can be overriden, provide default impl here - // return merged classification result of all classifiers - mean or most frequent? - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + + int[] freq = new int[results.size()]; + return results.get(0); } // or just provide method for adding swith some intrenal id? From 9ca1671eb75100e407384898999161ac00e8d103 Mon Sep 17 00:00:00 2001 From: deepnetts Date: Fri, 5 Feb 2021 14:24:36 +0100 Subject: [PATCH 75/87] moved AbstractImageClassifier to ri --- .../AbstractImageClassifier.java | 91 ------------------- .../ml/classification/EnsambleClassifier.java | 2 +- 2 files changed, 1 insertion(+), 92 deletions(-) delete mode 100644 src/main/java/javax/visrec/ml/classification/AbstractImageClassifier.java diff --git a/src/main/java/javax/visrec/ml/classification/AbstractImageClassifier.java b/src/main/java/javax/visrec/ml/classification/AbstractImageClassifier.java deleted file mode 100644 index 8bd0ec3..0000000 --- a/src/main/java/javax/visrec/ml/classification/AbstractImageClassifier.java +++ /dev/null @@ -1,91 +0,0 @@ -package javax.visrec.ml.classification; - -import javax.visrec.ImageFactory; -import javax.visrec.ml.model.ModelProvider; -import javax.visrec.spi.ServiceProvider; -import java.awt.image.BufferedImage; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Path; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; - -/** - * Skeleton abstract class to make it easier to implement image classifier. - * It provides implementation of Classifier interface for images, along with - * image factory for specific type of images. - * This class solves the problem of using various implementation of images and machine learning models in Java, - * and provides standard Classifier API for clients. - *

- * By default the type of key in the Map the {@link ImageClassifier} is {@code String} - * - * @param class to classify - * @param class of machine learning model - * @author Zoran Sevarac - * @since 1.0 - */ -public abstract class AbstractImageClassifier implements ImageClassifier, ModelProvider { - - private final ImageFactory imageFactory; - private MODEL_CLASS model; - - // TODO: this should ba a part of every classifier - private float threshold = 0.0f; - - protected AbstractImageClassifier(final Class imgCls, final MODEL_CLASS model) { - final Optional> optionalImageFactory = ServiceProvider.current() - .getImageFactoryService() - .getByImageType(imgCls); - if (!optionalImageFactory.isPresent()) { - throw new IllegalArgumentException(String.format("Could not find ImageFactory by '%s'", BufferedImage.class.getName())); - } - imageFactory = optionalImageFactory.get(); - setModel(model); - } - - public ImageFactory getImageFactory() { - return imageFactory; - } - - @Override - public Map classify(Path path) throws ClassificationException { - IMAGE_CLASS image; - try { - image = imageFactory.getImage(path); - return classify(image); - } catch (IOException e) { - throw new ClassificationException("Failed to transform input into a BufferedImage", e); - } - } - - @Override - public Map classify(InputStream inputStream) throws ClassificationException { - IMAGE_CLASS image; - try { - image = imageFactory.getImage(inputStream); - return classify(image); - } catch (IOException e) { - throw new RuntimeException("Failed to transform input into a BufferedImage", e); - } - } - - // todo: provide get top 1, 3, 5 results; sort and get - - @Override - public MODEL_CLASS getModel() { - return model; - } - - protected final void setModel(MODEL_CLASS model) { - this.model = Objects.requireNonNull(model, "Model cannot bu null!"); - } - - public float getThreshold() { - return threshold; - } - - public void setThreshold(float threshold) { - this.threshold = threshold; - } -} diff --git a/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java b/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java index 7d49aa2..aea19ff 100644 --- a/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java @@ -28,7 +28,7 @@ public R classify(T input) { } int[] freq = new int[results.size()]; - return results.get(0); + return results.get(0); // todo } // or just provide method for adding swith some intrenal id? From 0bbd2f4e7abcb98b4dfae6ecbed4119ea19932ed Mon Sep 17 00:00:00 2001 From: deepnetts Date: Tue, 16 Feb 2021 15:55:57 +0100 Subject: [PATCH 76/87] added classifiable, fixes for ensamble and zero rule clasifier --- .../AbstractMultiClassClassifier.java | 8 +++--- .../ml/classification/BinaryClassifier.java | 9 +++--- .../ml/classification/Classifiable.java | 28 +++++++++++++++++++ .../ml/classification/EnsambleClassifier.java | 20 ++++++++++--- 4 files changed, 52 insertions(+), 13 deletions(-) create mode 100644 src/main/java/javax/visrec/ml/classification/Classifiable.java diff --git a/src/main/java/javax/visrec/ml/classification/AbstractMultiClassClassifier.java b/src/main/java/javax/visrec/ml/classification/AbstractMultiClassClassifier.java index 41cc047..e8a1920 100644 --- a/src/main/java/javax/visrec/ml/classification/AbstractMultiClassClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/AbstractMultiClassClassifier.java @@ -3,11 +3,11 @@ import javax.visrec.ml.model.ModelProvider; /** + * Skeleton base class for implementations of multi class classifiers. * - * @author Zoran - * @param class of machine learning model backend - * @param - * @param + * @param class of machine learning model back-end + * @param type of classifier's input + * @param type of classifier's results/class */ public abstract class AbstractMultiClassClassifier implements MultiClassClassifier, ModelProvider { diff --git a/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java b/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java index 9c36954..eb77bac 100644 --- a/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java @@ -1,11 +1,10 @@ package javax.visrec.ml.classification; /** - * Binary classifier classifies object into one of two categories (for example: true/false, yes/no, red/blue, spam/not-spam, fraud/not-fraud). - * Returns a probability that input object belongs to one of two classes. - * - * @author Zoran Sevarac + * Binary classifier classifies input object into one of two possible categories + * (for example: true/false, yes/no, red/blue, positive/negative, spam/not-spam, fraud/not-fraud). + * Returns a probability (float value [0..1]) that input object belongs to one positive class. */ public interface BinaryClassifier extends Classifier { -} +} \ No newline at end of file diff --git a/src/main/java/javax/visrec/ml/classification/Classifiable.java b/src/main/java/javax/visrec/ml/classification/Classifiable.java new file mode 100644 index 0000000..dc78844 --- /dev/null +++ b/src/main/java/javax/visrec/ml/classification/Classifiable.java @@ -0,0 +1,28 @@ +package javax.visrec.ml.classification; + +/** + * Classes that implement this interface enable direct classification of Java objects, no need to manually convert to data structures used internally by ML. + * Simplifies usage and integration + * This interface should be implemented for classes whose objects we want to be able to classify.Instances of classes that implement this interface can be classified, and used as examples + * to build machine learning based classifiers.Typical implementation scenario is to wrap domain specific class and implement this interface. + * + * Classifiable can be classfied by the Classifier (with the same T and C) + * + * @param Type of input for classifier + * @param Type of class instances (could be anything like enum, String, Integer or user defined class) + */ +public interface Classifiable { + + /** + * Returns input for classifier. + * Implementation of this method should convert attributes of an object for specific classifier. + * @return + */ + T getClassifierInput(); + + /** + * Returns target class for classifier. + * @return + */ + C getTargetClass(); +} diff --git a/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java b/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java index aea19ff..e956882 100644 --- a/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java @@ -22,16 +22,28 @@ public final class EnsambleClassifier implements Classifier { @Override public R classify(T input) { List results = new ArrayList<>(); + Map freqCount = new HashMap<>(); + int maxFreq = 0; + R maxClass = null; for (Map.Entry> classifier : classifiers.entrySet()) { R result = classifier.getValue().classify(input); results.add(result); - } + // what if it is a binary classifier ? it should return class name with correspondin probability + if (freqCount.containsKey(result)) { + freqCount.put(result.toString(), freqCount.get(result.toString())+1); + } else { + freqCount.put(result.toString(), 1); + } + + if (freqCount.get(result.toString()) > maxFreq) { + maxFreq = freqCount.get(result.toString()); + maxClass = result; + } + } - int[] freq = new int[results.size()]; - return results.get(0); // todo + return maxClass; } - // or just provide method for adding swith some intrenal id? public void addClassifier(String classifierId, Classifier classifier) { classifiers.put(classifierId, classifier); } From eeed0411f8a41e244d72c4b37f16c14775edd201 Mon Sep 17 00:00:00 2001 From: deepnetts Date: Fri, 19 Feb 2021 17:30:11 +0100 Subject: [PATCH 77/87] removed @author tag in javadoc in api --- src/main/java/javax/visrec/ImageFactory.java | 1 - .../visrec/ml/classification/ClassificationException.java | 1 - .../java/javax/visrec/ml/classification/Classifier.java | 1 - .../javax/visrec/ml/classification/EnsambleClassifier.java | 1 - .../javax/visrec/ml/classification/ImageClassifier.java | 1 - .../javax/visrec/ml/classification/LogisticRegression.java | 1 - .../visrec/ml/classification/MultiClassClassifier.java | 1 - src/main/java/javax/visrec/ml/data/BasicDataSet.java | 1 - src/main/java/javax/visrec/ml/data/DataSet.java | 1 - src/main/java/javax/visrec/ml/detection/BoundingBox.java | 1 - src/main/java/javax/visrec/ml/detection/ObjectDetector.java | 1 - src/main/java/javax/visrec/ml/eval/EvaluationMetrics.java | 1 - src/main/java/javax/visrec/ml/eval/Evaluator.java | 1 - .../visrec/ml/model/InvalidConfigurationException.java | 1 - src/main/java/javax/visrec/ml/model/ModelBuilder.java | 6 +++--- .../java/javax/visrec/ml/model/ModelCreationException.java | 1 - src/main/java/javax/visrec/ml/regression/Regressor.java | 1 - .../java/javax/visrec/spi/ClassifierFactoryService.java | 1 - src/main/java/javax/visrec/spi/ImageFactoryService.java | 1 - src/main/java/javax/visrec/spi/ImplementationService.java | 2 +- src/main/java/javax/visrec/spi/ServiceProvider.java | 3 --- src/main/java/javax/visrec/spi/ServiceRegistry.java | 1 - 22 files changed, 4 insertions(+), 26 deletions(-) diff --git a/src/main/java/javax/visrec/ImageFactory.java b/src/main/java/javax/visrec/ImageFactory.java index fef62ac..1d07a4c 100644 --- a/src/main/java/javax/visrec/ImageFactory.java +++ b/src/main/java/javax/visrec/ImageFactory.java @@ -9,7 +9,6 @@ * This interface provides a standard way to get/read different(specified) kinds of image from file, url or input stream. * * @param the type of object to be returned after getting image from {@link Path}, {@link URL} or {@link InputStream} - * @author Zoran Sevarac * @since 1.0 */ public interface ImageFactory { diff --git a/src/main/java/javax/visrec/ml/classification/ClassificationException.java b/src/main/java/javax/visrec/ml/classification/ClassificationException.java index 583fbc3..f312e19 100644 --- a/src/main/java/javax/visrec/ml/classification/ClassificationException.java +++ b/src/main/java/javax/visrec/ml/classification/ClassificationException.java @@ -3,7 +3,6 @@ /** * Exception thrown if anything fails in the execution of a classifier. * - * @author Kevin Berendsen * @since 1.0 */ public class ClassificationException extends RuntimeException { diff --git a/src/main/java/javax/visrec/ml/classification/Classifier.java b/src/main/java/javax/visrec/ml/classification/Classifier.java index 0a524d0..407590d 100644 --- a/src/main/java/javax/visrec/ml/classification/Classifier.java +++ b/src/main/java/javax/visrec/ml/classification/Classifier.java @@ -14,7 +14,6 @@ * * @param type of input objects to classify (eg. User, Product, Transaction, Image, etc.) * @param type of classification result (String, Enum, custom class). - * @author Zoran Sevarac * @see BinaryClassifier * @see MultiClassClassifier * @see ImageClassifier diff --git a/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java b/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java index e956882..98a5540 100644 --- a/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java @@ -10,7 +10,6 @@ * classification result, which gives better accuracy then each individual * classifier. Usually average or most frequent answer is used as a final result. * - * @author Zoran Sevarac * @param The input type which is to be classified. * @param Return type of the classifier. * @since 1.0 diff --git a/src/main/java/javax/visrec/ml/classification/ImageClassifier.java b/src/main/java/javax/visrec/ml/classification/ImageClassifier.java index 7a4b9af..d8d2271 100644 --- a/src/main/java/javax/visrec/ml/classification/ImageClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/ImageClassifier.java @@ -9,7 +9,6 @@ * Classifier interface specialized in image classification * * @param type of input objects to classify (eg. User, Product, Transaction, Image, etc.) - * @author Zoran Sevarac * @since 1.0 */ public interface ImageClassifier extends Classifier> { diff --git a/src/main/java/javax/visrec/ml/classification/LogisticRegression.java b/src/main/java/javax/visrec/ml/classification/LogisticRegression.java index 530001e..dafc4ef 100644 --- a/src/main/java/javax/visrec/ml/classification/LogisticRegression.java +++ b/src/main/java/javax/visrec/ml/classification/LogisticRegression.java @@ -8,7 +8,6 @@ * using logistic regression algorithm. * Subclasses should use specific logistic regression implementation to provide that functionality. * - * @author Zoran Sevarac * @param Implementation class of underlying machine learning model */ public abstract class LogisticRegression implements BinaryClassifier, ModelProvider { diff --git a/src/main/java/javax/visrec/ml/classification/MultiClassClassifier.java b/src/main/java/javax/visrec/ml/classification/MultiClassClassifier.java index e1f070c..915a498 100644 --- a/src/main/java/javax/visrec/ml/classification/MultiClassClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/MultiClassClassifier.java @@ -7,7 +7,6 @@ * Multi class classification assigns input object to one of several possible category/class. * For example: is it a cat, a dog or a bird? * - * @author Zoran Sevarac * @param Type of input objects (which are being classified) * @param Type of classifier return value - type of object which represent category class. */ diff --git a/src/main/java/javax/visrec/ml/data/BasicDataSet.java b/src/main/java/javax/visrec/ml/data/BasicDataSet.java index 2ef49e1..acd7db7 100644 --- a/src/main/java/javax/visrec/ml/data/BasicDataSet.java +++ b/src/main/java/javax/visrec/ml/data/BasicDataSet.java @@ -10,7 +10,6 @@ * Provides a list of data set items with column info. * * @param Type of elements in data set - * @author Zoran Sevarac */ public class BasicDataSet implements DataSet { diff --git a/src/main/java/javax/visrec/ml/data/DataSet.java b/src/main/java/javax/visrec/ml/data/DataSet.java index 32a1e49..f72efbe 100644 --- a/src/main/java/javax/visrec/ml/data/DataSet.java +++ b/src/main/java/javax/visrec/ml/data/DataSet.java @@ -11,7 +11,6 @@ /** * Generic interface for all data sets for machine learning, independent of type of elements. * - * @author Zoran Sevarac * @param type of data set elements * @since 1.0 */ diff --git a/src/main/java/javax/visrec/ml/detection/BoundingBox.java b/src/main/java/javax/visrec/ml/detection/BoundingBox.java index 029b192..21b83af 100644 --- a/src/main/java/javax/visrec/ml/detection/BoundingBox.java +++ b/src/main/java/javax/visrec/ml/detection/BoundingBox.java @@ -3,7 +3,6 @@ /** * This class represents a bounding box over image at specified position, dimensions, label and score. * - * @author Zoran Sevarac * @since 1.0 */ public class BoundingBox { diff --git a/src/main/java/javax/visrec/ml/detection/ObjectDetector.java b/src/main/java/javax/visrec/ml/detection/ObjectDetector.java index d1a5247..a32ecbf 100644 --- a/src/main/java/javax/visrec/ml/detection/ObjectDetector.java +++ b/src/main/java/javax/visrec/ml/detection/ObjectDetector.java @@ -7,7 +7,6 @@ * Interface to perform object detection in image. * Returns a map of object labels/classes and corresponding location in image outlined by BoundingBox-es * - * @author Zoran Sevarac * @param Class used to represent image that will be analyzed * @since 1.0 */ diff --git a/src/main/java/javax/visrec/ml/eval/EvaluationMetrics.java b/src/main/java/javax/visrec/ml/eval/EvaluationMetrics.java index 4aa4861..ea9c071 100644 --- a/src/main/java/javax/visrec/ml/eval/EvaluationMetrics.java +++ b/src/main/java/javax/visrec/ml/eval/EvaluationMetrics.java @@ -27,7 +27,6 @@ /** * Wrapper for constants and values for classifier and regressor evaluation metrics. * - * @author Zoran Sevarac */ public class EvaluationMetrics { diff --git a/src/main/java/javax/visrec/ml/eval/Evaluator.java b/src/main/java/javax/visrec/ml/eval/Evaluator.java index def121f..9f33415 100644 --- a/src/main/java/javax/visrec/ml/eval/Evaluator.java +++ b/src/main/java/javax/visrec/ml/eval/Evaluator.java @@ -28,7 +28,6 @@ * @param Model class * @param Data set class * - * @author Zoran Sevarac * @since 1.0 */ @FunctionalInterface diff --git a/src/main/java/javax/visrec/ml/model/InvalidConfigurationException.java b/src/main/java/javax/visrec/ml/model/InvalidConfigurationException.java index 64f6322..b96ca38 100644 --- a/src/main/java/javax/visrec/ml/model/InvalidConfigurationException.java +++ b/src/main/java/javax/visrec/ml/model/InvalidConfigurationException.java @@ -5,7 +5,6 @@ * declared setter method can't be invoked it will throw this exception because the configuration * doesn't match the method to invoke. * - * @author Kevin Berendsen */ public class InvalidConfigurationException extends ModelCreationException { diff --git a/src/main/java/javax/visrec/ml/model/ModelBuilder.java b/src/main/java/javax/visrec/ml/model/ModelBuilder.java index 279980d..3758084 100644 --- a/src/main/java/javax/visrec/ml/model/ModelBuilder.java +++ b/src/main/java/javax/visrec/ml/model/ModelBuilder.java @@ -5,11 +5,9 @@ import java.util.Map; /** - * Generic builder interface, that all builders for machine learning algorithms implement. + * Generic model builder interface, that all builders for machine learning algorithms implement. * * @param type of the object to be returned by the builder. - * @author Zoran Sevarac - * @author Kevin Berendsen * @since 1.0 */ public interface ModelBuilder { @@ -18,6 +16,7 @@ public interface ModelBuilder { * Builds and returns an object using properties set using available builder methods. * * @return object specified by the builder to build + * @throws javax.visrec.ml.model.ModelCreationException */ T build() throws ModelCreationException; @@ -26,6 +25,7 @@ public interface ModelBuilder { * * @param configuration properties for the builder, a map of key, value pairs. * @return object specified by the builder to build + * @throws javax.visrec.ml.model.ModelCreationException */ default T build(Map configuration) throws ModelCreationException { Method[] methods = this.getClass().getDeclaredMethods(); diff --git a/src/main/java/javax/visrec/ml/model/ModelCreationException.java b/src/main/java/javax/visrec/ml/model/ModelCreationException.java index eff258e..ab16f68 100644 --- a/src/main/java/javax/visrec/ml/model/ModelCreationException.java +++ b/src/main/java/javax/visrec/ml/model/ModelCreationException.java @@ -3,7 +3,6 @@ /** * Exception thrown if anything fails in the creation of a classifier. * - * @author Kevin Berendsen * @since 1.0 */ public class ModelCreationException extends Exception { diff --git a/src/main/java/javax/visrec/ml/regression/Regressor.java b/src/main/java/javax/visrec/ml/regression/Regressor.java index 0a4d05a..16dffa5 100644 --- a/src/main/java/javax/visrec/ml/regression/Regressor.java +++ b/src/main/java/javax/visrec/ml/regression/Regressor.java @@ -6,7 +6,6 @@ * Implementations should specify specific type of inputs and outputs that * specific algorithm expects and returns. * - * @author Zoran Sevarac * @param type of inputs / features * @param return/result type */ diff --git a/src/main/java/javax/visrec/spi/ClassifierFactoryService.java b/src/main/java/javax/visrec/spi/ClassifierFactoryService.java index 4280874..63e3e05 100644 --- a/src/main/java/javax/visrec/spi/ClassifierFactoryService.java +++ b/src/main/java/javax/visrec/spi/ClassifierFactoryService.java @@ -9,7 +9,6 @@ /** * Service to provide the correct {@link Classifier} implementation. * - * @author Kevin Berendsen * @since 1.0 */ public final class ClassifierFactoryService { diff --git a/src/main/java/javax/visrec/spi/ImageFactoryService.java b/src/main/java/javax/visrec/spi/ImageFactoryService.java index b64b91a..3c1e5da 100644 --- a/src/main/java/javax/visrec/spi/ImageFactoryService.java +++ b/src/main/java/javax/visrec/spi/ImageFactoryService.java @@ -6,7 +6,6 @@ /** * The service to locate and find implementations of the {@link ImageFactory} interface. * - * @author Kevin Berendsen * @since 1.0 */ public interface ImageFactoryService { diff --git a/src/main/java/javax/visrec/spi/ImplementationService.java b/src/main/java/javax/visrec/spi/ImplementationService.java index 0150a1f..47fc2e1 100644 --- a/src/main/java/javax/visrec/spi/ImplementationService.java +++ b/src/main/java/javax/visrec/spi/ImplementationService.java @@ -2,7 +2,7 @@ /** * Returns information about the used implementation of visual recognition API - * @author Kevin Berendsen + * * @since 1.0 */ public abstract class ImplementationService { diff --git a/src/main/java/javax/visrec/spi/ServiceProvider.java b/src/main/java/javax/visrec/spi/ServiceProvider.java index ec72f54..225a01b 100644 --- a/src/main/java/javax/visrec/spi/ServiceProvider.java +++ b/src/main/java/javax/visrec/spi/ServiceProvider.java @@ -10,9 +10,6 @@ /** * The ServiceProvider is the centralized provider to provide API scoped services. * - * @author Werner Keil - * @author Martin Desruisseaux - * @author Kevin Berendsen * @since 1.0 */ public abstract class ServiceProvider { diff --git a/src/main/java/javax/visrec/spi/ServiceRegistry.java b/src/main/java/javax/visrec/spi/ServiceRegistry.java index 85f07d5..dd75760 100644 --- a/src/main/java/javax/visrec/spi/ServiceRegistry.java +++ b/src/main/java/javax/visrec/spi/ServiceRegistry.java @@ -22,7 +22,6 @@ /** * Registry for all ML algorithms provided by this implementation. * - * @author Zoran Sevarac */ public class ServiceRegistry { From 4cb44f9a5bfe59ca0484010701f1ac9fb38e6c8d Mon Sep 17 00:00:00 2001 From: deepnetts Date: Wed, 3 Mar 2021 12:57:38 +0100 Subject: [PATCH 78/87] Java doc updated --- .../visrec/ml/classification/Classifiable.java | 14 +++++++++----- .../javax/visrec/ml/classification/Classifier.java | 8 +++++--- .../visrec/ml/classification/package-info.java | 7 +++++++ .../java/javax/visrec/ml/data/package-info.java | 5 +++++ .../visrec/ml/data/preprocessing/package-info.java | 4 ++++ .../javax/visrec/ml/detection/ObjectDetector.java | 2 +- .../javax/visrec/ml/detection/package-info.java | 4 ++++ src/main/java/javax/visrec/package-info.java | 2 +- 8 files changed, 36 insertions(+), 10 deletions(-) create mode 100644 src/main/java/javax/visrec/ml/classification/package-info.java create mode 100644 src/main/java/javax/visrec/ml/data/package-info.java create mode 100644 src/main/java/javax/visrec/ml/data/preprocessing/package-info.java create mode 100644 src/main/java/javax/visrec/ml/detection/package-info.java diff --git a/src/main/java/javax/visrec/ml/classification/Classifiable.java b/src/main/java/javax/visrec/ml/classification/Classifiable.java index dc78844..846e3ae 100644 --- a/src/main/java/javax/visrec/ml/classification/Classifiable.java +++ b/src/main/java/javax/visrec/ml/classification/Classifiable.java @@ -1,15 +1,19 @@ package javax.visrec.ml.classification; /** - * Classes that implement this interface enable direct classification of Java objects, no need to manually convert to data structures used internally by ML. - * Simplifies usage and integration - * This interface should be implemented for classes whose objects we want to be able to classify.Instances of classes that implement this interface can be classified, and used as examples - * to build machine learning based classifiers.Typical implementation scenario is to wrap domain specific class and implement this interface. + * Classes that implement this interface enable direct classification of Java objects, + * no need to manually convert to data structures used internally by ML. + * + * This interface simplifies usage and integration of machine learning based classifiers with Java objects. + * It should be implemented by classes whose objects we want to be able to classify. + * Instances of classes that implement this interface can be used as examples + * to build machine learning based classifiers. + * Typical implementation scenario is to wrap domain specific class and implement this interface. * * Classifiable can be classfied by the Classifier (with the same T and C) * * @param Type of input for classifier - * @param Type of class instances (could be anything like enum, String, Integer or user defined class) + * @param Type of categories/labels (could be anything like enum, String, Integer or user defined class) */ public interface Classifiable { diff --git a/src/main/java/javax/visrec/ml/classification/Classifier.java b/src/main/java/javax/visrec/ml/classification/Classifier.java index 407590d..08b8acf 100644 --- a/src/main/java/javax/visrec/ml/classification/Classifier.java +++ b/src/main/java/javax/visrec/ml/classification/Classifier.java @@ -1,10 +1,12 @@ package javax.visrec.ml.classification; /** - * Classifier answers the question what is the category/type of an input object. - * Each category/type has corresponding label or class name, which can be String, Enum or custom user defined class. - * This is a generic classifier interface, that all classifiers should implement, and + * Generic classifier interface, that all classifiers should implement, and * it provides a method to classify given instances of some class. + * Each category/type has corresponding label or class, which can be String, Enum or custom user defined class. + * Machine learning based classifier can learn from examples how to determine a + * category of an input object with high degree of confidence. + * *

* Implementations should specify input type of instances that are classified, * and type of the returned vales . diff --git a/src/main/java/javax/visrec/ml/classification/package-info.java b/src/main/java/javax/visrec/ml/classification/package-info.java new file mode 100644 index 0000000..0003f3a --- /dev/null +++ b/src/main/java/javax/visrec/ml/classification/package-info.java @@ -0,0 +1,7 @@ +/** + * Classification represents task of determining a category of a given object. + * Machine learning classifiers are able to learn from examples how to determine + * a category for a given object, that has not seen before + * (although it should be similar to examples that were used to build a classifier). + */ +package javax.visrec.ml.classification; \ No newline at end of file diff --git a/src/main/java/javax/visrec/ml/data/package-info.java b/src/main/java/javax/visrec/ml/data/package-info.java new file mode 100644 index 0000000..a4faf64 --- /dev/null +++ b/src/main/java/javax/visrec/ml/data/package-info.java @@ -0,0 +1,5 @@ +/** + * A collection of example data used to build/train machine learning model. + * The goal of this package is to have reusable data abstractions with common operations for building machine learning models. + */ +package javax.visrec.ml.data; \ No newline at end of file diff --git a/src/main/java/javax/visrec/ml/data/preprocessing/package-info.java b/src/main/java/javax/visrec/ml/data/preprocessing/package-info.java new file mode 100644 index 0000000..b3e71de --- /dev/null +++ b/src/main/java/javax/visrec/ml/data/preprocessing/package-info.java @@ -0,0 +1,4 @@ +/** + * Data preprocessing techniques used to prepare data for building machine learning models. + */ +package javax.visrec.ml.data.preprocessing; \ No newline at end of file diff --git a/src/main/java/javax/visrec/ml/detection/ObjectDetector.java b/src/main/java/javax/visrec/ml/detection/ObjectDetector.java index a32ecbf..8824b9f 100644 --- a/src/main/java/javax/visrec/ml/detection/ObjectDetector.java +++ b/src/main/java/javax/visrec/ml/detection/ObjectDetector.java @@ -14,7 +14,7 @@ public interface ObjectDetector { /** - * Detects object in specified image + * Detects object in specified image and returns a map with detected objects in bounding boxes. * * @param image image to search for object * @return a map of multiple {@link BoundingBox} diff --git a/src/main/java/javax/visrec/ml/detection/package-info.java b/src/main/java/javax/visrec/ml/detection/package-info.java new file mode 100644 index 0000000..a66b75d --- /dev/null +++ b/src/main/java/javax/visrec/ml/detection/package-info.java @@ -0,0 +1,4 @@ +/** + * Object detection algorithms. + */ +package javax.visrec.ml.detection; \ No newline at end of file diff --git a/src/main/java/javax/visrec/package-info.java b/src/main/java/javax/visrec/package-info.java index ed7ba4d..c00e93c 100644 --- a/src/main/java/javax/visrec/package-info.java +++ b/src/main/java/javax/visrec/package-info.java @@ -1,5 +1,5 @@ /** - * Visual recognition API provides reusable abstractions for visual recognition tasks based on machine learning, + * Reusable abstractions for visual recognition tasks based on machine learning, * that simplify implementation and integration of various machine learning models and image types. */ package javax.visrec; \ No newline at end of file From cb703b051684cf3d0ae7dec8859810135288ef9f Mon Sep 17 00:00:00 2001 From: kevto Date: Tue, 16 Mar 2021 14:37:57 +0100 Subject: [PATCH 79/87] Updating version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8e014b2..0089e22 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 javax.visrec visrec-api - 1.0.1-SNAPSHOT + 1.0.2-SNAPSHOT jar javax.visrec:visrec-api From 6df4afe998f91acb87da0ce4b0affd1a445edb8c Mon Sep 17 00:00:00 2001 From: deepnetts Date: Tue, 30 Mar 2021 11:36:11 +0200 Subject: [PATCH 80/87] Fixes to implement latest visrec api --- .../visrec/ml/classification/BinaryClassifier.java | 2 +- .../visrec/ml/classification/EnsambleClassifier.java | 3 ++- src/main/java/javax/visrec/ml/data/BasicDataSet.java | 2 +- src/main/java/javax/visrec/ml/data/DataSet.java | 12 ++++++++++-- .../javax/visrec/ml/data/preprocessing/Scaler.java | 2 +- 5 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java b/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java index eb77bac..96c0847 100644 --- a/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java @@ -3,7 +3,7 @@ /** * Binary classifier classifies input object into one of two possible categories * (for example: true/false, yes/no, red/blue, positive/negative, spam/not-spam, fraud/not-fraud). - * Returns a probability (float value [0..1]) that input object belongs to one positive class. + * Returns a probability (float value [0..1]) that input object belongs to the positive class. */ public interface BinaryClassifier extends Classifier { diff --git a/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java b/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java index 98a5540..11ef06d 100644 --- a/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java @@ -27,7 +27,8 @@ public R classify(T input) { for (Map.Entry> classifier : classifiers.entrySet()) { R result = classifier.getValue().classify(input); results.add(result); - // what if it is a binary classifier ? it should return class name with correspondin probability + // what if it is a binary classifier ? it should return class name with corresponding probability + // if (instanceof BinaryClassifier) if (freqCount.containsKey(result)) { freqCount.put(result.toString(), freqCount.get(result.toString())+1); } else { diff --git a/src/main/java/javax/visrec/ml/data/BasicDataSet.java b/src/main/java/javax/visrec/ml/data/BasicDataSet.java index acd7db7..d813be0 100644 --- a/src/main/java/javax/visrec/ml/data/BasicDataSet.java +++ b/src/main/java/javax/visrec/ml/data/BasicDataSet.java @@ -57,7 +57,7 @@ public List getItems() { } @Override - public List columns() { + public List getColumns() { return columns; } diff --git a/src/main/java/javax/visrec/ml/data/DataSet.java b/src/main/java/javax/visrec/ml/data/DataSet.java index f72efbe..194a499 100644 --- a/src/main/java/javax/visrec/ml/data/DataSet.java +++ b/src/main/java/javax/visrec/ml/data/DataSet.java @@ -172,8 +172,16 @@ default void shuffle(Random rnd) { * * @return */ - public List columns(); - + public List getColumns(); + + /** + * Get the names of target columns. + * Target columns are use as target output during the training. + * + * @return Returns target columns + */ + public String[] getTargetColumnsNames(); + default public Stream stream() { return getItems().stream(); diff --git a/src/main/java/javax/visrec/ml/data/preprocessing/Scaler.java b/src/main/java/javax/visrec/ml/data/preprocessing/Scaler.java index e1999a5..3dd58fc 100644 --- a/src/main/java/javax/visrec/ml/data/preprocessing/Scaler.java +++ b/src/main/java/javax/visrec/ml/data/preprocessing/Scaler.java @@ -11,6 +11,6 @@ * @param Data set class (that implements DataSet interface) */ public interface Scaler> { - public void scale(T dataSet); + public void apply(T dataSet); } From 235e16a01058daf8cef051dd5f0a0182933d33c6 Mon Sep 17 00:00:00 2001 From: deepnetts Date: Tue, 30 Mar 2021 15:16:30 +0200 Subject: [PATCH 81/87] Fixes to implement latest visrec api --- src/main/java/javax/visrec/ml/classification/Classifier.java | 1 + .../javax/visrec/ml/classification/EnsambleClassifier.java | 5 +++-- .../java/javax/visrec/ml/classification/package-info.java | 2 +- src/main/java/javax/visrec/ml/regression/Regressor.java | 2 +- .../javax/visrec/ml/regression/SimpleLinearRegression.java | 5 +++-- 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/main/java/javax/visrec/ml/classification/Classifier.java b/src/main/java/javax/visrec/ml/classification/Classifier.java index 08b8acf..634b15d 100644 --- a/src/main/java/javax/visrec/ml/classification/Classifier.java +++ b/src/main/java/javax/visrec/ml/classification/Classifier.java @@ -19,6 +19,7 @@ * @see BinaryClassifier * @see MultiClassClassifier * @see ImageClassifier + * @see Classifiable * @since 1.0 */ @FunctionalInterface diff --git a/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java b/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java index 11ef06d..8ae983c 100644 --- a/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java @@ -28,7 +28,7 @@ public R classify(T input) { R result = classifier.getValue().classify(input); results.add(result); // what if it is a binary classifier ? it should return class name with corresponding probability - // if (instanceof BinaryClassifier) + // if (instanceof BinaryClassifier) deal with binary classifiers using if statement if (freqCount.containsKey(result)) { freqCount.put(result.toString(), freqCount.get(result.toString())+1); } else { @@ -44,8 +44,9 @@ public R classify(T input) { return maxClass; } - public void addClassifier(String classifierId, Classifier classifier) { + public EnsambleClassifier addClassifier(String classifierId, Classifier classifier) { classifiers.put(classifierId, classifier); + return this; } public Classifier getClassifier(String classiferId) { diff --git a/src/main/java/javax/visrec/ml/classification/package-info.java b/src/main/java/javax/visrec/ml/classification/package-info.java index 0003f3a..2aa5dbb 100644 --- a/src/main/java/javax/visrec/ml/classification/package-info.java +++ b/src/main/java/javax/visrec/ml/classification/package-info.java @@ -1,7 +1,7 @@ /** * Classification represents task of determining a category of a given object. * Machine learning classifiers are able to learn from examples how to determine - * a category for a given object, that has not seen before + * a category (or a label) for a given input object, that has not seen before * (although it should be similar to examples that were used to build a classifier). */ package javax.visrec.ml.classification; \ No newline at end of file diff --git a/src/main/java/javax/visrec/ml/regression/Regressor.java b/src/main/java/javax/visrec/ml/regression/Regressor.java index 16dffa5..8ef2b52 100644 --- a/src/main/java/javax/visrec/ml/regression/Regressor.java +++ b/src/main/java/javax/visrec/ml/regression/Regressor.java @@ -9,7 +9,7 @@ * @param type of inputs / features * @param return/result type */ -public interface Regressor { +public interface Regressor { R predict(I inputs); diff --git a/src/main/java/javax/visrec/ml/regression/SimpleLinearRegression.java b/src/main/java/javax/visrec/ml/regression/SimpleLinearRegression.java index bc8ab84..77ea15d 100644 --- a/src/main/java/javax/visrec/ml/regression/SimpleLinearRegression.java +++ b/src/main/java/javax/visrec/ml/regression/SimpleLinearRegression.java @@ -27,7 +27,7 @@ protected final void setModel(MODEL_CLASS model) { public abstract Float predict(Float input); /** - * Slope tells how much on average output change when input changes by one. + * Slope parameter of the model tells how much on average output change when input changes by one. * * If it is zero there is no linear dependency between input and output, and data is probably scattered. * If it is less then one output grows slower then input. @@ -39,7 +39,8 @@ protected final void setModel(MODEL_CLASS model) { public abstract float getSlope(); /** - * Intercept tells us the value of prediction when input is zero + * Intercept tells us the value of prediction when input is zero. + * * @return */ public abstract float getIntercept(); From a937e2e46c4e7b9f4659e43fcc9454df64676317 Mon Sep 17 00:00:00 2001 From: deepnetts Date: Thu, 15 Apr 2021 17:24:39 +0200 Subject: [PATCH 82/87] Data set columns fix --- src/main/java/javax/visrec/ml/data/BasicDataSet.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/javax/visrec/ml/data/BasicDataSet.java b/src/main/java/javax/visrec/ml/data/BasicDataSet.java index d813be0..951dce4 100644 --- a/src/main/java/javax/visrec/ml/data/BasicDataSet.java +++ b/src/main/java/javax/visrec/ml/data/BasicDataSet.java @@ -21,7 +21,7 @@ public class BasicDataSet implements DataSet { /** * List of data set columns. Each column provides info about it's name, type. */ - private List columns; + private List columns = new ArrayList(); protected BasicDataSet() { items = new ArrayList<>(); @@ -62,7 +62,7 @@ public List getColumns() { } public void setColumnNames(String[] columnNames) { - for(int i=0; i Date: Fri, 16 Apr 2021 14:57:41 +0200 Subject: [PATCH 83/87] Updating version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0089e22..d560460 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 javax.visrec visrec-api - 1.0.2-SNAPSHOT + 1.0.3-SNAPSHOT jar javax.visrec:visrec-api From 307f2742f0006ef439939640dbe448e8154a4f29 Mon Sep 17 00:00:00 2001 From: deepnetts Date: Tue, 11 May 2021 19:28:10 +0200 Subject: [PATCH 84/87] target column names fix --- pom.xml | 2 +- src/main/java/javax/visrec/ml/data/BasicDataSet.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index d560460..5217df4 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 javax.visrec visrec-api - 1.0.3-SNAPSHOT + 1.0.4-SNAPSHOT jar javax.visrec:visrec-api diff --git a/src/main/java/javax/visrec/ml/data/BasicDataSet.java b/src/main/java/javax/visrec/ml/data/BasicDataSet.java index 951dce4..e74cb9f 100644 --- a/src/main/java/javax/visrec/ml/data/BasicDataSet.java +++ b/src/main/java/javax/visrec/ml/data/BasicDataSet.java @@ -21,7 +21,7 @@ public class BasicDataSet implements DataSet { /** * List of data set columns. Each column provides info about it's name, type. */ - private List columns = new ArrayList(); + private List columns = new ArrayList<>(); protected BasicDataSet() { items = new ArrayList<>(); @@ -94,6 +94,7 @@ public void setAsTargetColumns(String... targetColNames) { }); } + @Override public String[] getTargetColumnsNames() { List targetLabels = columns.stream() .filter((col) -> col.isTarget()) From 4f16b35e434a2d5dd86f65be4ebef2c074c51189 Mon Sep 17 00:00:00 2001 From: kevto Date: Tue, 6 Jul 2021 19:21:29 +0200 Subject: [PATCH 85/87] Fixing bug with input class in ModelBuilder.build(Map) --- pom.xml | 2 +- src/main/java/javax/visrec/ml/model/ModelBuilder.java | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 5217df4..5f89a6a 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 javax.visrec visrec-api - 1.0.4-SNAPSHOT + 1.0.5-SNAPSHOT jar javax.visrec:visrec-api diff --git a/src/main/java/javax/visrec/ml/model/ModelBuilder.java b/src/main/java/javax/visrec/ml/model/ModelBuilder.java index 3758084..bca835a 100644 --- a/src/main/java/javax/visrec/ml/model/ModelBuilder.java +++ b/src/main/java/javax/visrec/ml/model/ModelBuilder.java @@ -28,18 +28,22 @@ public interface ModelBuilder { * @throws javax.visrec.ml.model.ModelCreationException */ default T build(Map configuration) throws ModelCreationException { + ModelBuilder thizz = this; Method[] methods = this.getClass().getDeclaredMethods(); for (Method method : methods) { if (!method.getName().equals("build") && method.getParameterCount() == 1 && configuration.containsKey(method.getName())) { try { - method.invoke(this, configuration.get(method.getName())); + Object obj = method.invoke(thizz, configuration.get(method.getName())); + if (thizz.getClass().isInstance(obj)) { + thizz = (ModelBuilder) thizz.getClass().cast(obj); + } } catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException e) { throw new InvalidConfigurationException("Couldn't invoke '" + method.getName() + "'", e); } } } - return build(); + return thizz.build(); } } From 1718671b7acd9ac6b02da8e61461ca4911157db6 Mon Sep 17 00:00:00 2001 From: Deep Netts Date: Mon, 22 Nov 2021 17:38:09 +0100 Subject: [PATCH 86/87] Update LICENSE.md --- LICENSE.md | 560 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 357 insertions(+), 203 deletions(-) diff --git a/LICENSE.md b/LICENSE.md index f8512ad..ef23593 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,203 +1,357 @@ -Copyright 2019 The VisRec Expert Group, Contributors and Advisors. All rights reserved. - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed 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. + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. + + +CLASSPATH" EXCEPTION TO THE GPL + +Linking this library statically or dynamically with other modules is making +a combined work based on this library. Thus, the terms and conditions of +the GNU General Public License cover the whole combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your +choice, provided that you also meet, for each linked independent module, +the terms and conditions of the license of that module. An independent +module is a module which is not derived from or based on this library. If +you modify this library, you may extend this exception to your version of +the library, but you are not obligated to do so. If you do not wish to do +so, delete this exception statement from your version. From 1b06cb6d2ab42bd215cd45373415582b6c7bee57 Mon Sep 17 00:00:00 2001 From: deepnetts Date: Thu, 2 Dec 2021 13:15:04 +0100 Subject: [PATCH 87/87] Added GPL header to all files --- src/main/java/javax/visrec/ImageFactory.java | 19 + .../AbstractMultiClassClassifier.java | 69 ++-- .../ml/classification/BinaryClassifier.java | 37 +- .../ml/classification/Classifiable.java | 21 +- .../ClassificationException.java | 77 ++-- .../visrec/ml/classification/Classifier.java | 19 + .../ml/classification/EnsambleClassifier.java | 19 + .../ml/classification/ImageClassifier.java | 87 ++-- .../ml/classification/LogisticRegression.java | 71 ++-- .../classification/MultiClassClassifier.java | 19 + .../NeuralNetBinaryClassifier.java | 291 +++++++------- .../NeuralNetImageClassifier.java | 379 +++++++++--------- .../javax/visrec/ml/data/BasicDataSet.java | 19 + .../java/javax/visrec/ml/data/Column.java | 139 ++++--- .../java/javax/visrec/ml/data/DataSet.java | 19 + .../visrec/ml/data/preprocessing/Scaler.java | 19 + .../visrec/ml/detection/BoundingBox.java | 19 + .../visrec/ml/detection/ObjectDetector.java | 19 + .../visrec/ml/eval/ClassificationMetrics.java | 121 +++--- .../visrec/ml/eval/EvaluationMetrics.java | 34 +- .../java/javax/visrec/ml/eval/Evaluator.java | 36 +- .../visrec/ml/eval/RegressionMetrics.java | 90 +++-- .../model/InvalidConfigurationException.java | 49 ++- .../javax/visrec/ml/model/ModelBuilder.java | 19 + .../ml/model/ModelCreationException.java | 73 ++-- .../javax/visrec/ml/model/ModelProvider.java | 19 + .../javax/visrec/ml/regression/Regressor.java | 19 + .../ml/regression/SimpleLinearRegression.java | 115 +++--- .../visrec/spi/BinaryClassifierFactory.java | 45 ++- .../visrec/spi/ClassifierFactoryService.java | 19 + .../visrec/spi/ImageClassifierFactory.java | 45 ++- .../javax/visrec/spi/ImageFactoryService.java | 19 + .../visrec/spi/ImplementationService.java | 79 ++-- .../javax/visrec/spi/ServiceProvider.java | 19 + .../javax/visrec/spi/ServiceRegistry.java | 32 +- 35 files changed, 1392 insertions(+), 783 deletions(-) diff --git a/src/main/java/javax/visrec/ImageFactory.java b/src/main/java/javax/visrec/ImageFactory.java index 1d07a4c..336fb53 100644 --- a/src/main/java/javax/visrec/ImageFactory.java +++ b/src/main/java/javax/visrec/ImageFactory.java @@ -1,3 +1,22 @@ +/** + * Visual Recognition API for Java, JSR381 + * Copyright (C) 2020 Zoran Sevarac, Frank Greco + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + package javax.visrec; import java.io.IOException; diff --git a/src/main/java/javax/visrec/ml/classification/AbstractMultiClassClassifier.java b/src/main/java/javax/visrec/ml/classification/AbstractMultiClassClassifier.java index e8a1920..748540e 100644 --- a/src/main/java/javax/visrec/ml/classification/AbstractMultiClassClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/AbstractMultiClassClassifier.java @@ -1,25 +1,44 @@ -package javax.visrec.ml.classification; - -import javax.visrec.ml.model.ModelProvider; - -/** - * Skeleton base class for implementations of multi class classifiers. - * - * @param class of machine learning model back-end - * @param type of classifier's input - * @param type of classifier's results/class - */ -public abstract class AbstractMultiClassClassifier implements MultiClassClassifier, ModelProvider { - - private MODEL_CLASS model; - - @Override - public MODEL_CLASS getModel() { - return model; - } - - protected void setModel(MODEL_CLASS model) { - this.model = model; - } - -} +/** + * Visual Recognition API for Java, JSR381 + * Copyright (C) 2020 Zoran Sevarac, Frank Greco + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +package javax.visrec.ml.classification; + +import javax.visrec.ml.model.ModelProvider; + +/** + * Skeleton base class for implementations of multi class classifiers. + * + * @param class of machine learning model back-end + * @param type of classifier's input + * @param type of classifier's results/class + */ +public abstract class AbstractMultiClassClassifier implements MultiClassClassifier, ModelProvider { + + private MODEL_CLASS model; + + @Override + public MODEL_CLASS getModel() { + return model; + } + + protected void setModel(MODEL_CLASS model) { + this.model = model; + } + +} diff --git a/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java b/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java index 96c0847..7b93c2c 100644 --- a/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java @@ -1,10 +1,29 @@ -package javax.visrec.ml.classification; - -/** - * Binary classifier classifies input object into one of two possible categories - * (for example: true/false, yes/no, red/blue, positive/negative, spam/not-spam, fraud/not-fraud). - * Returns a probability (float value [0..1]) that input object belongs to the positive class. - */ -public interface BinaryClassifier extends Classifier { - +/** + * Visual Recognition API for Java, JSR381 + * Copyright (C) 2020 Zoran Sevarac, Frank Greco + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +package javax.visrec.ml.classification; + +/** + * Binary classifier classifies input object into one of two possible categories + * (for example: true/false, yes/no, red/blue, positive/negative, spam/not-spam, fraud/not-fraud). + * Returns a probability (float value [0..1]) that input object belongs to the positive class. + */ +public interface BinaryClassifier extends Classifier { + } \ No newline at end of file diff --git a/src/main/java/javax/visrec/ml/classification/Classifiable.java b/src/main/java/javax/visrec/ml/classification/Classifiable.java index 846e3ae..a11b5c8 100644 --- a/src/main/java/javax/visrec/ml/classification/Classifiable.java +++ b/src/main/java/javax/visrec/ml/classification/Classifiable.java @@ -1,3 +1,22 @@ +/** + * Visual Recognition API for Java, JSR381 + * Copyright (C) 2020 Zoran Sevarac, Frank Greco + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + package javax.visrec.ml.classification; /** @@ -10,7 +29,7 @@ * to build machine learning based classifiers. * Typical implementation scenario is to wrap domain specific class and implement this interface. * - * Classifiable can be classfied by the Classifier (with the same T and C) + * Classifiable can be classified by the Classifier (with the same T and C) * * @param Type of input for classifier * @param Type of categories/labels (could be anything like enum, String, Integer or user defined class) diff --git a/src/main/java/javax/visrec/ml/classification/ClassificationException.java b/src/main/java/javax/visrec/ml/classification/ClassificationException.java index f312e19..3d1067c 100644 --- a/src/main/java/javax/visrec/ml/classification/ClassificationException.java +++ b/src/main/java/javax/visrec/ml/classification/ClassificationException.java @@ -1,29 +1,48 @@ -package javax.visrec.ml.classification; - -/** - * Exception thrown if anything fails in the execution of a classifier. - * - * @since 1.0 - */ -public class ClassificationException extends RuntimeException { - - /** - * Creates a new instance of the exception - * - * @param message additional message of the cause. - */ - public ClassificationException(String message) { - super(message); - } - - /** - * Creates a new instance of the exception - * - * @param message additional message of the cause. - * @param throwable caused by throwable. - */ - public ClassificationException(String message, Throwable throwable) { - super(message, throwable); - } - -} +/** + * Visual Recognition API for Java, JSR381 + * Copyright (C) 2020 Zoran Sevarac, Frank Greco + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +package javax.visrec.ml.classification; + +/** + * Exception thrown if anything fails in the execution of a classifier. + * + * @since 1.0 + */ +public class ClassificationException extends RuntimeException { + + /** + * Creates a new instance of the exception + * + * @param message additional message of the cause. + */ + public ClassificationException(String message) { + super(message); + } + + /** + * Creates a new instance of the exception + * + * @param message additional message of the cause. + * @param throwable caused by throwable. + */ + public ClassificationException(String message, Throwable throwable) { + super(message, throwable); + } + +} diff --git a/src/main/java/javax/visrec/ml/classification/Classifier.java b/src/main/java/javax/visrec/ml/classification/Classifier.java index 634b15d..c0a97ea 100644 --- a/src/main/java/javax/visrec/ml/classification/Classifier.java +++ b/src/main/java/javax/visrec/ml/classification/Classifier.java @@ -1,3 +1,22 @@ +/** + * Visual Recognition API for Java, JSR381 + * Copyright (C) 2020 Zoran Sevarac, Frank Greco + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + package javax.visrec.ml.classification; /** diff --git a/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java b/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java index 8ae983c..f0b94d6 100644 --- a/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java @@ -1,3 +1,22 @@ +/** + * Visual Recognition API for Java, JSR381 + * Copyright (C) 2020 Zoran Sevarac, Frank Greco + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + package javax.visrec.ml.classification; import java.util.ArrayList; diff --git a/src/main/java/javax/visrec/ml/classification/ImageClassifier.java b/src/main/java/javax/visrec/ml/classification/ImageClassifier.java index d8d2271..0aa4aae 100644 --- a/src/main/java/javax/visrec/ml/classification/ImageClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/ImageClassifier.java @@ -1,34 +1,53 @@ -package javax.visrec.ml.classification; - - -import java.io.InputStream; -import java.nio.file.Path; -import java.util.Map; - -/** - * Classifier interface specialized in image classification - * - * @param type of input objects to classify (eg. User, Product, Transaction, Image, etc.) - * @since 1.0 - */ -public interface ImageClassifier extends Classifier> { - - /** - * Classify the input and get a map of classification results as output - * - * @param input {@link Path} to use as input - * @return {@code Map} with key as classification label and with value as accuracy percentage of likelihood - * @throws ClassificationException if the file couldn't be found or classified - */ - Map classify(Path input) throws ClassificationException; - - /** - * Classify the input and get a map of classification results as output - * - * @param input {@link InputStream} to use as input - * @return {@code Map} with key as classification label and with value as accuracy percentage of likelihood - * @throws ClassificationException if input couldn't be classified - */ - Map classify(InputStream input) throws ClassificationException; - -} +/** + * Visual Recognition API for Java, JSR381 + * Copyright (C) 2020 Zoran Sevarac, Frank Greco + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +package javax.visrec.ml.classification; + + +import java.io.InputStream; +import java.nio.file.Path; +import java.util.Map; + +/** + * Classifier interface specialized in image classification + * + * @param type of input objects to classify (eg. User, Product, Transaction, Image, etc.) + * @since 1.0 + */ +public interface ImageClassifier extends Classifier> { + + /** + * Classify the input and get a map of classification results as output + * + * @param input {@link Path} to use as input + * @return {@code Map} with key as classification label and with value as accuracy percentage of likelihood + * @throws ClassificationException if the file couldn't be found or classified + */ + Map classify(Path input) throws ClassificationException; + + /** + * Classify the input and get a map of classification results as output + * + * @param input {@link InputStream} to use as input + * @return {@code Map} with key as classification label and with value as accuracy percentage of likelihood + * @throws ClassificationException if input couldn't be classified + */ + Map classify(InputStream input) throws ClassificationException; + +} diff --git a/src/main/java/javax/visrec/ml/classification/LogisticRegression.java b/src/main/java/javax/visrec/ml/classification/LogisticRegression.java index dafc4ef..8ffe52b 100644 --- a/src/main/java/javax/visrec/ml/classification/LogisticRegression.java +++ b/src/main/java/javax/visrec/ml/classification/LogisticRegression.java @@ -1,26 +1,45 @@ -package javax.visrec.ml.classification; - -import java.util.Objects; -import javax.visrec.ml.model.ModelProvider; - -/** - * This class performs basic binary classification - mapping of specified input to true/false with probability - * using logistic regression algorithm. - * Subclasses should use specific logistic regression implementation to provide that functionality. - * - * @param Implementation class of underlying machine learning model - */ -public abstract class LogisticRegression implements BinaryClassifier, ModelProvider { - - private MODEL_CLASS model; - - @Override - public MODEL_CLASS getModel() { - return model; - } - - protected final void setModel(MODEL_CLASS model) { - this.model = Objects.requireNonNull(model, "Model cannot be null!"); - } - -} +/** + * Visual Recognition API for Java, JSR381 + * Copyright (C) 2020 Zoran Sevarac, Frank Greco + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +package javax.visrec.ml.classification; + +import java.util.Objects; +import javax.visrec.ml.model.ModelProvider; + +/** + * This class performs basic binary classification - mapping of specified input to true/false with probability + * using logistic regression algorithm. + * Subclasses should use specific logistic regression implementation to provide that functionality. + * + * @param Implementation class of underlying machine learning model + */ +public abstract class LogisticRegression implements BinaryClassifier, ModelProvider { + + private MODEL_CLASS model; + + @Override + public MODEL_CLASS getModel() { + return model; + } + + protected final void setModel(MODEL_CLASS model) { + this.model = Objects.requireNonNull(model, "Model cannot be null!"); + } + +} diff --git a/src/main/java/javax/visrec/ml/classification/MultiClassClassifier.java b/src/main/java/javax/visrec/ml/classification/MultiClassClassifier.java index 915a498..e310fc2 100644 --- a/src/main/java/javax/visrec/ml/classification/MultiClassClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/MultiClassClassifier.java @@ -1,3 +1,22 @@ +/** + * Visual Recognition API for Java, JSR381 + * Copyright (C) 2020 Zoran Sevarac, Frank Greco + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + package javax.visrec.ml.classification; import java.util.Map; diff --git a/src/main/java/javax/visrec/ml/classification/NeuralNetBinaryClassifier.java b/src/main/java/javax/visrec/ml/classification/NeuralNetBinaryClassifier.java index 3840f9a..c13eff6 100644 --- a/src/main/java/javax/visrec/ml/classification/NeuralNetBinaryClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/NeuralNetBinaryClassifier.java @@ -1,136 +1,155 @@ -package javax.visrec.ml.classification; - -import javax.visrec.ml.model.ModelCreationException; -import javax.visrec.spi.ServiceProvider; -import java.nio.file.Path; - -public interface NeuralNetBinaryClassifier extends BinaryClassifier { - - static NeuralNetBinaryClassifier.Builder builder() { - return new NeuralNetBinaryClassifier.Builder<>(); - } - - class BuildingBlock { - private Class inputCls; - private int inputsNum; - private int[] hiddenLayers; - private float maxError; - private int maxEpochs; - private float learningRate; - private Path trainingPath; - private float threshold; - - private BuildingBlock() { - } - - public Class getInputClass() { - return inputCls; - } - - public int getInputsNum() { - return inputsNum; - } - - public int[] getHiddenLayers() { - return hiddenLayers; - } - - public float getMaxError() { - return maxError; - } - - public int getMaxEpochs() { - return maxEpochs; - } - - public float getLearningRate() { - return learningRate; - } - - public Path getTrainingPath() { - return trainingPath; - } - - public float getThreshold() { - return threshold; - } - - - - private static BuildingBlock copyWithNewTargetClass(BuildingBlock block, Class cls) { - BuildingBlock newBlock = new BuildingBlock<>(); - newBlock.inputCls = cls; - newBlock.inputsNum = block.inputsNum; - newBlock.hiddenLayers = block.hiddenLayers; - newBlock.maxError = block.maxError; - newBlock.maxEpochs = block.maxEpochs; - newBlock.learningRate = block.learningRate; - newBlock.trainingPath = block.trainingPath; - newBlock.threshold = block.threshold; - return newBlock; - } - } - - class Builder implements javax.visrec.ml.model.ModelBuilder> { - - private NeuralNetBinaryClassifier.BuildingBlock block; - - private Builder() { - this(new NeuralNetBinaryClassifier.BuildingBlock<>()); - } - - private Builder(BuildingBlock block) { - this.block = block; - } - - public Builder inputClass(Class cls) { - BuildingBlock newBlock = BuildingBlock.copyWithNewTargetClass(block, cls); - return new Builder<>(newBlock); - } - - public Builder inputsNum(int inputsNum) { - block.inputsNum = inputsNum; - return this; - } - - public Builder hiddenLayers(int... hiddenLayers) { - block.hiddenLayers = hiddenLayers; - return this; - } - - public Builder maxError(float maxError) { - block.maxError = maxError; - return this; - } - - public Builder maxEpochs(int maxEpochs) { - block.maxEpochs = maxEpochs; - return this; - } - - public Builder learningRate(float learningRate) { - block.learningRate = learningRate; - return this; - } - - public Builder trainingPath(Path trainingPath) { - block.trainingPath = trainingPath; - return this; - } - - public Builder threshold(float threshold) { - block.threshold = threshold; - return this; - } - - - - public NeuralNetBinaryClassifier.BuildingBlock getBuildingBlock() { - return block; - } - - public BinaryClassifier build() throws ModelCreationException { - return ServiceProvider.current().getClassifierFactoryService().createNeuralNetBinaryClassifier(block); - } - } -} +/** + * Visual Recognition API for Java, JSR381 + * Copyright (C) 2020 Zoran Sevarac, Frank Greco + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +package javax.visrec.ml.classification; + +import javax.visrec.ml.model.ModelCreationException; +import javax.visrec.spi.ServiceProvider; +import java.nio.file.Path; + +public interface NeuralNetBinaryClassifier extends BinaryClassifier { + + static NeuralNetBinaryClassifier.Builder builder() { + return new NeuralNetBinaryClassifier.Builder<>(); + } + + class BuildingBlock { + private Class inputCls; + private int inputsNum; + private int[] hiddenLayers; + private float maxError; + private int maxEpochs; + private float learningRate; + private Path trainingPath; + private float threshold; + + private BuildingBlock() { + } + + public Class getInputClass() { + return inputCls; + } + + public int getInputsNum() { + return inputsNum; + } + + public int[] getHiddenLayers() { + return hiddenLayers; + } + + public float getMaxError() { + return maxError; + } + + public int getMaxEpochs() { + return maxEpochs; + } + + public float getLearningRate() { + return learningRate; + } + + public Path getTrainingPath() { + return trainingPath; + } + + public float getThreshold() { + return threshold; + } + + + + private static BuildingBlock copyWithNewTargetClass(BuildingBlock block, Class cls) { + BuildingBlock newBlock = new BuildingBlock<>(); + newBlock.inputCls = cls; + newBlock.inputsNum = block.inputsNum; + newBlock.hiddenLayers = block.hiddenLayers; + newBlock.maxError = block.maxError; + newBlock.maxEpochs = block.maxEpochs; + newBlock.learningRate = block.learningRate; + newBlock.trainingPath = block.trainingPath; + newBlock.threshold = block.threshold; + return newBlock; + } + } + + class Builder implements javax.visrec.ml.model.ModelBuilder> { + + private NeuralNetBinaryClassifier.BuildingBlock block; + + private Builder() { + this(new NeuralNetBinaryClassifier.BuildingBlock<>()); + } + + private Builder(BuildingBlock block) { + this.block = block; + } + + public Builder inputClass(Class cls) { + BuildingBlock newBlock = BuildingBlock.copyWithNewTargetClass(block, cls); + return new Builder<>(newBlock); + } + + public Builder inputsNum(int inputsNum) { + block.inputsNum = inputsNum; + return this; + } + + public Builder hiddenLayers(int... hiddenLayers) { + block.hiddenLayers = hiddenLayers; + return this; + } + + public Builder maxError(float maxError) { + block.maxError = maxError; + return this; + } + + public Builder maxEpochs(int maxEpochs) { + block.maxEpochs = maxEpochs; + return this; + } + + public Builder learningRate(float learningRate) { + block.learningRate = learningRate; + return this; + } + + public Builder trainingPath(Path trainingPath) { + block.trainingPath = trainingPath; + return this; + } + + public Builder threshold(float threshold) { + block.threshold = threshold; + return this; + } + + + + public NeuralNetBinaryClassifier.BuildingBlock getBuildingBlock() { + return block; + } + + public BinaryClassifier build() throws ModelCreationException { + return ServiceProvider.current().getClassifierFactoryService().createNeuralNetBinaryClassifier(block); + } + } +} diff --git a/src/main/java/javax/visrec/ml/classification/NeuralNetImageClassifier.java b/src/main/java/javax/visrec/ml/classification/NeuralNetImageClassifier.java index c612f5f..2dd0b70 100644 --- a/src/main/java/javax/visrec/ml/classification/NeuralNetImageClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/NeuralNetImageClassifier.java @@ -1,180 +1,199 @@ -package javax.visrec.ml.classification; - -import javax.visrec.ml.model.ModelCreationException; -import javax.visrec.spi.ServiceProvider; -import java.nio.file.Path; - -public interface NeuralNetImageClassifier extends ImageClassifier { - - static NeuralNetImageClassifier.Builder builder() { - return new Builder<>(); - } - - class BuildingBlock { - - private int imageWidth; - private int imageHeight; - private Path networkArchitecture; - private Path trainingPath; - private Path labelsFile; - private float maxError; - private float learningRate; - private Path exportPath; - private Path importPath; - private int maxEpochs; - private float threshold; - private Class inputCls; - - private BuildingBlock() { - } - - public Path getNetworkArchitecture() { - return networkArchitecture; - } - - public int getImageWidth() { - return imageWidth; - } - - public int getImageHeight() { - return imageHeight; - } - - public Path getTrainingPath() { - return trainingPath; - } - - public Path getLabelsPath() { - return labelsFile; - } - - public float getMaxError() { - return maxError; - } - - public float getLearningRate() { - return learningRate; - } - - public Path getExportPath() { - return exportPath; - } - - public Path getImportPath() { - return importPath; - } - - - public int getMaxEpochs() { - return maxEpochs; - } - - public float getThreshold() { - return threshold; - } - - - - public Class getInputClass() { - return inputCls; - } - - private static BuildingBlock copyWithNewInputClass(BuildingBlock block, Class cls) { - BuildingBlock newBlock = new BuildingBlock<>(); - newBlock.inputCls = cls; - newBlock.imageHeight = block.imageHeight; - newBlock.imageWidth = block.imageWidth; - newBlock.labelsFile = block.labelsFile; - newBlock.exportPath = block.exportPath; - newBlock.importPath = block.importPath; - newBlock.networkArchitecture = block.networkArchitecture; - newBlock.maxError = block.maxError; - newBlock.maxEpochs = block.maxEpochs; - newBlock.learningRate = block.learningRate; - newBlock.trainingPath = block.trainingPath; - newBlock.threshold = block.threshold; - return newBlock; - } - } - - class Builder implements javax.visrec.ml.model.ModelBuilder> { - - private BuildingBlock block; - - private Builder() { - block = new BuildingBlock<>(); - } - - private Builder(BuildingBlock block) { - this.block = block; - } - - public Builder inputClass(Class cls) { - BuildingBlock newBlock = BuildingBlock.copyWithNewInputClass(block, cls); - return new Builder<>(newBlock); - } - - public Builder imageWidth(int imageWidth) { - block.imageWidth = imageWidth; - return this; - } - - public Builder imageHeight(int imageHeight) { - block.imageHeight = imageHeight; - return this; - } - - public Builder trainingFile(Path trainingFile) { - block.trainingPath = trainingFile; - return this; - } - - public Builder labelsFile(Path labelsFile) { - block.labelsFile = labelsFile; - return this; - } - - public Builder maxError(float maxError) { - block.maxError = maxError; - return this; - } - - public Builder maxEpochs(int epochs) { - block.maxEpochs = epochs; - return this; - } - - public Builder learningRate(float learningRate) { - block.learningRate = learningRate; - return this; - } - - public Builder threshold(float threshold) { - block.threshold = threshold; - return this; - } - - public Builder exportModel(Path path) { - block.exportPath = path; - return this; - } - - public Builder importModel(Path path) { - block.importPath = path; - return this; - } - - public Builder networkArchitecture(Path architecture) { - block.networkArchitecture = architecture; - return this; - } - - public BuildingBlock getBuildingBlock() { - return block; - } - - public ImageClassifier build() throws ModelCreationException { - return ServiceProvider.current().getClassifierFactoryService().createNeuralNetImageClassifier(block); - } - } -} +/** + * Visual Recognition API for Java, JSR381 + * Copyright (C) 2020 Zoran Sevarac, Frank Greco + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +package javax.visrec.ml.classification; + +import javax.visrec.ml.model.ModelCreationException; +import javax.visrec.spi.ServiceProvider; +import java.nio.file.Path; + +public interface NeuralNetImageClassifier extends ImageClassifier { + + static NeuralNetImageClassifier.Builder builder() { + return new Builder<>(); + } + + class BuildingBlock { + + private int imageWidth; + private int imageHeight; + private Path networkArchitecture; + private Path trainingPath; + private Path labelsFile; + private float maxError; + private float learningRate; + private Path exportPath; + private Path importPath; + private int maxEpochs; + private float threshold; + private Class inputCls; + + private BuildingBlock() { + } + + public Path getNetworkArchitecture() { + return networkArchitecture; + } + + public int getImageWidth() { + return imageWidth; + } + + public int getImageHeight() { + return imageHeight; + } + + public Path getTrainingPath() { + return trainingPath; + } + + public Path getLabelsPath() { + return labelsFile; + } + + public float getMaxError() { + return maxError; + } + + public float getLearningRate() { + return learningRate; + } + + public Path getExportPath() { + return exportPath; + } + + public Path getImportPath() { + return importPath; + } + + + public int getMaxEpochs() { + return maxEpochs; + } + + public float getThreshold() { + return threshold; + } + + + + public Class getInputClass() { + return inputCls; + } + + private static BuildingBlock copyWithNewInputClass(BuildingBlock block, Class cls) { + BuildingBlock newBlock = new BuildingBlock<>(); + newBlock.inputCls = cls; + newBlock.imageHeight = block.imageHeight; + newBlock.imageWidth = block.imageWidth; + newBlock.labelsFile = block.labelsFile; + newBlock.exportPath = block.exportPath; + newBlock.importPath = block.importPath; + newBlock.networkArchitecture = block.networkArchitecture; + newBlock.maxError = block.maxError; + newBlock.maxEpochs = block.maxEpochs; + newBlock.learningRate = block.learningRate; + newBlock.trainingPath = block.trainingPath; + newBlock.threshold = block.threshold; + return newBlock; + } + } + + class Builder implements javax.visrec.ml.model.ModelBuilder> { + + private BuildingBlock block; + + private Builder() { + block = new BuildingBlock<>(); + } + + private Builder(BuildingBlock block) { + this.block = block; + } + + public Builder inputClass(Class cls) { + BuildingBlock newBlock = BuildingBlock.copyWithNewInputClass(block, cls); + return new Builder<>(newBlock); + } + + public Builder imageWidth(int imageWidth) { + block.imageWidth = imageWidth; + return this; + } + + public Builder imageHeight(int imageHeight) { + block.imageHeight = imageHeight; + return this; + } + + public Builder trainingFile(Path trainingFile) { + block.trainingPath = trainingFile; + return this; + } + + public Builder labelsFile(Path labelsFile) { + block.labelsFile = labelsFile; + return this; + } + + public Builder maxError(float maxError) { + block.maxError = maxError; + return this; + } + + public Builder maxEpochs(int epochs) { + block.maxEpochs = epochs; + return this; + } + + public Builder learningRate(float learningRate) { + block.learningRate = learningRate; + return this; + } + + public Builder threshold(float threshold) { + block.threshold = threshold; + return this; + } + + public Builder exportModel(Path path) { + block.exportPath = path; + return this; + } + + public Builder importModel(Path path) { + block.importPath = path; + return this; + } + + public Builder networkArchitecture(Path architecture) { + block.networkArchitecture = architecture; + return this; + } + + public BuildingBlock getBuildingBlock() { + return block; + } + + public ImageClassifier build() throws ModelCreationException { + return ServiceProvider.current().getClassifierFactoryService().createNeuralNetImageClassifier(block); + } + } +} diff --git a/src/main/java/javax/visrec/ml/data/BasicDataSet.java b/src/main/java/javax/visrec/ml/data/BasicDataSet.java index e74cb9f..652e8d1 100644 --- a/src/main/java/javax/visrec/ml/data/BasicDataSet.java +++ b/src/main/java/javax/visrec/ml/data/BasicDataSet.java @@ -1,3 +1,22 @@ +/** + * Visual Recognition API for Java, JSR381 + * Copyright (C) 2020 Zoran Sevarac, Frank Greco + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + package javax.visrec.ml.data; import java.util.ArrayList; diff --git a/src/main/java/javax/visrec/ml/data/Column.java b/src/main/java/javax/visrec/ml/data/Column.java index 6e927cd..220b310 100644 --- a/src/main/java/javax/visrec/ml/data/Column.java +++ b/src/main/java/javax/visrec/ml/data/Column.java @@ -1,61 +1,80 @@ -package javax.visrec.ml.data; - -/** - * Column in a data set. - * - * @see DataSet - */ - public class Column { - private String name; - private Type type; - private boolean isTarget; - - public Column(String name) { - this.name = name; - this.type = null; - this.isTarget = false; - } - - public Column(String name, Type type) { - this.name = name; - this.type = type; - this.isTarget = false; - } - - public Column(String name, Type type, boolean isTarget) { - this.name = name; - this.type = type; - this.isTarget = isTarget; - } - - public String getName() { - return name; - } - - public Type getType() { - return type; - } - - public boolean isTarget() { - return isTarget; - } - - public void setName(String name) { - this.name = name; - } - - public void setType(Type type) { - this.type = type; - } - - public void setAsTarget(boolean isTarget) { - this.isTarget = isTarget; - } - - /** - * Column data type - */ - public static enum Type { - DECIMAL, INTEGER, BINARY, ENUM, STRING; - } +/** + * Visual Recognition API for Java, JSR381 + * Copyright (C) 2020 Zoran Sevarac, Frank Greco + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +package javax.visrec.ml.data; + +/** + * Column in a data set. + * + * @see DataSet + */ + public class Column { + private String name; + private Type type; + private boolean isTarget; + + public Column(String name) { + this.name = name; + this.type = null; + this.isTarget = false; + } + + public Column(String name, Type type) { + this.name = name; + this.type = type; + this.isTarget = false; + } + + public Column(String name, Type type, boolean isTarget) { + this.name = name; + this.type = type; + this.isTarget = isTarget; + } + + public String getName() { + return name; + } + + public Type getType() { + return type; + } + + public boolean isTarget() { + return isTarget; + } + + public void setName(String name) { + this.name = name; + } + + public void setType(Type type) { + this.type = type; + } + + public void setAsTarget(boolean isTarget) { + this.isTarget = isTarget; + } + + /** + * Column data type + */ + public static enum Type { + DECIMAL, INTEGER, BINARY, ENUM, STRING; + } } \ No newline at end of file diff --git a/src/main/java/javax/visrec/ml/data/DataSet.java b/src/main/java/javax/visrec/ml/data/DataSet.java index 194a499..99a4549 100644 --- a/src/main/java/javax/visrec/ml/data/DataSet.java +++ b/src/main/java/javax/visrec/ml/data/DataSet.java @@ -1,3 +1,22 @@ +/** + * Visual Recognition API for Java, JSR381 + * Copyright (C) 2020 Zoran Sevarac, Frank Greco + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + package javax.visrec.ml.data; import java.util.Collection; diff --git a/src/main/java/javax/visrec/ml/data/preprocessing/Scaler.java b/src/main/java/javax/visrec/ml/data/preprocessing/Scaler.java index 3dd58fc..4752816 100644 --- a/src/main/java/javax/visrec/ml/data/preprocessing/Scaler.java +++ b/src/main/java/javax/visrec/ml/data/preprocessing/Scaler.java @@ -1,3 +1,22 @@ +/** + * Visual Recognition API for Java, JSR381 + * Copyright (C) 2020 Zoran Sevarac, Frank Greco + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + package javax.visrec.ml.data.preprocessing; import javax.visrec.ml.data.DataSet; diff --git a/src/main/java/javax/visrec/ml/detection/BoundingBox.java b/src/main/java/javax/visrec/ml/detection/BoundingBox.java index 21b83af..00a98a5 100644 --- a/src/main/java/javax/visrec/ml/detection/BoundingBox.java +++ b/src/main/java/javax/visrec/ml/detection/BoundingBox.java @@ -1,3 +1,22 @@ +/** + * Visual Recognition API for Java, JSR381 + * Copyright (C) 2020 Zoran Sevarac, Frank Greco + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + package javax.visrec.ml.detection; /** diff --git a/src/main/java/javax/visrec/ml/detection/ObjectDetector.java b/src/main/java/javax/visrec/ml/detection/ObjectDetector.java index 8824b9f..6a48c6e 100644 --- a/src/main/java/javax/visrec/ml/detection/ObjectDetector.java +++ b/src/main/java/javax/visrec/ml/detection/ObjectDetector.java @@ -1,3 +1,22 @@ +/** + * Visual Recognition API for Java, JSR381 + * Copyright (C) 2020 Zoran Sevarac, Frank Greco + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + package javax.visrec.ml.detection; import java.util.List; diff --git a/src/main/java/javax/visrec/ml/eval/ClassificationMetrics.java b/src/main/java/javax/visrec/ml/eval/ClassificationMetrics.java index 3bd5b2f..630b13c 100644 --- a/src/main/java/javax/visrec/ml/eval/ClassificationMetrics.java +++ b/src/main/java/javax/visrec/ml/eval/ClassificationMetrics.java @@ -1,52 +1,71 @@ -package javax.visrec.ml.eval; - -/** - * Commonly used metrics to estimate how good machine learning model solves some classification task. - */ -public class ClassificationMetrics extends EvaluationMetrics { - - /** - * The percent of correct predictions of a classifier in total. - * Tells how often the classifier is correct for some given test set. - * Note that accuracy can be a misleading metric for imbalanced data sets. - * - * Formula: Accuracy = (TP+TN) / (TP+TN+FP+FN) - * - * @return classification accuracy metric - */ - public double getAccuracy() { - return get(ACCURACY); - } - - /** - * The percent of correct positive predictions. - * This metrics answers the question: when classifier gives positive prediction, how often is it correct? - * Formula: Precision = TP/(TP+FP) - * - * @return classification precision metric - */ - public double getPrecision() { - return get(PRECISION); - } - - /** - * The percent of the positive examples that were not recognized by the classifier. - * This metric answers the question: when it is actually positive class, how often does it give positive prediction - * Formula: Recall = TP / (TP+FN) - * - * @return classification recall - */ - public double getRecall() { - return get(RECALL); - } - - /** - * The mean/balance of the recall and precision metrics. - * - * @return classification f score - */ - public double getF1score() { - return get(F1SCORE); - } - +/** + * Visual Recognition API for Java, JSR381 + * Copyright (C) 2020 Zoran Sevarac, Frank Greco + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +package javax.visrec.ml.eval; + +/** + * Commonly used metrics to estimate how good machine learning model solves some classification task. + */ +public class ClassificationMetrics extends EvaluationMetrics { + + /** + * The percent of correct predictions of a classifier in total. + * Tells how often the classifier is correct for some given test set. + * Note that accuracy can be a misleading metric for imbalanced data sets. + * + * Formula: Accuracy = (TP+TN) / (TP+TN+FP+FN) + * + * @return classification accuracy metric + */ + public double getAccuracy() { + return get(ACCURACY); + } + + /** + * The percent of correct positive predictions. + * This metrics answers the question: when classifier gives positive prediction, how often is it correct? + * Formula: Precision = TP/(TP+FP) + * + * @return classification precision metric + */ + public double getPrecision() { + return get(PRECISION); + } + + /** + * The percent of the positive examples that were not recognized by the classifier. + * This metric answers the question: when it is actually positive class, how often does it give positive prediction + * Formula: Recall = TP / (TP+FN) + * + * @return classification recall + */ + public double getRecall() { + return get(RECALL); + } + + /** + * The mean/balance of the recall and precision metrics. + * + * @return classification f score + */ + public double getF1score() { + return get(F1SCORE); + } + } \ No newline at end of file diff --git a/src/main/java/javax/visrec/ml/eval/EvaluationMetrics.java b/src/main/java/javax/visrec/ml/eval/EvaluationMetrics.java index ea9c071..ee1a7a3 100644 --- a/src/main/java/javax/visrec/ml/eval/EvaluationMetrics.java +++ b/src/main/java/javax/visrec/ml/eval/EvaluationMetrics.java @@ -1,24 +1,22 @@ /** - * DeepNetts is pure Java Deep Learning Library with support for Backpropagation - * based learning and image recognition. - * - * Copyright (C) 2017 Zoran Sevarac - * - * This file is part of DeepNetts. - * - * DeepNetts is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later - * version. - * + * Visual Recognition API for Java, JSR381 + * Copyright (C) 2020 Zoran Sevarac, Frank Greco + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General - * Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see .package - * deepnetts.core; + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ + package javax.visrec.ml.eval; diff --git a/src/main/java/javax/visrec/ml/eval/Evaluator.java b/src/main/java/javax/visrec/ml/eval/Evaluator.java index 9f33415..a18bdb8 100644 --- a/src/main/java/javax/visrec/ml/eval/Evaluator.java +++ b/src/main/java/javax/visrec/ml/eval/Evaluator.java @@ -1,24 +1,22 @@ -/** - * DeepNetts is pure Java Deep Learning Library with support for Backpropagation - * based learning and image recognition. +/** + * Visual Recognition API for Java, JSR381 + * Copyright (C) 2020 Zoran Sevarac, Frank Greco * - * Copyright (C) 2017 Zoran Sevarac - * - * This file is part of DeepNetts. - * - * DeepNetts is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see .package deepnetts.core; + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ - + package javax.visrec.ml.eval; /** diff --git a/src/main/java/javax/visrec/ml/eval/RegressionMetrics.java b/src/main/java/javax/visrec/ml/eval/RegressionMetrics.java index bed3f56..2cd9618 100644 --- a/src/main/java/javax/visrec/ml/eval/RegressionMetrics.java +++ b/src/main/java/javax/visrec/ml/eval/RegressionMetrics.java @@ -1,35 +1,55 @@ -package javax.visrec.ml.eval; - -/** - * Commonly used metrics to estimate how good machine learning model solves some regression task. - * This class is typed wrapper for EvaluationMetrics which uses map to store metrics, - * and allows storing and accessing of custom metrics. - */ -public class RegressionMetrics extends EvaluationMetrics { - - /** - * Portion of variation explained. - * How much better is this than the average. - * @return - */ - public double getRSquared() { - return get(R_SQUARED); - } - - public double getResidualSquareSum() { - return get(RESIDUAL_SQUARE_SUM); - } - - public double getFstat() { - return get(F_STAT); - } - - public double getMeanSquaredError() { - return get(MEAN_SQUARED_ERROR); - } - - public double getResidualStandardError() { - return get(RESIDUAL_STANDARD_ERROR); - } - -} +/** + * Visual Recognition API for Java, JSR381 + * Copyright (C) 2020 Zoran Sevarac, Frank Greco + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + + +package javax.visrec.ml.eval; + +/** + * Commonly used metrics to estimate how good machine learning model solves some regression task. + * This class is typed wrapper for EvaluationMetrics which uses map to store metrics, + * and allows storing and accessing of custom metrics. + */ +public class RegressionMetrics extends EvaluationMetrics { + + /** + * Portion of variation explained. + * How much better is this than the average. + * @return + */ + public double getRSquared() { + return get(R_SQUARED); + } + + public double getResidualSquareSum() { + return get(RESIDUAL_SQUARE_SUM); + } + + public double getFstat() { + return get(F_STAT); + } + + public double getMeanSquaredError() { + return get(MEAN_SQUARED_ERROR); + } + + public double getResidualStandardError() { + return get(RESIDUAL_STANDARD_ERROR); + } + +} diff --git a/src/main/java/javax/visrec/ml/model/InvalidConfigurationException.java b/src/main/java/javax/visrec/ml/model/InvalidConfigurationException.java index b96ca38..2c195e1 100644 --- a/src/main/java/javax/visrec/ml/model/InvalidConfigurationException.java +++ b/src/main/java/javax/visrec/ml/model/InvalidConfigurationException.java @@ -1,15 +1,34 @@ -package javax.visrec.ml.model; - -/** - * The Builder is able to attempt to invoke setter methods of the implemented Builder interface. If the - * declared setter method can't be invoked it will throw this exception because the configuration - * doesn't match the method to invoke. - * - */ -public class InvalidConfigurationException extends ModelCreationException { - - InvalidConfigurationException(String msg, Throwable throwable) { - super(msg, throwable); - } - -} +/** + * Visual Recognition API for Java, JSR381 + * Copyright (C) 2020 Zoran Sevarac, Frank Greco + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +package javax.visrec.ml.model; + +/** + * The Builder is able to attempt to invoke setter methods of the implemented Builder interface. If the + * declared setter method can't be invoked it will throw this exception because the configuration + * doesn't match the method to invoke. + * + */ +public class InvalidConfigurationException extends ModelCreationException { + + InvalidConfigurationException(String msg, Throwable throwable) { + super(msg, throwable); + } + +} diff --git a/src/main/java/javax/visrec/ml/model/ModelBuilder.java b/src/main/java/javax/visrec/ml/model/ModelBuilder.java index bca835a..fa1c3f4 100644 --- a/src/main/java/javax/visrec/ml/model/ModelBuilder.java +++ b/src/main/java/javax/visrec/ml/model/ModelBuilder.java @@ -1,3 +1,22 @@ +/** + * Visual Recognition API for Java, JSR381 + * Copyright (C) 2020 Zoran Sevarac, Frank Greco + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + package javax.visrec.ml.model; import java.lang.reflect.InvocationTargetException; diff --git a/src/main/java/javax/visrec/ml/model/ModelCreationException.java b/src/main/java/javax/visrec/ml/model/ModelCreationException.java index ab16f68..3404c22 100644 --- a/src/main/java/javax/visrec/ml/model/ModelCreationException.java +++ b/src/main/java/javax/visrec/ml/model/ModelCreationException.java @@ -1,27 +1,46 @@ -package javax.visrec.ml.model; - -/** - * Exception thrown if anything fails in the creation of a classifier. - * - * @since 1.0 - */ -public class ModelCreationException extends Exception { - - /** - * Creates a new instance of the exception - * @param message additional message of the cause. - */ - public ModelCreationException(String message) { - super(message); - } - - /** - * Creates a new instance of the exception - * @param message additional message of the cause. - * @param throwable caused by throwable. - */ - public ModelCreationException(String message, Throwable throwable) { - super(message, throwable); - } - -} +/** + * Visual Recognition API for Java, JSR381 + * Copyright (C) 2020 Zoran Sevarac, Frank Greco + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +package javax.visrec.ml.model; + +/** + * Exception thrown if anything fails in the creation of a classifier. + * + * @since 1.0 + */ +public class ModelCreationException extends Exception { + + /** + * Creates a new instance of the exception + * @param message additional message of the cause. + */ + public ModelCreationException(String message) { + super(message); + } + + /** + * Creates a new instance of the exception + * @param message additional message of the cause. + * @param throwable caused by throwable. + */ + public ModelCreationException(String message, Throwable throwable) { + super(message, throwable); + } + +} diff --git a/src/main/java/javax/visrec/ml/model/ModelProvider.java b/src/main/java/javax/visrec/ml/model/ModelProvider.java index 3fb5440..7ee8184 100644 --- a/src/main/java/javax/visrec/ml/model/ModelProvider.java +++ b/src/main/java/javax/visrec/ml/model/ModelProvider.java @@ -1,3 +1,22 @@ +/** + * Visual Recognition API for Java, JSR381 + * Copyright (C) 2020 Zoran Sevarac, Frank Greco + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + package javax.visrec.ml.model; /** diff --git a/src/main/java/javax/visrec/ml/regression/Regressor.java b/src/main/java/javax/visrec/ml/regression/Regressor.java index 8ef2b52..c6a598b 100644 --- a/src/main/java/javax/visrec/ml/regression/Regressor.java +++ b/src/main/java/javax/visrec/ml/regression/Regressor.java @@ -1,3 +1,22 @@ +/** + * Visual Recognition API for Java, JSR381 + * Copyright (C) 2020 Zoran Sevarac, Frank Greco + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + package javax.visrec.ml.regression; /** diff --git a/src/main/java/javax/visrec/ml/regression/SimpleLinearRegression.java b/src/main/java/javax/visrec/ml/regression/SimpleLinearRegression.java index 77ea15d..2f14fd4 100644 --- a/src/main/java/javax/visrec/ml/regression/SimpleLinearRegression.java +++ b/src/main/java/javax/visrec/ml/regression/SimpleLinearRegression.java @@ -1,48 +1,67 @@ -package javax.visrec.ml.regression; - -import java.util.Objects; -import javax.visrec.ml.model.ModelProvider; - -/** - * Simple linear regression finds the best possible straight line that tries to roughly describe given training set. - * Mathematical formula for linear regression is: prediction = slope * x + intercept - * which is a formula for linear function (straight line) and that's where the names comes from. - * - * @param Implementation class of the background model - */ -public abstract class SimpleLinearRegression implements Regressor, ModelProvider { - - private MODEL_CLASS model; - - @Override - public MODEL_CLASS getModel() { - return model; - } - - protected final void setModel(MODEL_CLASS model) { - this.model = Objects.requireNonNull(model, "Model cannot bu null!"); - } - - @Override - public abstract Float predict(Float input); - - /** - * Slope parameter of the model tells how much on average output change when input changes by one. - * - * If it is zero there is no linear dependency between input and output, and data is probably scattered. - * If it is less then one output grows slower then input. - * If it is greater than one, then output is growing faster than input. - * If its negative, then output is lowering as input grows. - * - * @return slope of the line produced by linear regression. - */ - public abstract float getSlope(); - - /** - * Intercept tells us the value of prediction when input is zero. - * - * @return - */ - public abstract float getIntercept(); - -} +/** + * Visual Recognition API for Java, JSR381 + * Copyright (C) 2020 Zoran Sevarac, Frank Greco + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +package javax.visrec.ml.regression; + +import java.util.Objects; +import javax.visrec.ml.model.ModelProvider; + +/** + * Simple linear regression finds the best possible straight line that tries to roughly describe given training set. + * Mathematical formula for linear regression is: prediction = slope * x + intercept + * which is a formula for linear function (straight line) and that's where the names comes from. + * + * @param Implementation class of the background model + */ +public abstract class SimpleLinearRegression implements Regressor, ModelProvider { + + private MODEL_CLASS model; + + @Override + public MODEL_CLASS getModel() { + return model; + } + + protected final void setModel(MODEL_CLASS model) { + this.model = Objects.requireNonNull(model, "Model cannot bu null!"); + } + + @Override + public abstract Float predict(Float input); + + /** + * Slope parameter of the model tells how much on average output change when input changes by one. + * + * If it is zero there is no linear dependency between input and output, and data is probably scattered. + * If it is less then one output grows slower then input. + * If it is greater than one, then output is growing faster than input. + * If its negative, then output is lowering as input grows. + * + * @return slope of the line produced by linear regression. + */ + public abstract float getSlope(); + + /** + * Intercept tells us the value of prediction when input is zero. + * + * @return + */ + public abstract float getIntercept(); + +} diff --git a/src/main/java/javax/visrec/spi/BinaryClassifierFactory.java b/src/main/java/javax/visrec/spi/BinaryClassifierFactory.java index b1c9d26..a3d3b0c 100644 --- a/src/main/java/javax/visrec/spi/BinaryClassifierFactory.java +++ b/src/main/java/javax/visrec/spi/BinaryClassifierFactory.java @@ -1,13 +1,32 @@ -package javax.visrec.spi; - -import javax.visrec.ml.model.ModelCreationException; -import javax.visrec.ml.classification.BinaryClassifier; -import javax.visrec.ml.classification.NeuralNetBinaryClassifier; - -public interface BinaryClassifierFactory { - - Class getTargetClass(); - - BinaryClassifier create(NeuralNetBinaryClassifier.BuildingBlock block) throws ModelCreationException; - -} +/** + * Visual Recognition API for Java, JSR381 + * Copyright (C) 2020 Zoran Sevarac, Frank Greco + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +package javax.visrec.spi; + +import javax.visrec.ml.model.ModelCreationException; +import javax.visrec.ml.classification.BinaryClassifier; +import javax.visrec.ml.classification.NeuralNetBinaryClassifier; + +public interface BinaryClassifierFactory { + + Class getTargetClass(); + + BinaryClassifier create(NeuralNetBinaryClassifier.BuildingBlock block) throws ModelCreationException; + +} diff --git a/src/main/java/javax/visrec/spi/ClassifierFactoryService.java b/src/main/java/javax/visrec/spi/ClassifierFactoryService.java index 63e3e05..edb653b 100644 --- a/src/main/java/javax/visrec/spi/ClassifierFactoryService.java +++ b/src/main/java/javax/visrec/spi/ClassifierFactoryService.java @@ -1,3 +1,22 @@ +/** + * Visual Recognition API for Java, JSR381 + * Copyright (C) 2020 Zoran Sevarac, Frank Greco + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + package javax.visrec.spi; import javax.visrec.ml.model.ModelCreationException; diff --git a/src/main/java/javax/visrec/spi/ImageClassifierFactory.java b/src/main/java/javax/visrec/spi/ImageClassifierFactory.java index 533cb1a..903bbf3 100644 --- a/src/main/java/javax/visrec/spi/ImageClassifierFactory.java +++ b/src/main/java/javax/visrec/spi/ImageClassifierFactory.java @@ -1,13 +1,32 @@ -package javax.visrec.spi; - -import javax.visrec.ml.model.ModelCreationException; -import javax.visrec.ml.classification.ImageClassifier; -import javax.visrec.ml.classification.NeuralNetImageClassifier; - -public interface ImageClassifierFactory { - - Class getImageClass(); - - ImageClassifier create(NeuralNetImageClassifier.BuildingBlock block) throws ModelCreationException; - -} +/** + * Visual Recognition API for Java, JSR381 + * Copyright (C) 2020 Zoran Sevarac, Frank Greco + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +package javax.visrec.spi; + +import javax.visrec.ml.model.ModelCreationException; +import javax.visrec.ml.classification.ImageClassifier; +import javax.visrec.ml.classification.NeuralNetImageClassifier; + +public interface ImageClassifierFactory { + + Class getImageClass(); + + ImageClassifier create(NeuralNetImageClassifier.BuildingBlock block) throws ModelCreationException; + +} diff --git a/src/main/java/javax/visrec/spi/ImageFactoryService.java b/src/main/java/javax/visrec/spi/ImageFactoryService.java index 3c1e5da..779575d 100644 --- a/src/main/java/javax/visrec/spi/ImageFactoryService.java +++ b/src/main/java/javax/visrec/spi/ImageFactoryService.java @@ -1,3 +1,22 @@ +/** + * Visual Recognition API for Java, JSR381 + * Copyright (C) 2020 Zoran Sevarac, Frank Greco + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + package javax.visrec.spi; import javax.visrec.ImageFactory; diff --git a/src/main/java/javax/visrec/spi/ImplementationService.java b/src/main/java/javax/visrec/spi/ImplementationService.java index 47fc2e1..72292b9 100644 --- a/src/main/java/javax/visrec/spi/ImplementationService.java +++ b/src/main/java/javax/visrec/spi/ImplementationService.java @@ -1,30 +1,49 @@ -package javax.visrec.spi; - -/** - * Returns information about the used implementation of visual recognition API - * - * @since 1.0 - */ -public abstract class ImplementationService { - - /** - * Get the name of the implementation - * @return name as {@code String} - */ - public abstract String getName(); - - /** - * Get the version of the implementation - * @return version as {@code String} - */ - public abstract String getVersion(); - - /** - * Returns the name, major and minor version of the implementation - * @return combined information in a {@code String} - */ - @Override - public final String toString() { - return getName() + " " + getVersion(); - } -} +/** + * Visual Recognition API for Java, JSR381 + * Copyright (C) 2020 Zoran Sevarac, Frank Greco + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +package javax.visrec.spi; + +/** + * Returns information about the used implementation of visual recognition API + * + * @since 1.0 + */ +public abstract class ImplementationService { + + /** + * Get the name of the implementation + * @return name as {@code String} + */ + public abstract String getName(); + + /** + * Get the version of the implementation + * @return version as {@code String} + */ + public abstract String getVersion(); + + /** + * Returns the name, major and minor version of the implementation + * @return combined information in a {@code String} + */ + @Override + public final String toString() { + return getName() + " " + getVersion(); + } +} diff --git a/src/main/java/javax/visrec/spi/ServiceProvider.java b/src/main/java/javax/visrec/spi/ServiceProvider.java index 225a01b..68d2fa6 100644 --- a/src/main/java/javax/visrec/spi/ServiceProvider.java +++ b/src/main/java/javax/visrec/spi/ServiceProvider.java @@ -1,3 +1,22 @@ +/** + * Visual Recognition API for Java, JSR381 + * Copyright (C) 2020 Zoran Sevarac, Frank Greco + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + package javax.visrec.spi; import java.util.*; diff --git a/src/main/java/javax/visrec/spi/ServiceRegistry.java b/src/main/java/javax/visrec/spi/ServiceRegistry.java index dd75760..7d04f88 100644 --- a/src/main/java/javax/visrec/spi/ServiceRegistry.java +++ b/src/main/java/javax/visrec/spi/ServiceRegistry.java @@ -1,18 +1,22 @@ -/* - * Copyright 2019 Zoran. - * - * Licensed 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. +/** + * Visual Recognition API for Java, JSR381 + * Copyright (C) 2020 Zoran Sevarac, Frank Greco + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ + package javax.visrec.spi; import java.util.HashMap;