محاسبهی گرادیان در شبکههای عصبی تنها نیمی از مسیر آموزش مدل است. گرادیان فقط جهت حرکت را مشخص میکند، اما نمیگوید با چه سرعتی و تا چه اندازه باید در فضای پارامترها پیش رفت. استفاده از گرادیان کاهشی ساده معمولاً به نوسانهای شدید در درههای باریک تابع زیان، درجا زدن در نقاط زینی و عدم هماهنگی نرخ بهروزرسانی برای وزنهای مختلف منجر میشود.
الگوریتمهای مدرن مانند Adam و AdamW با ترکیب تکانه و نرخ یادگیری انطباقی به ازای هر پارامتر، این موانع را برطرف کردهاند. در این درس، سازوکار ریاضی و منطق بهینهسازهای پرکاربرد از جمله SGD، Momentum، RMSProp، Adam و تفاوت حیاتی AdamW را بررسی میکنیم و هر یک را از صفر در Python پیادهسازی خواهیم کرد.
گرادیان کاهشی به شما میگوید به کدام سمت بروید، اما دربارهی اینکه چقدر یا با چه سرعتی حرکت کنید هیچ حرفی نمیزند. SGD شبیه یک قطبنماست؛ اما Adam درست مثل یک GPS مجهز به دادههای ترافیک زنده عمل میکند.
اهداف یادگیری
- پیادهسازی بهینهسازهای SGD، SGD مجهز به تکانه (momentum)، Adam و AdamW از صفر در Python
- توضیح نحوهی جبران مقداردهی اولیهی صفر در گشتاورهای Adam با کمک تصحیح سوگیری (bias correction) در گامهای آغازین آموزش
- بررسی دلیل تعمیم بهتر AdamW در مقایسه با Adam مجهز به منظمسازی L2 در یک مسئلهی یکسان
- انتخاب بهینهساز مناسب و هایپرپارامترهای پیشفرض برای ترنسفورمرها، CNNها، GANها و فاینتیونینگ
صورت مسئله
گرادیانها را محاسبه کردهاید و میدانید وزن شمارهی 4,721 باید 0.003 واحد کم شود تا تابع زیان (loss) کاهش یابد. اما این 0.003 با چه مقیاسی سنجیده میشود؟ ضریب تغییرات آن چیست؟ و آیا باید در گام 1 دقیقاً به همان اندازهی گام 1,000 جابهجا شوید؟
گرادیان کاهشی ساده (Vanilla gradient descent) در هر گام، یک نرخ یادگیری یکسان را روی تمام پارامترها اعمال میکند: . این رویکرد سه مشکل به وجود میآورد که در عمل آموزش شبکههای عصبی را عذابآور میکنند:
نخست، نوسان. چشمانداز زیان (loss landscape) بهندرت شبیه یک کاسهی هموار است؛ بیشتر به درهای کشیده و باریک شباهت دارد. بردار گرادیان معمولاً در جهت دیوارههای دره (راستای شیب تند) است، نه در امتداد بستر آن (راستای کمشیب). در نتیجه گرادیان کاهشی مدام در راستای این بُعد کمعرض به این سو و آن سو تاب میخورد و در امتداد مسیر اصلی پیشرفت بسیار ناچیزی دارد. حتماً این حالت را دیدهاید: تابع زیان ابتدا با شیب زیادی افت میکند و سپس به یک سطح ثابت میرسد؛ نه به این خاطر که مدل همگرا شده، بلکه از شدت نوسان در جا میزند.
دوم، ناکارآمدیِ یک نرخ یادگیری ثابت برای همهی پارامترها. بعضی از وزنها به بهروزرسانیهای بزرگ نیاز دارند (چون در مراحل اولیهی کمبرازش قرار دارند). در مقابل، برخی وزنها به تغییرات بسیار ریزی محتاجاند (چون به مقدار بهینهی خود رسیدهاند). نرخ یادگیری مناسب برای گروه اول، دستهی دوم را خراب میکند و برعکس.
سوم، نقاط زینی (saddle points). در فضاهای چندبُعدی، چشمانداز زیان بخشهای مسطح و پهناوری دارد که گرادیان در آنها نزدیک به صفر است. گرادیان کاهشی ساده با سرعتی هماندازهی خود گرادیان در این دشتها میخزد؛ یعنی عملاً متوقف میشود. به نظر میرسد مدل گیر کرده، اما اینطور نیست؛ فقط در دشتی آرام افتاده که کمی جلوتر از آن، مسیر فرود مفیدی کشیده شده است. با این حال SGD هیچ سازوکاری برای push کردن و عبور از این نواحی ندارد.
الگوریتم Adam هر سه مشکل را حل میکند. این بهینهساز برای هر پارامتر دو میانگین متحرک ذخیره میکند: میانگین گرادیان (تکانه، برای مهار نوسان) و میانگین مجذور گرادیان (نرخ انطباقی، برای هماهنگی با مقیاسهای مختلف). این دو ویژگی در کنار تصحیح سوگیری برای گامهای آغازین، بهینهسازی میسازند که در 80% مسائل با همان هایپرپارامترهای پیشفرض جواب میدهد. در این درس آن را از صفر میسازیم تا متوجه شوید چرا و چه زمانی در آن 20% باقیمانده شکست میخورد.
مفاهیم پایه
گرادیان کاهشی تصادفی (SGD)
سادهترین بهینهساز ممکن: گرادیان را روی یک دستهی کوچک (mini-batch) حساب کنید و در جهت مخالف آن گام بردارید.
کلمهی «تصادفی» یعنی به جای کل دادهها، از یک زیرمجموعهی تصادفی (دستهی کوچک) برای برآورد گرادیان استفاده میکنید. این نویز در عمل اتفاقاً مفید است و به فرار از کمینههای محلی تند کمک میکند؛ اما از سوی دیگر نوسان هم به راه میاندازد.
نرخ یادگیری تنها پیچ تنظیم شماست. اگر خیلی زیاد باشد، تابع زیان واگرا میشود؛ اگر خیلی کم باشد، فرایند آموزش تا ابد طول میکشد. مقدار بهینه به معماری، دادهها، اندازهی دسته (batch size) و فاز فعلی آموزش بستگی دارد. برای SGD ساده روی شبکههای مدرن، مقادیر رایج بین 0.01 تا 0.1 تغییر میکنند؛ اما حتی در طول یک چرخهی آموزش، نرخ یادگیری ایدهآل ثابت نمیماند.
تکانه (Momentum)
تشبیه حرکت گرادیان به توپی که از تپه پایین میغلتد دستمالیشده به نظر میرسد، اما کاملاً دقیق است. به جای آنکه فقط با اتکا به گرادیان فعلی گام بردارید، یک متغیر سرعت نگه میدارید که گرادیانهای گذشته را در خود جمع میکند.
ضریب بتا (معمولاً 0.9) مشخص میکند چه مقدار از تاریخچهی قبل نگهداری شود. وقتی باشد، تکانه تقریباً برابر میانگین 10 گرادیان اخیر خواهد بود ().
دلیل مهار نوسان توسط تکانه این است: گرادیانهای همجهت با هم جمع و تقویت میشوند، ولی گرادیانهایی که تغییر جهت میدهند اثر یکدیگر را خنثی میکنند. در آن درهی باریک، مؤلفهی عمودی در هر گام علامت عوض میکند و میرا میشود؛ در عوض مؤلفهی طولی ثابت میماند و شتاب میگیرد. نتیجه، پیشروی روان و پرشتاب در مسیر مفید است.
یک عدد واقعی: اجرای SGD ساده روی چشمانداز زیانی با شرایط نامساعد شاید به 10,000 گام نیاز داشته باشد. اجرای SGD همراه با تکانه () روی همان مسئله معمولاً بین 3,000 تا 5,000 گام حل میشود؛ یعنی شتاب حاصل به هیچ وجه جزئی نیست.
RMSProp
اولین روش نرخ یادگیری انطباقی به ازای هر پارامتر که در عمل جواب داد. جفری هینتون این روش را در یکی از دورههای Coursera مطرح کرد و هرگز در قالب مقالهای رسمی به چاپ نرسید.
متغیر میانگین متحرک مجذور گرادیانها را ثبت میکند. پارامترهایی که مداوم گرادیانهای بزرگ دارند، بر عددی بزرگ تقسیم میشوند (نرخ یادگیری مؤثرِ کمتر) و پارامترهایی با گرادیانهای ریز، بر عددی کوچک تقسیم میشوند (نرخ یادگیری مؤثرِ بیشتر).
این سازوکار مشکل «نرخ یادگیری یکسان برای همهی پارامترها» را حل میکند. وزنی که تا الان آپدیتهای درشتی گرفته، احتمالاً نزدیک به مقصد است؛ پس باید سرعتش را کم کنیم. در مقابل، وزنی که تغییرات ریزی داشته، احتمالاً هنوز خوب آموزش ندیده است؛ پس باید سرعتش را بالا ببریم.
اپسیلون (معمولاً 1e-8) جلوی خطای تقسیم بر صفر را در پارامترهایی میگیرد که هنوز بهروزرسانی نشدهاند.
Adam: ترکیب تکانه و RMSProp
الگوریتم Adam هر دو رویکرد را با هم درمیآمیزد و برای هر پارامتر دو میانگین متحرک نمایی را حفظ میکند:
تصحیح سوگیری همان جزئیات تعیینکنندهای است که بیشتر منابع از آن رد میشوند. در گام اول، . با ، این مقدار به میرسد؛ یعنی ده برابر کوچکتر از اندازهی واقعی، چون میانگین متحرک هنوز گرم نشده است. تصحیح سوگیری این کاستی را جبران میکند:
در گام 1 با فرض ، مقدار دقیقاً با گرادیان واقعی برابر میشود. در گام 100، تقریباً به 1.0 میرسد؛ بنابراین اثر تصحیح از بین میرود. تصحیح سوگیری صرفاً در حدود 10 گام آغازین حیاتی است و بعد از حدود 50 گام هیچ تأثیری ندارد.
بهروزرسانی نهایی:
مقادیر پیشفرض در Adam: ، ، و . این تنظیمات برای 80% سناریوها کافی هستند. اگر جواب نگرفتید، اول نرخ یادگیری را تغییر دهید؛ بعد به سراغ بروید. تقریباً هیچوقت به یا دست نزنید.
AdamW: کاهش وزن به روش درست
منظمسازی L2 عبارت را به تابع زیان اضافه میکند. در SGD ساده، این کار عیناً معادل کاهش وزن (weight decay) یعنی کم کردن از وزن در هر گام است؛ اما در Adam این برابری نقض میشود.
یافتهی کلیدی لاشچیلُف و هوتر (Loshchilov & Hutter) این بود: اگر L2 را به تابع زیان بیفزایید و سپس Adam گرادیان را پردازش کند، نرخ یادگیری انطباقی ناخواسته جملهی جریمه را هم تغییر مقیاس میدهد. در نتیجه، پارامترهایی با واریانس گرادیان بالا جریمهی کمتری میگیرند و پارامترهایی با واریانس پایین، بیش از حد منقبض میشوند. این رویکرد نادرست است؛ شما فارغ از آمار گرادیان هر پارامتر، جریمهای یکنواخت میخواهید.
الگوریتم AdamW با اعمال مستقیم کاهش وزن روی خودِ وزنها پس از اتمام بهروزرسانی Adam، این ضعف را رفع میکند:
در این ساختار، جملهی کاهش وزن () تحت تأثیر ضریب انطباقی Adam قرار نمیگیرد و همهی وزنها به تناسبی مساوی مهار میشوند.
شاید تغییری جزئی به نظر برسد، اما واقعاً اینطور نیست. AdamW تقریباً در تمام تسکها نسبت به ترکیب Adam و تنظیمکنندهی L2 به نقطهی بهینهی بهتری همگرا میشود. هماکنون این روش بهینهساز پیشفرض PyTorch برای آموزش ترنسفورمرها، مدلهای انتشار و اغلب شبکههای مدرن است. مدلهای BERT، GPT، LLaMA و Stable Diffusion همگی با AdamW آموزش دیدهاند.
نرخ یادگیری: حیاتیترین هایپرپارامتر
اگر قرار است فقط یک متغیر را دستکاری کنید، آن متغیر نرخ یادگیری است. تغییر 10 برابری نرخ یادگیری، اثرگذارتر از هر تصمیم معماری دیگری خواهد بود که فکرش را بکنید. مقادیر پیشفرض رایج عبارتاند از:
- برای SGD: مقدار lr = 0.01 تا 0.1
- برای Adam/AdamW: مقدار lr = 1e-4 تا 3e-4
- برای فاینتیونینگ مدلهای ازپیشآموزشدیده: lr = 1e-5 تا 5e-5
- گرمکردن نرخ یادگیری (warmup): افزایش خطی در بازهی 1 تا 10 درصد نخست گامها
مقایسهی بهینهسازها
موارد برتری هر بهینهساز
پیادهسازی گامبهگام
گام 1: گرادیان کاهشی ساده (Vanilla SGD)
class SGD:
def __init__(self, lr=0.01):
self.lr = lr
def step(self, params, grads):
for i in range(len(params)):
params[i] -= self.lr * grads[i]
گام 2: SGD مجهز به تکانه
class SGDMomentum:
def __init__(self, lr=0.01, beta=0.9):
self.lr = lr
self.beta = beta
self.velocities = None
def step(self, params, grads):
if self.velocities is None:
self.velocities = [0.0] * len(params)
for i in range(len(params)):
self.velocities[i] = self.beta * self.velocities[i] + grads[i]
params[i] -= self.lr * self.velocities[i]
گام 3: Adam
import math
class Adam:
def __init__(self, lr=0.001, beta1=0.9, beta2=0.999, epsilon=1e-8):
self.lr = lr
self.beta1 = beta1
self.beta2 = beta2
self.epsilon = epsilon
self.m = None
self.v = None
self.t = 0
def step(self, params, grads):
if self.m is None:
self.m = [0.0] * len(params)
self.v = [0.0] * len(params)
self.t += 1
for i in range(len(params)):
self.m[i] = self.beta1 * self.m[i] + (1 - self.beta1) * grads[i]
self.v[i] = self.beta2 * self.v[i] + (1 - self.beta2) * grads[i] ** 2
m_hat = self.m[i] / (1 - self.beta1 ** self.t)
v_hat = self.v[i] / (1 - self.beta2 ** self.t)
params[i] -= self.lr * m_hat / (math.sqrt(v_hat) + self.epsilon)
گام 4: AdamW
class AdamW:
def __init__(self, lr=0.001, beta1=0.9, beta2=0.999, epsilon=1e-8, weight_decay=0.01):
self.lr = lr
self.beta1 = beta1
self.beta2 = beta2
self.epsilon = epsilon
self.weight_decay = weight_decay
self.m = None
self.v = None
self.t = 0
def step(self, params, grads):
if self.m is None:
self.m = [0.0] * len(params)
self.v = [0.0] * len(params)
self.t += 1
for i in range(len(params)):
self.m[i] = self.beta1 * self.m[i] + (1 - self.beta1) * grads[i]
self.v[i] = self.beta2 * self.v[i] + (1 - self.beta2) * grads[i] ** 2
m_hat = self.m[i] / (1 - self.beta1 ** self.t)
v_hat = self.v[i] / (1 - self.beta2 ** self.t)
params[i] -= self.lr * m_hat / (math.sqrt(v_hat) + self.epsilon)
params[i] -= self.lr * self.weight_decay * params[i]
گام 5: مقایسهی فرایند آموزش
همان شبکهی دولایهی درس 05 را با هر چهار بهینهساز روی مجموعهدادهی دایرهها آموزش دهید و روند همگرایی آنها را با هم بسنجید.
import random
def sigmoid(x):
x = max(-500, min(500, x))
return 1.0 / (1.0 + math.exp(-x))
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
class OptimizerTestNetwork:
def __init__(self, optimizer, hidden_size=8):
random.seed(0)
self.hidden_size = hidden_size
self.optimizer = optimizer
self.w1 = [[random.gauss(0, 0.5) for _ in range(2)] for _ in range(hidden_size)]
self.b1 = [0.0] * hidden_size
self.w2 = [random.gauss(0, 0.5) for _ in range(hidden_size)]
self.b2 = 0.0
def get_params(self):
params = []
for row in self.w1:
params.extend(row)
params.extend(self.b1)
params.extend(self.w2)
params.append(self.b2)
return params
def set_params(self, params):
idx = 0
for i in range(self.hidden_size):
for j in range(2):
self.w1[i][j] = params[idx]
idx += 1
for i in range(self.hidden_size):
self.b1[i] = params[idx]
idx += 1
for i in range(self.hidden_size):
self.w2[i] = params[idx]
idx += 1
self.b2 = params[idx]
def forward(self, x):
self.x = x
self.z1 = []
self.h = []
for i in range(self.hidden_size):
z = self.w1[i][0] * x[0] + self.w1[i][1] * x[1] + self.b1[i]
self.z1.append(z)
self.h.append(max(0.0, z))
self.z2 = sum(self.w2[i] * self.h[i] for i in range(self.hidden_size)) + self.b2
self.out = sigmoid(self.z2)
return self.out
def compute_grads(self, target):
eps = 1e-15
p = max(eps, min(1 - eps, self.out))
d_loss = -(target / p) + (1 - target) / (1 - p)
d_sigmoid = self.out * (1 - self.out)
d_out = d_loss * d_sigmoid
grads = [0.0] * (self.hidden_size * 2 + self.hidden_size + self.hidden_size + 1)
idx = 0
for i in range(self.hidden_size):
d_relu = 1.0 if self.z1[i] > 0 else 0.0
d_h = d_out * self.w2[i] * d_relu
grads[idx] = d_h * self.x[0]
grads[idx + 1] = d_h * self.x[1]
idx += 2
for i in range(self.hidden_size):
d_relu = 1.0 if self.z1[i] > 0 else 0.0
grads[idx] = d_out * self.w2[i] * d_relu
idx += 1
for i in range(self.hidden_size):
grads[idx] = d_out * self.h[i]
idx += 1
grads[idx] = d_out
return grads
def train(self, data, epochs=300):
losses = []
for epoch in range(epochs):
total_loss = 0.0
correct = 0
for x, y in data:
pred = self.forward(x)
grads = self.compute_grads(y)
params = self.get_params()
self.optimizer.step(params, grads)
self.set_params(params)
eps = 1e-15
p = max(eps, min(1 - eps, pred))
total_loss += -(y * math.log(p) + (1 - y) * math.log(1 - p))
if (pred >= 0.5) == (y >= 0.5):
correct += 1
avg_loss = total_loss / len(data)
accuracy = correct / len(data) * 100
losses.append((avg_loss, accuracy))
if epoch % 75 == 0 or epoch == epochs - 1:
print(f" Epoch {epoch:3d}: loss={avg_loss:.4f}, accuracy={accuracy:.1f}%")
return losses
پیادهسازی کاربردی با ابزارها
بهینهسازهای PyTorch وظیفهی گروهبندی پارامترها، برش گرادیان (gradient clipping) و برنامهریزی نرخ یادگیری را به خوبی بر دوش میکشند:
import torch
import torch.optim as optim
model = torch.nn.Sequential(
torch.nn.Linear(784, 256),
torch.nn.ReLU(),
torch.nn.Linear(256, 10),
)
optimizer = optim.AdamW(model.parameters(), lr=3e-4, weight_decay=0.01)
scheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=100)
for epoch in range(100):
optimizer.zero_grad()
output = model(torch.randn(32, 784))
loss = torch.nn.functional.cross_entropy(output, torch.randint(0, 10, (32,)))
loss.backward()
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
optimizer.step()
scheduler.step()
این الگو را همیشه به همین ترتیب به خاطر بسپارید: zero_grad، بعد forward، سپس loss، بعد backward، در صورت نیاز clip، بعد step و در آخر schedule. برهمزدن این توالی (مثل فراخوانی scheduler.step() قبل از optimizer.step()) یکی از رایجترین علتهای باگهای نامحسوس است.
در شبکههای CNN، هنوز هم مهندسان ترجیح میدهند از SGD همراه با تکانه (lr=0.1، momentum=0.9 و weight_decay=1e-4) با زمانبندی کسینوسی یا پلهای استفاده کنند؛ چون SGD نقاط کمینهی مسطحتری پیدا میکند که غالباً قابلیت تعمیم بهتری دارند. برای ترنسفورمرها و LLMها، AdamW در ترکیب با warmup و افت کسینوسی پیشفرض بلامنازع است؛ بدون داشتن دلایل تجربی دقیق برخلاف جریان عمل نکنید.
خروجی نهایی
در این درس به این فایل دست مییابید:
outputs/prompt-optimizer-selector.md-- یک پرامپت تصمیمگیری برای انتخاب بهینهساز و نرخ یادگیری متناسب با هر نوع معماری
تمرینها
-
تکانهی نستروف (Nesterov momentum) را پیادهسازی کنید؛ روشی که گرادیان را به جای موقعیت فعلی، در نقطهی آیندهنگر () محاسبه میکند. سرعت همگرایی آن را با تکانهی معمولی روی مجموعهدادهی دایره مقایسه کنید.
-
برنامهی زمانبندی نرخ یادگیری با دورهی گرمکردن (warmup) بسازید: افزایش خطی از 0 تا max_lr در 10% آغازین گامها و سپس افت کسینوسی تا 0. مدل را در دو حالت Adam با warmup و بدون آن آموزش دهید؛ سپس بشمارید رسیدن به دقت 90% روی دادههای دایره چند ایپاک زمان میبرد.
-
نرخ یادگیری مؤثر هر پارامتر را در طول آموزش با Adam ثبت کنید. فرمول این نرخ برابر است با . نمودار توزیع این مقادیر را بعد از 10، 50 و 200 گام رسم کنید. آیا تمام وزنها با سرعت یکسانی بهروزرسانی میشوند؟
-
برش گرادیان را بر اساس نُرم سراسری بنویسید و سقف آن را روی 1.0 تنظیم کنید. مدل را یک بار با برش گرادیان و یک بار بدون آن، با نرخ یادگیری بالا (lr=0.01 در Adam) آموزش دهید. بررسی کنید در 10 سید تصادفی، تابع زیان چند بار واگرا میشود (به NaN میرسد).
-
بهینهسازهای Adam و AdamW را روی شبکهای با وزنهای اولیه بزرگ بررسی کنید. تمام وزنها را در بازهی تصادفی [-5, 5] قرار دهید (خیلی بزرگتر از حد معمول). مدل را برای 200 ایپاک با weight_decay=0.1 آموزش دهید. نُرم L2 وزنها را حین آموزش برای هر دو روش رسم کنید؛ AdamW باید وزنها را با سرعت بیشتری مهار کند و کاهش دهد.
اصطلاحات کلیدی
| اصطلاح | در گفتگوها چه میگویند | مفهوم دقیق آن در عمل |
|---|---|---|
| Learning rate | «اندازهی گام» | ضریب عددی در بهروزرسانی گرادیان؛ تأثیرگذارترین هایپرپارامتر در روند آموزش |
| SGD | «گرادیان کاهشی مقدماتی» | گرادیان کاهشی تصادفی: اصلاح وزنها با کم کردن که روی یک دستهی کوچک محاسبه میشود |
| Momentum | «تشبیه توپ غلتان» | میانگین متحرک نمایی گرادیانهای پیشین؛ نوسانها را کم میکند و به مسیرهای یکنواخت سرعت میدهد |
| RMSProp | «نرخ یادگیری انطباقی» | گرادیان هر پارامتر را بر ریشهی میانگین مجذورات گرادیانهای اخیرش تقسیم میکند تا نرخها همتراز شوند |
| Adam | «بهینهساز پیشفرض» | ترکیب تکانه (گشتاور اول) و RMSProp (گشتاور دوم) همراه با تصحیح سوگیری در گامهای ابتدایی |
| AdamW | «نسخهی درست Adam» | مدل Adam با کاهش وزن تفکیکشده؛ جریمهی منظمسازی را مستقیم به وزنها میزند نه از طریق گرادیان |
| Bias correction | «گرمکردن میانگین متحرک» | تقسیم بر برای جبران مقداردهی اولیهی صفر در برآوردهای گشتاور در الگوریتم Adam |
| Weight decay | «کوچک کردن وزنها» | کسر کردن نسبتی از وزن در هر گام؛ سازوکاری برای جلوگیری از بیشازحد بزرگ شدن پارامترها |
| Learning rate schedule | «تغییر نرخ در طول زمان» | برنامهی زمانبندی نرخ یادگیری حین آموزش؛ الگوی warmup همراه با افت کسینوسی استاندارد مدرن است |
| Gradient clipping | «بستن سقف برای نُرم گرادیان» | مقیاسبندی و کوچک کردن بردار گرادیان در صورت عبور از یک آستانه؛ مانع از انفجار گرادیان میشود |
برای مطالعهی بیشتر
- مقالهی کینگما و با (Kingma & Ba) تحت عنوان "Adam: A Method for Stochastic Optimization" (سال 2014) -- مقالهی اصلی Adam همراه با تحلیل همگرایی و اثبات فرمول تصحیح سوگیری
- مقالهی لاشچیلُف و هوتر (Loshchilov & Hutter) با عنوان "Decoupled Weight Decay Regularization" (سال 2017) -- اثبات عدم همارزی منظمسازی L2 و کاهش وزن در Adam، و معرفی رسمی AdamW
- مقالهی اسمیت (Smith) به نام "Cyclical Learning Rates for Training Neural Networks" (سال 2017) -- معرفی تست بازهی نرخ یادگیری و زمانبندیهای چرخهای که وابستگی به تنظیم یک نرخ ثابت را برطرف میکنند
- مقالهی رودر (Ruder) تحت عنوان "An Overview of Gradient Descent Optimization Algorithms" (سال 2016) -- بهترین مقالهی مروری بر تمامی گونههای گرادیان کاهشی با تحلیلهای بصری و دقیق
