Freigeben über


Ausführen von ONNX-Inference in WebAssembly (WASM)-Datenflussdiagrammen

In diesem Artikel wird gezeigt, wie Sie kleine Open Neural Network Exchange (ONNX)-Modelle in Ihre WebAssembly-Module einbetten und ausführen, um im Rahmen von Azure IoT Operations-Datenflussdiagrammen In-Band-Ableitungen durchzuführen. Verwenden Sie diesen Ansatz für die Anreicherung und Klassifizierung mit geringer Latenz direkt auf Streamingdaten, ohne externe Vorhersagedienste aufzurufen.

Von Bedeutung

Datenflussdiagramme unterstützen derzeit nur MQTT (Message Queuing Telemetry Transport), Kafka und OpenTelemetry-Endpunkte. Andere Endpunkttypen wie Data Lake, Microsoft Fabric OneLake, Azure Data Explorer und lokaler Speicher werden nicht unterstützt. Weitere Informationen finden Sie unter Bekannte Probleme.

Gründe für die Verwendung von In-Band-ONNX-Interferenzen

Mit Azure IoT Operations-Datenflussdiagrammen können Sie kleine ONNX-Modellinferenz direkt in den Datenfluss einbetten, statt einen externen Vorhersagedienst zu verwenden. Dieser Ansatz bietet mehrere praktische Vorteile:

  • Geringe Latenz: Durchführen einer Echtzeitanreicherung oder -klassifizierung im selben Operatorpfad, in dem Daten eingehen. Jede Nachricht verursacht nur lokale CPU-Ableitungen und vermeidet Netzwerk-Roundtrips.
  • Kompakte Größe: Zielkomprimierte Modelle wie MobileNet-Klassenmodelle. Diese Funktion ist nicht für große Transformatormodelle, GPU/TPU-Beschleunigung oder häufige A/B-Modellrollouts vorgesehen.
  • Optimiert für bestimmte Anwendungsfälle:
    • In Einklang mit der Multi-Source-Datenstromverarbeitung, bei der die Features bereits in der Grafik zusammengeführt werden
    • Ausgerichtet an der Ereigniszeitsemantik, sodass dabei die Inferenz dieselben Zeitstempel wie andere Operatoren verwendet.
    • Klein genug gehalten, um im Modul eingebettet zu werden, ohne die praktischen Größen- und Speicherbeschränkungen von WASM zu überschreiten.
  • Einfache Updates: Versenden Sie ein neues Modul mit WASM und eingebettetem Modell, und aktualisieren Sie dann den Diagrammdefinitionsverweis. Es muss keine separate Modellregistrierung oder externe Endpunktänderung erforderlich sein.
  • Hardwareeinschränkungen: ONNX-Back-End wird über webAssembly System Interface (WASI) wasi-nnauf DER CPU ausgeführt. Keine GPU/TPU-Ziele; nur unterstützte ONNX-Operatoren werden ausgeführt.
  • Horizontale Skalierung: Die Ableitung wird skaliert, wenn das Datenflussdiagramm skaliert wird. Wenn das Laufzeitsystem weitere Worker zur Verbesserung der Durchsatzleistung hinzufügt, lädt jeder Worker das eingebettete Modell und nimmt am Lastenausgleich teil.

Wann man In-Band-ONNX-Inferenz verwendet

Verwenden Sie die In-Band-Ableitung, wenn Sie die folgenden Anforderungen erfüllen:

  • Geringe Latenz muss Nachrichten inline zur Erfassungszeit anreichern und klassifizieren.
  • Kleine und effiziente Modelle wie MobileNet-Klasse vision oder ähnliche kompakte Modelle
  • Rückschluss, der mit der Ereigniszeitverarbeitung und den gleichen Zeitstempeln wie andere Operatoren zusammenpassen muss
  • Einfache Updates durch Versand einer neuen Modulversion mit einem aktualisierten Modell

Vermeiden Sie die In-Band-Ableitung, wenn Sie über diese Anforderungen verfügen:

  • Große Transformatormodelle, GPU/TPU-Beschleunigung oder anspruchsvolle A/B-Rollouts
  • Modelle, die mehrere Tensoreingaben, die Zwischenspeicherung von Schlüsselwerten oder nicht unterstützte ONNX-Operatoren erfordern

Hinweis

Sie möchten Module und eingebettete Modelle klein halten. Große Modelle und arbeitsspeicherintensive Workloads werden nicht unterstützt. Verwenden Sie kompakte Architekturen und kleine Eingabegrößen wie 224×224 für die Bildklassifizierung.

Voraussetzungen

Bevor Sie beginnen, stellen Sie sicher, dass Sie folgendes haben:

  • Eine Azure IoT Operations-Bereitstellung mit Datenflussdiagrammfunktionen.
  • Zugriff auf eine Containerregistrierung wie Azure Container Registry.
  • Entwicklungsumgebung für die WebAssembly-Modulentwicklung eingerichtet.

Ausführliche Anweisungen zum Einrichten finden Sie unter Entwickeln von WebAssembly-Modulen.

Architekturmuster

Das allgemeine Muster für ONNX-Inferenz in Datenflussgraphen umfasst:

  1. Vorverarbeitungsdaten: Transformieren Sie rohe Eingabedaten so, dass sie dem erwarteten Format Ihres Modells entsprechen. Bei Bildmodellen umfasst dieser Vorgang in der Regel Folgendes:
    • Decodieren von Bilddaten.
    • Skalierung auf eine Zieldimension (z. B. 224×224).
    • Konvertieren des Farbraums (z. B. RGB in BGR).
    • Normalisieren von Pixelwerten in den erwarteten Bereich (0 bis 1 oder -1 bis 1).
    • Anordnen von Daten im richtigen Tensorlayout: NCHW (Batch, Kanäle, Höhe, Breite) oder NHWC (Batch, Höhe, Breite, Kanäle).
  2. Ausführen von Rückschlüssen: Konvertieren von vorverarbeiteten Daten in Tensoren mithilfe der wasi-nn Schnittstelle, Laden Des eingebetteten ONNX-Modells mit dem CPU-Back-End, Festlegen von Eingabe-Tensoren im Ausführungskontext, Aufrufen des Vorwärtsdurchlaufs des Modells und Abrufen von Ausgabe-Tensoren mit Rohvorhersagen.
  3. Postprozess-Ausgaben: Transformieren Sie rohe Modellergebnisse in aussagekräftige Resultate. Allgemeine Vorgänge:
    • Wenden Sie Softmax an, um Klassifizierungswahrscheinlichkeiten zu erzeugen.
    • Wählen Sie die top-K-Vorhersagen aus.
    • Wenden Sie einen Konfidenzschwellenwert an, um Ergebnisse mit niedriger Konfidenz zu filtern.
    • Ordnen Sie Vorhersageindizes zu menschenlesbaren Bezeichnungen zu.
    • Formatieren Sie Ergebnisse für die nachgelagerte Nutzung.

In den IoT-Beispielen für Rust WASM-Operatoren finden Sie zwei Beispiele, die diesem Muster folgen:

Konfigurieren der Graphdefinition

Um die ONNX-Ableitung in Ihrem Datenflussdiagramm zu aktivieren, müssen Sie sowohl die Diagrammstruktur als auch die Modulparameter konfigurieren. Die Diagrammdefinition gibt den Pipelinefluss an, während Modulkonfigurationen die Laufzeitanpassung des Vorverarbeitungs- und Ableitungsverhaltens ermöglichen.

Aktivieren der WASI-NN-Unterstützung

Um die Unterstützung der WebAssembly Neural Network-Schnittstelle zu aktivieren, fügen Sie die wasi-nn Funktion zu Ihrer Diagrammdefinition hinzu:

moduleRequirements:
  apiVersion: "1.1.0"
  runtimeVersion: "1.1.0"
  features:
    - name: "wasi-nn"

Definieren von Vorgängen und Datenfluss

Konfigurieren Sie die Vorgänge, die Ihre Ableitungspipeline bilden. Dieses Beispiel zeigt einen typischen Bildklassifizierungsworkflow:

operations:
  - operationType: "source"
    name: "camera-input"
  - operationType: "map"
    name: "module-format/map"
    module: "format:1.0.0"
  - operationType: "map"
    name: "module-snapshot/map"
    module: "snapshot:1.0.0"
  - operationType: "sink"
    name: "results-output"

connections:
  - from: { name: "camera-input" }
    to: { name: "module-format/map" }
  - from: { name: "module-format/map" }
    to: { name: "module-snapshot/map" }
  - from: { name: "module-snapshot/map" }
    to: { name: "results-output" }

Diese Konfiguration erstellt eine Pipeline, in der:

  • camera-input Empfängt rohe Bilddaten aus einer Quelle
  • module-format/map Vorverarbeitung von Bildern (Decodieren, Ändern der Größe, Formatkonvertierung)
  • module-snapshot/map führt ONNX-Inferenz und Nachbearbeitung aus.
  • results-output gibt Klassifizierungsergebnisse an eine Senke aus

Konfigurieren von Modulparametern

Definieren Sie Laufzeitparameter zum Anpassen des Modulverhaltens ohne Neuerstellung. Diese Parameter werden bei der Initialisierung an Ihre WASM-Module übergeben:

moduleConfigurations:
  - name: module-format/map
    parameters:
      width:
        name: width
        description: "Target width for image resize (default: 224)"
        required: false
      height:
        name: height
        description: "Target height for image resize (default: 224)"
        required: false
      pixelFormat:
        name: pixel_format
        description: "Output pixel format (rgb24, bgr24, grayscale)"
        required: false

  - name: module-snapshot/map
    parameters:
      executionTarget:
        name: execution_target
        description: "Inference execution target (cpu, auto)"
        required: false
      labelMap:
        name: label_map
        description: "Label mapping strategy (embedded, imagenet, custom)"
        required: false
      scoreThreshold:
        name: score_threshold
        description: "Minimum confidence score to include in results (0.0-1.0)"
        required: false
      topK:
        name: top_k
        description: "Maximum number of predictions to return (default: 5)"
        required: false

Ihr Operator init kann diese Werte über die Modulkonfigurationsschnittstelle lesen. Ausführliche Informationen finden Sie unter Modulkonfigurationsparameter.

Packen des Modells

Durch das direkte Einbetten von ONNX-Modellen in Ihre WASM-Komponente wird eine nahtlose Bereitstellung und Versionskonsistenz gewährleistet. Dieser Ansatz vereinfacht die Verteilung und entfernt Laufzeitabhängigkeiten von externen Modelldateien oder Registrierungen.

Tipp

Beim Einbetten werden die Modell- und Operatorlogik in derselben Version gehalten. Um ein Modell zu aktualisieren, veröffentlichen Sie eine neue Modulversion, und aktualisieren Sie ihre Diagrammdefinition, um darauf zu verweisen. Bei diesem Ansatz werden Modellabweichungen beseitigt und reproduzierbare Bereitstellungen sichergestellt.

Richtlinien für die Modellvorbereitung

Stellen Sie vor dem Einbetten des Modells sicher, dass es die Anforderungen für die WASM-Bereitstellung erfüllt:

  • Halten Sie Modelle unter 50 MB für praktische WASM Ladezeiten und Arbeitsspeichereinschränkungen.
  • Überprüfen Sie, ob Ihr Modell eine einzelne Tensoreingabe in einem gängigen Format akzeptiert (float32 oder uint8).
  • Stellen Sie sicher, dass das WASM ONNX-Runtime-Back-End jeden vom Modell verwendeten Operator unterstützt.
  • Verwenden Sie ONNX-Optimierungstools, um die Modellgröße zu reduzieren und die Rückschlussgeschwindigkeit zu verbessern.

Einbettungsworkflow

Führen Sie die folgenden Schritte aus, um Ihr Modell und die zugehörigen Ressourcen einzubetten:

  1. Organisieren Sie Modellressourcen: Platzieren Sie die .onnx Modelldatei und optional labels.txt in Ihrem Quellverzeichnis. Verwenden Sie eine dedizierte Verzeichnisstruktur wie src/fixture/models/ und src/fixture/labels/ für eine klare Organisation.
  2. Zur Kompilierungszeit einbetten: Verwenden Sie sprachspezifische Mechanismen, um Modell-Bytes in Ihre Binärdatei einzuschließen. Verwenden Sie in Rust include_bytes! für Binärdaten und include_str! für Textdateien.
  3. Initialisieren Sie den WASI-NN Graph: Erstellen Sie in der Funktion des Operators einen Graph aus den eingebetteten Bytes, wobei die ONNX-Codierung und das CPU-Ausführungsziel angegeben werden.
  4. Implementieren Sie eine Ableitungsschleife: Für jede eingehende Nachricht werden Eingaben vorverarbeitet, um den Modellanforderungen zu entsprechen, Eingabe-Tensoren festzulegen, Ableitungen auszuführen, Ausgaben abzurufen und Postverarbeitung anzuwenden.
  5. Behandeln Sie Fehler ordnungsgemäß: Implementieren Sie die ordnungsgemäße Fehlerbehandlung für Modellladefehler, nicht unterstützte Operatoren und Laufzeitableitungsfehler.

Ein vollständiges Implementierungsmuster finden Sie im Beispiel "Snapshot".

Organisieren Sie Ihr WASM-Modulprojekt mit einer klaren Trennung von Bedenken:

src/
├── lib.rs                 # Main module implementation
├── model/
│   ├── mod.rs            # Model management module
│   └── inference.rs      # Inference logic
└── fixture/
    ├── models/
    │   ├── mobilenet.onnx      # Primary model
    │   └── mobilenet_opt.onnx  # Optimized variant
    └── labels/
        ├── imagenet.txt        # ImageNet class labels
        └── custom.txt          # Custom label mappings

Beispieldateiverweise

Verwenden Sie das folgende Dateilayout aus dem Beispiel "snapshot" als Referenz:

Beispiel für minimale Einbettung

Das folgende Beispiel zeigt minimale Rust-Einbettung. Die Pfade sind relativ zur Quelldatei, die das Makro enthält:

// src/lib.rs (example)
// Embed ONNX model and label map into the component
static MODEL: &[u8] = include_bytes!("fixture/models/mobilenet.onnx");
static LABEL_MAP: &[u8] = include_bytes!("fixture/labels/synset.txt");

fn init_model() -> Result<(), anyhow::Error> {
  // Create wasi-nn graph from embedded ONNX bytes using the CPU backend
  // Pseudocode – refer to the snapshot sample for the full implementation
  // use wasi_nn::{graph::{load, GraphEncoding, ExecutionTarget}, Graph};
  // let graph = load(&[MODEL.to_vec()], GraphEncoding::Onnx, ExecutionTarget::Cpu)?;
  // let exec_ctx = Graph::init_execution_context(&graph)?;
  Ok(())
}

Leistungsoptimierung

Um das ErneuteStellen des ONNX-Diagramms und des Ausführungskontexts für jede Nachricht zu vermeiden, initialisieren Sie es einmal, und verwenden Sie es wieder. Im öffentlichen Beispiel wird ein statisches LazyLockBeispiel verwendet:

use crate::wasi::nn::{
     graph::{load, ExecutionTarget, Graph, GraphEncoding, GraphExecutionContext},
     tensor::{Tensor, TensorData, TensorDimensions, TensorType},
 };

 static mut CONTEXT: LazyLock<GraphExecutionContext> = LazyLock::new(|| {
     let graph = load(&[MODEL.to_vec()], GraphEncoding::Onnx, ExecutionTarget::Cpu).unwrap();
     Graph::init_execution_context(&graph).unwrap()
 });
    
fn run_inference(/* input tensors, etc. */) {
   unsafe {
     // (*CONTEXT).compute()?;
  }
}

Bereitstellen Ihrer Module

Verwenden Sie die optimierten Beispiel-Generatoren oder erstellen Sie lokal:

Folgen Sie diesem Bereitstellungsprozess:

  1. Erstellen Sie Ihr WASM-Modul im Releasemodus, und erstellen Sie eine <module-name>-<version>.wasm Datei.
  2. Übertragen Sie das Modul und optional eine Graphdefinition in Ihre Registrierung, indem Sie OCI Registry as Storage (ORAS) verwenden.
  3. Erstellen oder Wiederverwenden eines Registrierungsendpunkts in Azure IoT Operations.
  4. Erstellen Sie eine Datenflussdiagrammressource, die auf ihr Diagrammdefinitionsartefakt verweist.

Beispiel: MobileNet-Bildklassifizierung

Die öffentlichen IoT-Beispiele stellen zwei Beispiele bereit, die in ein Diagramm für die Bildklassifizierung verkabelt sind: Das Beispiel "Format" stellt Bildcode- und Größenänderungsfunktionen bereit, und das Beispiel "Snapshot" bietet ONNX-Ableitungen und Softmax-Verarbeitung.

Um dieses Beispiel bereitzustellen, rufen Sie die Artefakte aus der öffentlichen Registrierung ab, übertragen Sie sie an Ihre Registrierung, und stellen Sie ein Datenflussdiagramm bereit, wie in Beispiel 2 gezeigt: Bereitstellen eines komplexen Diagramms. Das komplexe Diagramm verwendet diese Module zum Verarbeiten von Bildmomentaufnahmen und ausgeben Klassifizierungsergebnisse.

Einschränkungen

Die Ableitung in WASM-Datenflussdiagrammen hat die folgenden Einschränkungen:

  • ONNX ausschließlich. Datenflussdiagramme unterstützen keine anderen Formate wie TFLite.
  • Nur CPU. Keine GPU/TPU-Beschleunigung.
  • Kleine Modelle empfohlen. Große Modelle und speicherintensive Rückschlüsse werden nicht unterstützt.
  • Single-Tensor-Eingabemodelle werden unterstützt. Multieingabemodelle, Zwischenspeicherung von Schlüsselwerten und erweiterte Sequenz- oder generative Szenarien werden nicht unterstützt.
  • Stellen Sie sicher, dass das ONNX-Back-End in der WASM-Laufzeit die Operatoren Ihres Modells unterstützt. Wenn ein Operator nicht unterstützt wird, schlägt die Ableitung zur Lade- oder Ausführungszeit fehl.

Nächste Schritte