# ONNX Runtime for Edge Deployment

**Last updated:** 2026-02
**Status:** GA
**Category:** Hybrid Cloud & Edge AI

---

## Introduksjon

ONNX Runtime er Microsofts open-source, hoyytelses inferensmotor for kjoring av maskinlaeringsmodeller i ONNX-format (Open Neural Network Exchange). Den er optimalisert for bade sky og edge, og stotter Linux, Windows og macOS pa tvers av CPU, GPU og NPU-akseleratorer. ONNX Runtime er innebygd i Windows som del av Windows ML og driver inferens i hoyskala Microsoft-tjenester som Bing, Office og Azure AI.

For edge-deployment er ONNX Runtime sarlig verdifull fordi den gir en enhetlig inferensmotor pa tvers av hardware-plattformer — fra kraftige edge-servere med GPU til ressursbegrensede IoT-enheter med kun CPU. Modeller fra PyTorch, TensorFlow, scikit-learn og andre rammeverk kan konverteres til ONNX-format og deretter optimaliseres for spesifikk target-hardware med Olive-verktoysettet.

For norsk offentlig sektor betyr ONNX Runtime at AI-modeller kan deployes lokalt uten skyavhengighet, noe som er viktig for datasuverenitetsscenarier, offline-drift, og miljoer med begrenset nettverkstilkobling.

---

## Kjernekomponenter

| Komponent | Formal | Teknologi |
|-----------|--------|-----------|
| ONNX Runtime | Inferensmotor for ONNX-modeller | C++/Python/C#/JS |
| ONNX Runtime GenAI | Generativ AI-inferens (LLM) | Python/C# |
| Olive | Modelloptimalisering og kompilering | Python CLI |
| Windows ML | ONNX Runtime integrert i Windows | Windows SDK |
| DirectML | Hardware-akselerasjon pa Windows | GPU EP |
| Execution Providers | Hardware-spesifikke akseleratorer | CPU/GPU/NPU |

---

## ONNX Model Conversion

### Konvertering fra populaere rammeverk

```python
# PyTorch til ONNX-konvertering
import torch
import onnx

def convert_pytorch_to_onnx(model, sample_input, output_path: str):
    """Konverter PyTorch-modell til ONNX-format"""
    model.eval()

    torch.onnx.export(
        model,
        sample_input,
        output_path,
        export_params=True,
        opset_version=17,
        do_constant_folding=True,
        input_names=['input'],
        output_names=['output'],
        dynamic_axes={
            'input': {0: 'batch_size'},
            'output': {0: 'batch_size'}
        }
    )

    # Valider ONNX-modell
    onnx_model = onnx.load(output_path)
    onnx.checker.check_model(onnx_model)
    print(f"ONNX-modell lagret: {output_path}")
    print(f"Modellstorrelse: {os.path.getsize(output_path) / 1024 / 1024:.1f} MB")
```

```python
# TensorFlow/Keras til ONNX med tf2onnx
import tf2onnx
import tensorflow as tf

def convert_tensorflow_to_onnx(saved_model_path: str, output_path: str):
    """Konverter TensorFlow SavedModel til ONNX"""
    model_proto, _ = tf2onnx.convert.from_saved_model(
        saved_model_path,
        output_path=output_path,
        opset=17
    )
    print(f"Konvertert TensorFlow-modell til {output_path}")
```

```python
# scikit-learn til ONNX med skl2onnx
from skl2onnx import convert_sklearn
from skl2onnx.common.data_types import FloatTensorType

def convert_sklearn_to_onnx(model, n_features: int, output_path: str):
    """Konverter scikit-learn-modell til ONNX"""
    initial_type = [('input', FloatTensorType([None, n_features]))]
    onnx_model = convert_sklearn(model, initial_types=initial_type)

    with open(output_path, "wb") as f:
        f.write(onnx_model.SerializeToString())
```

### Olive-basert optimalisering

```bash
# Olive: Automatisk modelloptimalisering for target-hardware
pip install olive-ai

# Konverter og optimaliser Phi-3 for CPU edge deployment
olive run \
  --model microsoft/Phi-3-mini-4k-instruct \
  --output-dir ./optimized-model \
  --device cpu \
  --precision int4 \
  --passes onnx_conversion,onnx_quantization,ort_optimization
```

```json
// olive-config.json for edge-optimalisering
{
  "input_model": {
    "type": "HfModel",
    "model_path": "microsoft/Phi-3-mini-4k-instruct"
  },
  "systems": {
    "local": {
      "type": "LocalSystem",
      "accelerators": [{"device": "cpu"}]
    }
  },
  "passes": {
    "conversion": {
      "type": "OnnxConversion",
      "target_opset": 17
    },
    "quantization": {
      "type": "OnnxQuantization",
      "quant_mode": "dynamic",
      "weight_type": "QInt4",
      "calibration_data_config": {
        "name": "my_calibration_dataset"
      }
    },
    "optimization": {
      "type": "OrtTransformersOptimization",
      "model_type": "gpt2",
      "opt_level": 2,
      "float16": false
    }
  },
  "engine": {
    "evaluator": {
      "metrics": [
        {"name": "latency", "type": "latency", "priority": 1},
        {"name": "accuracy", "type": "accuracy", "priority": 2}
      ]
    }
  }
}
```

---

## Hardware Acceleration (GPU/NPU)

### Execution Provider-oversikt

| Execution Provider | Hardware | Plattform | Brukstilfelle |
|-------------------|----------|-----------|---------------|
| CPUExecutionProvider | Alle CPU-er | Alle | Baseline, alltid tilgjengelig |
| CUDAExecutionProvider | NVIDIA GPU | Linux/Windows | Hoy-ytelse GPU-inferens |
| TensorrtExecutionProvider | NVIDIA GPU | Linux | Lavest latens GPU-inferens |
| DirectMLExecutionProvider | GPU/NPU | Windows | Windows-universal akselerasjon |
| OpenVINOExecutionProvider | Intel CPU/GPU/NPU | Linux/Windows | Intel-optimalisert |
| QNNExecutionProvider | Qualcomm NPU | Windows ARM64 | Snapdragon AI akselerasjon |
| AzureExecutionProvider | Azure AI | Cloud | Sky-basert inferens |

### GPU-akselerert inferens

```python
# NVIDIA GPU-akselerert inferens med ONNX Runtime
import onnxruntime as ort

def create_gpu_session(model_path: str) -> ort.InferenceSession:
    """Opprett GPU-akselerert ONNX Runtime-session"""
    session_options = ort.SessionOptions()
    session_options.graph_optimization_level = ort.GraphOptimizationLevel.ORT_ENABLE_ALL
    session_options.enable_mem_pattern = True

    # Prioriter GPU, fall tilbake til CPU
    providers = [
        ('CUDAExecutionProvider', {
            'device_id': 0,
            'arena_extend_strategy': 'kNextPowerOfTwo',
            'gpu_mem_limit': 4 * 1024 * 1024 * 1024,  # 4 GB
            'cudnn_conv_algo_search': 'EXHAUSTIVE',
            'do_copy_in_default_stream': True
        }),
        'CPUExecutionProvider'
    ]

    session = ort.InferenceSession(
        model_path,
        sess_options=session_options,
        providers=providers
    )

    # Verifiser at GPU brukes
    active_provider = session.get_providers()[0]
    print(f"Aktiv provider: {active_provider}")

    return session
```

### Windows ML med automatisk EP-discovery

```csharp
// Windows ML med automatisk hardware-deteksjon
using Microsoft.ML.OnnxRuntime;

public class WindowsMLInference
{
    private InferenceSession _session;

    public async Task InitializeAsync(string modelPath)
    {
        var sessionOptions = new SessionOptions();

        // Windows ML velger automatisk beste EP
        // Qualcomm NPU → Intel OpenVINO → DirectML GPU → CPU
        sessionOptions.AppendExecutionProvider_WindowsML();

        _session = new InferenceSession(modelPath, sessionOptions);

        // Logg valgt EP
        var providers = _session.GetAvailableProviders();
        Console.WriteLine($"Tilgjengelige providers: {string.Join(", ", providers)}");
    }

    public float[] RunInference(float[] input, int[] dimensions)
    {
        var inputTensor = new DenseTensor<float>(input, dimensions);
        var inputs = new List<NamedOnnxValue>
        {
            NamedOnnxValue.CreateFromTensor("input", inputTensor)
        };

        using var results = _session.Run(inputs);
        return results.First().AsTensor<float>().ToArray();
    }
}
```

---

## Cross-Platform Compatibility

### Deployment-matrise

| Plattform | OS | Arkitektur | Stoettede EP-er | Brukstilfelle |
|-----------|-----|------------|-----------------|---------------|
| Edge server | Linux | x64 | CUDA, TensorRT, CPU | Hoyytelse-inferens |
| Edge server | Windows | x64 | DirectML, CUDA, CPU | Windows-basert edge |
| IoT Gateway | Linux | ARM64 | CPU, OpenVINO | Lettvekt-inferens |
| Copilot+ PC | Windows | ARM64 | QNN (NPU), DirectML | Klient-AI |
| Azure Local | Linux | x64 | CUDA, CPU | On-premises |
| Raspberry Pi | Linux | ARM64 | CPU | Prototype/test |

### Cross-platform deployment med Docker

```dockerfile
# Multi-platform ONNX Runtime edge container
FROM --platform=$TARGETPLATFORM mcr.microsoft.com/onnxruntime/server:latest

# Kopier optimalisert modell
COPY ./models/optimized_model.onnx /models/model.onnx

# Konfigurasjon
ENV MODEL_PATH=/models/model.onnx
ENV HTTP_PORT=8001

# Helsesjekkek
HEALTHCHECK --interval=30s --timeout=5s \
  CMD curl -f http://localhost:${HTTP_PORT}/health || exit 1

EXPOSE ${HTTP_PORT}
CMD ["--model_path", "/models/model.onnx", "--http_port", "8001"]
```

```yaml
# Multi-arch build for edge deployment
# docker buildx build --platform linux/amd64,linux/arm64 -t myregistry/inference:v1 .
apiVersion: apps/v1
kind: Deployment
metadata:
  name: onnx-inference-edge
spec:
  replicas: 1
  template:
    spec:
      containers:
        - name: inference
          image: myregistry/inference:v1
          resources:
            requests:
              memory: "512Mi"
              cpu: "500m"
            limits:
              memory: "2Gi"
              cpu: "2"
              nvidia.com/gpu: "1"  # Valgfritt, kun pa GPU-noder
          ports:
            - containerPort: 8001
```

---

## Performance Profiling

### Ytelsesanalyse-verktoy

| Verktoy | Formal | Plattform |
|---------|--------|-----------|
| ONNX Runtime Profiler | Session-level profilering | Alle |
| Windows Performance Analyzer | System-wide AI-analyse | Windows |
| Netron | Modellvisualisering og inspeksjon | Alle |
| Olive Benchmarking | Automatisert ytelses-benchmarking | Alle |
| NVIDIA Nsight | GPU-profilering | NVIDIA |

### Profilering med ONNX Runtime

```python
# Ytelsesprofilering av ONNX-modell
import onnxruntime as ort
import numpy as np
import time

class ONNXProfiler:
    def __init__(self, model_path: str):
        self.options = ort.SessionOptions()
        self.options.enable_profiling = True
        self.options.profile_file_prefix = "onnx_profile"

        self.session = ort.InferenceSession(
            model_path,
            sess_options=self.options
        )

    def benchmark(self, input_data: dict, iterations: int = 100) -> dict:
        """Kjor benchmark med detaljerte tidsmalinger"""
        # Warmup
        for _ in range(10):
            self.session.run(None, input_data)

        # Benchmark
        latencies = []
        for _ in range(iterations):
            start = time.perf_counter_ns()
            self.session.run(None, input_data)
            end = time.perf_counter_ns()
            latencies.append((end - start) / 1e6)  # ms

        # Stopp profilering og lagre rapport
        profile_path = self.session.end_profiling()

        return {
            "mean_latency_ms": np.mean(latencies),
            "p50_latency_ms": np.percentile(latencies, 50),
            "p95_latency_ms": np.percentile(latencies, 95),
            "p99_latency_ms": np.percentile(latencies, 99),
            "throughput_qps": 1000 / np.mean(latencies),
            "iterations": iterations,
            "profile_file": profile_path,
            "providers": self.session.get_providers()
        }
```

---

## Norsk offentlig sektor

### Fordeler med ONNX Runtime for offentlig sektor

- **Leverandoruavhengighet**: ONNX er et apent format — modeller er portable mellom plattformer og leverandorer
- **Lokal deployment**: Kjor modeller lokalt uten skyavhengighet, viktig for datasuverenitet
- **Cross-platform**: Samme modell kan kjores pa server, edge-gateway, og klientenhet
- **Kostnadseffektivt**: Ingen per-inferens-kostnader, kun infrastrukturkostnader

### Anbefalt deployment-pipeline

1. Tren modell i Azure ML (sky)
2. Konverter til ONNX med Olive
3. Kvantiser til INT4/INT8 for target-hardware
4. Valider ytelse med benchmarking
5. Deploy via container til AKS Edge eller direkte til device
6. Overvak med Application Insights

---

## Beslutningsrammeverk

| Scenario | Anbefaling | Begrunnelse |
|----------|------------|-------------|
| Windows-klient med NPU | Windows ML (automatisk EP) | Enklest, best integrasjon |
| NVIDIA GPU edge server | CUDA EP + TensorRT | Lavest latens |
| Intel-basert edge | OpenVINO EP | Intel-optimalisert |
| ARM64 IoT gateway | CPU EP med INT4-kvantisering | Minst ressursbruk |
| Cross-platform deployment | Docker + CPU EP | Maksimal portabilitet |
| Azure Local | CUDA EP i Kubernetes | Enterprise-skalerbart |

---

## For Cosmo

- **ONNX Runtime er den universelle inferensmotoren** for Microsoft-okosystemet — anbefal det som standard for alle edge AI-deployments pa grunn av cross-platform-stoette og hardware-akselerasjon
- **Olive er det foretrukne verktoeyet for modelloptimalisering** — det automatiserer konvertering, kvantisering og optimalisering i en pipeline og sikrer at modellen er optimalisert for spesifikk target-hardware
- **Windows ML erstatter DirectML** som anbefalt tilnaerming pa Windows — det abstraherer EP-management og velger automatisk beste akselerator (NPU, GPU, CPU)
- **INT4-kvantisering via Olive gir 5-8x stoerrelses-reduksjon** med minimalt noyaktighetstap — dette er kritisk for edge-deployment der minne og lagring er begrenset
- **For norsk offentlig sektor: ONNX-format sikrer leverandoeruavhengighet** som kreves av Digdirs arkitekturprinsipper — modeller kan flyttes mellom Azure, on-premises, og andre skyleverandoerer uten endring
