فاز 3 · درس 9

برنامه‌ریزی نرخ یادگیری و وارم‌آپ در یادگیری عمیق

نوع
ساختنی
زمان
حدود 90 دقیقه
زبان‌ها
Python
پیش‌نیاز
درس 03.06 (بهینه‌سازها)، درس 03.08 (مقداردهی اولیه‌ی وزن‌ها)
یک منحنی نرم نئونی که ابتدا به آرامی اوج می‌گیرد و سپس به شکل موج کسینوسی به آرامی نزول می‌کند بر روی صفحه‌ای تاریک و هندسی
فهرست مطالب
  1. اهداف یادگیری
  2. صورت مسئله
  3. مفاهیم پایه
  4. نرخ یادگیری ثابت
  5. کاهش پله‌ای
  6. تبرید کسینوسی
  7. وارم‌آپ: چرا باید با مقادیر کوچک شروع کرد؟
  8. وارم‌آپ خطی همراه با کاهش کسینوسی
  9. سیاست تک‌چرخه‌ای (1cycle Policy)
  10. شکل‌های مختلف برنامه‌های زمان‌بندی
  11. فلوچارت تصمیم‌گیری
  12. مقادیر واقعی در مدل‌های منتشرشده
  13. پیاده‌سازی گام‌به‌گام
  14. گام 1: توابع برنامه‌ی زمان‌بندی
  15. گام 2: مصورسازی تمام برنامه‌های زمان‌بندی
  16. گام 3: شبکه‌ی آموزش
  17. گام 4: مقایسه‌ی تمام برنامه‌های زمان‌بندی
  18. گام 5: نرخ یادگیری خیلی بالا در برابر خیلی پایین
  19. کاربرد در دنیای واقعی
  20. خروجی نهایی
  21. تمرین‌ها
  22. اصطلاحات کلیدی
  23. برای مطالعه‌ی بیشتر

تنظیم نرخ یادگیری (learning rate) حساس‌ترین گام در آموزش مدل‌های یادگیری عمیق است. انتخاب یک عدد ثابت اغلب شما را میان دو پرتگاه واگرایی زودهنگام یا درجا زدن مدل در کمینه‌های نامناسب گرفتار می‌کند؛ در حالی که رسیدن به دقت‌های بالا در مدل‌های پیشرفته دقیقاً به تغییر پویا و حساب‌شده‌ی این مقدار در طول آموزش وابسته است.

در آموزش مدل‌های مدرن مانند خانواده‌ی Llama یا GPT، استفاده از وارم‌آپ (warmup) برای پایدارسازی آماره‌های اولیه‌ی بهینه‌سازهایی مثل Adam و به‌کارگیری کاهش کسینوسی (cosine annealing) به استاندارد قطعی تبدیل شده است. بدون درک این الگوها، هنگام آموزش از صفر یا فاین‌تیونینگ شبکه‌ها با خطاهای رایج بهینه‌سازی و نوسان بی‌پایان تابع زیان روبه‌رو خواهید شد.

این درس به شما نشان می‌دهد چطور زمان‌بندی‌های مختلف مانند کاهش پله‌ای، تبرید کسینوسی، وارم‌آپ و سیاست 1cycle را از پایه پیاده کنید، رفتار همگرایی آن‌ها را بسنجید و بهترین استراتژی را متناسب با بودجه‌ی پردازشی خود در PyTorch انتخاب کنید.

نرخ یادگیری (learning rate) مهم‌ترین هایپرپارامتر مدل است؛ نه معماری، نه اندازه‌ی مجموعه‌داده و نه تابع فعال‌سازی؛ فقط نرخ یادگیری. اگر قرار است تنها یک چیز را تنظیم کنید، همین را تنظیم کنید.

اهداف یادگیری

  • پیاده‌سازی برنامه‌های زمان‌بندی نرخ یادگیری (learning rate schedule) ثابت (constant)، کاهش پله‌ای (step decay)، تبرید کسینوسی (cosine annealing)، وارم‌آپ همراه با کسینوسی (warmup + cosine) و تک‌چرخه‌ای (1cycle) از صفر
  • نمایش سه حالت شکست در انتخاب نرخ یادگیری: واگرایی (خیلی بالا)، درجا زدن و کندی مفرط (خیلی پایین) و نوسان (بدون کاهش)
  • توضیح چرایی لزوم وارم‌آپ (warmup) برای بهینه‌سازهای مبتنی بر Adam و نحوه‌ی پایدارسازی مراحل اولیه‌ی آموزش به‌کمک آن
  • مقایسه‌ی سرعت همگرایی در هر پنج برنامه‌ی زمان‌بندی روی یک مسئله‌ی یکسان و انتخاب گزینه‌ی مناسب بر اساس بودجه‌ی پردازشی آموزش

صورت مسئله

نرخ یادگیری را روی 0.1 بگذارید؛ آموزش واگرا می‌شود و تابع زیان (loss) در 3 گام به بی‌نهایت می‌رسد. آن را روی 0.0001 تنظیم کنید؛ آموزش با سرعتی لاک‌پشتی پیش می‌رود و بعد از 100 ایپاک، مدل به‌سختی از حالت تصادفی اولیه فاصله می‌گیرد. آن را روی 0.01 بگذارید؛ آموزش تا 50 ایپاک خوب پیش می‌رود، اما بعد از آن تابع زیان دور نقطه‌ی کمینه‌ای نوسان می‌کند که هرگز به آن نمی‌رسد؛ چون گام‌ها بیش‌ازحد بزرگ‌اند.

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

تک‌تک مدل‌های بزرگ منتشرشده در سه سال گذشته از برنامه‌ی زمان‌بندی نرخ یادگیری استفاده می‌کنند. مدل Llama 3 از نرخ یادگیری اوج lr=3e-4 همراه با 2000 گام وارم‌آپ و سپس کاهش کسینوسی تا 3e-5 استفاده کرد. مدل GPT-3 از lr=6e-4 همراه با وارم‌آپ روی 375 میلیون توکن (token) بهره برد. این‌ها انتخاب‌هایی دلبخواهی نیستند، بلکه حاصل جست‌وجوی گسترده‌ی هایپرپارامترها با هزینه‌های چند میلیون دلاری‌اند.

باید این برنامه‌ها را بشناسید، چون مقادیر پیش‌فرض برای مسئله‌ی شما جواب نمی‌دهند. هنگام فاین‌تیونینگ (fine-tuning) یک مدل از‌پیش‌آموزش‌دیده، برنامه‌ی مناسب با آموزش از صفر کاملاً تفاوت دارد. وقتی اندازه‌ی بچ (batch size) را افزایش می‌دهید، دوره‌ی وارم‌آپ هم باید تغییر کند. اگر آموزش در گام 10,000 از کار افتاد، باید بدانید اشکال از برنامه‌ی زمان‌بندی است یا چیز دیگری.

مفاهیم پایه

نرخ یادگیری ثابت

ساده‌ترین روش ممکن: یک عدد انتخاب می‌کنید و در تمام گام‌ها همان را به کار می‌برید.

lr(t)=lr0\text{lr}(t) = \text{lr}_0

این روش به‌ندرت بهینه است؛ یا برای اواخر آموزش زیادی بزرگ است (نوسان در اطراف کمینه)، یا برای اوایل کار زیادی کوچک است (هدر رفتن توان پردازشی روی گام‌های بسیار ریز). برای مدل‌های کوچک و اشکال‌زدایی مناسب است، اما برای هر مدلی که آموزشش بیش از یک ساعت طول می‌کشد، گزینه‌ای فاجعه‌بار به شمار می‌رود.

کاهش پله‌ای

رویکرد سنتیِ دوران ResNet: نرخ یادگیری را در ایپاک‌های مشخصی با ضریبی معین (معمولاً 10 برابر) کاهش می‌دهید.

lr(t)=lr0⋅γ⌊epoch/step_size⌋\text{lr}(t) = \text{lr}_0 \cdot \gamma^{\lfloor \text{epoch} / \text{step\_size} \rfloor}

که در آن γ=0.1\gamma = 0.1 و step_size = 30 یعنی: نرخ یادگیری هر 30 ایپاک یک‌بار، 10 برابر کوچک‌تر می‌شود. شبکه عصبی (neural network) مدل ResNet-50 از همین الگو استفاده می‌کرد؛ lr=0.1 و کاهش 10 برابری در ایپاک‌های 30، 60 و 90.

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

تبرید کسینوسی

کاهش هموار نرخ یادگیری از مقدار بیشینه به یک مقدار کمینه، مطابق با منحنی کسینوسی:

lr(t)=lrmin⁡+0.5⋅(lrmax⁡−lrmin⁡)⋅(1+cos⁡(πtT))\text{lr}(t) = \text{lr}_{\min} + 0.5 \cdot (\text{lr}_{\max} - \text{lr}_{\min}) \cdot \left(1 + \cos\left(\frac{\pi t}{T}\right)\right)

که در آن tt گام فعلی و TT تعداد کل گام‌ها است.

در t=0t=0، عبارت کسینوسی برابر با 1 است، پس lr=lrmax⁡\text{lr} = \text{lr} _{\max}. در t=Tt=T، عبارت کسینوسی برابر با 1- است، پس lr=lrmin⁡\text{lr} = \text{lr} _{\min}. روند کاهش در ابتدا ملایم است، در اواسط کار شتاب می‌گیرد و نزدیک به پایان دوباره آرام می‌شود.

این حالت، گزینه‌ی پیش‌فرض بیشتر آموزش‌های امروزی است و هایپرپارامتری جز lrmax⁡\text{lr} _{\max} و lrmin⁡\text{lr} _{\min} برای تنظیم ندارد. شکل منحنی کسینوسی با این مشاهده‌ی تجربی هم‌خوانی دارد که بخش عمده‌ی یادگیری در میانه‌ی آموزش رخ می‌دهد؛ بنابراین در این دوره‌ی حیاتی به گام‌هایی با اندازه‌ی معقول نیاز دارید.

وارم‌آپ: چرا باید با مقادیر کوچک شروع کرد؟

بهینه‌ساز Adam و سایر بهینه‌سازهای تطبیقی، برآوردهای متحرکی از میانگین و واریانس گرادیان (gradient) نگه می‌دارند. در گام 0، مقدار اولیه‌ی این برآوردها صفر است؛ بنابراین اولین به‌روزرسانی‌های گرادیان بر پایه‌ی آماره‌هایی کاملاً نامعتبر انجام می‌گیرند. اگر نرخ یادگیری در این بازه بزرگ باشد، مدل گام‌هایی غول‌آسا در جهت‌های نامناسب برمی‌دارد.

وارم‌آپ این مشکل را حل می‌کند: کار را با نرخ یادگیری بسیار کوچکی (اغلب lr_max / warmup_steps یا حتی صفر) شروع می‌کنید و طی NN گام ابتدایی، آن را به‌صورت خطی تا lrmax⁡\text{lr}_{\max} بالا می‌برید. تا زمانی که به نرخ یادگیری کامل برسید، آماره‌های Adam پایدار شده‌اند.

lr(t)=lrmax⁡⋅twarmup_stepsfor t<warmup_steps\text{lr}(t) = \text{lr}_{\max} \cdot \frac{t}{\text{warmup\_steps}} \quad \text{for } t < \text{warmup\_steps}

وارم‌آپ معمولاً 1 تا 5 درصد از کل گام‌های آموزش را شامل می‌شود. مدل Llama 3 روی حدود 1.8 تریلیون توکن آموزش دید و وارم‌آپ آن 2000 گام بود. مدل GPT-3 نیز وارم‌آپ را در طول 375 میلیون توکن اجرا کرد.

وارم‌آپ خطی همراه با کاهش کسینوسی

گزینه‌ی پیش‌فرض امروزی: افزایش خطی در ابتدا و سپس کاهش با منحنی کسینوسی:

if t < warmup_steps:
    lr(t) = lr_max * (t / warmup_steps)
else:
    progress = (t - warmup_steps) / (total_steps - warmup_steps)
    lr(t) = lr_min + 0.5 * (lr_max - lr_min) * (1 + cos(pi * progress))

این همان الگویی است که Llama، مدل GPT، مدل PaLM و بیشتر ترنسفورمرهای (transformer) مدرن به کار می‌برند. وارم‌آپ جلوی ناپایداری‌های آغازین را می‌گیرد و کاهش کسینوسی مدل را به‌خوبی در یک کمینه‌ی مناسب مستقر می‌کند.

سیاست تک‌چرخه‌ای (1cycle Policy)

کشف لزلی اسمیت در سال 2018: نرخ یادگیری را در نیمه‌ی اول آموزش از مقداری پایین تا مقداری بالا افزایش دهید، سپس در نیمه‌ی دوم دوباره آن را پایین بیاورید. در نگاه اول دور از ذهن است؛ چرا باید نرخ یادگیری را در میانه‌ی راه افزایش داد؟

توجیه نظری: نرخ یادگیری بالا با افزودن نوفه به مسیر بهینه‌سازی (optimization)، مانند نوعی منظم‌سازی عمل می‌کند. در نتیجه، مدل در فاز صعودی بخش‌های بیشتری از چشم‌انداز زیان (loss landscape) را کاوش می‌کند و حوضچه‌های بهتری می‌یابد. فاز نزولی هم تنظیم دقیق مدل را در همان بهترین حوضچه‌ی کشف‌شده تکمیل می‌کند.

Phase 1 (0 to T/2):    lr ramps from lr_max/25 to lr_max
Phase 2 (T/2 to T):    lr ramps from lr_max to lr_max/10000

سیاست 1cycle با بودجه‌ی پردازشی ثابت، اغلب سریع‌تر از تبرید کسینوسی آموزش را به سرانجام می‌رساند. عیبش این است که باید تعداد کل گام‌ها را از همان ابتدا بدانید.

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

گرماگرمی + کسینوسیکاهش کسینوسیکاهش پله‌ایثابتlrlrlr0.10.10.010.001lr_maxتدریجیتندlr_min0lr_maxکسینوسیlr_min

فلوچارت تصمیم‌گیری

بلهخیرزیاد (روزها/هفته‌ها)کم (ساعت‌ها)متوسطانتخاب برنامه LRتعداد کل گام‌هایآموزش مشخص است؟بودجه محاسباتی؟استفاده از LR ثابتبا کاهش دستیگرماگرمی + کاهش کسینوسی(پیش‌فرض Llama/GPT)سیاست 1cycle(سریع‌ترین همگرایی)کاهش کسینوسی(پیش‌فرض امن)گرماگرمی = 1-5% گام‌هایافتن lr_max با آزمون بازه LRتنظیم lr_min = lr_max / 10

مقادیر واقعی در مدل‌های منتشرشده

پیکربندی‌های LR منتشرشدهLlama 3 (405B)اوج: 3e-4گرماگرمی: 2000 گامبرنامه: کسینوسی تا 3e-5GPT-3 (175B)اوج: 6e-4گرماگرمی: 375M توکنبرنامه: کسینوسی تا 0ResNet-50اوج: 0.1گرماگرمی: نداردبرنامه: کاهش پله‌ای x0.1 در 30، 60، 90BERT (340M)اوج: 1e-4گرماگرمی: 10K گامبرنامه: کاهش خطی
زمان‌بندی نرخ یادگیرییک زمان‌بندی انتخاب کنید
LR SCHEDULEThe learning rate rarely stays fixed. A short warmup avoids early instability; cosine or step decay then anneals the rate toward zero so late training settles into a good minimum.
نرخ یادگیری به‌ندرت ثابت می‌ماند. یک گرم‌کردن (warmup) کوتاه از ناپایداری اولیه جلوگیری می‌کند؛ سپس افت کسینوسی یا پله‌ای، نرخ را به‌سمت صفر کاهش می‌دهد تا مراحل پایانی آموزش در یک کمینهٔ مطلوب تثبیت شوند.

پیاده‌سازی گام‌به‌گام

گام 1: توابع برنامه‌ی زمان‌بندی

هر تابع گام فعلی را می‌گیرد و نرخ یادگیری متناظر با آن گام را برمی‌گرداند.

import math


def constant_schedule(step, lr=0.01, **kwargs):
    return lr


def step_decay_schedule(step, lr=0.1, step_size=100, gamma=0.1, **kwargs):
    return lr * (gamma ** (step // step_size))


def cosine_schedule(step, lr=0.01, total_steps=1000, lr_min=1e-5, **kwargs):
    if step >= total_steps:
        return lr_min
    return lr_min + 0.5 * (lr - lr_min) * (1 + math.cos(math.pi * step / total_steps))


def warmup_cosine_schedule(step, lr=0.01, total_steps=1000, warmup_steps=100, lr_min=1e-5, **kwargs):
    if total_steps <= warmup_steps:
        return lr * (step / max(warmup_steps, 1))
    if step < warmup_steps:
        return lr * step / warmup_steps
    progress = (step - warmup_steps) / (total_steps - warmup_steps)
    return lr_min + 0.5 * (lr - lr_min) * (1 + math.cos(math.pi * progress))


def one_cycle_schedule(step, lr=0.01, total_steps=1000, **kwargs):
    mid = max(total_steps // 2, 1)
    if step < mid:
        return (lr / 25) + (lr - lr / 25) * step / mid
    else:
        progress = (step - mid) / max(total_steps - mid, 1)
        return lr * (1 - progress) + (lr / 10000) * progress

گام 2: مصورسازی تمام برنامه‌های زمان‌بندی

چاپ یک نمودار متنی ساده برای نمایش نحوه‌ی تغییر هر برنامه در طول فرایند آموزش.

def visualize_schedule(name, schedule_fn, total_steps=500, **kwargs):
    steps = list(range(0, total_steps, total_steps // 20))
    if total_steps - 1 not in steps:
        steps.append(total_steps - 1)

    lrs = [schedule_fn(s, total_steps=total_steps, **kwargs) for s in steps]
    max_lr = max(lrs) if max(lrs) > 0 else 1.0

    print(f"\n{name}:")
    for s, lr_val in zip(steps, lrs):
        bar_len = int(lr_val / max_lr * 40)
        bar = "#" * bar_len
        print(f"  Step {s:4d}: lr={lr_val:.6f} {bar}")

گام 3: شبکه‌ی آموزش

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

import random


def sigmoid(x):
    x = max(-500, min(500, x))
    return 1.0 / (1.0 + math.exp(-x))


def relu(x):
    return max(0.0, x)


def relu_deriv(x):
    return 1.0 if x > 0 else 0.0


def make_circle_data(n=200, seed=42):
    random.seed(seed)
    data = []
    for _ in range(n):
        x = random.uniform(-2, 2)
        y = random.uniform(-2, 2)
        label = 1.0 if x * x + y * y < 1.5 else 0.0
        data.append(([x, y], label))
    return data


def train_with_schedule(schedule_fn, schedule_name, data, epochs=300, base_lr=0.05, **kwargs):
    random.seed(0)
    hidden_size = 8
    total_steps = epochs * len(data)

    std = math.sqrt(2.0 / 2)
    w1 = [[random.gauss(0, std) for _ in range(2)] for _ in range(hidden_size)]
    b1 = [0.0] * hidden_size
    w2 = [random.gauss(0, std) for _ in range(hidden_size)]
    b2 = 0.0

    step = 0
    epoch_losses = []

    for epoch in range(epochs):
        total_loss = 0
        correct = 0

        for x, target in data:
            lr = schedule_fn(step, lr=base_lr, total_steps=total_steps, **kwargs)

            z1 = []
            h = []
            for i in range(hidden_size):
                z = w1[i][0] * x[0] + w1[i][1] * x[1] + b1[i]
                z1.append(z)
                h.append(relu(z))

            z2 = sum(w2[i] * h[i] for i in range(hidden_size)) + b2
            out = sigmoid(z2)

            error = out - target
            d_out = error * out * (1 - out)

            for i in range(hidden_size):
                d_h = d_out * w2[i] * relu_deriv(z1[i])
                w2[i] -= lr * d_out * h[i]
                for j in range(2):
                    w1[i][j] -= lr * d_h * x[j]
                b1[i] -= lr * d_h
            b2 -= lr * d_out

            total_loss += (out - target) ** 2
            if (out >= 0.5) == (target >= 0.5):
                correct += 1
            step += 1

        avg_loss = total_loss / len(data)
        accuracy = correct / len(data) * 100
        epoch_losses.append(avg_loss)

    return epoch_losses

گام 4: مقایسه‌ی تمام برنامه‌های زمان‌بندی

آموزش همان شبکه با هر یک از این برنامه‌ها و مقایسه‌ی تابع زیان نهایی و رفتار همگرایی آن‌ها.

def compare_schedules(data):
    configs = [
        ("Constant", constant_schedule, {}),
        ("Step Decay", step_decay_schedule, {"step_size": 15000, "gamma": 0.1}),
        ("Cosine", cosine_schedule, {"lr_min": 1e-5}),
        ("Warmup+Cosine", warmup_cosine_schedule, {"warmup_steps": 3000, "lr_min": 1e-5}),
        ("1cycle", one_cycle_schedule, {}),
    ]

    print(f"\n{'Schedule':<20} {'Start Loss':>12} {'Mid Loss':>12} {'End Loss':>12} {'Best Loss':>12}")
    print("-" * 70)

    for name, schedule_fn, extra_kwargs in configs:
        losses = train_with_schedule(schedule_fn, name, data, epochs=300, base_lr=0.05, **extra_kwargs)
        mid_idx = len(losses) // 2
        best = min(losses)
        print(f"{name:<20} {losses[0]:>12.6f} {losses[mid_idx]:>12.6f} {losses[-1]:>12.6f} {best:>12.6f}")

گام 5: نرخ یادگیری خیلی بالا در برابر خیلی پایین

نمایش سه حالت شکست: زیادی بالا (واگرایی)، زیادی پایین (درجا زدن) و مقدار کاملاً مناسب.

def lr_sensitivity(data):
    learning_rates = [1.0, 0.1, 0.01, 0.001, 0.0001]

    print("\nLR Sensitivity (constant schedule, 100 epochs):")
    print(f"  {'LR':>10} {'Start Loss':>12} {'End Loss':>12} {'Status':>15}")
    print("  " + "-" * 52)

    for lr in learning_rates:
        losses = train_with_schedule(constant_schedule, f"lr={lr}", data, epochs=100, base_lr=lr)
        start = losses[0]
        end = losses[-1]

        if end > start or math.isnan(end) or end > 1.0:
            status = "DIVERGED"
        elif end > start * 0.9:
            status = "BARELY MOVED"
        elif end < 0.15:
            status = "CONVERGED"
        else:
            status = "LEARNING"

        end_str = f"{end:.6f}" if not math.isnan(end) else "NaN"
        print(f"  {lr:>10.4f} {start:>12.6f} {end_str:>12} {status:>15}")

کاربرد در دنیای واقعی

کتابخانه‌ی PyTorch این زمان‌بندها را در ماژول torch.optim.lr_scheduler ارائه می‌دهد:

import torch
import torch.optim as optim
from torch.optim.lr_scheduler import CosineAnnealingLR, OneCycleLR, StepLR

model = nn.Sequential(nn.Linear(10, 64), nn.ReLU(), nn.Linear(64, 1))
optimizer = optim.Adam(model.parameters(), lr=3e-4)

scheduler = CosineAnnealingLR(optimizer, T_max=1000, eta_min=1e-5)

for step in range(1000):
    loss = train_step(model, optimizer)
    scheduler.step()

برای ترکیب وارم‌آپ و کسینوسی، از یک زمان‌بند مبتنی بر تابع lambda یا تابع get_cosine_schedule_with_warmup در کتابخانه‌ی HuggingFace استفاده کنید:

from transformers import get_cosine_schedule_with_warmup

scheduler = get_cosine_schedule_with_warmup(
    optimizer,
    num_warmup_steps=2000,
    num_training_steps=100000,
)

تابع ارائه‌شده در HuggingFace همان کدی است که بیشتر اسکریپت‌های فاین‌تیونینگ Llama و GPT به کار می‌برند. اگر شک داشتید، ترکیب وارم‌آپ و کسینوسی را با وارم‌آپی معادل 3 تا 5 درصد از کل گام‌ها پیاده کنید؛ تقریباً برای هر کاری عالی عمل می‌کند.

خروجی نهایی

خروجی این درس:

  • outputs/prompt-lr-schedule-advisor.md -- پرامپتی (prompt) که برنامه‌ی زمان‌بندی نرخ یادگیری و هایپرپارامترهای بهینه را برای ساختار آموزشی شما پیشنهاد می‌کند.

تمرین‌ها

  1. کاهش نمایی (exponential decay) را پیاده‌سازی کنید: lr(t)=lr0⋅γt\text{lr}(t) = \text{lr}_0 \cdot \gamma^t که در آن γ=0.999\gamma = 0.999. سپس عملکرد آن را با تبرید کسینوسی روی مجموعه‌داده‌ی دایره مقایسه کنید.

  2. آزمون دامنه‌ی نرخ یادگیری (Leslie Smith) را پیاده‌سازی کنید: مدل را برای چند صد گام آموزش دهید و هم‌زمان نرخ یادگیری را به‌صورت نمایی از 1e-7 تا 1 بالا ببرید. نمودار تابع زیان بر حسب نرخ یادگیری را رسم کنید. نرخ یادگیری بیشینه‌ی بهینه، درست قبل از نقطه‌ای است که تابع زیان شروع به افزایش می‌کند.

  3. مدل را با وارم‌آپ + کسینوسی آموزش دهید، اما طول دوره‌ی وارم‌آپ را تغییر دهید: 0%، 1%، 5%، 10% و 20% از کل گام‌ها. نقطه‌ی طلایی بیشترین پایداری آموزش را پیدا کنید.

  4. تبرید کسینوسی با شروع‌های مجدد گرم (SGDR) را پیاده‌سازی کنید: نرخ یادگیری را هر TT گام یک‌بار روی lrmax⁡\text{lr}_{\max} ریست کنید و دوباره کاهش دهید. عملکرد این روش را با کسینوسی استاندارد در یک آموزش طولانی‌تر مقایسه کنید.

  5. یک «جراح برنامه‌ی زمان‌بندی» بسازید که تابع زیان آموزش را پایش کند؛ به این صورت که پس از پایدار شدن تابع زیان، زمان‌بندی را خودکار از وارم‌آپ به کسینوسی تغییر دهد و در صورت درجا زدن طولانی‌مدت تابع زیان، نرخ یادگیری را پایین بیاورد.

اصطلاحات کلیدی

اصطلاح در گفت‌وگوها معنای دقیق فنی
نرخ یادگیری (Learning rate) «سرعت یادگیری مدل» مقدار اسکالری که در گرادیان ضرب می‌شود تا اندازه‌ی گام به‌روزرسانی پارامترها را مشخص کند.
برنامه‌ی زمان‌بندی (Schedule) «تغییر نرخ یادگیری در طول زمان» تابعی که گام آموزش را به نرخ یادگیری نگاشت می‌کند تا همگرایی بهینه شود.
وارم‌آپ (Warmup) «شروع با نرخ یادگیری کوچک» افزایش خطی نرخ یادگیری از مقداری نزدیک به صفر تا مقدار هدف طی NN گام ابتدایی برای پایدارسازی آماره‌های بهینه‌ساز.
تبرید کسینوسی (Cosine annealing) «کاهش هموار نرخ یادگیری» کاهش نرخ یادگیری مطابق منحنی کسینوسی از lrmax⁡\text{lr} _{\max} تا lrmin⁡\text{lr} _{\min} در طول دوره آموزش.
کاهش پله‌ای (Step decay) «افت پله‌ای در نقاط مشخص» ضرب کردن نرخ یادگیری در یک ضریب (معمولاً 0.1) در بازه‌های زمانی ثابت ایپاک‌ها.
سیاست تک‌چرخه‌ای (1cycle policy) «بالا رفتن و سپس پایین آمدن» روش ابداعی لزلی اسمیت برای بالا بردن نرخ یادگیری و سپس پایین آوردن آن در قالب یک چرخه‌ی منفرد به‌منظور همگرایی سریع‌تر.
آزمون دامنه‌ی نرخ یادگیری (LR range test) «یافتن بهترین نرخ یادگیری» آموزش کوتاه‌مدت مدل هم‌زمان با افزایش نرخ یادگیری برای یافتن مقداری که تابع زیان در آن شروع به واگرایی می‌کند.
کسینوسی با شروع‌های مجدد گرم (Cosine with warm restarts) «تنظیم مجدد و تکرار» بازنشانی دوره‌ای نرخ یادگیری به lrmax⁡\text{lr} _{\max} و تکرار روند کاهش آن (SGDR).
حداقل نرخ یادگیری (Eta min) «کف نرخ یادگیری» کمترین مقدار نرخ یادگیری که برنامه‌ی زمان‌بندی تا آن حد کاهش می‌یابد.
نرخ یادگیری اوج (Peak learning rate) «بیشترین نرخ یادگیری» بالاترین نرخ یادگیری حاصل‌شده در طول فرایند آموزش؛ معمولاً در پایان دوره‌ی وارم‌آپ.

برای مطالعه‌ی بیشتر

  • Loshchilov & Hutter, "SGDR: Stochastic Gradient Descent with Warm Restarts" (2017) -- مقاله‌ی معرفی تبرید کسینوسی و شروع‌های مجدد گرم
  • Smith, "Super-Convergence: Very Fast Training of Neural Networks Using Large Learning Rates" (2018) -- مقاله‌ی سیاست تک‌چرخه‌ای (1cycle policy)
  • Touvron et al., "Llama 2: Open Foundation and Fine-Tuned Chat Models" (2023) -- مستندات برنامه‌ی وارم‌آپ همراه با کسینوسی در مقیاس بزرگ
  • Goyal et al., "Accurate, Large Minibatch SGD: Training ImageNet in 1 Hour" (2017) -- قاعده‌ی مقیاس‌بندی خطی و وارم‌آپ برای آموزش با مینی‌بچ‌های بزرگ

سؤالات متداول

چرا استفاده از نرخ یادگیری ثابت در آموزش شبکه‌های عصبی اشتباه است؟

یک نرخ ثابت معمولاً یا در آغاز آموزش بیش‌ازحد کوچک است و سرعت یادگیری را تلف می‌کند، یا در اواخر کار آن‌قدر بزرگ است که باعث نوسان دائمی حول نقطه کمینه می‌شود و مانع از استقرار دقیق مدل می‌گردد.

چرا استفاده از وارم‌آپ (Warmup) برای بهینه‌ساز Adam ضروری است؟

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

سیاست 1cycle چیست و چه مزیتی دارد؟

در روش 1cycle نرخ یادگیری ابتدا تا اوج بالا رفته و سپس کاهش می‌یابد. نرخ بالا در نیمه اول نقش نوعی منظم‌سازی دارد و به کاوش بهتر چشم‌انداز زیان کمک می‌کند، در نتیجه معمولاً آموزش در زمان کوتاه‌تری به همگرایی می‌رسد.

استاندارد رایج برای فاین‌تیونینگ مدل‌های زبانی بزرگ چیست؟

ترکیب وارم‌آپ خطی (حدود 1 تا 5 درصد کل گام‌ها) همراه با کاهش کسینوسی (Cosine Decay)، که در کتابخانه‌هایی مانند HuggingFace پیاده شده، گزینه‌ی استاندارد و مطمئن برای اغلب پروژه‌هاست.

ما رو توی گوگل بیشتر ببین

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