pytorch笔记:policy gradient
本文參考了?策略梯度PG( Policy Gradient) 的pytorch代碼實現示例 cart-pole游戲_李瑩斌XJTU的博客-CSDN博客_策略梯度pytorch
在其基礎上添加了注釋和自己的一些理解
1 理論部分
強化學習筆記:Policy-based Approach_UQI-LIUWJ的博客-CSDN博客
我們使用其中的框架(在我們后面的實驗中,我們認為每次N取1就對參數進行一次更新)
同時獎勵R不是使用,而是使用折扣回報?
?2? 代碼部分
2.1 導入庫 & 參數處理
import argparse import numpy as np import gym from itertools import count import torch import torch.nn as nn import torch.nn.functional as F import torch.optim as optim from torch.distributions import Categorical parser = argparse.ArgumentParser(description='Pytorch REINFORCE example') parser.add_argument('--gamma', type=float, default=0.99) parser.add_argument('--seed',type=int, default=543) parser.add_argument('--render',action='store_false') parser.add_argument('--log-interval', type=int, default=10) parser.add_argument('--episodes', type=int, default=10) parser.add_argument('--steps_per_episode', type=int, default=10)args = parser.parse_args()python 筆記:argparse_UQI-LIUWJ的博客-CSDN博客
2.2 gym環境創建
python 筆記 :Gym庫 (官方文檔筆記)_UQI-LIUWJ的博客-CSDN博客
env = gym.make('CartPole-v1') #創建一個推車桿的gym環境 env.seed(args.seed) #設置隨機種子 torch.manual_seed(args.seed) # 策略梯度算法方差很大,設置隨機以保證復現性print('observation space:',env.observation_space) ''' Box([-4.8000002e+00 -3.4028235e+38 -4.1887903e-01 -3.4028235e+38],[4.8000002e+00 3.4028235e+38 4.1887903e-01 3.4028235e+38],(4,),float32) '''print('action space:',env.action_space) #Discrete(2)cartpole 的state是一個4維向量,分別是位置,速度,桿子的角度,加速度;
action是二維、離散,即向左/右推桿子
2.3 創建Policy類
輸入某一時刻的狀態(也就是一個四維向量),輸出采取各個動作的概率(二維向量)
class Policy(nn.Module):## 離散空間采用了 softmax policy 來參數化策略def __init__(self):super(Policy,self).__init__()self.fc1 = nn.Linear(4,128)#一開始是一個[1,4]維的Tensor,表示狀態#先使用一個全連接層將維度升至128維self.dropout = nn.Dropout(p=0.6)self.fc2 = nn.Linear(128,2)# 兩種動作 (取決于action_space,Discrete(2))# 再降維至每一個動作一個維度self.saved_log_probs = []#一個數組,記錄每個時刻的log p(a|s)self.rewards = []#一個數組,記錄每個時刻做完動作后的rewarddef forward(self, x):x = self.fc1(x)x = self.dropout(x)x = F.relu(x)action_scores = self.fc2(x)return F.softmax(action_scores,dim=1)#a[..][0],a[..][1],...a[..][n] 這些進行softmax#求得在狀態x下各個action被執行的概率policy = Policy()optimizer = optim.Adam(policy.parameters(),lr=1e-2)eps = np.finfo(np.float32).eps.item() # 非負的最小值,使得歸一化時分母不為0numpy 筆記:finfo_UQI-LIUWJ的博客-CSDN博客
2.4 選擇動作
def select_action(state):## 選擇動作,這個動作不是根據Q值來選擇,而是使用softmax生成的概率來選# 在policy gradient中,不需要epsilon-greedy,因為概率本身就具有隨機性state = torch.from_numpy(state).float().unsqueeze(0)#print(state.shape) #torch.size([1,4])#通過unsqueeze操作變成[1,4]維的向量probs = policy(state)#Policy的返回結果,在狀態x下各個action被執行的概率m = Categorical(probs) # 生成分布action = m.sample() # 從分布中采樣(根據各個action的概率)#print(m.log_prob(action))# m.log_prob(action)相當于probs.log()[0][action.item()].unsqueeze(0)#換句話說,就是選出來的這個action的概率,再加上log運算policy.saved_log_probs.append(m.log_prob(action))# 即 logP(a_t|s_t,θ)return action.item() # 返回一個元素值'''所以每一次select_action做的事情是,選擇一個合理的action,返回這個action;同時我們當前policy中添加在當前狀態下選擇這個action的概率的log結果'''2.5 Policy 中參數的更新
def finish_episode(ep_reward):R = 0policy_loss = []returns = []for r in policy.rewards[::-1]:R = r + args.gamma * R#相當于是對時刻i而言 Σ(j ∈[i,t)) R^(j-i),也就是之后考慮衰減的獎勵和returns.insert(0,R) # 將R插入到指定的位置0處(折扣獎勵)returns = torch.tensor(returns)#所以returns的位數也和policy一樣print(policy.saved_log_probs)'''一個類似于[tensor([-0.9295], grad_fn=<SqueezeBackward1>),tensor([-0.5822], grad_fn=<SqueezeBackward1>)]的list'''print(returns)#一個類似于tensor([8.6483, 7.7255])的tensorreturns = (returns - returns.mean()) / (returns.std() + eps)# 歸一化for log_prob, R in zip(policy.saved_log_probs,returns):#相當于 對 i ∈[0,len(returns)) 每次取saved_log_probs和returns相同下標的元素policy_loss.append(-log_prob * ep_reward)# 折扣獎勵*logP(a|s)print(policy_loss)'''也是一個類似于[tensor([-0.9295], grad_fn=<SqueezeBackward1>),tensor([-0.5822], grad_fn=<SqueezeBackward1>)]的list'''policy_loss = torch.cat(policy_loss).sum()#torch.cat之后,變成tensor([-0.9295,-0.5822],grad_fn=<CatBackward>)的形式#sum求和,也就是這個episode的總lossoptimizer.zero_grad()policy_loss.backward()optimizer.step()#pytorch深度學習老三樣del policy.rewards[:] # 清空episode 數據del policy.saved_log_probs[:]2.6 main函數
def main():running_reward = 10for i_episode in range(args.episodes):# 采集(訓練)最多1000個序列state, ep_reward = env.reset(),0# ep_reward表示每個episode中的reward#state表示初始化這一個episode的環境state#array([-0.00352001, 0.01611176, -0.00538757, -0.00544052], dtype=float32)for t in range(1,args.steps_per_episode):#一個epsiode里面有幾步action = select_action(state)#根據當前state的結果,按照概率選擇下一步的action#同時我們當前policy中添加在當前狀態下選擇這個action的概率的log結果(后來的梯度上升中用)state, reward, done, _ = env.step(action)#四個返回的內容是state,reward,done(是否重置環境),infoif args.render:env.render()#渲染環境,如果你是再服務器上跑的,只想出結果,不想看動態推桿過程的話,可以設置為Falsepolicy.rewards.append(reward)#選擇這個action后的獎勵,也添加到policy對應的數組中ep_reward += reward#這一個episode總的rewardif done:break'''結束一個episode后,policy中會有兩個等長的數組,一個是獎勵,一個是概率的log結果它們兩兩對齊'''running_reward = 0.05 * ep_reward + (1-0.05) * running_reward#通過這種方式計算加權平均rewardfinish_episode(ep_reward)if i_episode % args.log_interval == 0:print('Episode {}\tLast reward: {:.2f}\tAverage reward: {:.2f}'.format(i_episode, ep_reward, running_reward))if running_reward > env.spec.reward_threshold: # 大于游戲的最大閾值475時,退出游戲print("Solved! Running reward is now {} and ""the last episode runs to {} time steps!".format(running_reward, t))breakif __name__ == '__main__':main()3 和pytorch? 深度學習的區別
可以看出來,主題框架和pytorch 深度學習(如pytorch筆記——簡易回歸問題_UQI-LIUWJ的博客-CSDN博客)是幾乎一樣的,不同的是,那里損失函數使用torch.nn中的一個直接調用的,這里相當于是自己設定,設定在一定程度上依賴于強化學習的獎勵。
然后這里使用了折扣回報代替整體回報,同時我們每采一個episode就進行更新。我們也可以采樣多個episode再進行更新,那樣的話就是我一次性存儲多個episode的獎勵和概率,然后統一計算損失函數
梯度是隨著P(a|s)傳遞的,反向傳播也逆之更新模型各參數
4 結果
做了兩組實驗
一個的更新過程就是一個episode 全是這個episode的獎勵?
可以看到他即使到了1000次也沒有收斂
另一種更新的方法是折扣回報?
?可以看到它在進行700個episode的時候就結束了(平均reward大于475)?
?4 補充說明:離散動作 & 連續動作
- 要輸出離散動作的話,可以加一層 softmax 層來確保說所有的輸出是動作概率,而且所有的動作概率加和為 1。
- 要輸出連續動作的話,一般可以在輸出層這里加一層 tanh,把輸出先限制到[-1,1]之間。拿到這個輸出后,可以根據實際動作的范圍再做縮放
總結
以上是生活随笔為你收集整理的pytorch笔记:policy gradient的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: pytorch 笔记:torch.dis
- 下一篇: Git 笔记 上传文件至github