[强化学习笔记专题(二)]Nature DQN

转自 我的博客

DQN (Nature)

1

一、 算法流程:

  1. 定义可配置参数
    • episode 数量 M
    • 最大仿真时间 T, ϵ − g r e e d y \epsilon-greedy ϵgreedy参数 ϵ l o w \epsilon_{low} ϵlow, ϵ h i g h \epsilon_{high} ϵhigh
    • batch size N ​ N​ N
    • 折扣率 γ \gamma γ,学习率 α \alpha α等优化器参数
    • Soft update 频率 C ​ C​ C
  2. 初始化
    • 初始化 replay buffer 大小N
    • 初始化 Q 网络 Q ​ Q​ Q ,使用随机权值 θ ​ \theta​ θ
    • 初始化 TargetQ 网络 Q ^ \hat{Q} Q^ 权值 θ − \theta^- θ,使用 Q 网络的权值 θ \theta θ
  3. DQN 一个Episode的流程
    • 使用 ϵ − g r e e d y \epsilon-greedy ϵgreedy 策略 选择一个 action a t a_t at
    • 执行当前 action a t a_t at, 获取下一个状态 s t + 1 s_{t+1} st+1 和 reward r t r_{t} rt
    • 将当前状态 s t s_t st赋值为下一个状态 s t + 1 s_{t+1} st+1
    • 将五元组$\langle s_t,a_t,r_t,s_{t+1},done \rangle $存入 replay buffer D D D
    • 训练Q网络 Q ​ Q​ Q:
      • **[Pre-condition]**训练网络的前提是 **replay buffer 的已有五元组数量大于 batch size ** N N N
      • 从 replay buffer D ​ D​ D中随机选取 batch size N ​ N​ N条数据 ⟨ s j , a j , r j , s j + 1 , d o n e ⟩ ​ \langle s_j,a_j,r_j,s_{j+1},done\rangle​ sj,aj,rj,sj+1,done D s e l e c t e d ​ D_{selected}​ Dselected
      • 计算目标Q值 y ​ y​ y y ​ y​ y是一个向量, { y j ∈ y ∣ j ∈ [ 0 , N ] } ​ \{y_j \in y |j\in[0,N]\} ​ {yjyj[0,N]},大小为 batch size N ​ N​ N
        • D s e l e c t e d ​ D_{selected}​ Dselected[j] 中 d o n e = T r u e ​ done=True​ done=True 时,即终局状态,此时 y j = r j ​ y_j=r_j​ yj=rj
        • D s e l e c t e d D_{selected} Dselected[j] 中 d o n e = F a l s e done=False done=False 时,即非终局状态,此时 y i = r j + γ m a x a ′ Q ^ ( s j + 1 , a ′ ; θ − ) y_i=r_j+\gamma max_{a'}\hat{Q}(s_{j+1},a';\theta^-) yi=rj+γmaxaQ^(sj+1,a;θ), 注意这里是用的 TargetQ 网络进行的
      • 使用优化器进行梯度下降,损失函数是(一个batch里面) ( y − Q ( s , a ; θ ) ) 2 ​ (y-Q(s,a;\theta))^2​ (yQ(s,a;θ))2,注意这里使用的是Q网络进行,来让计算出来的目标Q值当前Q网络输出的Q值进行MSE
      • C C C 次 episode,soft update 一次 target net 参数, θ − = θ \theta^- = \theta θ=θ
  4. 不断迭代Episode流程 M M M

img

二、对应代码

完整代码地址: Nature DQN

  1. 初始化
    • 初始化 replay buffer 大小N
    • 初始化 Q 网络 Q Q Q ,使用随机权值 θ \theta θ
    • 初始化 TargetQ 网络 Q ^ \hat{Q} Q^ 权值 θ − \theta^- θ,使用 Q 网络的权值 θ \theta θ
        def create_Q_network(self):
            """
            Q net 网络定义
            :return:
            """
            # 输入状态 placeholder
            self.state_input = tf.placeholder("float", [None, self.state_dim])
    
            # Q 网络结构 两层全连接
            with tf.variable_scope('current_net'):
                W1 = self.weight_variable([self.state_dim, 100])
                b1 = self.bias_variable([100])
                W2 = self.weight_variable([100, self.action_dim])
                b2 = self.bias_variable([self.action_dim])
                h_layer = tf.nn.relu(tf.matmul(self.state_input, W1) + b1)
                # Q Value
                self.Q_value = tf.matmul(h_layer, W2) + b2
    
            # Target Net 结构与 Q相同,可以用tf的reuse实现
            with tf.variable_scope('target_net'):
                W1t = self.weight_variable([self.state_dim, 100])
                b1t = self.bias_variable([100])
                W2t = self.weight_variable([100, self.action_dim])
                b2t = self.bias_variable([self.action_dim])
                h_layer_t = tf.nn.relu(tf.matmul(self.state_input, W1t) + b1t)
                # target Q Value
                self.target_Q_value = tf.matmul(h_layer_t, W2t) + b2t
    
            t_params = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope='target_net')
            e_params = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope='current_net')
    
            # soft update 更新 target net
            with tf.variable_scope('soft_replacement'):
                self.target_replace_op = [tf.assign(t, e) for t, e in zip(t_params, e_params)]
    
    #===============================================================#
        def weight_variable(self, shape):
            """
            初始化网络权值(随机, truncated_normal)
            :param shape:
            :return:
            """
            initial = tf.truncated_normal(shape)
            return tf.Variable(initial)
    
    #===============================================================#
        def bias_variable(self, shape):
            """
            初始化bias(const)
            :param shape:
            :return:
            """
            initial = tf.constant(0.01, shape=shape)
            return tf.Variable(initial)
    
  2. ϵ − g r e e d y \epsilon-greedy ϵgreedy 策略 定义,这里对 ϵ \epsilon ϵ进行一个随时间步的迁移而减小的策略,使其动作选择的不确定性逐渐减小。

    def egreedy_action(self, state):
        """
        epsilon-greedy策略
        :param state:
        :return:
        """
        Q_value = self.Q_value.eval(feed_dict={
            self.state_input: [state]
        })[0]
        if random.random() <= self.epsilon:
            self.epsilon -= (INITIAL_EPSILON - FINAL_EPSILON) / 10000
            return random.randint(0, self.action_dim - 1)
        else:
            self.epsilon -= (INITIAL_EPSILON - FINAL_EPSILON) / 10000
            return np.argmax(Q_value)
  1. Replay buffer的定义

        def perceive(self, state, action, reward, next_state, done):
            """
            Replay buffer
            :param state:
            :param action:
            :param reward:
            :param next_state:
            :param done:
            :return:
            """
            # 对action 进行one-hot存储,方便网络进行处理
            # [0,0,0,0,1,0,0,0,0] action=5
            one_hot_action = np.zeros(self.action_dim)
            one_hot_action[action] = 1
    
            # 存入replay_buffer
            # self.replay_buffer = deque()
            self.replay_buffer.append((state, one_hot_action, reward, next_state, done))
    
            # 溢出出队
            if len(self.replay_buffer) > REPLAY_SIZE:
                self.replay_buffer.popleft()
                
            # 可进行训练条件
            if len(self.replay_buffer) > BATCH_SIZE:
                self.train_Q_network()
    
  2. Q网络训练

    def train_Q_network(self):
        """
        Q网络训练
        :return:
        """
        self.time_step += 1
        # 从 replay buffer D中随机选取 batch size N条数据<s_j,a_j,r_j,s_j+1,done>   D_selected
        minibatch = random.sample(self.replay_buffer, BATCH_SIZE)
        state_batch = [data[0] for data in minibatch]
        action_batch = [data[1] for data in minibatch]
        reward_batch = [data[2] for data in minibatch]
        next_state_batch = [data[3] for data in minibatch]

        # 计算目标Q值y
        y_batch = []
        Q_value_batch = self.target_Q_value.eval(feed_dict={self.state_input: next_state_batch})
        for i in range(0, BATCH_SIZE):
            done = minibatch[i][4]
            if done:
                y_batch.append(reward_batch[i])
            else:
                y_batch.append(reward_batch[i] + GAMMA * np.max(Q_value_batch[i]))

        self.optimizer.run(feed_dict={
            self.y_input: y_batch,
            self.action_input: action_batch,
            self.state_input: state_batch
        })
  1. Soft update

        def update_target_q_network(self, episode):
           # 更新 target Q netowrk
           if episode % REPLACE_TARGET_FREQ == 0:
    

三、实验结果

环境 cart-pole-v0 (期望回报是200)


四、DQN参考论文流程:

img

五、Double DQN

DQN存在的问题是Q function容易过拟合,根据状态 s t + 1 s_{t+1} st+1 选择动作 a t + 1 a_{t+1} at+1 的过程,以及估计 Q ( s t + 1 , a t + 1 ) ​ Q(s_{t+1},a_{t+1})​ Q(st+1,at+1) 使用的同一个Q net网络参数,这可能导致选择过高的估计值,从而导致过于乐观的值估计。为了避免这种情况的出现,可以对选择和衡量进行解耦,从而就有了使用 Double DQN 来解决这一问题。

Double DQN与DQN的区别仅在于 y y y的求解方式不同,Double DQN根据Q网络参数来选择动作 a t + 1 a_{t+1} at+1,再用Target Q网络参数来衡量 Q ( s t + 1 , a t + 1 ) Q(s_{t+1},a_{t+1}) Q(st+1,at+1)的值。
Y t D Q N = R t + 1 + γ Q ^ ( S t + 1 , a r g m a x a Q ^ ( S t + 1 , a ; θ t − ) ; θ t − ) Y t D D Q N = R t + 1 + γ Q ^ ( S t + 1 , a r g m a x a Q ( S t + 1 , a ; θ t ) ; θ t − ) Y_t^{DQN}=R_{t+1}+\gamma \hat{Q}(S_{t+1},argmax_a\hat{Q}(S_{t+1},a;\theta_t^-);\theta_t^-)\\ Y_t^{DDQN}=R_{t+1}+\gamma \hat{Q}(S_{t+1},argmax_aQ(S_{t+1},a;\theta_t);\theta_t^-) YtDQN=Rt+1+γQ^(St+1,argmaxaQ^(St+1,a;θt);θt)YtDDQN=Rt+1+γQ^(St+1,argmaxaQ(St+1,a;θt);θt)
反映在代码上,就是训练的时候选择Q的时候有点变动:

    def train_Q_network(self):
        """
        Q网络训练
        :return:
        """
        self.time_step += 1
        # 从 replay buffer D中随机选取 batch size N条数据<s_j,a_j,r_j,s_j+1,done>$  D_selected
        minibatch = random.sample(self.replay_buffer, BATCH_SIZE)
        state_batch = [data[0] for data in minibatch]
        action_batch = [data[1] for data in minibatch]
        reward_batch = [data[2] for data in minibatch]
        next_state_batch = [data[3] for data in minibatch]

        # 计算目标Q值y
        y_batch = []
        QTarget_value_batch = self.target_Q_value.eval(feed_dict={self.state_input: next_state_batch})
        Q_value_batch = self.Q_value.eval(feed_dict={self.state_input: next_state_batch})
        for i in range(0, BATCH_SIZE):
            done = minibatch[i][4]
            if done:
                y_batch.append(reward_batch[i])
            else:
                #################用target Q(Q)#######################
                if DOUBLE_DQN:
                    selected_q_next = QTarget_value_batch[i][np.argmax(Q_value_batch[i])]
                #################用target Q(target Q)################
                else:
                    selected_q_next = np.max(QTarget_value_batch[i])

                y_batch.append(reward_batch[i] + GAMMA * selected_q_next)

        self.optimizer.run(feed_dict={
            self.y_input: y_batch,
            self.action_input: action_batch,
            self.state_input: state_batch
        })

六、DQN,DDQN实验结果对比

可以看到DoubleDQN的表现比 DQN稳定

七、 Dueling DDQN

八、 Dueling DQN, DDQN, DQN对比

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值