نوشتن عملیات سفارشی، کرنل و گرادینت در TensorFlow.js

بررسی اجمالی

این راهنما مکانیسم‌هایی را برای تعریف عملیات سفارشی (ops)، هسته‌ها و گرادیان‌ها در TensorFlow.js شرح می‌دهد. هدف آن ارائه یک نمای کلی از مفاهیم اصلی و نشانگرهای کد است که مفاهیم را در عمل نشان می دهد.

این راهنما برای چه کسانی است؟

این یک راهنمای نسبتاً پیشرفته است که به برخی از قسمت های داخلی TensorFlow.js می پردازد، ممکن است به ویژه برای گروه های زیر مفید باشد:

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

این راهنمای استفاده عمومی از TensorFlow.js نیست زیرا به مکانیسم‌های پیاده‌سازی داخلی می‌رود. برای استفاده از TensorFlow.js نیازی به درک این مکانیسم ها ندارید

برای استفاده حداکثری از این راهنما، باید با خواندن کد منبع TensorFlow.js راحت باشید (یا بخواهید امتحان کنید).

واژه شناسی

برای این راهنما، چند اصطلاح کلیدی برای توصیف اولیه مفید است.

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

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

Gradient / GradFunc - تعریف «حالت عقب‌نشینی» یک op/kernel که مشتق آن تابع را با توجه به برخی ورودی‌ها محاسبه می‌کند. گرادیان ها کد «سطح بالا» هستند (خاص باطن نیستند) و می توانند عملیات یا هسته های دیگر را فراخوانی کنند.

رجیستری هسته - نقشه ای از یک تاپل (نام هسته، نام باطن) به یک پیاده سازی هسته.

Gradient Registry - نقشه ای از نام هسته تا اجرای گرادیان .

سازمان کد

عملیات ها و گرادیان ها در tfjs-core تعریف شده اند.

هسته ها مختص بک اند هستند و در پوشه های باطن مربوطه خود تعریف می شوند (مثلا tfjs-backend-cpu ).

عملیات سفارشی، کرنل ها و گرادینت ها نیازی به تعریف داخل این بسته ها ندارند. اما اغلب از نمادهای مشابه در اجرای آنها استفاده می شود.

پیاده سازی عملیات سفارشی

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

  • برخی از عملیات ها را می توان به طور کامل بر اساس عملیات های موجود تعریف کرد و فقط باید این توابع را مستقیما وارد و فراخوانی کرد. به عنوان مثال .
  • پیاده سازی یک عملیات همچنین می تواند به هسته های باطنی خاص ارسال شود. این کار از طریق Engine.runKernel انجام می شود و در بخش "پیاده سازی کرنل های سفارشی" بیشتر توضیح داده خواهد شد. به عنوان مثال .

پیاده سازی کرنل های سفارشی

پیاده‌سازی‌های خاص هسته پشتیبان امکان اجرای بهینه منطق را برای یک عملیات معین فراهم می‌کنند. هسته ها توسط عملیاتی فراخوانی می شوند که tf.engine().runKernel() فراخوانی می کنند. پیاده سازی هسته با چهار چیز تعریف می شود

  • یک نام هسته
  • پشتیبان هسته در آن پیاده سازی می شود.
  • ورودی ها: آرگومان های تانسور تابع هسته.
  • ویژگی ها: آرگومان های غیر تانسوری تابع هسته.

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

به طور کلی هسته ها در سطحی پایین تر از تانسورها کار می کنند و در عوض مستقیماً در حافظه می خوانند و می نویسند که در نهایت توسط tfjs-core به تانسورها پیچیده می شود.

هنگامی که یک هسته پیاده سازی شد، می توان آن را با استفاده از تابع registerKernel از tfjs-core در TensorFlow.js ثبت کرد. می‌توانید برای هر باطنی که می‌خواهید آن هسته در آن کار کند، یک هسته ثبت کنید. پس از ثبت نام، هسته می‌تواند با tf.engine().runKernel(...) فراخوانی شود و TensorFlow.js مطمئن شود که به پیاده‌سازی در باطن فعال فعلی

پیاده سازی گرادیان های سفارشی

گرادیان ها به طور کلی برای یک هسته مشخص تعریف می شوند (که با همان نام هسته استفاده شده در فراخوانی به tf.engine().runKernel(...) مشخص می شود). این به tfjs-core اجازه می دهد تا از یک رجیستری برای جستجوی تعاریف گرادیان برای هر هسته در زمان اجرا استفاده کند.

پیاده سازی گرادینت های سفارشی برای موارد زیر مفید است:

  • افزودن یک تعریف گرادیان که ممکن است در کتابخانه وجود نداشته باشد
  • نادیده گرفتن یک تعریف گرادیان موجود برای سفارشی کردن محاسبه گرادیان برای یک هسته مشخص.

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

هنگامی که یک گرادینت را برای یک فراخوانی خاص پیاده سازی کردید، می توان آن را با استفاده از تابع registerGradient از tfjs-core در TensorFlow.js ثبت کرد.

روش دیگر برای پیاده‌سازی گرادیان‌های سفارشی که رجیستری گرادیان را دور می‌زند (و بنابراین امکان محاسبه گرادینت‌ها را برای توابع دلخواه به روش‌های دلخواه فراهم می‌کند، استفاده از tf.customGrad است.

در اینجا نمونه ای از یک عملیات در کتابخانه استفاده از customGrad است