Quick Start
SMILE is a comprehensive, high-performance machine learning engine for the JVM. SMILE v7 requires Java 25. Besides Java, SMILE also provides idiomatic APIs for Scala and Kotlin. The core module is self-contained (no native dependencies required for most algorithms). Optionally, native BLAS/LAPACK libraries can be used for accelerated linear algebra, and LibTorch (PyTorch C++) enables GPU-accelerated deep learning and LLM inference.
Copy the snippet below to try SMILE in your own JVM project.
var iris = Read.arff("data/weka/iris.arff");
var formula = Formula.lhs("class");
var rf = RandomForest.fit(formula, iris);
System.out.println(rf.metrics());
val iris = read.arff("data/weka/iris.arff")
val rf = randomForest("class" ~, iris)
println(rf.metrics)
val iris = read.arff("data/weka/iris.arff")
val rf = randomForest(Formula.lhs("class"), iris)
println(rf.metrics())
Installation
Add the relevant artifact(s) to your build tool. All artifacts are published to Maven Central.
<!-- Core ML algorithms (classification, regression, clustering, …) -->
<dependency>
<groupId>com.github.haifengl</groupId>
<artifactId>smile-core</artifactId>
<version>7.0.0</version>
</dependency>
<!-- Deep learning + LLMs (requires LibTorch native libraries) -->
<dependency>
<groupId>com.github.haifengl</groupId>
<artifactId>smile-deep</artifactId>
<version>7.0.0</version>
</dependency>
<!-- Natural language processing -->
<dependency>
<groupId>com.github.haifengl</groupId>
<artifactId>smile-nlp</artifactId>
<version>7.0.0</version>
</dependency>
<!-- Swing + Vega-Lite data visualization -->
<dependency>
<groupId>com.github.haifengl</groupId>
<artifactId>smile-plot</artifactId>
<version>7.0.0</version>
</dependency>
dependencies {
// Core ML algorithms
implementation("com.github.haifengl:smile-core:7.0.0")
// Idiomatic Kotlin API (wraps smile-core)
implementation("com.github.haifengl:smile-kotlin:7.0.0")
// Deep learning + LLMs
implementation("com.github.haifengl:smile-deep:7.0.0")
// NLP
implementation("com.github.haifengl:smile-nlp:7.0.0")
// Visualization
implementation("com.github.haifengl:smile-plot:7.0.0")
}
// Idiomatic Scala API (pulls in smile-core transitively)
libraryDependencies += "com.github.haifengl" %% "smile-scala" % "7.0.0"
// Deep learning
libraryDependencies += "com.github.haifengl" % "smile-deep" % "7.0.0"
Native BLAS / LAPACK (optional)
Several algorithms (manifold learning, Gaussian Process, MLP) benefit significantly from native BLAS/LAPACK. Install the system libraries:
sudo apt update
sudo apt install libopenblas-dev libarpack2
brew install arpack
# If macOS SIP strips DYLD_LIBRARY_PATH, copy the dylib to your working directory:
cp /opt/homebrew/lib/libarpack.dylib .
Pre-built DLLs are included in the bin/ directory of the
release package.
Add that directory to your PATH.
GPU / LibTorch (for Deep Learning & LLMs)
The smile-deep module calls LibTorch through Java's Foreign Function
& Memory (FFM) API — not JNI — so native libraries are resolved via the
platform loader (LD_LIBRARY_PATH on Linux,
PATH on Windows), not java.library.path.
On macOS, System Integrity Protection (SIP) strips
DYLD_LIBRARY_PATH from most child processes; copy or symlink
required .dylib files into your working directory or
/usr/local/lib instead.
The release package bundles libsmile_torch and LibTorch under
bin/ and libtorch/. GPU builds link LibTorch against a
specific CUDA version — make sure your machine has a compatible
NVIDIA driver and CUDA runtime libraries (cuDNN, etc.) before
running GPU workloads. CPU-only inference works without a GPU.
Build from Source
Clone the repository and build with the Gradle wrapper (requires Java 25):
git clone https://github.com/haifengl/smile.git
cd smile
./gradlew build -x test # build all modules, skip tests
./gradlew :core:build -x test # build only the core module
To run the tests (requires LibTorch on the library path for smile-deep):
./gradlew :core:test
./gradlew :deep:test -DexcludeTags=integration
Download the Release Package
For the interactive shell and CLI tools, download the self-contained release package from the releases page. It works on macOS, Linux, and Windows.
# Extract and run first-time setup (BLAS/LAPACK, Python venv — see GPU / LibTorch above)
cd bin
./setup # once: native libs + Python environment
./smile # launches SMILE Studio (desktop notebook IDE)
Run bin/setup once after unzipping the release package. It installs
optional native dependencies via your system package manager:
- Linux (apt):
libopenblas-dev,libarpack2 - macOS (Homebrew):
arpack - RHEL/Fedora (yum):
openblas-devel,arpack-devel - Arch (pacman):
openblas,arpack
It also installs ripgrep, creates a Python virtual environment, and
pulls packages from conf/requirements.txt (including ONNX Runtime).
LibTorch and CUDA are not installed by setup — they ship with
the release bundle (GPU builds) or must match your build environment when compiling
from source.
Interactive Shell
SMILE integrates with JShell (available since Java 9). In the home directory of the release package, run:
$ ./smile shell
All SMILE classes are pre-imported. To pass more heap memory:
$ ./smile shell -R-Xmx30G
When the shell starts you will see the SMILE banner followed by the JShell prompt:
| Welcome to SMILE -- Version 7.0.0
===============================================================================
| Welcome to JShell -- Version 25
| For an introduction type: /help intro
smile>
All SMILE definitions are pre-imported. You can run any valid Java
expression. Type /exit to leave:
smile> 2 + 3
$1 ==> 5
smile> var iris = Read.arff("data/weka/iris.arff")
iris ==> [...]
smile> var rf = RandomForest.fit(Formula.lhs("class"), iris)
smile> System.out.println(rf.metrics())
The Scala REPL has all high-level SMILE operators pre-imported:
$ ./smile scala
$ ./smile scala -J-Xmx30G # with extra heap
smile> val iris = read.arff("data/weka/iris.arff")
smile> val rf = randomForest("class" ~, iris)
smile> println(rf.metrics)
// Tab-completion shows available classifiers:
smile> smile.classification.r
randomForest rbfnet rda
There is no ./smile kotlin CLI REPL. For interactive Kotlin,
use SMILE Studio (./smile) and open a
.kts notebook — the release package includes
notebooks/kotlin.ipynb as a starter. The idiomatic API
comes from the smile-kotlin artifact:
val iris = read.arff("data/weka/iris.arff")
val rf = randomForest(Formula.lhs("class"), iris)
println(rf.metrics())
Running a Script
Save a snippet and run it non-interactively with the matching shell:
// examples/iris.jsh
import smile.classification.RandomForest;
import smile.data.formula.Formula;
import smile.io.Read;
var data = Read.arff("data/weka/iris.arff");
var formula = Formula.lhs("class");
var rf = RandomForest.fit(formula, data);
System.out.println(rf.metrics());
// examples/iris.sc
val data = read.arff("data/weka/iris.arff")
val formula = "class" ~ "."
val rf = smile.classification.randomForest(formula, data)
println(s"OOB error = %.2f%%" format 100 * rf.error)
$ ./smile shell examples/iris.jsh
$ ./smile scala examples/iris.sc
Training & Inference CLI
The SMILE shell also exposes a command-line interface for training models, batch prediction, and real-time serving — no code required.
Train a Random Forest on the Iris dataset and save the model:
$ ./smile train \
--data data/weka/iris.arff \
--formula "class ~ ." \
--model iris_rf.sml \
random-forest
Training metrics: {
fit time: 191.678 ms,
score time: 17.059 ms,
validation data size: 150,
error: 6,
accuracy: 96.00%,
cross entropy: 0.1316
}
Run ./smile train -h for a full list of supported algorithms
(ada-boost, cart, gradient-boost, lasso, lda, logistic, mlp, ols, qda,
random-forest, rbf, rda, ridge, svm, …) and
./smile train random-forest -h for algorithm-specific options.
Run batch inference on a file using a saved model:
$ ./smile predict \
--model iris_rf.sml \
--probability \
data/weka/iris.arff
0 0.9601 0.0205 0.0194
0 0.9599 0.0206 0.0195
...
The optional --probability flag outputs posterior class probabilities
alongside the predicted label.
Start an HTTP inference server (powered by Quarkus):
$ ./smile serve --model iris_rf.sml
INFO Listening on: http://0.0.0.0:8080
# Query a single sample
$ curl -X POST http://localhost:8080/api/v1/models/iris_rf-1 \
-H "Content-Type: application/json" \
-d '{"sepallength":5.1,"sepalwidth":3.5,"petallength":1.4,"petalwidth":0.2}'
{"class":0,"probability":[0.9599,0.0207,0.0194]}
If --model points to a directory, every .sml file is
loaded automatically. Discover available endpoints with
GET /api/v1/models.
The /stream endpoint processes a JSON-lines or CSV request body
element-by-element with full back-pressure, making it safe to send very large
payloads (multi-GB):
# Generate 150,000 rows (iris × 1000) and stream them through the server
$ for i in {1..1000}; do
tail -n 153 data/weka/iris.arff | head -n 150
done | curl -H "Content-Type: text/plain" \
-X POST --data-binary @- \
http://localhost:8080/api/v1/models/iris_rf-1/stream
This completes end-to-end (including HTTP transfer and printing) in under 4 seconds for 150,000 samples.