diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..c442be9 --- /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 package diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml new file mode 100644 index 0000000..6bff773 --- /dev/null +++ b/.github/workflows/snapshot.yml @@ -0,0 +1,41 @@ +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: + repository_dispatch: + types: [snapshot-pub] + 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: 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 repository + run: ./mvnw deploy -s settings.xml + env: + OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} + OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} + GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} diff --git a/.github/workflows/staging.yml b/.github/workflows/staging.yml new file mode 100644 index 0000000..d860d41 --- /dev/null +++ b/.github/workflows/staging.yml @@ -0,0 +1,46 @@ +name: staging + +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 repository + run: | + sed -i "s/-SNAPSHOT//g" pom.xml + ./mvnw deploy -s settings.xml + env: + OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} + OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} + GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} 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 0000000..2cc7d4a Binary files /dev/null and b/.mvn/wrapper/maven-wrapper.jar differ 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/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..ef23593 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,357 @@ + 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. diff --git a/README.md b/README.md index 064b73a..76a5a5a 100644 --- a/README.md +++ b/README.md @@ -1,41 +1,30 @@ # visrec-api -Specification of standard Visual Recognition API for Java (JSR work in progress) +![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) -## Examples -TODO General example text +This repo contains specification of standard Visual Recognition API for Java (JSR381) -There's support for the following build tools: -* Maven -* Gradle -* Gradle Wrapper +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. -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. +Reference implementation of specification is available at -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. +https://github.com/JavaVisRec/visrec-ri/ -### Maven -TODO Instructions here. +## Getting Started Guide +For step by step guide and additional info see getting started guide at -### 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. +https://github.com/JavaVisRec/visrec-api/wiki/Getting-Started-Guide -Go to directory of the example and perform the following command: -> `gradle run` +## Quick Start with Examples -OR remain in the root directory of the project and perform the following command: -> `gradle :visrec-deepnetts-impl:run` +Introductory examples are available at -You can change `visrec-deepnetts-impl` into any of the other examples' directory. +https://github.com/JavaVisRec/jsr381-examples -### 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. +Quick start with commands: -Remain in the root directory of the project and perform the following command: -> `gradlew :visrec-deepnetts-impl:run` + git clone https://github.com/JavaVisRec/jsr381-examples.git + cd jsr381-examples + mvn clean install + mvn exec:java -Dexec.mainClass=jsr381.example.ImplementationExample -You can change `visrec-deepnetts-impl` into any of the other examples' directory. \ No newline at end of file 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 old mode 100644 new mode 100755 index 518efff..2fe81a7 --- a/gradlew +++ b/gradlew @@ -1,172 +1,183 @@ -#!/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" "$@" +#!/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 index e95643d..24467a1 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,3 +1,19 @@ +@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 @@ -14,7 +30,7 @@ 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= +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome 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 ca2179b..5f89a6a 100644 --- a/pom.xml +++ b/pom.xml @@ -1,9 +1,10 @@ - + 4.0.0 javax.visrec visrec-api - 1.0-SNAPSHOT + 1.0.5-SNAPSHOT jar javax.visrec:visrec-api @@ -45,17 +46,11 @@ - - org.json - json - 20160212 - jar - - junit junit 4.0 + test @@ -64,28 +59,35 @@ ossrh https://oss.sonatype.org/content/repositories/snapshots - - - - + + ossrh + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + - + + --pinentry-mode + loopback + + - + org.sonatype.plugins @@ -103,9 +105,10 @@ true org.apache.maven.plugins maven-javadoc-plugin - 2.9.1 + 3.1.0 true + none 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? diff --git a/settings.xml b/settings.xml new file mode 100644 index 0000000..57135b5 --- /dev/null +++ b/settings.xml @@ -0,0 +1,29 @@ + + + + + + ossrh + ${env.OSSRH_USERNAME} + ${env.OSSRH_PASSWORD} + + + + + + ossrh + + true + + + gpg + ${env.GPG_PASSPHRASE} + + + + + ossrh + + \ No newline at end of file diff --git a/src/main/java/javax/visrec/AbstractImageClassifier.java b/src/main/java/javax/visrec/AbstractImageClassifier.java deleted file mode 100644 index b955a67..0000000 --- a/src/main/java/javax/visrec/AbstractImageClassifier.java +++ /dev/null @@ -1,84 +0,0 @@ -package javax.visrec; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -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. - * 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 Classifier} 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 - - 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() - .getImageFactoryService() - .getByImageType(cls); - if (!optionalImageFactory.isPresent()) { - throw new IllegalArgumentException(String.format("Could not find ImageFactory by '%s'", cls.getName())); - } - imageFactory = optionalImageFactory.get(); - setModel(model); - } - - public ImageFactory getImageFactory() { - return imageFactory; - } - - public Map classify(File file) throws IOException { - IMAGE_CLASS image = imageFactory.getImage(file); - return classify(image); - } - - public Map classify(InputStream inStream) throws IOException { - IMAGE_CLASS image = imageFactory.getImage(inStream); - return classify(image); - } - - // 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; - } - - protected void setModel(MODEL_CLASS model) { - Objects.requireNonNull(model, "Model cannot bu null!"); - this.model = model; - } - - public float getThreshold() { - return threshold; - } - - public void setThreshold(float threshold) { - this.threshold = threshold; - } -} diff --git a/src/main/java/javax/visrec/ImageFactory.java b/src/main/java/javax/visrec/ImageFactory.java index a221b6a..336fb53 100644 --- a/src/main/java/javax/visrec/ImageFactory.java +++ b/src/main/java/javax/visrec/ImageFactory.java @@ -1,44 +1,65 @@ +/** + * 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.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. * - * @author Zoran Sevarac - * @param the type of object to be returned after getting image from {@link File}, {@link URL} or {@link InputStream} + * @param the type of object to be returned after getting image from {@link Path}, {@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/AbstractMultiClassClassifier.java b/src/main/java/javax/visrec/ml/classification/AbstractMultiClassClassifier.java new file mode 100644 index 0000000..748540e --- /dev/null +++ b/src/main/java/javax/visrec/ml/classification/AbstractMultiClassClassifier.java @@ -0,0 +1,44 @@ +/** + * 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 new file mode 100644 index 0000000..7b93c2c --- /dev/null +++ b/src/main/java/javax/visrec/ml/classification/BinaryClassifier.java @@ -0,0 +1,29 @@ +/** + * 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 new file mode 100644 index 0000000..a11b5c8 --- /dev/null +++ b/src/main/java/javax/visrec/ml/classification/Classifiable.java @@ -0,0 +1,51 @@ +/** + * 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; + +/** + * 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 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) + */ +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/ClassificationException.java b/src/main/java/javax/visrec/ml/classification/ClassificationException.java new file mode 100644 index 0000000..3d1067c --- /dev/null +++ b/src/main/java/javax/visrec/ml/classification/ClassificationException.java @@ -0,0 +1,48 @@ +/** + * 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 158dd1a..c0a97ea 100644 --- a/src/main/java/javax/visrec/ml/classification/Classifier.java +++ b/src/main/java/javax/visrec/ml/classification/Classifier.java @@ -1,28 +1,56 @@ +/** + * 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; - /** - * 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. + * 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 . + *

+ * 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 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 (String, Enum, custom class). + * @see BinaryClassifier + * @see MultiClassClassifier + * @see ImageClassifier + * @see Classifiable * @since 1.0 */ @FunctionalInterface public interface Classifier { /** - * Classifies specified instance and returns classification results as - * map with class names and corresponding classification scores. + * 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 + * @throws ClassificationException if the input could not be classified */ - Map 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 6d83d4a..0000000 --- a/src/main/java/javax/visrec/ml/classification/ClassifierBuilder.java +++ /dev/null @@ -1,50 +0,0 @@ -package javax.visrec.ml.classification; - -import javax.visrec.spi.ServiceProvider; - -/** - * Builder to create @{link Classifier} - * - * @author Kevin Berendsen - * @since 1.0 - */ -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/EnsambleClassifier.java b/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java index f9b7b2b..f0b94d6 100644 --- a/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/EnsambleClassifier.java @@ -1,6 +1,27 @@ +/** + * 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; import java.util.HashMap; +import java.util.List; import java.util.Map; /** @@ -8,7 +29,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 @@ -18,18 +38,34 @@ public final class EnsambleClassifier implements Classifier { private final Map> classifiers = new HashMap<>(); @Override - public Map classify(T input) { - classifiers.values().stream() // or parallelStream - .forEach(c -> c.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? - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + 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 corresponding probability + // if (instanceof BinaryClassifier) deal with binary classifiers using if statement + 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; + } + } + + return maxClass; } - // or just provide method for adding swith some intrenal id? - 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/ImageClassifier.java b/src/main/java/javax/visrec/ml/classification/ImageClassifier.java index df8ceae..0aa4aae 100644 --- a/src/main/java/javax/visrec/ml/classification/ImageClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/ImageClassifier.java @@ -1,104 +1,53 @@ -package javax.visrec.ml.classification; - -import javax.visrec.spi.ServiceProvider; -import java.awt.image.BufferedImage; -import java.io.File; - -public interface ImageClassifier extends Classifier { - - static ImageClassifier.Builder newBuilder() { - return new Builder(); - } - - class BuildingBlock { - - private int imageWidth; - private int imageHeight; - private File trainingsFile; - private File labelsFile; - private float maxError; - private float learningRate; - private File modelFile; - - private BuildingBlock() { - } - - 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; - } - } - - class Builder implements javax.visrec.util.Builder { - - private BuildingBlock block; - - private Builder() { - block = new BuildingBlock(); - } - - 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 learningRate(float learningRate) { - block.learningRate = learningRate; - return this; - } - - public Builder modelFile(File modelFile) { - block.modelFile = modelFile; - return this; - } - - @Override - public ImageClassifier build() { - return ServiceProvider.current().getClassifierService().createImageClassifier(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 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 new file mode 100644 index 0000000..8ffe52b --- /dev/null +++ b/src/main/java/javax/visrec/ml/classification/LogisticRegression.java @@ -0,0 +1,45 @@ +/** + * 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 7269a96..e310fc2 100644 --- a/src/main/java/javax/visrec/ml/classification/MultiClassClassifier.java +++ b/src/main/java/javax/visrec/ml/classification/MultiClassClassifier.java @@ -1,15 +1,34 @@ -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; - } - -} +/** + * 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; + +/** + * 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? + * + * @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/classification/NeuralNetBinaryClassifier.java b/src/main/java/javax/visrec/ml/classification/NeuralNetBinaryClassifier.java new file mode 100644 index 0000000..c13eff6 --- /dev/null +++ b/src/main/java/javax/visrec/ml/classification/NeuralNetBinaryClassifier.java @@ -0,0 +1,155 @@ +/** + * 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 new file mode 100644 index 0000000..2dd0b70 --- /dev/null +++ b/src/main/java/javax/visrec/ml/classification/NeuralNetImageClassifier.java @@ -0,0 +1,199 @@ +/** + * 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/classification/package-info.java b/src/main/java/javax/visrec/ml/classification/package-info.java new file mode 100644 index 0000000..2aa5dbb --- /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 (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/data/BasicDataSet.java b/src/main/java/javax/visrec/ml/data/BasicDataSet.java index 47a926c..652e8d1 100644 --- a/src/main/java/javax/visrec/ml/data/BasicDataSet.java +++ b/src/main/java/javax/visrec/ml/data/BasicDataSet.java @@ -1,30 +1,66 @@ +/** + * 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; import java.util.Arrays; -import java.util.Iterator; import java.util.List; -import java.util.Random; import java.util.stream.Collectors; /** - * Basic implementation of {@link DataSet} interface - * - * @author Zoran Sevarac + * Basic implementation of {@link DataSet} interface. + * Provides a list of data set items with column info. + * + * @param Type of elements in data set */ -public class BasicDataSet implements DataSet{ +public class BasicDataSet implements DataSet { - private List items; - private Column[] columns; + /** + * List of data set items in this data set. + */ + protected List items; + + /** + * List of data set columns. Each column provides info about it's name, type. + */ + private List columns = new ArrayList<>(); + protected BasicDataSet() { + items = new ArrayList<>(); + } + /** * Creates an instance of {@link BasicDataSet} * @param cols columns of the data set. */ - public BasicDataSet(Column[] cols) { - this.columns = cols; + 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} @@ -33,83 +69,70 @@ 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(); - } + public List getItems() { + return items; + } @Override - public int size() { - return items.size(); + public List getColumns() { + return columns; } - - @Override - public DataSet[] split(int parts) { - throw new UnsupportedOperationException("not implemented"); + + public void setColumnNames(String[] columnNames) { + for(int i=0; i[] split(int parts, Random rnd) { - throw new UnsupportedOperationException("not implemented"); + public String[] getColumnNames() { + String[] colNames = new String[columns.size()]; + for(int i=0; i[] split(double... parts) { - throw new UnsupportedOperationException("not implemented"); + + public void setAsTargetColumns(int... targetIdxs) { + // reset all cureent target columns + columns.stream().forEach( c->c.setAsTarget(false)); + + for(int idx : targetIdxs) { + columns.get(idx).setAsTarget(true); + } } - + + 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.setAsTarget(true); + } + }); + } + @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() { - List targetLabels = Arrays.asList(columns).stream() + public String[] getTargetColumnsNames() { + List targetLabels = columns.stream() .filter((col) -> col.isTarget()) .map((col) -> col.getName() ) .collect(Collectors.toList()); 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. -// } + } + + // remove? @Override - public Iterator iterator() { - return items.iterator(); + public DataSet[] split(double... parts) { + throw new UnsupportedOperationException("Not supported yet."); } @Override - public List getItems() { - return items; + public void setColumns(List columns) { + this.columns = columns; } - -} +} \ No newline at end of file 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..220b310 --- /dev/null +++ b/src/main/java/javax/visrec/ml/data/Column.java @@ -0,0 +1,80 @@ +/** + * 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 df28887..99a4549 100644 --- a/src/main/java/javax/visrec/ml/data/DataSet.java +++ b/src/main/java/javax/visrec/ml/data/DataSet.java @@ -1,22 +1,40 @@ +/** + * 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; import java.util.Collections; +import java.util.Iterator; 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. * - * @author Zoran Sevarac * @param type of data set elements * @since 1.0 */ 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} @@ -48,12 +66,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 +80,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,22 +96,44 @@ 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. - * + * 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. */ - 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); + } /** @@ -135,36 +178,32 @@ 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); -// TODO String[] getOutputLabels(); -// TODO void setColumnNames(String[] labels); - - class Column { - private final String name; - private final ColumnType type; - private final boolean isTarget; - - public Column(String name, ColumnType type, boolean isTarget) { - this.name = name; - this.type = type; - this.isTarget = isTarget; - } - - public String getName() { - return name; - } - - public ColumnType getType() { - return type; - } - - public boolean isTarget() { - return isTarget; - } - } - - enum ColumnType { - DECIMAL, INTEGER, BINARY, STRING; + /** + * Returns the columns of the data set. + * + * @return + */ + 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(); } } \ No newline at end of file diff --git a/src/main/java/javax/visrec/ml/data/DataSets.java b/src/main/java/javax/visrec/ml/data/DataSets.java deleted file mode 100644 index 7628cf3..0000000 --- a/src/main/java/javax/visrec/ml/data/DataSets.java +++ /dev/null @@ -1,72 +0,0 @@ -package javax.visrec.ml.data; - -import javax.visrec.ml.data.norm.Normalizer; - -/** - * Utility class that provides commmon operations on data sets - * @author zoran - */ -public class DataSets { - - private DataSets() { } - - // 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 DataSet normalize(DataSet dataSet, Normalizer norm) { - return norm.normalize(dataSet, false); - } - - // how about moving thes estatic methods to coresponding interface? -// public static DataSet 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 DataSet standardize(DataSet 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 - */ - -} 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/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/Scaler.java b/src/main/java/javax/visrec/ml/data/preprocessing/Scaler.java new file mode 100644 index 0000000..4752816 --- /dev/null +++ b/src/main/java/javax/visrec/ml/data/preprocessing/Scaler.java @@ -0,0 +1,35 @@ +/** + * 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; + +/** + * 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 value ranges among data. + * + * @param Data set class (that implements DataSet interface) + */ +public interface Scaler> { + public void apply(T dataSet); +} + 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/util/BoundingBox.java b/src/main/java/javax/visrec/ml/detection/BoundingBox.java similarity index 56% rename from src/main/java/javax/visrec/util/BoundingBox.java rename to src/main/java/javax/visrec/ml/detection/BoundingBox.java index ba208e3..00a98a5 100644 --- a/src/main/java/javax/visrec/util/BoundingBox.java +++ b/src/main/java/javax/visrec/ml/detection/BoundingBox.java @@ -1,9 +1,27 @@ -package javax.visrec.util; +/** + * 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; /** * 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 982f29b..6a48c6e 100644 --- a/src/main/java/javax/visrec/ml/detection/ObjectDetector.java +++ b/src/main/java/javax/visrec/ml/detection/ObjectDetector.java @@ -1,6 +1,24 @@ +/** + * 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 javax.visrec.util.BoundingBox; import java.util.List; import java.util.Map; @@ -8,7 +26,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 */ @@ -16,7 +33,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/ml/eval/ClassificationMetrics.java b/src/main/java/javax/visrec/ml/eval/ClassificationMetrics.java new file mode 100644 index 0000000..630b13c --- /dev/null +++ b/src/main/java/javax/visrec/ml/eval/ClassificationMetrics.java @@ -0,0 +1,71 @@ +/** + * 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 new file mode 100644 index 0000000..ee1a7a3 --- /dev/null +++ b/src/main/java/javax/visrec/ml/eval/EvaluationMetrics.java @@ -0,0 +1,100 @@ +/** + * 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; + +import java.util.HashMap; + +/** + * Wrapper for constants and values for classifier and regressor evaluation metrics. + * + */ +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"; + + // 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"; + + // Hold values of relevant evaluation metrics + 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, "Harmonic average (balance) of precision and recall"); + } + + + 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()); + if (description.get(e.getKey())!=null) + sb.append(" (") + .append(description.get(e.getKey())) + .append(")"); + sb.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..a18bdb8 100644 --- a/src/main/java/javax/visrec/ml/eval/Evaluator.java +++ b/src/main/java/javax/visrec/ml/eval/Evaluator.java @@ -1,49 +1,43 @@ -/** - * 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; /** + * 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/ml/eval/RegressionMetrics.java b/src/main/java/javax/visrec/ml/eval/RegressionMetrics.java new file mode 100644 index 0000000..2cd9618 --- /dev/null +++ b/src/main/java/javax/visrec/ml/eval/RegressionMetrics.java @@ -0,0 +1,55 @@ +/** + * 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 new file mode 100644 index 0000000..2c195e1 --- /dev/null +++ b/src/main/java/javax/visrec/ml/model/InvalidConfigurationException.java @@ -0,0 +1,34 @@ +/** + * 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 new file mode 100644 index 0000000..fa1c3f4 --- /dev/null +++ b/src/main/java/javax/visrec/ml/model/ModelBuilder.java @@ -0,0 +1,68 @@ +/** + * 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; +import java.lang.reflect.Method; +import java.util.Map; + +/** + * Generic model builder interface, that all builders for machine learning algorithms implement. + * + * @param type of the object to be returned by the builder. + * @since 1.0 + */ +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; + + /** + * Builds an object using properties from the specified input argument + * + * @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 { + 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 { + 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 thizz.build(); + } + +} diff --git a/src/main/java/javax/visrec/ml/model/ModelCreationException.java b/src/main/java/javax/visrec/ml/model/ModelCreationException.java new file mode 100644 index 0000000..3404c22 --- /dev/null +++ b/src/main/java/javax/visrec/ml/model/ModelCreationException.java @@ -0,0 +1,46 @@ +/** + * 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 new file mode 100644 index 0000000..7ee8184 --- /dev/null +++ b/src/main/java/javax/visrec/ml/model/ModelProvider.java @@ -0,0 +1,31 @@ +/** + * 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; + +/** + * This interface should be implemented by classes which expose access to underlying ML model + * + * @param Type of the underlying ML model + */ +public interface ModelProvider { + + T getModel(); + +} diff --git a/src/main/java/javax/visrec/ml/regression/Regressor.java b/src/main/java/javax/visrec/ml/regression/Regressor.java new file mode 100644 index 0000000..c6a598b --- /dev/null +++ b/src/main/java/javax/visrec/ml/regression/Regressor.java @@ -0,0 +1,35 @@ +/** + * 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; + +/** + * 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. + * + * @param type of inputs / features + * @param return/result type + */ +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 new file mode 100644 index 0000000..2f14fd4 --- /dev/null +++ b/src/main/java/javax/visrec/ml/regression/SimpleLinearRegression.java @@ -0,0 +1,67 @@ +/** + * 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/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 diff --git a/src/main/java/javax/visrec/regression/LogisticRegression.java b/src/main/java/javax/visrec/regression/LogisticRegression.java deleted file mode 100644 index 56ce044..0000000 --- a/src/main/java/javax/visrec/regression/LogisticRegression.java +++ /dev/null @@ -1,24 +0,0 @@ -package javax.visrec.regression; - -import javax.visrec.ml.classification.Classifier; - -/** - * This class performs basic binary classification - mapping of specified input to true/false with probability. - * - * @author Zoran Sevarac - * @param Implementation class of underlying machine learning model - */ -public abstract class LogisticRegression implements Classifier{ - - private MODEL_CLASS model; - - public MODEL_CLASS getModel() { - return model; - } - - protected void setModel(MODEL_CLASS model) { - this.model = model; - } - - // add train method here so we can dow model.train() -} diff --git a/src/main/java/javax/visrec/regression/Regressor.java b/src/main/java/javax/visrec/regression/Regressor.java deleted file mode 100644 index 50dd681..0000000 --- a/src/main/java/javax/visrec/regression/Regressor.java +++ /dev/null @@ -1,16 +0,0 @@ -package javax.visrec.regression; - -/** - * Base interface for all regressors. - * Regressors try to predict a continual value(s) (a decimal number) based on a set of inputs. - * - * @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/regression/SimpleLinearRegression.java b/src/main/java/javax/visrec/regression/SimpleLinearRegression.java deleted file mode 100644 index 2e74a16..0000000 --- a/src/main/java/javax/visrec/regression/SimpleLinearRegression.java +++ /dev/null @@ -1,51 +0,0 @@ -package javax.visrec.regression; - -import javax.visrec.regression.Regressor; - -/** - * Simple linear regression finds the best possible straight line that tries to explain given training set. - * - * @author zoran - */ -public abstract class SimpleLinearRegression implements Regressor { - - private MODEL_CLASS model; - - public MODEL_CLASS getModel() { - return model; - } - - protected void setModel(MODEL_CLASS model) { - this.model = model; - } - - @Override - public abstract Float predict(Float inputs); - - /** - * 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 - */ - public abstract float getSlope(); - - /** - * The value of output 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() - -} 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..a3d3b0c --- /dev/null +++ b/src/main/java/javax/visrec/spi/BinaryClassifierFactory.java @@ -0,0 +1,32 @@ +/** + * 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/BuilderService.java b/src/main/java/javax/visrec/spi/BuilderService.java deleted file mode 100644 index ac8495d..0000000 --- a/src/main/java/javax/visrec/spi/BuilderService.java +++ /dev/null @@ -1,19 +0,0 @@ -package javax.visrec.spi; - -import javax.visrec.ml.classification.ClassifierBuilder; - -/** - * Service to provide builders. - * - * @author Kevin Berendsen - * @since 1.0 - */ -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/ClassifierFactoryService.java b/src/main/java/javax/visrec/spi/ClassifierFactoryService.java new file mode 100644 index 0000000..edb653b --- /dev/null +++ b/src/main/java/javax/visrec/spi/ClassifierFactoryService.java @@ -0,0 +1,101 @@ +/** + * 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.*; +import java.util.HashMap; +import java.util.Map; +import java.util.ServiceLoader; + +/** + * Service to provide the correct {@link Classifier} implementation. + * + * @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 NeuralNetImageClassifier.BuildingBlock} to tune + * the implementation's image classifier. + * + * @param block {@link NeuralNetImageClassifier.BuildingBlock} is provided to tune the building of the image classifier. + * @return {@link ImageClassifier} + * @throws ModelCreationException if the classifier can not be created due to any reason. + */ + public ImageClassifier createNeuralNetImageClassifier(NeuralNetImageClassifier.BuildingBlock block) throws ModelCreationException { + if (imageClassifierFactories == null) { + imageClassifierFactories = new HashMap<>(); + for (ImageClassifierFactory classifierCreator : ServiceLoader.load(ImageClassifierFactory.class)) { + imageClassifierFactories.put(classifierCreator.getImageClass(), classifierCreator); + } + } + + ImageClassifierFactory creator = imageClassifierFactories.get(block.getInputClass()); + if (creator == null) { + throw new ModelCreationException("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 ModelCreationException if the classifier can not be created due to any reason. + */ + public BinaryClassifier createNeuralNetBinaryClassifier(NeuralNetBinaryClassifier.BuildingBlock block) throws ModelCreationException { + if (binaryClassifierFactories == null) { + binaryClassifierFactories = new HashMap<>(); + for (BinaryClassifierFactory classifierCreator : ServiceLoader.load(BinaryClassifierFactory.class)) { + binaryClassifierFactories.put(classifierCreator.getTargetClass(), classifierCreator); + } + } + + BinaryClassifierFactory creator = binaryClassifierFactories.get(block.getInputClass()); + if (creator == null) { + throw new ModelCreationException("Unsupported target class"); + } + + @SuppressWarnings("unchecked") + BinaryClassifierFactory castedCreator = (BinaryClassifierFactory) 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 ac86d92..0000000 --- a/src/main/java/javax/visrec/spi/ClassifierService.java +++ /dev/null @@ -1,21 +0,0 @@ -package javax.visrec.spi; - -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} - */ - ImageClassifier createImageClassifier(ImageClassifier.BuildingBlock block); -} diff --git a/src/main/java/javax/visrec/spi/ImageClassifierFactory.java b/src/main/java/javax/visrec/spi/ImageClassifierFactory.java new file mode 100644 index 0000000..903bbf3 --- /dev/null +++ b/src/main/java/javax/visrec/spi/ImageClassifierFactory.java @@ -0,0 +1,32 @@ +/** + * 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 32dbf1a..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; @@ -6,19 +25,19 @@ /** * The service to locate and find implementations of the {@link ImageFactory} interface. * - * @author Kevin Berendsen * @since 1.0 */ 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/ImplementationService.java b/src/main/java/javax/visrec/spi/ImplementationService.java index be14f5d..72292b9 100644 --- a/src/main/java/javax/visrec/spi/ImplementationService.java +++ b/src/main/java/javax/visrec/spi/ImplementationService.java @@ -1,36 +1,49 @@ -package javax.visrec.spi; - -/** - * Returns information about the used implementation of visual recognition API - * @author Kevin Berendsen - * @since 1.0 - */ -public abstract class ImplementationService { - - /** - * Get the name of the implementation - * @return name as {@code String} - */ - public abstract String getName(); - - /** - * Get the major version of the implementation - * @return major version as {@code int} - */ - public abstract int getMajorVersion(); - - /** - * Get the minor version of the implementation - * @return minor version as {@code int} - */ - public abstract int getMinorVersion(); - - /** - * Returns the name, major and minor version of the implementation - * @return combined information in a {@code String} - */ - @Override - public final String toString() { - return getName() + " " + getMajorVersion() + "." + getMinorVersion(); - } -} +/** + * 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 5599026..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.*; @@ -10,9 +29,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 { @@ -36,16 +52,12 @@ public int getPriority() { } /** - * Get the {@link BuilderService} - * @return builder service. - */ - public abstract BuilderService getBuilderService(); - - /** - * Get the {@link ClassifierService} - * @return classifier service + * Get the {@link ClassifierFactoryService} + * @return classifier creator service */ - public abstract ClassifierService getClassifierService(); + public ClassifierFactoryService getClassifierFactoryService() { + return ClassifierFactoryService.getInstance(); + } /** * Get the {@link ImageFactoryService} 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..7d04f88 --- /dev/null +++ b/src/main/java/javax/visrec/spi/ServiceRegistry.java @@ -0,0 +1,49 @@ +/** + * 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; +import java.util.Iterator; +import java.util.Map; + +/** + * Registry for all ML algorithms provided by this implementation. + * + */ +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)); + } +} diff --git a/src/main/java/javax/visrec/util/Builder.java b/src/main/java/javax/visrec/util/Builder.java deleted file mode 100644 index ecea7bc..0000000 --- a/src/main/java/javax/visrec/util/Builder.java +++ /dev/null @@ -1,45 +0,0 @@ -package javax.visrec.util; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Map; - -/** - * Generic builder interface, that all builders for machine learning algorithms implement. - * - * @author Zoran Sevarac - * @author Kevin Berendsen - * @param type of the object to be returned by the builder. - * @since 1.0 - */ -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(); - - /** - * Builds an object using properties from the specified input argument - * - * @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) { - 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 InvalidBuilderConfigurationException("Couldn't invoke '" + method.getName() + "'", e); - } - } - } - return build(); - } - -} \ No newline at end of file diff --git a/src/main/java/javax/visrec/util/InvalidBuilderConfigurationException.java b/src/main/java/javax/visrec/util/InvalidBuilderConfigurationException.java deleted file mode 100644 index a686489..0000000 --- a/src/main/java/javax/visrec/util/InvalidBuilderConfigurationException.java +++ /dev/null @@ -1,16 +0,0 @@ -package javax.visrec.util; - -/** - * 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. - * - * @author Kevin Berendsen - */ -public class InvalidBuilderConfigurationException extends RuntimeException { - - InvalidBuilderConfigurationException(String msg, Throwable throwable) { - super(msg, throwable); - } - -} diff --git a/src/main/java/javax/visrec/util/Model.java b/src/main/java/javax/visrec/util/Model.java deleted file mode 100644 index 5401872..0000000 --- a/src/main/java/javax/visrec/util/Model.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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; - -/** - * - * @author zoran - */ -public interface Model { - void train(DataSet trainingSet); - void test(DataSet testSet); // evaluate -} 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"; -}