在之前的文章中,我們介紹了神經網絡、卷積神經網絡(CNN)、循環神經網絡(RNN)、Transformer 等多種深度學習模型,并應用于圖像分類、文本分類、時間序列預測等任務。本文將介紹強化學習的基本概念,并使用 PyTorch 實現一個經典的深度 Q 網絡(DQN)來解決強化學習中的經典問題——CartPole。
一、強化學習基礎
強化學習(Reinforcement Learning, RL)是機器學習的一個重要分支,它通過智能體(Agent)與環境(Environment)的交互來學習策略,以最大化累積獎勵。強化學習的核心思想是通過試錯來學習,智能體在環境中采取行動,觀察結果,并根據獎勵信號調整策略。
1. 強化學習的基本要素
-
智能體(Agent):學習并做出決策的主體。
-
環境(Environment):智能體交互的外部世界。
-
狀態(State):環境在某一時刻的描述。
-
動作(Action):智能體在某一狀態下采取的行動。
-
獎勵(Reward):智能體采取動作后,環境返回的反饋信號。
-
策略(Policy):智能體在給定狀態下選擇動作的規則。
-
價值函數(Value Function):評估在某一狀態下采取某一動作的長期回報。
2. Q-Learning 與深度 Q 網絡(DQN)
Q-Learning 是一種經典的強化學習算法,它通過學習一個 Q 函數來評估在某一狀態下采取某一動作的長期回報。Q 函數的更新公式為:
深度 Q 網絡(DQN)將 Q-Learning 與深度學習結合,使用神經網絡來近似 Q 函數。DQN 通過經驗回放(Experience Replay)和目標網絡(Target Network)來穩定訓練過程。
二、CartPole 問題實戰
CartPole 是強化學習中的經典問題,目標是控制一個小車(Cart)使其上的桿子(Pole)保持直立。我們將使用 PyTorch 實現一個 DQN 來解決這個問題。
1. 問題描述
CartPole 環境的狀態空間包括小車的位置、速度、桿子的角度和角速度。動作空間包括向左或向右移動小車。智能體每保持桿子直立一步,就會獲得 +1 的獎勵,當桿子傾斜超過一定角度或小車移動超出范圍時,游戲結束。
2. 實現步驟
-
安裝并導入必要的庫。
-
定義 DQN 模型。
-
定義經驗回放緩沖區。
-
定義 DQN 訓練過程。
-
測試模型并評估性能。
3. 代碼實現
import gym
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
import random
from collections import deque
import matplotlib.pyplot as plt
?
# 設置 Matplotlib 支持中文顯示
plt.rcParams['font.sans-serif'] = ['SimHei'] # 設置字體為 SimHei(黑體)
plt.rcParams['axes.unicode_minus'] = False # 解決負號顯示問題
?
# 1. 安裝并導入必要的庫
env = gym.make('CartPole-v1')
?
# 2. 定義 DQN 模型
class DQN(nn.Module):def __init__(self, state_size, action_size):super(DQN, self).__init__()self.fc1 = nn.Linear(state_size, 64)self.fc2 = nn.Linear(64, 64)self.fc3 = nn.Linear(64, action_size)
?def forward(self, x):x = torch.relu(self.fc1(x))x = torch.relu(self.fc2(x))x = self.fc3(x)return x
?
# 3. 定義經驗回放緩沖區
class ReplayBuffer:def __init__(self, capacity):self.buffer = deque(maxlen=capacity)
?def push(self, state, action, reward, next_state, done):self.buffer.append((state, action, reward, next_state, done))
?def sample(self, batch_size):state, action, reward, next_state, done = zip(*random.sample(self.buffer, batch_size))return np.array(state), np.array(action), np.array(reward), np.array(next_state), np.array(done)
?def __len__(self):return len(self.buffer)
?
# 4. 定義 DQN 訓練過程
state_size = env.observation_space.shape[0]
action_size = env.action_space.n
model = DQN(state_size, action_size)
target_model = DQN(state_size, action_size)
target_model.load_state_dict(model.state_dict())
optimizer = optim.Adam(model.parameters(), lr=0.001)
buffer = ReplayBuffer(10000)
?
def train(batch_size, gamma=0.99):if len(buffer) < batch_size:returnstate, action, reward, next_state, done = buffer.sample(batch_size)state = torch.FloatTensor(state)next_state = torch.FloatTensor(next_state)action = torch.LongTensor(action)reward = torch.FloatTensor(reward)done = torch.FloatTensor(done)
?q_values = model(state)next_q_values = target_model(next_state)q_value = q_values.gather(1, action.unsqueeze(1)).squeeze(1)next_q_value = next_q_values.max(1)[0]expected_q_value = reward + gamma * next_q_value * (1 - done)
?loss = nn.MSELoss()(q_value, expected_q_value.detach())optimizer.zero_grad()loss.backward()optimizer.step()
?
# 5. 測試模型并評估性能
def test(env, model, episodes=10):total_reward = 0for _ in range(episodes):state = env.reset()done = Falsewhile not done:state = torch.FloatTensor(state).unsqueeze(0)action = model(state).max(1)[1].item()next_state, reward, done, _ = env.step(action)total_reward += rewardstate = next_statereturn total_reward / episodes
?
# 訓練過程
episodes = 500
batch_size = 64
gamma = 0.99
epsilon = 1.0
epsilon_min = 0.01
epsilon_decay = 0.995
rewards = []
?
for episode in range(episodes):state = env.reset()done = Falsetotal_reward = 0
?while not done:if random.random() < epsilon:action = env.action_space.sample()else:state_tensor = torch.FloatTensor(state).unsqueeze(0)action = model(state_tensor).max(1)[1].item()
?next_state, reward, done, _ = env.step(action)buffer.push(state, action, reward, next_state, done)state = next_statetotal_reward += reward
?train(batch_size, gamma)
?epsilon = max(epsilon_min, epsilon * epsilon_decay)rewards.append(total_reward)
?if (episode + 1) % 50 == 0:avg_reward = test(env, model)print(f"Episode: {episode + 1}, Avg Reward: {avg_reward:.2f}")
?
# 6. 可視化訓練結果
plt.plot(rewards)
plt.xlabel("Episode")
plt.ylabel("Total Reward")
plt.title("DQN 訓練過程")
plt.show()
三、代碼解析
-
環境與模型定義:
-
使用
gym
創建 CartPole 環境。 -
定義 DQN 模型,包含三個全連接層。
-
-
經驗回放緩沖區:
-
使用
deque
實現經驗回放緩沖區,存儲狀態、動作、獎勵等信息。
-
-
訓練過程:
-
使用 epsilon-greedy 策略進行探索與利用。
-
通過經驗回放緩沖區采樣數據進行訓練,更新模型參數。
-
-
測試過程:
-
在測試環境中評估模型性能,計算平均獎勵。
-
-
可視化:
-
繪制訓練過程中的總獎勵曲線。
-
四、運行結果
運行上述代碼后,你將看到以下輸出:
-
訓練過程中每 50 個 episode 打印一次平均獎勵。
-
訓練結束后,繪制訓練過程中的總獎勵曲線。
五、總結
本文介紹了強化學習的基本概念,并使用 PyTorch 實現了一個深度 Q 網絡(DQN)來解決 CartPole 問題。通過這個例子,我們學習了如何定義 DQN 模型、使用經驗回放緩沖區、訓練模型以及評估性能。
在下一篇文章中,我們將探討更復雜的強化學習算法,如 Actor-Critic 和 Proximal Policy Optimization (PPO)。敬請期待!
代碼實例說明:
-
本文代碼可以直接在 Jupyter Notebook 或 Python 腳本中運行。
-
如果你有 GPU,可以將模型和數據移動到 GPU 上運行,例如:
model = model.to('cuda')
,state = state.to('cuda')
。
希望這篇文章能幫助你更好地理解強化學習的基礎知識!如果有任何問題,歡迎在評論區留言討論。