AI時代系列(3) 機器學習三部曲: 📘 第三部:《強化學習 —— AI 的決策與進化》
49/100 第五週:📌 Deep Q-Network(DQN)與深度強化學習入門
49.實作練習:CartPole with DQN 🎮 訓練不會倒的智慧體!
________________________________________
🎯 單元導讀
到目前為止,我們學習了 DQN 的架構與核心技巧。
本單元將帶你從零開始,使用 PyTorch 建立 DQN,訓練一個能撐竿平衡的智慧體,成功解決經典環境 —— [CartPole-v1]!
________________________________________
🧱 一、CartPole 問題簡介
這是一個經典的倒立擺(CartPole)強化學習任務,系統的 狀態空間 由 4 維連續向量組成,分別代表小車的位置、速度、竿子的角度與角速度;動作空間 則是離散的兩個動作:向左推(0)或向右推(1)。訓練目標是讓竿子維持平衡不倒,撐得越久越好。當竿子傾倒角度超過 15 度,或小車位置超出 ±2.4 的範圍時即視為失敗並終止該回合,每個 episode 最長可持續 500 步,若成功撐滿則視為成功達成任務。
________________________________________
🧠 二、DQN 核心元件回顧
• 神經網路模型 Q(s, a)
• Replay Buffer 記錄經驗
• ε-Greedy 策略 負責探索
• Target Network 提供穩定學習目標
• TD 誤差 作為損失函數進行訓練
________________________________________
🧪 三、完整實作程式碼(PyTorch)
✅ 安裝與匯入
pip install gym torch numpy
python
import gym
import torch
import torch.nn as nn
import torch.optim as optim
import random
import numpy as np
from collections import deque
________________________________________
✅ 建立 Q 網路
python
class QNet(nn.Module):
def __init__(self, state_dim, action_dim):
super().__init__()
self.fc = nn.Sequential(
nn.Linear(state_dim, 128),
nn.ReLU(),
nn.Linear(128, 128),
nn.ReLU(),
nn.Linear(128, action_dim)
)
def forward(self, x):
return self.fc(x)
這個 QNet 類別定義了一個標準的 Q-Learning 神經網路,透過三層全連接層(Linear + ReLU)將輸入的狀態向量 x 轉換成對應每個動作的 Q 值預測,輸出長度為 action_dim,代表各動作的價值估計。
________________________________________
✅ 參數與環境設定
python
env = gym.make("CartPole-v1")
state_dim = env.observation_space.shape[0]
action_dim = env.action_space.n
q_net = QNet(state_dim, action_dim)
target_net = QNet(state_dim, action_dim)
target_net.load_state_dict(q_net.state_dict())
optimizer = optim.Adam(q_net.parameters(), lr=1e-3)
loss_fn = nn.SmoothL1Loss()
replay_buffer = deque(maxlen=10000)
batch_size = 64
gamma = 0.99
epsilon = 1.0
epsilon_min = 0.01
epsilon_decay = 0.995
target_update_freq = 10
這段程式建立 CartPole 環境,初始化 Q 網路與目標網路(並同步參數),設定 Adam 優化器、Smooth L1 損失函數、經驗回放緩衝區及一組 DQN 訓練用的超參數(如批次大小、折扣因子、ε 探索機制與目標網路更新頻率)。
________________________________________
✅ 訓練主迴圈
python
def choose_action(state):
if random.random() < epsilon:
return env.action_space.sample()
with torch.no_grad():
state = torch.FloatTensor(state).unsqueeze(0)
return q_net(state).argmax().item()
def train():
batch = random.sample(replay_buffer, batch_size)
states, actions, rewards, next_states, dones = zip(*batch)
states = torch.FloatTensor(states)
actions = torch.LongTensor(actions).unsqueeze(1)
rewards = torch.FloatTensor(rewards)
next_states = torch.FloatTensor(next_states)
dones = torch.FloatTensor(dones)
q_values = q_net(states).gather(1, actions).squeeze()
with torch.no_grad():
next_q = target_net(next_states).max(1)[0]
targets = rewards + gamma * next_q * (1 - dones)
loss = loss_fn(q_values, targets)
optimizer.zero_grad()
loss.backward()
optimizer.step()
choose_action() 透過 ε-Greedy 策略在探索與利用間選擇動作,而 train() 則隨機取出回放資料,計算目前 Q 值與目標 Q 值的 TD 誤差,使用 Smooth L1 Loss 反向傳播更新 Q 網路參數。
________________________________________
✅ 開始訓練!
python
episodes = 500
for ep in range(episodes):
state = env.reset()
total_reward = 0
done = False
while not done:
action = choose_action(state)
next_state, reward, done, _ = env.step(action)
replay_buffer.append((state, action, reward, next_state, float(done)))
state = next_state
total_reward += reward
if len(replay_buffer) >= batch_size:
train()
if ep % target_update_freq == 0:
target_net.load_state_dict(q_net.state_dict())
global epsilon
epsilon = max(epsilon_min, epsilon * epsilon_decay)
print(f"Ep {ep}: Reward={total_reward:.0f}, ε={epsilon:.3f}")
訓練流程共執行 500 回合,智慧體在每回合中以 ε-Greedy 策略互動並累積經驗進入回放池,當樣本足夠時進行訓練,並每隔固定回合同步目標網路,同時逐步衰減 ε 以平衡探索與利用,並即時輸出每回合獎勵與 ε 值。
________________________________________
📈 四、成功標準與觀察指標
項目 說明
成功定義 平均 100 回合回報 > 475(接近滿分)
觀察指標 Reward 上升曲線、Loss 收斂趨勢、Q 值變化趨勢
測試表現 設定 ε = 0 看智慧體行為是否穩定不倒
________________________________________
🔍 五、延伸挑戰與強化目標
• ✅ 加入 Dueling DQN 架構強化判斷
• ✅ 改為 Double DQN 降低估計偏差
• ✅ 記錄與繪製訓練曲線(可用 matplotlib、TensorBoard)
• ✅ 訓練結果儲存與測試回放(使用 torch.save 模型)
________________________________________
✅ 六、小結與啟示
• CartPole 是強化學習入門的絕佳實作環境
• 學會 DQN 的訓練流程,是未來攻克複雜任務的基礎
• 訓練智慧體不倒,就像訓練自己的人生決策平衡感:觀察、選擇、回饋、持續調整