instmodel-rust-inference
A high-performance neural network inference library for Rust that executes optimized computation sequences through a unified buffer architecture.
Installation
Or add to your Cargo.toml:
[]
= "<version>"
Overview
This library provides a lightweight, zero-dependency neural network inference engine. Models are defined as a sequence of instructions that operate on computation buffers, enabling efficient memory reuse and predictable performance.
Key Features:
- Instruction-based execution model for neural network inference
- Support for common neural network operations (dot product, activations, attention, etc.)
- JSON serialization/deserialization for model configuration
- Built-in model validation
- Memory-efficient unified buffer architecture
Benchmarks
These benchmarks measure a simple 2-layer dense network:
- Model:
250 -> 300 -> 200(ReLUthenSigmoid) - Samples:
200,000 - Threads:
16(8 physical cores + hyperthreading) - Warmup: included
Performance (CPU: AMD Ryzen 9 5900HX)
| Implementation | Time | Inferences/sec |
|---|---|---|
| Rust (sequential) | 2.686s | 74,460 |
| Rust (parallel, default threads) | 0.355s | 563,516 |
TensorFlow CPU (batch_size=8192) |
0.458s | 436,261 |
Memory Footprint
| Implementation | Model (weights+bias) | Input + Output | Compute Buffers | Total |
|---|---|---|---|---|
| Rust (seq) | 529.3 KB | 343.3 MB | 2.9 KB | 343.8 MB |
| Rust (par) | 529.3 KB | 343.3 MB | 46.9 KB | 343.9 MB |
| TensorFlow | 529.3 KB | 343.3 MB | 23.4 MB | 367.3 MB |
Model weights are shared across all threads/batches (not replicated). Rust parallel uses 16× more compute buffer memory than sequential (one buffer per thread), but still 500× less than TensorFlow's batch buffer.
Note: On smaller models or fewer inferences, TensorFlow's performance degrades significantly due to Python/framework overhead, JIT compilation, and batch scheduling. Rust maintains consistent low-latency performance regardless of scale.
How to run
# Rust
# TensorFlow (CPU)
Quick Start
Simple Neural Network
use ;
// Define a simple single-layer neural network
// Input: 2 features -> Output: 1 value
let model_info = InstructionModelInfo ;
let model = new?;
// Run inference
let input = vec!;
let output = model.predict?;
println!;
// Or get a single output value directly
let result = model.predict_single?;
Multi-Layer Neural Network
use ;
// 2 inputs -> 2 hidden (ReLU) -> 1 output (Sigmoid)
let model_info = InstructionModelInfo ;
let model = new?;
let result = model.predict_single?;
Loading from JSON
Models can be defined in JSON format and loaded at runtime:
use ;
let json_config = r#"
{
"features": ["feature1", "feature2"],
"buffer_sizes": [2, 2, 1],
"instructions": [
{
"type": "DOT",
"input": 0,
"output": 1,
"weights": 0,
"activation": "RELU"
},
{
"type": "DOT",
"input": 1,
"output": 2,
"weights": 1,
"activation": "SIGMOID"
}
],
"weights": [
[[2.0, 0.5], [-2.0, -0.5]],
[[0.5, -1.0]]
],
"bias": [
[0.25, -0.25],
[2.0]
]
}
"#;
let model_info: InstructionModelInfo = from_str?;
let model = new?;
Logistic Regression
Create a logistic regression model directly from coefficients:
use ;
use HashMap;
let mut coefficients = new;
coefficients.insert;
coefficients.insert;
coefficients.insert; // bias term
let model_info = from_logistic_regression_model?;
let model = new?;
let probability = model.predict_single?;
Using the Builder Pattern
use ;
let model_info = builder
.feature_size
.computation_buffer_sizes
.instructions
.weights
.bias
.build?;
let model = new?;
Supported Operations
Activation Functions
| Activation | Description |
|---|---|
Relu |
f(x) = max(0, x) |
Sigmoid |
f(x) = 1 / (1 + exp(-x)) |
Softmax |
Numerically stable softmax over a buffer |
Tanh |
f(x) = tanh(x) |
Sqrt |
f(x) = sqrt(x) for x > 0, else 0 |
Log |
f(x) = ln(x + 1) for x > 0, else 0 |
Log10 |
f(x) = log10(x + 1) for x > 0, else 0 |
Inverse |
f(x) = 1 - x |
Instruction Types
| Instruction | JSON Type | Description |
|---|---|---|
| Dot Product | DOT |
Matrix multiplication with optional activation |
| Copy | COPY |
Copy buffer contents to another location |
| Copy Masked | COPY_MASKED |
Copy specific indices from a buffer |
| Activation | ACTIVATION |
Apply activation function in-place |
| Element-wise Add | ADD_ELEMENTWISE |
Add parameters element-wise |
| Element-wise Multiply | MUL_ELEMENTWISE |
Multiply by parameters element-wise |
| Buffers Add | ADD_ELEMENTWISE_BUFFERS |
Sum multiple buffers |
| Buffers Multiply | MULTIPLY_ELEMENTWISE_BUFFERS |
Multiply multiple buffers element-wise |
| Reduce Sum | REDUCE_SUM |
Sum all values in a buffer to a single value |
| Attention | ATTENTION |
Attention mechanism (linear + softmax + element-wise) |
| Map Transform | MAP_TRANSFORM |
Lookup and transform using a map |
Advanced Usage
External Buffer Management
For high-performance scenarios, you can manage the computation buffer yourself:
let model = new?;
// Allocate buffer once
let mut buffer = vec!;
// Reuse buffer for multiple predictions
for input in inputs
Parallel Prediction
For batch inference across multiple threads:
use ;
let model = new?;
// Flatten all inputs into a contiguous buffer
// For 1000 samples with 250 features each:
let inputs: = samples.iter.flatten.copied.collect;
// Default config uses all available CPU cores
let config = new;
let result = model.predict_parallel?;
// Access results
let all_outputs = result.as_slice;
let first_sample = result.get_result?;
// Copy to your own buffer
let mut my_buffer = vec!;
result.copy_results?;
With custom configuration:
let config = new
.with_threads // Use 8 threads
.with_slice_result_buffer; // Only return first 100 samples
let result = model.predict_parallel?;
GPU-Embeddable Inference (WGSL)
The library provides GPU-embeddable inference functions in WGSL that can be called from within your own GPU compute shaders. This is particularly useful for RL simulations where each episode runs in its own GPU thread.
Rust Side - Prepare the model:
use ;
// Convert your model to GPU format
let gpu_model = from_info?;
// Get the model data as bytes for GPU buffer
let model_bytes = gpu_model.as_bytes;
// Get WGSL shader code to include in your kernel
let wgsl_functions = get_instmodel_wgsl;
WGSL Side - Use in your compute shader:
// Your shader bindings
@group(0) @binding(0) var<storage, read> model_data: array<f32>;
@group(0) @binding(1) var<storage, read> inputs: array<f32>;
@group(0) @binding(2) var<storage, read_write> outputs: array<f32>;
// Include the generated instmodel functions (via string replacement at runtime)
// This provides: predict(), get_feature_size(), get_output_size(), get_output_start()
@compute @workgroup_size(256)
fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
let thread_id = global_id.x;
// Each thread has its own compute buffer (function-local)
var compute_buffer: array<f32, 1024>; // Size from gpu_model.compute_buffer_size()
// Model offset (0 for single model, or index into packed multi-model buffer)
let model_offset: u32 = 0u;
// Copy input to compute buffer
let feature_size = get_feature_size(model_offset);
let input_offset = thread_id * feature_size;
for (var i: u32 = 0u; i < feature_size; i = i + 1u) {
compute_buffer[i] = inputs[input_offset + i];
}
// Run inference - this executes all model instructions
predict(model_offset, &compute_buffer);
// Copy output from compute buffer
let output_start = get_output_start(model_offset);
let output_size = get_output_size(model_offset);
let output_offset = thread_id * output_size;
for (var i: u32 = 0u; i < output_size; i = i + 1u) {
outputs[output_offset + i] = compute_buffer[output_start + i];
}
}
Key GPU Functions Available:
| Function | Description |
|---|---|
predict(model_offset, &compute_buffer) |
Execute all model instructions |
get_feature_size(model_offset) |
Get input feature count |
get_output_size(model_offset) |
Get output size |
get_output_start(model_offset) |
Get output position in compute buffer |
get_compute_buffer_size(model_offset) |
Get required compute buffer size |
get_full_model_size(model_offset) |
Get total model size (for multi-model packing) |
Why GPU-Embedded Inference?
For RL and simulation workloads, the model data stays on GPU and each thread can call predict() multiple times per episode without CPU<->GPU transfers. This eliminates transfer overhead and enables massive parallelism across episodes.
Model Validation
Include validation data to verify model correctness on creation:
use ValidationData;
let model_info = InstructionModelInfo ;
// Model creation will fail if outputs don't match expected values
let model = new?;
Array Features
Features can specify array sizes using bracket notation:
let model_info = InstructionModelInfo ;
Architecture
The library uses a unified buffer architecture where all computation buffers are laid out contiguously in memory. Instructions read from and write to specific regions of this buffer:
┌─────────────┬─────────────┬─────────────┬─────────────┐
│ Buffer 0 │ Buffer 1 │ Buffer 2 │ Buffer 3 │
│ (Input) │ (Hidden) │ (Hidden) │ (Output) │
└─────────────┴─────────────┴─────────────┴─────────────┘
▲ │ │
└─────────────┴─────────────┘
Instructions operate on
buffer regions by index
License
MIT