---
title: "Getting started with OneModel"
url: https://recursiveai.org/onemodel/docs/getting-started/
description: "Install the OneModel preview for .NET 10, run an ONNX model with one call, read its inputs and outputs, and see which kernels it picked. No native…"
version: "0.3.0-preview.1"
---

# Getting started with OneModel

Install the OneModel preview for .NET 10, run an ONNX model with one call, read its inputs and outputs, and see which kernels it picked. No native binaries, no ONNX Runtime.

## Install

OneModel targets `net10.0`, so you need the .NET 10 SDK. It is a preview: this guide uses 0.3.0-preview.1, and the API may change before 1.0.

```shell
dotnet new console -o OneModelStart
cd OneModelStart
dotnet add package RecursiveAI.OneModel --version 0.3.0-preview.1
```

The package has no dependency beyond the .NET base class library and contains no native code. It works under NativeAOT and trimming; for a NativeAOT build, see [publishing with the right instruction set](https://recursiveai.org/onemodel/docs/overview/#nativeaot-users-set-ilcinstructionset).

## The sample models

The guide and the [cookbook](https://recursiveai.org/onemodel/cookbook/) use three small models made with the `onnx` Python package (`pip install onnx numpy`), so the outputs below can be reproduced exactly. Any float32 ONNX model with one input and one output works the same way. `models.py`:

```python
import numpy as np, onnx
from onnx import helper as h, TensorProto as T, numpy_helper as nh

rng = np.random.default_rng(7)

def w(name, *shape):
    return nh.from_array(rng.standard_normal(shape).astype(np.float32) * 0.5, name)

# classifier.onnx: 4 features -> 8 hidden (Relu) -> 3 classes (Softmax)
g = h.make_graph(
    [h.make_node("Gemm", ["x", "W1", "b1"], ["h"], transB=1),
     h.make_node("Relu", ["h"], ["hr"]),
     h.make_node("Gemm", ["hr", "W2", "b2"], ["logits"], transB=1),
     h.make_node("Softmax", ["logits"], ["probs"], axis=1)],
    "classifier",
    [h.make_tensor_value_info("x", T.FLOAT, ["batch", 4])],
    [h.make_tensor_value_info("probs", T.FLOAT, ["batch", 3])],
    [w("W1", 8, 4), w("b1", 8), w("W2", 3, 8), w("b2", 3)])
m = h.make_model(g, opset_imports=[h.make_opsetid("", 17)], ir_version=8)
onnx.checker.check_model(m)
onnx.save(m, "classifier.onnx")

# scorer.onnx: two named inputs, two outputs
g = h.make_graph(
    [h.make_node("MatMul", ["features", "W"], ["proj"]),
     h.make_node("Add", ["proj", "bias"], ["score"]),
     h.make_node("ReduceMax", ["score"], ["best"], axes=[1], keepdims=0)],
    "scorer",
    [h.make_tensor_value_info("features", T.FLOAT, ["batch", 3]),
     h.make_tensor_value_info("bias", T.FLOAT, [1, 2])],
    [h.make_tensor_value_info("score", T.FLOAT, ["batch", 2]),
     h.make_tensor_value_info("best", T.FLOAT, ["batch"])],
    [nh.from_array(np.array([[1, 0], [0, 1], [1, 1]], np.float32), "W")])
m = h.make_model(g, opset_imports=[h.make_opsetid("", 13)], ir_version=8)
onnx.checker.check_model(m)
onnx.save(m, "scorer.onnx")

# wide.onnx: a larger float32 model for half-precision weight storage (256 -> 512 -> 64)
g = h.make_graph(
    [h.make_node("MatMul", ["x", "W1"], ["h"]),
     h.make_node("Relu", ["h"], ["hr"]),
     h.make_node("MatMul", ["hr", "W2"], ["y"])],
    "wide",
    [h.make_tensor_value_info("x", T.FLOAT, [1, 256])],
    [h.make_tensor_value_info("y", T.FLOAT, [1, 64])],
    [nh.from_array((rng.standard_normal((256, 512)) * 0.05).astype(np.float32), "W1"),
     nh.from_array((rng.standard_normal((512, 64)) * 0.05).astype(np.float32), "W2")])
m = h.make_model(g, opset_imports=[h.make_opsetid("", 17)], ir_version=8)
onnx.checker.check_model(m)
onnx.save(m, "wide.onnx")
print("ok")
```

`classifier.onnx` takes four features and returns three class probabilities. Run `python3 models.py` and copy `classifier.onnx` next to `Program.cs`.

## Run a model

`Model.Load` reads the file and builds a session; `Run` takes the input values in row-major order and returns the output as a new array. Names and shapes come from the model. Here the model declares its input as `[batch, 4]`, so four values are one row:

```csharp
using RecursiveAI.OneModel;

using var model = Model.Load("classifier.onnx");

float[] features = [5.1f, 3.5f, 1.4f, 0.2f];
float[] probs = model.Run(features);

Console.WriteLine(string.Join(", ", probs.Select(p => p.ToString("F4"))));
Console.WriteLine($"Kernels: {model.Session.KernelPath}");
foreach (var input in model.Session.Inputs)
    Console.WriteLine($"Input {input.Name}: {input.DType}, rank {input.Rank}");
```

```text
0.2323, 0.2813, 0.4864
Kernels: Avx512
Input x: F32, rank 2
```

`KernelPath` says which kernels the session chose from the hardware at start-up: `Avx512`, `Avx2`, `Neon`, `Portable128` or `Scalar`. On another machine it may differ; in the default fast mode the results then agree to within rounding, and in [exact mode](https://recursiveai.org/onemodel/cookbook/exact-mode/) they are the same bits.

## What `Run` accepts

- `float[]`, `long[]` (token ids) and `int[]` inputs, with an optional shape: `model.Run(values, [2, 4])` for two rows.
- A span form, `Run<TIn, TOut>(input, shape, output)`, that writes into your buffer and allocates nothing once the model has run once with that shape.
- One input and one output. For several of either, named tensors, or options such as exact mode, use `model.Session` or `Session.Load`: see [Named inputs and outputs](https://recursiveai.org/onemodel/cookbook/named-inputs-and-outputs/).

`Run` may be called from any number of threads at once. Fast-mode results don’t depend on the thread count.

## When a model doesn’t load

A model that uses an operator OneModel doesn’t implement fails in `Model.Load` with a `SessionException` that lists every missing operator at once, not the first one it meets: see [When a model won’t load](https://recursiveai.org/onemodel/cookbook/missing-operators/). Which operators pass the ONNX backend tests is in [conformance](https://recursiveai.org/onemodel/docs/conformance/).

## Next

- [Exact mode](https://recursiveai.org/onemodel/cookbook/exact-mode/): the same bits on every platform and thread count.
- [The OneModel format](https://recursiveai.org/onemodel/cookbook/convert-to-onemodel-format/): convert an ONNX file once and load it as memory-mapped weights.
- [Half-precision weights](https://recursiveai.org/onemodel/cookbook/half-precision-weights/): halve the memory of large weights.
- [Sessions and plans](https://recursiveai.org/onemodel/docs/graph-runtime/): how a model is planned, cached and run.
