pytorch笔记:policy gradient
本文參考了?策略梯度PG( Policy Gradient) 的pytorch代碼實(shí)現(xiàn)示例 cart-pole游戲_李瑩斌XJTU的博客-CSDN博客_策略梯度pytorch
在其基礎(chǔ)上添加了注釋和自己的一些理解
1 理論部分
強(qiáng)化學(xué)習(xí)筆記:Policy-based Approach_UQI-LIUWJ的博客-CSDN博客
我們使用其中的框架(在我們后面的實(shí)驗(yàn)中,我們認(rèn)為每次N取1就對參數(shù)進(jìn)行一次更新)
同時獎勵R不是使用,而是使用折扣回報(bào)?
?2? 代碼部分
2.1 導(dǎo)入庫 & 參數(shù)處理
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環(huán)境創(chuàng)建
python 筆記 :Gym庫 (官方文檔筆記)_UQI-LIUWJ的博客-CSDN博客
env = gym.make('CartPole-v1') #創(chuàng)建一個推車桿的gym環(huán)境 env.seed(args.seed) #設(shè)置隨機(jī)種子 torch.manual_seed(args.seed) # 策略梯度算法方差很大,設(shè)置隨機(jī)以保證復(fù)現(xiàn)性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 創(chuàng)建Policy類
輸入某一時刻的狀態(tài)(也就是一個四維向量),輸出采取各個動作的概率(二維向量)
class Policy(nn.Module):## 離散空間采用了 softmax policy 來參數(shù)化策略def __init__(self):super(Policy,self).__init__()self.fc1 = nn.Linear(4,128)#一開始是一個[1,4]維的Tensor,表示狀態(tài)#先使用一個全連接層將維度升至128維self.dropout = nn.Dropout(p=0.6)self.fc2 = nn.Linear(128,2)# 兩種動作 (取決于action_space,Discrete(2))# 再降維至每一個動作一個維度self.saved_log_probs = []#一個數(shù)組,記錄每個時刻的log p(a|s)self.rewards = []#一個數(shù)組,記錄每個時刻做完動作后的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] 這些進(jìn)行softmax#求得在狀態(tài)x下各個action被執(zhí)行的概率policy = Policy()optimizer = optim.Adam(policy.parameters(),lr=1e-2)eps = np.finfo(np.float32).eps.item() # 非負(fù)的最小值,使得歸一化時分母不為0numpy 筆記:finfo_UQI-LIUWJ的博客-CSDN博客
2.4 選擇動作
def select_action(state):## 選擇動作,這個動作不是根據(jù)Q值來選擇,而是使用softmax生成的概率來選# 在policy gradient中,不需要epsilon-greedy,因?yàn)楦怕时旧砭途哂须S機(jī)性state = torch.from_numpy(state).float().unsqueeze(0)#print(state.shape) #torch.size([1,4])#通過unsqueeze操作變成[1,4]維的向量probs = policy(state)#Policy的返回結(jié)果,在狀態(tài)x下各個action被執(zhí)行的概率m = Categorical(probs) # 生成分布action = m.sample() # 從分布中采樣(根據(jù)各個action的概率)#print(m.log_prob(action))# m.log_prob(action)相當(dāng)于probs.log()[0][action.item()].unsqueeze(0)#換句話說,就是選出來的這個action的概率,再加上log運(yùn)算policy.saved_log_probs.append(m.log_prob(action))# 即 logP(a_t|s_t,θ)return action.item() # 返回一個元素值'''所以每一次select_action做的事情是,選擇一個合理的action,返回這個action;同時我們當(dāng)前policy中添加在當(dāng)前狀態(tài)下選擇這個action的概率的log結(jié)果'''2.5 Policy 中參數(shù)的更新
def finish_episode(ep_reward):R = 0policy_loss = []returns = []for r in policy.rewards[::-1]:R = r + args.gamma * R#相當(dāng)于是對時刻i而言 Σ(j ∈[i,t)) R^(j-i),也就是之后考慮衰減的獎勵和returns.insert(0,R) # 將R插入到指定的位置0處(折扣獎勵)returns = torch.tensor(returns)#所以returns的位數(shù)也和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):#相當(dāng)于 對 i ∈[0,len(returns)) 每次取saved_log_probs和returns相同下標(biāo)的元素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深度學(xué)習(xí)老三樣del policy.rewards[:] # 清空episode 數(shù)據(jù)del policy.saved_log_probs[:]2.6 main函數(shù)
def main():running_reward = 10for i_episode in range(args.episodes):# 采集(訓(xùn)練)最多1000個序列state, ep_reward = env.reset(),0# ep_reward表示每個episode中的reward#state表示初始化這一個episode的環(huán)境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)#根據(jù)當(dāng)前state的結(jié)果,按照概率選擇下一步的action#同時我們當(dāng)前policy中添加在當(dāng)前狀態(tài)下選擇這個action的概率的log結(jié)果(后來的梯度上升中用)state, reward, done, _ = env.step(action)#四個返回的內(nèi)容是state,reward,done(是否重置環(huán)境),infoif args.render:env.render()#渲染環(huán)境,如果你是再服務(wù)器上跑的,只想出結(jié)果,不想看動態(tài)推桿過程的話,可以設(shè)置為Falsepolicy.rewards.append(reward)#選擇這個action后的獎勵,也添加到policy對應(yīng)的數(shù)組中ep_reward += reward#這一個episode總的rewardif done:break'''結(jié)束一個episode后,policy中會有兩個等長的數(shù)組,一個是獎勵,一個是概率的log結(jié)果它們兩兩對齊'''running_reward = 0.05 * ep_reward + (1-0.05) * running_reward#通過這種方式計(jì)算加權(quán)平均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? 深度學(xué)習(xí)的區(qū)別
可以看出來,主題框架和pytorch 深度學(xué)習(xí)(如pytorch筆記——簡易回歸問題_UQI-LIUWJ的博客-CSDN博客)是幾乎一樣的,不同的是,那里損失函數(shù)使用torch.nn中的一個直接調(diào)用的,這里相當(dāng)于是自己設(shè)定,設(shè)定在一定程度上依賴于強(qiáng)化學(xué)習(xí)的獎勵。
然后這里使用了折扣回報(bào)代替整體回報(bào),同時我們每采一個episode就進(jìn)行更新。我們也可以采樣多個episode再進(jìn)行更新,那樣的話就是我一次性存儲多個episode的獎勵和概率,然后統(tǒng)一計(jì)算損失函數(shù)
梯度是隨著P(a|s)傳遞的,反向傳播也逆之更新模型各參數(shù)
4 結(jié)果
做了兩組實(shí)驗(yàn)
一個的更新過程就是一個episode 全是這個episode的獎勵?
可以看到他即使到了1000次也沒有收斂
另一種更新的方法是折扣回報(bào)?
?可以看到它在進(jìn)行700個episode的時候就結(jié)束了(平均reward大于475)?
?4 補(bǔ)充說明:離散動作 & 連續(xù)動作
- 要輸出離散動作的話,可以加一層 softmax 層來確保說所有的輸出是動作概率,而且所有的動作概率加和為 1。
- 要輸出連續(xù)動作的話,一般可以在輸出層這里加一層 tanh,把輸出先限制到[-1,1]之間。拿到這個輸出后,可以根據(jù)實(shí)際動作的范圍再做縮放
總結(jié)
以上是生活随笔為你收集整理的pytorch笔记:policy gradient的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: pytorch 笔记:torch.dis
- 下一篇: Git 笔记 上传文件至github