Deep learning 一个简单控制问题的DDPG不收敛

Deep learning 一个简单控制问题的DDPG不收敛,deep-learning,reinforcement-learning,q-learning,policy-gradient-descent,Deep Learning,Reinforcement Learning,Q Learning,Policy Gradient Descent,我试图用DDPG解决一个控制问题。这个问题很简单,所以我可以对它的离散化版本进行值函数迭代,因此我有一个“完美”的解决方案来比较我的结果。但是我想用DDPG解决这个问题,希望能把RL应用到更难的版本上 有关该问题的一些详细信息: 控制空间为[0,1],状态空间的维数为2 这是一个随机环境,状态之间的转换不是确定性的 在任何时期都有一些非恒定的奖励,所以稀疏的奖励应该不是问题 值函数迭代只需要10分钟左右,同样,这是一个非常简单的控制问题 问题出在哪里: 我的代理最终总是收敛到一个退化策略,动作总

我试图用DDPG解决一个控制问题。这个问题很简单,所以我可以对它的离散化版本进行值函数迭代,因此我有一个“完美”的解决方案来比较我的结果。但是我想用DDPG解决这个问题,希望能把RL应用到更难的版本上

有关该问题的一些详细信息

  • 控制空间为[0,1],状态空间的维数为2
  • 这是一个随机环境,状态之间的转换不是确定性的
  • 在任何时期都有一些非恒定的奖励,所以稀疏的奖励应该不是问题
  • 值函数迭代只需要10分钟左右,同样,这是一个非常简单的控制问题
  • 问题出在哪里

    我的代理最终总是收敛到一个退化策略,动作总是1或0。在训练过程中的某个时刻,它可能有点接近正确的策略,但它永远不会真正接近

    类似地,我通常无法正确获得Q函数的形状:

    我想做的事

  • 我在actor网络的末尾放了一个sigmoid层(很自然,因为控制空间是[0,1])
  • 我有政策和批评的目标网络
  • 我拍拍我的动作,使它们在[0.01,0.99]之间(完美的解决方案总是在这些边界内)
  • 我尝试添加一些人工惩罚来奖励接近0和1的动作。然后,算法收敛到了其他的东西,但又不是好的东西
  • 我尝试了随机均匀探测或添加小的正常噪声。我要么随时间降低探测速度,要么保持恒定但很小
  • 为了检查我的代码,我运行了以下实验。我会首先修正政策,使之成为“完美”的政策,并且只更新批评家。在这种情况下,我很好地学习了Q网络(形状也一样)。然后,我冻结批评家并使用DDPG更新规则只更新参与者。我设法接近完美的政策。但当我开始同时更新演员和评论家的时候,他们又偏离了原来的方向
  • 我用我的超参数做了很多实验,目前它们如下:
  • 如果您有任何建议,我将不胜感激,谢谢

    我已经面对并更改了模型、网络、剧集数量以及所有其他参数,如学习率,以适应您的环境,这些都可能解决问题。但是,它在某些环境中表现不佳。因此,我改为A2C,因为它显示了更好的结果。
    这是我得到更好结果的DDPG模型和参数:

    import os
    
    import tensorflow as tf
    import numpy as np
    from collections import deque
    label = 'DDPG_model'
    rand_unif = tf.keras.initializers.RandomUniform(minval=-3e-3,maxval=3e-3)
    import var
    winit = tf.contrib.layers.xavier_initializer()
    binit = tf.constant_initializer(0.01)
    class CriticNetwork(object):
        def __init__(self, sess, s_dim, a_dim, learning_rate=1e-3, tau=1e-3, gamma=0.995, hidden_unit_size=64):
    
            self.sess = sess
            self.s_dim = s_dim
            self.a_dim = a_dim
            self.hidden_unit_size = hidden_unit_size
            self.learning_rate = learning_rate
            self.tau = tau
            self.gamma = gamma
            self.seed = 0
    
            # Create the critic network
            self.inputs, self.action, self.out = self.buil_critic_nn(scope='critic')
            self.network_params = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope='critic')
    
            # Target Network
            self.target_inputs, self.target_action, self.target_out = self.buil_critic_nn(scope='target_critic')
            self.target_network_params = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope='target_critic')
    
            # Op for periodically updating target network with online network
            # weights with regularization
            self.update_target_network_params = [self.target_network_params[i].assign(
                tf.multiply(self.network_params[i], self.tau) + tf.multiply(self.target_network_params[i], 1. - self.tau))
                                                 for i in range(len(self.target_network_params))]
    
            # Network target (y_i)
            self.predicted_q_value = tf.placeholder(tf.float32, [None, 1])
    
            # Define loss and optimization Op
            self.loss = tf.losses.huber_loss(self.out,self.predicted_q_value, delta=0.5)
            self.optimize = tf.train.AdamOptimizer(
                self.learning_rate).minimize(self.loss)
            if var.opt == 2:
                self.optimize = tf.train.RMSPropOptimizer(learning_rate=var.learning_rate, momentum=0.95,
                                                          epsilon=0.01).minimize(self.loss)
            elif var.opt == 0:
                self.optimize = tf.train.GradientDescentOptimizer(learning_rate=var.learning_rate).minimize(self.loss)
    
            # Get the gradient of the net w.r.t. the action.
            # For each action in the minibatch (i.e., for each x in xs),
            # this will sum up the gradients of each critic output in the minibatch
            # w.r.t. that action. Each output is independent of all
            # actions except for one.
            self.action_grads = tf.gradients(self.out, self.action)
    
        def buil_critic_nn(self, scope='network'):
            hid1_size = self.hidden_unit_size
            hid2_size = self.hidden_unit_size
            with tf.variable_scope(scope, reuse=tf.AUTO_REUSE):
                state = tf.placeholder(name='c_states', dtype=tf.float32, shape=[None, self.s_dim])
                action = tf.placeholder(name='c_action', dtype=tf.float32, shape=[None, self.a_dim])
    
                net = tf.concat([state, action], 1)
    
                net1 = tf.layers.dense(inputs=net, units=1000, activation="linear",
                                       kernel_initializer=tf.zeros_initializer(),
                                       name='anet1')
    
                net2 = tf.layers.dense(inputs=net1, units=520, activation="relu", kernel_initializer=tf.zeros_initializer(),
                                       name='anet2')
                net3 = tf.layers.dense(inputs=net2, units=220, activation="linear", kernel_initializer=tf.zeros_initializer(),
                                       name='anet3')
    
    
                out = tf.layers.dense(inputs=net3, units=1,
                                      kernel_initializer=tf.zeros_initializer(),
                                      name='anet_out')
                out = (tf.nn.softsign(out))
    
    
            return state, action, out
    
        def train(self, inputs, action, predicted_q_value):
            return self.sess.run([self.out, self.optimize], feed_dict={
                self.inputs: inputs,
                self.action: action,
                self.predicted_q_value: predicted_q_value
            })
    
        def predict(self, inputs, action):
            return self.sess.run(self.out, feed_dict={
                self.inputs: inputs,
                self.action: action
            })
    
        def predict_target(self, inputs, action):
            return self.sess.run(self.target_out, feed_dict={
                self.target_inputs: inputs,
                self.target_action: action
            })
    
        def action_gradients(self, inputs, actions):
            return self.sess.run(self.action_grads, feed_dict={
                self.inputs: inputs,
                self.action: actions
            })
    
        def update_target_network(self):
            self.sess.run(self.update_target_network_params)
        def return_loss(self, predict, inputs, action):
            return self.sess.run(self.loss ,feed_dict={
            self.predicted_q_value: predict, self.inputs: inputs,
                self.action: action})
    
    
    
    
    class ActorNetwork(object):
        def __init__(self, sess, s_dim, a_dim,lr=1e-4,  tau=1e-3, batch_size=64,action_bound=1):
    
            self.sess = sess
            self.s_dim = s_dim
            self.a_dim = a_dim
            self.act_min = 0
            self.act_max = 51
    
            self.hdim = 64
            self.lr = lr
    
            self.tau = tau  # Parameter for soft update
            self.batch_size = batch_size
    
            self.seed = 0
            self.action_bound = action_bound
            # Actor Network
            self.inputs, self.out , self.scaled_out =  self.create_actor_network(scope='actor')
            self.network_params = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope='actor')
    
            # Target Network
            self.target_inputs, self.target_out, self.target_scaled_out = self.create_actor_network(scope='target_actor')
            self.target_network_params = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope='target_actor')
    
            # Parameter Updating Operator
            self.update_target_network_params = [self.target_network_params[i].assign(
                tf.multiply(self.network_params[i], self.tau) + tf.multiply(self.target_network_params[i], 1. - self.tau))
                for i in range(len(self.target_network_params))]
            self.action_gradient = tf.placeholder(tf.float32, [None, self.a_dim])
            # Gradient will be provided by the critic network
            self.actor_gradients = tf.gradients(self.scaled_out, self.network_params, -self.action_gradient)
    
            # Combine the gradients here
            self.unnormalized_actor_gradients = tf.gradients(self.out, self.network_params, -self.action_gradient)
            #         self.actor_gradients = list(map(lambda x: x/self.batch_size, self.unnormalized_actor_gradients))
            self.actor_gradients = [unnz_actor_grad / self.batch_size for unnz_actor_grad in
                                    self.unnormalized_actor_gradients]
    
            # Optimizer
            self.optimize = tf.train.AdamOptimizer(-self.lr).apply_gradients(zip(self.actor_gradients, self.network_params))
    
    
            if var.opt == 2:
                self.optimize = tf.train.RMSPropOptimizer(learning_rate=var.learning_rate, momentum=0.95, epsilon=0.01). \
                    apply_gradients(zip(self.unnormalized_actor_gradients, self.network_params))
            elif var.opt == 0:
                self.optimize = tf.train.GradientDescentOptimizer(learning_rate=var.learning_rate). \
                    apply_gradients(zip(self.unnormalized_actor_gradients, self.network_params))
    
            self.num_trainable_vars = len(self.network_params) + len(self.target_network_params)
    
        def create_actor_network(self, scope='network'):
            hid1_size = self.hdim
            hid2_size = self.hdim
    
            with tf.variable_scope(scope, reuse=tf.AUTO_REUSE):
                state = tf.placeholder(name='a_states', dtype=tf.float32, shape=[None, self.s_dim])
    
                net1 = tf.layers.dense(inputs=state, units=1500, activation="linear", kernel_initializer=tf.zeros_initializer(),
                                      name='anet1')
    
    
                net2 = tf.layers.dense(inputs=net1, units=1250, activation="relu",kernel_initializer=tf.zeros_initializer(), name='anet2')
    
    
    
                out = tf.layers.dense(inputs=net2, units=self.a_dim, kernel_initializer=tf.zeros_initializer(),
                                       name='anet_out')
                out=(tf.nn.sigmoid(out))
                scaled_out = tf.multiply(out, self.action_bound)
                # out = tf.nn.tanh(out)
            return state, out,scaled_out
    
        def train(self, inputs, a_gradient):
            self.sess.run(self.optimize, feed_dict={
                self.inputs: inputs,
                self.action_gradient: a_gradient
            })
    
        def predict(self, inputs):
            return self.sess.run(self.out, feed_dict={
                self.inputs: inputs
            })
    
        def predict_target(self, inputs):
            return self.sess.run(self.target_out, feed_dict={
                self.target_inputs: inputs
            })
    
        def update_target_network(self):
            self.sess.run(self.update_target_network_params)
    
        def get_num_trainable_vars(self):
            return self.num_trainable_vars
    
        def save_models(self, sess, model_path):
            """ Save models to the current directory with the name filename """
            current_dir = os.path.dirname(os.path.realpath(__file__))
            model_path = os.path.join(current_dir, "DDPGmodel" + str(var.n_vehicle) + "/" + model_path)
            saver = tf.train.Saver(max_to_keep=var.n_vehicle * var.n_neighbor)
            if not os.path.exists(os.path.dirname(model_path)):
                os.makedirs(os.path.dirname(model_path))
            saver.save(sess, model_path, write_meta_graph=True)
    
        def save(self):
            print('Training Done. Saving models...')
            model_path = label + '/agent_'
            print(model_path)
            self.save_models(self.sess, model_path)
    
        def load_models(self, sess, model_path):
            """ Restore models from the current directory with the name filename """
            dir_ = os.path.dirname(os.path.realpath(__file__))
            saver = tf.train.Saver(max_to_keep=var.n_vehicle * var.n_neighbor)
            model_path = os.path.join(dir_, "DDPGmodel" + str(var.n_vehicle) + "/" + model_path)
            saver.restore(self.sess, model_path)
    
        def load(self,sess):
            print("\nRestoring the model...")
            model_path = label + '/agent_'
            self.load_models(sess, model_path)
    
    参数

     parser = argparse.ArgumentParser(description='provide arguments for DDPG agent')
    
        # agent parameters
        parser.add_argument('--actor-lr', help='actor network learning rate', default=var.learning_rateMADDPG)
        parser.add_argument('--critic-lr', help='critic network learning rate', default=var.learning_rateMADDPG_c2)
    
        parser.add_argument('--gamma', help='discount factor for critic updates', default=0.99)
        parser.add_argument('--tau', help='soft target update parameter', default=0.001)
        parser.add_argument('--buffer-size', help='max size of the replay buffer', default=100000)
        parser.add_argument('--minibatch-size', help='size of minibatch for minibatch-SGD', default=32)
    
        # run parameters
        parser.add_argument('--env', help='choose the gym env- tested on {Pendulum-v0}', default='Pendulum-v0')
        parser.add_argument('--random-seed', help='random seed for repeatability', default=1234)
        parser.add_argument('--max-episodes', help='max num of episodes to do while training', default=var.number_eps)
        parser.add_argument('--max-episode-len', help='max length of 1 episode', default=100)
        parser.add_argument('--render-env', help='render the gym env', action='store_true')
        parser.add_argument('--use-gym-monitor', help='record gym results', action='store_true')
        parser.add_argument('--monitor-dir', help='directory for storing gym results', default='./results/gym_ddpg')
        parser.add_argument('--summary-dir', help='directory for storing tensorboard info', default='./results/tf_ddpg')
    
    要选择操作,请使用以下方法之一:

    # action = np.argmax(actions)
     action = np.random.choice(np.arange(len(actions[0])), p=actions[0])
    
    你可以找到不同的报纸谈论这个问题。例如,在论文
    [1-5]
    中,作者指出了DDPG的一些缺点,并说明了DDPG算法无法实现收敛的原因

    • DDPG设计用于具有连续且通常为高维动作空间的设置,并且随着代理数量的增加,问题变得非常尖锐
    • 第二个问题来自DDPG无法处理代理集上的可变性
    • 然而,现实平台中的设置是相当动态的,随着时间的推移,代理的到达和离开或其成本会发生变化,为了使分配算法适用,它应该能够处理这种变化
    • DDPG需要更多的步骤来覆盖
    • 改变结果表明,使用回放内存的算法在不断变化的环境中表现不佳,因为稳定性问题被视为向模型中输入观测值时的主要问题之一,该模型不能从过去的经验中正确概括,并且这些经验的使用效率低下。此外,当代理数量的增加以指数方式扩展状态-动作空间时,会出现这些问题

    1-Cai,Q.,Filos Ratsikas,A.,Tang,p.,和Zhang,Y.(2018年4月)。电子商务的强化机制设计。《2018年万维网会议记录》(第1339-1348页)

    2-Iqbal,S.,和Sha,F.(2019年5月)。多智能体强化学习的参与者注意批评家。在国际机器学习会议上(第2961-2970页)。PMLR

    3-Foerster,J.,Nardelli,N.,Farquhar,G.,Afouras,T.,Torr,p.H.,Kohli,p.,Whiteson,S.(2017年8月)。稳定体验重放,用于深度多智能体强化学习。第34届机器学习国际会议记录第70卷(第1146-1155页)。JMLR。组织

    4-侯,Y.,和张,Y.(2019)。通过优先体验重播改进DDPG。不,梅


    5-Wang,Y.,和Zhang,Z.(2019年11月)。多智能体深度强化学习中的经验选择。2019年,IEEE第31届人工智能工具国际会议(ICTAI)(第864-870页)。IEEE。

    非常感谢您的回复!我将密切关注A2C,尽管我的问题与多代理RL(我的绘图上的代理0、代理1等,用于在同一环境中进行单独的模拟)关系不大。这些规则可以应用于单代理和多代理,并尝试上面的代码,查看结果。
    # action = np.argmax(actions)
     action = np.random.choice(np.arange(len(actions[0])), p=actions[0])