Huấn luyện, vẽ biểu đồ và đánh giá kết quả đồ án
Ở bài trước, bạn đã có vòng lặp REINFORCE (REINFORCE loop) hoàn chỉnh cùng baseline (baseline) và advantage (advantage). Giờ là lúc chạy nó đủ lâu, ghi lại số liệu, vẽ biểu đồ và trả lời câu hỏi quan trọng nhất của đồ án: policy của mình có thực sự học được không?
Một lần chạy ra con số đẹp chưa nói lên điều gì. Kỹ năng của bài này là biến một lần chạy may mắn thành một bằng chứng (evidence) đáng tin: nhiều seed (seed), đường cong có làm mượt, và một quy trình đánh giá (evaluation) tách biệt với lúc huấn luyện.
Mục tiêu của chặng cuối: từ "chạy được" sang "chứng minh được"
Đồ án của bạn cần trả lời được ba câu:
- Phần thưởng (return) có tăng theo thời gian huấn luyện không?
- Kết quả đó có ổn định khi đổi seed không, hay chỉ là may mắn?
- Policy sau khi huấn luyện hành xử ra sao khi ta đánh giá nó một cách nghiêm túc?
Trả lời được ba câu này là bạn có một đồ án hoàn chỉnh, không chỉ là một đoạn code.
Yêu cầu kỹ thuật: đồ án phải xuất ra những gì
flowchart TD
Train["🔁<br/>Huấn luyện"] --> Log["📝<br/>Ghi log"]
Log --> Smooth["📉<br/>Làm mượt"]
Smooth --> Plot["📊<br/>Vẽ biểu đồ"]
Plot --> Eval["🧪<br/>Đánh giá"]
Eval --> Report["📄<br/>Kết luận đồ án"]
Cụ thể, chương trình của bạn cần:
- Ghi log (logging) mỗi episode:
episode,return,seed, và nếu có thìentropy,loss. - Đánh giá định kỳ (periodic evaluation): cứ mỗi N episode, chạy policy trên môi trường ở chế độ đánh giá và ghi riêng
eval_return. Đừng trộn số liệu đánh giá vào đường cong huấn luyện. - Làm mượt (smoothing): đường cong thô rất nhiễu, hãy vẽ thêm trung bình trượt (moving average) trên cửa sổ $W$ episode:
$$ \bar{R}t = \frac{1}{W}\sum{i=0}^{W-1} R_{t-i} $$
- Nhiều seed: chạy ít nhất 3 seed, báo cáo trung bình cộng với dải độ lệch chuẩn (standard deviation band).
- Hình ảnh: lưu
reward_curve.pngvà đưa vào báo cáo đồ án.
Đoạn code vẽ đường cong tối giản:
import numpy as np
import matplotlib.pyplot as plt
def moving_average(x, w=20):
if len(x) < w:
return np.asarray(x, dtype=float)
return np.convolve(x, np.ones(w) / w, mode="valid")
plt.figure(figsize=(7, 4))
for seed, rets in runs.items(): # runs: {seed: [return, ...]}
smooth = moving_average(rets, w=20)
plt.plot(np.arange(len(smooth)) + 19, smooth, label=f"seed {seed}")
plt.xlabel("Episode")
plt.ylabel("Return (moving average, W=20)")
plt.legend()
plt.tight_layout()
plt.savefig("reward_curve.png", dpi=150)
Tip: Hãy chọn $W$ khoảng 20 đến 50 episode cho CartPole. $W$ quá nhỏ thì đường vẫn nhiễu, $W$ quá lớn thì bạn khó thấy lúc policy bắt đầu học.
Bài tập nhanh 1
Đường cong của bạn phẳng ở mức khoảng 10 phần thưởng suốt 500 episode. Bạn kiểm tra gì trước tiên?
Xem gợi ý
Kiểm tra ba thứ theo thứ tự: (1) log-prob và dấu của loss, vì một lỗi dấu làm gradient đi ngược; (2) chuẩn hóa return hoặc advantage, vì advantage quá lớn gây bước cập nhật bùng nổ; (3) learning rate, vì quá nhỏ thì policy gần như không dịch chuyển. Chỉ sau khi loại ba nguyên nhân này mới nên nghĩ đến việc tăng số episode.
Lộ trình làm việc: từ một lần chạy đến bằng chứng
- Chạy một seed với 500 episode, in return trung bình mỗi 50 episode ra màn hình để chắc chắn con số di chuyển.
- Ghi log ra file CSV (hoặc list trong bộ nhớ) gồm episode, return, seed, eval_return.
- Thêm hàm moving_average và vẽ đường cong thô cùng đường làm mượt trên cùng một hình.
- Bọc vòng huấn luyện trong một hàm nhận seed, rồi lặp qua 3 seed.
- Vẽ cả ba seed lên cùng một biểu đồ, thêm dải mean cộng trừ std.
- Viết phần đánh giá cuối: chạy policy đã huấn luyện 100 episode, tính tỉ lệ thành công (success rate).
- Ghi lại kết luận vào README của đồ án: cấu hình, seed, hình, và nhận xét.
Mẹo thực dụng: hãy log cả entropy của policy. Nếu entropy lao về 0 chỉ sau vài chục episode, policy của bạn đã sụp đổ entropy (entropy collapse): nó kẹt ở gần như một hành động duy nhất và gần như không còn học được nữa.
Đánh giá: đừng để policy "học thuộc" lúc huấn luyện
Khi huấn luyện, policy lấy mẫu (sample) hành động theo xác suất. Khi đánh giá, ta thường chọn hành động có xác suất cao nhất (greedy/argmax) để loại bỏ yếu tố may rủi. Cả hai đều hợp lệ, nhưng phải nói rõ bạn dùng cách nào trong báo cáo.
Ba chỉ số nên có trong phần đánh giá:
| Chỉ số | Ý nghĩa | Ghi chú |
|---|---|---|
eval_return trung bình |
Chất lượng policy sau huấn luyện | Chạy ít nhất 100 episode |
| Độ lệch chuẩn qua seed | Độ ổn định của thuật toán | Càng nhỏ càng đáng tin |
success_rate |
Tỉ lệ episode đạt ngưỡng bạn đặt | Ví dụ return ≥ 475 với CartPole |
Dấu hiệu học thành công rất dễ nhận ra: đường cong phần thưởng có xu hướng đi lên và ổn định qua nhiều seed. Ngược lại, đường cong nhảy loạn không có xu hướng, hoặc tăng ở train nhưng eval_return đứng yên, là tín hiệu cần xem lại.
Một lưu ý về môi trường có tính ngẫu nhiên (stochasticity): kể cả policy hoàn hảo cũng có episode xấu. Vì vậy hãy so sánh phân bố phần thưởng, đừng so sánh một episode đơn lẻ.
Bài tập nhanh 2
Ba seed cho kết quả cuối lần lượt là 480, 200 và 460. Bạn kết luận gì và làm gì tiếp?
Xem gợi ý
Kết quả chưa ổn định: seed 200 cho thấy thuật toán rất nhạy với khởi tạo. Đừng che nó đi bằng cách báo cáo "seed tốt nhất". Hãy báo cáo trung bình kèm độ lệch chuẩn, chạy thêm 2 đến 3 seed, và thử giảm learning rate hoặc tăng số episode để xem seed xấu có cứu được không. Nếu seed xấu vẫn hỏng, ghi nhận đó là một phát hiện trung thực của đồ án.
Tiêu chí nghiệm thu: khi nào được coi là xong
Đồ án đạt yêu cầu khi:
- Có ít nhất 3 seed, mỗi seed có log đầy đủ và một đường cong riêng.
- Biểu đồ có trục có nhãn, có chú giải, có cả đường thô và đường làm mượt.
- Có phần đánh giá độc lập với huấn luyện, kèm con số cụ thể (return trung bình, success rate).
- README mô tả được: cấu hình, số seed, hình, và một kết luận ngắn.
- Bạn giải thích được vì sao dùng baseline và advantage, dựa trên hai đường cong có và không có baseline.
Gỡ lỗi và những cái bẫy thường gặp
- Trộn train và eval: đường cong đẹp bất thường thường là do vô tình log episode đánh giá vào cùng danh sách.
- Chỉ chạy một seed: kết quả tốt có thể là may mắn, và bạn không có cách nào biết.
- Làm mượt quá tay: cửa sổ quá lớn che mất giai đoạn policy bắt đầu học, đúng phần thú vị nhất của biểu đồ.
- Không đặt ngưỡng thành công: không có ngưỡng thì "tốt" chỉ là cảm giác.
- Bỏ qua thời gian chạy: ghi lại thời gian mỗi lần huấn luyện giúp bạn biết thay đổi nào là khả thi.
- Xóa seed xấu: đây là lỗi nghiêm trọng nhất về mặt trung thực khoa học.
Warning: Nếu
eval_returncao hơn hẳnreturnlúc huấn luyện, hãy kiểm tra lại: rất có thể policy đánh giá đang chọn hành động tất định trong khi môi trường huấn luyện có nhiễu mạnh. Chênh lệch này là bình thường ở mức nhỏ, nhưng chênh lớn là dấu hiệu bạn đang so sánh hai thứ khác nhau.
Chốt lại đồ án của bạn
Bạn đã đi hết một vòng: viết vòng lặp REINFORCE, thêm baseline và advantage, rồi huấn luyện nhiều seed, vẽ đường cong phần thưởng có làm mượt, và đánh giá policy một cách tách biệt. Đầu ra cuối cùng không phải một con số, mà là một bộ bằng chứng nhỏ gọn: biểu đồ, bảng chỉ số, và vài câu kết luận trung thực về điểm mạnh lẫn điểm yếu của thuật toán.
Bài tiếp theo là checkpoint: bạn sẽ tự kiểm tra lại toàn bộ cài đặt REINFORCE và phần giảm variance, với các câu hỏi bám sát chính đồ án bạn vừa hoàn thành.
Ôn nhanh bằng thẻ ghi nhớ
Front: Vì sao phải vẽ trung bình trượt thay vì chỉ đường cong thô? Back: Đường thô rất nhiễu; trung bình trượt làm lộ xu hướng học.
Front: Cửa sổ làm mượt W nên chọn thế nào? Back: Khoảng 20 đến 50 episode với CartPole; quá nhỏ còn nhiễu, quá lớn che mất giai đoạn học.
Front: Vì sao cần chạy nhiều seed? Back: Để tách tín hiệu học thật khỏi may mắn do khởi tạo ngẫu nhiên.
Front: Nên báo cáo kết quả qua nhiều seed như thế nào? Back: Trung bình cộng với dải độ lệch chuẩn, không phải seed tốt nhất.
Front: eval_return khác return ở chỗ nào? Back: return là lúc huấn luyện (có lấy mẫu), eval_return là lúc đánh giá riêng policy.
Front: Khi đánh giá nên chọn hành động thế nào? Back: Thường dùng greedy/argmax để bỏ yếu tố may rủi, và nói rõ trong báo cáo.
Front: Sụp đổ entropy (entropy collapse) là gì? Back: Policy gần như chỉ còn một hành động, entropy về gần 0, hết khả năng khám phá.
Front: Ba chỉ số nên có trong phần đánh giá? Back: eval_return trung bình, độ lệch chuẩn qua seed, và success_rate.
Front: Dấu hiệu rõ nhất của việc học thành công? Back: Đường cong phần thưởng đi lên và ổn định qua nhiều seed.
Front: Vì sao không nên xóa seed xấu khỏi báo cáo? Back: Che giấu seed xấu làm sai lệch kết luận về độ ổn định của thuật toán.
Front: Nên ghi log những gì mỗi episode? Back: episode, return, seed, eval_return, và tùy chọn entropy, loss.
Front: Vì sao phải đặt ngưỡng thành công cụ thể? Back: Không có ngưỡng thì không có tiêu chí khách quan để nói đồ án đã đạt.
Điền vào chỗ trống để ghi nhớ
Đường cong phần thưởng thô rất nhiễu, nên ta vẽ thêm _____ trên một cửa sổ W episode.
Để tách nhiễu ngẫu nhiên khỏi tín hiệu học, ta chạy huấn luyện với nhiều _____ rồi báo cáo trung bình kèm độ lệch chuẩn.
Khi đánh giá, ta thường cho policy chạy ở chế độ _____ thay vì lấy mẫu hành động.
Nếu entropy của policy giảm về gần 0 quá sớm, đó là dấu hiệu của _____.
Một đồ án đáng tin phải báo cáo cả seed _____, thay vì chỉ chọn seed cho kết quả đẹp nhất.