Policy Gradients
- Q learning学习奖惩值, 根据自己认为的高价值选行为, Policy Gradients不通过分析奖励值, 直接输出行为的方法
- 最大好处就是, 它能在一个连续区间内挑选动作, 而基于值的, 如 Q-learning, 做不到
Policy Gradients的反向传递
- 没有误差反向传递
- 反向传递目的是让这次被选中的行为更有可能在下次发生. 通过reward 奖惩来决定被增加被选的概率
核心思想
-
也是靠奖励来左右神经网络反向传递.
-
观测的信息通过神经网络分析, 选出了①行为, 直接进行反向传递, 使之下次被选的可能性增加,根据奖惩信息,如果行为好增加动作可能性增加的幅度 ,不好则减低
算法
不像 Value-based 方法 (Q learning, Sarsa), 但他也要接受环境信息 (observation), 不同的是他要输出不是 action 的 value, 而是具体的那一个 action, policy gradient 跳过了 value 这个阶段
- 第一个算法是一种基于 整条回合数据 的更新
更新神经网络参数时: - 更新参数依据先往这个方向更新,根据Vt判断方向是否正确,如果正确,则在这个方向幅度大一点;Vt不好幅度小一点,下次选中的概率略微少一点
- log形式的概率是为了更好地收敛性
- 以回合为基础,回合完了一次性更新(Qlearning单步更新)
代码结构
建立 policy 神经网络
- 第一层建立全连接层
- 第二层输出所有action
- 将每个输出的值转换成概率
- 计算误差(policy 是没有误差的)此处‘loss’是指反向传递后,使下一次选择这个动作的概率的增加一点乘以增加的幅度
self.all_act_prob = tf.nn.softmax(all_act, name='act_prob') # 激励函数 softmax 出概率
with tf.name_scope('loss'):
# 最大化 总体 reward (log_p * R) 就是在最小化 -(log_p * R), 而 tf 的功能里只有最小化 loss
neg_log_prob = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=all_act, labels=self.tf_acts) # 所选 action 的概率 -log 值
# 下面的方式是一样的:
# neg_log_prob = tf.reduce_sum(-tf.log(self.all_act_prob)*tf.one_hot(self.tf_acts, self.n_actions), axis=1)
loss = tf.reduce_mean(neg_log_prob * self.tf_vt) # (vt = 本reward + 衰减的未来reward) 引导参数的梯度下降
- tf.log(self.all_act_prob),all_act_prob所有action的概率
- 放到记忆库中action是单个单个的值,如第0个action,放到记忆库中是0,第一个action放到记忆库中是1,。。。如果要进行如上的计算,最好变成矩阵的形式与概率tf.log(self.all_act_prob)相乘,one_hot(self.tf_acts, self.n_actions)采取action为1(没有采取为0)与相乘,筛选出采取了哪个对应action的概率
- 负号 因为Tensorflow只能最小化loss。因为是想要得到奖励概率越来越大所以用负号将minimize换成max
self.tf_vt幅度
选行为
不通过 Q value 来选定的, 而是用概率来选定. 虽然不用epsilon-greedy, 也具有一定的随机性.
def choose_action(self, observation):
prob_weights = self.sess.run(self.all_act_prob, feed_dict={self.tf_obs: observation[np.newaxis, :]}) # 所有 action 的概率
action = np.random.choice(range(prob_weights.shape[1]), p=prob_weights.ravel()) # 根据概率来选 action
return action
- np.random.choice()根据概率来产生随机数
存储回合
将这一步的 observation, action, reward 加到列表中去. 因为本回合完毕之后要清空列表, 然后存储下一回合的数据, 所以会在 learn() 当中进行清空列表的动作.
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):
# 衰减, 并标准化这回合的 reward
discounted_ep_rs_norm = self._discount_and_norm_rewards() # 功能再面
# train on episode
self.sess.run(self.train_op, feed_dict={
self.tf_obs: np.vstack(self.ep_obs), # shape=[None, n_obs]
self.tf_acts: np.array(self.ep_as), # shape=[None, ]
self.tf_vt: discounted_ep_rs_norm, # shape=[None, ]
})
self.ep_obs, self.ep_as, self.ep_rs = [], [], [] # 清空回合 data
return discounted_ep_rs_norm # 返回这一回合的 state-action value
- 将reward处理过程放到train
- 输入observation、action、vt到Tensorflow
- 清空列表用于下一个回合