Awesome
menoh-java
menoh-java enables you to build your own Deep Neural Network (DNN) application with a few lines of code in Java.
This is a Java binding for Menoh DNN inference library, which supports ONNX model format.
Getting Started
Add a dependency
Using Gradle:
dependencies {
implementation 'jp.preferred.menoh:menoh:0.1.0'
}
Using Maven:
<dependency>
<groupId>jp.preferred.menoh</groupId>
<artifactId>menoh</artifactId>
<version>0.1.0</version>
</dependency>
Install native libraries
menoh-java requires Menoh Core and its dependent native shared libraries to maximize the utilization of hardware resources. You need to install them to the JVM classpath or the system library path before running.
Examples
Please see menoh-examples directory in this repository.
Usage
menoh-java provides two types of APIs: high-level and low-level. The high-level API is a simple wrapper of the low-level API. You should choose the high-level API in most cases because it manages lifecycle of the low-level objects on behalf of you.
High-level API
ModelRunner
is a high-level API of menoh-java. What you only need to do is to configure ModelRunnerBuilder
by using your ONNX model, and build()
a runner object.
Note that you must close()
both the runner and its builder objects explicitly because it frees the memory for objects in the native heap which will not be garbage collected by the JVM.
import jp.preferred.menoh.ModelRunner;
import jp.preferred.menoh.ModelRunnerBuilder;
try (
ModelRunnerBuilder builder = ModelRunner
// Load ONNX model data
.fromOnnxFile(onnxModelPath)
// Define input profile (name, dtype, dims) and output profile (name, dtype)
// Menoh calculates dims of outputs automatically at build time
.addInputProfile(conv11InName, DType.FLOAT, new int[] {batchSize, channelNum, height, width})
.addOutputProfile(fc6OutName, DType.FLOAT)
.addOutputProfile(softmaxOutName, DType.FLOAT)
// Configure backend
.backendName("mkldnn")
.backendConfig("");
ModelRunner runner = builder.build()
) {
// The builder can be deleted explicitly after building a model runner
builder.close();
...
Once you create the ModelRunner
, you can run()
the model with input data again and again:
// Run the inference
runner.run(conv11InName, imageData);
final Variable softmaxOut = runner.variable(softmaxOutName);
final int[] softmaxOutDims = softmaxOut.dims();
final ByteBuffer softmaxOutBuf = softmaxOut.buffer();
// Note: use `get()` instead of `array()` because it is a direct buffer
final float[] scores = new float[softmaxOutDims[1]];
softmaxOutBuf.asFloatBuffer().get(scores);
...
Low-level API
The low-level API consists of ModelData
, VariableProfileTable
and Model
. You don't need to use them in most cases other than managing lifecycle of the builder objects and the variable buffers by hand.
Building from Source
$ git clone https://github.com/pfnet-research/menoh-java.git
$ cd menoh-java
$ mvn package
Note that mvn test
requires that Menoh Core is available in the JNA search path.
FAQ
menoh-java fails with java.lang.UnsatisfiedLinkError
menoh-java depends on the native Menoh Core library. You'll get java.lang.UnsatisfiedLinkError
at startup if it isn't located in JNA search path even if it exists in the local system.
java.lang.UnsatisfiedLinkError: Unable to load library 'menoh': Native library (win32-x86-64/menoh.dll) not found in resource path ([file:/C:/workspace/menoh-java/menoh-examples/target/classes/, file:/C:/Users/user/.m2/repository/jp/preferred/menoh/menoh/1.0.0-SNAPSHOT/menoh-1.0.0-SNAPSHOT.jar, file:/C:/Users/user/.m2/repository/net/java/dev/jna/jna/4.5.2/jna-4.5.2.jar])
at com.sun.jna.NativeLibrary.loadLibrary(NativeLibrary.java:303)
at com.sun.jna.NativeLibrary.getInstance(NativeLibrary.java:427)
at com.sun.jna.Library$Handler.<init>(Library.java:179)
at com.sun.jna.Native.loadLibrary(Native.java:569)
at com.sun.jna.Native.loadLibrary(Native.java:544)
at jp.preferred.menoh.MenohNative.<clinit> (MenohNative.java:11)
...
If you fall into this situation, you need to configure the system property (jna.library.path
) or install the library file to the JVM classpath or the system library path, which depends on your platform (PATH
on Windows, LD_LIBRARY_PATH
on Linux and DYLD_LIBRARY_PATH
on OSX). See the JNA's document for more details.
To inspect the problem, you may set the system property jna.debug_load=true
to know what is getting wrong:
$ mvn exec:java ... -Djna.debug_load=true
Looking in classpath from java.net.URLClassLoader@3e997fa1 for /com/sun/jna/win32-x86-64/jnidispatch.dll
Found library resource at jar:file:/C:/Users/.../.m2/repository/net/java/dev/jna/jna/4.5.2/jna-4.5.2.jar!/com/sun/jna/win32-x86-64/jnidispatch.dll
Looking for library 'menoh'
Adding paths from jna.library.path: null
Trying menoh.dll
Adding system paths: []
Trying menoh.dll
Looking for lib- prefix
Trying libmenoh.dll
Looking in classpath from java.net.URLClassLoader@3e997fa1 for menoh
And you can also see jna.platform.library.path
:
NativeLibrary.getProcess(); // a trick to initialize `NativeLibrary` explicitly in this place
System.err.println("jna.library.path: " + System.getProperty("jna.library.path"));
System.err.println("jna.platform.library.path: " + System.getProperty("jna.platform.library.path"));
Limitation
This library only works on 64-bit architecture at the moment.
License
menoh-java is released under MIT License. Please see the LICENSE file for details.