本文是强化学习入门系列的第六篇,将介绍一种有别于前面Q-learning这些基于价值的算法——策略梯度。
即策略梯度,是一种Policy-based的方法。不同于Q-Learning等基于value的方法,策略梯度不需要计算value function,直接计算出随机策略,直接输出action。policy gradient 可以在一个连续分布上选取 action。策略梯度除了可以解决连续性问题,也适用于分幕式问题。分幕式可以理解为离散型问题。比如我们玩下棋游戏,棋子的上下左右移动这一动作是离散的,而在自动驾驶场景里面,汽车速度的变化是连续的,这也就对应连续型问题。
而在策略梯度算法中,两种问题考虑的性能指标有所不同:
我们知道 π ( a ∣ s ) \pi(a|s) π(a∣s) 表示状态s下选择动作a的概率,不同策略 π \pi π 下不同的状态,其状态价值函数 V π V_{\pi} Vπ 不同;同一状态下不同动作的动作价值函数 Q π Q_{\pi} Qπ 也不同。 G t G_t Gt 表示奖励的总和。
Q π ( s t , a t ) = E [ G t ∣ S t = s t , A t = a t ] V π ( s t , a t ) = E A [ Q π ( s t , A ) ] = ∑ a π ( a ∣ s t ) Q π ( s t , a ) \\ Q_{\pi}(s_t,a_t)=E[G_t|S_t=s_t,A_t=a_t] \\ V_{\pi}(s_t,a_t)=E_A[Q_{\pi}(s_t,A)]=\sum_a\pi(a|s_t)Q_{\pi}(s_t,a) Qπ(st,at)=E[Gt∣St=st,At=at]Vπ(st,at)=EA[Qπ(st,A)]=a∑π(a∣st)Qπ(st,a)
策略梯度使用神经网络来近似状态价值函数,我们引入神经网络的参数 θ \theta θ, θ \theta θ 其实就是决定了策略 π \pi π 。 Q ( s t , a ) Q(s_t,a) Q(st,a) 是考虑所有策略 π \pi π 后的可能的下一状态和动作的奖励的期望。又a在求和过程中被消掉,因此目标函数定义如下:
J ( θ ) = V π ( s ; θ ) = ∑ a π ( a ∣ s ; θ ) Q π ( s , a ) J(\theta) = V_{\pi}(s;\theta)=\sum_a\pi(a|s;\theta)Q_{\pi}(s,a) J(θ)=Vπ(s;θ)=a∑π(a∣s;θ)Qπ(s,a)
那么问题就变成如何学习出一个最优的 θ \theta θ 使得目标函数最大?
先对目标函数求梯度:
∇ J ( θ ) = ∑ a ∂ π ( a ∣ s ; θ ) ∂ θ Q π ( s , a ) = ∑ a π ( a ∣ s ; θ ) 1 π ( a ∣ s ; θ ) ∂ π ( a ∣ s ; θ ) ∂ θ Q π ( s , a ) = ∑ a π ( a ∣ s ; θ ) ∂ ln π ( a ∣ s ; θ ) ∂ θ Q π ( s , a ) \begin{aligned} \nabla J(\theta)=&\sum_a \dfrac{\partial \pi(a|s;\theta)}{\partial \theta} Q_{\pi}(s,a)\\ =&\sum_a \pi(a|s;\theta) \dfrac{1}{\pi(a|s;\theta)} \dfrac{\partial \pi(a|s;\theta)}{\partial \theta} Q_{\pi}(s,a) \\ =&\sum_a \pi(a|s;\theta) \dfrac{\partial \ln\pi(a|s;\theta)}{\partial \theta}Q_{\pi}(s,a) \\ \end{aligned} ∇J(θ)===a∑∂θ∂π(a∣s;θ)Qπ(s,a)a∑π(a∣s;θ)π(a∣s;θ)1∂θ∂π(a∣s;θ)Qπ(s,a)a∑π(a∣s;θ)∂θ∂lnπ(a∣s;θ)Qπ(s,a)
这里面的变化是仔细看能发现是依据 ∇ ln x = ∇ x x \nabla\ln x=\dfrac{\nabla x}{x} ∇lnx=x∇x。策略 π \pi π是一个概率密度函数,自然有 ∑ a π ( a ∣ s ; θ ) = 1 \sum_a\pi(a|s;\theta)=1 ∑aπ(a∣s;θ)=1 。所以概率密度乘以右边项再对a求累加,就相当于对右边项求期望,所以有:
∇ J ( θ ) = E a ∼ π ( ⋅ ∣ s ; θ ) [ ∂ ln π ( a ∣ s ; θ ) ∂ θ Q π ( s , a ) ] = E a ∼ π ( ⋅ ∣ s ; θ ) [ ∇ ln π ( a ∣ s ; θ ) Q π ( s , a ) ] \begin{aligned} \nabla J(\theta) =& E_{a \sim \pi(\cdot|s;\theta)}[\dfrac{\partial \ln\pi(a|s;\theta)}{\partial \theta} Q_{\pi}(s,a)]\\ =& E_{a \sim \pi(\cdot|s;\theta)}[\nabla\ln\pi(a|s;\theta) Q_{\pi}(s,a)] \end{aligned} ∇J(θ)==Ea∼π(⋅∣s;θ)[∂θ∂lnπ(a∣s;θ)Qπ(s,a)]Ea∼π(⋅∣s;θ)[∇lnπ(a∣s;θ)Qπ(s,a)]
采用蒙特卡洛方法(随机样本采样),从策略 π \pi π 的概率密度函数中随机采样 a ^ \hat{a} a^ ,可以直接计算。
算法流程(梯度上升):
神经网络如何搭建?
因为最后输出的策略 π \pi π 是一个概率密度,所以神经网络的输出层需加一个softmax处理。
假设现在智能体和环境交互比如玩一局游戏,观察到一段轨迹(Trajectory) τ = s 1 , a 1 , r 1 , . . . , s t , a t , r t \tau=s_1,a_1,r_1,...,s_t,a_t,r_t τ=s1,a1,r1,...,st,at,rt,每一个轨迹也有一个发生概率,假设agent有一个参数 θ \theta θ ,决定了其玩游戏的策略,在给定 θ \theta θ 下,轨迹的概率
p θ ( τ ) = p ( s 1 ) π θ ( a 1 ∣ s 1 ) p ( s 2 ∣ s 1 , a 1 ) . . . = p ( s 1 ) ∏ t = 1 T π θ ( a t ∣ s t ) p ( s t + 1 ∣ s t , a t ) \begin{aligned} p_{\theta}(\tau)=&p(s_1)\pi_{\theta}(a_1|s_1)p(s_2|s_1,a_1)...\\ =&p(s_1)\prod_{t=1}^T \pi_{\theta}(a_t|s_t)p(s_{t+1}|s_t,a_t) \end{aligned} pθ(τ)==p(s1)πθ(a1∣s1)p(s2∣s1,a1)...p(s1)t=1∏Tπθ(at∣st)p(st+1∣st,at)
同时,不同的 θ \theta θ 下会有不同的奖励 R θ R_{\theta} Rθ ,而我们要考虑的就是奖励 R 的期望,我们的目标就在于近似这一期望。
R ( τ ) = ∑ t T r t R ‾ = ∑ τ R ( τ ) p θ ( τ ) = E τ ∼ p θ ( τ ) [ R ( τ ) ] R(\tau)=\sum_t^T r_t \\ \overline R=\sum_{\tau}R(\tau)p_{\theta}(\tau)=E_{\tau \sim p_{\theta}(\tau)}[R(\tau)] R(τ)=t∑TrtR=τ∑R(τ)pθ(τ)=Eτ∼pθ(τ)[R(τ)]
因为我们想要的是奖励越大越好,所以要最大化这个期望,而要最大化我们则采用梯度上升。先对目标函数求梯度:
∇ R ‾ = ∑ τ R ( τ ) ∇ p θ ( τ ) = ∑ τ R ( τ ) p θ ( τ ) ∇ p θ ( τ ) p θ ( τ ) = ∑ τ p θ ( τ ) R ( τ ) ∇ ln p θ ( τ ) = E τ ∼ p θ ( τ ) [ R ( τ ) ∇ ln p θ ( τ ) ] \begin{aligned} \nabla\overline R=& \sum_{\tau}R(\tau) \nabla p_{\theta}(\tau) \\ =& \sum_{\tau}R(\tau) p_{\theta}(\tau) \dfrac{\nabla p_{\theta}(\tau)}{p_{\theta}(\tau)} \\ =& \sum_{\tau}p_{\theta}(\tau) R(\tau) \nabla \ln p_{\theta}(\tau) \\ =& E_{\tau\sim p_{\theta}(\tau)}[R(\tau) \nabla \ln p_{\theta}(\tau)] \end{aligned} ∇R====τ∑R(τ)∇pθ(τ)τ∑R(τ)pθ(τ)pθ(τ)∇pθ(τ)τ∑pθ(τ)R(τ)∇lnpθ(τ)Eτ∼pθ(τ)[R(τ)∇lnpθ(τ)]
不难发现,因为 p θ ( τ ) p_{\theta}(\tau) pθ(τ) 是一个概率密度函数,所以式子最终可以写成右边项的期望形式。实际上,这个期望是没办法求的,我们可以通过 n n n 次随机采样,得到很多轨迹,从而来近似这一期望(其实也就是蒙特卡洛方法)。所以式子可以进一步写成:
∇ R ‾ = 1 N ∑ n = 1 N R ( τ n ) ∇ ln p θ ( τ n ) = 1 N ∑ n = 1 N R ( τ n ) ∇ ( ln p ( s 1 ) + ∑ t = 1 T ln p θ ( a t ∣ s t ) + ∑ t = 1 T ln p ( s t + 1 ∣ s t , a t ) ) = 1 N ∑ n = 1 N R ( τ n ) ∇ ∑ t = 1 T ln p θ ( a t ∣ s t ) = 1 N ∑ t = 1 T ∑ n = 1 N R ( τ n ) ∇ ln p θ ( a t ∣ s t ) \begin{aligned} \nabla\overline R=&\dfrac{1}{N}\sum_{n=1}^N R(\tau^n) \nabla \ln p_{\theta}(\tau^n)\\ =& \dfrac{1}{N}\sum_{n=1}^N R(\tau^n) \nabla(\ln p(s_1) + \sum_{t=1}^T \ln p_{\theta}(a_t|s_t)+ \sum_{t=1}^T\ln p(s_{t+1}|s_t,a_t)) \\ =& \dfrac{1}{N}\sum_{n=1}^N R(\tau^n) \nabla \sum_{t=1}^T \ln p_{\theta}(a_t|s_t) \\ =& \dfrac{1}{N} \sum_{t=1}^T \sum_{n=1}^N R(\tau^n) \nabla \ln p_{\theta}(a_t|s_t) \end{aligned} ∇R====N1n=1∑NR(τn)∇lnpθ(τn)N1n=1∑NR(τn)∇(lnp(s1)+t=1∑Tlnpθ(at∣st)+t=1∑Tlnp(st+1∣st,at))N1n=1∑NR(τn)∇t=1∑Tlnpθ(at∣st)N1t=1∑Tn=1∑NR(τn)∇lnpθ(at∣st)
梯度更新:
θ ← θ + α ∇ R ‾ \theta \leftarrow \theta+\alpha\nabla \overline R θ←θ+α∇R
先介绍两种不同的更新方法:
蒙特卡洛(Monte-Carlo),属于回合更新。当算法完成一个回合后,每个时刻的奖励 r t r_t rt都可以获取到,这样就可以计算未来总奖励 G t G_t Gt。完成一次回合才learn一次。
时序差分(Temporal-Difference),属于单步更新,比如Q-learning。每个步骤都learn一下。
前面我们在分幕式问题中近似状态价值函数的时候,使用了蒙特卡洛方法,其实就是这个REINFORCE(也称 蒙特卡洛策略梯度)算法。我们下面仔细讲讲。REINFORCE是属于回合更新的方法,也是一个策略梯度算法。
蒙特卡洛策略梯度的算法流程如下:
其实就是使用 G t G_t Gt 来近似 Q π ( s t , a t ) Q_{\pi}(s_t,a_t) Qπ(st,at)。 G t G_t Gt 就是奖励的总和,这个我们是可以通过采样得到的。具体来说,就是先获取每一时刻的reward,再计算未来的总奖励(看上图伪代码)。所以梯度的近似可以进一步写成:
∇ J ( θ ) = E a ∼ π ( ⋅ ∣ s ; θ ) [ G t ∇ ln π ( a ∣ s ; θ ) ] \begin{aligned} \nabla J(\theta) =& E_{a \sim \pi(\cdot|s;\theta)}[G_t\nabla\ln\pi(a|s;\theta)] \end{aligned} ∇J(θ)=Ea∼π(⋅∣s;θ)[Gt∇lnπ(a∣s;θ)]
伪代码中引入了折扣因子 γ \gamma γ 是为了兼容非分幕式的任务。对于分幕式的任务, γ = 1 \gamma=1 γ=1,其实也可以看做是连续任务的一个特例。
我们将策略梯度再进一步推广,给动作价值函数 Q π ( s , a ) Q_{\pi}(s,a) Qπ(s,a) 加入一个baseline b ( s ) b(s) b(s),这个baseline可以是任意函数。
∇ J ( θ ) = ∑ a π ( a ∣ s ; θ ) ∇ ln π ( a ∣ s ; θ ) [ Q π ( s , a ) − b ( s ) ] \nabla J(\theta)=\sum_a \pi(a|s;\theta) \nabla \ln\pi(a|s;\theta)[Q_{\pi}(s,a)-b(s)] \\ ∇J(θ)=a∑π(a∣s;θ)∇lnπ(a∣s;θ)[Qπ(s,a)−b(s)]
为什么要引入这个baseline?
这是因为,如果我们得到的奖励总是正的,那更新的时候概率都要上升,只不过上升的程度有大有小。但是这是理想情况下的,在实际中采样时,某时刻只能采样到几个动作,某个动作没被采样到。因为其它动作被采样到,所以概率就上升,但那个没被采样到的动作,它的概率就会下降。这显然是不对的。这个时候我们希望奖励有正有负就好了。
那让总奖励减去一个baseline,可以变得有正有负。如果采样一个动作使得得到的 G t G_t Gt 大于baseline,梯度更新的时候就让它的概率上升;如果 G t G_t Gt 小于baseline,就让它的概率下降。而且,类似梯度赌博机算法在更新的时候减去奖励的均值,这样减去一个baseline,不会影响更新的期望,但会影响更新的方差,可以帮助算法收敛的更快些。
所以带baseline的REINFORCE算法的梯度改写为:
∇ J ( θ ) = E a ∼ π ( ⋅ ∣ s ; θ ) [ ( G t − b ( s ) ) ∇ ln π ( a ∣ s ; θ ) ] \begin{aligned} \nabla J(\theta) =& E_{a \sim \pi(\cdot|s;\theta)}[(G_t-b(s))\nabla\ln\pi(a|s;\theta)] \end{aligned} ∇J(θ)=Ea∼π(⋅∣s;θ)[(Gt−b(s))∇lnπ(a∣s;θ)]
伪代码如下:
策略梯度算法,不同于Q-Learning等基于价值的方法,策略梯度不需要计算价值函数,直接计算出随机策略,直接输出action。策略梯度除了可以解决连续性问题,也适用于分幕式问题。策略梯度在更新策略参数时虽然可能需要近似价值动作函数,但其在动作选择上是不需要动作价值函数的估计值的。
参考