A Rust ML framework over the kurumi engine: a Tensor with NumPy broadcasting, nn modules, optimizers, a data loader, and a single-file .hodu artifact. The engine stays a small closed-primitive IR; hodu is the ergonomic user layer on top.
The split: kurumi's ops are strict (same shape, same dtype). hodu inserts broadcasting and dtype promotion before them, composes the strict primitives into layers, and drives training with a graph that is built once and fed per step.
hodu (호두) is the Korean word for "walnut"; the kernel inside is kurumi (くるみ).
- NumPy-ergonomic tensors. Broadcasting and dtype promotion are inserted before the engine's strict ops, with operator overloading, reductions, activations, conv/pool, and attention as methods.
- A real
nn. Linear, Conv2d, pooling, Embedding, multi-head attention and transformer blocks, LSTM/GRU, LayerNorm/RmsNorm/Group/Instance/BatchNorm, Dropout, and Sequential -- composed through oneModuletrait. - Training. SGD/Adam/AdamW, LR schedulers, gradient clipping and accumulation, weight-only int8/int4 quantization, and the losses/inits you expect.
- Deploy artifact.
.hoduis a self-describing container: named params, non-learnable buffers (e.g. BatchNorm running stats), and optimizer state -- so save/load round-trips eval-mode behavior and resumes training.save_runnableadditionally writes the forward graph andload_runnablerebuilds and runs it, so the artifact runs from the file alone. - CPU and Metal. The same static graph runs on the CPU reference or, on Apple Silicon, the Metal backend via
Ctx::metal().
| crate | role |
|---|---|
hodu |
the user layer: nn, optim, loss, data, .hodu serialize, quant |
hodu_core |
the Tensor handle + Ctx: broadcasting/promotion over the kurumi engine |
use hodu::prelude::*;
let ctx = Ctx::cpu(); // or Ctx::metal() on Apple Silicon
let lin = Linear::new(&ctx, 1, 1, 0);
// build the loss graph once; x, y are fed leaves
let x = ctx.input(vec![64, 1]);
let y = ctx.input(vec![64, 1]);
let loss = (&lin.forward(&x).unwrap() - &y).square().mean_all().unwrap();
let params = lin.parameters();
let grads = loss.grad(¶ms.iter().map(Param::tensor).collect::<Vec<_>>()).unwrap();
let sgd = Sgd::new(params, 0.1);
for _ in 0..200 {
ctx.feed(x.node(), xs.clone(), vec![64, 1]); // feed the batch each step
ctx.feed(y.node(), ys.clone(), vec![64, 1]);
sgd.step(&grad_values(&grads));
}
save("model.hodu", &lin).unwrap(); // deploy: named tensors, self-describingSee hodu/examples for linear regression, an MLP/CNN classifier, an LSTM, and a transformer.
A Cargo workspace; tasks run through just:
just check-- format check, lint, and tests (the CI gate)just format-- format Rust and the justfilejust --list-- all recipes
Requirements: a recent stable Rust (edition 2024). The Metal tests need macOS on Apple Silicon; elsewhere they skip and the CPU path still builds and tests.
Early development. Working today: the Tensor layer, the nn/optim/loss/data surface, the .hodu artifact with checkpointing and weight-only quant, and CPU + Metal execution.
See CONTRIBUTING.md.
Licensed under either of Apache License, Version 2.0 or MIT license at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
Third-party dependency licenses are collected in LICENSES/ and THIRD-PARTY.md, generated by cargo tribute (just licenses).
