ms-ai-architect/skills/ms-ai-infrastructure/references/hybrid-edge/onnx-runtime-edge-deployment.md
Kjell Tore Guttormsen 3a73eeafdc refactor(ms-ai-architect): R13 del 1 — nøytraliser Cosmo-personaen i ref-korpusets headinger, etter å ha rettet en gate som var målt usann to ganger
Ordre 20260912T193441Z-7358817909. Steg 1 var ikke transformen, men å rette
roadmapens R13-gate og få den ratifisert. Gaten `grep -rl "Cosmo"
skills/*/references -> 0` var usann på to uavhengige måter:

1. Ordren fanget den første: 451 av forekomstene er Azure Cosmos DB, ekte
   produktinnhold. Diskriminatoren er ikke bokstaven «s» — `Cosmos <norsk
   substantiv>` er genitiv av personaen (`### Cosmos tonalitet`), mens
   `Cosmos DB`/`CosmosClient`/`cosmos_ru` er produkt.
2. Denne økten fant den andre: 132 persona-forekomster ligger i prosa,
   tabeller, dialog-replikker og proveniens-linjer. Heading-nøytralisering
   kan ikke nå dem, så «0 persona» er uoppnåelig også under den ratifiserte
   formen. Operatøren ratifiserte alternativ A: gaten speiler formen, og de
   132 bokføres til R13b/R14.

Tre korreksjoner av premisser som sto i ordren og STATE:
  «ca 320 produkt»   -> 451 (case-sensitivt nett manglet 327 lowercase
                        TOC-ankre + 99 identifikatorer; sann nevner 1 638)
  «169 headinger»    -> 401. 169 var `^## For Cosmo`-prefikset (168) og var
                        internt inkonsistent med sin egen topp-variant (204)
  «417 matcher ingen
   populasjon»       -> 417 er cosmo-headinger utenfor kodefences; briefens
                        nevner var reell hele tiden

Fence-bevissthet er målt skadelig, ikke nødvendig: begge toggle-regler er
gale på dette korpuset (naiv toggle skjuler en ekte heading i
chain-of-thought-prompting.md, CommonMark-regelen ubalanserer
service-level-documentation-dr.md). Fence-agnostisk deteksjon finner 401
heading-linjer i nøyaktig de samme 40 variantene som fence-bevisst finner
400 i — ingen kodeblokk-linje er byte-identisk til en persona-heading. Derfor
nøkles transformen på 40 enumererte heading-tekster og ignorerer fences. En
ukjent variant kaster; en slug-kollisjon kaster. Ingenting auto-fikses.

TOC-en regenereres ikke, den rettes kirurgisk: alle 327 persona-lenker hadde
lenketekst lik én av de 40 heading-tekstene og anker lik slugify av den
(327/327, 0 avvik), så heading og TOC-entry skrives i samme operasjon og
ingen mellomtilstand etterlater en død lenke.

Ratifisert målform: `For Cosmo`, `For Cosmo Skyberg` og `For arkitekten
(Cosmo)` konvergerer på `For arkitekten`. To filer kolliderte og er adjudisert
ved å lese dem, ikke ved regel.

Verifisering (alle 7 kriterier fra ordren):
  G1 persona på heading-linjer   401 -> 0
  G2 døde fragmentlenker         1 -> 1 (pre-eksisterende, unntatt)
  G3 produkt-forekomster         451 -> 451; `Cosmos DB|Azure Cosmos` 308 = 308
  de 3 kun-produkt-filene        byte-identiske
  nettet validert begge veier    injisert persona feller G1; genitiv feller G1;
                                 produkt-heading og de 3 filene passerer
  hele diffen                    802 heading-linjer + 654 TOC-linjer, ANNET = 0
  linjeantall                    728 lagt til = 728 slettet
  suite                          1120/1120 (1097 + 23 nye)
  validate-plugin                250 PASS / 0 FAIL
  stikkprøve                     10 filer, alle 5 skills, inkl. de 3 mest
                                 produkt-tunge (26/20/19) — kun heading+TOC

Utenfor scope, urørt: de 4 SKILL.md, de 23 commands, CLAUDE.md, README.md,
NOTICE.md, docs/ (alt R14).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 22:12:28 +02:00

14 KiB

ONNX Runtime for Edge Deployment

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


Innhold

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

# 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")
# 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}")
# 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

# 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
// 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

# 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

// 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

# 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"]
# 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

# 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 arkitekten

  • 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