• 强化学习10-Deep Q Learning-fix target


    针对 Deep Q Learning 可能无法收敛的问题,这里提出了一种  fix target 的方法,就是冻结现实神经网络,延时更新参数。

    这个方法的初衷是这样的:

    1. 之前我们每个(批)记忆都会更新参数,这是一种实时更新神经网络参数的方法,这个方法有个问题,就是每次都更新,由于样本都是随机的,可能存在各种不正常现象,比如你考试得了90分,妈妈奖励了你,但是也有可能是考了90分,被臭骂一顿,因为别人都考了95分以上,当然这只是个例子,正是各种异常现象,可能导致损失忽小忽大,参数来回震荡,无法收敛。

    2. fix target 方法搭了2个神经网络,一个是估计,一个是现实,估计神经网络实时更新,而现实神经网络暂时冻结,q估计用估计神经网络,q现实用现实神经网络,冻结现实神经网络,就是我先不动,然后派很多人去做尝试,回来给我汇报,我根据汇报总结经验,然后再行动,这是我们正常的处事逻辑,这样显得神经网络更稳重,容易收敛。

    核心代码如下

    def _build_net(self):
            # ------------------ build evaluate_net ------------------
            self.s = tf.placeholder(tf.float32, [None, self.n_features], name='s')  # input
            self.q_target = tf.placeholder(tf.float32, [None, self.n_actions], name='Q_target')  # for calculating loss
            with tf.variable_scope('eval_net'):
                # n_l1 第一隐层的神经元个数   w b 初始化
                c_names, n_l1, w_initializer, b_initializer = 
                    ['eval_net_params', tf.GraphKeys.GLOBAL_VARIABLES], 10, 
                    tf.random_normal_initializer(0., 0.3), tf.constant_initializer(0.1)  # config of layers
    
                # first layer. collections is used later when assign to target net
                with tf.variable_scope('l1'):
                    w1 = tf.get_variable('w1', [self.n_features, n_l1], initializer=w_initializer, collections=c_names)
                    b1 = tf.get_variable('b1', [1, n_l1], initializer=b_initializer, collections=c_names)
                    l1 = tf.nn.relu(tf.matmul(self.s, w1) + b1)
    
                # second layer. collections is used later when assign to target net
                with tf.variable_scope('l2'):
                    w2 = tf.get_variable('w2', [n_l1, self.n_actions], initializer=w_initializer, collections=c_names)
                    b2 = tf.get_variable('b2', [1, self.n_actions], initializer=b_initializer, collections=c_names)
                    self.q_eval = tf.matmul(l1, w2) + b2
    
            with tf.variable_scope('loss'):
                self.loss = tf.reduce_mean(tf.squared_difference(self.q_target, self.q_eval))
            with tf.variable_scope('train'):
                self._train_op = tf.train.RMSPropOptimizer(self.lr).minimize(self.loss)
    
            # ------------------ build target_net ------------------
            self.s_ = tf.placeholder(tf.float32, [None, self.n_features], name='s_')    # input
            with tf.variable_scope('target_net'):
                # c_names(collections_names) are the collections to store variables
                c_names = ['target_net_params', tf.GraphKeys.GLOBAL_VARIABLES]
    
                # first layer. collections is used later when assign to target net
                with tf.variable_scope('l1'):
                    w1 = tf.get_variable('w1', [self.n_features, n_l1], initializer=w_initializer, collections=c_names)
                    b1 = tf.get_variable('b1', [1, n_l1], initializer=b_initializer, collections=c_names)
                    l1 = tf.nn.relu(tf.matmul(self.s_, w1) + b1)
    
                # second layer. collections is used later when assign to target net
                with tf.variable_scope('l2'):
                    w2 = tf.get_variable('w2', [n_l1, self.n_actions], initializer=w_initializer, collections=c_names)
                    b2 = tf.get_variable('b2', [1, self.n_actions], initializer=b_initializer, collections=c_names)
                    self.q_next = tf.matmul(l1, w2) + b2
    
        def store_transition(self, s, a, r, s_):
            # 存储记忆,固定大小的记忆库
            if not hasattr(self, 'memory_counter'):
                self.memory_counter = 0
    
            transition = np.hstack((s, [a, r], s_))
    
            # replace the old memory with new memory
            index = self.memory_counter % self.memory_size
            self.memory[index, :] = transition
    
            self.memory_counter += 1
    
        def choose_action(self, observation):
            # q learning 选择动作 e贪心
            observation = observation[np.newaxis, :]
    
            if np.random.uniform() < self.epsilon:
                actions_value = self.sess.run(self.q_eval, feed_dict={self.s: observation})
                action = np.argmax(actions_value)
            else:
                action = np.random.randint(0, self.n_actions)
            return action
    
        def learn(self):
            # 每隔一定步数更新,代表积累了一定的经验才进行总结,这样显得不那么武断,对应到神经网络,就是更新效率高,容易收敛
            if self.learn_step_counter % self.replace_target_iter == 0:     # 更新神经网络参数
                self.sess.run(self.replace_target_op)
                print('
    target_params_replaced
    ')
    
            ##### 取样本
                ## memory 是 初始化一个 memory_size 的数据表,当记忆大于这个表时,表已被填满,随机从表中选择记忆即可,
                ## 当记忆小于这个表时,表未被填满,只能从记忆里随机选样本
            if self.memory_counter > self.memory_size:
                sample_index = np.random.choice(self.memory_size, size=self.batch_size)
            else:
                sample_index = np.random.choice(self.memory_counter, size=self.batch_size)
            batch_memory = self.memory[sample_index, :]
    
            ##### 训练神经网络
                # 利用神经网络 计算 q_next 下个状态的q值,q_eval 当前状态的q值
            q_next, q_eval = self.sess.run([self.q_next, self.q_eval], feed_dict={
                    self.s_: batch_memory[:, -self.n_features:],   # 下一个状态
                    self.s: batch_memory[:, :self.n_features],     # 当前状态
                })
    
            q_target = q_eval.copy()        # q_eval 是q 估计
    
            ### 更新 q learning 的 q表
            ## 每个真实实验有个动作和奖励
            batch_index = np.arange(self.batch_size, dtype=np.int32)
            eval_act_index = batch_memory[:, self.n_features].astype(int)   # 动作
            reward = batch_memory[:, self.n_features + 1]                   # 奖励
    
            ## 更新q表
            q_target[batch_index, eval_act_index] = reward + self.gamma * np.max(q_next, axis=1)        # q 现实
            # 注意这里的动作当前状态选择的动作,而不是下个状态基于贪心的动作
    
            # train eval network
            _, self.cost = self.sess.run([self._train_op, self.loss],
                                         feed_dict={self.s: batch_memory[:, :self.n_features],
                                                    self.q_target: q_target})
            self.cost_his.append(self.cost)
    
            # increasing epsilon
            self.epsilon = self.epsilon + self.epsilon_increment if self.epsilon < self.epsilon_max else self.epsilon_max
            self.learn_step_counter += 1

     图示如下

  • 相关阅读:
    SpringCloud微服务初步认识
    SpringCloud-Hystrix:服务熔断与降级
    List接口下重要集合源码分析
    高频面试题:手写一个LRU
    Java基础面试题面经整理(持续更新)
    Redis高可用之主从复制
    Redis过期键删除和内存淘汰
    Redis持久化(RDB与AOF)
    了解Redis事务
    Redis入门与安装
  • 原文地址:https://www.cnblogs.com/yanshw/p/10563026.html
Copyright © 2020-2023  润新知