通过把Policy Based 和Value Based结合起来的Actor Critic,解决了Value Based如Q-Learning的无法解决连续和高维度问题,也解决了Policy Based的效率低速度慢的问题。但是同样的,像DQN一样,在使用神经网络进行值估计的时候,神经网络的相关性都太强了,梯度更新相互依赖,导致网络将会学不到东西。
有两种解决方法:DDPG和AC3。
DDPG
Actor-Critic+DQN=Deep Deterministic Policy Gradient。
先将这个词拆成三部分:
- Deep:使用神经网络估计值。
- Policy Gradient:根据学习到的策略分布输出筛选动作。
- Deterministic:斩钉截铁的输出一个动作。因为以往的随机策略会先学习动作分布再随机进行筛选,在某些场景中的动作维度(动作多或联系性动作)可能极大,如果想精确的学习到概率分布需要很大的样本。但是不管动作维度怎么样,最大概率肯定是只有一个,所以确定性策略就直接输出概率最大的动作就可以了。
Actor-Critic+DQN,两者如何融合?
Actor-Critic:Actor网络学习动作策略,Critic网络用于评价动作。
DQN:记忆库,两套网络解决网络相关性。
DQN中的两套网络是为了计算价值函数,那么还是Value Based,现在加入了Policy Based后,同样也需要两套网络来计算策略函数。即使用双Actor神经网络和双Critic神经网络共有4套网络的方法来改善神经网络更新的收敛性。
对于Actor的双网络 ,有用来估计的新网络和延迟的旧网络。估计网络用来输出实时的动作,而旧网络则是用来更新价值网络系统的.。
对于Critic的双网络,也有估计的新网络和延迟的旧网络。它们都输出根据状态的输出相应的value价值,估计网络根据actor的动作进行输出,而旧网络会根据actor旧网络得到的动作进行输出。
太绕了,于是博主自己画了一张图:
即先从一个状态S出发,通过Actor新网络得到动作A并执行,存入记忆库。然后从记忆库中采样,得到Si,Ai,Si’,Si’通过Actor旧网络得到动作Ai’,用于给Critic更新参数,即输入到Critic旧网络中得到一个“现实目标值”Q’,即可以算出在这个状态下的动作总值y,和Critic的估计值进行均方误差就可以更新Critic网络了。(AC中是用前后V值差的均方来更新,现在使用了旧网络能够更加的客观)而actor的网络用Critic新网络得到的Q值来评价动作的好坏,即就用来更新了Actor网络。(AC中是用Reward的TD误差来更新,现在通过旧网络同样更客观了)
Critic 参数更新公式为:
旧网络会依据下一状态, 用 Actor旧网络中的结果来选择动作,使用这种方法获得的值能像 DQN 那样切断相关性, 以更好的提高收敛性。
Actor参数更新公式为:
前半部分从Critic新网络来的, 用于评价Actor的动作要怎么移动, 才能获得更大的 Q, 而后半部分是从 Actor 来的, 用于说明Actor 要怎么样修改自身参数, 使得 Actor 更有可能做这个动作. 所以两者合起来就是在说: Actor 要朝着更有可能获取大 Q 的方向修改动作参数。
再看下整体的算法流程:
- 初始化四套神经网络的参数,θ,θ′,w,w′和记忆库R。
- 对于每次迭代,初始化第一个状态S,得到其特征向量。
- Actor网络根据状态S得到动作A(算法中的N为随机噪音,可以增加一些随机性)。执行动作A,得到新状态S’和奖励r,存入记忆库R。
- 然后从R中采样N组,计算当前目标Q值y_i,其中要先从actor旧网络中得到策略,再结合状态输入到Critic旧网络中才是Q’,才能得到y_i
- 使用均方误差更新Critic,梯度反向来更新Actor。
- C步之后,更新旧网络的参数。直到结束。
使用keras实现DDPG
def Actor_network(self):
inp = Input((self.env_dim)) #环境状态的维度
x = Dense(256, activation='relu')(inp)
x = GaussianNoise(1.0)(x) #随机变量以增加随机性,探索性
x = Flatten()(x)
x = Dense(128, activation='relu')(x) #relu激活
x = GaussianNoise(1.0)(x)
out = Dense(self.act_dim, activation='tanh', kernel_initializer=RandomUniform())(x)
out = Lambda(lambda i: i * self.act_range)(out)
return Model(inp, out)
def Critic_network(self):
state = Input((self.env_dim))
action = Input((self.act_dim,)) #输入s和a,计算value值
x = Dense(256, activation='relu')(state)
x = concatenate([Flatten()(x), action])
x = Dense(128, activation='relu')(x)
out = Dense(1, activation='linear', kernel_initializer=RandomUniform())(x)
return Model([state, action], out)
def memorize(self, state, action, reward, done, new_state):
self.buffer.memorize(state, action, reward, done, new_state)#记忆库
def update_models(self, states, actions, critic_target):#从采样中更新两个网络
self.critic.train_on_batch(states, actions, critic_target)#训练Critic
# 从当前策略计算Q
actions = self.actor.model.predict(states)
grads = self.critic.gradients(states, actions)
self.actor.train(states, actions, np.array(grads).reshape((-1, self.act_dim)))#训练actor
#隔一段时间就copy到旧网络中
self.actor.transfer_weights()
self.critic.transfer_weights()
time, cumul_reward, done = 0, 0, False
old_state = env.reset()
actions, states, rewards = [], [], []
noise = OrnsteinUhlenbeckProcess(size=self.act_dim)
while not done:
if args.render: env.render()
a = self.policy_action(old_state) #根据状态选确定的动作
a = np.clip(a+noise.generate(time), -self.act_range, self.act_range)#clip限制在范围中
new_state, r, done, _ = env.step(a) #得到新状态,奖励,是否终端
self.memorize(old_state, a, r, done, new_state)#加入到记忆库
states, actions, rewards, dones, new_states, _ = self.sample_batch(args.batch_size)#从记忆库采样
q_values = self.critic.target_predict([new_states, self.actor.target_predict(new_states)]) #在旧网络预测Q
critic_target = self.bellman(rewards, q_values, dones)
self.update_models(states, actions, critic_target)#训练网络
old_state = new_state #更新状态
cumul_reward += r
time += 1 #时间步控制旧网络的更新
A3C(Asynchronous Advantage Actor-Critic)
同样为了解决神经网络更新太依赖的问题,A3C的方法是使用了多线程并行计算,使不同的副本学习到不同的知识并相互通信共同的完成任务,这样网络之间也就没有那么的依赖,解决了不收敛的问题。
即有一个主线程负责更新Actor和Critic的参数,多个辅线程负责分别和环境交互,一定次数后能得到梯度更新值,但是不是更新自己而汇总一起更新主线程网络的参数。而所有的辅线程会定期从主线程更新网络参数。这些辅线程还是起到了类似DQN中经验回放的作用,但是效果更好,而且大大提高了速度。
DPPO
PPO(Proximal Policy Optimization)
主要是限制更新步长。因为学习速率慢时间就长,学习速率快就容易躁动。
限制的部分就在于actor的更新,A会乘一个新旧概率比,如果差距大优势大那么学习幅度就加大,同时还要减去一个新旧的分布的KL,做以惩罚项,让他们不要差距太大。
另外也可以不要KL的惩罚项,因为惩罚也是为了限制它的更新速度,那么直接对新旧比的出现幅度进行控制就可以了。(比如倍数不超过多少倍),即clip。
Distributed PPO
类似与AC3的多线程。