Steg 9 (R4): unified migrate-corpus.mjs --write over engineering/governance/ infrastructure/security. 327 filer mutert, verified=null, prosa byte-identisk (fra første ## seksjon), advisor urørt (0 endringer). To applier-fixes oppdaget under kjøring (TDD, RED→GREEN): - insertHeaderFields: anker faller nå tilbake når en meta-linje selv passerer 500B (2 filer pakket et avsnitt i **Status:** → Type/Source landet utenfor scan-vinduet, applierens post-write-assertion fanget + restaurerte). - normalizeStaleVerified: fjerner nå ALLE stale non-date **Verified:** i 500B-vinduet, inkl. stray body-dup rett under --- (9 mlops-genaiops-filer var ellers falskt "verified"/fresh, droppet fra worklist). Operatør-godkjent utvidelse av carve-out; kun stray metadata-linjer, aldri prosa. test-transform-criterion: precondition oppdatert til post-migrasjons-sannhet (fila bærer nå Source). Suite 728/728 grønn.
494 lines
16 KiB
Markdown
494 lines
16 KiB
Markdown
# Edge AI Inferencing Patterns
|
|
|
|
**Last updated:** 2026-02
|
|
**Status:** GA
|
|
**Category:** Hybrid Cloud & Edge AI
|
|
**Type:** reference
|
|
|
|
---
|
|
|
|
## Innhold
|
|
|
|
- [Introduksjon](#introduksjon)
|
|
- [Model Quantization og Compression](#model-quantization-og-compression)
|
|
- [Real-time Inference Acceleration](#real-time-inference-acceleration)
|
|
- [Caching Patterns for Edge](#caching-patterns-for-edge)
|
|
- [Batching vs. Streaming Inference](#batching-vs-streaming-inference)
|
|
- [IoT Edge ML Inference Pattern](#iot-edge-ml-inference-pattern)
|
|
- [Ytelsesreferanser](#ytelsesreferanser)
|
|
- [For Cosmo](#for-cosmo)
|
|
|
|
## Introduksjon
|
|
|
|
Edge AI-inferens handler om a kjore maskinlaeringsmodeller naermest mulig der data oppstar — pa enheter, gateways, lokale servere eller Azure Local-klynger. For norsk offentlig sektor er dette relevant i scenarioer som sanntids videoanalyse, dokumentbehandling i felt, naturspraakbehandling offline, og autonome systemer i omrader med begrenset nettverkstilkobling.
|
|
|
|
Microsoft tilbyr et bredt spekter av verktoy for edge-inferens: ONNX Runtime som universell inferensmotor, Azure IoT Edge for container-baserte modeller, Azure Stack Edge for hardware-akselerert inferens, og KAITO for LLM-deployment pa Kubernetes. Valget av moenster avhenger av modellstorrelse, latenskrav, tilgjengelig hardware og tilkoblingsstatus.
|
|
|
|
Denne referansen dekker de viktigste moensterne for modelloptimalisering, akselerasjon, caching og batching/streaming — alle med fokus pa Microsoft Azure-okosystemet og relevans for offentlig sektor.
|
|
|
|
---
|
|
|
|
## Model Quantization og Compression
|
|
|
|
### Hva er kvantisering?
|
|
|
|
Kvantisering reduserer presisjonen til modellvekter fra hoyere til lavere bit-representasjoner, noe som reduserer modellstorrelse og oker inferenshastighet med minimalt noyaktighetstap.
|
|
|
|
| Presisjon | Bits | Storrelse (7B modell) | Hastighet | Noyaktighet |
|
|
|-----------|------|----------------------|-----------|-------------|
|
|
| FP32 | 32 | ~28 GB | Baseline | 100% |
|
|
| FP16 | 16 | ~14 GB | 2x | ~99.9% |
|
|
| BF16 | 16 | ~14 GB | 2x | ~99.9% |
|
|
| INT8 | 8 | ~7 GB | 3-4x | ~99% |
|
|
| INT4 | 4 | ~3.5 GB | 5-8x | ~97% |
|
|
|
|
### Kvantiseringsmetoder i Azure-okosystemet
|
|
|
|
| Metode | Verktoy | Best for | Presisjon |
|
|
|--------|---------|----------|-----------|
|
|
| Post-Training Quantization (PTQ) | ONNX Runtime, Olive | Rask konvertering | INT8/INT4 |
|
|
| Quantization-Aware Training (QAT) | PyTorch + Azure ML | Hoyest noyaktighet | INT8 |
|
|
| GPTQ | HuggingFace + KAITO | LLM-kvantisering | INT4 |
|
|
| AWQ | HuggingFace + KAITO | LLM-kvantisering | INT4 |
|
|
| Dynamic Quantization | ONNX Runtime | CPU-inferens | INT8 |
|
|
|
|
### ONNX Runtime-kvantisering
|
|
|
|
```python
|
|
# Kvantiser ONNX-modell til INT8
|
|
from onnxruntime.quantization import quantize_dynamic, QuantType
|
|
|
|
quantize_dynamic(
|
|
model_input="model_fp32.onnx",
|
|
model_output="model_int8.onnx",
|
|
weight_type=QuantType.QInt8,
|
|
optimize_model=True
|
|
)
|
|
```
|
|
|
|
### Olive — Microsofts modelloptimalisering
|
|
|
|
Olive er Microsofts verktoy for helhetlig modelloptimalisering:
|
|
|
|
```python
|
|
# olive_config.json
|
|
{
|
|
"input_model": {
|
|
"type": "OnnxModel",
|
|
"model_path": "model.onnx"
|
|
},
|
|
"systems": {
|
|
"local_system": {
|
|
"type": "LocalSystem",
|
|
"accelerators": [{"device": "npu"}]
|
|
}
|
|
},
|
|
"passes": {
|
|
"quantization": {
|
|
"type": "OnnxQuantization",
|
|
"config": {
|
|
"quant_mode": "static",
|
|
"quant_format": "QDQ",
|
|
"calibration_data_reader": "CalibrationDataReader"
|
|
}
|
|
},
|
|
"perf_tuning": {
|
|
"type": "OrtPerfTuning",
|
|
"config": {
|
|
"data_dir": "./calibration_data"
|
|
}
|
|
}
|
|
},
|
|
"engine": {
|
|
"search_strategy": {
|
|
"execution_order": "joint",
|
|
"search_algorithm": "exhaustive"
|
|
},
|
|
"output_dir": "./optimized"
|
|
}
|
|
}
|
|
```
|
|
|
|
### Modellkomprimering
|
|
|
|
| Teknikk | Beskrivelse | Storrelsereduksjon | Noyaktighetstap |
|
|
|---------|-------------|-------------------|-----------------|
|
|
| Pruning | Fjerner uvesentlige vekter | 30-70% | 1-3% |
|
|
| Knowledge Distillation | Laerer liten modell fra stor | 50-90% | 2-5% |
|
|
| Weight Sharing | Deler vekter mellom lag | 20-40% | <1% |
|
|
| Low-Rank Factorization | Dekomponerer vektmatriser | 30-50% | 1-2% |
|
|
|
|
---
|
|
|
|
## Real-time Inference Acceleration
|
|
|
|
### ONNX Runtime Execution Providers
|
|
|
|
ONNX Runtime stotter flere hardware-akseleratorer gjennom Execution Providers (EP):
|
|
|
|
| Execution Provider | Hardware | Best for | Latens |
|
|
|--------------------|----------|----------|--------|
|
|
| CPU EP | x86/ARM CPU | Universell | Basis |
|
|
| CUDA EP | NVIDIA GPU | GPU-inferens | 5-50x raskere |
|
|
| TensorRT EP | NVIDIA GPU | Optimalisert GPU | 10-100x raskere |
|
|
| OpenVINO EP | Intel CPU/GPU/VPU | Intel-optimalisert | 3-20x raskere |
|
|
| DirectML EP | Windows GPU/NPU | Windows-enheter | 5-30x raskere |
|
|
| QNN EP | Qualcomm NPU | Snapdragon-enheter | 10-50x raskere |
|
|
|
|
### GPU-akselerert inferens med ONNX Runtime
|
|
|
|
```python
|
|
import onnxruntime as ort
|
|
|
|
# Konfigurasjon for NVIDIA GPU (TensorRT)
|
|
session_options = ort.SessionOptions()
|
|
session_options.graph_optimization_level = \
|
|
ort.GraphOptimizationLevel.ORT_ENABLE_ALL
|
|
|
|
providers = [
|
|
('TensorrtExecutionProvider', {
|
|
'trt_max_workspace_size': 2147483648, # 2 GB
|
|
'trt_fp16_enable': True,
|
|
'trt_engine_cache_enable': True,
|
|
'trt_engine_cache_path': './trt_cache'
|
|
}),
|
|
('CUDAExecutionProvider', {
|
|
'device_id': 0,
|
|
'arena_extend_strategy': 'kSameAsRequested',
|
|
'gpu_mem_limit': 4 * 1024 * 1024 * 1024, # 4 GB
|
|
'cudnn_conv_algo_search': 'DEFAULT'
|
|
}),
|
|
'CPUExecutionProvider'
|
|
]
|
|
|
|
session = ort.InferenceSession(
|
|
"model_fp16.onnx",
|
|
sess_options=session_options,
|
|
providers=providers
|
|
)
|
|
|
|
# Inferens
|
|
result = session.run(None, {"input": input_data})
|
|
```
|
|
|
|
### OpenVINO Model Server (OVMS) pa Edge
|
|
|
|
For Azure Arc/Azure Local-miljoer der Intel-hardware brukes:
|
|
|
|
```yaml
|
|
# ovms-deployment.yaml
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: ovms-inference
|
|
spec:
|
|
replicas: 2
|
|
template:
|
|
spec:
|
|
containers:
|
|
- name: ovms
|
|
image: openvino/model_server:latest
|
|
ports:
|
|
- containerPort: 9000 # gRPC
|
|
- containerPort: 8000 # REST
|
|
volumeMounts:
|
|
- name: model-store
|
|
mountPath: /models
|
|
env:
|
|
- name: MODELS_CONFIG
|
|
value: "/models/config.json"
|
|
resources:
|
|
limits:
|
|
cpu: "4"
|
|
memory: "8Gi"
|
|
volumes:
|
|
- name: model-store
|
|
persistentVolumeClaim:
|
|
claimName: model-pvc
|
|
```
|
|
|
|
### vLLM for LLM-inferens
|
|
|
|
KAITO bruker vLLM som standard inferensmotor for LLM-er:
|
|
|
|
| Funksjon | Beskrivelse | Fordel |
|
|
|----------|-------------|--------|
|
|
| PagedAttention | Effektiv KV-cache-haandtering | 2-4x gjennomstromning |
|
|
| Continuous batching | Dynamisk batching av foresporsler | Redusert latens |
|
|
| Tensor parallelism | Fordel modell over GPUer | Storre modeller |
|
|
| Quantization support | AWQ, GPTQ, SqueezeLLM | Lavere minnebruk |
|
|
| OpenAI-compatible API | Standard API-format | Enkel integrasjon |
|
|
|
|
---
|
|
|
|
## Caching Patterns for Edge
|
|
|
|
### Modellcaching-strategier
|
|
|
|
| Strategi | Implementasjon | Bruksomrade |
|
|
|----------|---------------|-------------|
|
|
| Model preloading | Last modell i minne ved oppstart | Sanntids inferens |
|
|
| TensorRT engine cache | Cach kompilerte TRT-motorer | GPU-inferens |
|
|
| ONNX session cache | Gjenbruk ORT-sesjoner | Repetitive inferenser |
|
|
| Result caching | Redis/memcached for resultater | Identiske inputs |
|
|
| Embedding cache | Cach vektorrepresentasjoner | RAG pa edge |
|
|
|
|
### Resultatchaching med Redis pa Edge
|
|
|
|
```yaml
|
|
# redis-cache-deployment.yaml
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: inference-cache
|
|
spec:
|
|
template:
|
|
spec:
|
|
containers:
|
|
- name: redis
|
|
image: redis:7-alpine
|
|
ports:
|
|
- containerPort: 6379
|
|
resources:
|
|
limits:
|
|
memory: "2Gi"
|
|
args:
|
|
- "--maxmemory"
|
|
- "1.5gb"
|
|
- "--maxmemory-policy"
|
|
- "allkeys-lru"
|
|
```
|
|
|
|
```python
|
|
# Inferens med caching
|
|
import redis
|
|
import hashlib
|
|
import json
|
|
|
|
cache = redis.Redis(host='inference-cache', port=6379)
|
|
|
|
def cached_inference(model_session, input_data, ttl=3600):
|
|
# Generer cache-nokkel fra input
|
|
cache_key = hashlib.sha256(
|
|
json.dumps(input_data, sort_keys=True).encode()
|
|
).hexdigest()
|
|
|
|
# Sjekk cache
|
|
cached = cache.get(cache_key)
|
|
if cached:
|
|
return json.loads(cached)
|
|
|
|
# Kjor inferens
|
|
result = model_session.run(None, input_data)
|
|
|
|
# Lagre i cache
|
|
cache.setex(cache_key, ttl, json.dumps(result.tolist()))
|
|
return result
|
|
```
|
|
|
|
### KV-cache for LLM-er
|
|
|
|
For LLM-inferens pa edge er KV-cache (key-value cache) kritisk:
|
|
|
|
| Teknikk | Beskrivelse | Minnebesparelse |
|
|
|---------|-------------|-----------------|
|
|
| Standard KV-cache | Full cache for alle tokens | Baseline |
|
|
| Sliding window | Begrens cache til siste N tokens | 50-80% |
|
|
| Grouped-query attention | Faerre KV-hoder | 4-8x |
|
|
| PagedAttention (vLLM) | Sidert minnehaandtering | Dynamisk |
|
|
|
|
---
|
|
|
|
## Batching vs. Streaming Inference
|
|
|
|
### Sammenligning
|
|
|
|
| Egenskap | Batch Inference | Streaming Inference |
|
|
|----------|----------------|---------------------|
|
|
| Latens | Hoyere (venter pa batch) | Lavere (umiddelbar) |
|
|
| Gjennomstromning | Hoyere (GPU-utnyttelse) | Lavere (per request) |
|
|
| GPU-utnyttelse | Optimal (fyller batch) | Variabel |
|
|
| Bruksomrade | Dokumentanalyse, batch-scoring | Chat, real-time |
|
|
| Skalering | Horisontal (flere workers) | Vertikal (GPU-kapasitet) |
|
|
|
|
### Beslutningstre
|
|
|
|
```
|
|
Trenger du sanntidssvar (<100ms)?
|
|
├── Ja → Streaming inference
|
|
│ ├── Enkelt request → Single request pipeline
|
|
│ └── Flere samtidige → Continuous batching (vLLM)
|
|
└── Nei → Batch inference
|
|
├── <1000 elementer → Micro-batch pa GPU
|
|
└── >1000 elementer → Azure ML Batch Endpoints
|
|
```
|
|
|
|
### Batch Inference pa Edge
|
|
|
|
```python
|
|
import numpy as np
|
|
from collections import deque
|
|
import threading
|
|
import time
|
|
|
|
class EdgeBatchInferencer:
|
|
def __init__(self, session, batch_size=8, max_wait_ms=50):
|
|
self.session = session
|
|
self.batch_size = batch_size
|
|
self.max_wait = max_wait_ms / 1000
|
|
self.queue = deque()
|
|
self.lock = threading.Lock()
|
|
|
|
def infer(self, input_data):
|
|
"""Legg til i koe og vent pa batch-resultat."""
|
|
event = threading.Event()
|
|
result_container = {}
|
|
|
|
with self.lock:
|
|
self.queue.append((input_data, event, result_container))
|
|
|
|
# Trigger batch hvis full
|
|
if len(self.queue) >= self.batch_size:
|
|
self._process_batch()
|
|
|
|
# Vent pa resultat (med timeout)
|
|
event.wait(timeout=self.max_wait * 2)
|
|
return result_container.get('result')
|
|
|
|
def _process_batch(self):
|
|
"""Prosesser akkumulerte inputs som en batch."""
|
|
with self.lock:
|
|
items = []
|
|
while self.queue and len(items) < self.batch_size:
|
|
items.append(self.queue.popleft())
|
|
|
|
if not items:
|
|
return
|
|
|
|
# Kombiner inputs til batch
|
|
batch_input = np.stack([item[0] for item in items])
|
|
|
|
# Kjor batch-inferens
|
|
batch_results = self.session.run(
|
|
None, {"input": batch_input}
|
|
)
|
|
|
|
# Distribuer resultater
|
|
for i, (_, event, container) in enumerate(items):
|
|
container['result'] = batch_results[0][i]
|
|
event.set()
|
|
```
|
|
|
|
### Streaming Inference for LLM pa Edge
|
|
|
|
```python
|
|
# Streaming med vLLM-kompatibelt API (KAITO)
|
|
import requests
|
|
import json
|
|
|
|
def stream_inference(prompt, service_ip, max_tokens=500):
|
|
"""Stream tokens fra lokal LLM pa edge."""
|
|
response = requests.post(
|
|
f"http://{service_ip}/v1/completions",
|
|
json={
|
|
"model": "phi-4-mini-instruct",
|
|
"prompt": prompt,
|
|
"max_tokens": max_tokens,
|
|
"stream": True
|
|
},
|
|
stream=True
|
|
)
|
|
|
|
for line in response.iter_lines():
|
|
if line:
|
|
data = line.decode('utf-8')
|
|
if data.startswith('data: '):
|
|
chunk = json.loads(data[6:])
|
|
if chunk.get('choices'):
|
|
token = chunk['choices'][0].get('text', '')
|
|
yield token
|
|
```
|
|
|
|
---
|
|
|
|
## IoT Edge ML Inference Pattern
|
|
|
|
### Azure IoT Edge med dynamisk modellasting
|
|
|
|
```
|
|
┌─────────────────────────────────────────┐
|
|
│ Azure Cloud │
|
|
│ ┌──────────┐ ┌──────────────────┐ │
|
|
│ │ Blob │ │ IoT Hub │ │
|
|
│ │ Storage │ │ (Device Twins) │ │
|
|
│ │ (Models) │ │ │ │
|
|
│ └────┬─────┘ └────────┬─────────┘ │
|
|
└───────┼───────────────────┼─────────────┘
|
|
│ │
|
|
│ ┌───────────────▼──────────┐
|
|
│ │ IoT Edge Runtime │
|
|
│ │ ┌─────────────────────┐ │
|
|
└───┼─►│ Model Loader Module │ │
|
|
│ └──────────┬──────────┘ │
|
|
│ ┌──────────▼──────────┐ │
|
|
│ │ Inference Module │ │
|
|
│ │ (ONNX/LiteRT) │ │
|
|
│ └──────────┬──────────┘ │
|
|
│ ┌──────────▼──────────┐ │
|
|
│ │ Local Storage │ │
|
|
│ │ (Model Cache) │ │
|
|
│ └─────────────────────┘ │
|
|
└──────────────────────────┘
|
|
```
|
|
|
|
### Device Twin-basert modellstyring
|
|
|
|
```python
|
|
# Motta modelloppdatering via IoT Edge Device Twin
|
|
from azure.iot.device import IoTHubModuleClient
|
|
|
|
async def twin_update_handler(patch):
|
|
if 'model_version' in patch:
|
|
model_url = patch['model_url']
|
|
model_version = patch['model_version']
|
|
checksum = patch['model_checksum']
|
|
|
|
# Last ned ny modell
|
|
await download_model(model_url, checksum)
|
|
|
|
# Hot-swap modell uten nedetid
|
|
await reload_model(model_version)
|
|
|
|
# Rapporter tilbake
|
|
reported = {
|
|
"active_model_version": model_version,
|
|
"model_loaded_at": datetime.utcnow().isoformat()
|
|
}
|
|
client.patch_twin_reported_properties(reported)
|
|
```
|
|
|
|
---
|
|
|
|
## Ytelsesreferanser
|
|
|
|
### Typiske inferenstider pa Microsoft edge-hardware
|
|
|
|
| Hardware | Modell | Oppgave | Latens (ms) |
|
|
|----------|--------|---------|-------------|
|
|
| Azure Stack Edge Pro GPU (T4) | YOLOv8 | Objektdeteksjon | 8-15 |
|
|
| Azure Stack Edge Pro GPU (T4) | ResNet-50 | Bildeklassifisering | 3-5 |
|
|
| Azure Local (A2) | Phi-3-mini-4k | Tekst (128 tokens) | 200-400 |
|
|
| Azure Local (L4) | Phi-4-mini | Tekst (128 tokens) | 80-150 |
|
|
| Azure Local (L40S) | Mistral-7B | Tekst (128 tokens) | 50-100 |
|
|
| Intel CPU (Xeon) + OpenVINO | BERT-base | NER | 5-10 |
|
|
| CPU (ONNX Runtime) | DistilBERT | Sentiment | 3-8 |
|
|
|
|
---
|
|
|
|
## For Cosmo
|
|
|
|
- **ONNX Runtime er universalmotoren for edge-inferens** — stotter CPU, GPU, NPU via Execution Providers, med TensorRT for NVIDIA og OpenVINO for Intel som de viktigste akseleratorene.
|
|
- **Kvantisering (INT8/INT4) er den enkleste og mest effektive optimaliseringen** — reduserer modellstorrelse 2-8x med minimalt noyaktighetstap, spesielt viktig for edge-enheter med begrenset minne.
|
|
- **Velg batching for gjennomstromning, streaming for latens** — continuous batching (vLLM/KAITO) gir det beste av begge for LLM-inferens pa edge Kubernetes-klynger.
|
|
- **Caching pa flere nivaer er essensielt for edge-ytelse** — TensorRT engine cache, resultat-cache (Redis), og KV-cache for LLM-er reduserer bade latens og GPU-belastning.
|
|
- **IoT Edge med Device Twins gir skalerbar modellstyring** for distribuerte edge-enheter — modellversjonering, inkrementell oppdatering og hot-swap uten nedetid.
|