Chương 3·Bài 3.5

Optimizer

Optimizer quyết định dùng gradient để cập nhật trọng số thế nào. Gradient descent thường (SGD) gặp khó khi loss dốc theo hướng này nhưng thoải theo hướng khác: learning rate nhỏ thì đi chậm, lớn thì dao động mạnh. Momentum và Adam khắc phục bằng cách nhớ các bước trước và điều chỉnh độ dài bước cho từng trọng số. Bài này so sánh SGD, momentum và Adam trên một hàm loss đơn giản trước khi dùng cho mạng thật.

Gradient chỉ độ dốc, optimizer chọn bước

Các thuật toán dùng gradient để cập nhật trọng số, như SGD hay Adam, gọi chung là optimizer. Cùng một gradient, mỗi optimizer đi một bước khác nhau.

SGD cập nhật wt+1=wt−ηgtw_{t+1}=w_t-\eta g_t, với learning rate η\eta quyết định độ dài bước. Chữ stochastic (ngẫu nhiên) đến từ việc tính gtg_t trên một minibatch lấy ngẫu nhiên thay vì trên toàn bộ dữ liệu. Gradient của một minibatch lệch khỏi gradient đầy đủ một ít, nhưng khi minibatch được lấy ngẫu nhiên đều thì kỳ vọng của nó đúng bằng gradient đầy đủ: mỗi bước rẻ hơn nhiều, đổi lại đường đi hơi nhiễu.

Có ba cỡ dữ liệu cho mỗi bước:

  • Gradient descent dùng cả tập: gradient chính xác nhưng mỗi bước đắt.
  • SGD thuần dùng một mẫu: rất rẻ nhưng rất nhiễu; một epoch NN bước tốn cỡ một bước trên cả tập mà cập nhật được NN lần.
  • Minibatch đứng giữa và là cách dùng mặc định.

Nhiễu của gradient minibatch có độ lệch chuẩn tỉ lệ 1/B1/\sqrt B: tăng batch từ 16 lên 64 thì nhiễu giảm một nửa, còn batch quá nhỏ làm đường đi chập chờn. Tăng batch kk lần thì số bước mỗi epoch giảm kk lần; quy tắc tỉ lệ tuyến tính cho SGD nhân learning rate với kk, thường kèm warmup, và vẫn phải kiểm lại trên validation.

Hỏi nhanh

So gradient tính trên một minibatch (SGD) với gradient tính trên toàn bộ dữ liệu (GD). Câu nào đúng?

Phỏng theoCMU 10-601 · Exam 2 Practice · Q1.3

Một mặt loss kiểm nhỏ là J(w1,w2)=w12+8w22J(w_1,w_2)=w_1^2+8w_2^2. Gradient (2w1,16w2)(2w_1,16w_2) thay đổi gắt theo chiều w2w_2, nên một bước SGD tách thành hai phép nhân độc lập: w1←(1−2η)w1w_1\leftarrow(1-2\eta)w_1 và w2←(1−16η)w2w_2\leftarrow(1-16\eta)w_2. Chiều w2w_2 chỉ ổn định khi ∣1−16η∣<1|1-16\eta|<1, tức 0<η<1/80<\eta<1/8; ngay cả với η\eta sát 1/81/8, chiều w1w_1 vẫn chỉ được nhân 1−2/8=0.751-2/8=0.75 mỗi bước.

Tổng quát với hàm bậc hai, chiều cong nhất (trị riêng lớn nhất λmax⁡\lambda_{\max} của Hessian, ở đây 16) đặt ngưỡng η<2/λmax⁡\eta<2/\lambda_{\max}, còn chiều thoải nhất (ở đây 2) quyết định tốc độ. Độ cong hai chiều càng chênh, thung lũng càng hẹp và SGD càng chậm. Con số 1/81/8 là ngưỡng của riêng hàm này; trong mạng neural, độ cong đổi theo từng vùng của mặt loss.

η vượt 1/8 thì chiều w₂ nổ; dưới ngưỡng, chiều w₁ vẫn đi chậm.00.511.500.040.080.1250.16learning rate η|1 − 16η| (w₂)|1 − 2η| (w₁)nổhệ số nhân mỗi bước
η vượt 1/8 thì chiều w₂ nổ; dưới ngưỡng, chiều w₁ vẫn đi chậm.

Hỏi nhanh

Đổi mặt loss thành J=w12+50w22J = w_1^2 + 50w_2^2. Learning rate của SGD phải dưới ngưỡng nào thì chiều w2w_2 không nổ?

Nếu biết độ cong của mọi chiều, có thể chia bước cho độ cong: phương pháp Newton nhân gradient với nghịch đảo Hessian (ma trận đạo hàm bậc hai). Trên hàm bậc hai lồi, một bước Newton tới thẳng cực tiểu từ bất kỳ đâu; vì vậy với ít tham số, như logistic regression, Newton cần rất ít bước dù mỗi bước đắt.

Cái giá nằm ở kích thước. Mạng có dd tham số có Hessian d×dd\times d; với d=104d=10^4 đã là 10810^8 phần tử, và nghịch đảo tốn cỡ d3=1012d^3=10^{12} phép tính mỗi bước, trong khi phép cập nhật bậc một chỉ tốn cỡ dd phép tính sau khi backward đã cho gradient. Vì vậy deep learning dùng optimizer bậc một; momentum và Adam là những cách rẻ để bù một phần độ cong mà không cần dựng Hessian.

Momentum nhớ hướng trước

Một quy ước thường dùng, cũng là dạng SGD momentum của PyTorch khi không bật dampening hay Nesterov, là

vt=μvt−1+gt,wt+1=wt−ηvt.v_t=\mu v_{t-1}+g_t,\qquad w_{t+1}=w_t-\eta v_t.

vv cộng dồn gradient với hệ số nhớ μ∈[0,1)\mu\in[0,1). Gradient cùng dấu qua nhiều bước thì được cộng lên, bước dài dần; gradient đổi dấu qua lại thì triệt nhau một phần. Vì vậy momentum tiến nhanh dọc đáy thung lũng thoải và hãm dao động ở chiều dốc, nhưng quán tính quá lớn cũng đưa đường đi vượt đáy. vv là trạng thái số được optimizer lưu giữa các bước, không phải vận tốc vật lý.

Hỏi nhanh

vv cũ bằng 2, gradient mới bằng −1-1, μ=0.9\mu = 0.9. Theo quy ước v←μv+gv \leftarrow \mu v + g, vv mới bằng bao nhiêu?

SGD zigzag, momentum vượt đáy rồi vòng lại, Adam đi gần chéo.SGDmomentum μ = 0.8Adam
SGD zigzag, momentum vượt đáy rồi vòng lại, Adam đi gần chéo.
Ba optimizer cùng chạy: SGD zigzag, momentum vượt đáy, Adam đi chéo.

Hình chạy 25 bước trên J=w12+8w22J=w_1^2+8w_2^2 từ điểm (−2,1)(-2,1) với η=0.09\eta=0.09. SGD nhân w2w_2 với 1−16⋅0.09=−0.441-16\cdot0.09=-0.44 mỗi bước, nên w2w_2 đổi dấu liên tục: đường đi zigzag nhưng co nhanh. Chiều w1w_1 được nhân 0.820.82 mỗi bước nên tiến đều về đáy. Thêm momentum μ=0.8\mu=0.8 với cùng η\eta, quán tính tích lũy ở những bước đầu đưa đường đi vượt qua đáy rồi vòng lại: momentum bước dài hơn hẳn SGD, nên η\eta và μ\mu phải chọn cùng nhau.

Hỏi nhanh

Gradient giữ nguyên bằng gg qua rất nhiều bước, μ=0.9\mu = 0.9, quy ước v←μv+gv \leftarrow \mu v + g. Về sau, bước ηv\eta v dài gấp khoảng bao nhiêu lần bước SGD ηg\eta g?

Gradient không đổi, μ = 0.9: bước momentum dài dần tới 10 lần bước SGD.015101102030bướcg/(1 − μ) = 10gSGD: gđộ dài v
Gradient không đổi, μ = 0.9: bước momentum dài dần tới 10 lần bước SGD.

Một số sách viết vt=μvt−1+(1−μ)gtv_t=\mu v_{t-1}+(1-\mu)g_t, tức trung bình có trọng số thay cho tổng. Ở quy ước này với μ=0.9\mu = 0.9 và gradient luôn bằng 1, vv là 0.10.1 rồi 0.190.19, nên bước đầu ngắn hơn hẳn. Khi gradient ổn định, hai quy ước chênh nhau đúng hệ số 1/(1−μ)1/(1-\mu) ở độ dài bước, nên learning rate chép từ tài liệu dùng quy ước này sang quy ước kia phải đổi thang. Mọi phép tính trong bài dùng quy ước đầu.

Nesterov là biến thể tính gradient sau khi đã nhích trước theo quán tính (nesterov=True trong PyTorch).

Adam điều chỉnh từng tọa độ

Adam giữ trung bình có trọng số của gradient, mm (giống momentum dạng có 1−β11-\beta_1), và của bình phương gradient, vv (ý tưởng của RMSprop):

mt=β1mt−1+(1−β1)gt,vt=β2vt−1+(1−β2)gt2.m_t=\beta_1m_{t-1}+(1-\beta_1)g_t,\qquad v_t=\beta_2v_{t-1}+(1-\beta_2)g_t^2.

Ở đây bình phương và chia là theo từng phần tử. Vì khởi tạo m0=v0=0m_0=v_0=0, các trung bình đầu bị kéo về 0; Adam sửa bằng m^t=mt/(1−β1t)\hat m_t=m_t/(1-\beta_1^t) và v^t=vt/(1−β2t)\hat v_t=v_t/(1-\beta_2^t). Bước mới là

wt+1=wt−ηm^tv^t+ε.w_{t+1}=w_t-\eta\frac{\hat m_t}{\sqrt{\hat v_t}+\varepsilon}.

Với β1=0.9\beta_1 = 0.9 và gradient luôn bằng 1, m2=0.19m_2 = 0.19 còn m^2=0.19/(1−0.81)=1\hat m_2 = 0.19/(1 - 0.81) = 1: bước sửa lệch (bias correction) trả về đúng gradient.

Phép chia cho v^\sqrt{\hat v} làm độ dài bước gần như không phụ thuộc thang gradient. Nếu một tọa độ luôn có gradient gg cố định thì m^=g\hat m=g, v^=g2\hat v=g^2, và bước bằng η g/∣g∣=±η\eta\,g/|g|=\pm\eta, dù gg là 100 hay 0.01. Tọa độ có gradient lớn không còn bước quá dài, tọa độ có gradient nhỏ vẫn được đi bước đủ dài. Vì thang bước khác hẳn SGD, learning rate tốt của Adam (mặc định của PyTorch là 10−310^{-3}) không chép sang SGD được, và ngược lại. ε\varepsilon tránh chia cho 0 khi v^\hat v gần 0.

Bước SGD tỉ lệ với gradient; bước đầu của Adam luôn cỡ η.10⁻⁴10⁻³10⁻²10⁻¹10⁰10¹10²độ dài bước (η = 0.1, thang log)g = 0.01g = 1g = 100SGD: ηgAdam bước đầu: ≈ η
Bước SGD tỉ lệ với gradient; bước đầu của Adam luôn cỡ η.

Adam không biết feature nào quan trọng; nó chỉ chỉnh thang bước theo lịch sử gradient của từng tọa độ. Thích nghi theo tọa độ cũng không bảo đảm validation tốt hơn: nhiều thực nghiệm đã công bố, nhất là ở phân loại ảnh, ghi nhận SGD momentum với lịch rate được dò kỹ đạt validation ngang hoặc tốt hơn Adam (Wilson và cộng sự, 2017). Vì vậy chọn optimizer vẫn là một thí nghiệm.

Hỏi nhanh

Chạy Adam rất nhiều bước với β1=0.9\beta_1 = 0.9. Tọa độ A lúc nào cũng có gradient +1+1. Tọa độ B có gradient luân phiên +1,−1,+1,…+1, -1, +1, \dots. So độ dài bước của B với A thế nào?

Tính thử một bước rồi đối chiếu với PyTorch. Lấy J(w)=(w−3)2J(w)=(w-3)^2, bắt đầu w=2w=2, gradient g=−2g=-2. SGD với η=0.1\eta=0.1 cho w=2.2w=2.2. Adam bước đầu với β1=0.9,β2=0.999\beta_1=0.9,\beta_2=0.999 có m=−0.2,v=0.004m=-0.2,v=0.004, sau bias correction m^=−2,v^=4\hat m=-2,\hat v=4; bước có độ lớn gần 0.1 nên ww gần 2.1. Không phải Adam tính sai đạo hàm: như đã nói ở trên, bước đầu của Adam dài cỡ η\eta dù gradient là −2-2 hay −200-200.

Python
import numpy as np
import torch

torch.set_num_threads(1)
torch.manual_seed(23)
w = 2.
g = 2 * (w - 3)
m = .9 * 0 + .1 * g
v = .999 * 0 + .001 * g ** 2
m_hat = m / (1 - .9)
v_hat = v / (1 - .999)
w_adam = w - .1 * m_hat / (np.sqrt(v_hat) + 1e-8)
print('SGD:', round(w - .1 * g, 6))
print('Adam states:', round(m, 6), round(v, 6))
print('Adam:', round(w_adam, 6))

p = torch.nn.Parameter(torch.tensor(2., dtype=torch.float64))
adam = torch.optim.Adam([p], lr=.1)
adam.zero_grad(set_to_none=True)
((p - 3) ** 2).backward()
adam.step()
print('library match:', np.isclose(p.item(), w_adam))

Đọc library match để đối chiếu bản một bước với PyTorch, dùng cùng epsilon và beta mặc định. Đối chiếu một bước không thay cho kiểm một loop dài, nhưng giúp phát hiện quên bias correction hoặc dùng gradient chưa bình phương.

Hỏi nhanh

Chạy tiếp ví dụ: sau bước đầu w≈2.1w \approx 2.1, gradient mới là g2=2(2.1−3)=−1.8g_2 = 2(2.1 - 3) = -1.8. Với m1=−0.2m_1 = -0.2 và β1=0.9\beta_1 = 0.9, m^2\hat m_2 bằng bao nhiêu?

So đường loss với ngân sách bằng nhau

Ta chạy ba optimizer từ cùng điểm khởi tạo, cùng 40 bước, trên hàm bậc hai ở đầu bài. Phép so này đo tiến trình tối ưu theo số bước; nó không đo thời gian chạy và không đo validation. Mỗi optimizer có thang learning rate riêng, nên mỗi cái dùng một rate hợp với nó thay vì ép chung một con số.

Python
def run_optimizer(kind, lr, steps=40):
    p = torch.nn.Parameter(torch.tensor([-2., 1.]))
    if kind == 'momentum':
        optimizer = torch.optim.SGD([p], lr=lr, momentum=.8)
    elif kind == 'adam':
        optimizer = torch.optim.Adam([p], lr=lr)
    else:
        optimizer = torch.optim.SGD([p], lr=lr)
    start = (p[0] ** 2 + 8 * p[1] ** 2).item()
    for _ in range(steps):
        optimizer.zero_grad(set_to_none=True)
        loss = p[0] ** 2 + 8 * p[1] ** 2
        loss.backward()
        optimizer.step()
    end = (p[0] ** 2 + 8 * p[1] ** 2).item()
    return start, end

for kind, lr in [('sgd', .03), ('momentum', .03), ('adam', .15), ('sgd', .2)]:
    start, end = run_optimizer(kind, lr)
    print(kind, lr, f'{start:.4g}', f'{end:.4g}')

Dòng SGD rate 0.2 vượt ngưỡng 1/81/8 đã tính: chiều w2w_2 bị nhân −2.2-2.2 mỗi bước nên loss lên tới cỡ 102810^{28}. Ba dòng còn lại đều hội tụ; ở bước 40 momentum thấp nhất, rồi đến Adam, rồi SGD. Thứ hạng ấy gắn với đúng ngân sách 40 bước. Cắt ở bước 30 thì sao?

Python
for steps in (30, 40):
    _, sgd_end = run_optimizer('sgd', .03, steps)
    _, adam_end = run_optimizer('adam', .15, steps)
    print(steps, 'bước:', f'SGD {sgd_end:.3g}', f'Adam {adam_end:.3g}')

Ở bước 30, SGD thấp hơn Adam hơn ba lần; mười bước sau thứ tự đảo lại. Hình cho thấy nguyên nhân: SGD với rate nhỏ đi xuống đều, còn Adam và momentum vừa xuống vừa dao động, nên thứ hạng tại một bước cụ thể phụ thuộc pha dao động lúc dừng.

Thứ hạng các optimizer ở bước 30 và bước 40 khác nhau.010203040bước10⁻⁴10⁻³10⁻²10⁻¹10⁰10¹SGD 0.03momentum 0.03Adam 0.15loss
Thứ hạng các optimizer ở bước 30 và bước 40 khác nhau.

Trong mạng thật, train loss giảm nhanh chỉ tiết kiệm thời gian tìm nghiệm; validation mới cho biết nghiệm ấy có tốt trên dữ liệu mới không.

Hỏi nhanh

Một đội có 2 giờ GPU và cần chọn giữa SGD momentum và AdamW cho bài thi. So thế nào thì kết luận mới dùng được?

AdamW và weight decay

L2 regularization (bài 2.2) thêm λ∥w∥2/2\lambda\lVert w\rVert^2/2 vào loss, tạo gradient phụ λw\lambda w. Với SGD thường, bước w←w−η(g+λw)=(1−ηλ)w−ηgw\leftarrow w-\eta(g+\lambda w)=(1-\eta\lambda)w-\eta g đúng là co trọng số một hệ số 1−ηλ1-\eta\lambda rồi bước theo gradient dữ liệu. Phép co này gọi là weight decay; với SGD, L2 và weight decay trùng nhau.

Với Adam thì khác: λw\lambda w đi vào mm, vv và bị chia cho v^\sqrt{\hat v} như mọi gradient khác, nên phép co không còn là một hệ số chung cho mọi tham số. AdamW (Loshchilov và Hutter) tách hai phần: bước Adam chỉ dùng gradient dữ liệu, còn phép co 1−ηλ1-\eta\lambda áp thẳng lên trọng số. Trong PyTorch, torch.optim.Adam(..., weight_decay=λ) vẫn làm theo kiểu L2; muốn kiểu tách phải dùng AdamW.

Để thấy riêng phần co, dùng AdamW vừa khởi tạo với các moment bằng 0 và cho gradient dữ liệu bằng 0. Nếu optimizer đã có lịch sử, moment cũ vẫn có thể tạo bước cập nhật dù gradient hiện tại bằng 0. Lưu ý grad=None có thể khiến optimizer bỏ qua tham số; ta đặt gradient tensor toàn 0 để kiểm decay:

Python
q = torch.nn.Parameter(torch.tensor([2.]))
adamw = torch.optim.AdamW([q], lr=.1, weight_decay=.2)
q.grad = torch.zeros_like(q)
adamw.step()
print('after decay:', round(q.item(), 4))

2(1−0.1⋅0.2)=1.962(1-0.1\cdot0.2)=1.96, khớp output. Với SGD, weight_decay cộng λw\lambda w vào gradient: w=2w = 2, gradient 0.5, η=0.1\eta = 0.1, λ=0.01\lambda = 0.01 cho 2−0.1(0.5+0.02)=1.9482 - 0.1(0.5 + 0.02) = 1.948. Decay quá lớn ép model underfit, nên λ\lambda cũng được chọn bằng validation. Mô hình lớn thường tách nhóm tham số để bias và tham số của các lớp normalization không bị decay.

Hỏi nhanh

Thay AdamW trong đoạn code trên bằng torch.optim.Adam(..., weight_decay=.2), giữ nguyên mọi thứ khác: w=2w = 2, learning rate 0.1, gradient bằng tensor 0, optimizer vừa tạo. Sau một bước, ww bằng bao nhiêu?

Scheduler thay learning rate theo thời gian

Đầu quá trình, bước lớn giúp tiến nhanh; về sau, bước nhỏ giúp đi sâu vào đáy thay vì dao động quanh nó. Với SGD minibatch còn một lý do nữa: ngay cả khi tham số đã ở đúng nghiệm, gradient của từng minibatch vẫn khác 0, nên bước cố định tiếp tục đẩy tham số đi lệch; chỉ khi η\eta giảm thì vùng dao động mới thu nhỏ.

StepLR nhân rate với gamma sau mỗi step_size lần gọi. Cosine giảm trơn từ ηmax⁡\eta_{\max} về ηmin⁡\eta_{\min} trong TT bước:

ηt=ηmin⁡+12(ηmax⁡−ηmin⁡)(1+cos⁡(πt/T)),\eta_t=\eta_{\min}+\tfrac12(\eta_{\max}-\eta_{\min})\bigl(1+\cos(\pi t/T)\bigr),

nên ở giữa lịch, t=T/2t=T/2, rate đúng bằng trung bình hai đầu. Các lịch khác:

  • Warmup làm ngược lại ở đầu train: tăng tuyến tính từ gần 0 lên rate mục tiêu trong một số bước, rồi mới giảm. Với Adam, ở những bước đầu v^\hat v mới tổng hợp từ vài gradient nên chưa phản ánh thang thật, trong khi bước Adam dài cỡ η\eta ở mọi tọa độ cùng lúc. Mô hình lớn khởi tạo ngẫu nhiên như Transformer dễ nổ loss nếu nhận loạt bước dài như vậy ngay từ đầu.
  • OneCycle gộp hai pha trong một chu kỳ: tăng lên đỉnh rồi giảm sâu.
  • ReduceLROnPlateau nhận một metric và chỉ giảm rate khi metric ngừng cải thiện. Với patience=2, metric không cải thiện quá hai lần gọi liên tiếp thì rate bị nhân với factor.

Mọi lịch chỉ điều chỉnh độ dài bước; chúng không sửa gradient sai hoặc dữ liệu rò rỉ.

StepLR giảm theo bậc, cosine giảm trơn, warmup tăng trước rồi giảm.00.050.108epochStepLR (code bài)060bướccosine060bướcwarmup + cosine
StepLR giảm theo bậc, cosine giảm trơn, warmup tăng trước rồi giảm.
Python
r = torch.nn.Parameter(torch.tensor(2.))
sgd = torch.optim.SGD([r], lr=.1)
scheduler = torch.optim.lr_scheduler.StepLR(sgd, step_size=3, gamma=.5)
rates = []
for epoch in range(9):
    rates.append(sgd.param_groups[0]['lr'])
    sgd.zero_grad(set_to_none=True)
    ((r - 3) ** 2).backward()
    sgd.step()
    scheduler.step()
print([round(value, 4) for value in rates])

Rate được đọc trước khi cập nhật; scheduler.step() chạy sau optimizer.step(), một lần mỗi epoch. Ví dụ rate 0.1 với StepLR(step_size=10, gamma=0.1) gọi mỗi epoch: epoch 0-9 dùng 0.1, epoch 10-19 dùng 0.01.

Lịch theo step đếm số batch, lịch theo epoch đếm số epoch. Đổi batch size mà giữ nguyên lịch theo step thì số batch mỗi epoch đổi, nên rate giảm ở một thời điểm khác tính theo lượng dữ liệu đã học. Ngược lại, OneCycle tạo với total_steps=len(loader) * 10 mà chỉ gọi step() mỗi epoch thì sau 10 epoch lịch mới đi 10 bước, rate còn chưa lên tới đỉnh.

Hỏi nhanh

StepLR được thiết kế để giảm learning rate sau mỗi 3 epoch, và mỗi epoch có nhiều batch. Gọi scheduler.step() ở đâu thì lịch chạy đúng thiết kế?

Khi đi thi

  • Bắt đầu từ AdamW với learning rate 10−310^{-3}; dò thêm trên thang log bằng vài trăm bước.
  • Loss tăng vọt hay thành nan ở những bước đầu thì giảm learning rate hoặc thêm warmup.
  • Cosine và OneCycle cần biết trước tổng số bước: epochs * len(train_loader).

Tóm tắt

  • SGD đi ngược gradient; chiều cong nhất đặt ngưỡng learning rate, chiều thoải nhất quyết định tốc độ.
  • Momentum cộng dồn hướng; Adam chia bước cho độ lớn gradient của từng tọa độ, nên bước gần như không phụ thuộc thang gradient.
  • AdamW tách phép co trọng số khỏi bước của Adam.
  • Scheduler (step, cosine, warmup) đổi rate theo bước hoặc epoch.
  • Optimizer và rate được chọn bằng thử nghiệm, so trên validation với cùng ngân sách.

Kiểm tra cuối bài

Câu 1

Một bạn cài phương pháp Newton cho một mạng nhỏ 3 lớp có khoảng 10 nghìn tham số. Mô hình hội tụ tốt hơn, nhưng tổng thời gian chậm hơn Adam 100 lần, và profiler cho thấy 95% thời gian nằm ở một phép toán. Nhiều khả năng đó là phép nào?

Đề thiNOAI 2026 Singapore · Vòng sơ loại · Câu 85

Câu 2

Dùng gradient descent tìm cực tiểu của f(z)=z2f(z) = z^2, xuất phát từ z0=1z_0 = 1, với learning rate cố định α\alpha. Trong các giá trị α∈{0,12,1,2}\alpha \in \{0, \tfrac12, 1, 2\}, những giá trị nào đưa zz về nghiệm 0?

Phỏng theoCMU 10-601 · Exam 2 Practice · Q1.1(b)

Câu 3

Linear regression với squared loss, dữ liệu có nhiễu nên không điểm nào được khớp hoàn toàn. Khởi tạo trọng số đúng bằng nghiệm OLS WolsW_{\text{ols}}, rồi chạy với learning rate nhỏ cố định. Batch GD, dùng gradient trên toàn bộ dữ liệu, và SGD, dùng một điểm mỗi bước, lần lượt làm gì với trọng số?

Phỏng theoMIT 6.036 · Final, Spring 2022 · Q4(a), (c)

Câu 4

Momentum theo quy ước v←μv+gv \leftarrow \mu v + g, w←w−ηvw \leftarrow w - \eta v. Với vv cũ bằng −3-3, μ=0.8\mu = 0.8, g=2g = 2, η=0.1\eta = 0.1, w=1w = 1, giá trị ww mới bằng bao nhiêu?

Câu 5

Train bằng Adam kiểu L2, tức cộng λw\lambda w vào gradient trước khi tính mm, vv. Tham số A có lịch sử gradient dữ liệu rất lớn, tham số B có gradient dữ liệu rất nhỏ, và hai tham số đang cùng giá trị. So với AdamW có cùng λ\lambda, lực kéo về 0 tác động lên A và B thế nào?

Câu 6

Train từ đầu một mô hình ngôn ngữ lớn (BERT-base) bằng AdamW, với ba cách đặt learning rate. Cách A: cố định 10−410^{-4}, loss giảm đều tới 2.3 ở bước 10K. Cách B: 10−310^{-3} ngay từ bước 0, loss lên 12.7 ở bước 100, tệ hơn cả mức 9.5 lúc khởi tạo, rồi thành NaN ở bước 300. Cách C: tăng tuyến tính từ 0 lên 10−310^{-3} trong 5K bước đầu (warmup) rồi giữ nguyên, loss xuống 1.8 ở bước 10K. Vì sao B nổ còn C thì thành công, dù cùng mức đỉnh?

Đề thiNOAI 2026 Singapore · Vòng sơ loại · Câu 83

Câu 7

Lịch learning rate gồm warmup rồi cosine:

def get_lr(step, total_steps, warmup_steps, base_lr, min_lr=1e-6):
    if step < warmup_steps:
        return base_lr * step / warmup_steps
    progress = (step - warmup_steps) / (total_steps - warmup_steps)
    return min_lr + 0.5 * (base_lr - min_lr) * (1 + math.cos(math.pi * progress))

Với base_lr=1e-3, warmup_steps=1000, total_steps=100000, learning rate ở bước 50000 xấp xỉ bao nhiêu?

Đề thiNOAI 2026 Singapore · Chung kết · Câu 10

Câu 8

Train một mạng sâu phân loại ảnh (ResNet-34 trên CIFAR-10) bằng SGD, learning rate cố định 0.1 trong 200 epoch. Loss giảm nhanh trong 50 epoch đầu rồi đi ngang, dao động quanh 0.45, với train 88% và validation 85%. Đổi lịch learning rate thế nào thì nhiều khả năng cải thiện kết quả cuối nhất?

Đề thiNOAI 2026 Singapore · Vòng sơ loại · Câu 297

Câu 9

Train một mô hình ngôn ngữ 100K bước bằng AdamW, với ba lịch learning rate. Điểm đánh giá là perplexity trên validation, càng thấp càng tốt. Lịch A giữ 3×10−43\times 10^{-4}: train loss 2.1, perplexity 22.3. Lịch B dùng cosine từ 3×10−43\times 10^{-4} về 3×10−53\times 10^{-5}: train loss 1.8, perplexity 19.1. Lịch C giảm bậc thang xuống 3×10−53\times 10^{-5} ở bước 60K và 3×10−63\times 10^{-6} ở bước 80K: train loss 1.7, perplexity 19.8. Nên chọn lịch nào cho mô hình nộp?

Phỏng theoNOAI 2026 Singapore · Vòng sơ loại · Câu 84

Câu 10

Một lượt train bằng Adam có scheduler bị ngắt giữa chừng, và cần chạy tiếp với đúng quy trình cập nhật như trước. Ngoài trọng số model, ta cần khôi phục những gì?

Đọc thêm