from TD3 to SAC

TD3

DDPG常常会遇到Q值overestimate的问题,这将会导致Critic部分给出错误的评判,导致Actor部分错误利用了这部分知识进行学习。TD3则是为了解决这个问题。

  • 技巧一:快速双q学习。TD3学习两个q函数而不是一个q函数(即twin),并使用两个q值中较小的一个作为Bellman误差损失函数中的目标。
  • 技巧二:延迟的政策更新。TD3更新策略(和目标网络)的频率低于q函数。本文建议每两个q函数更新一次策略更新。这样可以有效避免policy带来的偏差问题。
  • 技巧三:目标政策平滑。TD3为目标动作添加了噪声,使得策略更难利用Q函数误差,因为Q在动作中的变化是平滑的。

要点

最特别的一点就是要学习两个Q函数

两个q函数都使用一个单一的目标,使用两个q函数中的任何一个给出一个较小的目标值进行计算

在这里插入图片描述

对目标使用较小的q值,并向较小的q值回归,有助于防止q函数中的高估。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SjuzHSFp-1617262314466)(C:\Users\liuyi\AppData\Roaming\Typora\typora-user-images\image-20210331195639208.png)]

SAC

SAC是一种将随机策略优化方法和DDPG算法(确定性策略)相结合的算法。它虽然也使用了双裁剪的Q学习方法,但是它并不能严格算成TD3的改进版本。它的一个重要特点就是加入了熵的方法。

Entropy-Regularized Reinforcement Learning

该方法在传统RL方法的基础上,加入了熵的思想。普通方法在执行完一个决策之后,都会获得一个即时reward,而该方法除了即时reward外,还加入了一个基于熵的reward。

在这里插入图片描述

SAC

Q学习

与TD3方法的相同与不同

相同点:

  • 和TD3一样,两个q函数都是通过MSBE最小化来学习的,通过回归到一个单一的共享目标
  • 与TD3一样,共享目标是使用目标Q-network计算的,目标Q-network是通过polyak对训练过程中的Q-network参数进行平均得到的。
  • 与TD3中一样,共享目标使用剪切的双q技巧。

不同点

  • 与TD3不同,该目标还包括一项,该项来自SAC对熵正则化的使用
  • 与TD3不同,目标中使用的下一状态操作来自当前策略,而不是目标策略。
  • 与TD3不同,没有明确的目标政策平滑。TD3训练了一个确定性策略,因此它通过向下一状态动作添加随机噪声来实现平滑。SAC训练了一个随机策略,因此来自该随机性的噪声足以获得类似的效果。

SAC利用这种对目标的样本近似,为每个q函数设置MSBE损耗。这里唯一尚未确定的是,用哪个Q函数来计算样本备份:像TD3一样,SAC使用剪切双Q技巧,并在两个Q近似器之间取最小Q值。但这里需要注意的是,计算目标值的时候的那个动作产生,是由本身策略产生的,而不是由目标策略产生的。
在这里插入图片描述在这里插入图片描述

疑问:

为什么这里就不需要设置目标的策略参数了呢?

以下是基于TD3SAC算法的简单实现,使用Python和TensorFlow框架: ```python import tensorflow as tf import numpy as np class TD3_SAC: def __init__(self, state_dim, action_dim, max_action): self.state_dim = state_dim self.action_dim = action_dim self.max_action = max_action # Actor network self.actor = self.build_actor_network() self.actor_target = self.build_actor_network() self.actor_target.set_weights(self.actor.get_weights()) # Critic networks self.critic_1 = self.build_critic_network() self.critic_2 = self.build_critic_network() self.critic_1_target = self.build_critic_network() self.critic_2_target = self.build_critic_network() self.critic_1_target.set_weights(self.critic_1.get_weights()) self.critic_2_target.set_weights(self.critic_2.get_weights()) # Replay buffer self.buffer = ReplayBuffer() # Hyperparameters self.gamma = 0.99 self.tau = 0.005 self.alpha = 0.2 self.policy_noise = 0.2 * self.max_action self.noise_clip = 0.5 * self.max_action self.policy_freq = 2 self.batch_size = 256 # Optimizers self.actor_optimizer = tf.keras.optimizers.Adam(learning_rate=3e-4) self.critic_optimizer_1 = tf.keras.optimizers.Adam(learning_rate=3e-4) self.critic_optimizer_2 = tf.keras.optimizers.Adam(learning_rate=3e-4) def build_actor_network(self): inputs = tf.keras.layers.Input(shape=(self.state_dim,)) x = tf.keras.layers.Dense(256, activation='relu')(inputs) x = tf.keras.layers.Dense(256, activation='relu')(x) outputs = tf.keras.layers.Dense(self.action_dim, activation='tanh')(x) outputs = outputs * self.max_action return tf.keras.Model(inputs=inputs, outputs=outputs) def build_critic_network(self): state_inputs = tf.keras.layers.Input(shape=(self.state_dim,)) action_inputs = tf.keras.layers.Input(shape=(self.action_dim,)) x = tf.keras.layers.Concatenate()([state_inputs, action_inputs]) x = tf.keras.layers.Dense(256, activation='relu')(x) x = tf.keras.layers.Dense(256, activation='relu')(x) outputs = tf.keras.layers.Dense(1)(x) return tf.keras.Model(inputs=[state_inputs, action_inputs], outputs=outputs) def select_action(self, state): state = np.expand_dims(state, axis=0) action = self.actor(state).numpy()[0] return action def train(self): if len(self.buffer) < self.batch_size: return state_batch, action_batch, reward_batch, next_state_batch, done_batch = self.buffer.sample(self.batch_size) # Target actions next_action_batch = self.actor_target(next_state_batch).numpy() noise = np.random.normal(0, self.policy_noise, size=next_action_batch.shape) noise = np.clip(noise, -self.noise_clip, self.noise_clip) next_action_batch = next_action_batch + noise next_action_batch = np.clip(next_action_batch, -self.max_action, self.max_action) # Target Q values q1_target = self.critic_1_target([next_state_batch, next_action_batch]).numpy() q2_target = self.critic_2_target([next_state_batch, next_action_batch]).numpy() q_target = np.minimum(q1_target, q2_target) q_target = reward_batch + (1 - done_batch) * self.gamma * q_target # Update critics with tf.GradientTape(persistent=True) as tape: q1 = self.critic_1([state_batch, action_batch]) q2 = self.critic_2([state_batch, action_batch]) critic_loss_1 = tf.reduce_mean(tf.square(q1 - q_target)) critic_loss_2 = tf.reduce_mean(tf.square(q2 - q_target)) grad_1 = tape.gradient(critic_loss_1, self.critic_1.trainable_variables) grad_2 = tape.gradient(critic_loss_2, self.critic_2.trainable_variables) self.critic_optimizer_1.apply_gradients(zip(grad_1, self.critic_1.trainable_variables)) self.critic_optimizer_2.apply_gradients(zip(grad_2, self.critic_2.trainable_variables)) # Update actor with tf.GradientTape() as tape: policy_action = self.actor(state_batch) actor_loss = -tf.reduce_mean(self.critic_1([state_batch, policy_action])) actor_loss += self.alpha * tf.reduce_mean(tf.math.log(self.actor(state_batch) + 1e-6)) grad = tape.gradient(actor_loss, self.actor.trainable_variables) self.actor_optimizer.apply_gradients(zip(grad, self.actor.trainable_variables)) # Update target networks self.actor_target.set_weights(self.tau * np.array(self.actor.get_weights()) + (1 - self.tau) * np.array(self.actor_target.get_weights())) self.critic_1_target.set_weights(self.tau * np.array(self.critic_1.get_weights()) + (1 - self.tau) * np.array(self.critic_1_target.get_weights())) self.critic_2_target.set_weights(self.tau * np.array(self.critic_2.get_weights()) + (1 - self.tau) * np.array(self.critic_2_target.get_weights())) def save_model(self, path): self.actor.save_weights(path + 'actor') self.actor_target.save_weights(path + 'actor_target') self.critic_1.save_weights(path + 'critic_1') self.critic_2.save_weights(path + 'critic_2') self.critic_1_target.save_weights(path + 'critic_1_target') self.critic_2_target.save_weights(path + 'critic_2_target') def load_model(self, path): self.actor.load_weights(path + 'actor') self.actor_target.load_weights(path + 'actor_target') self.critic_1.load_weights(path + 'critic_1') self.critic_2.load_weights(path + 'critic_2') self.critic_1_target.load_weights(path + 'critic_1_target') self.critic_2_target.load_weights(path + 'critic_2_target') ``` 在这个代码中,我们定义了一个名为`TD3_SAC`的类,它包括了一个actor网络,两个critic网络(分别对应Q1和Q2),以及它们各自的target网络。我们还定义了一个replay buffer,用于存储样本。 在训练过程中,我们首先从replay buffer中采样一批样本,并计算目标Q值和目标动作。然后,我们使用这些样本更新critic网络的参数。接下来,我们使用actor网络和当前状态计算出一个动作,并用critic网络计算出该动作的Q值。我们使用这个Q值更新actor网络的参数。最后,我们使用soft更新方法更新target网络的参数。 在实践中,您可能需要根据您的具体问题调整超参数,以获得更好的性能。除此之外,您还可以使用其他技巧,如延迟更新、target policy smoothing等,以进一步改进算法的性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值