### چکیده
رشد شتابان فناوریهای مبتنی بر یادگیری ماشین و یادگیری عمیق در سالهای اخیر، موجب افزایش چشمگیر حجم دادهها، پیچیدگی مدلها و نیاز به توان پردازشی بسیار بالا شده است. امروزه مدلهای پیشرفتهای مانند شبکههای عصبی عمیق، مدلهای زبانی بزرگ (Large Language Models)، سامانههای بینایی ماشین و مدلهای پردازش سیگنال، میلیونها تا میلیاردها پارامتر را در خود جای دادهاند و اجرای آنها اغلب از توان یک پردازنده یا حتی یک رایانه منفرد فراتر میرود. در نتیجه، استفاده از سامانههای چندپردازنده، چندهستهای و توزیعشده به یکی از الزامات اصلی توسعه و اجرای این مدلها تبدیل شده است. با این حال، برنامهنویسی برای چنین معماریهایی نیازمند دانش تخصصی در زمینه زمانبندی پردازشها، مدیریت ارتباط میان گرهها، هماهنگسازی دادهها، تقسیم بار محاسباتی و بهینهسازی حافظه است؛ موضوعی که میتواند پژوهشگران حوزه یادگیری ماشین را از تمرکز بر طراحی و توسعه مدلهای هوشمند بازدارد.
در دهههای گذشته، تلاشهای فراوانی برای سادهسازی برنامهنویسی موازی انجام شده است. ظهور چارچوبهایی نظیر PyTorch و TensorFlow موجب شد توسعهدهندگان بتوانند بدون درگیر شدن با جزئیات سختافزاری، مدلهای یادگیری ماشین را طراحی و اجرا کنند. این چارچوبها با استفاده از گرافهای محاسباتی، عملیات ریاضی مدل را نمایش داده و اجرای آن را مدیریت میکنند. با وجود این، بیشتر این گرافها ماهیتی پویا دارند و هنگام اجرای برنامه ایجاد میشوند. هرچند این ویژگی انعطافپذیری بالایی برای طراحی مدلها فراهم میکند، اما امکان انجام بسیاری از بهینهسازیهای کامپایلری و زمانبندی ایستا را محدود میسازد. از سوی دیگر، زبان StreamIt که در ابتدا برای برنامههای پردازش جریان داده و پردازش سیگنال طراحی شده است، از ساختاری مبتنی بر جریان داده و گرافهای ایستا بهره میبرد که قابلیت بسیار مناسبی برای زمانبندی، تقسیم پردازش و اجرای موازی روی چندین هسته یا ماشین فراهم میکند. این تفاوت، زمینه مناسبی را برای ترکیب مزایای انعطافپذیری PyTorch با قابلیتهای بهینهسازی StreamIt ایجاد کرده است.
مسئله اصلی این پایاننامه، ایجاد بستری است که بتواند مدلهای طراحیشده در PyTorch را بدون نیاز به بازنویسی دستی، به ساختاری مبتنی بر StreamIt تبدیل کرده و امکان اجرای بهینه آنها را بر روی سامانههای چندپردازنده و توزیعشده فراهم سازد. هدف اساسی پژوهش، کاهش فاصله میان طراحی مدلهای یادگیری ماشین و پیادهسازی بهینه آنها بر روی معماریهای موازی است؛ به گونهای که پژوهشگر تنها بر توسعه مدل تمرکز کند و فرآیند تبدیل، زمانبندی و تولید کد به صورت خودکار انجام گیرد.
برای دستیابی به این هدف، ابتدا یک کامپایلر چندمرحلهای برای زبان StreamIt طراحی و پیادهسازی شده است. این کامپایلر بر پایه کتابخانه BuildIt توسعه یافته که امکان تولید کد در چند مرحله را فراهم میکند. در این رویکرد، بخشی از اطلاعات در زمان کامپایل مشخص شده و بر اساس آن، کدی تخصصیتر، سادهتر و سریعتر برای مرحله بعد تولید میشود. استفاده از این روش باعث حذف بسیاری از ساختارهای پیچیده برنامهنویسی شیءگرا مانند فراخوانیهای مجازی، کلاسها، شرطها و حلقههای غیرضروری شده و در نهایت کدی تولید میشود که توسط کامپایلرهای قدرتمندی مانند LLVM یا GCC با کارایی بسیار بالا بهینهسازی خواهد شد.
در بخش نخست پژوهش، ساختار زبان StreamIt، انواع دادهها، فیلترها، کانالها، Pipelineها و ساختارهای SplitJoin به طور کامل بررسی و پیادهسازی شدهاند. همچنین نحوه مدیریت نرخهای Push، Pop و Peek برای انتقال داده میان اجزای مختلف سیستم تشریح شده است. سپس روشهای زمانبندی ایستا برای هماهنگسازی جریان داده میان بخشهای مختلف برنامه ارائه شده تا از ایجاد وقفه یا انتظارهای غیرضروری در اجرای موازی جلوگیری شود. این زمانبندی بر پایه تحلیل نرخ انتقال داده میان اجزای مختلف گراف محاسباتی انجام میشود و امکان اجرای هماهنگ کل سیستم را فراهم میکند.
در ادامه، پژوهش به بررسی ساختار گرافهای محاسباتی در چارچوبهای یادگیری ماشین میپردازد. نشان داده میشود که چگونه عملیات مختلف شبکههای عصبی به صورت یک گراف جهتدار بدون دور نمایش داده میشوند و هر گره بیانگر یک عملیات محاسباتی و هر یال نمایانگر وابستگی داده میان عملیات مختلف است. همچنین تفاوت میان گرافهای ایستا و پویا، مزایا و محدودیتهای هر یک، و تأثیر آنها بر فرآیند بهینهسازی مورد تحلیل قرار گرفته است. نتایج این بررسی نشان میدهد که اگرچه گرافهای پویا انعطاف بیشتری در طراحی مدل دارند، اما بسیاری از فرصتهای بهینهسازی در زمان کامپایل را از بین میبرند.
مهمترین بخش این پایاننامه، طراحی سامانهای برای استخراج خودکار گراف محاسباتی از مدلهای PyTorch است. برای این منظور از ابزار torch.fx استفاده شده که امکان اجرای نمادین مدل و استخراج گراف عملیات را فراهم میکند. پس از استخراج گراف اولیه، اطلاعات موجود به یک نمایش میانی (Intermediate Representation یا IR) تبدیل میشوند. این نمایش میانی به گونهای طراحی شده است که علاوه بر حفظ وابستگی میان عملیات، ساختار برنامه را نیز سادهتر کرده و امکان انجام تحلیلها و بهینهسازیهای بعدی را فراهم سازد. در این نمایش، هر عملیات تنها یک خروجی تولید میکند و تمامی وابستگیها به صورت صریح نمایش داده میشوند که این موضوع فرآیند تولید کد را سادهتر میکند.
پس از ایجاد نمایش میانی، مجموعهای از بهینهسازیها بر روی آن اعمال میشود. یکی از مهمترین این بهینهسازیها، تحلیل زنده بودن متغیرها (Liveness Analysis) و حذف کدهای مرده (Dead Code Elimination) است. در بسیاری از مدلهای یادگیری ماشین، به ویژه شبکههای بازگشتی، بخشهایی از محاسبات در خروجی نهایی تأثیری ندارند. حذف این بخشها باعث کاهش حجم گراف، کاهش تعداد عملیات اجرایی و افزایش سرعت اجرای برنامه میشود. علاوه بر این، امکان ترکیب برخی عملیات متوالی، حذف محاسبات تکراری و آمادهسازی گراف برای تولید کد نیز فراهم شده است.
مرحله نهایی پژوهش، تولید خودکار کد StreamIt از روی نمایش میانی است. در این مرحله، ساختارهای مختلف موجود در گراف PyTorch به اجزای متناظر در StreamIt تبدیل میشوند. مدلهای ترتیبی ساده، شبکههای دارای انشعاب مانند ResNet، مدلهای دارای چند ورودی و چند خروجی، ساختارهای مبتنی بر Round Robin، حلقههای بازگشتی و شبکههای ترتیبی از جمله مواردی هستند که توسط سیستم پشتیبانی شدهاند. همچنین نحوه مدیریت جریان داده در ساختارهای SplitJoin و Pipeline به گونهای طراحی شده است که امکان توزیع پردازش میان چندین هسته یا ماشین بدون نیاز به مداخله مستقیم برنامهنویس فراهم گردد.
به منظور ارزیابی عملکرد، چندین مدل نمونه در محیط طراحیشده اجرا و فرآیند تبدیل آنها از PyTorch به StreamIt بررسی شده است. نتایج نشان میدهد که سامانه توسعهیافته قادر است گرافهای محاسباتی را با موفقیت استخراج، تحلیل، بهینهسازی و به کد قابل اجرای StreamIt تبدیل کند. همچنین استفاده از کامپایل چندمرحلهای موجب حذف بخش قابل توجهی از سربارهای ناشی از ساختارهای شیءگرا و تولید کدی سادهتر و کارآمدتر شده است. اگرچه این پژوهش بیشتر بر طراحی زیرساخت و اثبات امکانپذیری این رویکرد تمرکز دارد، اما نتایج اولیه نشان میدهد که چنین معماری میتواند زمینه مناسبی برای توسعه کامپایلرهای هوشمند نسل آینده در حوزه یادگیری ماشین فراهم سازد.
از مهمترین دستاوردهای این پایاننامه میتوان به طراحی و پیادهسازی یک کامپایلر چندمرحلهای برای زبان StreamIt، توسعه یک نمایش میانی اختصاصی برای مدلهای PyTorch، طراحی الگوریتم استخراج و تبدیل خودکار گرافهای محاسباتی، پیادهسازی روشهای بهینهسازی مانند حذف کدهای مرده و تحلیل زنده بودن متغیرها، و تولید خودکار کد StreamIt برای اجرای موازی مدلهای یادگیری ماشین اشاره کرد. این دستاوردها نشان میدهد که میتوان بدون تغییر در نحوه طراحی مدل توسط پژوهشگر، فرآیند تبدیل به یک ساختار بهینه و قابل اجرا بر روی سامانههای پردازش موازی را به صورت کاملاً خودکار انجام داد.
در مجموع، این پایاننامه گامی مؤثر در جهت نزدیکتر کردن حوزه کامپایلرها و یادگیری ماشین محسوب میشود. رویکرد ارائهشده با ترکیب قابلیتهای برنامهنویسی سطح بالای PyTorch، تکنیکهای کامپایل چندمرحلهای BuildIt و معماری جریانمحور StreamIt، بستری مناسب برای توسعه سامانههای هوشمند با کارایی بالا ایجاد کرده است. انتظار میرود توسعه این ایده در آینده با افزودن بهینهسازیهای بیشتر، پشتیبانی از مدلهای پیچیدهتر و گسترش قابلیت اجرای توزیعشده، بتواند نقش مهمی در افزایش سرعت، مقیاسپذیری و بهرهوری اجرای مدلهای یادگیری ماشین در مراکز داده، سامانههای ابری و تجهیزات لبه ایفا کند.
فهرست مطالب
| سرفصل | شماره صفحه |
|---|---|
| چکیده | iii |
| سپاسگزاری | iv |
| فصل ۱: مقدمه | 1 |
| ۱-۱. مقدمه | 1 |
| ۱-۲. پیشینه و انگیزه پژوهش | 2 |
| ۱-۳. اهداف پژوهش | 5 |
| ۱-۴. ساختار پایاننامه | 7 |
| فصل ۲: کامپایلر StreamIt مبتنی بر BuildIt | 8 |
| ۲-۱. مقدمه | 8 |
| ۲-۲. طراحی زبان StreamIt | 11 |
| ۲-۳. تابع Work و نرخهای جریان داده (Push / Pop / Peek) | 23 |
| ۲-۴. خطوط لوله (Pipeline) | 26 |
| ۲-۵. اتصال موازی جریانها (SplitJoin) | 30 |
| ۲-۶. زمانبندی ایستا (Static Scheduling) | 33 |
| ۲-۶-۱. محدودیتهای جریان داده در Pipeline | 33 |
| ۲-۶-۲. محدودیتهای جریان داده در SplitJoin | 34 |
| فصل ۳: محاسبات یادگیری ماشین | 37 |
| ۳-۱. گرافهای محاسباتی (Computation Graphs) | 37 |
| ۳-۲. پژوهشهای مرتبط در اجرای توزیعشده یادگیری ماشین | 40 |
| فصل ۴: کامپایل گرافهای PyTorch به StreamIt | 43 |
| ۴-۱. استخراج گراف (Graph Extraction) | 44 |
| ۴-۱-۱. نمونهای از یک ماژول PyTorch | 44 |
| ۴-۱-۲. تولید گراف با استفاده از Torch.fx | 45 |
| ۴-۱-۳. خروجی و تشریح گراف | 45 |
| ۴-۱-۴. ویژگیهای Torch.fx | 46 |
| ۴-۲. نمایش میانی (Intermediate Representation – IR) | 47 |
| ۴-۲-۱. دستور زبان نمایش میانی | 48 |
| ۴-۲-۲. توجیه ریاضی | 49 |
| ۴-۲-۳. نمونهای از نمایش میانی | 49 |
| ۴-۳. تولید کد StreamIt | 50 |
| ۴-۳-۱. مدلهای ترتیبی ساده | 50 |
| ۴-۳-۲. مدلهای دارای انشعاب و اتصال مجدد | — |
| ۴-۳-۳. مدلهای دارای چند ورودی و چند خروجی | — |
| ۴-۳-۴. تولید Pipeline و SplitJoin | — |
| ۴-۳-۵. تولید کد نهایی StreamIt | — |
| فصل ۵: نتایج، جمعبندی و پیشنهادهای آینده | 60 |
| ۵-۱. ارزیابی و نتایج | 60 |
| ۵-۲. جمعبندی | 63 |
| ۵-۳. پیشنهادهایی برای پژوهشهای آینده | 64 |
| مراجع | 65 |
آیا میتوان مدلهای PyTorch را بدون بازنویسی، سریعتر و هوشمندتر اجرا کرد؟ این پایاننامه پاسخ جالبی دارد!
هرچه مدلهای هوش مصنوعی بزرگتر و پیچیدهتر میشوند، اجرای آنها نیز به همان نسبت دشوارتر میشود. امروز دیگر مسئله فقط «طراحی یک شبکه عصبی» نیست؛ مسئله این است که چگونه همان مدل را روی چندین پردازنده، چندین GPU یا حتی چندین رایانه اجرا کنیم، بدون اینکه برنامهنویس مجبور باشد ساعتها درگیر جزئیات پردازش موازی شود.
دقیقاً همین چالش، موضوع اصلی این پایاننامه است. پژوهشی که تلاش میکند پلی میان سادگی برنامهنویسی در PyTorch و قدرت اجرای موازی StreamIt ایجاد کند؛ پلی که میتواند آینده اجرای مدلهای یادگیری ماشین را متحول کند.
چرا اجرای مدلهای یادگیری ماشین هنوز یک مشکل بزرگ است؟
PyTorch یکی از محبوبترین ابزارهای توسعه مدلهای هوش مصنوعی است. دلیل محبوبیت آن نیز ساده است؛ پژوهشگر فقط مدل خود را مینویسد و باقی کارها را کتابخانه انجام میدهد.
اما پشت این سادگی، یک مشکل مهم پنهان شده است.
گرافهای محاسباتی PyTorch معمولاً به صورت پویا (Dynamic) ساخته میشوند؛ یعنی ساختار واقعی محاسبات تا زمان اجرای برنامه مشخص نیست. این انعطاف فوقالعاده است، اما باعث میشود کامپایلر نتواند بسیاری از بهینهسازیهای مهم را از قبل انجام دهد.
در نتیجه، بخشی از توان سختافزار عملاً هدر میرود.
ایدهای که پایاننامه ارائه میدهد؛ تبدیل خودکار PyTorch به StreamIt
جذابترین بخش این پژوهش، ساخت یک کامپایلر خودکار است.
این کامپایلر ابتدا مدل نوشتهشده در PyTorch را تحلیل میکند، سپس گراف محاسباتی آن را استخراج کرده و در نهایت همان مدل را به زبان StreamIt تبدیل میکند.
نکته جالب اینجاست که برنامهنویس تقریباً هیچ تغییری در کد خود ایجاد نمیکند.
به عبارت دیگر، همان مدلی که برای تحقیق نوشته شده است، میتواند به مدلی مناسب برای اجرای موازی تبدیل شود.
این دقیقاً همان چیزی است که بسیاری از چارچوبهای آینده هوش مصنوعی به دنبال آن هستند.
یک نمایش میانی هوشمند؛ راز اصلی کامپایلر
قبل از تولید کد نهایی، پژوهش یک نمایش میانی (Intermediate Representation یا IR) طراحی میکند.
شاید این بخش در نگاه اول ساده به نظر برسد، اما در واقع قلب کل سیستم است.
نمایش میانی باعث میشود:
- وابستگی میان عملیات کاملاً مشخص شود.
- هر عملیات تنها یک خروجی داشته باشد.
- حذف محاسبات اضافی بسیار آسان شود.
- تولید کد نهایی سادهتر و سریعتر انجام گیرد.
به زبان ساده، این مرحله مانند مرتب کردن قطعات یک پازل قبل از ساخت تصویر نهایی است.
کامپایلر قبل از اجرا شروع به فکر کردن میکند!
یکی از جذابترین ویژگیهای این پایاننامه استفاده از کامپایل چندمرحلهای (Multi-stage Compilation) است.
به جای اینکه تمام تصمیمها هنگام اجرای برنامه گرفته شوند، بسیاری از آنها از قبل مشخص میشوند.
نتیجه چیست؟
- حذف فراخوانیهای غیرضروری
- حذف کلاسهای اضافی
- کاهش سربار برنامه
- تولید کد بسیار سبکتر
- افزایش سرعت اجرا
در واقع، کامپایلر بخشی از «تفکر» را قبل از اجرای برنامه انجام میدهد.
حذف محاسباتی که هیچوقت استفاده نمیشوند
همه محاسباتی که در یک مدل انجام میشوند، لزوماً در خروجی نهایی تأثیر ندارند.
این پایاننامه با استفاده از تحلیل Liveness Analysis و Dead Code Elimination، تمام بخشهایی را که در نتیجه نهایی نقشی ندارند حذف میکند.
این یعنی:
- حافظه کمتر مصرف میشود.
- تعداد عملیات کاهش پیدا میکند.
- سرعت اجرا افزایش مییابد.
گاهی حذف چند گره از گراف محاسباتی میتواند تفاوت محسوسی در عملکرد ایجاد کند.
زمانبندی هوشمند؛ وقتی همه پردازندهها هماهنگ کار میکنند
یکی از مشکلات بزرگ پردازش موازی، هماهنگی میان بخشهای مختلف برنامه است.
اگر یک پردازنده منتظر پردازنده دیگر بماند، بخش زیادی از توان سیستم از بین میرود.
پژوهش حاضر با استفاده از Static Scheduling (زمانبندی ایستا)، قبل از اجرای برنامه مشخص میکند که هر بخش دقیقاً چه زمانی اجرا شود و چه مقدار داده دریافت یا ارسال کند.
نتیجه، کاهش انتظارها و افزایش بهرهوری سیستم است.
StreamIt؛ زبانی که دوباره مورد توجه قرار گرفته است
شاید بسیاری از توسعهدهندگان نام StreamIt را کمتر شنیده باشند.
اما این زبان برای برنامههای مبتنی بر جریان داده طراحی شده و قابلیت فوقالعادهای در اجرای موازی دارد.
این پایاننامه نشان میدهد که StreamIt میتواند دوباره، این بار در کنار هوش مصنوعی، نقش مهمی ایفا کند.
در واقع پژوهش تلاش میکند قدرت زمانبندی StreamIt را با محبوبیت PyTorch ترکیب کند.
چرا این پژوهش اهمیت دارد؟
این پایاننامه صرفاً یک تبدیلکننده کد نیست.
بلکه گامی در جهت ساخت نسل جدیدی از کامپایلرهای هوشمند است؛ کامپایلرهایی که:
- ساختار مدل را درک میکنند.
- بهترین روش اجرای آن را انتخاب میکنند.
- پردازش را میان چندین پردازنده تقسیم میکنند.
- و بدون دخالت برنامهنویس، کدی سریعتر تولید میکنند.
این همان مسیری است که بسیاری از فناوریهای آینده هوش مصنوعی به سمت آن حرکت میکنند.
جمعبندی؛ شاید آینده هوش مصنوعی بیشتر به کامپایلرها وابسته باشد تا مدلها
وقتی صحبت از پیشرفت هوش مصنوعی میشود، اغلب همه نگاهها به مدلهای جدید، دادههای بیشتر یا GPUهای قدرتمندتر معطوف است. اما این پایاننامه یادآوری میکند که کامپایلرها نیز میتوانند نقش تعیینکنندهای در افزایش کارایی داشته باشند.
اگر بتوان یک مدل را بدون تغییر در منطق آن، هوشمندانهتر تحلیل، بهینهسازی و برای اجرای موازی آماده کرد، میتوان از همان سختافزار موجود عملکرد بسیار بهتری به دست آورد.
شاید سؤال مهم آینده این نباشد که «مدل بعدی چقدر بزرگتر خواهد بود؟» بلکه این باشد که «آیا میتوان همان مدل را بسیار هوشمندانهتر اجرا کرد؟» این پژوهش نشان میدهد که پاسخ این سؤال میتواند مثبت باشد.
اگر بخواهید، میتوانم این متن را به سبک ویرگول (روانتر و داستانیتر) یا مدیوم (تحلیلیتر و حرفهایتر) نیز بازنویسی کنم.
بسیار سریع و ساده می توانید اصل این پایان نامه را به صورت فایل PDF در اختیار داشته باشید.