1,定義獎勵函數
首先,需要根據具體的任務需求來定義獎勵函數。例如,對于機器人導航任務,可以根據機器人與目標點的距離來定義獎勵函數:
import numpy as npdef navigation_reward(robot_position, target_position):# 計算機器人當前位置與目標位置之間的歐幾里得距離distance = np.linalg.norm(np.array(robot_position) - np.array(target_position))# 距離越近,獎勵越高reward = -distancereturn reward
2. 集成獎勵函數到環境中
在強化學習中,環境負責與智能體進行交互,并根據智能體的動作給出相應的獎勵。通常,環境類會有一個?step
?方法,該方法接受智能體的動作作為輸入,并返回下一個狀態、獎勵、是否終止等信息
import numpy as npclass NavigationEnv: # 定義導航環境類def __init__(self):# 初始化機器人的起始位置和目標位置self.robot_position = np.array([0, 0]) # 機器人初始位置 (x=0, y=0)self.target_position = np.array([10, 10]) # 目標位置 (x=10, y=10)def step(self, action):# 核心邏輯:執行動作 → 更新狀態 → 計算獎勵 → 判斷終止# 根據動作更新機器人的位置self.robot_position += action # 通過向量加法更新位置# 通過向量加法更新機器人位置。例如,若動作是 [2, 3],新位置為 (0+2, 0+3) = (2, 3)# 計算獎勵reward = navigation_reward(self.robot_position, self.target_position)# 判斷是否到達目標位置done = np.linalg.norm(self.robot_position - self.target_position) < 0.1# 返回下一個狀態、獎勵、是否終止等信息,返回四元組return self.robot_position, reward, done, {}
3. 在訓練循環中使用獎勵函數
在訓練智能體時,需要在每個時間步調用環境的?step
?方法,并根據返回的獎勵來更新智能體的策略。以下是一個簡單的訓練循環示例:
代碼分為三大部分:
-
環境 (NavigationEnv)
- 狀態:機器人的二維坐標
- 動作:離散動作空間 (0 = 向右移動,1 = 向上移動)
- 獎勵:負距離 (-distance),鼓勵機器人靠近目標
-
策略網絡 (PolicyNetwork)
- 輸入:機器人當前位置 (二維向量)
- 輸出:兩個動作的概率分布
- 結構:兩層全連接網絡,使用 ReLU 激活和 softmax 輸出
-
訓練循環
- 收集數據:每個 episode 收集狀態、動作、獎勵序列
- 計算回報:使用折扣因子計算每個時間步的累積回報
- 更新策略:通過最大化累積回報的對數概率來更新網絡參數
# 修正后的完整代碼
import numpy as np
import torch
import torch.optim as optimclass NavigationEnv:def __init__(self):self.reset() ## 初始化時直接調用reset方法def reset(self):self.robot_position = np.array([0.0, 0.0])self.target_position = np.array([10.0, 10.0])return self.robot_positiondef step(self, action):self.robot_position += action # # 執行動作(向量加法)distance = np.linalg.norm(self.robot_position - self.target_position)reward = -distance # 簡單獎勵函數,獎勵設計:距離越近獎勵越高(負值越小)done = distance < 0.1 # 終止條件:距離目標小于0.1單位return self.robot_position, reward, done, {}class PolicyNetwork(torch.nn.Module):def __init__(self, input_size, output_size):super().__init__()self.fc1 = torch.nn.Linear(input_size, 128) # 輸入層→隱藏層(128神經元)self.fc2 = torch.nn.Linear(128, output_size) # 隱藏層→輸出層(動作維度)def forward(self, x):x = torch.relu(self.fc1(x)) # ReLU激活函數引入非線性 return torch.softmax(self.fc2(x), dim=-1) # 輸出動作概率分布env = NavigationEnv()
policy_net = PolicyNetwork(2, 2) # 輸入狀態維度2,輸出動作數2
optimizer = optim.Adam(policy_net.parameters(), lr=0.001) # 自適應學習率優化器
action_map = {0: np.array([1,0]), 1: np.array([0,1])} # 動作映射表 0向右移動1個單位,1向上移動1個單位
gamma = 0.99 #未來獎勵折扣因子
for episode in range(1000): #訓練1000輪state = env.reset() # 重置環境done = Falserewards, states, actions = [], [], [] # 數據收集容器while not done:state_tensor = torch.FloatTensor(state) # 轉為PyTorch張量probs = policy_net(state_tensor) # 獲取動作概率action_idx = torch.multinomial(probs, 1).item() # 按概率抽樣動作action = action_map[action_idx] # 轉換為實際動作向量next_state, reward, done, _ = env.step(action) # 環境反饋# 存儲軌跡數據rewards.append(reward) states.append(state_tensor)actions.append(action_idx)state = next_state # 狀態更新# 計算累積回報returns = []cumulative = 0for r in reversed(rewards): # 從最后一步反向計算cumulative = r + gamma * cumulative # 計算累積回報returns.insert(0, cumulative) # 保持時序# 策略梯度更新optimizer.zero_grad() # 清空梯度for s, a, R in zip(states, actions, returns):prob = policy_net(s) # 重新計算動作概率(需梯度)log_prob = torch.log(prob[a]) # 選擇動作的對數概率loss = -log_prob * R # 策略梯度損失loss.backward() # 反向傳播累積梯度optimizer.step()print(f"Episode {episode}, Total Reward: {sum(rewards):.1f}")
-
Episode 0
-
初始位置 (0,0)
-
隨機選擇動作:可能頻繁撞墻(若未加邊界約束)
-
獎勵約 -200(低效路徑)
-
-
Episode 500
-
網絡學會向目標方向移動
-
路徑呈現鋸齒形(探索仍在進行)
-
獎勵提升至 -50
-
-
Episode 1000
-
穩定選擇向右和向上動作
-
直線接近目標,獎勵接近 0
-
成功收斂
-
優化方向建議
-
狀態歸一化:將坐標范圍縮放到 [-1,1] 加速訓練
-
經驗回放:使用?
deque
?存儲歷史數據,隨機采樣更新 -
熵正則化:在損失函數中添加熵項鼓勵探索
-
Advantage Actor-Critic:引入價值函數估計優勢值