นี่คือคำแนะนำ LiteRT.js แบบต้นทางถึงปลายทางที่ครอบคลุมกระบวนการแปลงโมเดล PyTorch เพื่อเรียกใช้ในเบราว์เซอร์ด้วยการเร่งความเร็ว WebGPU ตัวอย่างนี้ใช้ ResNet18 สำหรับโมเดลการมองเห็น และ TensorFlow.js สำหรับ การประมวลผลล่วงหน้าและหลังการประมวลผล
คู่มือนี้จะครอบคลุมขั้นตอนต่อไปนี้
- แปลงโมเดล PyTorch เป็น LiteRT โดยใช้ AI Edge
Torch
- เพิ่มแพ็กเกจ LiteRT ลงในเว็บแอป
- โหลดโมเดล
- เขียนตรรกะก่อนและหลังการประมวลผล
แปลงเป็น LiteRT
ใช้สมุดบันทึก PyTorch Converter
เพื่อแปลงโมเดล PyTorch เป็นรูปแบบ .tflite
ที่เหมาะสม ดูคำแนะนำแบบเจาะลึกเกี่ยวกับประเภทข้อผิดพลาดที่คุณอาจพบและวิธีแก้ไขได้ใน AI
Edge Torch Converter
README
โมเดลของคุณต้องใช้งานร่วมกับ
torch.export.export
ได้ ซึ่งหมายความว่าต้องส่งออกด้วย TorchDynamo ได้ ดังนั้น จึงต้องไม่มี
สาขาแบบมีเงื่อนไขของ Python ที่ขึ้นอยู่กับค่ารันไทม์ภายในเทนเซอร์ หากคุณเห็นข้อผิดพลาดต่อไปนี้ระหว่างtorch.export.export
โมเดลของคุณจะส่งออกด้วย torch.export.export
ไม่ได้ นอกจากนี้ โมเดลต้องไม่มีมิติข้อมูลอินพุตหรือเอาต์พุตแบบไดนามิกในเทนเซอร์ ซึ่งรวมถึง
มิติข้อมูลกลุ่ม
นอกจากนี้ คุณยังเริ่มต้นด้วยโมเดล PyTorch ที่เข้ากันได้กับ TensorRT หรือส่งออกเป็น ONNX ได้ด้วย
โมเดลเวอร์ชันที่เข้ากันได้กับ TensorRT อาจเป็นจุดเริ่มต้นที่ดี เนื่องจาก การแปลง TensorRT บางประเภทยังกำหนดให้โมเดลต้องส่งออกได้ใน TorchDynamo ด้วย หาก คุณใช้การดำเนินการ NVIDIA / CUDA ในโมเดล คุณจะต้องแทนที่การดำเนินการเหล่านั้น ด้วยการดำเนินการ PyTorch มาตรฐาน
โมเดล PyTorch ที่ส่งออกได้ใน ONNX อาจเป็นจุดเริ่มต้นที่ดี แม้ว่าโมเดล ONNX บางรุ่นจะใช้ TorchScript แทน TorchDynamo ในการส่งออก ในกรณีนี้ โมเดลอาจส่งออกไม่ได้ใน TorchDynamo (แม้ว่าอาจจะใกล้เคียงกว่าโค้ดโมเดลเดิม)
ดูข้อมูลเพิ่มเติมได้ที่แปลงโมเดล PyTorch เป็น LiteRT
เพิ่มแพ็กเกจ LiteRT
ติดตั้งแพ็กเกจ @litertjs/core
จาก npm โดยใช้คำสั่งต่อไปนี้
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 เพื่อส่ง Tensor ไปยัง 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
ได้
หากต้องการสร้างอินพุตปลอม คุณต้องทราบชื่อและรูปร่างของเทนเซอร์อินพุต
ซึ่งสามารถค้นหาได้ด้วย LiteRT.js โดยการเรียกใช้ model.getInputDetails
หรือ
model.getOutputDetails
วิธีง่ายๆ ในการค้นหาคือการตั้งค่าเบรกพอยต์หลังจากสร้างโมเดลแล้ว หรือจะใช้โปรแกรมสำรวจโมเดลก็ได้
เมื่อทราบรูปร่างและชื่อของอินพุตและเอาต์พุตแล้ว คุณจะทดสอบโมเดลด้วยอินพุตจำลองได้ ซึ่งจะช่วยให้คุณมั่นใจได้ว่าโมเดลจะทำงานก่อนที่คุณจะเขียนไปป์ไลน์แมชชีนเลิร์นนิงที่เหลือ ซึ่งจะทดสอบว่าระบบรองรับการดำเนินการทั้งหมดของโมเดล หรือไม่ เช่น
// 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