https://github.com/emergentorder/onnx-scala
An ONNX (Open Neural Network eXchange) API and backend for typeful, functional deep learning and classical machine learning in Scala 3
Science Score: 26.0%
This score indicates how likely this project is to be science-related based on various indicators:
-
○CITATION.cff file
-
✓codemeta.json file
Found codemeta.json file -
✓.zenodo.json file
Found .zenodo.json file -
○DOI references
-
○Academic publication links
-
○Committers with academic emails
-
○Institutional organization owner
-
○JOSS paper metadata
-
○Scientific vocabulary similarity
Low similarity (11.1%) to scientific vocabulary
Keywords
Keywords from Contributors
Repository
An ONNX (Open Neural Network eXchange) API and backend for typeful, functional deep learning and classical machine learning in Scala 3
Basic Info
Statistics
- Stars: 139
- Watchers: 6
- Forks: 8
- Open Issues: 1
- Releases: 13
Topics
Metadata Files
README.md

Getting Started
Add this to the build.sbt in your project:
scala
libraryDependencies += "org.emergent-order" %% "onnx-scala-backends" % "0.17.0"
A short, recent talk I gave about the project: ONNX-Scala: Typeful, Functional Deep Learning / Dotty Meets an Open AI Standard
Full ONNX model inference - quick start
First, download the model file for SqueezeNet.
You can use get_models.sh
Note that all code snippets are written in Scala 3 (Dotty).
First we create an "image" tensor composed entirely of pixel value 42:
```scala import java.nio.file.{Files, Paths} import org.emergentorder.onnx.Tensors._ import org.emergentorder.onnx.Tensors.Tensor._ import org.emergentorder.onnx.backends._ import org.emergentorder.compiletime._ import org.emergentorder.io.kjaer.compiletime._
val squeezenetBytes = Files.readAllBytes(Paths.get("squeezenet11Opset18.onnx")) val squeezenet = new ORTModelBackend(squeezenetBytes)
val data = Array.fill(13224*224){42f}
//In NCHW tensor image format val shape = 1 #: 3 #: 224 #: 224 #: SNil val tensorShapeDenotation = "Batch" ##: "Channel" ##: "Height" ##: "Width" ##: TSNil
val tensorDenotation: String & Singleton = "Image"
val imageTens = Tensor(data,tensorDenotation,tensorShapeDenotation,shape)
//or as a shorthand if you aren't concerned with enforcing denotations val imageTensDefaultDenotations = Tensor(data,shape) ```
Note that ONNX tensor content is in row-major order.
Next we run SqueezeNet image classification inference on it:
```scala val out = squeezenet.fullModelFloat, "ImageNetClassification", "Batch" ##: "Class" ##: TSNil, 1 #: 1000 #: SNil // val out: // Tensor[Float,("ImageNetClassification", // "Batch" ##: "Class" ##: TSNil, // 1 #: 1000 #: 1 #: 1 SNil)] = IO(...) // ...
//The output shape out.shape.unsafeRunSync() // val res0: Array[Int] = Array(1, 1000, 1, 1)
val data = out.data.unsafeRunSync() // val data: Array[Float] = Array(1.786191E-4, ...)
//The highest scoring and thus highest probability (predicted) class data.indices.maxBy(data) // val res1: Int = 753 ```
Referring to the ImageNet 1000 class labels, we see that the predicted class is "radiator".
Based on a simple benchmark of 100000 iterations of SqueezeNet inference, the run time is on par (within 3% of) ONNX Runtime (via Python). The discrepancy can be accounted for by the overhead of shipping data between the JVM and native memory.
When using this API, we load the provided ONNX model file and pass it as-is to the underlying ONNX backend, which is able to optimize the full graph. This is the most performant execution mode, and is recommended for off-the-shelf models / performance-critical scenarios.
This full-model API is untyped in the inputs, so it can fail at runtime. This is inevitable because we load models from disk at runtime. An upside of this is that you are free to use dynamic shapes, for example in the case of differing batch sizes per model call (assuming your model supports this via symbolic dimensions, see ONNX Shape Inference ). If your input shapes are static, feel free to wrap your calls into it in a facade with typed inputs.
Project Details
ONNX-Scala is cross-built against Scala JVM, Scala.js/JavaScript and Scala Native (for Scala 3 / Dotty )
Currently at ONNX 1.17.0 (Backward compatible to at least 1.2.0 for the full model API, 1.7.0 for the fine-grained API), ONNX Runtime 1.20.0.
Fine-grained API
A complete*, versioned, numerically generic, type-safe / typeful API to ONNX(Open Neural Network eXchange, an open format to represent deep learning and classical machine learning models), derived from the Protobuf definitions and the operator schemas (defined in C++).
We also provide implementations for each operator in terms of a generic core operator method to be implemented by the backend. For more details on the low-level fine-grained API see here
The preferred high-level fine-grained API, most suitable for the end user, is NDScala
* Up to roughly the set of ops supported by ONNX Runtime Web (WebGL backend)
Training
Automatic differentiation to enable training is under consideration (ONNX currently provides facilities for training as a tech preview only).
Type-safe Tensors
Featuring type-level tensor and axis labels/denotations, which along with literal types for dimension sizes allow for tensor/axes/shape/data-typed tensors. Type constraints, as per the ONNX spec, are implemented at the operation level on inputs and outputs, using union types, match types and compiletime singleton ops (thanks to @MaximeKjaer for getting the latter into dotty). Using ONNX docs for dimension and type denotation, as well as the operators doc as a reference, and inspired by Nexus, Neurocat and Named Tensors.
Backend
There is one backend per Scala platform. For the JVM the backend is based on ONNX Runtime, via their official Java API. For Scala.js / JavaScript the backend is based on the ONNX Runtime Web.
Supported ONNX input and output tensor data types: * Byte * Short * Int * Long * Float * Double * Boolean * String
Supported ONNX ops: * ONNX-Scala, Fine-grained API: 87/178 total * ONNX-Scala, Full model API: Same as below
- ONNX Runtime Web (using Wasm backend): 165/178 total.
- ONNX Runtime: 165/178 total
See the ONNX backend scoreboard
Example execution
TODO: T5 example
Build / Publish
You'll need sbt.
To build and publish locally:
sbt publishLocal
Built With
Core
ONNX via ScalaPB - Open Neural Network Exchange / The missing bridge between Java and native C++ libraries (For access to Protobuf definitions, used in the fine-grained API to create ONNX models in memory to send to the backend)
Spire - Powerful new number types and numeric abstractions for Scala. (For support for unsigned ints, complex numbers and the Numeric type class in the core API)
Dotty - The Scala 3 compiler, also known as Dotty. (For union types (used here to express ONNX type constraints), match types, compiletime singleton ops, ...)
Backends
ONNX Runtime via ORT Java API - ONNX Runtime: cross-platform, high performance ML inferencing and training accelerator
Inspiration
Scala
Neurocat - From neural networks to the Category of composable supervised learning algorithms in Scala with compile-time matrix checking based on singleton-types
Nexus - Experimental typesafe tensors & deep learning in Scala
Lantern - Machine learning framework prototype in Scala. The design of Lantern is built on two important and well-studied programming language concepts, delimited continuations (for automatic differentiation) and multi-stage programming (staging for short).
DeepLearning.scala - A simple library for creating complex neural networks
tf-dotty - Shape-safe TensorFlow in Dotty
Owner
- Name: Alex Merritt
- Login: EmergentOrder
- Kind: user
- Location: Remote
- Company: Independent - contract
- Website: www.linkedin.com/in/alex-merritt-a9463719
- Repositories: 71
- Profile: https://github.com/EmergentOrder
Machine Learning - Scala / Python - Data Science / Engineering - Functional Programming
GitHub Events
Total
- Watch event: 4
- Delete event: 2
- Issue comment event: 3
- Push event: 36
- Pull request event: 3
- Fork event: 1
- Create event: 4
Last Year
- Watch event: 4
- Delete event: 2
- Issue comment event: 3
- Push event: 36
- Pull request event: 3
- Fork event: 1
- Create event: 4
Committers
Last synced: 9 months ago
Top Committers
| Name | Commits | |
|---|---|---|
| Alex Merritt | l****n@g****m | 661 |
| Scala Steward | me@s****g | 435 |
| i10416 | i****6@g****m | 1 |
| dependabot[bot] | 4****] | 1 |
Committer Domains (Top 20 + Academic)
Issues and Pull Requests
Last synced: 9 months ago
All Time
- Total issues: 9
- Total pull requests: 1,199
- Average time to close issues: 27 days
- Average time to close pull requests: 4 days
- Total issue authors: 3
- Total pull request authors: 3
- Average comments per issue: 1.89
- Average comments per pull request: 0.08
- Merged pull requests: 1,036
- Bot issues: 0
- Bot pull requests: 16
Past Year
- Issues: 0
- Pull requests: 31
- Average time to close issues: N/A
- Average time to close pull requests: 12 days
- Issue authors: 0
- Pull request authors: 2
- Average comments per issue: 0
- Average comments per pull request: 0.26
- Merged pull requests: 10
- Bot issues: 0
- Bot pull requests: 3
Top Authors
Issue Authors
- ivanthewebber (1)
- i10416 (1)
- neillbyrne (1)
Pull Request Authors
- scala-steward (235)
- dependabot[bot] (14)
- i10416 (2)
Top Labels
Issue Labels
Pull Request Labels
Dependencies
- actions/checkout v3 composite
- scalacenter/sbt-dependency-submission v2 composite
- actions/checkout v3 composite
- actions/setup-java v3 composite
- 318 dependencies
- concat-with-sourcemaps 1.0.7 development
- source-map-loader 2.0.0 development
- webpack 5.24.3 development
- webpack-cli 4.5.0 development
- webpack-dev-server ^4.11.1 development
- onnxruntime-common 1.13.1
- onnxruntime-node 1.13.1