共用方式為


在 WebAssembly (WASM) 資料流程圖中執行 ONNX 推論

本文說明如何在 WebAssembly 模組內內嵌和執行小型 Open Neural Network Exchange (ONNX) 模型,以執行頻內推斷作為 Azure IoT 作業資料流程圖的一部分。 使用此方法直接在串流資料上進行低延遲擴充和分類,而不需要呼叫外部預測服務。

這很重要

資料流程圖目前僅支援 MQTT (訊息佇列遙測傳輸)、Kafka 和 OpenTelemetry 端點。 不支援其他端點類型,例如 Data Lake、Microsoft Fabric OneLake、Azure 資料總管和本機儲存體。 如需詳細資訊,請參閱已知問題。

為何使用頻內 ONNX 推理

使用 Azure IoT 作業資料流程圖,您可以直接在管線中內嵌小型 ONNX 模型推斷,而不是呼叫外部預測服務。 這種方法具有幾個實際優勢:

  • 低延遲:在資料到達的相同運算子路徑中執行即時擴充或分類。 每則訊息僅涉及本機 CPU 推論,避免網路的往返操作。
  • 緊湊型設計:針對緊湊型模型,如 MobileNet 類模型。 此功能不適用於大型 Transformer 模型、GPU/TPU 加速或頻繁的 A/B 模型部署。
  • 針對特定用例進行了優化
    • 與多來源串流處理內嵌,其中特徵已在圖形中並置
    • 與事件時間語意一致,因此推論使用與其他運算子相同的時間戳記
    • 保持足夠小以便嵌入模組,且不超過實際的 WASM 大小與記憶體限制
  • 簡單更新:提供帶有 WASM 和嵌入式模型的新模塊,然後更新圖形定義參考。 不需要個別的模型登錄或外部端點變更。
  • 硬體限制:ONNX後端透過WebAssembly系統介面(WASI) wasi-nn在CPU上運行。 無 GPU/TPU 目標;僅受支援的 ONNX 運算子會執行。
  • 水平擴展:推論會隨著資料流程圖的擴展而擴展。 當執行階段新增更多工作者以取得輸送量時,每個工作者都會載入內嵌模型並參與負載平衡。

何時使用內嵌式 ONNX 推論

當您有下列需求時,請使用頻內推論:

  • 低延遲需要在資料擷取時即時豐富或分類訊息
  • 小型且高效的模型,例如 MobileNet 級的視覺模型或類似的緊湊型模型
  • 需要與事件時間處理保持一致的推論,以及與其他運算子相同的時間戳記
  • 透過提供具有更新模型的新模組版本來進行簡單更新

當您有以下要求時,請避免頻內推論:

  • 大型 Transformer 模型、GPU/TPU 加速或複雜的 A/B 測試
  • 需要多個張量輸入、需要鍵值快取功能,或包含不支援的 ONNX 運算子的模型

備註

您想要保持模組和內嵌模型較小。 不支援大型模型和記憶體密集型工作負載。 使用緊湊的架構和小輸入大小(如 224×224)進行影像分類。

先決條件

在開始之前,請確保您擁有:

  • 具有資料流程圖形功能的 Azure IoT 作業部署。
  • 存取容器登錄,例如 Azure 容器登錄。
  • 為WebAssembly模組開發而設定的開發環境。

如需詳細的設定指示,請參閱 開發 WebAssembly 模組

架構模式

資料流程圖中 ONNX 推斷的常見模式包括:

  1. 預處理數據: 轉換原始輸入數據以匹配模型的預期格式。 對於影像模型,此程式通常涉及:
    • 解碼圖像位元組。
    • 將大小調整為目標維度(例如224×224)。
    • 轉換色彩空間 (例如,RGB 至 BGR)。
    • 將圖元值正規化為預期範圍 (0-1 或 -1 到 1)。
    • 以正確的張量佈局排列資料:NCHW(批次、通道、高度、寬度)或 NHWC(批次、高度、寬度、通道)。
  2. 運行推理: 使用接口將 wasi-nn 預處理數據轉換為張量,使用 CPU 後端加載您的嵌入式 ONNX 模型,在執行上下文上設置輸入張量,調用模型的前向傳遞,並檢索包含原始預測的輸出張量。
  3. 後處理輸出: 將原始模型輸出轉換為有意義的結果。 常見操作:
    • 應用softmax來產生分類機率。
    • 選取前 K 個預測。
    • 套用信賴臨界值來篩選低信賴度結果。
    • 將預測指數對應至人類可讀的標籤。
    • 格式化結果以供下游取用。

Rust WASM 操作者的物聯網樣本 中,你可以找到兩個遵循此模式的樣本:

設定圖形定義

若要在資料流程圖中啟用 ONNX 推斷,您必須設定圖形結構和模組參數。 圖形定義會指定管線流程,而模組組態則允許執行階段自訂前置處理和推論行為。

啟用 WASI-NN 支援

若要啟用 WebAssembly 神經網路介面支援,請將特性 wasi-nn 新增至圖形定義:

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

定義作業和資料流程

設定構成推理流程的操作。 此範例顯示典型的影像分類工作流程:

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

此設定會建立管線,其中:

  • camera-input 從來源接收原始影像資料
  • module-format/map 預處理圖像(解碼、調整大小、格式轉換)
  • module-snapshot/map 執行 ONNX 推理和後處理
  • results-output 將分類結果發出至接收器

設定模組參數

定義執行階段參數以自訂模組行為,而無需重建。 這些參數在初始化時傳遞給您的 WASM 模組:

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

您的操作員 init 可以透過模組配置介面讀取這些值。 如需詳細資訊,請參閱 模組組態參數

封裝模型

將 ONNX 模型直接嵌入到您的 WASM 元件中可確保原子部署和版本一致性。 這種方法簡化了分發並消除了對外部模型檔案或註冊表的運行時依賴關係。

小提示

內嵌會讓模型和運算子邏輯版本化在一起。 若要更新模型,請發佈新的模組版本,並更新圖形定義以參考它。 這種方法消除了模型漂移並確保了可重現的部署。

模型準備指南

在嵌入模型之前,請確保它符合 WASM 部署的要求:

  • 將模型保持在 50 MB 以下,以實現實際的 WASM 載入時間和記憶體限制。
  • 確認您的模型是否接受通用格式 (float32 或 uint8) 的單一張量輸入。
  • 確認 WASM ONNX 執行階段後端支援模型使用的每個運算子。
  • 使用ONNX最佳化工具來減小模型大小,提高推理速度。

內嵌工作流程

請遵循下列步驟來內嵌您的模型和相關資源:

  1. 組織模型資產: 將 .onnx 模型文件和可選 labels.txt 放置在您的源樹中。 使用專用的目錄結構,例如 src/fixture/models/src/fixture/labels/ 進行清晰的組織。
  2. 編譯時嵌入: 使用特定於語言的機制在二進位文件中包含模型位元組。 在 Rust 中,用於 include_bytes! 二進位資料和 include_str! 文字檔案。
  3. 初始化 WASI-NN 圖: 在運算子的 init 函數中,從嵌入的位元組創建一個 wasi-nn 圖,指定 ONNX 編碼和 CPU 執行目標。
  4. 實現推理循環: 對於每個傳入消息,預處理輸入以匹配模型需求,設置輸入張量,執行推理,檢索輸出,並應用後處理。
  5. 優雅地處理錯誤: 針對模型加載失敗、不支持的運算子和運行時推理錯誤實施正確的錯誤處理。

如需完整的實作模式,請參閱 「快照集」範例

組織您的 WASM 模組項目,並明確劃分關注點:

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

範例檔案參考

使用「快照集」範例中的下列檔案配置作為參考:

最小內嵌範例

以下範例顯示了最小的 Rust 嵌入。 路徑相對於包含巨集的來源檔案:

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

效能優化

若要避免為每則訊息重新建立 ONNX 圖形和執行內容,請初始化一次並重複使用。 公用範例會使用靜態LazyLock

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

部署您的模組

重新使用精簡化的範例產生器或在本地構建:

請遵循下列部署程式:

  1. 在發布模式下構建您的 WASM 模塊並生成一個 <module-name>-<version>.wasm 文件。
  2. 使用 OCI 註冊表作為存儲(ORAS),將模組與圖形定義選擇性地推送至註冊表。
  3. 在 Azure IoT 作業中建立或重複使用登錄端點。
  4. 建立一個資料流圖資源,來參考您的圖形定義組件。

範例:MobileNet 影像分類

IoT 公用範例提供兩個連線到圖形中的範例,以進行影像分類:「 格式」範例 提供影像解碼和調整大小功能, 而「快照集」範例 則提供 ONNX 推斷和 softmax 處理。

若要部署此範例,請從公用登錄提取構件,將它們推送至登錄,然後部署資料流程圖,如 範例 2:部署複雜圖形所示。 複圖使用這些模組來處理影像快照並發出分類結果。

局限性

WASM 資料流程圖中的推理有以下限制:

  • 僅限 ONNX。 資料流程圖不支援其他格式,例如 TFLite。
  • 僅限於 CPU。 沒有 GPU/TPU 加速。
  • 推薦小型型號。 不支援大型模型和記憶體密集型推論。
  • 支援單一張量輸入模型。 不支援多重輸入模型、鍵值快取功能以及進階序列或生成場景。
  • 確保 WASM 運行時中的 ONNX 後端支持模型的運算子。 如果不支援運算子,推論會在載入或執行時失敗。

後續步驟