Udostępnij przez


Uruchamianie wnioskowania ONNX na wykresach przepływu danych webAssembly (WASM)

W tym artykule pokazano, jak osadzać i uruchamiać małe modele Open Neural Network Exchange (ONNX) wewnątrz modułów webAssembly w celu wykonywania wnioskowania wewnątrz pasmowego w ramach wykresów przepływu danych operacji usługi Azure IoT. Użyj tego podejścia do wzbogacania i klasyfikacji o małych opóźnieniach bezpośrednio na danych przesyłanych strumieniowo bez wywoływania zewnętrznych usług przewidywania.

Ważne

Obecnie wykresy przepływu danych obsługują tylko punkty końcowe MQTT (Message Queuing Telemetry Transport), Kafka i OpenTelemetry. Inne typy punktów końcowych, takie jak Data Lake, Microsoft Fabric OneLake, Azure Data Explorer i Local Storage, nie są obsługiwane. Aby uzyskać więcej informacji, zobacz Znane problemy.

Dlaczego warto używać interferencji ONNX w pasmie

Za pomocą wykresów przepływu danych operacji usługi Azure IoT można osadzać małe wnioskowanie modelu ONNX bezpośrednio w potoku zamiast wywoływać zewnętrzną usługę przewidywania. Takie podejście oferuje kilka praktycznych zalet:

  • Małe opóźnienie: wykonaj wzbogacanie lub klasyfikację w czasie rzeczywistym w tej samej ścieżce operatora, w której docierają dane. Każdy komunikat powoduje tylko lokalne wnioskowanie CPU, unikając przesyłania danych w sieci.
  • Kompaktowy rozmiar: docelowe modele kompaktowe, takie jak modele klasy MobileNet. Ta funkcja nie dotyczy dużych modeli transformatorów, przyspieszania procesora GPU/TPU ani częstych wdrożeń modeli A/B.
  • Zoptymalizowane pod kątem określonych przypadków użycia:
    • Zgodne z wieloźródłowym przetwarzaniem strumieniowym, gdzie funkcje są już zlokalizowane w grafie
    • Zakładane na bazie semantyki czasu zdarzeń, wnioskowanie wykorzystuje te same znaczniki czasu jak inne operatory
    • Zachowany dostatecznie mały rozmiar, aby osadzić go z modułem, nie przekraczając praktycznych ograniczeń rozmiaru i pamięci WASM.
  • Proste aktualizacje: wprowadzenie nowego modułu z osadzonym modelem WASM, a następnie zaktualizowanie odwołania do definicji grafu. Nie trzeba mieć oddzielnego rejestru modelu ani zmiany zewnętrznego punktu końcowego.
  • Ograniczenia sprzętowe: zaplecze ONNX działa na procesorze przez interfejs systemowy WebAssembly (WASI). wasi-nn Brak docelowych jednostek GPU/TPU; uruchamiane są tylko obsługiwane operatory ONNX.
  • Skalowanie w poziomie: wnioskowanie skaluje się w miarę skalowania wykresu przepływu danych. Gdy środowisko uruchomieniowe dodaje więcej pracowników do zwiększenia przepustowości, każdy z nich ładuje osadzony model i bierze udział w procesie równoważenia obciążenia.

Kiedy należy używać wnioskowania ONNX w pasmie

Jeśli masz następujące wymagania, użyj wnioskowania w pasmie:

  • Polityka niskiego opóźnienia wymaga wzbogacania lub klasyfikowania komunikatów w czasie ich pobierania.
  • Małe i wydajne modele, takie jak modele klasy MobileNet lub podobne kompaktowe modele
  • Wnioskowanie, które musi być zgodne z przetwarzaniem czasu zdarzenia i tymi samymi znacznikami czasu co inne operatory
  • Proste aktualizacje dzięki wysłaniu nowej wersji modułu ze zaktualizowanym modelem

Unikaj wnioskowania w pasmie, jeśli masz następujące wymagania:

  • Duże modele przekształcania, przyspieszanie procesora GPU/TPU lub zaawansowane wdrożenia A/B
  • Modele, które wymagają wielu danych wejściowych w postaci tensorów, buforowania par klucz-wartość lub korzystania z nieobsługiwanych operatorów ONNX

Uwaga / Notatka

Chcesz zachować małe moduły i osadzone modele. Duże modele i obciążenia z dużą ilością pamięci nie są obsługiwane. Użyj kompaktowych architektur i małych rozmiarów wejściowych, takich jak 224×224 do klasyfikacji obrazów.

Wymagania wstępne

Przed rozpoczęciem upewnij się, że masz:

  • Wdrożenie operacji usługi Azure IoT z funkcją grafów przepływu danych.
  • Dostęp do rejestru kontenerów, takiego jak Usługa Azure Container Registry.
  • Środowisko programistyczne skonfigurowane na potrzeby tworzenia modułów zestawu WebAssembly.

Aby uzyskać szczegółowe instrukcje dotyczące konfiguracji, zobacz Develop WebAssembly modules (Tworzenie modułów zestawu WebAssembly).

Wzorzec architektury

Typowy wzorzec wnioskowania ONNX w grafach przepływu danych obejmuje:

  1. Przetwarzanie wstępne danych: przekształć nieprzetworzone dane wejściowe, aby były zgodne z oczekiwanym formatem modelu. W przypadku modeli obrazów ten proces zwykle obejmuje:
    • Dekodowanie bajtów obrazu.
    • Zmiana rozmiaru na wymiar docelowy (na przykład 224×224).
    • Konwertowanie przestrzeni kolorów (na przykład RGB na BGR).
    • Normalizacja wartości pikseli do oczekiwanego zakresu (od 0 do 1 lub -1 do 1).
    • Rozmieszczanie danych w poprawnym układzie tensorowym: NCHW (partia, kanały, wysokość, szerokość) lub NHWC (partia, wysokość, szerokość, kanały).
  2. Uruchamianie wnioskowania: przekonwertuj wstępnie przetworzone dane na tensory przy użyciu interfejsu wasi-nn , załaduj osadzony model ONNX za pomocą zaplecza procesora CPU, ustaw tensory wejściowe w kontekście wykonywania, wywołaj przekazywanie do przodu modelu i pobierz tensory wyjściowe zawierające nieprzetworzone przewidywania.
  3. Dane wyjściowe przetwarzania końcowego: przekształć nieprzetworzone dane wyjściowe modelu w znaczące wyniki. Typowe operacje:
    • Zastosuj softmax, aby wygenerować prawdopodobieństwa klasyfikacji.
    • Wybierz przewidywania najwyższego poziomu K.
    • Zastosuj próg ufności, aby filtrować wyniki o niskiej pewności.
    • Mapuj indeksy przewidywania na etykiety czytelne dla człowieka.
    • Formatuj wyniki na potrzeby dalszego przetwarzania.

W przykładach IoT dla operatorów Rust WASM można znaleźć dwa przykłady, które są zgodne z tym wzorcem:

Konfigurowanie definicji grafu

Aby włączyć wnioskowanie ONNX na wykresie przepływu danych, należy skonfigurować zarówno strukturę grafu, jak i parametry modułu. Definicja grafu określa przepływ potoku, a konfiguracje modułów umożliwiają dostosowanie środowiska uruchomieniowego wstępnego przetwarzania i zachowania wnioskowania.

Włącz obsługę WASI-NN

Aby włączyć obsługę interfejsu sieci neuronowej WebAssembly, dodaj wasi-nn funkcję do definicji grafu.

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

Definiowanie operacji i przepływu danych

Skonfiguruj operacje, które tworzą potok wnioskowania. W tym przykładzie przedstawiono typowy przepływ pracy klasyfikacji obrazów:

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

Ta konfiguracja tworzy potok, w którym:

  • camera-input odbiera nieprzetworzone dane obrazu ze źródła
  • module-format/map wstępnie przetwarza obrazy (dekoduj, zmienia rozmiar, konwersję formatu)
  • module-snapshot/map uruchamia wnioskowanie i postprocesowanie ONNX
  • results-output przesyła wyniki klasyfikacji do odbiornika

Konfigurowanie parametrów modułu

Zdefiniuj parametry środowiska uruchomieniowego, aby dostosować zachowanie modułu bez ponownego kompilowania. Te parametry są przekazywane do modułów WASM podczas inicjowania:

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

Operator init może odczytywać te wartości za pomocą interfejsu konfiguracji modułu. Aby uzyskać szczegółowe informacje, zobacz Parametry konfiguracji modułu.

Pakowanie modelu

Osadzanie modeli ONNX bezpośrednio w składniku WASM zapewnia atomowe wdrażanie i zgodność wersji. Takie podejście upraszcza dystrybucję i usuwa zależności środowiska uruchomieniowego od zewnętrznych plików modelu lub rejestrów.

Wskazówka

Osadzanie pozwala zachować wersję modelu i logiki operatora. Aby zaktualizować model, opublikuj nową wersję modułu i zaktualizuj definicję grafu, aby się do niego odwoływać. Takie podejście eliminuje dryf modelu i zapewnia powtarzalne wdrożenia.

Wytyczne dotyczące przygotowywania modelu

Przed osadzeniem modelu upewnij się, że spełnia ona wymagania dotyczące wdrożenia WASM:

  • Zachowaj modele poniżej 50 MB na potrzeby praktycznych czasów ładowania WASM i ograniczeń pamięci.
  • Sprawdź, czy model akceptuje pojedynczy tensor wejściowy w typowym formacie (float32 lub uint8).
  • Sprawdź, czy zaplecze środowiska uruchomieniowego WASM ONNX obsługuje każdego operatora używanego przez model.
  • Użyj narzędzi optymalizacji ONNX, aby zmniejszyć rozmiar modelu i zwiększyć szybkość wnioskowania.

Osadzanie przepływu pracy

Wykonaj następujące kroki, aby osadzić model i skojarzone zasoby:

  1. Organizowanie zasobów modelu: umieść .onnx plik modelu i opcjonalnie labels.txt w drzewie źródłowym. Użyj dedykowanej struktury katalogów, takiej jak src/fixture/models/ i src/fixture/labels/ , aby wyczyścić organizację.
  2. Osadzanie w czasie kompilacji: użyj mechanizmów specyficznych dla języka, aby uwzględnić bajty modelu w pliku binarnym. W języku Rust użyj danych include_bytes! binarnych i include_str! plików tekstowych.
  3. Zainicjuj wykres WASI-NN: w funkcji operatora init utwórz wasi-nn graf na podstawie osadzonych bajtów, określając kodowanie ONNX i cel wykonywania procesora CPU.
  4. Implementuj pętlę wnioskowania: dla każdego przychodzącego komunikatu przetworzyć dane wejściowe, aby były zgodne z wymaganiami modelu, ustawić tensory wejściowe, wykonywać wnioskowanie, pobrać dane wyjściowe i stosować przetwarzanie końcowe.
  5. Spokojna obsługa błędów: Zaimplementuj właściwą obsługę błędów podczas ładowania modelu, obsługi operatorów oraz błędów wnioskowania w czasie wykonywania.

Pełny wzorzec implementacji można znaleźć w przykładzie "snapshot".

Organizuj projekt modułu WASM z wyraźnym rozdzieleniem zagadnień:

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

Przykładowe odwołania do plików

Użyj następującego układu pliku z przykładu "snapshot" jako odwołania:

Przykład minimalnego osadzania

W poniższym przykładzie pokazano minimalne osadzanie elementów Rust. Ścieżki są powiązane z plikiem źródłowym zawierającym makro:

// 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(())
}

Optymalizacja wydajności

Aby uniknąć ponownego tworzenia grafu ONNX i kontekstu wykonywania dla każdego komunikatu, zainicjuj go raz i użyj go ponownie. Przykład publiczny używa statycznego LazyLockelementu :

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()?;
  }
}

Wdrażanie modułów

Użyj uproszczonych konstruktorów przykładów lub kompiluj lokalnie:

Postępuj zgodnie z tym procesem wdrażania:

  1. Skompiluj moduł WASM w trybie kompilacji do wydania i utwórz plik <module-name>-<version>.wasm.
  2. Prześlij moduł oraz opcjonalnie definicję grafu do swojego rejestru, korzystając z rejestru OCI jako magazynu (ORAS).
  3. Utwórz lub użyj ponownie punktu końcowego rejestru w operacjach Azure IoT.
  4. Utwórz zasób grafu przepływu danych, który odwołuje się do artefaktu definicji grafu.

Przykład: klasyfikacja obrazów sieci MobileNet

Publiczne przykłady IoT udostępniają dwa przykłady wbudowane w graf do klasyfikacji obrazów: przykład "format" dostarcza funkcję dekodowania i zmiany rozmiaru obrazu, a przykład "migawka" zapewnia wnioskowanie ONNX i przetwarzanie softmax.

Aby wdrożyć ten przykład, należy ściągnąć artefakty z rejestru publicznego, wypchnąć je do rejestru i wdrożyć wykres przepływu danych, jak pokazano w przykładzie 2: Wdrażanie złożonego grafu. Złożony graf używa tych modułów do przetwarzania migawek obrazów i emitowania wyników klasyfikacji.

Ograniczenia

Wnioskowanie w grafach przepływu danych WASM ma następujące ograniczenia:

  • Tylko ONNX. Wykresy przepływu danych nie obsługują innych formatów, takich jak TFLite.
  • Tylko CPU. Brak przyspieszenia procesora GPU/TPU.
  • Zalecane są małe modele. Duże modele i wnioskowanie intensywnie korzystające z pamięci nie są obsługiwane.
  • Obsługiwane są modele wejściowe z pojedynczymi tensorami. Modele z wieloma danymi wejściowymi, buforowanie klucz-wartość i zaawansowane scenariusze sekwencji lub generowania nie są obsługiwane.
  • Upewnij się, że zaplecze ONNX w środowisku uruchomieniowym WASM obsługuje operatory modelu. Jeśli operator nie jest obsługiwany, wnioskowanie kończy się niepowodzeniem podczas ładowania lub wykonywania.

Dalsze kroki