Partilhar via


Executar inferência ONNX em gráficos de fluxo de dados WebAssembly (WASM)

Este artigo mostra como incorporar e executar pequenos modelos ONNX (Open Neural Network Exchange) dentro de seus módulos WebAssembly para executar inferência em banda como parte dos gráficos de fluxo de dados do Azure IoT Operations. Use essa abordagem para enriquecimento e classificação de baixa latência diretamente em dados de streaming sem chamar serviços de previsão externos.

Importante

Atualmente, os gráficos de fluxo de dados suportam apenas os pontos de extremidade MQTT (Message Queuing Telemetry Transport), Kafka e OpenTelemetry. Não há suporte para outros tipos de ponto de extremidade, como Data Lake, Microsoft Fabric OneLake, Azure Data Explorer e Armazenamento Local. Para obter mais informações, consulte Problemas conhecidos.

Por que usar interferência ONNX em banda

Com os gráficos de fluxo de dados do Azure IoT Operations, você pode incorporar pequenas inferências de modelo ONNX diretamente no pipeline em vez de chamar um serviço de previsão externo. Esta abordagem oferece várias vantagens práticas:

  • Baixa latência: execute enriquecimento ou classificação em tempo real no mesmo trajeto do operador onde os dados chegam. Cada mensagem gera apenas inferência de CPU local, evitando viagens desnecessárias na rede.
  • Tamanho compacto: Direcione modelos compactos, como modelos da classe MobileNet. Esse recurso não é para modelos de transformadores grandes, aceleração de GPU/TPU ou lançamentos frequentes de modelos A/B.
  • Otimizado para casos de uso específicos:
    • Em linha com o processamento de fluxo de várias fontes onde as funcionalidades já estão localizadas no mesmo gráfico
    • Está alinhado com a semântica de tempo de evento, permitindo que a inferência utilize as mesmas marcas temporais que outros operadores.
    • Mantido pequeno o suficiente para incorporar com o módulo sem exceder o tamanho prático do WASM e as restrições de memória
  • Atualizações simples: envie um novo módulo com WASM e modelo incorporado e, em seguida, atualize a referência de definição de gráfico. Não há necessidade de ter um registro de modelo separado ou alteração de ponto de extremidade externo.
  • Restrições de hardware: O back-end ONNX é executado na CPU através da WebAssembly System Interface (WASI). wasi-nn Sem alvos GPU/TPU; apenas os operadores ONNX suportados são executados.
  • Dimensionamento horizontal: a inferência é dimensionada à medida que o gráfico de fluxo de dados é dimensionado. Quando o runtime adiciona mais trabalhadores para aumentar a taxa de transferência, cada trabalhador carrega o modelo incorporado e participa no balanceamento de carga.

Quando utilizar a inferência ONNX em banda

Utilize a inferência em banda quando tiver estes requisitos:

  • A necessidade de baixa latência exige que mensagens sejam enriquecidas ou classificadas em tempo real durante a ingestão.
  • Modelos pequenos e eficientes, como os modelos de visão da classe MobileNet ou modelos compactos semelhantes
  • A inferência que precisa estar alinhada com o processamento em tempo de evento e com os mesmos timestamps que outros operadores.
  • Atualizações simples enviando uma nova versão do módulo com um modelo atualizado

Evite a inferência em banda quando tiver estes requisitos:

  • Modelos de transformadores grandes, aceleração GPU/TPU ou implementações A/B sofisticadas
  • Modelos que exigem várias entradas de tensores, armazenamento em cache de chave-valor ou operadores ONNX não suportados

Observação

Você deseja manter os módulos e modelos incorporados pequenos. Não há suporte para modelos grandes e cargas de trabalho com muita memória. Use arquiteturas compactas e tamanhos de entrada pequenos, como 224×224 para classificação de imagens.

Pré-requisitos

Antes de começar, certifique-se de que tem:

  • Uma implantação de Operações IoT do Azure com capacidade de gráficos de fluxo de dados.
  • Acesso a um registro de contêiner como o Registro de Contêiner do Azure.
  • Ambiente de desenvolvimento configurado para desenvolvimento do módulo WebAssembly.

Para obter instruções detalhadas de configuração, consulte Desenvolver módulos WebAssembly.

Padrão de arquitetura

O padrão comum para inferência ONNX em gráficos de fluxo de dados inclui:

  1. Dados de pré-processamento: transforme os dados de entrada brutos para corresponder ao formato esperado do seu modelo. Para modelos de imagem, esse processo normalmente envolve:
    • Decodificação de bytes de imagem.
    • Redimensionamento para uma dimensão de destino (por exemplo, 224×224).
    • Converter o espaço de cores (por exemplo, RGB para BGR).
    • Normalização de valores de pixel para o intervalo esperado (0–1 ou -1 a 1).
    • Organizando os dados no layout tensor correto: NCHW (lote, canais, altura, largura) ou NHWC (lote, altura, largura, canais).
  2. Executar inferência: converta dados pré-processados em tensores usando a wasi-nn interface, carregue seu modelo ONNX incorporado com o back-end da CPU, defina tensores de entrada no contexto de execução, invoque a passagem direta do modelo e recupere tensores de saída contendo previsões brutas.
  3. Saídas pós-processo: transforme saídas brutas do modelo em resultados significativos. Operações comuns:
    • Aplique softmax para produzir probabilidades de classificação.
    • Selecione as principais K previsões.
    • Aplique um limite de confiança para filtrar resultados de baixa confiança.
    • Mapeie índices de previsão para rótulos legíveis por humanos.
    • Formatar resultados para consumo a jusante.

Nos exemplos de IoT para operadores Rust WASM pode encontrar dois exemplos que seguem este padrão:

Configurar definição de gráfico

Para habilitar a inferência ONNX em seu gráfico de fluxo de dados, você precisa configurar a estrutura do gráfico e os parâmetros do módulo. A definição do gráfico especifica o fluxo do pipeline, enquanto as configurações do módulo permitem a personalização do tempo de execução do comportamento de pré-processamento e inferência.

Ativar suporte WASI-NN

Para habilitar o suporte à interface da Rede Neural WebAssembly, adicione o wasi-nn recurso à sua definição de gráfico:

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

Definir operações e fluxo de dados

Configure as operações que formam seu pipeline de inferência. Este exemplo mostra um fluxo de trabalho típico de classificação de imagens:

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

Esta configuração cria um pipeline onde:

  • camera-input recebe dados brutos de imagem de uma fonte
  • module-format/map pré-processa imagens (decodificar, redimensionar, formatar a conversão)
  • module-snapshot/map executa a inferência e o pós-processamento ONNX
  • results-output emite resultados de classificação para um sumidouro

Configurar parâmetros do módulo

Defina parâmetros de tempo de execução para personalizar o comportamento do módulo sem reconstruir. Esses parâmetros são passados para seus módulos WASM na inicialização:

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

Seu operador init pode ler esses valores através da interface de configuração do módulo. Para obter detalhes, consulte Parâmetros de configuração do módulo.

Empacotar o modelo

A incorporação de modelos ONNX diretamente em seu componente WASM garante a implantação atômica e a consistência da versão. Essa abordagem simplifica a distribuição e remove dependências de tempo de execução em arquivos de modelo externos ou registros.

Sugestão

A incorporação mantém a versão conjunta do modelo e da lógica do operador. Para atualizar um modelo, publique uma nova versão do módulo e atualize sua definição de gráfico para fazer referência a ele. Essa abordagem elimina o desvio do modelo e garante implantações reproduzíveis.

Diretrizes de preparação do modelo

Antes de incorporar seu modelo, verifique se ele atende aos requisitos para a implantação do WASM:

  • Mantenha os modelos abaixo de 50 MB para tempos de carregamento WASM práticos e restrições de memória.
  • Verifique se seu modelo aceita uma única entrada de tensor em um formato comum (float32 ou uint8).
  • Verifique se o backend de execução WASM ONNX suporta todos os operadores que o seu modelo utiliza.
  • Use ferramentas de otimização ONNX para reduzir o tamanho do modelo e melhorar a velocidade de inferência.

Incorporar fluxo de trabalho

Siga estas etapas para incorporar seu modelo e recursos associados:

  1. Organizar recursos do modelo: coloque o arquivo de modelo e, se necessário, o .onnxlabels.txt na sua árvore de origem. Use uma estrutura de diretórios dedicada, como src/fixture/models/ e src/fixture/labels/ para uma organização clara.
  2. Incorporar em tempo de compilação: utilize mecanismos específicos do idioma para incluir os bytes de dados do modelo no seu binário. Em Rust, use include_bytes! para dados binários e include_str! para arquivos de texto.
  3. Inicializar gráfico WASI-NN: Na função do init operador, crie um wasi-nn gráfico a partir dos bytes incorporados, especificando a codificação ONNX e o alvo de execução da CPU.
  4. Implementar loop de inferência: para cada mensagem recebida, pré-processe entradas para corresponder aos requisitos do modelo, defina tensores de entrada, execute inferência, recupere saídas e aplique pós-processamento.
  5. Manipule erros normalmente: implemente o tratamento adequado de erros para falhas de carregamento de modelo, operadores sem suporte e erros de inferência de tempo de execução.

Para obter um padrão de implementação completo, consulte o exemplo de "instantâneo".

Organize seu projeto de módulo WASM com separação clara de preocupações:

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

Exemplos de referências de ficheiros

Use o seguinte layout de arquivo do exemplo de "instantâneo" como referência:

Exemplo de incorporação mínima

O exemplo a seguir mostra a incorporação mínima de Rust. Os caminhos são relativos ao arquivo de origem que contém a macro:

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

Otimização do desempenho

Para evitar recriar o gráfico ONNX e o contexto de execução de cada mensagem, inicialize-o uma vez e reutilize-o. O exemplo público usa um estático 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()?;
  }
}

Implante seus módulos

Reutilize os construtores de amostras simplificados ou construa localmente:

Siga este processo de implantação:

  1. Compile o módulo WASM em modo de lançamento e produza um arquivo <module-name>-<version>.wasm.
  2. Envie o módulo e, se desejar, uma definição de gráfico para o seu registo usando OCI Registry as Storage (ORAS).
  3. Crie ou reutilize um endpoint de registo nas Operações do Azure IoT.
  4. Crie um recurso de grafo de fluxo de dados que faça referência ao artefato de definição do grafo.

Exemplo: classificação de imagem MobileNet

Os exemplos públicos de IoT fornecem dois exemplos conectados em um gráfico para classificação de imagem: o exemplo de "formato" fornece a funcionalidade de decodificação e redimensionamento de imagem e o exemplo de "instantâneo" fornece inferência ONNX e processamento softmax.

Para implantar este exemplo, extraia os artefatos do registro público, envie-os por push para o registro e implante um gráfico de fluxo de dados, conforme mostrado no Exemplo 2: Implantar um gráfico complexo. O gráfico complexo usa esses módulos para processar instantâneos de imagem e emitir resultados de classificação.

Limitações

A inferência em gráficos de fluxo de dados WASM tem as seguintes limitações:

  • Apenas ONNX. Os gráficos de fluxo de dados não suportam outros formatos como o TFLite.
  • Apenas CPU. Sem aceleração GPU/TPU.
  • Recomendam-se modelos pequenos. Não há suporte para modelos grandes e inferência com uso intensivo de memória.
  • Modelos de entrada de tensor único são suportados. Não há suporte para modelos com várias entradas, cache de chave-valor e cenários avançados de sequência e de geração.
  • Assegure-se de que o backend ONNX no tempo de execução do WASM suporta os operadores do seu modelo. Se um operador não for suportado, a inferência falhará no tempo de carga ou execução.

Próximos passos