---
title: "Run an ONNX model in C#"
url: https://recursiveai.org/onemodel/cookbook/run-onnx-model/
description: "Run an ONNX model in C# with no ONNX Runtime and no native binaries: load the file, pass a float array, read the output. Runnable code on a public MNIST model, with OneModel (preview)."
version: "0.3.0-preview.1"
---

# Run an ONNX model in C#

Load the `.onnx` file with `Model.Load`, pass the input as a `float[]` with its shape, and read the output array. The program below runs the MNIST digit classifier from the ONNX model zoo on a handwritten “7” from the MNIST test set. OneModel is pure managed C#: no ONNX Runtime, no native libraries.

```shell
dotnet new console -o RunOnnx && cd RunOnnx
dotnet add package RecursiveAI.OneModel --version 0.3.0-preview.1
dotnet add package RecursiveAI.OneImage --version 1.10.4
curl -LO https://github.com/onnx/models/raw/main/validated/vision/classification/mnist/model/mnist-12.onnx
curl -O https://recursiveai.org/onemodel/samples/digit.png
```

Put this in `Program.cs` and run `dotnet run`:

```csharp
using OneImage;
using RecursiveAI.OneModel;

using var model = Model.Load("mnist-12.onnx");
foreach (var i in model.Session.Inputs)
    Console.WriteLine($"Input  {i.Name}: {i.DType} [{string.Join(", ", i.Dims)}]");
foreach (var o in model.Session.Outputs)
    Console.WriteLine($"Output {o.Name}: {o.DType} [{string.Join(", ", o.Dims)}]");

// 28 x 28 gray pixels, 0 to 255, white on black: what this model was trained on on
Gray8[] pixels = Image.Load("digit.png").ToArray<Gray8>();
float[] input = pixels.Select(p => (float)p.V).ToArray();

float[] scores = model.Run(input, [1, 1, 28, 28]);   // one score per digit, 0 to 9

int digit = Array.IndexOf(scores, scores.Max());
Console.WriteLine($"Predicted digit: {digit}");
Console.WriteLine($"Scores: {string.Join(", ", scores.Select(s => $"{s:F0}"))}");
```

```text
Input  Input3: F32 [1, 1, 28, 28]
Output Plus214_Output_0: F32 [1, 10]
Predicted digit: 7
Scores: -553, 138, 2179, 2320, -3467, -1778, -6442, 8063, -1860, 1034
```

`Model.Load` reads the ONNX file and plans it for this CPU; `Run` takes the values in row-major order and returns the model’s output as a new array. This model returns ten raw scores, one per digit, and the highest wins; ONNX Runtime gives the same ten scores for this image, to the nearest whole number. Load the model once and call `Run` as often as you like, from any number of threads.

## Inputs, shapes and outputs

- `model.Session.Inputs` and `Outputs` give each tensor’s name, element type and dimensions, read from the model. A named dimension such as `batch` takes any size.
- `Run` accepts `float[]`, `long[]` (token ids) and `int[]`, and an optional shape: leave it out when the model’s input shape is fixed except for its first dimension.
- A span form, `model.Run<float, float>(input, shape, output)`, writes into your buffer and allocates nothing once warm.
- For a model with several inputs or outputs, use a `Session`: see [Run an ONNX model with multiple inputs](https://recursiveai.org/onemodel/cookbook/named-inputs-and-outputs/).

## Limits

- **OneModel is a preview** (0.3.0-preview.1, .NET 10). The API may change before 1.0, and there is no GPU backend: it runs on SIMD CPU kernels.
- **Not every operator is implemented.** A model that needs a missing one fails in `Model.Load` with every missing operator listed: see [When an ONNX model won’t load](https://recursiveai.org/onemodel/cookbook/missing-operators/). Coverage is in [conformance](https://recursiveai.org/onemodel/docs/conformance/).
- **Preprocessing is yours.** OneModel runs the graph; resizing, normalizing and tokenizing happen in your code, exactly as the model was trained. Here OneImage decodes the PNG; this model wants unscaled 0 to 255 values.
- **Inference only.** Training isn’t in this preview.

For bit-identical results on every machine, see [Deterministic ONNX inference](https://recursiveai.org/onemodel/cookbook/exact-mode/). Everything else starts in [getting started](https://recursiveai.org/onemodel/docs/getting-started/).
