ایجاد بسته‌های مرورگر با اندازه بهینه‌سازی شده با TensorFlow.js

بررسی اجمالی

TensorFlow.js 3.0 از ساخت بسته‌های مرورگر بهینه‌سازی شده و تولید گرا پشتیبانی می‌کند. به بیان دیگر، می‌خواهیم ارسال جاوا اسکریپت کمتری به مرورگر را برای شما آسان‌تر کنیم.

این ویژگی برای کاربران با موارد استفاده تولیدی طراحی شده است که به ویژه از تراشیدن بایت ها از محموله خود سود می برند (و بنابراین مایلند برای رسیدن به این هدف تلاش کنند). برای استفاده از این ویژگی باید با ماژول‌های ES ، ابزارهای بسته‌بندی جاوا اسکریپت مانند بسته‌بندی وب یا جمع‌آوری و مفاهیمی مانند حذف کدهای درخت تکان دادن/دد-کد آشنا باشید.

این آموزش نحوه ایجاد یک ماژول tensorflow.js سفارشی را نشان می دهد که می تواند با یک باندلر برای ایجاد یک ساخت بهینه اندازه برای یک برنامه با استفاده از tensorflow.js استفاده شود.

واژه شناسی

در زمینه این سند چند اصطلاح کلیدی وجود دارد که ما از آنها استفاده خواهیم کرد:

ماژول های ES - سیستم استاندارد ماژول جاوا اسکریپت . در ES6/ES2015 معرفی شد. با استفاده از اظهارنامه واردات و صادرات قابل شناسایی است.

بسته‌بندی - گرفتن مجموعه‌ای از دارایی‌های جاوا اسکریپت و گروه‌بندی/بسته‌بندی آنها به یک یا چند دارایی جاوا اسکریپت که در مرورگر قابل استفاده هستند. این مرحله ای است که معمولاً دارایی های نهایی را که به مرورگر ارائه می شود تولید می کند. برنامه ها عموماً بسته بندی خود را مستقیماً از منابع کتابخانه ای ترجمه شده انجام می دهند . بسته‌های متداول شامل rollup و webpack هستند. نتیجه نهایی بسته‌بندی، بسته‌ای شناخته می‌شود (یا گاهی اوقات اگر به چند قسمت تقسیم شود، به صورت یک تکه است).

درخت لرزان / حذف کد مرده - حذف کدی که توسط برنامه مکتوب نهایی استفاده نمی شود. این در طول بسته‌بندی، معمولاً در مرحله کوچک‌سازی انجام می‌شود.

عملیات (Ops) - یک عملیات ریاضی روی یک یا چند تانسور که یک یا چند تانسور را به عنوان خروجی تولید می کند. Ops کدهای سطح بالا هستند و می توانند از عملیات های دیگر برای تعریف منطق خود استفاده کنند.

هسته - اجرای خاصی از یک عملیات مرتبط با قابلیت های سخت افزاری خاص. کرنل‌ها «سطح پایین» و مختص باطن هستند. برخی از عملیات ها نقشه برداری یک به یک از عملیات به هسته دارند در حالی که عملیات های دیگر از چندین هسته استفاده می کنند.

دامنه و موارد استفاده

استنتاج فقط مدل های گراف

مورد استفاده اولیه ای که از کاربران مرتبط با این موضوع شنیده ایم و در این نسخه از آن پشتیبانی می شود، استنتاج با مدل های نمودار TensorFlow.js است. اگر از یک مدل لایه‌های TensorFlow.js استفاده می‌کنید، می‌توانید آن را با استفاده از مبدل tfjs به قالب مدل graph-model تبدیل کنید. قالب مدل نمودار برای موارد استفاده استنتاج کارآمدتر است.

دستکاری تانسور سطح پایین با tfjs-core

مورد دیگری که ما پشتیبانی می کنیم برنامه هایی است که مستقیماً از بسته @tensorflow/tjfs-core برای دستکاری تانسور سطح پایین تر استفاده می کنند.

رویکرد ما به ساخت های سفارشی

اصول اصلی ما هنگام طراحی این قابلیت شامل موارد زیر است:

  • از سیستم ماژول جاوا اسکریپت (ESM) حداکثر استفاده را ببرید و به کاربران TensorFlow.js اجازه دهید همین کار را انجام دهند.
  • TensorFlow.js را تا حد امکان توسط باندلرهای موجود (مثلاً بسته وب، جمع‌آوری و غیره) قابل تکان دادن درخت قرار دهید. این به کاربران امکان می‌دهد از تمام قابلیت‌های آن دسته‌ها از جمله ویژگی‌هایی مانند تقسیم کد استفاده کنند.
  • تا حد امکان سهولت استفاده را برای کاربرانی که به اندازه باندل حساس نیستند حفظ کنید. این بدان معناست که ساخت‌های تولیدی به تلاش بیشتری نیاز دارند زیرا بسیاری از پیش‌فرض‌های کتابخانه‌های ما از سهولت استفاده نسبت به ساخت‌های بهینه‌شده با اندازه پشتیبانی می‌کنند.

هدف اصلی گردش کار ما این است که یک ماژول جاوا اسکریپت سفارشی برای TensorFlow.js تولید کنیم که فقط شامل عملکردهای مورد نیاز برای برنامه ای است که ما در تلاش برای بهینه سازی آن هستیم. ما برای انجام بهینه سازی واقعی به باندلرهای موجود متکی هستیم.

در حالی که ما عمدتاً به سیستم ماژول جاوا اسکریپت متکی هستیم، یک ابزار CLI سفارشی را نیز برای مدیریت قطعاتی که تعیین آنها از طریق سیستم ماژول در کد رو به رو کاربر آسان نیست، ارائه می دهیم. دو نمونه از این موارد عبارتند از:

  • مشخصات مدل در فایل های model.json ذخیره شده است
  • سیستم توزیع هسته باطن خاص که ما استفاده می کنیم.

این امر باعث می‌شود که ساخت یک ساخت tfjs سفارشی کمی بیشتر از نشان دادن یک باندلر به بسته معمولی @tensorflow/tfjs درگیر شود.

نحوه ایجاد بسته های سفارشی با اندازه بهینه شده

مرحله 1: تعیین کنید که برنامه شما از کدام هسته استفاده می کند

این مرحله به ما امکان می دهد تمام هسته های استفاده شده توسط هر مدلی را که اجرا می کنید یا کدهای قبل/پس از پردازش را با توجه به باطن انتخابی شما تعیین کنیم.

از tf.profile برای اجرای بخش هایی از برنامه خود که از tensorflow.js استفاده می کنند استفاده کنید و هسته ها را دریافت کنید. چیزی شبیه به این خواهد شد

const profileInfo = await tf.profile(() => {
  // You must profile all uses of tf symbols.
  runAllMyTfjsCode();
});

const kernelNames = profileInfo.kernelNames
console.log(kernelNames);

برای مرحله بعدی آن لیست هسته ها را در کلیپ بورد خود کپی کنید.

شما باید کد را با استفاده از همان Backend(هایی) که می خواهید در بسته سفارشی خود استفاده کنید، نمایه کنید.

اگر مدل شما تغییر کرد یا کد پیش/پس از پردازش تغییر کرد، باید این مرحله را تکرار کنید.

مرحله 2. یک فایل پیکربندی برای ماژول سفارشی tfjs بنویسید

در اینجا یک فایل پیکربندی مثال است.

به نظر می رسد این است:

{
  "kernels": ["Reshape", "_FusedMatMul", "Identity"],
  "backends": [
      "cpu"
  ],
  "models": [
      "./model/model.json"
  ],
  "outputPath": "./custom_tfjs",
  "forwardModeOnly": true
}
  • kernels: لیستی از هسته هایی که باید در بسته گنجانده شوند. این را از خروجی مرحله 1 کپی کنید.
  • backends: لیستی از باطن (های) که می خواهید شامل شود. گزینه های معتبر عبارتند از "cpu"، "webgl" و "wasm".
  • models: لیستی از فایل های model.json برای مدل هایی که در برنامه خود بارگذاری می کنید. اگر برنامه شما از tfjs_converter برای بارگذاری مدل گراف استفاده نمی کند، می تواند خالی باشد.
  • outputPath: مسیری به یک پوشه برای قرار دادن ماژول های تولید شده در آن.
  • forwardModeOnly: اگر می‌خواهید گرادینت‌هایی را برای هسته‌های فهرست‌شده قبلی اضافه کنید، این را روی false قرار دهید.

مرحله 3. ماژول سفارشی tfjs را ایجاد کنید

ابزار ساخت سفارشی را با فایل کانفیگ به عنوان آرگومان اجرا کنید. برای دسترسی به این ابزار باید بسته @tensorflow/tfjs را نصب کنید.

npx tfjs-custom-module  --config custom_tfjs_config.json

این یک پوشه در outputPath با چند فایل جدید ایجاد می کند.

مرحله 4. باندلر خود را با نام مستعار tfjs در ماژول سفارشی جدید پیکربندی کنید.

در بسته‌هایی مانند webpack و rollup، می‌توانیم با نام مستعار ارجاعات موجود به ماژول‌های tfjs به ماژول‌های tfjs سفارشی جدید تولید شده خود اشاره کنیم. سه ماژول وجود دارد که برای حداکثر صرفه جویی در اندازه بسته باید مستعار شوند.

در اینجا یک قطعه از آنچه در وب پک به نظر می رسد ( نمونه کامل اینجا ) آمده است:

...

config.resolve = {
  alias: {
    '@tensorflow/tfjs$':
        path.resolve(__dirname, './custom_tfjs/custom_tfjs.js'),
    '@tensorflow/tfjs-core$': path.resolve(
        __dirname, './custom_tfjs/custom_tfjs_core.js'),
    '@tensorflow/tfjs-core/dist/ops/ops_for_converter': path.resolve(
        __dirname, './custom_tfjs/custom_ops_for_converter.js'),
  }
}

...

و در اینجا قطعه کد معادل برای جمع آوری ( نمونه کامل در اینجا ) است:

import alias from '@rollup/plugin-alias';

...

alias({
  entries: [
    {
      find: /@tensorflow\/tfjs$/,
      replacement: path.resolve(__dirname, './custom_tfjs/custom_tfjs.js'),
    },
    {
      find: /@tensorflow\/tfjs-core$/,
      replacement: path.resolve(__dirname, './custom_tfjs/custom_tfjs_core.js'),
    },
    {
      find: '@tensorflow/tfjs-core/dist/ops/ops_for_converter',
      replacement: path.resolve(__dirname, './custom_tfjs/custom_ops_for_converter.js'),
    },
  ],
}));

...

اگر باندلر شما از نام مستعار ماژول پشتیبانی نمی‌کند، باید دستورهای import خود را برای وارد کردن tensorflow.js از custom_tfjs.js ایجاد شده در مرحله 3 تغییر دهید. تکان خورده به طور کلی هسته های تکان دهنده درخت بیشترین صرفه جویی را در اندازه بسته نهایی فراهم می کند.

اگر فقط از بسته @tensoflow/tfjs-core استفاده می کنید، فقط باید آن یک بسته را نام مستعار کنید.

مرحله 5. بسته نرم افزاری خود را ایجاد کنید

باندلر خود را اجرا کنید (مثلاً webpack یا rollup ) برای تولید بسته خود. اندازه باندل باید کوچکتر از زمانی باشد که باندلر را بدون نام مستعار ماژول اجرا کنید. همچنین می‌توانید از تجسم‌کننده‌هایی مانند این استفاده کنید تا ببینید چه چیزی آن را به بسته نهایی شما تبدیل کرده است.

مرحله 6. برنامه خود را تست کنید

مطمئن شوید که آزمایش کنید که برنامه شما همانطور که انتظار می رود کار می کند!