強化學習原理源碼解讀003:Actor-Critic和A2C


目錄

  Policy-based框架的缺點

  Valued-based框架的缺點

  Actor-Critic結合

  算法流程

  向Policy Gradient中加入baseline

  Q網絡和V網絡的定義

  A2C (Advantage Actor-Critic)

  A2C損失函數的構建

  源碼實現

  參考資料


在強化學習中,可以分為如下圖所示的兩種框架。基於Policy-based框架的算法有Policy Gradient(Sutton 2000)、PPO、PPO2等;基於Value-based框架的算法有DQN(Mnih 2013)、DDQN等;結合這兩種框架的算法有Actor-Critic(VR Konda 2000在Policy Gradient之后)、A2C、A3C(2016 DeepMind)、Rainbow等。

Policy-based框架的缺點

只使用參數化的策略。通過仿真直接估計累計回報值對actor參數的梯度,並向改進方向更新參數。這種方法的一個可能的缺點是梯度估計量可能有一個大的方差。此外,隨着策略的變化,對新的梯度的估計獨立於過去的估計。因此,沒有“學習”,也就是舊信息的積累和鞏固。

 返回目錄

 

Valued-based框架的缺點

完全依賴於值函數近似。通過學習Bellman方程的近似解,然后有希望規定一個接近最優的策略。這些方法是間接的,因為它們不試圖直接優化策略空間。這種類型的方法可以成功地構造一個值函數的“好的”近似值,但在結果策略的接近最優性方面缺乏可靠的保證。另外對於連續型動作不宜求解。

 返回目錄

 

Actor-Critic結合

Actor-Critic算法的學習過程克服了Policy-based框架下計算得到的回報值方差大的問題,大部分情況下,也可以推廣到任意狀態和動作空間的情況下。

 返回目錄

 

算法流程

 

 

下面將整個算法分解為下面幾個小問題進行詳述:

■向Policy Gradient中加入baseline

■Q網絡和V網絡的定義

■A2C (Advantage Actor-Critic)

■A2C損失函數的構建

 返回目錄

 

向Policy Gradient中加入baseline

 

結合上圖,如果所有的動作都會得到正的回報,會存在一個問題,假設有三個動作可以執行abc:

在理想情況下,做梯度上升,會把采用abc的幾率都拉高,但是他們對應的R是不一樣的,R小的,上升的就小,權重大的就上升的多。因為最終幾率的和等於1,所以上升的多的才會上升,上升的小的會下降。

但是在實際過程中,我們做的是采樣,那就意味着有的動作會采樣不到(有可能是一個很好的動作),那么就會惡性循環,接下來采用這個動作的幾率會越來越小。

 

解決方法:

回報減去一個基礎值baseline,讓權重有正有負

比如b是一個讓回報增加很小的動作(也就是一個比較差的動作),那么他的權重很大程度是小於baseline的,那么梯度上升更新之后,采用b的概率會下降。嵌入baseline后的梯度值如下所示:

當然也可以加入折扣因子:

 返回目錄

 

Q網絡和V網絡的定義

這個b可以使用狀態價值函數V網絡來計算,因為他就是累計回報值這個隨機變量數學期望,紅色方框內相減之后就會有正有負,達到我們想要的效果。

藍色下划線部分是執行了a之后的累計回報值的期望可以由Q網絡計算。

這時需要學習的網絡就有三個:策略網絡、Q網絡和V網絡,如果直接這樣做的話會因為網絡參數過多,導致優化難度變大的問題,A2C算法就解決了這個問題。

 返回目錄

 

A2C (Advantage Actor-Critic)

 

A2C算法指出,我們可以在忍受一定方差的影響的情況下,只估測V,然后用V表示Q

 

所以我們的網絡結構變成:

 返回目錄

 

A2C損失函數的構建

 

 返回目錄

 

源碼實現

這里做了一些簡練:去掉了分別學習目標網絡、去掉了Replay Buffer

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
#Hyperparameters
learning_rate = 0.0002
gamma         = 0.98
n_rollout     = 10

class ActorCritic(nn.Module):
    def __init__(self):
        super(ActorCritic, self).__init__()
        self.data = []
        
        self.fc1 = nn.Linear(4,256)
        self.fc_pi = nn.Linear(256,2)
        self.fc_v = nn.Linear(256,1)
        self.optimizer = optim.Adam(self.parameters(), lr=learning_rate)
        
    def pi(self, x, softmax_dim = 0):
        x = F.relu(self.fc1(x))
        x = self.fc_pi(x)
        prob = F.softmax(x, dim=softmax_dim)
        return prob
    
    def v(self, x):
        x = F.relu(self.fc1(x))
        v = self.fc_v(x)
        return v
    
    def put_data(self, transition):
        self.data.append(transition)
        
    def make_batch(self):
        s_lst, a_lst, r_lst, s_prime_lst, done_lst = [], [], [], [], []
        for transition in self.data:
            s,a,r,s_prime,done = transition
            s_lst.append(s)
            a_lst.append([a])
            r_lst.append([r/100.0])
            s_prime_lst.append(s_prime)
            done_mask = 0.0 if done else 1.0
            done_lst.append([done_mask])
        
        s_batch, a_batch, r_batch, s_prime_batch, done_batch = torch.tensor(s_lst, dtype=torch.float), torch.tensor(a_lst), \
                                                               torch.tensor(r_lst, dtype=torch.float), torch.tensor(s_prime_lst, dtype=torch.float), \
                                                               torch.tensor(done_lst, dtype=torch.float)
        self.data = []
        return s_batch, a_batch, r_batch, s_prime_batch, done_batch
  
    def train_net(self):
        s, a, r, s_prime, done = self.make_batch()
        td_target = r + gamma * self.v(s_prime) * done
        delta = td_target - self.v(s)
        
        pi = self.pi(s, softmax_dim=1)
        pi_a = pi.gather(1,a)
        loss = -torch.log(pi_a) * delta.detach() + F.smooth_l1_loss(self.v(s), td_target.detach())

        self.optimizer.zero_grad()
        loss.mean().backward()
        self.optimizer.step()         
      
def main():  
    env = gym.make('CartPole-v1')
    model = ActorCritic()    
    print_interval = 20
    score = 0.0
    x = []
    y = []

    for n_epi in range(5000):
        done = False
        s = env.reset()
        while not done:
            for t in range(n_rollout):
                prob = model.pi(torch.from_numpy(s).float())
                m = Categorical(prob)
                a = m.sample().item()
                s_prime, r, done, info = env.step(a)
                model.put_data((s,a,r,s_prime,done))
                
                s = s_prime
                score += r
                
                if done:
                    break                     
            
            if score < 500 * print_interval:
                model.train_net()
            else:
                print(score)
            
        if n_epi%print_interval==0 and n_epi!=0:
            print("# of episode :{}, avg score : {:.1f}".format(n_epi, score/print_interval))
            x.append(n_epi)
            y.append(score / print_interval)
            score = 0.0
    env.close()
    plt.plot(x, y)
    plt.savefig('pic_saved/res_A2C.jpg')
    plt.show()

if __name__ == '__main__':
    main()
View Code

橫坐標表示訓練輪數,縱坐標表示智能體得分的能力(滿分500分)

 返回目錄

 

參考資料

https://github.com/seungeunrho/minimalRL

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

paper:Actor-Critic Algorithms

paper:Asynchronous Methods for Deep Reinforcement Learning

 返回目錄

 


免責聲明!

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



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