بدء استخدام LiteRT.js

هذا دليل شامل حول LiteRT.js يغطي عملية تحويل نموذج PyTorch لتشغيله في المتصفح باستخدام تسريع WebGPU. يستخدم هذا المثال ResNet18 لنموذج الرؤية، وTensorFlow.js للمعالجة المسبقة واللاحقة.

سيتناول الدليل الخطوات التالية:

  1. حوِّل نموذج PyTorch إلى LiteRT باستخدام AI Edge Torch.
    1. أضِف حزمة LiteRT إلى تطبيق الويب.
  2. حمِّل النموذج.
  3. كتابة منطق المعالجة المسبقة واللاحقة

التحويل إلى LiteRT

استخدِم دفتر ملاحظات PyTorch Converter لتحويل نموذج PyTorch إلى تنسيق .tflite المناسب. للحصول على دليل مفصّل حول أنواع الأخطاء التي قد تواجهها وكيفية إصلاحها، يُرجى الاطّلاع على ملف README الخاص بأداة AI Edge Torch Converter.

يجب أن يكون النموذج متوافقًا مع 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 لتمرير الموترات إلى 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 Model Tester

يشغّل أداة اختبار النماذج LiteRT.js نموذجك على وحدة معالجة الرسومات ووحدة المعالجة المركزية باستخدام مدخلات عشوائية للتحقّق من أنّ النموذج يعمل بشكل صحيح على وحدة معالجة الرسومات. يفحص المساعِد ما يلي:

  • تحديد ما إذا كانت أنواع بيانات الإدخال والإخراج متوافقة
  • ما إذا كانت جميع العمليات متاحة على وحدة معالجة الرسومات.
  • مدى تطابق مخرجات وحدة معالجة الرسومات مع مخرجات وحدة المعالجة المركزية المرجعية
  • أداء الاستدلال في وحدة معالجة الرسومات

لتشغيل أداة اختبار نموذج 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 مع LiteRT.js. تندرج الأخطاء عادةً ضمن الفئات التالية:

  • عدم تطابق الشكل: خطأ معروف يؤثر في وحدة معالجة الرسومات فقط.
  • العملية غير متاحة: لا يتيح وقت التشغيل تنفيذ عملية في النموذج. تتوفّر إمكانية استخدام WebGPU بشكل محدود أكثر من وحدة المعالجة المركزية، لذا إذا ظهرت لك هذه الرسالة على وحدة معالجة الرسومات، قد تتمكّن من تشغيل النموذج على وحدة المعالجة المركزية بدلاً من ذلك.
  • نوع Tensor غير متوافق: لا يتيح LiteRT.js استخدام سوى int32 وfloat32 tensors كمدخلات ومخرجات للنموذج.
  • النموذج كبير جدًا: يقتصر حجم النماذج التي يمكن تحميلها في LiteRT.js على حدّ معيّن.

العملية غير متاحة

يشير ذلك إلى أنّ الخلفية المستخدَمة لا تتوافق مع إحدى العمليات في النموذج. عليك إعادة كتابة نموذج PyTorch الأصلي لتجنُّب هذه العملية وإعادة تحويله، أو قد تتمكّن من تشغيل النموذج على وحدة المعالجة المركزية.

في حالة BROADCAST_TO، يمكن حلّ هذه المشكلة من خلال جعل بُعد الدفعة هو نفسه لكل موتر إدخال للنموذج. وقد تكون حالات أخرى أكثر تعقيدًا.

نوع Tensor غير متوافق

لا يتيح LiteRT.js سوى استخدام موترات int32 وfloat32 لمدخلات النموذج ومخرجاته.

النموذج كبير جدًا

يظهر هذا الخطأ عادةً على شكل طلب إلى Aborted() أو تعذُّر تخصيص الذاكرة في وقت تحميل النموذج. يتم فرض قيود على حجم النماذج التي يمكن تحميلها باستخدام LiteRT.js، لذا إذا ظهرت لك هذه الرسالة، قد يكون حجم النموذج كبيرًا جدًا. يمكنك محاولة تحديد عدد البتات للأوزان باستخدام ai-edge-quantizer، ولكن احتفِظ بالعمليات الحسابية على float32 أو float16، واحتفِظ بمدخلات ومخرجات النموذج على float32 أو int32.