强化学习_DDPG算法实现Pendulum-v1

DDPG算法原理

全称是 deep deterministic policy gradient, 深度确定性策略梯度算法。

DDPG 是解決连续控制型问题的的一个算法,不过和 PPO 不一样,PPO输出的是一个策略,也就是一个概率分布,而 DDPG 输出的直接是一个动作。

在这里插入图片描述

DDPG 更接近 DQN,是用一个actor去弥补 DQN 不能处理连续控制性问题的缺点。我们先来回顾 DQN。DQN是更新动作的q值:

在这里插入图片描述

我们从公式中也能看出,DQN 不能用于连续控制问题原因,是因为 maxQ(s’,a’)函数只能处理离散型的。

我们知道 DQN 用magic函数,也就是神经网络解决了 Qlearning 不能解决的连续状态空间问题。同样的,DDPG 就是用magic 解決 DQN 不能解决的连续控制型问题。

也就是说,用一个 magic 函数,直接替代 maxQ(s’,a’)的功能。也就是说,我们期待我们输入状态 S,magic 函数返回我们动作 action 的取值,这个取值能够让q 值最大。这个就是DDPG 中的Actor的功能。

在这里插入图片描述

综上所述:

Critic:

  • Critic 网络的作用是预估 Q,注意Critic 的输入有两个:动作和状态。
  • Critic 网络的loss 用的是 TD-error

Actor:

  • 和AC 不同,Actor输出的是一个动作;
  • Actor的功能是,输出一个动作 A,这个动作A输入到 Critic 后,能够获得最大的Q值。

fix network技术

另外,和 DQN 一样,更新的时候如果更新目标在不断变动,会造成更新困难。

所以DDPG 和 DQN一样,用了固定网络(fix network)技术,就是先冻结住用来求target 的网络。在更新一段时间之后,再把参数赋值到target 网络。

实际操作的时候,我们需要 4 个网络: actor, critic, actor_target, cirtic_target

在这里插入图片描述

TD3

TD3是Twin Delayed Deep Deterministic policy gradient algorithm 的简称,双延迟深度确定性策略梯度。

也就是说TD3是DDPG 的一个优化版本。其中有三个非常重要的优化。

double network

DDPG 起源于 DQN,是 DQN 解决连续控制问题的一个解决方法。而 DQN 有一个众所周知的问题,就是 Q值会被高估。

而这个问题也会出现在 DDPG 中,而要解决这个问题的思路,我们可以借鉴 double DQN。

在TD3中,多用了两套网络估算Q值,这样,DDPG 算法涉及了 4 个网络,所以TD3 需要用到6个网络。

我们先看看 DDPG 中的网络架构:
在这里插入图片描述

上图中,我们通过 Critic 网络估算动作A的Q值。一个Critic 的评估可能会较高。所以我们加一个,两个Critic网络互相监督。

在这里插入图片描述

在目标网络中,我们估算出来的 Q值会用min()函数求出较少值。以这个值作为更新的目标。这个目标会更新两个网络Critic 网络1和Critic 网络2,过一段时间,把学习好的网络赋值给目标网络。

Critic部分的学习:

  • 只有我们在计算 Critic 的更新目标时,我们才用 target network(其中就包括了一个Policy network,用于计算 A’;两个Qnetwork,用于计算两个Q值:Q1(A)和Q2(A))

  • Q1(A) 和Q2(A)取最小值min(Q1,Q2) 将代替 DDPG 的 Q(a)计算更新目标

  • 也就是说: target = min(Q1,Q2) * gamma + r,target 将会是 Qnetwork 1 和 Qnetwork 2 两个网络的更新目标。

Actor 部分的学习:

  • actor的任务,就是用梯度上升的方法,寻着使得 Q值最高的 action。
  • 对于 actor 来说,其实并不在乎 Q 值是否会被高估,那是critic 该做的事情,他的任务只是不断做梯度上升,寻找这最大的 Q 值。

Delayed Actor Update

这里说的 Delayed,是actor 更新的delay。也就是说 critic 更新多次后,actor 再进行更新。

其实这里特别好理解,critic像一个老师,actor像一个学生,老师给打分的方式要固定一些,学生才知道该学什么和怎么学才能得到更高分,反过来说,老师如果打分方式总变,那么学生就会很迷茫,学的时候就会各种策略去试,心态也会不好,学起来不稳定,这里对应就是 actor 收敛慢,参数更新来回震荡。

target policy smoothing regularization

TD3中,价值函数的更新目标每次都在action上加一个小扰动,这个操作就是 target policy smoothing regularization

注意这里是给 actor 目标网络输出的 action 增加 noise,而不是给真正给出实际输出的action 增加noise。

这里给actor 目标网络输出的action 增加noise,是为了给后面增加难度,如果能在有输入干扰的情况下,也能给出正确的分值,那么我们的critic 就有更好的 泛化能力。

DDPG代码实现

"""
Note: This is a updated version from my previous code,
for the target network, I use moving average to soft replace target parameters instead using assign function.
By doing this, it has 20% speed up on my machine (CPU).

Deep Deterministic Policy Gradient (DDPG), Reinforcement Learning.
DDPG is Actor Critic based algorithm.
Pendulum example.

View more on my tutorial page: https://morvanzhou.github.io/tutorials/

Using:
tensorflow 1.0
gym 0.8.0
"""

import tensorflow.compat.v1 as tf
tf.disable_v2_behavior()

import numpy as np
import gym
import time


#####################  hyper parameters  ####################

MAX_EPISODES = 200
MAX_EP_STEPS = 200
LR_A = 0.001    # learning rate for actor
LR_C = 0.002    # learning rate for critic
GAMMA = 0.9     # reward discount
TAU = 0.01      # soft replacement
MEMORY_CAPACITY = 10000
BATCH_SIZE = 32

RENDER = False
ENV_NAME = 'Pendulum-v1'


###############################  DDPG  ####################################


class DDPG(object):
    def __init__(self, a_dim, s_dim, a_bound,):
        self.memory = np.zeros((MEMORY_CAPACITY, s_dim * 2 + a_dim + 1), dtype=np.float32)
        self.pointer = 0
        self.sess = tf.Session()

        self.a_dim, self.s_dim, self.a_bound = a_dim, s_dim, a_bound,
        self.S = tf.placeholder(tf.float32, [None, s_dim], 's')
        self.S_ = tf.placeholder(tf.float32, [None, s_dim], 's_')
        self.R = tf.placeholder(tf.float32, [None, 1], 'r')

        self.a = self._build_a(self.S,)
        q = self._build_c(self.S, self.a, )
        a_params = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope='Actor')
        c_params = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope='Critic')
        ema = tf.train.ExponentialMovingAverage(decay=1 - TAU)          # soft replacement

        def ema_getter(getter, name, *args, **kwargs):
            return ema.average(getter(name, *args, **kwargs))

        target_update = [ema.apply(a_params), ema.apply(c_params)]      # soft update operation
        a_ = self._build_a(self.S_, reuse=True, custom_getter=ema_getter)   # replaced target parameters
        q_ = self._build_c(self.S_, a_, reuse=True, custom_getter=ema_getter)

        a_loss = - tf.reduce_mean(q)  # maximize the q
        self.atrain = tf.train.AdamOptimizer(LR_A).minimize(a_loss, var_list=a_params)

        with tf.control_dependencies(target_update):    # soft replacement happened at here
            q_target = self.R + GAMMA * q_
            td_error = tf.losses.mean_squared_error(labels=q_target, predictions=q)
            self.ctrain = tf.train.AdamOptimizer(LR_C).minimize(td_error, var_list=c_params)

        self.sess.run(tf.global_variables_initializer())

    def choose_action(self, s):
        return self.sess.run(self.a, {self.S: s[np.newaxis, :]})[0]

    def learn(self):
        indices = np.random.choice(MEMORY_CAPACITY, size=BATCH_SIZE)
        bt = self.memory[indices, :]
        bs = bt[:, :self.s_dim]
        ba = bt[:, self.s_dim: self.s_dim + self.a_dim]
        br = bt[:, -self.s_dim - 1: -self.s_dim]
        bs_ = bt[:, -self.s_dim:]

        self.sess.run(self.atrain, {self.S: bs})
        self.sess.run(self.ctrain, {self.S: bs, self.a: ba, self.R: br, self.S_: bs_})

    def store_transition(self, s, a, r, s_):
        transition = np.hstack((s, a, [r], s_))
        index = self.pointer % MEMORY_CAPACITY  # replace the old memory with new memory
        self.memory[index, :] = transition
        self.pointer += 1

    def _build_a(self, s, reuse=None, custom_getter=None):
        trainable = True if reuse is None else False
        with tf.variable_scope('Actor', reuse=reuse, custom_getter=custom_getter):
            net = tf.layers.dense(s, 30, activation=tf.nn.relu, name='l1', trainable=trainable)
            a = tf.layers.dense(net, self.a_dim, activation=tf.nn.tanh, name='a', trainable=trainable)
            return tf.multiply(a, self.a_bound, name='scaled_a')

    def _build_c(self, s, a, reuse=None, custom_getter=None):
        trainable = True if reuse is None else False
        with tf.variable_scope('Critic', reuse=reuse, custom_getter=custom_getter):
            n_l1 = 30
            w1_s = tf.get_variable('w1_s', [self.s_dim, n_l1], trainable=trainable)
            w1_a = tf.get_variable('w1_a', [self.a_dim, n_l1], trainable=trainable)
            b1 = tf.get_variable('b1', [1, n_l1], trainable=trainable)
            net = tf.nn.relu(tf.matmul(s, w1_s) + tf.matmul(a, w1_a) + b1)
            return tf.layers.dense(net, 1, trainable=trainable)  # Q(s,a)


###############################  training  ####################################

env = gym.make(ENV_NAME, render_mode='human')
env = env.unwrapped


s_dim = env.observation_space.shape[0]
a_dim = env.action_space.shape[0]
a_bound = env.action_space.high

ddpg = DDPG(a_dim, s_dim, a_bound)

var = 3  # control exploration
t1 = time.time()
for i in range(MAX_EPISODES):
    s = env.reset()[0]
    ep_reward = 0
    for j in range(MAX_EP_STEPS):
        if RENDER:
            env.render()

        # Add exploration noise
        a = ddpg.choose_action(s)
        a = np.clip(np.random.normal(a, var), -2, 2)    # add randomness to action selection for exploration
        s_, r, done, info, _ = env.step(a)

        ddpg.store_transition(s, a, r / 10, s_)

        if ddpg.pointer > MEMORY_CAPACITY:
            var *= .9995    # decay the action randomness
            ddpg.learn()

        s = s_
        ep_reward += r
        if j == MAX_EP_STEPS-1:
            print('Episode:', i, ' Reward: %i' % int(ep_reward), 'Explore: %.2f' % var, )
            # if ep_reward > -300:RENDER = True
            break

print('Running time: ', time.time() - t1)
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,DQN算法是一种比较经典的深度强化学习算法Pendulum-v1是一个经典的强化学习环境,其中智能体需要控制一个单摆来保持竖直。下面是DQN算法Pendulum-v1环境中的实现步骤: 1. 确定状态空间、动作空间和奖励函数:在Pendulum-v1环境中,状态空间为一个三维向量,包括单摆的角度、角速度和角加速度。动作空间为一个连续的动作,即施加的扭矩大小。奖励函数为当前状态下的负平方误差。 2. 构建深度神经网络:使用深度神经网络作为Q函数的估计器。神经网络的输入是当前状态,输出是每个动作的Q值。 3. 初始化经验回放缓存:使用经验回放机制来平衡数据的相关性和效率。将所有的经验数据存储在一个缓存池中,每次训练时从中随机采样一批数据进行训练。 4. 进行训练:在每个时间步中,智能体根据当前状态选择一个动作,使用选择的动作与环境进行交互,得到下一个状态和奖励,将这些经验加入经验回放缓存中。然后从经验回放缓存中随机采样一批数据进行训练,并更新深度神经网络的参数。 5. 执行策略:在每个时间步中,根据当前状态和深度神经网络的参数计算出每个动作的Q值,选择具有最大Q值的动作执行。 6. 调整超参数:根据实验效果调整超参数,如神经网络的结构、学习率、折扣因子等。 以上就是DQN算法Pendulum-v1环境中的实现步骤,需要注意的是,由于动作空间是连续的,所以需要采用一些技巧来处理。比如可以使用深度确定性策略梯度(DDPG)算法来解决连续动作空间的问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

¥骁勇善战¥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值