เริ่มต้นใช้งาน LiteRT.js

นี่คือคำแนะนำ LiteRT.js แบบต้นทางถึงปลายทางที่ครอบคลุมกระบวนการแปลงโมเดล PyTorch เพื่อเรียกใช้ในเบราว์เซอร์ด้วยการเร่งความเร็ว WebGPU ตัวอย่างนี้ใช้ ResNet18 สำหรับโมเดลการมองเห็น และ TensorFlow.js สำหรับ การประมวลผลล่วงหน้าและหลังการประมวลผล

คู่มือนี้จะครอบคลุมขั้นตอนต่อไปนี้

  1. แปลงโมเดล PyTorch เป็น LiteRT โดยใช้ AI Edge Torch
    1. เพิ่มแพ็กเกจ LiteRT ลงในเว็บแอป
  2. โหลดโมเดล
  3. เขียนตรรกะก่อนและหลังการประมวลผล

แปลงเป็น 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