پرش به محتوای اصلی
پرش به محتوای مقاله

جداسازی ابرپارامترهای PyTorch از کد آموزش با استفاده از Gin Config

·۲۴ تیر ۱۴۰۵۹ دقیقه مطالعه۲ بازدید
راهنما
ساخت خط لوله پای‌تورچ با کنترل جین‌کانفیگ: شبکه عصبی چندلایه قابل تنظیم، زمان‌بندی کسینوسی و بازنویسی پارامترها در زمان اجرا
ساخت خط لوله پای‌تورچ با کنترل جین‌کانفیگ: شبکه عصبی چندلایه قابل تنظیم، زمان‌بندی کسینوسی و بازنویسی پارامترها در زمان اجرا
اشتراک‌گذاری
واقعاً چه چیز جدید است؟

به‌کارگیری Gin Config برای تبدیل هایپرپارامترهای PyTorch از متغیرهای کد به وابستگی‌های деклараاتیو و معرفی مفهوم «پیکربندی عملیاتی» برای ثبت دقیق وضعیت نهایی اجرا.

تصور کنید در پروژه‌ای هستید که هر تغییر کوچک در نرخ یادگیری، شما را مجبور می‌کند ده‌ها خط کد را کامنت کنید یا نسخه‌های متعددی از یک اسکریپت بسازید. این آشفتگی در پروژه‌های PyTorch رایج است، جایی که ابرپارامترهای سخت‌کد شده (hardcoded) اغلب باعث ایجاد مجموعه‌ای از خطوط کامنت‌شده و نسخه‌های تکه‌تکه از اسکریپت‌ها می‌شود. اما با Gin Config می‌توان تمام درجات آزادی آزمایش — از ابعاد لایه‌ها تا نرخ یادگیری — را به فایل‌های خارجی Declarative منتقل کرد تا کد اصلی اجرایی ثابت و پایدار بماند.

در گردش‌کارهای فعلی یادگیری ماشین، تکرارپذیری اغلب شکست می‌خورد چون پیکربندی دقیقی که برای یک اجرای خاص به کار رفته، ثبت نمی‌شود. اکثر پژوهشگران به ثبت دستی یا فایل‌های حجیم JSON متکی هستند که مستقیماً با آرگومان‌های توابع مطابقت ندارند. طبق گزارشی از Marktechpost، سیستم Gin با تبدیل پیکربندی‌ها به یک سامانه تزریق وابستگی سراسری (Global Dependency Injection)، این مشکل را حل می‌کند.

برای درک بهتر، اسکریپت آموزش را مانند یک آشپزخانه حرفه‌ای تصور کنید: کد، مجموعه‌ای از ابزارها و دستورپخت است، اما فایل Gin مانند لیست خرید امروز است؛ شما برای تغییر یک ماده اولیه، اجاق گاز را عوض نمی‌کنید، بلکه فقط لیست را تغییر می‌دهید.

همان‌طور که در تحلیل‌های پیشین ما درباره امنیت و مدیریت مدل‌های متن‌باز اشاره کردیم، جداسازی لایه تنظیمات از منطق اجرا، اولین قدم برای مقیاس‌پذیری هر پروژه است.

معماری خط لوله‌های پیکربندی‌پذیر

پیاده‌سازی این سیستم با افزودن دکوراتور @gin.configurable به توابع اصلی آغاز می‌شود. این کار به Gin می‌گوید که آرگومان‌های تابع می‌توانند به مقادیر یک فایل خارجی .gin متصل شوند. در این خط لوله خاص، سیستم همه چیز را مدیریت می‌کند؛ از تنظیم پوشه‌ها (با استفاده از Path برای CONFIG_DIR و RUN_DIR) تا مدیریت وضعیت سراسری پیکربندی از طریق gin.clear_config().

برای تست این سازوکار، از یک تکلیف طبقه‌بندی دوتایی مارپیچ غیرخطی استفاده شده است. این مجموعه داده توسط تابع make_spiral_dataset و با کمک NumPy تولید می‌شود تا دو مارپیچ درهم‌تنیده ایجاد کند. ساخت این داده‌ها شامل محاسبه radius_0 و radius_1 از طریق np.linspace(0.05, 1.0, n_per_class) و محاسبه theta_0 و theta_1 با استفاده از فرمول rotations * 2 * np.pi * radius است.

پیچیدگی این تکلیف با پارامترهایی مثل نویز (noise) با مقدار پیش‌فرض ۰.۱۸ و چرخش (rotations) با مقدار ۱.۷۵ کنترل می‌شود. همچنین از یک train_fraction برابر با ۰.۸ برای تقسیم داده‌ها استفاده شده است. تابع تولید مجموعه داده، یک دیکشنری شامل تنسورهای آموزش و اعتبارسنجی به‌همراه یک بلوک متاداده (metadata) برمی‌گرداند که بذر (seed)، نویز و چرخش دقیق مورد استفاده برای آن تولید خاص را ثبت می‌کند.

این سامانه یک MLP پیکربندی‌پذیر با اجزای ماژولار زیر تعریف می‌کند:

  • کلاس MLP: از دکوراتور @gin.configurable برای خارجی کردن input_dim (الزامی) و hidden_dims (پیش‌فرض ۶۴، ۶۴) و output_dim استفاده می‌کند. انتخاب‌های معماری مثل تابع فعال‌ساز (activation) که از ReLU، GELU، Tanh و SiLU از طریق یک کمکی داخلی به نام activation_layer پشتیبانی می‌کند، دراپ‌اوت (dropout) با مقدار پیش‌فرض ۰.۰ و استفاده از لایه نرمال‌سازی (LayerNorm)، همگی از بیرون کنترل می‌شوند. شبکه در نهایت به عنوان یک بلوک nn.Sequential ساخته می‌شود.
  • کارخانه بهینه‌ساز: تابع make_optimizer اجازه می‌دهد با استفاده از رشته‌های پیکربندی بین AdamW (با نرخ یادگیری پیش‌فرض 3e-3 و weight_decay=1e-3) و SGD (با نرخ یادگیری پیش‌فرض 3e-3، مومنتوم ۰.۹ و weight_decay=1e-3) جابه‌جا شویم. این تابع از یک denylist=["params"] استفاده می‌کند تا Gin سعی نکند پارامترهای خود مدل را پیکربندی کند.
  • زمان‌بند کسینوسی: تابع make_cosine_scheduler منطق مربوط به دوره‌های گرم‌کردن (warmup_epochs پیش‌فرض ۵)، کل دوره‌ها (total_epochs پیش‌فرض ۶۰) و کمترین نرخ یادگیری (min_lr_factor پیش‌فرض ۰.۰۵) را پیاده می‌کند. این بخش از LambdaLR برای مدیریت منحنی کاهش نرخ یادگیری استفاده می‌کند و پیشرفت را به صورت (epoch - warmup_epochs) / (total_epochs - warmup_epochs) محاسبه می‌کند تا از گرم‌کردن خطی به کاهش کسینوسی انتقال یابد.
  • توابع زیان: از bce_with_logits_loss استفاده شده که شامل پارامتر پیکربندی‌پذیر هموارسازی برچسب (label_smoothing) با مقداری مانند ۰.۰۲ است. این کار تعمیم‌پذیری را با اصلاح اهداف طبق فرمول targets * (1.0 - label_smoothing) + 0.5 * label_smoothing بهبود می‌بخشد.

مدیریت داده‌ها و حلقه آموزش

فراتر از مدل، خط لوله داده نیز ماژولار است. تابع make_loader با دکوراتور @gin.configurable(denylist=["x", "y"]) تعریف شده است. این ساختار اجازه می‌دهد اندازه دسته (batch_size) با پیش‌فرض ۱۲۸، رفتار برهم‌زدن (shuffle) و یک seed خاص برای torch.Generator بدون تغییر در کد Instantiation مربوط به DataLoader در فایل پیکربندی تنظیم شوند.

اجرای اصلی در تابع fit رخ می‌دهد. این تابع بسیار منعطف است و پارامتر grad_clip_norm (پیش‌فرض ۱.۰) را برای جلوگیری از انفجار گرادیان‌ها با استفاده از nn.utils.clip_grad_norm_ می‌پذیرد. همچنین پارامتر log_every برای کنترل فرکانس خروجی‌های کنسول به کار می‌رود. حلقه fit عملیات Forward Pass، محاسبه زیان Cross-Entropy دوتایی و اجرای پس‌انتشار (Backpropagation) را انجام می‌دهد.

در طول آموزش، بهینه‌ساز از zero_grad(set_to_none=True) برای بازدهی بیشتر حافظه و سرعت استفاده می‌کند. پس از هر Epoch، تابع evaluate با استفاده از torch.no_grad() صحت (accuracy) و زیان را روی مجموعه‌های آموزش و اعتبارسنجی محاسبه می‌کند. این تابع ابتدا مقدار Sigmoid لوجیت‌ها را گرفته و پیش‌بینی‌هایی که probs >= 0.5 هستند را شناسایی می‌کند.

در نهایت، یک پوشش به نام run_experiment این اجزا را متصل می‌کند. این بخش تخصیص دستگاه (استفاده از cuda اگر prefer_gpu درست باشد و torch.cuda.is_available() تایید شود) را مدیریت کرده و چرخه حیات کلی را کنترل می‌کند؛ از فراخوانی seed_everything() (که بذر random، numpy، torch.manual_seed و torch.cuda.manual_seed_all را تنظیم می‌کند) تا تجمیع نتایج نهایی در یک دیکشنری شامل تگ، دستگاه، متاداده و تعداد پارامترها.

پیوندهای محدودشده و بازنویسی‌های زمان اجرا

یکی از قابلیت‌های کلیدی این ساختار، استفاده از ارجاعات محدودشده (Scoped Bindings) است. Gin اجازه می‌دهد چندین پیکربندی مدل مجزا در یک اجرا وجود داشته باشد. با استفاده از نماد @ در فایل‌های پیکربندی، می‌توان ارجاع داد به Scopeهای خاص. برای مثال، کاربر می‌تواند به‌طور هم‌زمان یک @compact/MLP() و یک @wide/MLP() تعریف کند که اجازه می‌دهد دو نسخه ساختاری مختلف از یک کلاس در یک پیکربندگی وجود داشته باشند.

در این مثال، یک فایل BASE_CONFIG پارامترهای مشترک را برای حفظ یکپارچگی تعریف می‌کند:

  • SEED = 123
  • N_PER_CLASS = 900
  • EPOCHS = 50
  • BATCH = 128
  • make_spiral_dataset.noise = 0.20
  • make_spiral_dataset.rotations = 1.85

سپس فایل‌های تخصصی مانند compact_adamw.gin و wide_sgd.gin با عبارت include تنظیمات پایه را وارد کرده و مقادیر خاص را بازنویسی (override) می‌کنند. مدل فشرده ابعاد لایه‌ها را hidden_dims = (64, 64, 64)، دراپ‌اوت را 0.05 و use_layernorm = True قرار می‌دهد. مدل گسترده ابعاد را hidden_dims = (128, 128, 128, 64)، فعال‌ساز را relu، دراپ‌اوت را 0.02 و use_layernorm = True تنظیم می‌کند.

علاوه بر فایل‌ها، این سیستم از Bindings زمان اجرا پشتیبانی می‌کند. این یعنی کاربر می‌تواند پارامتری را از طریق یک لیست پایتونی در حین اجرا تغییر دهد که اولویت آن بیشتر از فایل .gin است. در این آموزش، run_from_gin_file با runtime_bindings مانند ["fit.epochs = 45", "make_spiral_dataset.noise = 0.18", "run_experiment.tag = '...' "] فراخوانی می‌شود. این قابلیت اجازه تکرار سریع — تغییر مدت آموزش یا نویز داده‌ها — را بدون دست زدن به سیستم فایل می‌دهد.

تضمین تکرارپذیری مطلق

برای تضمین تکرارپذیری مطلق، مکانیسم «قفل پیکربندی» پیاده شده است. با تنظیم finalize_config=True در هنگام فراخوانی gin.parse_config_files_and_bindings هرگونه تغییر بعدی در زمان اجرا ممنوع می‌شود. اگر کاربر سعی کند پس از نهایی شدن پیکربندی، تابعی مثل gin.bind_parameter("fit.epochs", 999) را فراخوانی کند، سیستم خطای RuntimeError می‌دهد تا اطمینان حاصل شود که آزمایش خالص مانده و دست‌کاری نشده است.

برای حل مشکل ردیابی، خط لوله یک «پیکربندی عملیاتی» (operative config) صادر می‌کند. در حالی که فایل تنظیمات معمولی «قصد» کاربر (intention) را نشان می‌دهد، پیکربندی عملیاتی وضعیت «Resolve شده» را ثبت می‌کند؛ یعنی تک‌تک پارامترهایی که واقعاً در یک اجرای خاص استفاده شده‌اند، شامل موارد ارث‌بری شده از فایل‌های پایه یا تغییر یافته توسط بازنویسی‌های زمان اجرا. این خروجی از gin.operative_config_str() تولید و به عنوان operative_config.gin در کنار نتایج result.json برای هر تگ آزمایش در RUN_DIR ذخیره می‌شود.

مقایسه عملکرد

در این آموزش، دو پیکربندی متمایز روی مجموعه داده مارپیچ برای اعتبارسنجی این معماری جداسازانه مقایسه شدند:

  1. Compact GELU-AdamW: از مجموعه پارامترهای کوچک‌تر با فعال‌سازهای GELU و بهینه‌ساز AdamW (نرخ یادگیری ۰.۰۰۳، weight_decay=۰.۰۰۱) استفاده کرد که با نام @compact/MLP() محدود شده بود و از طریق بازنویسی زمان اجرا، ۴۵ دوره (epoch) آموزش دید.
  2. Wide ReLU-SGD: از یک معماری بزرگ‌تر (۱۲۸x۱۲۸x۱۲۸x۶۴) با فعال‌سازهای ReLU و بهینه‌ساز SGD (نرخ یادگیری ۰.۰۳۵، مومنتوم ۰.۹۲، weight_decay=۰.۰۰۰۵) استفاده کرد که با نام @wide/MLP() محدود شده بود و آن نیز برای ۴۵ دوره اجرا شد.

با تجسم منحنی‌های زیان و صحت اعتبارسنجی با matplotlib ثابت شد که کل رفتار آموزش را می‌توان صرفاً با تعویض فایل ورودی .gin تغییر داد، در حالی که حلقه fit در پایتون دست‌نخورده باقی ماند. نتایج نهایی در یک جدول خلاصه شامل tag (تگ)، params (تعداد کل پارامترها)، val_loss (زیان اعتبارسنجی) و val_accuracy (صحت اعتبارسنجی) ارائه شد.

این رویکرد جداسازانه، تجربه توسعه‌دهنده را تغییر می‌دهد. به‌جای عیب‌یابی تغییر یک متغیر در یک اسکریپت ۵۰۰ خطی، توسعه‌دهنده فقط یک فایل متنی تمیز و Declarative را بازرسی می‌کند. استفاده از gin.query_parameter نیز اجازه می‌دهد تنظیمات فعال (مانند fit.epochs یا make_loader.batch_size) بلافاصله پس از بارگذاری پیکربندی چاپ و تایید شوند.

برای کسانی که آزمایش‌های Colab را به خط لوله‌های پژوهشی تبدیل می‌کنند، این الگو اصطکاک تنظیم دستی ابرپارامترها (hyperparameters) — یعنی تنظیمات کلی مدل که قبل از آموزش تعیین می‌شوند — را از بین می‌برد. این روش اجازه می‌دهد تنظیمات تولید داده، استراتژی‌های بهینه‌سازی و زمان‌بندی‌های آموزش به‌صورت سیستماتیک تغییر کنند بدون اینکه ریسک شکستن منطق اصلی کد وجود داشته باشد. در این چارچوب، کد مانند یک موتور ثابت باقی می‌ماند و فایل‌های پیکربندی نقش پانل کنترل را ایفا می‌کنند.

اکنون می‌توانید با نصب بسته gin-config و استفاده از دکوراتور @gin.configurable برای کارخانه‌های PyTorch خود، منطق آزمایشی را از کد خارج کرده و به پیکربندی منتقل کنید.

گام بعدی شما

  • کتابخانه gin-config را نصب کنید و توابع ساخت مدل خود را با @gin.configurable علامت‌گذاری نمایید.
  • یک فایل base.gin برای پارامترهای ثابت ایجاد کنید و برای هر آزمایش یک فایل .gin مجزا بسازید که از فایل پایه include شود.
  • برای اطمینان از تکرارپذیری، حتماً از finalize_config=True استفاده کرده و خروجی operative_config را ذخیره کنید.

اما این نظم در تنظیمات تنها بخشی از ماجراست؛ برای مدیریت بهینه حافظه در مدل‌های عظیم، به تحلیل ما درباره vLLM مراجعه کنید.

چرا این موضوع مهم است؟

این روش با حذف وابستگی سخت تنظیمات به کد، تکرارپذیری (Reproducibility) را که یکی از بزرگ‌ترین چالش‌های پژوهشی در یادگیری عمیق است، تضمین می‌کند. اعتبار نتایج یک مقاله یا محصول زمانی تایید می‌شود که هر کسی بتواند با یک فایل پیکربندی، دقیقاً همان خروجی را بازتولید کند.

تأثیر برای ایران

این رویکرد برای پژوهشگران هوش مصنوعی در ایران که با محدودیت منابع محاسباتی (GPU) رو‌به‌رو هستند، حیاتی است؛ زیرا اجازه می‌دهد با دقت حداکثری و بدون اتلاف Compute، آزمایش‌ها را بهینه کنند.

·نگاه ما
تحریریه دات‌هوش

تغییر رویکرد از اسکریپت‌های خطی به سیستم‌های تزریق وابستگی مانند Gin، در واقع گذار از «برنامه‌نویسی مدل» به «مهندسی آزمایش» است. این متدولوژی ریسک خطای انسانی در زمان تغییر ابرپارامترها را به شدت کاهش می‌دهد و اجازه می‌دهد مدل‌های مختلف در یک جلسه اجرا به صورت موازی مقایسه شوند، بدون اینکه کد منبع به یک گورستان از متغیرهای تغییریافته تبدیل شود.

منابع

این گزارش با خط‌لولهٔ خودکار دات‌هوش از منابع معتبر جهانی تدوین و زیر نظر تحریریه منتشر شده است. روش کار ما

گفتگو

پنج‌شنبه‌های هوش‌محور

بسته‌ی هفتگی دات‌هوش

۵ خبر، ۲ ابزار، ۱ پرامپت در هر شماره. به‌زودی راه‌اندازی می‌شود — هر پنج‌شنبه صبح.

خبر کلیدی
ابزار کاربردی
پرامپت حرفه‌ای
تحلیل پژوهش
به‌زودی
زاویه‌ی ایرانی
به‌زودی
تمرین این هفته
به‌زودی

راهنماهای دات‌هوش

راهنماهای کاربردیِ دات‌هوش برای کار با هوش مصنوعی — از همین‌جا شروع کنید:

دات‌هوش

راهنمای فارسی هوش مصنوعی — با نگاه به ایران

اخبار روزانه، معرفی ابزارها و مدل‌ها، و آموزشِ کار با هوش مصنوعی؛ همیشه با این پرسش که از ایران چه چیزی کار می‌کند و چه چیزی نه.