文章目录
策略梯度是一种基于策略的算法,相比于DQN一类的基于价值的算法,它会直接显式的学习一个目标策略。梯度下降的基础知识可以参考之前的博客强化学习(六)策略梯度和《动手学强化学习》部分内容。
Reference
[1] 《动手学强化学习》 https://hrl.boyuai.com/
[2] David Silver: https://www.youtube.com/watch?v=KHZVXao4qXs&t=4609s
我们假设目标策略 π θ ( a ∣ s ) \pi_\theta(a|s) πθ(a∣s)是一种随机策略,并且处处可微, θ \theta θ为对应参数。可以通过神经网络或线性模型对目标策略进行建模。输入某个状态,输出动作的概率分布。
(1)目标函数
我们期望获得一个最优策略,能够最大化策略在环境中的期望回报。
J ( θ ) = E [ V π θ ( s ) ] J(\theta)=E[V^{\pi_\theta}(s)] J(θ)=E[Vπθ(s)]
根据贝尔曼方程,我们可以用Q函数表示目标函数
J ( θ ) = ∑ s ∈ S d ( s ) ∑ a ∈ A π θ ( a ∣ s ) Q π θ ( s , a ) J(\theta)=\sum_{s \in S} d(s) \sum_{a \in A} \pi_\theta(a|s) Q^{\pi_\theta}(s,a) J(θ)=s∈S∑d(s)a∈A∑πθ(a∣s)Qπθ(s,a)
(2)梯度
我们希望通过梯度下降(上升)优化策略,策略梯度可以表示为
∇ θ = α ∇ J ( θ ) ∇ J ( θ ) = ∑ s ∈ S d ( s ) ∑ a ∈ A ∇ π θ ( a ∣ s ) Q π θ ( s , a ) = E π θ [ Q π θ ( s , a ) ∇ log π θ ( a ∣ s ) ] \nabla \theta = \alpha \nabla J(\theta) \\ \nabla J(\theta) = \sum_{s \in S} d(s) \sum_{a \in A} \nabla \pi_\theta(a|s) Q^{\pi_\theta}(s,a)=E_{\pi_\theta}[Q^{\pi_\theta}(s,a) \nabla \log \pi_\theta(a|s)] ∇θ=α∇J(θ)∇J(θ)=s∈S∑d(s)a∈A∑∇πθ(a∣s)Qπθ(s,a)=Eπθ[Qπθ(s,a)∇logπθ(a∣s)]
因此我们可以将 Q π θ ( s , a ) log π θ ( a ∣ s ) Q^{\pi_\theta}(s,a) \log \pi_\theta(a|s) Qπθ(s,a)logπθ(a∣s)作为损失值反向传递优化模型。
1. REINFORCE
1.1 Basic
上文我们提到可以将 Q π θ ( s , a ) log π θ ( a ∣ s ) Q^{\pi_\theta}(s,a) \log \pi_\theta(a|s) Qπθ(s,a)logπθ(a∣s)作为损失值反向传递优化模型。我们在强化学习(五)价值函数拟合中学到可以通过MC或TD近似Q或V函数。REINFORCE算法就是采用MC方法,利用轨迹的累计回报预估Q函数,所以策略梯度改变成为:
∇ θ = α ∇ J ( θ ) ∇ J ( θ ) = E π θ [ G t ∇ log π θ ( a ∣ s ) ] \nabla \theta = \alpha \nabla J(\theta) \\ \nabla J(\theta) =E_{\pi_\theta}[G_t \nabla \log \pi_\theta(a|s)] ∇θ=α∇J(θ)∇J(θ)=Eπθ[Gt∇logπθ(a∣s)]
其中G_t是一条完整轨迹获得的累积奖励。REINFORCE
是一种在线学习方法,采样到的轨迹数据只能使用一次。同时因为使用累计回报 G t G_t Gt预测Q函数,所以算法的性能有一定程度的波动(高方差)。
1.2 Code
import gym
import torch
import torch.nn.functional as F
import numpy as np
import matplotlib.pyplot as plt
from tqdm import tqdm
import rl_utils
首先定义策略网络PolicyNet
,输入是某个状态,输出则是该状态下的动作概率分布。
class PolicyNet(torch.nn.Module):
def __init__(self, state_dim, hidden_dim, action_dim):
super(PolicyNet, self).__init__()
self.fc1 = torch.nn.Linear(state_dim, hidden_dim)
self.fc2 = torch.nn.Linear(hidden_dim, action_dim)
def forward(self, x):
x = F.relu(self.fc1(x))
return F.softmax(self.fc2(x), dim=1) # dim=1,对每行使用softmax
接着定义REINFORCE
算法,take_action
和update
是算法最重要的两个部分。在