強化學習原理源碼解讀001:Policy Gradient


目錄

  強化學習中的關鍵概念

  游戲案例

  策略網絡

  策略網絡的訓練

  源碼實現

  效果演示

  參考資料


本文不再維護,請移步最新博客:

https://zhuanlan.zhihu.com/p/408239932

強化學習中的關鍵概念

 

智能體(Agent):也就是我們的機器人,它內部有一個策略網絡,策略網絡接收一個可觀測狀態(observation)作為輸入,產生一個動作(action)作為輸出。

環境(Environment):也就是智能體與之交互的環境,它接收智能體的輸入后,會發生改變,同時會計算智能體動作的獎勵值(reward)。

 返回目錄

 

游戲案例

強化學習技術可以應用在很多領域,比如:內容推薦、廣告投放和機器人控制等等,另外強化學習技術在競技游戲中的應用也非常有效,最知名的就有AlphaGo(DeepMind)、DotaAIOpenAI)和王者榮耀的悟空AI(騰訊)等等。

在本案例中,我們針對https://gym.openai.com/中的一個簡單游戲進行分析

這是一個平衡桿游戲,人控制滑塊左右移動,保證上面木棒不倒下來

https://gym.openai.com/envs/CartPole-v1/

 返回目錄

 

策略網絡

使用了全連接網絡作為策略網絡

self.fc1 = nn.Linear(4, 128)
self.fc2 = nn.Linear(128, 2)

 

 

游戲初始的時候,環境會產生一個初始值(4個值,滑塊的位置,滑塊速度,木棒的角度,木棒尖端的速度)。

策略網絡接收環境的輸入,前饋,得到一個向左和向右的概率向量,依照概率選擇一個動作,執行,如果木棒不會倒,就獎勵1分。

環境接收動作后,發生改變,以此類推,直到桿子的傾斜角度超過一定閾值,游戲結束。

 返回目錄

 

策略網絡的訓練

第一步,收集智能體和環境的交互數據

假設某一個Trajectory中收集一筆數據: 

那么參數為θ的策略網絡產生該Trajectory的概率為:

累計回報值定義為: 

強化學習的目標就是最大化累計回報值的期望值:

 

 

那么,重點就在於計算的梯度值:

 

 

對θ微分時,R(τ)不需要微分,因為τ對應的R(τ)是不會變化的,或者說R(τ)和θ是沒有關系的

由公式,可得

 

 

改為期望的形式:

 

 

使用采樣代替期望值:,其中,N表示數據量

展開 τ :,pθ(s1)大部分情況下都是固定值,可以忽略不計。

 

在本文中,我們每收集一筆數據τ,就更新一次網絡,也就是SGD的方式,那么可以去掉和N有關的項,簡化為:

 

 

同時,可以為R(τ)加一個折扣因子: 

進行梯度上升,讓R越來越大:

 

 

在pytorch實踐中,我們無需手工梯度,只需要定義好損失函數即可:

 

 

PS:這就是policy Gradient的技巧。這里留給讀者一個思考題:既然我們已經知道pytorch無需手動求導,那為什么還要費力先求梯度,然后再還原回去呢?

該代碼明顯就是一個on-policy的方法,因為我們是:先收集數據,然后更新網絡,再收集數據,再更新網絡的方式。

 返回目錄

 

源碼實現

 代碼為

import gym
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.distributions import Categorical
import matplotlib.pyplot as plt
import time
#Hyperparameters
learning_rate = 0.0002
gamma         = 0.98

f_out = open("log.txt","w",encoding="utf-8")
class Policy(nn.Module):
    def __init__(self):
        super(Policy, self).__init__()
        self.data = []
        
        self.fc1 = nn.Linear(4, 128)
        self.fc2 = nn.Linear(128, 2)
        self.optimizer = optim.Adam(self.parameters(), lr=learning_rate)
        
    def forward(self, x):
        x = F.relu(self.fc1(x))
        x = F.softmax(self.fc2(x), dim=0)
        return x
      
    def put_data(self, item):
        self.data.append(item)
        
    def train_net(self):
        R = 0
        loss_prob = 0
        self.optimizer.zero_grad()
        for r, prob in self.data[::-1]:
            R = r + gamma * R
            loss = -torch.log(prob) * R
            loss_prob += loss

            loss.backward()
        # f_out.write(f'{"-" * 50},{loss_sum/len(self.data[::-1])}\n')
        self.optimizer.step()
        self.data = []


def main():
    env = gym.make('CartPole-v1')
    pi = Policy()
    score = 0.0
    x = []
    y = []
    print_interval = 20
    
    
    for n_epi in range(5000):
        s = env.reset()
        done = False
        
        while not done: # CartPole-v1 forced to terminates at 500 step.
            # env.render()
            prob = pi(torch.from_numpy(s).float())
            m = Categorical(prob)
            a = m.sample()
            s_prime, r, done, info = env.step(a.item())
            pi.put_data((r,prob[a]))
            s = s_prime
            score += r
            
        pi.train_net()
        # time.sleep(2)
        if n_epi%print_interval==0 and n_epi!=0:
            print("# of episode :{}, avg score : {}".format(n_epi, score/print_interval))
            x.append(n_epi)
            y.append(score/print_interval)
            f_out.write("# of episode :{}, avg score : {}\n".format(n_epi, score/print_interval))
            score = 0.0
    torch.save(pi, 'model.pkl')
    env.close()
    plt.plot(x,y)
    plt.savefig('res.jpg')
    plt.show()
    
if __name__ == '__main__':
    main()
View Code

 

PS:這個游戲超過500分就是自動結束,橫坐標是學習輪數,縱坐標是智能體的當前能獲取的分數均值

 返回目錄

 

效果演示

下圖是經過100輪訓練的智能體的玩游戲過程,可以看到,很快就會游戲結束

 

 

下圖是經過5000訓練的智能體的玩游戲過程,可以看到,他幾乎都可以玩到滿分

 

演示代碼為:

import gym
import torch
from torch.distributions import Categorical
from REINFORCE import Policy

pi = torch.load('model.pkl')

env = gym.make('CartPole-v1')
for i_episode in range(20):
    observation = env.reset()
    for t in range(10000):
        env.render()
        prob = pi(torch.from_numpy(observation).float())
        m = Categorical(prob)
        action = m.sample()
        observation, reward, done, info = env.step(action.item())
        if done:
            print("失敗,堅持了 {} 個時間步".format(t+1))
            break
env.close()
View Code

 

 返回目錄

 

參考資料

https://github.com/seungeunrho/minimalRL

 

https://www.bilibili.com/video/BV1UE411G78S?from=search&seid=10996250814942853843

 

 返回目錄

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM