هوگینگ فیس در دومین پست از سری «پروفایلینگ در PyTorch» به سراغ یکی از مهم‌ترین اجزای شبکه‌های عصبی رفته است: لایه‌های خطی و پرسپترون چندلایه. این مقاله با مشارکت محققانی مانند آریترا روی گوستیپاتی، رمی اوزان روبول، سرخیو پانیگو، پدرو کوئنکا و سایاک پال منتشر شده و در راستای تلاش برای گسترش هوش مصنوعی متن‌باز، مسیر بهینه‌سازی را از یک nn.Linear ساده تا یک MLP فیوژن‌شده با کرنل‌های دست‌تنظیم بررسی می‌کند.

چرا پروفایلینگ در PyTorch حیاتی است؟

در قسمت اول این سری، تابع torch.add(torch.matmul(x, w), b) بهانه‌ای شد تا زنجیره dispatch در CPU، سربار راه‌اندازی کرنل و تفاوت بین رژیم‌های محدود به سربار و محدود به محاسبه بررسی شود. پروفایلینگ به توسعه‌دهندگان نشان می‌دهد که زمان واقعی کجا صرف می‌شود و کدام عملیات را باید با هم ترکیب کرد. بدون این دید، بهینه‌سازی هوش مصنوعی اغلب به حدس و گمان تبدیل می‌شود.

از nn.Linear تا MLP فیوژن‌شده

لایه nn.Linear در ظاهر یک ضرب ماتریسی و یک جمع است، اما در ردگیری پروفایلر ممکن است کرنل‌های جداگانه‌ای برای transpose و عملیات‌های پیشین دیده شود. نویسندگان توضیح می‌دهند که این رفتار ناشی از چیدمان کرنل و pre-ops است. وقتی سه لایه خطی پشت سر هم قرار می‌گیرند، یک MLP می‌سازند که دو نوع کرنل GEMM را فعال می‌کند.

  • بررسی دلیل وجود کرنل‌های جداگانه mul و add در عملیات ساده
  • نقش transpose در چیدمان حافظه و تأثیر آن بر کارایی
  • تفاوت GEMMهای مختلف در یک MLP و مدیریت آن‌ها توسط torch.compile
  • مزیت استفاده از کرنل‌های دست‌تنظیم به‌جای اتکای کامل به کامپایل خودکار

نقش torch.compile و کرنل‌های Triton

یکی از پرسش‌های اصلی این مقاله این است که آیا --compile می‌تواند یک لایه Linear را بهینه کند؟ پاسخ ساده نیست؛ torch.compile گراف محاسباتی را ساده می‌کند، اما همیشه به بهینه‌ترین کرنل منجر نمی‌شود. برای رسیدن به عملکرد بالا، نویسندگان سراغ کتابخانه kernels و کرنل‌های دست‌تنظیم Triton می‌روند. این کرنل‌ها دقیقاً برای سخت‌افزار خاص تنظیم شده‌اند و تعداد دفعات خواندن و نوشتن در حافظه را کاهش می‌دهند.

نتیجه‌گیری

این مقاله نشان می‌دهد که برای بهینه‌سازی مدل‌های مبتنی بر هوش مصنوعی، آشنایی با پروفایلر ضروری است. ترکیب دانش پروفایلینگ، درک چیدمان حافظه و استفاده از کرنل‌های فیوژن‌شده می‌تواند سرعت اجرای MLP را به شکل چشمگیری افزایش دهد. اگر به دنبال یادگیری عمیق‌تر هستید، مطالعه مستقیم این پست در وبلاگ هوگینگ فیس را توصیه می‌کنیم.

پرسش‌های پرتکرار

چرا در MLP فیوژن‌شده دو نوع کرنل GEMM دیده می‌شود؟

در یک MLP متشکل از چند لایه خطی، هر لایه به یک ضرب ماتریسی جداگانه نیاز دارد. با فیوژن، تعداد دفعات انتقال داده بین حافظه و پردازنده کاهش می‌یابد، اما همچنان برای هر لایه کرنل GEMM مجزا اجرا می‌شود؛ تفاوت آن‌ها به چیدمان حافظه و ابعاد ورودی برمی‌گردد.

آیا torch.compile می‌تواند جایگزین کرنل‌های دست‌تنظیم شود؟

نه به‌طور کامل. torch.compile گراف را ساده و برخی عملیات‌ها را ترکیب می‌کند، اما برای رسیدن به حداکثر کارایی، کرنل‌های دست‌تنظیم Triton یا کتابخانه‌هایی مانند kernels بهینه‌سازی بیشتری روی سخت‌افزار خاص ارائه می‌دهند.