一、策略梯度算法推导以及解释
1.1 背景
设 π θ ( s ) \pi_{\theta }(s) πθ(s)是一个有网络参数 θ \theta θ的actor,然后我们让这个actor和环境(environment)互动或者说去玩一场游戏,在这个游戏中actor会观测环境处于的某种状态s,然后根据这个环境的状态做出一定的动作a(action)来应对环境的变化,从而得到一定的奖励r(reward)
下面是一个使用神经网络搭建的actor,设他的参数是
θ
\theta
θ
图片来自:理解策略梯度算法
设
τ
=
{
s
1
,
a
1
,
r
1
,
s
2
,
a
2
,
r
2
,
.
.
.
,
s
T
,
a
T
,
r
T
,
E
n
d
}
\tau = \{ s_{1}, a_{1}, r_{1},s_{2}, a_{2}, r_{2},...,s_{T}, a_{T}, r_{T},End \}
τ={s1,a1,r1,s2,a2,r2,...,sT,aT,rT,End}
对应一场游戏或者和环境互动得到的一个回合(episode)
具体的解释就是: actor在时间t=1时观测到环境的状态
s
1
s_{1}
s1,为了应对这个环境的状态,actor做出动作
a
1
a_{1}
a1,从而得到奖励
r
1
r_{1}
r1,因为我们做出了一个动作
a
1
a_{1}
a1,此时会引发环境发生变化或者环境自己变化,环境的状态到达
s
2
s_{2}
s2,actor又会根据这个状态继续做出动作,得到奖励,在这个过程中,actor根据状态做出的动作不一定是对的。对于错的动作,就要给出一个负的奖励,也就从奖励变成了惩罚。游戏会一直玩下去,直到actor灭亡或者环境终止。
1.2 一个小例子
例子:太空侵略者
在这个例子里面actor可以采取的动作有三种:开火(fire),向右移动(right),向左移动(left)。也就是遇到任何一个状态,actor可以选择的动作只能从这三个动作里面选择一个。
在上图中actor看到状态:
s
1
s_{1}
s1,做出的动作是向右移动:
a
1
a_{1}
a1,因为这里是击杀一个外星人才会有奖励,动作向右移动不会击杀外星人,那么获得的奖励
r
1
r_{1}
r1就是0,此时环境发生变化,actor看到环境的状态是游戏画面
s
2
s_{2}
s2,然后actor做出动作
a
2
a_{2}
a2:开火,因为此时击杀了一个外星人,得到的奖励
r
2
r_{2}
r2是5.
当所有的外星人被消灭完或者actor被外星人杀死,这个游戏就会结束,也就是一个回合(eposide)结束.
1.3 算法推导以及解释
根据一个回合
τ
=
{
s
1
,
a
1
,
r
1
,
s
2
,
a
2
,
r
2
,
.
.
.
,
s
T
,
a
T
,
r
T
,
E
n
d
}
\tau = \{ s_{1}, a_{1}, r_{1},s_{2}, a_{2}, r_{2},...,s_{T}, a_{T}, r_{T},End \}
τ={s1,a1,r1,s2,a2,r2,...,sT,aT,rT,End}
我们要极大化的目标是一个回合累计的总的奖励也就是优化目标:
R
θ
(
τ
)
=
∑
t
=
1
T
r
t
(1)
R_{\theta }(\tau)=\sum_{t=1}^{T} r_{t}\tag{1}
Rθ(τ)=t=1∑Trt(1)
下面是很重要的一个点
由于actor所处的环境具有一定的随机性,而且actor根据环境所作出的动作也是具有一定的随机性,我们要优化的目标函数是每个回合总的奖励(total reward)的期望值。
Question 1: 上面所说的环境的随机性是什么意思?
答: 假设把实际生活中的一个人当做一个actor,这个actor生活的环境里面也是有很大的随机性的,比如,突然刮了一场大风,风又突然把一棵大树吹断了,不巧,actor刚好路过,断了的大树突然把actor砸死了,猪脚actor卒,游戏结束,得到的总的奖励(total reward)是0。如果没有遇到上面的随机情况,actor说不定会遇到一个伯乐,然后各种升值加薪,迎娶白富美,走上人生巅峰,然后自然死亡,actor消亡之后,游戏(aposide)结束,获取的总的奖励很大。
你看因为环境的随机性,这个actor可以有两种完全不同的结局。
Question 2: actor本身的随机性又是什么意思?
答: 还拿上面的例子做解释,由于风太大,把树刮断了,大树快要砸着actor,actor由于以前没有经历过这种事情,又因为发生的突然,actor慌了,这种情况下,actor吓懵了,做出了一个在原地不动的动作,然后被大树砸死了,猪脚卒,游戏结束,没有奖励。另外一种情况就是,actor做出朝着一个方向跑的动作,在千钧一发之际,actor疯狂加速,他活了下来。随后遇到了伯乐,各种升职加薪,迎娶白富美,走上人生巅峰。。。。
你看,因为actor自身的随机性,也会有完全不同的结局发生
上面两种不同的结局,获取的一个回合总的奖励(total reward)相差很大,我们使用其中的任何一种来更新actor的网络参数都是不合适的,正式由于这种随机性,可以使用期望值更加精准的来更新actor的参数 θ \theta θ
设 R θ − = ∑ τ R ( τ ) ∗ P ( τ ∣ θ ) (2) \overset{-}{R_{\theta }} = \sum_{\tau }R(\tau )*P(\tau |\theta ) \tag{2} Rθ−=τ∑R(τ)∗P(τ∣θ)(2)是所有的eposide( τ \tau τ)所得到期望值。 R ( τ ) = ∑ t = 1 T r t R(\tau )=\sum_{t=1}^{T} r_{t} R(τ)=∑t=1Trt是回合 τ \tau τ的总的奖励, P ( τ ∣ θ ) P(\tau |\theta ) P(τ∣θ)表示在给定actor的网络参数 θ \theta θ,eposide( τ \tau τ)出现的概率。
上面的公式(2)求期望会遇到一个问题,假如 τ \tau τ 有无穷多个要怎么办?全部一一列举或者使用求积分来计算根本不靠谱,无法实现而且浪费时间。
Question 3: 如何逼近公式(2)?
答:采样。 比如我们可以得到
N
N
N个eposides,
τ
1
,
τ
1
,
.
.
.
,
τ
N
\tau_{1},\tau_{1},...,\tau_{N}
τ1,τ1,...,τN,我们就可以得到:
R
θ
−
=
∑
τ
R
(
τ
)
∗
P
(
τ
∣
θ
)
≈
1
N
∑
n
=
1
N
R
(
τ
n
)
(3)
\overset{-}{R_{\theta }} = \sum_{\tau }R(\tau )*P(\tau |\theta ) \approx \frac{1}{N}\sum_{n=1}^{N}R(\tau_{n}) \tag{3}
Rθ−=τ∑R(τ)∗P(τ∣θ)≈N1n=1∑NR(τn)(3)
在公式(3)里面我们假设了每个
τ
\tau
τ出现的概率是一样的,都是
1
N
\frac{1}{N}
N1。这样就简化了目标函数,并且达到了计算机可以实现的要求。但是,这样的目标函数里面没有参数
θ
\theta
θ,所以无法更新actor,还要再使用新的方法。
1.4如何优化actor?
首先给粗我们实际中使用的目标函数:注意这里是极大化,实际中还要转化为极小化。加负号就行了
R
=
1
N
∑
n
=
1
N
∑
t
=
1
T
n
R
(
τ
n
)
∗
l
o
g
p
(
a
t
n
∣
s
t
n
,
θ
)
R = \frac{1}{N}\sum_{n=1}^{N}\sum_{t=1}^{T_{n}}R(\tau _{n})*logp(a_{t}^{n}|s_{t}^{n}, \theta )
R=N1n=1∑Nt=1∑TnR(τn)∗logp(atn∣stn,θ)
公式解释:
N
N
N是表示采样的个数,
R
(
τ
n
)
R(\tau _{n})
R(τn)是第
n
n
n条样本的所获得累计的奖励,
p
(
a
t
n
∣
s
t
n
,
θ
)
p(a_{t}^{n}|s_{t}^{n}, \theta )
p(atn∣stn,θ)表示在状态
s
t
n
s_{t}^{n}
stn时采取动作
a
t
n
a_{t}^{n}
atn的概率。
但是这是和理论是有出入的,我么要根据理论内容进行反推出在实际操作中我们使用的目标函数,也就是损失。
下面开始理论的推导:
R
θ
−
=
∑
τ
R
(
τ
)
∗
P
(
τ
∣
θ
)
\overset{-}{R_{\theta }} = \sum_{\tau }R(\tau )*P(\tau |\theta )
Rθ−=τ∑R(τ)∗P(τ∣θ)
要优化actor,就要调整actor的网络参数
θ
\theta
θ,因为我们的目的是要极大化奖励,这里使用的梯度上升,其实因为深度学习框架tensorflow,pytorch等等没有极大化的优化程序,到后面还要将极大化转化为极小化。
因为actor是使用神经网络搭建的,我们来求导优化。
▽
R
θ
−
=
∑
τ
R
(
τ
)
∗
▽
P
(
τ
∣
θ
)
(4)
\bigtriangledown \overset{-}{R_{\theta }} = \sum_{\tau }R(\tau )*\bigtriangledown P(\tau |\theta )\tag{4}
▽Rθ−=τ∑R(τ)∗▽P(τ∣θ)(4)
由于
R
(
τ
)
R(\tau )
R(τ)中没有参数
θ
\theta
θ,因为我们不要求
R
(
τ
)
R(\tau )
R(τ)是可微的,任意的数值都是可以的。
▽
R
θ
−
=
∑
τ
R
(
τ
)
∗
▽
P
(
τ
∣
θ
)
=
∑
τ
R
(
τ
)
∗
P
(
τ
∣
θ
)
∗
▽
P
(
τ
∣
θ
)
P
(
τ
∣
θ
)
(5)
\bigtriangledown \overset{-}{R_{\theta }} = \sum_{\tau }R(\tau )*\bigtriangledown P(\tau |\theta )= \sum_{\tau }R(\tau )*P(\tau |\theta )*\frac{\bigtriangledown P(\tau |\theta )}{P(\tau |\theta )} \tag{5}
▽Rθ−=τ∑R(τ)∗▽P(τ∣θ)=τ∑R(τ)∗P(τ∣θ)∗P(τ∣θ)▽P(τ∣θ)(5)
在公式(4)的右端乘上
P
(
τ
∣
θ
)
P(\tau |\theta )
P(τ∣θ),然后再除以
P
(
τ
∣
θ
)
P(\tau |\theta )
P(τ∣θ),就可以得到公式(5)。
继续对公式(5)进行化简,利用的是对数的求导公式
d
l
n
(
f
(
x
)
)
d
x
=
1
f
(
x
)
∗
d
f
(
x
)
d
x
\frac{dln(f(x))}{dx}=\frac{1}{f(x)}*\frac{df(x)}{dx}
dxdln(f(x))=f(x)1∗dxdf(x)就可以得到下面的公式
▽
R
θ
−
=
∑
τ
R
(
τ
)
∗
p
(
τ
∣
θ
)
∗
▽
l
o
g
p
(
τ
∣
θ
)
(6)
\bigtriangledown \overset{-}{R_{\theta }} =\sum_{\tau }R(\tau )*p(\tau |\theta )*\bigtriangledown log p(\tau |\theta ) \tag{6}
▽Rθ−=τ∑R(τ)∗p(τ∣θ)∗▽logp(τ∣θ)(6)
我们前面说过,要使用采样的方法将理论转化为计算机可以实现的情况。这里我们依然使用采样的方法,来数值逼近公式(6),我们令公式(6)中的
p
(
τ
∣
θ
)
=
1
N
p(\tau |\theta )=\frac{1}{N}
p(τ∣θ)=N1 ,再修改一下求和号,就得到了下面的公式,根据大数定律,
▽
R
θ
−
=
1
N
∑
n
=
1
N
R
(
τ
n
)
∗
▽
l
o
g
p
(
τ
∣
θ
)
(7)
\bigtriangledown \overset{-}{R_{\theta }} =\frac{1}{N}\sum_{n=1}^{N}R(\tau _{n})*\bigtriangledown log p(\tau |\theta )\tag{7}
▽Rθ−=N1n=1∑NR(τn)∗▽logp(τ∣θ)(7)
N表示采样得到的N个样本,公式(7)和公式(3)对比一下就可以看到,公式(3)里面没有actor的参数
θ
\theta
θ,因此无法更新参数,然而,公式(7)里面就引入了actor的参数
θ
\theta
θ,可以更新网络的参数。
其实这里还有一个很复杂的问题,那就是如何计算 p ( τ ∣ θ ) p(\tau |\theta ) p(τ∣θ)
接下来我们利用链式法则来计算 p ( τ ∣ θ ) p(\tau |\theta ) p(τ∣θ),由于状态之间的转移具有马尔可夫性,也就是下一个状态的发生仅和上一个状态有关,比如状态 s n + 1 s_{n+1} sn+1的发生仅和状态 s n s_{n} sn有关,和状态 s n s_{n} sn之前的状态无关。
所以
p
(
τ
∣
θ
)
=
p
(
s
1
,
a
1
,
r
1
,
s
2
,
a
2
,
r
2
,
.
.
.
,
s
T
,
a
T
,
r
T
∣
θ
)
=
p
(
s
1
)
p
(
a
1
∣
s
1
,
θ
)
p
(
r
1
,
s
2
∣
s
1
,
a
1
)
p
(
a
2
∣
s
2
,
θ
)
p
(
r
2
,
s
3
∣
s
2
,
a
2
)
.
.
.
p
(
a
T
∣
s
t
,
θ
)
p
(
r
T
∣
s
T
,
a
T
)
=
p
(
s
1
)
∏
t
=
1
T
p
(
a
t
∣
s
t
,
θ
)
p
(
r
t
,
s
t
+
1
∣
s
t
,
a
t
)
(8)
p(\tau |\theta )=p(s_{1}, a_{1}, r_{1},s_{2}, a_{2}, r_{2},...,s_{T}, a_{T}, r_{T}|\theta )\\=p(s_{1})p(a_{1}|s_{1},\theta )p(r_{1},s_{2}|s_{1}, a_{1})p(a_{2}|s_{2},\theta )p(r_{2},s_{3}|s_{2}, a_{2})...p(a_{T}|s_{t},\theta)p(r_{T}|s_{T},a_{T})\\=p(s_{1})\prod_{t=1}^{T}p(a_{t}|s_{t},\theta )p(r_{t},s_{t+1}|s_{t},a_{t})\tag{8}
p(τ∣θ)=p(s1,a1,r1,s2,a2,r2,...,sT,aT,rT∣θ)=p(s1)p(a1∣s1,θ)p(r1,s2∣s1,a1)p(a2∣s2,θ)p(r2,s3∣s2,a2)...p(aT∣st,θ)p(rT∣sT,aT)=p(s1)t=1∏Tp(at∣st,θ)p(rt,st+1∣st,at)(8)
对公式8两边取自然对数,于是得:
l
o
g
p
(
τ
∣
θ
)
=
l
o
g
p
(
s
1
)
+
∑
t
=
1
T
l
o
g
p
(
a
t
∣
s
t
,
θ
)
+
l
o
g
p
(
r
t
,
s
t
+
1
∣
s
t
,
a
t
)
(9)
logp(\tau |\theta )=logp(s_{1})+\sum_{t=1}^{T}logp(a_{t}|s_{t},\theta )+logp(r_{t},s_{t+1}|s_{t},a_{t})\tag{9}
logp(τ∣θ)=logp(s1)+t=1∑Tlogp(at∣st,θ)+logp(rt,st+1∣st,at)(9)
对公式9关于
θ
\theta
θ求导得
▽
l
o
g
p
(
τ
∣
θ
)
=
▽
(
l
o
g
p
(
s
1
)
+
∑
t
=
1
T
l
o
g
p
(
a
t
∣
s
t
,
θ
)
+
l
o
g
p
(
r
t
,
s
t
+
1
∣
s
t
,
a
t
)
)
=
∑
t
=
1
T
▽
l
o
g
p
(
a
t
∣
s
t
,
θ
)
(10)
\bigtriangledown logp(\tau |\theta )=\bigtriangledown (logp(s_{1})+\sum_{t=1}^{T}logp(a_{t}|s_{t},\theta )+logp(r_{t},s_{t+1}|s_{t},a_{t}))\\=\sum_{t=1}^{T}\bigtriangledown logp(a_{t}|s_{t},\theta ) \tag{10}
▽logp(τ∣θ)=▽(logp(s1)+t=1∑Tlogp(at∣st,θ)+logp(rt,st+1∣st,at))=t=1∑T▽logp(at∣st,θ)(10)
因为是对
θ
\theta
θ求导数,
将公式10带入到公式7,于是就有:
▽
R
θ
−
=
1
N
∑
n
=
1
N
R
(
τ
n
)
∗
▽
l
o
g
p
(
τ
∣
θ
)
=
1
N
∑
n
=
1
N
∑
t
=
1
T
n
R
(
τ
n
)
▽
l
o
g
p
(
a
t
∣
s
t
,
θ
)
(11)
\bigtriangledown \overset{-}{R_{\theta }} =\frac{1}{N}\sum_{n=1}^{N}R(\tau _{n})*\bigtriangledown log p(\tau |\theta )\\=\frac{1}{N}\sum_{n=1}^{N}\sum_{t=1}^{T_{n}}R(\tau _{n})\bigtriangledown logp(a_{t}|s_{t},\theta )\tag{11}
▽Rθ−=N1n=1∑NR(τn)∗▽logp(τ∣θ)=N1n=1∑Nt=1∑TnR(τn)▽logp(at∣st,θ)(11)
到这里,根据公式(11)我们就可以反推出我们实际操作中优化的目标函数是:
R
θ
−
=
1
N
∑
n
=
1
N
R
(
τ
n
)
∗
l
o
g
p
(
τ
∣
θ
)
=
1
N
∑
n
=
1
N
∑
t
=
1
T
n
R
(
τ
n
)
l
o
g
p
(
a
t
∣
s
t
,
θ
)
\overset{-}{R_{\theta }} =\frac{1}{N}\sum_{n=1}^{N}R(\tau _{n})*log p(\tau |\theta )\\=\frac{1}{N}\sum_{n=1}^{N}\sum_{t=1}^{T_{n}}R(\tau _{n})logp(a_{t}|s_{t},\theta )
Rθ−=N1n=1∑NR(τn)∗logp(τ∣θ)=N1n=1∑Nt=1∑TnR(τn)logp(at∣st,θ)
还有一非常重要的一点就是:极大化下面的两个目标函数(公式12和13)得到的效果是一样的。
R
θ
−
=
∑
τ
R
(
τ
)
∗
P
(
τ
∣
θ
)
=
∑
τ
R
(
τ
)
p
(
s
1
)
∏
t
=
1
T
p
(
a
t
∣
s
t
,
θ
)
p
(
r
t
,
s
t
+
1
∣
s
t
,
a
t
)
(12)
\overset{-}{R_{\theta }} = \sum_{\tau }R(\tau )*P(\tau |\theta )\\=\sum_{\tau }R(\tau )p(s_{1})\prod_{t=1}^{T}p(a_{t}|s_{t},\theta )p(r_{t},s_{t+1}|s_{t},a_{t})\tag{12}
Rθ−=τ∑R(τ)∗P(τ∣θ)=τ∑R(τ)p(s1)t=1∏Tp(at∣st,θ)p(rt,st+1∣st,at)(12)
R
1
θ
−
=
∑
τ
R
(
τ
)
∏
t
=
1
T
p
(
a
t
∣
s
t
,
θ
)
(13)
\overset{-}{R1_{\theta }} =\sum_{\tau }R(\tau )\prod_{t=1}^{T}p(a_{t}|s_{t},\theta )\tag{13}
R1θ−=τ∑R(τ)t=1∏Tp(at∣st,θ)(13)
这两个目标函数在数值上只是相差了一个和 θ \theta θ无关的常数,因此在使用梯度上升方法时效果是一样的。因为对一个常数求导得到的导数是0。
我们可以看到上面推导出了两种不同形式的目标函数,一个带有对数函数,一个没有。
对于公式13的解释:
如果
R
(
τ
)
R(\tau )
R(τ)是大于0的,因为我们要极大化奖励,优化的方向就会朝着增大概率
p
(
a
t
∣
s
t
)
p(a_{t}|s_{t})
p(at∣st)进行,如果
R
(
τ
)
R(\tau )
R(τ)小于0,就会降低
p
(
a
t
∣
s
t
)
p(a_{t}|s_{t})
p(at∣st),只有这样才可以逐步增大总的奖励。
Question 4:将目标函数转化为对数形式的好处是什么?
答:下面引用李宏毅老师的强化学习课程里面的例子来解释。
▽
R
θ
−
=
1
N
∑
n
=
1
N
R
(
τ
n
)
∗
▽
l
o
g
p
(
τ
∣
θ
)
=
1
N
∑
n
=
1
N
∑
t
=
1
T
n
R
(
τ
n
)
▽
l
o
g
p
(
a
t
∣
s
t
,
θ
)
\bigtriangledown \overset{-}{R_{\theta }} =\frac{1}{N}\sum_{n=1}^{N}R(\tau _{n})*\bigtriangledown log p(\tau |\theta )\\=\frac{1}{N}\sum_{n=1}^{N}\sum_{t=1}^{T_{n}}R(\tau _{n})\bigtriangledown logp(a_{t}|s_{t},\theta )
▽Rθ−=N1n=1∑NR(τn)∗▽logp(τ∣θ)=N1n=1∑Nt=1∑TnR(τn)▽logp(at∣st,θ)
在这个公式中,
▽
l
o
g
p
(
a
t
∣
s
t
,
θ
)
=
▽
p
(
a
t
∣
s
t
,
θ
)
p
(
a
t
∣
s
t
,
θ
)
\bigtriangledown logp(a_{t}|s_{t},\theta )=\frac{\bigtriangledown p(a_{t}|s_{t},\theta )}{p(a_{t}|s_{t},\theta )}
▽logp(at∣st,θ)=p(at∣st,θ)▽p(at∣st,θ)
那么为什么要除去
p
(
a
t
∣
s
t
,
θ
)
?
p(a_{t}|s_{t},\theta )?
p(at∣st,θ)?
假如在采样得到的样本里面,状态s出现在
τ
13
,
τ
15
,
τ
17
,
τ
33
\tau_{13},\tau_{15},\tau_{17},\tau_{33}
τ13,τ15,τ17,τ33中
在
τ
13
\tau_{13}
τ13里,当看到状态s,采取动作a,总的奖励
R
(
τ
13
)
=
2
R(\tau_{13})=2
R(τ13)=2
在
τ
15
\tau_{15}
τ15里,当看到状态s,采取动作b,总的奖励
R
(
τ
13
)
=
1
R(\tau_{13})=1
R(τ13)=1
在
τ
17
\tau_{17}
τ17里,当看到状态s,采取动作b,总的奖励
R
(
τ
13
)
=
1
R(\tau_{13})=1
R(τ13)=1
在
τ
33
\tau_{33}
τ33里,当看到状态s,采取动作b,总的奖励
R
(
τ
13
)
=
1
R(\tau_{13})=1
R(τ13)=1
从上面的采样的数据可以看到,
p
(
b
∣
s
,
θ
)
>
p
(
a
∣
s
,
θ
)
p(b|s,\theta)>p(a|s,\theta)
p(b∣s,θ)>p(a∣s,θ),但是由于看到状态s采取动作a在一个eposide结束时得到的奖励比在看到状态s采取动作b得到的奖励要多,所我们除去
p
(
a
t
∣
s
t
,
θ
)
p(a_{t}|s_{t},\theta )
p(at∣st,θ)可以起到加权的效果,就像上面的小例子,因为
p
(
b
∣
s
,
θ
)
>
p
(
a
∣
s
,
θ
)
p(b|s,\theta)>p(a|s,\theta)
p(b∣s,θ)>p(a∣s,θ),除去
p
(
b
∣
s
,
θ
)
p(b|s,\theta)
p(b∣s,θ)和
p
(
a
∣
s
,
θ
)
p(a|s,\theta)
p(a∣s,θ)会使
▽
l
o
g
p
(
a
∣
s
,
θ
)
\bigtriangledown logp(a|s,\theta )
▽logp(a∣s,θ)相对增大,而
▽
l
o
g
p
(
b
∣
s
,
θ
)
\bigtriangledown logp(b|s,\theta )
▽logp(b∣s,θ)相对减小。
二、两个小技巧
2.1、增加一个baseline使得采样得到的 R ( τ ) R(\tau) R(τ)有正有负。
Question 5:为什么要让
R
(
τ
)
R(\tau)
R(τ)有正有负?
答:上面我们说过,如果
R
(
τ
)
>
0
R(\tau)>0
R(τ)>0,
p
(
a
t
∣
s
t
)
p(a_{t}|s_{t})
p(at∣st)会增加,反之若
R
(
τ
)
<
0
R(\tau)<0
R(τ)<0,
p
(
a
t
∣
s
t
)
p(a_{t}|s_{t})
p(at∣st)会减小。
例子: 假设我们采样得到4个
τ
\tau
τ,这4个
τ
\tau
τ均满足
R
(
τ
)
>
0
R(\tau)>0
R(τ)>0,分别设为1,2,4,5,因为这4个的total reward均大于0,对应的
p
(
a
t
∣
s
t
)
p(a_{t}|s_{t})
p(at∣st)会增加,而那些没有被采样到的策略出现的概率就会减小。比如还有一个
τ
ˉ
\bar{\tau }
τˉ,
R
(
τ
ˉ
)
=
3
R(\bar{\tau })=3
R(τˉ)=3,3>2>1,但是由于没有采样到
τ
ˉ
\bar{\tau }
τˉ而造成出现在
τ
ˉ
\bar{\tau }
τˉ中的策略的概率减小,这是显然不合理的,因此,我们引入一个baseline,对于那些不够显著的
R
(
τ
)
R(\tau)
R(τ),可以起到不更新的作用。
比如,我们可以取
b
=
1
+
2
+
4
+
5
4
=
3
b=\frac{1+2+4+5}{4}=3
b=41+2+4+5=3,将
b
b
b带入到公式11便得到:
▽
R
θ
−
=
1
N
∑
n
=
1
N
(
R
(
τ
n
)
−
b
)
∗
▽
l
o
g
p
(
τ
∣
θ
)
=
1
N
∑
n
=
1
N
∑
t
=
1
T
n
(
R
(
τ
n
)
−
b
)
▽
l
o
g
p
(
a
t
∣
s
t
,
θ
)
(14)
\bigtriangledown \overset{-}{R_{\theta }} =\frac{1}{N}\sum_{n=1}^{N}(R(\tau _{n})-b)*\bigtriangledown log p(\tau |\theta )\\=\frac{1}{N}\sum_{n=1}^{N}\sum_{t=1}^{T_{n}}(R(\tau _{n})-b)\bigtriangledown logp(a_{t}|s_{t},\theta )\tag{14}
▽Rθ−=N1n=1∑N(R(τn)−b)∗▽logp(τ∣θ)=N1n=1∑Nt=1∑Tn(R(τn)−b)▽logp(at∣st,θ)(14)
2.2、引入折扣因子 γ < 1 \gamma<1 γ<1
引入则扣因子之后,目标函数化为
▽
R
θ
−
=
1
N
∑
n
=
1
N
∑
t
=
1
T
n
(
∑
t
1
=
t
T
n
γ
t
1
−
t
r
t
1
n
−
b
)
▽
l
o
g
p
(
a
t
∣
s
t
,
θ
)
\bigtriangledown \overset{-}{R_{\theta }} =\frac{1}{N}\sum_{n=1}^{N}\sum_{t=1}^{T_{n}}(\sum_{t1=t}^{T_{n}}\gamma^{t1-t}r_{t1}^{n}-b)\bigtriangledown logp(a_{t}|s_{t},\theta )
▽Rθ−=N1n=1∑Nt=1∑Tn(t1=t∑Tnγt1−trt1n−b)▽logp(at∣st,θ)
Question 6:为什么引入折扣因子?
答: 折扣因子体现了actor重视当前奖励
r
t
r_{t}
rt和未来奖励
r
t
+
1
,
.
.
.
,
r
T
r_{t+1},...,r_{T}
rt+1,...,rT的程度,
γ
\gamma
γ越接近0,说明actor越是不重视未来奖励,越接近1,越重视。
2.3如何将奖励的期望极大化转化为深度学习框架常用的极小化
我们来看下面的公式
m
a
x
R
θ
−
=
1
N
∑
n
=
1
N
R
(
τ
n
)
∗
l
o
g
p
(
τ
n
∣
θ
)
max \overset{-}{R_{\theta }} =\frac{1}{N}\sum_{n=1}^{N}R(\tau _{n})*log p(\tau_{n} |\theta )
maxRθ−=N1n=1∑NR(τn)∗logp(τn∣θ)
因为深度学习框架没有极大化的优化函数,我们在上式两边同时加一个负号“-”将极大化转化为极小化,这一步也将对数函数转化为深度学习框架里面经常使用的交叉熵函数(在下面的程序里面会看到)。
在上式两端加负号“-”就变为下式:
m
i
n
−
R
θ
−
=
1
N
∑
n
=
1
N
R
(
τ
n
)
∗
(
−
l
o
g
p
(
τ
n
∣
θ
)
)
min -\overset{-}{R_{\theta }} =\frac{1}{N}\sum_{n=1}^{N}R(\tau _{n})*(-log p(\tau_{n} |\theta ))
min−Rθ−=N1n=1∑NR(τn)∗(−logp(τn∣θ))
到了这里, − l o g p ( τ n ∣ θ ) -log p(\tau_{n} |\theta ) −logp(τn∣θ)这里就已经可以转化为深度学习经常使用的交叉熵函数了。
三、实际案例
import gym
import tensorflow as tf
import numpy as np
import random
from collections import deque
# Hyper Parameters
GAMMA = 0.95 # 折扣因子
LEARNING_RATE=0.01 #学习率
class Policy_Gradient():
def __init__(self, env):
# init some parameters
self.time_step = 0
self.state_dim = env.observation_space.shape[0]#用一个向量表示一个状态,因此需要获取这个向量的维度
self.action_dim = env.action_space.n#是动作的个数
self.ep_obs, self.ep_as, self.ep_rs = [], [], []#用来存储一个eposide的所有的状态或者说是观测值,动作,还有奖励
self.create_softmax_network()
# Init session
self.session = tf.InteractiveSession()
self.session.run(tf.global_variables_initializer())
def create_softmax_network(self):
# network weights
#下面开始搭建actor的神经网络
W1 = self.weight_variable([self.state_dim, 20])#
b1 = self.bias_variable([20])
W2 = self.weight_variable([20, self.action_dim])#输出的最后一个维度是动作的个数,然后依据概率分布选择状态对应的动作
b2 = self.bias_variable([self.action_dim])
# input layer
self.state_input = tf.placeholder("float", [None, self.state_dim])#一次可以输入若干个状态
self.tf_acts = tf.placeholder(tf.int32, [None, ], name="actions_num")
self.tf_vt = tf.placeholder(tf.float32, [None, ], name="actions_value")
# hidden layers
h_layer = tf.nn.relu(tf.matmul(self.state_input, W1) + b1)
# softmax layer
self.softmax_input = tf.matmul(h_layer, W2) + b2
#softmax output
self.all_act_prob = tf.nn.softmax(self.softmax_input, name='act_prob')
self.neg_log_prob = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=self.softmax_input,
labels=self.tf_acts) #这里就是上面第二节第三个小技巧所说的将对数函数转化为我们经常使用的交叉熵函数
self.loss = tf.reduce_mean(self.neg_log_prob * self.tf_vt) # reward guided loss
self.train_op = tf.train.AdamOptimizer(LEARNING_RATE).minimize(self.loss)
def weight_variable(self, shape):
initial = tf.truncated_normal(shape)
return tf.Variable(initial)
def bias_variable(self, shape):
initial = tf.constant(0.01, shape=shape)
return tf.Variable(initial)
def choose_action(self, observation):
prob_weights = self.session.run(self.all_act_prob, feed_dict={self.state_input: observation[np.newaxis, :]})
action = np.random.choice(range(prob_weights.shape[1]), p=prob_weights.ravel()) # select action w.r.t the actions prob
return action
def store_transition(self, s, a, r):
self.ep_obs.append(s)
self.ep_as.append(a)
self.ep_rs.append(r)
def learn(self):
discounted_ep_rs = np.zeros_like(self.ep_rs)
running_add = 0
for t in reversed(range(0, len(self.ep_rs))):
running_add = running_add * GAMMA + self.ep_rs[t] #折扣因子
discounted_ep_rs[t] = running_add
discounted_ep_rs -= np.mean(discounted_ep_rs)
discounted_ep_rs /= np.std(discounted_ep_rs)
# train on episode
self.session.run(self.train_op, feed_dict={
self.state_input: np.vstack(self.ep_obs),
self.tf_acts: np.array(self.ep_as),
self.tf_vt: discounted_ep_rs,
})
self.ep_obs, self.ep_as, self.ep_rs = [], [], [] # empty episode data
# Hyper Parameters
ENV_NAME = 'CartPole-v0'
EPISODE = 300 # Episode limitation
STEP = 3000 # Step limitation in an episode
TEST = 10 # The number of experiment test every 100 episode
def main():
# initialize OpenAI Gym env and dqn agent
env = gym.make(ENV_NAME)
agent = Policy_Gradient(env)
print('action dim is :',agent.action_dim)
for episode in range(EPISODE):
# initialize task
state = env.reset()
# Train
for step in range(STEP):
print('state is :', state)
action = agent.choose_action(state) # e-greedy action for train
next_state, reward, done, _ = env.step(action)
agent.store_transition(state, action, reward)
state = next_state
if done:
#print("stick for ",step, " steps")
agent.learn()
break
# Test every 100 episodes
if episode % 100 == 0:
total_reward = 0
for i in range(TEST):
state = env.reset()
for j in range(STEP):
env.render()
action = agent.choose_action(state) # direct action for test
state,reward,done,_ = env.step(action)
total_reward += reward
if done:
break
ave_reward = total_reward/TEST
print ('episode: ',episode,'Evaluation Average Reward:',ave_reward)
env.close()
if __name__ == '__main__':
main()
注:上面的学习方法并没有使用采样,这里是每个eposide都会更新一下,也可以改改代码变成和上面一致的情况。
四、参考文献
1、李宏毅老师的强化学习课程,上面公式推导大多来自他的课程,然后写了一些自己的理解和解释
2、莫烦python
3、理解策略梯度算法
4、刘建平策略梯度(policy gradient)