强化学习(Double/Prioritised Replay/Dueling DQN)

在这里插入图片描述
Q_Learning和Sarsa中都是利用了Q表来记录Q值,小规模场景状态往往比较少,便可以方便的用表存储再查询更新,但很多现实问题状态和动作都很复杂,而且如果出现连续值的状态则需要等距离分割离散,存储量往往太大,比如像下围棋如果还用Q表来存状态是不可能的事情。那么如果不用Q表存取,怎么得到价值函数呢?

近似表示
那么就来拟合吧!即近似表示学习价值函数。 v ( S ) ≈ v ^ ( S , w ) v(S) \approx \hat{v}(S, w) v(S)v^(S,w)
w表示引入的参数,通常是一个矩阵或至少是一个向量。如下图有三种表示方式,一是输入状态s,输出状态的近似价值。二是输入状态s和采取的行为a,输出它们的近似价值。三是输入状态s,输出该状态下每一种可能采取的行为价值。
在这里插入图片描述
线性逼近?那么为什么不用神经网络。
于是采用了将NN+RL的方式,使用第三种方式来拟合价值函数,代替Q表,便是Deep Q Network,即DQN。
@@其实神经网络的类型并没有限制,根据不同应用场景,使用CNN,RNN都是可以的。

DQN
DQN的更新点主要有三点:

  • experience replay(记忆库) 。Q learning之所以是离线控制,就在于它不但可以学习当前状态,还可以学习以前状态,甚至其他经验(如每次选最大)。但由于DQN是没有表的,如何还能够学习到以前的经验,即使用experience replay,经验回放。使用一个固定大小的空间进行记忆,满了就重写最早的记录。通过记忆库就又可以知道了预测值与现实值的差分,就可以梯度反向传播了。
  • 神经网络计算 Q 值。完成输入s,输出所有a的value的映射。
  • 使用两个网络,参数相同异步更新。由于用神经网络计算了值,然后值又被用来更新了网络,两者会循环更新,依赖性太强了。所以为了网络更好的收敛。使用两个神经网络,结构一样但参数不同,其中一个网络延迟更新,使其还是旧的参数,再每隔如1000步等跟最新网络copy一次更新。

记忆库和target网络都能够减少数据关联性,以满足训练神经网络所需的独立同分布的前提,使RL的收敛能更加的稳定。
算法流程如下:
在这里插入图片描述

  • 初始化两套网络的参数w
  • 先从状态s,得到该状态的特征向量 ϕ ( S t ) \phi(S_t) ϕ(St)输入实时网络Q,输出该状态的所有动作a的Q值。然后对输出的Q结果按一定概率 ϵ−贪婪法的选择动作a,并执行a得到新状态的特征向量 ϕ ( S t + 1 ) \phi(S_{t+1}) ϕ(St+1)和奖励r。
  • 存入到记忆库D中。
  • 然后从记忆库中采样计算 旧网络Q’ y i y_i yi(相当于真实的Q值): y j = { r j i s _ e n d j    i s    t r u e r j + γ max ⁡ a ′ Q ′ ( ϕ j , a j ′ , w ′ ) i s _ e n d j    i s    f a l s e y_j= \begin{cases} r_j& {is\_end_j\; is \;true}\\ r_j + \gamma\max_{a'}Q'(\phi_j,a'_j,w') & {is\_end_j \;is\; false} \end{cases} yj={rjrj+γmaxaQ(ϕj,aj,w)is_endjistrueis_endjisfalse
  • 然后与刚刚选择动作a得到的Q值(由实时网络计算的预测Q值)进行均方误差 1 m ∑ j = 1 m ( y j − Q ( ϕ j , a j , w ) ) 2 \frac{1}{m}\sum\limits_{j=1}^m(y_j-Q(\phi_j,a_j,w))^2 m1j=1m(yjQ(ϕj,aj,w))2。反向传播更新实时Q网络。
  • 最后每隔C步就再更新一次旧网络的参数,直到循环结束。

1. y i y_i yi全部通过max Q来计算有没有问题?
有问题,不断学习max会造成的Over Estimation,因为实时神经网络预测Q本身就有误差,用来差分的Q’值也有误差,反向传播后的Q就会过度预测,如预测的值超过了最大值,这显然是不合理的。
Double DQN
那么分开Q值动作选择和目标Q值的计算。即不在目标旧网络里面找最大值来计算 y j = r j + γ max ⁡ a ′ Q ′ ( ϕ j , a j ′ , w ′ ) y_j= r_j + \gamma\max_{a'}Q'(\phi_j,a'_j,w') yj=rj+γmaxaQ(ϕj,aj,w),而是在当前的估值网络Q中找最大Q所对应的动作,然后用这个动作去在旧网络中计算Q值,即: y j = r j + γ Q ′ ( ϕ j , arg ⁡ max ⁡ a ′ Q ( ϕ j , a , w ) , w ′ ) y_j = r_j + \gamma Q'(\phi_j,\arg\max_{a'}Q(\phi_j,a,w),w') yj=rj+γQ(ϕj,argamaxQ(ϕj,a,w),w)

2. 在记忆库后中随机采样好吗?
按道理不同样本的重要性是不一样的,特别是更新时的TD误差样本之间的差距还是挺大的。
Prioritised Replay DQN
那么优化记忆库抽取。按误差的大小进行重要程度排序,误差越大说明越需要被学习。但是为了效率,不能每次都排一遍太麻烦,所以使用sumtree树排序相对来说就简单了(线段树)。
在这里插入图片描述
如上SumTree 是一种树形结构(Jaromír Janisch), 每片树叶存储每个样本的优先级 p,二叉树,根节点是所有的和。抽样时会用总数除以batch size,然后再按等区间进行抽样,优先级高的区段显然会被更高频率的抽中。

3. Q值是代表Q(S,a)的价值,那么对于状态S,单独动作价值a的评估会不会更准确?
因为有些state可能无论做什么动作,对下一个state都没有多大的影响。
Dueling DQN
那么改进Q为S,a的两个输出。即分为了在这个state时的价值和在这个state上采取各种行动 “多加” 的值。即Q变成: Q ( S , A , w , α , β ) = V ( S , w , α ) + A ( S , A , w , β ) Q(S,A, w, \alpha, \beta) = V(S,w,\alpha) + A(S,A,w,\beta) Q(S,A,w,α,β)=V(S,w,α)+A(S,A,w,β)
为了增加这两部分的辨识度,即为了防止状态输出直接为0,而动作输出直接学到了Q,会将动作输出中心化,即减去他们的平均值,以便突出这两部分的不同。 Q ( S , A , w , α , β ) = V ( S , w , α ) + ( A ( S , A , w , β ) − 1 N π ∑ a ′ ∈ π A ( S , a ′ , w , β ) ) Q(S,A, w, \alpha, \beta) = V(S,w,\alpha) + (A(S,A,w,\beta) - \frac{1}{N_\pi}\sum\limits_{a' \in \pi}A(S,a', w,\beta)) Q(S,A,w,α,β)=V(S,w,α)+(A(S,A,w,β)Nπ1aπA(S,a,w,β))

DQN代码
使用gym的游戏环境:
pip install gym
pip install gym[atari]

atari里面会有很多的游戏:
在这里插入图片描述
但同样的为了应对这样的环境,就不能使用NN了,而是需要通过CNN来构建神经网络部分。

from collections import deque
import gym
import numpy as np
import os
import tensorflow as tf
import sys
import matplotlib

def sample_memories(batch_size):
    indices = np.random.permutation(len(replay_memory))[:batch_size]
    cols = [[], [], [], [], []] #存储 state, action, reward, next_state, continue
    for idx in indices: #利用索引
        memory = replay_memory[idx]
        for col, value in zip(cols, memory):
            col.append(value)
    cols = [np.array(col) for col in cols]
    return cols
    
def epsilon_greedy(q_values, step): #epsilon贪婪
    epsilon = max(eps_min, eps_max - (eps_max-eps_min) * step / args.explore_steps)
    if np.random.rand() < epsilon: 
        return np.random.randint(env.action_space.n) # random action
    else:
        return np.argmax(q_values) # optimal action

def q_network(net, name, reuse=False): #使用CNN搭建网络
    with tf.variable_scope(name, reuse=reuse) as scope:
        initializer = tf.contrib.layers.variance_scaling_initializer()
        for n_maps, kernel_size, strides, padding, activation in zip(
                [32, 64, 64], [(8,8), (4,4), (3,3)], [4, 2, 1],
                ["SAME"] * 3 , [tf.nn.relu] * 3):
            net = tf.layers.conv2d(net, filters=n_maps, kernel_size=kernel_size, strides=strides, 
                padding=padding, activation=activation, kernel_initializer=initializer)
        net = tf.layers.dense(tf.contrib.layers.flatten(net), 256, activation=tf.nn.relu, kernel_initializer=initializer)
        net = tf.layers.dense(net, env.action_space.n, kernel_initializer=initializer)

    trainable_vars = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope=scope.name)
    return net, trainable_vars

最后再放一个github超级棒的项目:
在这里插入图片描述
(https://github.com/devsisters/DQN-tensorflow)

深度强化学习真的好用吗?

  • 它的样本利用率非常低。换言之为了让模型的表现达到一定高度需要极为大量的训练样本。
  • 参数难调。
  • 对环境的过拟合。
  • 最终表现很多时候不够好。不仅利用率低,参数很难调,表现也不一定会很好。
  • 奖励函数往往很难设计。1加入了合适的先验,不然容易被找到作弊手段;2奖励函数的值太过稀疏,即非0值太少了。3奖励函数有时候会引入新的偏见。
  • EE问题(exploration & exploitation)导致的不稳定性。

现有表现比较好的模型,都是在实验环境比较理想(如游戏),数据很多reward定义简单而且反馈快,可以从简单关卡开始学习,如何使其能很好的用在实践中还有待进一步的努力。

  • 5
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值