با LiteRT.js شروع کنید

این یک راهنمای جامع LiteRT.js است که فرآیند تبدیل یک مدل PyTorch را برای اجرا در مرورگر با شتاب‌دهی WebGPU پوشش می‌دهد. این مثال از ResNet18 برای مدل بینایی و از TensorFlow.js برای پیش‌پردازش و پس‌پردازش استفاده می‌کند.

این راهنما مراحل زیر را پوشش خواهد داد:

  1. مدل PyTorch خود را با استفاده از AI Edge Torch به LiteRT تبدیل کنید. 1. بسته LiteRT را به برنامه وب خود اضافه کنید.
  2. مدل را بارگذاری کنید.
  3. منطق پیش و پس پردازش را بنویسید.

تبدیل به LiteRT

از دفترچه راهنمای مبدل PyTorch برای تبدیل یک مدل PyTorch به فرمت .tflite مناسب استفاده کنید. برای راهنمای جامع در مورد انواع خطاهایی که ممکن است با آنها مواجه شوید و نحوه رفع آنها، به فایل راهنمای مبدل مشعل لبه هوش مصنوعی (AI Edge Torch Converter README) مراجعه کنید.

مدل شما باید با torch.export.export سازگار باشد، به این معنی که باید با TorchDynamo قابل استخراج باشد. بنابراین، نباید هیچ شاخه شرطی پایتون داشته باشد که به مقادیر زمان اجرا در تانسورها بستگی داشته باشد. اگر در طول torch.export.export خطاهای زیر را مشاهده کردید، مدل شما با torch.export.export قابل استخراج نیست. همچنین مدل شما نباید هیچ ابعاد ورودی یا خروجی پویایی در تانسورهای خود داشته باشد. این شامل ابعاد دسته‌ای نیز می‌شود.

همچنین می‌توانید با یک مدل PyTorch سازگار با TensorRT یا قابل استخراج با ONNX شروع کنید:

  • یک نسخه سازگار با TensorRT از یک مدل می‌تواند نقطه شروع خوبی باشد، زیرا برخی از انواع تبدیل‌های TensorRT نیز نیاز دارند که مدل‌ها قابل خروجی گرفتن با TorchDynamo باشند. اگر از هرگونه عملیات NVIDIA / CUDA در مدل استفاده می‌کنید، باید آنها را با عملیات استاندارد PyTorch جایگزین کنید.

  • یک مدل PyTorch قابل استخراج توسط ONNX می‌تواند نقطه شروع خوبی باشد، اگرچه برخی از مدل‌های ONNX به جای TorchDynamo از TorchScript برای استخراج استفاده می‌کنند که در این صورت ممکن است مدل قابل استخراج توسط TorchDynamo نباشد (اگرچه احتمالاً از کد مدل اصلی نزدیک‌تر است).

برای اطلاعات بیشتر، به تبدیل مدل‌های PyTorch به LiteRT مراجعه کنید.

بسته LiteRT را اضافه کنید

پکیج @litertjs/core را از npm نصب کنید:

npm install @litertjs/core

بسته را وارد کنید و فایل‌های Wasm آن را بارگذاری کنید:

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

// Load the LiteRT.js Wasm files from a CDN.
await loadLiteRt('https://cdn.jsdelivr.net/npm/@litertjs/core/wasm/')
// Alternatively, host them from your server.
// They are located in node_modules/@litertjs/core/wasm/
await loadLiteRt(`your/path/to/wasm/`);

مدل را بارگذاری کنید

LiteRT.js و ابزارهای تبدیل LiteRT-TFJS را وارد و مقداردهی اولیه کنید. همچنین برای ارسال تنسورها به LiteRT.js باید TensorFlow.js را وارد کنید.

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

// TensorFlow.js imports
import * as tf from '@tensorflow/tfjs';
import '@tensorflow/tfjs-backend-webgpu';
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 TFJS use the same GPU device as LiteRT.js (for tensor conversion)
  const device = await getWebGpuDevice();
  tf.removeBackend('webgpu');
  tf.registerBackend('webgpu', () => new WebGPUBackend(device, device.adapterInfo));
  await tf.setBackend('webgpu');
  // ...
}

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 imageData = 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
  return 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]);
});

// Run the model
const outputs = await runWithTfjsTensors(model, [imageData]);
const probabilities = outputs[0];

// Get the top five classes.
const top5 = tf.topk(probabilities, 5);

const values = await top5.values.data();
const indices = await top5.indices.data();

// Clean up TFJS tensors
tf.dispose(outputs);
tf.dispose(top5);
tf.dispose(imageData);

// 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 Model Tester استفاده کنید یا آن را به صورت دستی آزمایش کنید.

تستر مدل 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 پیدا کرد. روش دیگر، استفاده از Model Explorer است .

وقتی شکل‌ها و نام‌های ورودی و خروجی را دانستید، می‌توانید مدل را با یک ورودی جعلی آزمایش کنید. این کار به شما اطمینان می‌دهد که مدل قبل از نوشتن بقیه‌ی خط لوله‌ی یادگیری ماشین، اجرا خواهد شد. این کار آزمایش می‌کند که آیا تمام عملیات مدل پشتیبانی می‌شوند یا خیر. برای مثال:

// 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 = await runWithTfjsTensors(model, fakeInputs);
console.log(outputs);

انواع خطا

برخی از مدل‌های LiteRT ممکن است توسط LiteRT.js پشتیبانی نشوند. خطاها معمولاً در این دسته‌ها قرار می‌گیرند:

  • عدم تطابق شکل : یک اشکال شناخته شده که فقط بر پردازنده گرافیکی (GPU) تأثیر می‌گذارد.
  • عملیات پشتیبانی نمی‌شود : زمان اجرا از عملیاتی در مدل پشتیبانی نمی‌کند. پوشش بک‌اند WebGPU محدودتر از CPU است، بنابراین اگر این خطا را روی GPU مشاهده می‌کنید، ممکن است بتوانید مدل را روی CPU اجرا کنید.
  • نوع تنسور پشتیبانی نشده : LiteRT.js فقط از تنسورهای int32 و float32 برای ورودی‌ها و خروجی‌های مدل پشتیبانی می‌کند.
  • مدل خیلی بزرگ است : LiteRT.js در اندازه مدل‌هایی که می‌تواند بارگذاری کند، محدود است.

عملیات پشتیبانی نمی‌شود

این نشان می‌دهد که backend مورد استفاده از یکی از عملیات موجود در مدل پشتیبانی نمی‌کند. برای جلوگیری از این مشکل و تبدیل مجدد آن، باید مدل اصلی PyTorch را بازنویسی کنید، یا ممکن است بتوانید مدل را روی CPU اجرا کنید.

در مورد BROADCAST_TO ، این مشکل را می‌توان با یکسان کردن ابعاد دسته برای هر تانسور ورودی به مدل حل کرد. موارد دیگر ممکن است پیچیده‌تر باشند.

نوع تانسور پشتیبانی نشده

LiteRT.js فقط از تانسورهای int32 و float32 برای ورودی‌ها و خروجی‌های مدل پشتیبانی می‌کند.

مدل خیلی بزرگ

این معمولاً به صورت فراخوانی تابع Aborted() یا خطای تخصیص حافظه در زمان بارگذاری مدل ظاهر می‌شود. LiteRT.js در اندازه مدل‌هایی که می‌تواند بارگذاری کند، محدود است، بنابراین اگر این را مشاهده می‌کنید، ممکن است مدل شما خیلی بزرگ باشد. می‌توانید کوانتیزه کردن وزن‌ها را با ai-edge-quantizer امتحان کنید، اما محاسبات را در float32 یا float16 نگه دارید و ورودی‌ها و خروجی‌ها را به صورت float32 یا int32 مدل‌سازی کنید.