深度强化学习(五):策略梯度的方法

一、理论思想

在此之前,我们讨论了值函数的方法,把优化的重点放在了值函数上,得到了最优值函数,即可得到最优策略。事实上,策略梯度方法的思想则更加简单和直接,即将值函数表示为策略参数的某个函数,便可以求出值函数关于策略参数的梯度,并使参数沿着梯度上升的方向更新。其数学实现和推导过程如下:
强化学习的目标是找到最大化长期回报期望的策略:
其中表示轨迹的回报。
用表示前面提到的目标函数,将轨迹的期望回报展开,可以得到
对公式求导,可以得到
又通过变换,有

故有\begin{aligned} \nabla_{\theta} J(\theta) &=\int_{\tau \sim \pi_{\theta}(\tau)} \pi_{\theta}(\tau) \nabla_{\theta} \log \pi_{\theta}(\tau) r(\tau) \mathrm{d} \tau\\ &=E_{\tau \sim \pi_{\theta}(\tau)}\left[\nabla_{\theta} \log \pi_{\theta}(\tau) r(\tau)\right] \end{aligned}

\pi_{\theta}(\boldsymbol{\tau})=\pi_{\theta}\left(\mathbf{s}_{0}, \mathbf{a}_{0}, \ldots, \mathbf{s}_{T}, \mathbf{a}_{T}\right)=p\left(\mathbf{s}_{0}\right) \prod_{t=0}^{T} \pi_{\theta}\left(\mathbf{a}_{t} | \mathbf{s}_{t}\right) p\left(\mathbf{s}_{t+1} | \mathbf{s}_{t}, \mathbf{a}_{t}\right)

\begin{aligned} \nabla_{\theta} \log \pi(\tau) &=\nabla_{\theta} \log \left[p\left(s_{0}\right) \prod_{t=0}^{T} \pi_{\theta}\left(a_{t} | s_{t}\right) p\left(s_{t+1} | s_{t}, a_{t}\right)\right] \\ &=\nabla_{\theta}\left[\log p\left(s_{0}\right)+\sum_{t=0}^{T} \log \pi_{\theta}\left(a_{t} | s_{t}\right)+\sum_{t=0}^{T} \log p\left(s_{t+1} | s_{t}, a_{t}\right)\right] \\ &=\sum_{t=0}^{T} \nabla_{\theta} \log \pi_{\theta}\left(a_{t} | s_{t}\right) \end{aligned}
因此\begin{aligned} \nabla_{\theta} J(\theta) &=E_{\tau \sim \pi_{\theta}(\tau)}\left[\left(\sum_{t=0}^{T} \nabla_{\theta} \log \pi_{\theta}\left(a_{i, t} | s_{i, t}\right)\left(\sum_{t=0}^{T} r\left(s_{i, t}, a_{i, t}\right)\right]\right.\right.\\ &\approx\frac{1}{N} \sum_{i=1}^{N}\left[\sum_{t=0}^{T} \nabla_{\theta} \log \pi_{\theta}\left(a_{i, t} | s_{i, t}\right)\left(\sum_{t=0}^{T} r\left(s_{i, t}, a_{i, t}\right)\right]\right.\end{aligned}
以上就是梯度的求解,剩下的即是要进行参数更新,这两步可归结如下:
(1)计算
(2)
基本原理如以上所示,但仍存在一些问题。首先,需要策略梯度乘以所有时刻的回报值总和,而这是与马尔可夫性相违背的,即当前时刻之前的回报值不应该计算在梯度中,则公式改写为:\nabla_{\theta} J(\theta)=\frac{1}{N} \sum_{i=1}^{N} \sum_{t=0}^{T}\left[\nabla_{\theta} \log \pi_{\theta}\left(a_{i, t} | s_{i, t}\right)\left(\sum_{t^{\prime}=t}^{T} r\left(s_{i, t^{\prime}}, a_{i, t^{\prime}}\right)\right)\right]
其次,策略梯度法更像是加权版的最大似然优化法。“权重”将直接影响梯度的更新量,这样就会带来以下两个问题:1)如果计算得出的序列回报数值较大,那么对应的参数更新量就会比较大,这样优化就可能出现一定波动,这些波动很可能影响优化效果;2)在一些问题中,环境给予的回报始终为正, 那么不论决策如何, 最终累积的长期回报值都是一个正数。换句话说,我们会增强所有的策略,只是对于实际效果并不好的策略,我们为其提升的幅度会有所降低。而初衷是提高能最大化长期回报策略的概率,降低无法最大化长期回报策略的概率。
为了实现这个目标,可以调整权重的数值和范围,一个简单的方法就是给所有时刻的长期累积回报减去一个偏移量, 这个偏移量也被称为Baseline ,用变量b表示,于是公式就变为:\nabla_{\theta} J(\theta)=\frac{1}{N} \sum_{i=1}^{N} \sum_{t=0}^{T}\left[\nabla_{\theta} \log \pi_{\theta}\left(a_{i, t} | s_{i, t}\right)\left(\sum_{t^{\prime}=t}^{T} r\left(s_{i, t^{\prime}}, a_{i, t^{\prime}}\right)-b_{i, t^{\prime}}\right)\right]
其中为同一起始点的不同序列在同一时刻的长期回报均值,这样,所有时刻的权重均值变为0 ,就会存在权重为正或为负的行动。
事实上,引入偏移量并不会使原来的计算有偏,即:\begin{aligned} E\left[\nabla_{\theta} \log \pi_{\theta}(\tau) b\right] &=\int_{\tau \sim \pi_{\theta}(\tau)} \pi_{\theta}(\tau) \nabla_{\theta} \log \pi_{\theta}(\tau) b \mathrm{d} \tau \\ &=\int_{\tau \sim \pi_{\theta}(\tau)} \nabla_{\theta} \pi_{\theta}(\tau) b \mathrm{d} \tau \\ &=b \int_{\tau \sim \pi_{\theta}(\tau)} \nabla_{\theta} \pi_{\theta}(\tau) \mathrm{d} \tau \\ &=b \nabla_{\theta} \int_{\tau \sim \pi_{\theta}(\tau)} \pi_{\theta}(\tau) \mathrm{d} \tau \\ &=b \nabla_{\theta} 1 \\ &=0 \end{aligned}

二、AC、A2C、A3C 算法

2.1、Actor-Critic 算法

偏差与方差的平衡
回看一下梯度公式:\nabla_{\theta} J(\theta)=\frac{1}{N} \sum_{i=1}^{N} \sum_{t=0}^{T}\left[\nabla_{\theta} \log \pi_{\theta}\left(a_{i, t} | s_{i, t}\right)\left(\sum_{t^{\prime}=t}^{T} r\left(s_{i, t^{\prime}}, a_{i, t^{\prime}}\right)-b_{i}\right)\right]
用轨迹的回报表示整个序列的价值,这个表示是无偏的,但是在真实的训练过程中,由于交互次数的有限,方差相对较大,为了模型的稳定,可以牺牲一定的偏差来使方差变小,Actor-Critic 算法即是这样的一种方法。

Actor-Critic 算法流程

AC 算法的主要特点就是用一个独立的模型估计轨迹的长期回报,而不再直接使用轨迹的真实回报,在估计时使用模型估计轨迹价值,在更新时利用轨迹的回报得到目标价值,然后将模型的估计值和目标值进行比较,从而改进模型。使用TD-Error 估计轨迹的回报,此时梯度公式变为:
由于引入了状态价值模型, 算法整体包含了两个模型,一个是策略模型,一个是价值模型,所以这个算法被称为Actor-Critic , 其中Actor 表示策略模型, Critic 表示价值模型。

2.2、Advantage Actor-Critic(A2C) 算法

A2C算法直接使用优势函数估计轨迹的回报,由此梯度公式变为:

这样的话就需要有两个网络分别计算状态-动作价值Q和状态价值V,此时的Critic变为估计状态价值V的网络。因此Critic网络的损失变为实际的状态价值和估计的状态价值的平方损失。

A2C算法结构

2.3、Asynchronous Advantage Actor-Critic (A3C)算法

A3C 算法使用了多步回报估计法,即,这个方法可以在训练早期更快地提升价值模型,为了增加模型的探索性,模型的目标函数中加入了策略的熵。由于熵可以衡量概率分布的不确定性,所以我们希望模型的情尽可能大一些,这样模型就可以拥有更好的多样性。这样,完整的策略梯度计算公式就变为\nabla_{\theta} J(\theta)=\frac{1}{T} \sum_{t}^{T} \nabla_{\theta} \log \pi_{\theta}\left(\boldsymbol{a}_{t} | s_{t} \right)\left(\sum_{i=1}^{N} \gamma^{i-1} \boldsymbol{r}_{t+1}+v\left(\boldsymbol{s}_{t+N}\right)-v\left(\boldsymbol{s}_{t}\right)\right)+\beta \nabla_{\theta}\mathrm{H}\left(\pi_{\theta} \left(\boldsymbol{s}_{t}\right)\right)
其中为策略的熵在目标中的权重。

A3C与A2C的更新区别

A3C 和A2C 更新流程的对比如上图所示。可以看出,在的A3C中,每个线程各自完成参数更新值的计算,并异步完成参数的同步操作;而A2C 将决策和训练的任务集中到一处,其他进程只负责环境模拟的工作,A2C 在并发性和系统简洁性上都优于A3C。

三、案例实践

CartPole 车杆游戏:游戏里面有一个小车,上有竖着一根杆子。小车需要左右移动来保持杆子竖直。如果杆子倾斜的角度大于15°,那么游戏结束。小车也不能移动出一个范围(中间到两边各2.4个单位长度)。动作:左移,右移。状态:车的位置,杆子的角度,车速,角速度。奖励:左移或者右移小车的action之后,env都会返回一个+1的reward。到达200个reward之后,游戏也会结束。

CartPole

以下使用A2C方法实现CartPole游戏过程。

  1. 包的调用及参数设置,采用pytorch框架。
import numpy as np
import gym
import os
import math
import random
import pandas as pd
import matplotlib.pyplot as plt
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.autograd import Variable
import torch.optim as optim

MAX_EPISODE = 500
REWARD_THRESHOLD = 200
MAX_EP_STEPS = 5000
SAMPLE_NUMS = 30
RENDER = False
GAMMA = 0.9  # reward discount
LR_A = 0.001 # learning rate for actor
LR_C = 0.001 # learning rate for critic

env = gym.make("CartPole-v0")
init_state = env.reset()
N_F = env.observation_space.shape[0]
N_A = env.action_space.n
  1. Actor与Critic网络的搭建,均采用两层全连接神经网络
class Actor_net(nn.Module):
    def __init__(self, n_features,n_actions):
        super(Actor_net,self).__init__()
        self.l1 = nn.Linear(n_features,40)
        self.l2 = nn.Linear(40,n_actions)           
    def forward(self,x):
        out1 = F.relu(self.l1(x))
        out2 = F.log_softmax(self.l2(out1),dim=1)
        return out2

class Critic_net(nn.Module):
    def __init__(self, n_input,n_output):
        super(Critic_net,self).__init__()
        self.l1 = nn.Linear(n_input,40)
        self.l2 = nn.Linear(40,n_output)        
    def forward(self,x):
        out1 = F.relu(self.l1(x))
        out2 = F.relu(self.l2(out1))
        return out2
  1. 辅助函数。包括网络的搭建,观测值的采样,环境的重置等,另外是损失因子的设定,比较简明,不予详述。
def init_env(env,actor_net,critic_net,sample_nums,init_state):
    states = []
    actions = []
    rewards = []
    is_done = False
    final_r = 0
    state = init_state

    for i in range(sample_nums):
        states.append(state)
        log_softmax_action = actor_net(Variable(torch.Tensor([state])))
        softmax_action = torch.exp(log_softmax_action)
        action = np.random.choice(N_A,p=softmax_action.cpu().data.numpy()[0])
        one_hot_action = [int(k==action) for k in range(N_A)]
        next_state,reward,done,_ = env.step(action)
        
        actions.append(one_hot_action)
        rewards.append(reward)
        final_state = next_state
        state = next_state
        if done:
            is_done = True
            state = env.reset()
            break
    if not is_done:
        final_r = critic_net(Variable(torch.Tensor([final_state]))).cpu().data.numpy()
    return states,actions,rewards,final_r,state

def discount_reward(r,gamma,final_r):
    discount_r = np.zeros_like(r)
    running_add = final_r
    for t in reversed(range(0,len(r))):
        running_add = running_add*gamma +r[t]
        discount_r[t] = running_add
    return discount_r
  1. 主函数。其各部分功能与流程如下图所示。


actor = Actor_net(n_features=N_F,n_actions=N_A)
actor_optim = optim.Adam(actor.parameters(),lr=LR_A)
critic = Critic_net(n_input=N_F,n_output=1)
critic_optim = optim.Adam(critic.parameters(),lr=LR_C)

steps = []
test_results = []

for step in range(MAX_EP_STEPS):
    states,actions,rewards,final_r,current_state = init_env(env,actor,critic,SAMPLE_NUMS,init_state)
    init_state = current_state
    actions_var = Variable(torch.Tensor(actions).view(-1,N_A))
    states_var = Variable(torch.Tensor(states).view(-1,N_F))

    #训练策略网络
    actor_optim.zero_grad()
    log_softmax_actions = actor(states_var)
    vs = critic(states_var).detach()
    qs = Variable(torch.Tensor(discount_reward(rewards,GAMMA,final_r)))

    advantages = qs - vs
    actor_loss = -torch.mean(torch.sum(log_softmax_actions*actions_var,1)*advantages)
    actor_loss.backward()
    nn.utils.clip_grad_norm_(actor.parameters(),0.5)
    actor_optim.step()

    #训练值网络
    critic_optim.zero_grad()
    target_values = qs
    values = critic(states_var)
    critic_loss = nn.MSELoss()(values,target_values)
    critic_loss.backward()
    nn.utils.clip_grad_norm_(actor.parameters(),0.5)
    critic_optim.step()

    if (step+1) % 10 == 0:
        result = 0
        state = env.reset()
        for test_epi in range(10):
            state=env.reset()
            for test_step in range(200):
                softmax_action = torch.exp(actor(Variable(torch.Tensor([state]))))

                action = np.argmax(softmax_action.data.numpy()[0])
                next_state,reward,done,_ = env.step(action)
                result += reward
                state = next_state
                if done:
                    break
        print("step:",step+1,"test result:",result/10.0)
        steps.append(step+1)
        test_results.append(result/10)

plt.figure(1)
plt.plot(steps,test_results)
plt.grid(True)
plt.xlabel('episodes')
plt.ylabel('reward')
plt.show()

下图为实验中的奖励值变化情况,可见在经过1000余次的迭代之后即达到一个较稳定的收敛值。

奖励值变化

[1] Maxim Lapan. Deep Reinforcement Learning Hands-on. Packt Publishing 2018.
[2] 冯超著 强化学习精要:核心算法与TensorFlow实现. ----北京:电子工业出版社 2018.
[3] https://www.jianshu.com/p/428b640046aa

一点浩然气,千里快哉风。 ----苏轼《水调歌头·黄州快哉亭赠张偓佺》

你可能感兴趣的:(深度强化学习(五):策略梯度的方法)