本指南將從頭到尾介紹 LiteRT.js,說明如何轉換 PyTorch 模型,以便在瀏覽器中以 WebGPU 加速功能執行。本範例使用 ResNet18 做為視覺模型,並使用 TensorFlow.js 進行前處理和後處理。
本指南將說明以下步驟:
- 使用 AI Edge Torch 將 PyTorch 模型轉換為 LiteRT。
- 將 LiteRT 套件新增至網頁應用程式。
- 載入模型。
- 撰寫前處理和後處理邏輯。
轉換為 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-tester
和 npx model-tester
。系統會開啟瀏覽器分頁,供您執行模型。
手動測試模型
如果您想手動測試模型,而非使用 LiteRT.js 模型測試工具 (@litertjs/model-tester
),可以產生虛擬輸入內容,並使用 runWithTfjsTensors
執行模型。
如要產生虛擬輸入內容,您需要知道輸入張量的名稱和形狀。呼叫 model.getInputDetails
或 model.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。