Học tăng cường
Học tăng cường (reinforcement learning, viết tắt RL) là dạng học máy thứ ba, bên cạnh học có giám sát và học không giám sát. Điểm khác biệt căn bản là máy không được cho biết câu trả lời đúng. Máy chỉ nhận về một con số cho biết hành động vừa rồi tốt hay xấu, rồi tự điều chỉnh để làm tốt hơn theo thời gian.
Thử ngay: xem giá trị lan ngược trên lưới
Thứ mà RL học được thường đọng lại thành một con số cho mỗi tình huống: đứng ở đây thì về sau còn hy vọng gom được bao nhiêu phần thưởng. Con số đó gọi là giá trị, và thuật toán lặp giá trị (value iteration) tính nó trên một lưới nhỏ như dưới đây. Mỗi vòng, giá trị của mỗi ô được cập nhật bằng giá trị tốt nhất trong các ô kề, cộng chi phí một bước rồi nhân hệ số chiết khấu gamma (gamma càng gần 1 thì tác tử càng coi trọng phần thưởng ở xa). Bấm nút Sau để xem phần thưởng ở đích lan ngược dần ra ngoài, còn mũi tên hiện chính sách tham lam luôn đi về ô có giá trị cao nhất. Đổi gamma để thấy tầm nhìn xa của tác tử thay đổi ra sao.
Hãy để ý một điều tinh tế mà chính widget này bày ra. Kéo gamma từ 0,3 lên 0,99, các con số trong ô đổi rất mạnh, nhưng mũi tên thì không nhúc nhích: trên lưới tất định nhỏ này, tác tử cận thị hay nhìn xa đều chọn đúng một đường đi, gamma chỉ đổi giá trị chứ chưa đổi hành vi. Muốn thấy chính sách thật sự lật, hãy chỉnh ô thưởng mỗi bước sang số dương, ví dụ 2: lúc đó mỗi bước đi đều được trả công, tác tử phát hiện ra mẹo húc đầu vào tường để nhận thưởng vô hạn, và nó quay lưng với ô đích vì tới đích là hết cuộc chơi. Đây chính là lỗi thiết kế phần thưởng kinh điển, và nó cũng cho thấy gamma quyết định ranh giới: cùng mức thưởng dương ấy, gamma 0,5 vẫn dẫn tác tử về đích, còn gamma 0,9 thì không.
Ý tưởng cốt lõi
Hãy hình dung một đứa trẻ tập đi xe đạp. Không ai dán nhãn từng giây rằng đây là cách đạp đúng, cũng không ai đưa công thức giữ thăng bằng. Đứa trẻ chỉ thử một động tác, nhận phản hồi từ thực tế (đứng vững hay ngã), rồi điều chỉnh để tăng kết quả tốt và giảm kết quả xấu. Sau hàng trăm lần ngã, nó biết đi xe. Không có giáo viên, chỉ có kinh nghiệm và phản hồi.
Đó chính là tinh thần của RL. Ta có một tác tử (agent) liên tục tương tác với một môi trường (environment) theo vòng lặp:
- Tác tử quan sát trạng thái hiện tại của môi trường.
- Tác tử chọn một hành động.
- Môi trường trả về trạng thái mới và một phần thưởng (một con số).
- Tác tử dùng phần thưởng để cải thiện cách ra quyết định.
Vòng lặp này lặp đi lặp lại. Mục tiêu của tác tử không phải là tối đa phần thưởng ngay trước mắt, mà là tối đa tổng phần thưởng tích lũy trong dài hạn.
Một vài ứng dụng nổi bật của RL: AlphaGo và AlphaZero (chơi cờ vây, cờ vua ở mức siêu việt), robot học cách đi và cầm nắm, hệ thống làm mát trung tâm dữ liệu của DeepMind (giảm khoảng 40 phần trăm năng lượng), và kỹ thuật RLHF (học tăng cường từ phản hồi của con người) đứng sau các trợ lý như ChatGPT hay Claude.
Khác học giám sát ở đâu
RL dễ bị nhầm với học có giám sát vì cả hai đều dùng một tín hiệu số để dẫn dắt việc học, nhưng bản chất tín hiệu rất khác nhau. Trong học có giám sát, mỗi đầu vào có sẵn nhãn đúng, và mô hình được sửa thẳng về phía nhãn đó; tín hiệu vừa nói rõ đáp án đúng vừa cho biết ta sai bao nhiêu.
Phần thưởng trong RL không phải là đáp án. Nó chỉ chấm điểm hành động vừa làm là tốt hay xấu, chứ không cho biết hành động nào mới đúng. Nếu tác tử đi sai, môi trường không mách lẽ ra phải đi hướng nào. Thêm vào đó, ba đặc điểm khiến RL khó hơn hẳn: dữ liệu do chính tác tử sinh ra qua hành động của nó chứ không phải một tập cố định cho sẵn, các quyết định nối tiếp nhau nên một hành động ảnh hưởng tới cả tương lai, và phần thưởng có thể đến rất trễ so với hành động gây ra nó. Vì thế tác tử vừa phải học đánh giá hành động, vừa phải tự thu thập dữ liệu để học, hai việc đan vào nhau.
Trạng thái, hành động, phần thưởng
Ba khái niệm này là bộ ba nền tảng của mọi bài toán RL.
- Trạng thái (state), ký hiệu
s: mô tả tình huống hiện tại của môi trường. Ví dụ, trong một mê cung nhỏ, trạng thái là ô lưới mà tác tử đang đứng, dạng(hang, cot). - Hành động (action), ký hiệu
a: lựa chọn mà tác tử có thể thực hiện. Trong mê cung, đó là đi lên, xuống, trái, phải. - Phần thưởng (reward), ký hiệu
r: con số môi trường trả về sau mỗi hành động. Ví dụ, mỗi bước đi mất-1điểm (để khuyến khích đi nhanh), tới đích được+10.
Một đặc tính quan trọng làm RL khó hơn các dạng học khác là phần thưởng trễ. Phần thưởng có thể đến nhiều bước sau hành động gây ra nó. Một nước cờ hay ở đầu ván có thể chỉ dẫn tới chiến thắng sau năm mươi nước. Tác tử phải tự suy ra hành động nào lúc đầu mới thực sự đáng giá.
Để gộp các phần thưởng tương lai lại, ta dùng hệ số chiết khấu gamma nằm trong khoảng từ 0 tới 1. Tổng phần thưởng tích lũy (gọi là return) từ thời điểm hiện tại được tính bằng lời như sau: lấy phần thưởng bước kế tiếp, cộng gamma nhân phần thưởng bước sau nữa, cộng gamma bình phương nhân phần thưởng bước sau đó, và cứ thế. Vì gamma nhỏ hơn 1 nên phần thưởng càng xa trong tương lai càng bị giảm trọng số. Giá trị thường dùng cho gamma là 0.9 tới 0.99.
Chính sách và hàm giá trị
Chính sách (policy), ký hiệu pi, là cách tác tử quyết định hành động dựa trên trạng thái. Hiểu đơn giản, chính sách là một quy tắc: cho trạng thái s thì chọn hành động nào. Mục tiêu cuối cùng của RL là tìm chính sách tối ưu, tức chính sách cho tổng phần thưởng kỳ vọng cao nhất.
Để đánh giá xem một trạng thái hay một hành động đáng giá ra sao, ta dùng hàm giá trị.
- Hàm giá trị trạng thái
V(s): trả lời câu hỏi nếu đang ở trạng tháisvà đi theo chính sách hiện tại thì kỳ vọng tổng phần thưởng tương lai là bao nhiêu. - Hàm giá trị hành động
Q(s, a): trả lời câu hỏi nếu đang ởs, làm hành độnga, rồi sau đó đi theo chính sách thì tổng phần thưởng kỳ vọng là bao nhiêu.
Hàm Q đặc biệt tiện lợi. Nếu ta đã biết Q tối ưu cho mọi cặp trạng thái và hành động thì chính sách tối ưu rất dễ rút ra: ở mỗi trạng thái, chỉ cần chọn hành động có giá trị Q lớn nhất. Đây là lý do nhiều thuật toán RL tập trung học Q thay vì V, vì Q cho ngay hành động nên dùng mà không cần biết trước quy luật của môi trường.
Hàm giá trị cũng chính là cách RL đối phó với phần thưởng trễ. Thay vì phải chờ tới cuối mới biết một chuỗi hành động đáng giá bao nhiêu, giá trị của một trạng thái được ước lượng dựa một phần vào giá trị của trạng thái kế tiếp. Nhờ vậy thông tin về phần thưởng ở đích dần dần lan ngược về các trạng thái trước đó qua nhiều lần cập nhật, gán công lao cho những hành động sớm đã dọn đường cho thắng lợi về sau. Đây là mấu chốt để tác tử biết được nước cờ hay ở đầu ván, dù phần thưởng chỉ tới lúc kết thúc.
Thuật toán Q-learning
Q-learning (Watkins, 1989) là thuật toán model-free quan trọng nhất trong RL. Model-free nghĩa là tác tử không biết trước môi trường hoạt động ra sao: nó không biết xác suất chuyển trạng thái, cũng không biết quy luật phần thưởng. Tác tử chỉ học từ kinh nghiệm thực tế, gồm các mẫu dạng trạng thái, hành động, phần thưởng, trạng thái mới.
Ý tưởng là duy trì một bảng Q lưu giá trị ước lượng cho từng cặp trạng thái và hành động. Ban đầu bảng khởi tạo bằng 0. Sau mỗi lần tương tác, ta cập nhật bảng để nó dần dần tiến tới giá trị đúng.
Quy tắc cập nhật cốt lõi, viết dưới dạng mã, là:
Q[s,a] = Q[s,a] + alpha * (reward + gamma*max(Q[s2]) - Q[s,a])
Trong đó s là trạng thái cũ, a là hành động vừa làm, reward là phần thưởng nhận được, s2 là trạng thái mới, và max(Q[s2]) là giá trị Q lớn nhất có thể đạt được ở trạng thái mới. Tham số alpha nằm trong khoảng từ 0 tới 1 là tốc độ học.
Trực giác của quy tắc này: phần reward + gamma*max(Q[s2]) là một ước lượng mới, tốt hơn, về giá trị đúng của cặp (s, a), dựa trên những gì tác tử vừa quan sát. Hiệu giữa ước lượng mới và giá trị cũ Q[s,a] gọi là sai số thời gian (TD error). Ta kéo Q[s,a] về phía ước lượng mới một đoạn tỉ lệ với alpha. Lặp lại đủ nhiều lần, bảng Q hội tụ về giá trị tối ưu.
Một điểm tinh tế: Q-learning dùng max(Q[s2]) chứ không dùng giá trị của hành động thực tế sẽ làm ở s2. Nhờ vậy nó học chính sách tối ưu ngay cả khi đang khám phá bằng những hành động ngẫu nhiên. Tính chất này gọi là off-policy.
Khám phá và khai thác
Ở mỗi trạng thái, tác tử đứng trước hai lựa chọn trái ngược:
- Khai thác (exploit): chọn hành động có
Qlớn nhất, tức làm điều đang tin là tốt nhất theo hiểu biết hiện tại. - Khám phá (explore): thử một hành động khác để biết thêm, biết đâu nó tốt hơn.
Nếu luôn khai thác, tác tử dễ mắc kẹt ở một chính sách dưới tối ưu. Hãy tưởng tượng ở trạng thái đầu có hai hành động: hành động thứ nhất cho ngay +1 rồi kết thúc, hành động thứ hai cho 0 ngay nhưng dẫn tới chỗ có +100 ở bước sau. Lúc đầu cả hai đều có Q bằng 0. Tác tử thử hành động thứ nhất, được +1, nên từ đó luôn chọn nó và không bao giờ phát hiện ra hành động thứ hai mới thực sự đáng giá. Ngược lại, nếu luôn khám phá thì tác tử không tận dụng được những gì đã học.
Chiến lược cân bằng đơn giản và phổ biến nhất là epsilon-greedy. Ta chọn một tham số epsilon nhỏ, ví dụ 0.1, rồi:
- Với xác suất
epsilon: chọn một hành động ngẫu nhiên (khám phá). - Với xác suất
1 - epsilon: chọn hành động cóQlớn nhất (khai thác).
Một cách làm tốt hơn trong thực tế là cho epsilon giảm dần theo thời gian. Lúc đầu để epsilon cao (gần 1.0) nhằm khám phá mạnh khi chưa biết gì, rồi giảm dần về một mức nhỏ (ví dụ 0.05) để chủ yếu khai thác sau khi đã học đủ. Khám phá là điều kiện bắt buộc để Q-learning hội tụ, vì lý thuyết yêu cầu mọi cặp trạng thái và hành động phải được thử vô hạn lần.
Một hiểu nhầm phổ biến là nghĩ phần thưởng càng lớn thì học càng nhanh, nên cứ thưởng thật hậu ở đích là xong. Thực ra cái quyết định không phải độ lớn tuyệt đối của phần thưởng mà là chênh lệch giữa các hành động và việc tín hiệu có tới được tác tử hay không. Nếu phần thưởng quá thưa, chỉ có ở đích còn mọi nơi khác bằng 0, tác tử có thể lang thang rất lâu mà chẳng bao giờ tình cờ chạm đích để học được gì. Thiết kế phần thưởng sai còn nguy hiểm hơn: tác tử sẽ tối đa đúng cái ta viết ra, kể cả khi đó không phải điều ta thực sự muốn.
Mã nguồn Python
Dưới đây là ví dụ Q-learning hoàn chỉnh trên một lưới nhỏ (GridWorld). Tác tử xuất phát ở góc dưới bên trái, cần tới đích ở góc trên bên phải. Mỗi bước mất -1 điểm, tới đích được +10 điểm. Bảng Q được lưu bằng dict, khóa là cặp trạng thái và hành động.
import random
# Moi truong GridWorld 4x4
ROWS, COLS = 4, 4
START = (3, 0)
GOAL = (0, 3)
ACTIONS = ["up", "down", "left", "right"]
def step(state, action):
# Tra ve (trang thai moi, phan thuong, ket thuc)
r, c = state
if action == "up":
r -= 1
elif action == "down":
r += 1
elif action == "left":
c -= 1
elif action == "right":
c += 1
# Neu di ra ngoai luoi thi dung yen
if r < 0 or r >= ROWS or c < 0 or c >= COLS:
r, c = state
new_state = (r, c)
if new_state == GOAL:
return new_state, 10.0, True
return new_state, -1.0, False
def best_action(Q, state):
# Chon hanh dong co Q lon nhat tai trang thai
values = [Q.get((state, a), 0.0) for a in ACTIONS]
best = max(values)
# Neu nhieu hanh dong cung tot, chon ngau nhien mot trong so do
candidates = [a for a, v in zip(ACTIONS, values) if v == best]
return random.choice(candidates)
def q_learning(episodes=500, alpha=0.1, gamma=0.95):
Q = {} # dict: (state, action) -> gia tri
epsilon = 1.0
for ep in range(episodes):
state = START
done = False
steps = 0
while not done and steps < 100:
# epsilon-greedy: chon kham pha hoac khai thac
if random.random() < epsilon:
action = random.choice(ACTIONS)
else:
action = best_action(Q, state)
next_state, reward, done = step(state, action)
# Gia tri Q lon nhat tai trang thai moi
max_next = max(Q.get((next_state, a), 0.0) for a in ACTIONS)
# Quy tac cap nhat Q-learning
old = Q.get((state, action), 0.0)
Q[(state, action)] = old + alpha * (reward + gamma * max_next - old)
state = next_state
steps += 1
# Giam dan epsilon: kham pha nhieu luc dau, khai thac ve sau
epsilon = max(0.05, epsilon * 0.99)
return Q
def show_policy(Q):
# In ra chinh sach greedy hoc duoc
arrow = {"up": "U", "down": "D", "left": "L", "right": "R"}
for r in range(ROWS):
row = []
for c in range(COLS):
if (r, c) == GOAL:
row.append("G")
else:
row.append(arrow[best_action(Q, (r, c))])
print(" ".join(row))
if __name__ == "__main__":
Q = q_learning()
show_policy(Q)
print("Q tai trang thai bat dau:")
for a in ACTIONS:
print(a, round(Q.get((START, a), 0.0), 2))
Khi chạy khoảng 500 episode, tác tử hội tụ về đường đi tối ưu sáu bước từ điểm xuất phát tới đích. Hành động right ở trạng thái bắt đầu sẽ có giá trị Q cao nhất, khớp với chính sách tốt nhất. Đường tối ưu mất năm bước với phần thưởng -1 rồi một bước tới đích được +10, nên tổng phần thưởng là +5.
Bài tập thực hành
Bài 1. Thay đổi hệ số chiết khấu gamma thành 0.5 rồi thành 0.99, chạy lại và quan sát chính sách học được cùng các giá trị Q ở trạng thái bắt đầu. Giải thích vì sao gamma ảnh hưởng tới việc tác tử có chịu đi đường dài để lấy phần thưởng lớn ở cuối hay không.
Gợi ý
gamma nhỏ làm tác tử cận thị, chỉ quan tâm phần thưởng gần. Với gamma 0.5, phần thưởng +10 ở đích bị chiết khấu mạnh sau vài bước nên giá trị Q ở trạng thái xa đích sẽ nhỏ và có thể âm. Với gamma 0.99, phần thưởng cuối được giữ trọng số gần như nguyên vẹn, các giá trị Q dọc đường đi đều dương rõ rệt.
Bài 2. Cố định epsilon bằng 0 ngay từ đầu (bỏ hẳn dòng giảm epsilon và luôn khai thác). Chạy lại nhiều lần. Tác tử có luôn tìm ra đường tối ưu không? Giải thích bằng khái niệm khám phá.
Gợi ý
Với epsilon bằng 0, tác tử luôn chọn hành động có Q lớn nhất. Vì bảng Q ban đầu toàn 0, lựa chọn phụ thuộc may rủi của lần phá hòa đầu tiên, và nhiều cặp trạng thái với hành động không bao giờ được thử. Tác tử dễ kẹt ở chính sách dưới tối ưu. Đây chính là minh họa vì sao khám phá là điều kiện bắt buộc để hội tụ.
Bài 3. Thêm một ô tường vào lưới (ví dụ ô (1, 1) không đi vào được, nếu định đi vào thì đứng yên). Sửa hàm step cho phù hợp rồi huấn luyện lại. Quan sát xem chính sách có vòng tránh tường hay không.
Gợi ý
Trong hàm step, sau khi tính new_state, thêm kiểm tra nếu new_state trùng ô tường thì giữ nguyên state cũ (giống cách xử lý đi ra ngoài lưới). Tác tử sẽ học rằng đâm vào tường chỉ tốn -1 mà không tiến được, nên các mũi tên trong chính sách sẽ tự vòng tránh ô tường.
Tự kiểm tra
Trong quy tắc cập nhật Q-learning, vì sao ta dùng max(Q[s2]) thay vì giá trị của hành động thực tế sẽ làm ở s2?
Vì Q-learning là thuật toán off-policy: nó luôn học hướng tới chính sách tối ưu. Dùng max(Q[s2]) nghĩa là giả định ở trạng thái mới tác tử sẽ chọn hành động tốt nhất có thể, bất kể thực tế nó đang khám phá bằng hành động ngẫu nhiên nào. Nhờ đó tác tử vẫn hội tụ về chính sách tối ưu trong khi vẫn được tự do khám phá.
Nếu để epsilon cố định bằng 0.1 mãi mãi, sau khi đã hội tụ tác tử có còn thỉnh thoảng đi sai không?
Có. Với epsilon bằng 0.1, ở mỗi bước vẫn có 10 phần trăm khả năng tác tử chọn hành động ngẫu nhiên, kể cả khi đã biết đường tối ưu. Vì vậy đường cong phần thưởng sẽ dao động nhẹ quanh mức tối ưu chứ không phẳng tuyệt đối. Đây là lý do trong thực tế người ta thường cho epsilon giảm dần về một mức rất nhỏ sau khi học xong.
Học tăng cường khác học có giám sát ở điểm căn bản nào?
Trong học có giám sát mỗi đầu vào có sẵn nhãn đúng và mô hình được sửa thẳng về phía nhãn đó. Trong RL không có nhãn: môi trường chỉ trả về phần thưởng chấm điểm hành động vừa làm là tốt hay xấu, không cho biết hành động nào mới đúng. Thêm nữa tác tử tự sinh dữ liệu qua hành động của mình, các quyết định nối tiếp ảnh hưởng lẫn nhau, và phần thưởng có thể đến rất trễ, nên tác tử vừa phải học đánh giá hành động vừa phải tự thu thập dữ liệu để học.
Câu hỏi tự kiểm
- 1Khác biệt căn bản giữa tín hiệu phần thưởng trong RL và nhãn trong học có giám sát là gì?
- 2Nếu tác tử luôn khai thác (chọn hành động Q lớn nhất) mà không bao giờ khám phá thì rủi ro gì?
- 3Hệ số chiết khấu gamma nhỏ (gần 0) khiến tác tử hành xử thế nào?
- 4Quy tắc Q-learning dùng max(Q[s2]) thay vì giá trị hành động thực tế sẽ làm ở s2. Điều này có nghĩa gì?
Học tăng cường là chuyện tác tử học từ thử và lỗi qua tương tác với môi trường: quan sát trạng thái, chọn hành động, nhận phần thưởng, rồi cải thiện chính sách để tối đa tổng phần thưởng dài hạn. Q-learning học một bảng Q đánh giá từng cặp trạng thái và hành động bằng quy tắc Q[s,a] = Q[s,a] + alpha * (reward + gamma*max(Q[s2]) - Q[s,a]). Chìa khóa để học tốt là cân bằng khám phá và khai thác, mà cách đơn giản nhất là epsilon-greedy với epsilon giảm dần theo thời gian.