# 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(input, dimensions); var inputs = new List { NamedOnnxValue.CreateFromTensor("input", inputTensor) }; using var results = _session.Run(inputs); return results.First().AsTensor().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