确定性策略梯度DDPG

确定性策略梯度DDPG

一月 03, 2021

DDPG是google DeepMind团队提出的一种用于输出确定性动作的算法,它解决了Actor-Critic 神经网络每次参数更新前后都存在相关性,导致神经网络只能片面的看待问题这一缺点。同时也解决了DQN不能用于连续性动作的缺点。

论文链接:https://arxiv.org/pdf/1509.02971.pdf

确定性策略

确定性策略是和随机策略相对而言的,对于某一些动作集合来说,它可能是连续值,或者非常高维的离散值,这样动作的空间维度极大。如果我们使用随机策略,即像DQN一样研究它所有的可能动作的概率,并计算各个可能的动作的价值的话,那需要的样本量是非常大才可行的。于是有人就想出使用确定性策略来简化这个问题。

作为随机策略,在相同的策略,在同一个状态处,采用的动作是基于一个概率分布的,即是不确定的。而确定性策略则决定简单点,虽然在同一个状态处,采用的动作概率不同,但是最大概率只有一个,如果我们只取最大概率的动作,去掉这个概率分布,那么就简单多了。即作为确定性策略,相同的策略,在同一个状态处,动作是唯一确定的,即策略变成 $\pi_\theta(s) = a$。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class MLPActorCritic(nn.Module):

def __init__(self, observation_space, action_space, hidden_sizes=(256,256),
activation=nn.ReLU):
super().__init__()

obs_dim = observation_space.shape[0]
act_dim = action_space.shape[0]
act_limit = action_space.high[0]

# build policy and value functions
self.pi = MLPActor(obs_dim, act_dim, hidden_sizes, activation, act_limit)
self.q = MLPQFunction(obs_dim, act_dim, hidden_sizes, activation)

def act(self, obs):
with torch.no_grad():
return self.pi(obs).numpy()

理由:

  • 即使通过PG学习得到了随机策略之后,在每一步行为时,我们还需要对得到的最优策略概率分布进行采样,才能获得action的具体值;而action通常是高维的向量,比如25维、50维,在高维的action空间的频繁采样,无疑是很耗费计算能力的;
  • 在PG的学习过程中,每一步计算policy gradient都需要在整个action space进行积分。

DPG到DDPG

使用卷积神经网络来模拟策略函数和Q函数,并用深度学习的方法来训练,证明了在RL方法中,非线性模拟函数的准确性和高性能、可收敛;

而DPG中,可以看成使用线性回归的机器学习方法:使用带参数的线性函数来模拟策略函数和Q函数,然后使用线性回归的方法进行训练。

experience replay memory的使用:actor同环境交互时,产生的transition数据序列是在时间上高度关联(correlated)的,如果这些数据序列直接用于训练,会导致神经网络的overfit,不易收敛。

DDPG的actor将transition数据先存入experience replay buffer, 然后在训练时,从experience replay buffer中随机采样mini-batch数据,这样采样得到的数据可以认为是无关联的。

target 网络和online 网络的使用, 使的学习过程更加稳定,收敛更有保障。

实现框架

framwork

算法流程

algorithm

Exploration

DDPG以非策略的方式训练确定性策略。因为策略是确定的,如果agent要探索on-policy,在一开始它可能不会尝试足够广泛的行动来找到有用的学习信号。为了使DDPG政策更好地探索,我们在训练时为他们的行动添加噪音。原始DDPG论文的作者推荐了时间相关的OU噪声,但最近的结果表明,不相关、均值为零的高斯噪声工作得很好。因为后者更简单,所以更可取。为了便于获得高质量的训练数据,您可以在训练过程中减少噪声的规模。(我们在实现中没有这样做,并始终保持噪声规模固定。)

1
2
3
4
def get_action(o, noise_scale):
a = ac.act(torch.as_tensor(o, dtype=torch.float32))
a += noise_scale * np.random.randn(act_dim)
return np.clip(a, -act_limit, act_limit)