DDPG的基本思想
-
Actor-Critic架构:DDPG使用了Actor-Critic方法,其中Actor负责输出具体的动作,而Critic评估Actor输出的动作质量(即Q值)。Actor是一个策略网络,输入状态s输出动作a;Critic是一个Q网络,输入状态s和动作a输出Q值。
-
连续动作空间:与DQN不同,DDPG能够处理连续动作空间中的问题。Actor网络输出的动作是连续的,而不是离散的动作选择。
-
目标网络:与DQN类似,DDPG也使用了目标网络来提高训练的稳定性。Actor和Critic都有各自的目标网络,其参数从主网络缓慢更新,避免训练过程中参数震荡。
-
经验回放:经验回放机制用于解决样本之间的相关性问题。通过存储智能体的经验(状态,动作,奖励,下一个状态,是否终止)到回放池中,并从中随机抽取小批量样本进行训练,打破了样本之间的相关性,提高了样本利用效率。
-
策略更新:Actor的策略更新通过最大化Critic网络的Q值来进行,Critic网络的Q值更新则类似于DQN中的Q值更新,使用目标Q值和当前Q值之间的均方误差来训练。
详细的训练过程
-
初始化:初始化Actor和Critic网络及其目标网络,设置超参数和经验回放池。
-
交互环境:在每一回合中,智能体根据当前策略与环境进行交互,选择动作并获得奖励,存储经验到回放池中。
-
经验采样:当回放池中的经验数量足够时,从中随机抽取一个小批量样本用于训练。
-
计算目标Q值:使用Critic目标网络计算目标Q值,对于每个样本,目标Q值等于即时奖励加上下一状态的Q值乘以折扣因子。
-
更新Critic网络:通过最小化Critic网络预测的Q值和目标Q值之间的均方误差来更新Critic网络的参数。
-
更新Actor网络:通过最大化Critic网络的Q值来更新Actor网络的参数,使得Actor网络输出的动作能够获得更高的Q值。
-
更新目标网络:每隔一段时间,将Actor和Critic网络的参数以较小的步长更新到各自的目标网络中。
-
探索与利用:采用噪声方法在Actor网络的输出动作上添加噪声,以实现探索与利用的平衡。
-
训练结束:在达到设定的回合数后,结束训练过程。
import gym
import numpy as np
import tensorflow as tf
from tensorflow.keras import layers
import copy
# 超参数设置
gamma = 0.99 # 折扣因子
tau = 0.005 # 软更新参数
actor_lr = 0.001 # Actor学习率
critic_lr = 0.002 # Critic学习率
batch_size = 64 # 批量大小
memory_size = 1000000 # 经验回放池大小
# 环境设置
env = gym.make('Pendulum-v1')
state_dim = env.observation_space.shape[0]
action_dim = env.action_space.shape[0]
action_bound = env.action_space.high[0]
# 构建Actor网络
def build_actor():
model = tf.keras.Sequential()
model.add(layers.Dense(400, input_dim=state_dim, activation='relu'))
model.add(layers.Dense(300, activation='relu'))
model.add(layers.Dense(action_dim, activation='tanh'))
model.compile(loss='mse', optimizer=tf.keras.optimizers.Adam(lr=actor_lr))
return model
# 构建Critic网络
def build_critic():
state_input = layers.Input(shape=(state_dim,))
action_input = layers.Input(shape=(action_dim,))
concat = layers.Concatenate()([state_input, action_input])
dense1 = layers.Dense(400, activation='relu')(concat)
dense2 = layers.Dense(300, activation='relu')(dense1)
output = layers.Dense(1)(dense2)
model = tf.keras.Model(inputs=[state_input, action_input], outputs=output)
model.compile(loss='mse', optimizer=tf.keras.optimizers.Adam(lr=critic_lr))
return model
# 经验回放池
class ReplayMemory:
def __init__(self, max_size):
self.buffer = []
self.max_size = max_size
def add(self, experience):
if len(self.buffer) >= self.max_size:
self.buffer.pop(0)
self.buffer.append(experience)
def sample(self, batch_size):
idx = np.random.choice(len(self.buffer), size=batch_size, replace=False)
return [self.buffer[i] for i in idx]
# 软更新函数
def soft_update(target, source, tau):
for target_param, source_param in zip(target.weights, source.weights):
target_param.assign(tau * source_param + (1 - tau) * target_param)
# 训练DDPG
def train_ddpg(episodes):
actor = build_actor()
target_actor = build_actor()
target_actor.set_weights(actor.get_weights())
critic = build_critic()
target_critic = build_critic()
target_critic.set_weights(critic.get_weights())
memory = ReplayMemory(memory_size)
for episode in range(episodes):
state = env.reset()
total_reward = 0
while True:
state = np.reshape(state, [1, state_dim])
action = actor.predict(state)[0]
noise = np.random.normal(0, action_bound * 0.1, size=action_dim)
action = np.clip(action + noise, -action_bound, action_bound)
next_state, reward, done, _ = env.step(action)
next_state = np.reshape(next_state, [1, state_dim])
memory.add((state, action, reward, next_state, done))
st