强化学习-李(五):Actor-Critic【使用Critic(比如Q-Learning)作为Policy Gradient算法中评估策略好坏的手段】【可以处理离散型action、连续型action】

强化学习算法 { Value-Based Approach: Critic { State value function  V π ( s ) State-Action value function  Q π ( s , a )      ⟹     Q-Learning算法【训练Critic/值函数的参数:基于值函数结果来“间接”挑选最优 π】 Policy-Based Approach:Policy Gradient算法【“直接”训练  Actor /Policy π 的参数】    ⟹     PPO算法 Actor+Critic【使用Critic(比如Q-Learning)作为Policy Gradient算法(包括PPO)中评估策略好坏(Advantage)的手段】 \begin{aligned} \text{强化学习算法} \begin{cases} \text{Value-Based Approach:\color{violet}{Critic}} \begin{cases} \text{State value function $V^π(s)$}\\[2ex] \text{State-Action value function $Q^π(s,a)$ $\implies$ Q-Learning算法【训练Critic/值函数的参数:基于值函数结果来“间接”挑选最优 π】} \end{cases} \\[6ex] \text{Policy-Based Approach:Policy Gradient算法【“直接”训练 \color{violet}{Actor}\color{black}{/Policy π 的参数】}} \text{$\implies$ PPO算法} \\[2ex] \text{Actor+Critic}【\text{使用Critic(比如Q-Learning)作为Policy Gradient算法(包括PPO)中评估策略好坏(Advantage)的手段}】 \end{cases} \end{aligned} 强化学习算法 Value-Based ApproachCritic State value function Vπ(s)State-Action value function Qπ(s,a)  Q-Learning算法【训练Critic/值函数的参数:基于值函数结果来间接挑选最优 πPolicy-Based ApproachPolicy Gradient算法【直接训练 Actor/Policy π 的参数】 PPO算法Actor+Critic使用Critic(比如Q-Learning)作为Policy Gradient算法(包括PPO)中评估策略好坏(Advantage)的手段

一、Policy Gradient、Q-Learning算法缺点

1、Policy Gradient算法的缺点

∇ θ R ‾ θ = 1 N ∑ i = 1 N ∑ t = 1 T i [ ( ∑ t ′ = t T i γ t ′ − t r t ′ i − b ) ∇ θ l o g p θ ( a t i ∣ s t i ) ] \begin{aligned} \nabla_θ\overline{R}_θ &=\cfrac1N\sum^N_{i=1}\sum^{T_i}_{t=1}\left[(\color{violet}{\sum^{T_i}_{t'=t}γ^{t'-t}r^i_{t'}}\color{black}{-b)\nabla_θ logp_θ(a^i_t|s^i_t)}\right] \end{aligned} θRθ=N1i=1Nt=1Ti[(t=tTiγttrtib)θlogpθ(atisti)]

  • 在某一个 state s s s 采取某一个 action a a a 之后发生的事情虽然有固定的distribution,但是还是有随机性的。
    在这里插入图片描述
  • 如上图,在某一个 state s s s 采取某一个 action a a a 之后发生的事情的distribution的variance可能非常大。即:在某一个 state s s s 采取某一个 action a a a 之后得到的结果可能会是天差地别。上式中的 ∑ t ′ = t T i γ t ′ − t r t ′ i \sum^{T_i}_{t'=t}γ^{t'-t}r^i_{t'} t=tTiγttrti 是通过与环境有限次的互动获得的采样数据计算出来的,所以非常不稳定;
  • 如果取样次数够多,则不会有问题,但是实践中在update参数之前所采的样往往不够多,所以结果往往不够理想。

2、Q-Learning算法的缺点

  • Q-learning的缺点:由于Q-learning的做法是“选取一个使Q最大的action”: π ′ ( s ) = arg ⁡ max ⁡ a Q π ( s , a ) π'(s)=\arg\max_aQ^π(s,a) π(s)=argmaxaQπ(s,a),因此这个action的取值空间通常是有限且离散的,Q-learning不太容易处理连续的 action,因为无法穷举所有可能的连续action(比如:自驾车的方向盘转的角度、机器人关节的扭转角度等);而policy gradient则不存在这个问题,因为它通过policy模型根据state直接输出最优的action,那么这个action可以是任意连续的值。面对一个很大的action集合,Q-learning要计算很多遍Q值,即进行很多遍神经网络的前馈过程;相比之下,policy gradient的网络只需进行一遍网络的前馈,输出一个action值,然后与action集合中的各个值比较,选取最接近的那一个action即可。

二、Actor-Critic

∇ θ R ‾ θ = 1 N ∑ i = 1 N ∑ t = 1 T i [ ( ∑ t ′ = t T i γ t ′ − t r t ′ i − b ) ∇ θ l o g p θ ( a t i ∣ s t i ) ] = 1 N ∑ i = 1 N ∑ t = 1 T i { [ Q π θ ( s t i , a t i ) − V π θ ( s t i ) ] ∇ θ l o g p θ ( a t i ∣ s t i ) } \begin{aligned} \nabla_θ\overline{R}_θ &=\cfrac1N\sum^N_{i=1}\sum^{T_i}_{t=1}\left[(\color{violet}{\sum^{T_i}_{t'=t}γ^{t'-t}r^i_{t'}}\color{black}{-}\color{blue}{b}\color{black}{)\nabla_θ logp_θ(a^i_t|s^i_t)}\right]\\ &=\cfrac1N\sum^N_{i=1}\sum^{T_i}_{t=1}\left\{[\color{violet}{Q^{π_θ}(s^i_t,a^i_t)}\color{black}{-}\color{blue}{V^{π_θ}(s^i_t)}\color{black}{]\nabla_θ logp_θ(a^i_t|s^i_t)}\right\}\\ \end{aligned} θRθ=N1i=1Nt=1Ti[(t=tTiγttrtib)θlogpθ(atisti)]=N1i=1Nt=1Ti{[Qπθ(sti,ati)Vπθ(sti)]θlogpθ(atisti)}

  • ∵ \textbf{∵} ∑ t ′ = t T i γ t ′ − t r t ′ i = Q π θ ( s t i , a t i ) \sum^{T_i}_{t'=t}γ^{t'-t}r^i_{t'}=Q^{π_θ}(s^i_t,a^i_t) t=tTiγttrti=Qπθ(sti,ati) ,所以将Policy Gradient算法中的 ∑ t ′ = t T i γ t ′ − t r t ′ i \sum^{T_i}_{t'=t}γ^{t'-t}r^i_{t'} t=tTiγttrti 换成 Critic中的一种,即 State-Action value function: Q π θ ( s t i , a t i ) Q^{π_θ}(s^i_t,a^i_t) Qπθ(sti,ati)
  • 将Policy Gradient算法中的 b b b 换成 Critic中的一种,即 State value function: V π ( s ) V^π(s) Vπ(s)

在这里插入图片描述

三、Advantage Actor-Critic(A2C)

  • 实践中,如果简单地用式子 Q π θ ( s t i , a t i ) − V π ( s ) Q^{π_θ}(s^i_t,a^i_t)-V^π(s) Qπθ(sti,ati)Vπ(s) 代替 ∑ t ′ = t T i γ t ′ − t r t ′ i − b \sum^{T_i}_{t'=t}γ^{t'-t}r^i_{t'}-b t=tTiγttrtib,也可以操作,但是要使用 2 个Network,一个负责 Q π θ ( s t i , a t i ) Q^{π_θ}(s^i_t,a^i_t) Qπθ(sti,ati),另一个负责 V π ( s ) V^π(s) Vπ(s)。估测不准的风险增大。所以要想办法简化模型。
  • ∵ \textbf{∵} Q π ( s t i , a t i ) = E [ r t i + V π ( s t + 1 i ) ] Q^π(s^i_t,a^i_t)=E[r^i_t+V^π(s^i_{t+1})] Qπ(sti,ati)=E[rti+Vπ(st+1i)] 在 state s t s_t st 采取 action a t a_t at,接下来你会得到 reward r t r_t rt,然后跳到 state s t + 1 s_{t+1} st+1,但是你会得到什么样的 reward r t r_t rt 以及跳到什么样的 state s t + 1 s_{t+1} st+1,本身是有随机性的,所以要取一个期望值,左式才会等于右式。即 Q π ( s t i , a t i ) Q^π(s^i_t,a^i_t) Qπ(sti,ati) 等于 r t i + V π ( s t + 1 i ) r^i_t+V^π(s^i_{t+1}) rti+Vπ(st+1i) 的期望值。
  • 现在把期望值这件事情拿掉,直接让 Q π ( s t i , a t i ) = r t i + V π ( s t + 1 i ) Q^π(s^i_t,a^i_t)=r^i_t+V^π(s^i_{t+1}) Qπ(sti,ati)=rti+Vπ(st+1i)
    ∇ θ R ‾ θ = 1 N ∑ i = 1 N ∑ t = 1 T i [ ( ∑ t ′ = t T i γ t ′ − t r t ′ i − b ) ∇ θ l o g p θ ( a t i ∣ s t i ) ] = 1 N ∑ i = 1 N ∑ t = 1 T i { [ Q π θ ( s t i , a t i ) − V π θ ( s t i ) ] ∇ θ l o g p θ ( a t i ∣ s t i ) } = 1 N ∑ i = 1 N ∑ t = 1 T i { [ r t i + V π ( s t + 1 i ) − V π θ ( s t i ) ] ∇ θ l o g p θ ( a t i ∣ s t i ) } \begin{aligned} \nabla_θ\overline{R}_θ &=\cfrac1N\sum^N_{i=1}\sum^{T_i}_{t=1}\left[(\color{violet}{\sum^{T_i}_{t'=t}γ^{t'-t}r^i_{t'}}\color{black}{-}\color{blue}{b}\color{black}{)\nabla_θ logp_θ(a^i_t|s^i_t)}\right]\\ &=\cfrac1N\sum^N_{i=1}\sum^{T_i}_{t=1}\left\{[\color{violet}{Q^{π_θ}(s^i_t,a^i_t)}\color{black}{-}\color{blue}{V^{π_θ}(s^i_t)}\color{black}{]\nabla_θ logp_θ(a^i_t|s^i_t)}\right\}\\ &=\cfrac1N\sum^N_{i=1}\sum^{T_i}_{t=1}\left\{[\color{violet}{r^i_t+V^π(s^i_{t+1})}\color{black}{-}\color{blue}{V^{π_θ}(s^i_t)}\color{black}{]\nabla_θ logp_θ(a^i_t|s^i_t)}\right\}\\ \end{aligned} θRθ=N1i=1Nt=1Ti[(t=tTiγttrtib)θlogpθ(atisti)]=N1i=1Nt=1Ti{[Qπθ(sti,ati)Vπθ(sti)]θlogpθ(atisti)}=N1i=1Nt=1Ti{[rti+Vπ(st+1i)Vπθ(sti)]θlogpθ(atisti)}
  • 此时,只需要用1个Network来负责 V π ( s ) V^π(s) Vπ(s) 就够了。但是坏处是引入了随机量 r t r_t rt,但是 r t r_t rt 的随机性要远小于 ∑ t ′ = t T i γ t ′ − t r t ′ i \sum^{T_i}_{t'=t}γ^{t'-t}r^i_{t'} t=tTiγttrti 的随机性。所以把 Variance 比较大的 ∑ t ′ = t T i γ t ′ − t r t ′ i \sum^{T_i}_{t'=t}γ^{t'-t}r^i_{t'} t=tTiγttrti 换成 Variance 比较小的 r t r_t rt 也是合理的。

在这里插入图片描述

  • 整个流程是这样子的:
    • 我们现在先初始化一个 actor/policy π π π,让 π π π 去跟环境做互动采样,如果在 Policy Gradient算法中,采样完毕后就会直接去 update 你的 policy。但是在 A2C 算法里面,采样后不是直接去 update 你的 policy,而是拿这些资料去 estimate 出 V π ( s ) V^π(s) Vπ(s) 值。
    • estimate 出 V π ( s ) V^π(s) Vπ(s) 值以后,利用 ∇ θ R ‾ θ = 1 N ∑ i = 1 N ∑ t = 1 T i { [ r t i + V π ( s t + 1 i ) − V π θ ( s t i ) ] ∇ θ l o g p θ ( a t i ∣ s t i ) } \begin{aligned}\nabla_θ\overline{R}_θ=\cfrac1N\sum^N_{i=1}\sum^{T_i}_{t=1}\left\{[r^i_t+V^π(s^i_{t+1})-V^{π_θ}(s^i_t)]\nabla_θ logp_θ(a^i_t|s^i_t)\right\}\end{aligned} θRθ=N1i=1Nt=1Ti{[rti+Vπ(st+1i)Vπθ(sti)]θlogpθ(atisti)} 去 update π π π,得到新的 π ′ π' π
    • 利用新的 π ′ π' π再去跟环境做互动采样,迭代下去。
  • Actor-Critic 的时候一定要用的 Tips:
    在这里插入图片描述
    1. 要 estimate 的 network 有两个,一个是 V π ( s ) V^π(s) Vπ(s) 的 Network,一个是 actor/policy π π π 的 Network。这两个 Network 前几层 Layer 的参数共用。
    2. exploration 的机制:对 π π π 的 output 添加一个 constrain/限制,这个 constrain 是希望 π π π 的 output 的 distribution 的 entropy 不要太小,希望这个 distribution 的 entropy 可以大一点,也就是希望不同的 action 被采用的机率平均一点。这样在 testing 的时候, π π π 才会多尝试各种不同的 action,才会把这个环境探索的比较好,explorer 的比较好,才会得到比较好的结果。

四、Asynchronous Advantage Actor-Critic (A3C)【开分身同步训练】

  • A3C 算法的大体思想是:同时开很多个 worker,那每一个 worker 其实就是一个分身,最后这些分身会把所有的经验通通集合在一起。
  • A3C 算法实操时需要很多个 CPU同时运作,每个分身 Worker 需要用一个CPU来计算。
    在这里插入图片描述
  • A3C算法基本流程,每个Worker同时进行如下流程:
    1. Copy global parameters
    2. Sampling some data
    3. Compute gradients
    4. Update global models
  • 不需要在意各个Worker之间的协同性问题。

五、Pathwise Derivative Policy Gradient(DDPG)【类似GAN】

  • 我们在使用 Critic(评估价值)的过程中,传统的方法只是给一个评估的值得大小,我们利用评估的值,采取增加倾向于评估值大的action的概率。
  • 但是如果Critic不但给出对于action的评价,而且给出actor下一步的建议呢。(就像老师不但把我们作业批改了,然后还给出了怎么做好作业的建议,而传统的Critic知只是一个能给我们批改作业的老师,但是没有给出建议)
  • Deepmind 大神David Silver 给了我们一个“既能批改作业,又能给我们指导未来的老师”的算法. Pathwise derivative policy gradient。

1、DDPG算法思路

  • 思路是建立一个actor的network,它能够选择Q-learning 中的最大值。

在这里插入图片描述

  • 具体算法结构如下:
    1. 先初始化一个 Actor π 0 π_0 π0
    2. 利用 Actor π 0 π_0 π0 与环境互动采样,将采样喂给 Critic Network,得到 Q π 0 Q^{π_0} Qπ0
    3. 固定 Q π 0 Q^{π_0} Qπ0 这个 Critic Network
    4. 利用 Actor π 0 π_0 π0 这个Network生成 action a a a,将生成的 a a a 输入到 Q π 0 Q^{π_0} Qπ0 这个 Critic Network 中,通过不断梯度更新 Actor π 0 π_0 π0 使得 π 0 π_0 π0 生成的 a a a 喂给 Q π 0 Q^{π_0} Qπ0 后的 Output 越来越大,更新结束时,Actor π 0 π_0 π0 更新为 Actor π 1 π_1 π1
    5. 利用 Actor π 1 π_1 π1 与环境互动采样,将采样喂给 Critic Network,得到 Q π 1 Q^{π_1} Qπ1
    6. 如此反复,最终得到最优的 Actor π ∗ π^* π

2、Q-Learning算法与DDPG算法对比

在这里插入图片描述

六、Actor-Critic 与 GAN 的联系

在这里插入图片描述




参考资料:
Connecting Generative Adversarial Networks and Actor-Critic Methods

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
以下是基于Tensorflow的《Soft Actor-Critic: Off-Policy Maximum Entropy Deep Reinforcement Learning with a Stochastic Actor》版本的SAC强化学习算法的Python代码: ```python import tensorflow as tf import numpy as np import gym # Create actor network class Actor(tf.keras.Model): def __init__(self, state_dim, action_dim, max_action): super(Actor, self).__init__() self.layer1 = tf.keras.layers.Dense(256, activation='relu') self.layer2 = tf.keras.layers.Dense(256, activation='relu') self.mu_layer = tf.keras.layers.Dense(action_dim, activation='tanh') self.sigma_layer = tf.keras.layers.Dense(action_dim, activation='softplus') self.max_action = max_action def call(self, state): x = self.layer1(state) x = self.layer2(x) mu = self.mu_layer(x) * self.max_action sigma = self.sigma_layer(x) + 1e-4 return mu, sigma # Create two critic networks class Critic(tf.keras.Model): def __init__(self, state_dim, action_dim): super(Critic, self).__init__() self.layer1 = tf.keras.layers.Dense(256, activation='relu') self.layer2 = tf.keras.layers.Dense(256, activation='relu') self.layer3 = tf.keras.layers.Dense(1, activation=None) def call(self, state, action): x = tf.concat([state, action], axis=1) x = self.layer1(x) x = self.layer2(x) x = self.layer3(x) return x # Create Soft Actor-Critic (SAC) Agent class SACAgent: def __init__(self, state_dim, action_dim, max_action): self.actor = Actor(state_dim, action_dim, max_action) self.critic1 = Critic(state_dim, action_dim) self.critic2 = Critic(state_dim, action_dim) self.target_critic1 = Critic(state_dim, action_dim) self.target_critic2 = Critic(state_dim, action_dim) self.max_action = max_action self.alpha = tf.Variable(0.1, dtype=tf.float32, name='alpha') self.gamma = 0.99 self.tau = 0.005 self.optimizer_actor = tf.keras.optimizers.Adam(learning_rate=3e-4) self.optimizer_critic1 = tf.keras.optimizers.Adam(learning_rate=3e-4) self.optimizer_critic2 = tf.keras.optimizers.Adam(learning_rate=3e-4) def get_action(self, state): state = np.expand_dims(state, axis=0) mu, sigma = self.actor(state) dist = tfp.distributions.Normal(mu, sigma) action = tf.squeeze(dist.sample(1), axis=0) return action.numpy() def update(self, replay_buffer, batch_size): states, actions, rewards, next_states, dones = replay_buffer.sample(batch_size) with tf.GradientTape(persistent=True) as tape: # Compute actor loss mu, sigma = self.actor(states) dist = tfp.distributions.Normal(mu, sigma) log_pi = dist.log_prob(actions) q1 = self.critic1(states, actions) q2 = self.critic2(states, actions) q_min = tf.minimum(q1, q2) alpha_loss = -tf.reduce_mean(self.alpha * (log_pi + self.target_entropy)) actor_loss = -tf.reduce_mean(tf.exp(self.alpha) * log_pi * q_min) # Compute critic loss next_mu, next_sigma = self.actor(next_states) next_dist = tfp.distributions.Normal(next_mu, next_sigma) next_actions = tf.clip_by_value(next_dist.sample(1), -self.max_action, self.max_action) target_q1 = self.target_critic1(next_states, next_actions) target_q2 = self.target_critic2(next_states, next_actions) target_q = tf.minimum(target_q1, target_q2) target_q = rewards + self.gamma * (1.0 - dones) * (target_q - tf.exp(self.alpha) * next_dist.entropy()) q1_loss = tf.reduce_mean(tf.square(q1 - target_q)) q2_loss = tf.reduce_mean(tf.square(q2 - target_q)) critic_loss = q1_loss + q2_loss + alpha_loss # Compute gradients and update weights actor_grads = tape.gradient(actor_loss, self.actor.trainable_variables) critic1_grads = tape.gradient(critic_loss, self.critic1.trainable_variables) critic2_grads = tape.gradient(critic_loss, self.critic2.trainable_variables) self.optimizer_actor.apply_gradients(zip(actor_grads, self.actor.trainable_variables)) self.optimizer_critic1.apply_gradients(zip(critic1_grads, self.critic1.trainable_variables)) self.optimizer_critic2.apply_gradients(zip(critic2_grads, self.critic2.trainable_variables)) # Update target networks for w, w_target in zip(self.critic1.weights, self.target_critic1.weights): w_target.assign(self.tau * w + (1 - self.tau) * w_target) for w, w_target in zip(self.critic2.weights, self.target_critic2.weights): w_target.assign(self.tau * w + (1 - self.tau) * w_target) # Update alpha alpha_grad = tape.gradient(alpha_loss, self.alpha) self.alpha.assign_add(1e-4 * alpha_grad) def save(self, filename): self.actor.save_weights(filename + '_actor') self.critic1.save_weights(filename + '_critic1') self.critic2.save_weights(filename + '_critic2') def load(self, filename): self.actor.load_weights(filename + '_actor') self.critic1.load_weights(filename + '_critic1') self.critic2.load_weights(filename + '_critic2') # Create replay buffer class ReplayBuffer: def __init__(self, max_size): self.max_size = max_size self.buffer = [] self.position = 0 def add(self, state, action, reward, next_state, done): if len(self.buffer) < self.max_size: self.buffer.append(None) self.buffer[self.position] = (state, action, reward, next_state, done) self.position = (self.position + 1) % self.max_size def sample(self, batch_size): indices = np.random.choice(len(self.buffer), batch_size, replace=False) states, actions, rewards, next_states, dones = [], [], [], [], [] for idx in indices: state, action, reward, next_state, done = self.buffer[idx] states.append(np.array(state, copy=False)) actions.append(np.array(action, copy=False)) rewards.append(reward) next_states.append(np.array(next_state, copy=False)) dones.append(done) return np.array(states), np.array(actions), np.array(rewards, dtype=np.float32), np.array(next_states), np.array(dones, dtype=np.uint8) # Create environment and agent env = gym.make('Pendulum-v0') state_dim = env.observation_space.shape[0] action_dim = env.action_space.shape[0] max_action = float(env.action_space.high[0]) agent = SACAgent(state_dim, action_dim, max_action) replay_buffer = ReplayBuffer(1000000) # Train agent max_episodes = 1000 max_steps = 500 batch_size = 256 update_interval = 1 target_entropy = -action_dim for episode in range(max_episodes): state = env.reset() total_reward = 0 for step in range(max_steps): action = agent.get_action(state) next_state, reward, done, _ = env.step(action) replay_buffer.add(state, action, reward, next_state, done) if len(replay_buffer.buffer) > batch_size: agent.update(replay_buffer, batch_size) state = next_state total_reward += reward if done: break print("Episode:", episode, "Total Reward:", total_reward) ``` 请注意,以上代码仅供参考,并且需要根据具体环境和参数进行调整和完善。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值