Verwendung des WebGPU Execution Providers

Dieses Dokument erklärt, wie der WebGPU Execution Provider in ONNX Runtime verwendet wird.

Inhalt

Grundlagen

Was ist WebGPU? Sollte ich es verwenden?

WebGPU ist ein neuer Webstandard für allgemeine GPU-Berechnungen und Grafiken. Er ist als Low-Level-API konzipiert, basierend auf D3D12, Vulkan und Metal, und für die Verwendung im Browser gedacht. Er ist effizienter und leistungsfähiger als WebGL und für maschinelles Lernen, Grafiken und andere Rechenaufgaben konzipiert.

WebGPU ist in den neuesten Versionen von Chrome und Edge unter Windows, macOS, Android und ChromeOS sofort verfügbar. Es ist auch in Firefox hinter einem Flag und in Safari Technology Preview verfügbar. Weitere Informationen finden Sie unter WebGPU-Status.

Wenn Sie ONNX Runtime Web für die Inferenz sehr leichter Modelle in Ihrer Webanwendung verwenden und eine kleine Binärgröße wünschen, können Sie weiterhin den standardmäßigen WebAssembly (WASM) Execution Provider verwenden. Wenn Sie rechenintensivere Modelle ausführen möchten oder die GPU des Client-Geräts nutzen möchten, können Sie den WebGPU Execution Provider verwenden.

Wie verwende ich den WebGPU EP in ONNX Runtime Web

Dieser Abschnitt geht davon aus, dass Sie Ihre Webanwendung bereits mit ONNX Runtime Web eingerichtet haben. Wenn nicht, können Sie die Erste Schritte für grundlegende Informationen befolgen.

Um den WebGPU EP zu verwenden, müssen Sie nur 2 kleine Änderungen vornehmen

  1. Aktualisieren Sie Ihre Importanweisung

    • Ändern Sie für das HTML-Skript-Tag ort.min.js in ort.webgpu.min.js
      <script src="https://example.com/path/ort.webgpu.min.js"></script>
      
    • Ändern Sie für die JavaScript-Importanweisung onnxruntime-web in onnxruntime-web/webgpu
      import * as ort from 'onnxruntime-web/webgpu';
      

    Weitere Informationen finden Sie unter Bedingtes Importieren.

  2. Geben Sie den 'webgpu' EP explizit in den Sitzungsoptionen an

    const session = await ort.InferenceSession.create(modelPath, { ..., executionProviders: ['webgpu'] });
    

Sie können auch erwägen, die neueste Nightly Build-Version von ONNX Runtime Web (onnxruntime-web@dev) zu installieren, um von den neuesten Funktionen und Verbesserungen zu profitieren.

WebGPU EP-Funktionen

ONNX Runtime Web bietet die folgenden Funktionen, die bei der Verwendung mit dem WebGPU EP hilfreich sein können

Graph-Erfassung

Sie können die Graph-Erfassungsfunktion ausprobieren, wenn Ihr Modell statische Formen hat und alle seine Berechnungskernels auf dem WebGPU EP laufen. Diese Funktion kann potenziell die Leistung Ihres Modells verbessern.

Weitere Informationen finden Sie unter Graph-Erfassung.

Verwendung von ort.env.webgpu Flags

Weitere Informationen finden Sie unter env.webgpu.

Tensor-Daten auf der GPU belassen (IO-Binding)

Standardmäßig sind die Ein- und Ausgaben eines Modells Tensoren, die Daten im CPU-Speicher enthalten. Wenn Sie eine Sitzung mit dem WebGPU EP ausführen, werden die Daten in den GPU-Speicher kopiert und die Ergebnisse zurück in den CPU-Speicher kopiert. Wenn Sie Ihre Eingabedaten von einer GPU-basierten Quelle erhalten oder die Ausgabedaten für die weitere Verarbeitung auf der GPU belassen möchten, können Sie IO-Binding verwenden, um die Daten auf der GPU zu belassen. Dies ist besonders hilfreich, wenn Sie Transformer-basierte Modelle ausführen, die normalerweise ein einzelnes Modell mehrmals mit der vorherigen Ausgabe als nächste Eingabe ausführen.

Für Modelleingaben, wenn Ihre Eingabedaten ein WebGPU-Speicherpuffer sind, können Sie einen GPU-Tensor erstellen und ihn als Eingabetensor verwenden.

Für Modellausgaben gibt es 2 Möglichkeiten, die IO-Binding-Funktion zu nutzen

Bitte überprüfen Sie auch die folgenden Themen

Eingabetensor aus einem GPU-Puffer erstellen

Wenn Ihre Eingabedaten ein WebGPU-Speicherpuffer sind, können Sie einen GPU-Tensor erstellen und ihn als Eingabetensor verwenden

const inputTensor = ort.Tensor.fromGpuBuffer(inputGpuBuffer, {
  dataType: 'float32',
  dims: [1, 3, 224, 224]
});

Verwenden Sie diesen Tensor als Modelleingaben (Feeds), sodass die Eingabedaten auf der GPU verbleiben.

Vorkonfigurierte GPU-Tensoren verwenden

Wenn Sie die Ausgabeform im Voraus kennen, können Sie einen GPU-Tensor erstellen und ihn als Ausgabetensor verwenden


// Create a pre-allocated buffer and the corresponding tensor. Assuming that the output shape is [10, 1000].
const bufferSize = (10 * 1000) /* number of elements */ * 4 /* bytes per element */;
const device = ort.env.webgpu.device;
const myPreAllocatedBuffer = device.createBuffer({
    usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST | GPUBufferUsage.STORAGE,
    size: Math.ceil(bufferSize / 16) * 16 /* align to 16 bytes */
});

const myPreAllocatedOutputTensor = ort.Tensor.fromGpuBuffer(myPreAllocatedBuffer, {
  dataType: 'float32',
  dims: [10, 1000]
});

// ...

// Run the session with fetches
const feeds = { 'input_0': myInputTensor };
const fetches = { 'output_0': myPreAllocatedOutputTensor };
const results = await mySession.run(feeds, fetches);

Durch Angabe des Ausgabetensors in den Fetches verwendet ONNX Runtime Web den vorkonfigurierten Puffer als Ausgabepuffer. Bei einer Forminkongruenz schlägt der run()-Aufruf fehl.

Speicherort der Ausgabedaten angeben

Wenn Sie keine vorkonfigurierten GPU-Tensoren für Ausgaben verwenden möchten, können Sie den Speicherort der Ausgabedaten auch in den Sitzungsoptionen angeben

const mySessionOptions1 = {
  ...,
  // keep all output data on GPU
  preferredOutputLocation: 'gpu-buffer'
};

const mySessionOptions2 = {
  ...,
  // alternatively, you can specify the output location for each output tensor
  preferredOutputLocation: {
    'output_0': 'cpu',         // keep output_0 on CPU. This is the default behavior.
    'output_1': 'gpu-buffer'   // keep output_1 on GPU buffer
  }
};

Durch Angabe der Konfiguration preferredOutputLocation behält ONNX Runtime Web die Ausgabedaten auf dem angegebenen Gerät.

Weitere Informationen finden Sie in der API-Referenz: preferredOutputLocation.

Hinweise

Null-dimensionale Tensoren

Wenn die Form eines Tensors eine oder mehrere Dimensionen mit der Größe 0 enthält, gilt der Tensor als null-dimensionaler Tensor. Null-dimensionale Tensoren enthalten keine Daten, daher wird der Speicherort der Daten nicht angewendet. ONNX Runtime Web behandelt null-dimensionale Tensoren immer als CPU-Tensoren. Um einen null-dimensionalen Tensor zu erstellen, können Sie den folgenden Code verwenden

const zeroSizedTensor = new ort.Tensor('float32', [], [3, 256, 0, 64]);

Verwaltung des Lebenszyklus von GPU-Tensoren

Es ist wichtig zu verstehen, wie der zugrunde liegende GPU-Puffer verwaltet wird, um Speicherlecks zu vermeiden und die Effizienz der Buffernutzung zu verbessern.

Ein GPU-Tensor wird entweder vom Benutzercode oder von ONNX Runtime Web als Modellausgabe erstellt.

  • Wenn er vom Benutzercode erstellt wird, wird er immer mit einem vorhandenen GPU-Puffer unter Verwendung von Tensor.fromGpuBuffer() erstellt. In diesem Fall "besitzt" der Tensor den GPU-Puffer nicht.

    • Es liegt in der Verantwortung des Benutzers sicherzustellen, dass der zugrunde liegende Puffer während der Inferenz gültig ist, und buffer.destroy() aufzurufen, um den Puffer zu entsorgen, wenn er nicht mehr benötigt wird.
    • Vermeiden Sie das Aufrufen von tensor.getData() und tensor.dispose(). Verwenden Sie den GPU-Puffer direkt.
    • Die Verwendung eines GPU-Tensors mit einem zerstörten GPU-Puffer führt dazu, dass die Sitzung fehlschlägt.
  • Wenn er von ONNX Runtime Web als Modellausgabe erstellt wird (kein vorkonfigurierter GPU-Tensor), "besitzt" der Tensor den Puffer.

    • Sie müssen sich keine Sorgen machen, dass der Puffer zerstört wird, bevor der Tensor verwendet wird.
    • Rufen Sie tensor.getData() auf, um die Daten vom GPU-Puffer auf die CPU herunterzuladen und die Daten als typisiertes Array zu erhalten.
    • Rufen Sie explizit tensor.dispose() auf, um den zugrunde liegenden GPU-Puffer zu zerstören, wenn er nicht mehr benötigt wird.