開始使用 LiteRT.js

本指南將從頭到尾介紹 LiteRT.js,說明如何轉換 PyTorch 模型,以便在瀏覽器中以 WebGPU 加速功能執行。本範例使用 ResNet18 做為視覺模型,並使用 TensorFlow.js 進行前處理和後處理。

本指南將說明以下步驟:

  1. 使用 AI Edge Torch 將 PyTorch 模型轉換為 LiteRT。
    1. 將 LiteRT 套件新增至網頁應用程式。
  2. 載入模型。
  3. 撰寫前處理和後處理邏輯。

轉換為 LiteRT

使用 PyTorch 轉換器筆記本,將 PyTorch 模型轉換為適當的 .tflite 格式。如需可能遇到的錯誤類型和修正方式的深入指南,請參閱 AI Edge Torch 轉換器 README

模型必須與 torch.export.export 相容,也就是必須能透過 TorchDynamo 匯出。因此,不得有任何依附於張量中執行階段值的 Python 條件分支。如果在 torch.export.export 期間看到下列錯誤,表示模型無法透過 torch.export.export 匯出。此外,模型的張量也不得有任何動態輸入或輸出維度。這包括批次維度。

您也可以從與 TensorRT 相容或可匯出 ONNX 的 PyTorch 模型著手:

  • 模型必須可匯出為 TorchDynamo,才能進行某些類型的 TensorRT 轉換,因此 TensorRT 相容模型是個不錯的起點。如果模型中使用了任何 NVIDIA / CUDA 作業,請將其替換為標準 PyTorch 作業。

  • 可匯出 ONNX 的 PyTorch 模型是不錯的起點,但部分 ONNX 模型會使用 TorchScript 而非 TorchDynamo 匯出,在這種情況下,模型可能無法匯出 TorchDynamo (雖然可能比原始模型程式碼更接近)。

詳情請參閱將 PyTorch 模型轉換為 LiteRT

新增 LiteRT 套件

從 npm 安裝 @litertjs/core 套件:

npm install @litertjs/core

匯入套件並載入其 Wasm 檔案:

import {loadLiteRt} from '@litertjs/core';

// They are located in node_modules/@litertjs/core/wasm/
// Serve them statically on your server.
await loadLiteRt(`your/path/to/wasm/`);

載入模型

匯入並初始化 LiteRT.js 和 LiteRT-TFJS 轉換公用程式。您也需要匯入 TensorFlow.js,才能將張量傳遞至 LiteRT.js。

import {CompileOptions, loadAndCompile, loadLiteRt, setWebGpuDevice} from '@litertjs/core';
import {runWithTfjsTensors} from '@litertjs/tfjs-interop';

// TensorFlow.js imports
import * as tf from '@tensorflow/tfjs';
import '@tensorflow/tfjs-backend-webgpu'; // Only WebGPU is supported
import {WebGPUBackend} from '@tensorflow/tfjs-backend-webgpu';

async function main() {
  // Initialize TensorFlow.js WebGPU backend
  await tf.setBackend('webgpu');

  // Initialize LiteRT.js's Wasm files
  await loadLiteRt('your/path/to/wasm/');

  // Make LiteRt use the same GPU device as TFJS (for tensor conversion)
  const backend = tf.backend() as WebGPUBackend;
  setWebGpuDevice(backend.device);
  // ...
}

main();

載入轉換後的 LiteRT 模型:

const model = await loadAndCompile('path_to_model.tflite', {
  accelerator: 'webgpu', // or 'wasm'
});

編寫模型管道

編寫前處理和後處理邏輯,將模型連結至應用程式。建議使用 TensorFlow.js 進行前處理和後處理,但如果不是以 TensorFlow.js 編寫,您可以呼叫 await tensor.data 將值做為 ArrayBuffer 取得,或呼叫 await tensor.array 取得結構化 JS 陣列。

以下是 ResNet18 的端對端管道範例:

// Wrap in a tf.tidy call to automatically clean up intermediate TensorFlow.js tensors.
// (Note: tidy only supports synchronous functions).
const top5 = tf.tidy(() => {
  // Get RGB data values from an image element and convert it to range [0, 1).
  const image = tf.browser.fromPixels(dogs, 3).div(255);

  // These preprocessing steps come from https://github.com/pytorch/vision/blob/main/torchvision/models/resnet.py#L315
  // The mean and standard deviation for the image normalization come from https://github.com/pytorch/vision/blob/main/torchvision/transforms/_presets.py#L38
  const imageData = image.resizeBilinear([224, 224])
    .sub([0.485, 0.456, 0.406])
    .div([0.229, 0.224, 0.225])
    .reshape([1, 224, 224, 3])
    .transpose([0, 3, 1, 2]);

  // You can pass inputs as a single tensor, an array, or a JS Object
  // where keys are the tensor names in the TFLite model.
  // When passing an Object, the output is also an Object.
  // Here, we're passing a single tensor, so the output is an array.
  const probabilities = runWithTfjsTensors(model, imageData)[0];

  // Get the top five classes.
  return tf.topk(probabilities, 5);
});

const values = await top5.values.data();
const indices = await top5.indices.data();
top5.values.dispose(); // Clean up the tfjs tensors.
top5.indices.dispose();

// Print the top five classes.
const classes = ... // Class names are loaded from a JSON file in the demo.
for (let i = 0; i < 5; ++i) {
  const text = `${classes[indices[i]]}: ${values[i]}`;
  console.log(text);
}

測試及疑難排解

請參閱下列章節,瞭解如何測試應用程式及處理錯誤。

使用虛假輸入內容進行測試

載入模型後,建議先使用虛假輸入內容測試模型,這樣一來,您就能在花時間為模型管道編寫前後處理邏輯之前,先找出所有執行階段錯誤。如要檢查這點,可以使用 LiteRT.js 模型測試工具,或手動測試。

LiteRT.js 模型測試工具

LiteRT.js 模型測試工具會使用隨機輸入內容,在 GPU 和 CPU 上執行模型,確認模型是否能在 GPU 上正常運作。小幫手會檢查下列項目:

  • 是否支援輸入和輸出資料類型。
  • 所有作業是否都能在 GPU 上執行。
  • GPU 輸出內容與參考 CPU 輸出內容的相符程度。
  • GPU 推論的效能。

如要執行 LiteRT.js 模型測試工具,請依序執行 npm i @litertjs/model-testernpx model-tester。系統會開啟瀏覽器分頁,供您執行模型。

手動測試模型

如果您想手動測試模型,而非使用 LiteRT.js 模型測試工具 (@litertjs/model-tester),可以產生虛擬輸入內容,並使用 runWithTfjsTensors 執行模型。

如要產生虛擬輸入內容,您需要知道輸入張量的名稱和形狀。呼叫 model.getInputDetailsmodel.getOutputDetails,即可透過 LiteRT.js 找到這些項目。如要輕鬆找到這些項目,請在模型建立後設定中斷點。您也可以使用「模型多層檢視」

瞭解輸入和輸出形狀和名稱後,您可以使用虛擬輸入測試模型。這樣一來,您就能確信模型會執行,再編寫其餘的機器學習管道。這會測試是否支援所有模型作業。例如:

// Imports, initialization, and model loading...
// Create fake inputs for the model
const fakeInputs = model.getInputDetails().map(
    ({shape, dtype}) => tf.ones(shape, dtype));

// Run the model
const outputs = runWithTfjsTensors(model, fakeInputs);
console.log(outputs);

錯誤類型

LiteRT.js 可能不支援部分 LiteRT 模型。錯誤通常可分為以下類別:

  • 形狀不符:已知錯誤,只會影響 GPU。
  • 不支援這項作業:執行階段不支援模型中的作業。WebGPU 後端的涵蓋範圍比 CPU 更有限,因此如果在 GPU 上看到這項錯誤,或許可以改用 CPU 執行模型。
  • 不支援的張量類型:LiteRT.js 僅支援 int32 和 float32 張量,做為模型輸入和輸出。
  • 模型過大:LiteRT.js 可載入的模型大小有限。

不支援這項作業

這表示所用的後端不支援模型中的其中一項作業。您需要重新編寫原始 PyTorch 模型,避免使用這項作業並重新轉換,或是改用 CPU 執行模型。

如果是 BROADCAST_TO,只要讓模型的所有輸入張量都採用相同的批次維度,即可解決這個問題。其他情況可能較為複雜。

不支援的張量類型

LiteRT.js 僅支援模型的 int32 和 float32 張量輸入和輸出。

模型太大

這通常會顯示為對 Aborted() 的呼叫,或模型載入時的記憶體配置失敗。LiteRT.js 可載入的模型大小有限,因此如果看到這則訊息,表示模型可能過大。您可以嘗試使用 ai-edge-quantizer 量化權重,但請將計算作業保留在 float32 或 float16,並將模型輸入和輸出內容設為 float32 或 int32。