继上篇的DQNhttps://blog.csdn.net/weixin_42001089/article/details/81448677之后,这里说一下PG(Poilcy Gradients),它是DRL另一大家族,先来谈一下它出现的背景。
这要追溯到DQN的来源,DQN的出现是因为有些场景状态数过多导致Q表行数过大,为了解决这一问题即通过神经网络近似了Q值函数(value function),通过不断的训练神经网络,便可以拟合出一套参数来规避维护行数过多的Q表。
那么现在我们考虑一下Q表的列数,加入列数过多呢?比如一些场景的行动值不是离散的几个,而是一个连续值呢?比如声音的大小,气压的大小,这些值虽然可以通过离散化来处理,但是可想而知这个效果并不好,比如选取的离散化区间过大时,结果往往收敛不到一个较佳值,使结果一直在较好结果周围来回徘徊,当选取的区间较小时,又会带来列数明显增加,总之都是麻烦事,所以DQN连续化的是value function,但其动作值还是离散化的,既然神经网络善于解决这种通过提取特征来解决这种高纬度的拟合问题,那么我们何不在action上面也用DL呢?
综合考虑到Q表的列数和行数也就是状态和行动都高维时,我们这里搭建一个模型让它拟合这样一个问题:
输入状态---------------》输出该走的行为
注意和DQN的对比,DQN也是输入状态,但是其是输出该状态下所有动作的Q值,然后通过选择策略Policy 选出该走的动作,而PG则是跳过了中间Q值这一步直接输出该走的action,所以可以将PG简单的理解为拟合了Policy,又因为这里用了神经网络,本质就是一个优化问题,优化问题的解决方案一般就是梯度下降,所以起名Poilcy Gradients
其实DQN和Poilcy Gradients都是通过DL解决高维的情况来泛化RL的方法,只是角度不一样罢了
关于Poilcy Gradients的公式推导这里简单说一下:
首先我们将奖励值作为我们要优化的目标J(θ)(行为后得到奖励的平均值)
这里的就是状态S在策略下的马尔可夫链中不变分布,
可以看到就是在状态S下,采取行动a后的奖励值的矩阵
接下求最值问题就是求导了,关于怎么近似求导的这篇Paperhttps://papers.nips.cc/paper/1713-policy-gradient-methods-for-reinforcement-learning-with-function-approximation.pdf有详细的介绍,这里我们直接看结果:
然后:
带入到上面的求导:
最后:
最好这张图就是Poilcy Gradients最核心的算法
更多推导细节可以参考:
https://blog.csdn.net/LagrangeSK/article/details/80335117
下面说明是Poilcy Gradients以回合为更新的,也就是说一个游戏回合结束后才进行更新网络参数,并不是单步更新。
神经网络(DL)的输入是States:[None,features]其中features就是状态的数学化表示需要的个数,例如状态是坐标,那么features=2,如果是空间坐标那么就是features=3,None就是代表一个游戏回合结束后走过的状态数(步骤数),比如这个回合一共走了100步,那么就是[100,features]
DL中神经网络层的输出为Prob[None,actions]其中None代表的意思同上,actions就是每种行动对应的概率(可以用tf.nn.softmax实现)。
这里要用到DL的框架即tensorflow,其必须定义Loss函数,然后才可以通过反向传播进行梯度下降,而Loss一般得有标签,然后和预测的差值作为Loss,可是这里并没有标签,怎么办呢?
在RL问题中我们评判走得行为好不好唯一可以用的标准就是Reward,结合上面最后一张图我们定义Loss:
Loss=tf.reduce_mean(log_prob *vt)
这里的log_prob可以看出上面的(就是待训练的神经网络参数),vt就是上面的vt。因为如此定义了Loss后反向传播求梯度的话,正好对应上图中的。
具体到什么是log_prob呢?
它就是神经网络输出行动们概率分布通过log函数后的数,即:
log_prob=tf.reduce_sum(-tf.log(actions)*tf.one_hot(acts, n_actions), axis=1)
注意这里的one_hot的作用就是要使得状态和采取的行动值对上(State和acts在一个回合中成对保存好了,这里可以理解为DQN 的experience replay,比如这一个游戏回合一共走了100,那么它们就是这一路探索下来对应的100对值)
注意这里的负号,因为当log_prob=tf.reduce_sum(tf.log(actions)*tf.one_hot(acts, n_actions), axis=1)时我们实际上是要最大化Loss=tf.reduce_mean(log_prob *vt),但是tensorflow最只有最小化Loss的API所以这里加了负号,最小化它相当于最大化我们预期的东西。
具体到什么是vt呢?
vt就是Reward,就是每一步走后对应的当前的Q值,只不过这里常常可以归一化,还有就是衰减,衰减是从现在往前衰减,还是代码看的清楚一点吧:
vt = np.zeros_like(len(r))
running_add = 0
for t in reversed(range(0, len(r))):
running_add = running_add * self.gamma + r[t]
vt[t] = running_add
# normalize
vt -= np.mean(vt)
vt /= np.std(vt)
即:
import numpy as np
r=[1.0,2.0,3.0,4.0]
r.append(5.0)
print(r)
vt = np.zeros_like(r)
running_add=0
for t in reversed(range(0, len(r))):
running_add = running_add*0.9+ r[t]
vt[t] = running_add
print(vt)
对应到怎么根据当前状态选取下一步的,那就是
现将当前状态输入,然后得到动作的概率,然后使用np.random.choice的按概率抽取方法进行抽取即可,所以整体思路大概就是这样比如玩100回合
for i in range(100):
S = environment.reset()
while True:
environment.render()
action = RL.choose_action(S)
S', reward, done, info = environment.step(action)
RL.store_transition(S, action, reward)
if done:
vt = RL.learn()
break
S = S'
写RL.learn的时候可以将每一回合的vt值返回,方便我们观察每一回合vt的变化