☰
keras-rl DDPGAgent 完全指南:在 Keras 中实现面向连续动作空间的深度确定性策略梯度
2026/10/14 16:22:05 网站建设 项目流程
  • 人工智能
  • 强化学习
  • 机器学习

【免费下载链接】keras-rl

Deep Reinforcement Learning for Keras.

项目地址:https://gitcode.com/gh_mirrors/ke/keras-rl
点击查看免费下载

导读:本文以 keras-rl 仓库中DDPGAgent的官方文档(docs/templates/agents/ddpg.md 及其自动生成产物 docs/sources/agents/ddpg.md)为核心骨架,系统讲解 DDPG(Deep Deterministic Policy Gradient)在连续动作空间下的原理、Actor/Critic 网络结构约定、全部构造参数语义,并借助仓库源码(rl/agents/ddpg.py)与示例(examples/ddpg_pendulum.py)深入剖析其训练循环、目标网络更新与探索噪声机制。读完本文,你将能够独立用 keras-rl 为 Pendulum 等连续控制任务搭建、编译、训练并评估一个完整的 DDPGAgent。


1. DDPGAgent 是什么:连续动作空间版的 DQN

DDPGAgent是 keras-rl 中面向连续动作空间的 off-policy 强化学习智能体,其类定义位于 rl/agents/ddpg.py,算法出处为 Lillicrap 等人 2015 年的论文《Continuous control with deep reinforcement learning》(arXiv:1509.02971)。

DDPG 的核心思想可以概括为:同时学习一个策略(Actor)和一个 Q 函数(Critic):

  • Actor(策略网络):学习一个确定性策略。它的参数更新依赖对 Q 函数使用链式法则——即把策略梯度看成「Q 值对动作的梯度」与「动作对策略参数的梯度」的复合,从而朝着最大化期望回报的方向调整策略。
  • Critic(Q 函数网络):像 Q-Learning 一样基于Bellman 方程更新,拟合给定「状态—动作」对下的期望回报。

因此从算法家族上看,DDPG 可以理解为DQN 在连续动作空间上的扩展:DQN 通过离散动作上的max操作选出最佳动作,而连续动作空间无法穷举,于是 DDPG 改用 Actor 网络直接输出最优动作,Critic 则负责给出该动作的 Q 值评估。

仓库 README(README.md)将 DDPG 列为项目已实现的核心算法之一,并同样以 examples/ddpg_pendulum.py 作为官方示例。

1.1 类签名(来自自动生成文档)

rl.agents.ddpg.DDPGAgent(nb_actions, actor, critic, critic_action_input, memory, gamma=0.99, batch_size=32, nb_steps_warmup_critic=1000, nb_steps_warmup_actor=1000, train_interval=1, memory_interval=1, delta_range=None, delta_clip=inf, random_process=None, custom_model_objects={}, target_model_update=0.001)

该签名由 docs/autogen.py 从DDPGAgent.__init__自动提取并注入模板的{{autogenerated}}占位符生成,因此与 rl/agents/ddpg.py 中构造函数的真实参数完全一致。


2. Actor 与 Critic 的网络结构约定

DDPGAgent 对传入的两个 Keras 模型有严格的输入输出约定,理解这些约定是正确使用的前提。

2.1 Actor:从状态观测到动作

  • 输入:状态观测(state observation);
  • 输出:动作本身(连续向量)。

需要特别注意的是:在环境step函数中被执行的「动作」,正是 Actor 模型的输出。这与离散动作空间中的 DQN 形成鲜明对比——DQN 的模型学习的是 Q 函数,策略从中挑选nb_actions个离散动作之一;而 DDPG 的 Actor 直接回归出连续动作值。

在 rl/agents/ddpg.py 的select_action中,动作通过self.actor.predict_on_batch(batch).flatten()计算,并要求结果形状与(nb_actions,)严格一致,否则触发断言。

2.2 Critic:状态与动作的拼接输入

  • 输入:状态观测与 Actor 所选动作的拼接(concatenation);
  • 输出:该「状态—动作」组合下的 Q 值。

其中形状为nb_actions的 Keras 输入层,要通过参数critic_action_input显式传给 Agent,以便它在内部定位动作输入层。

2.3 构造时的输入合法性校验

DDPGAgent.__init__在构造阶段就会校验模型结构(rl/agents/ddpg.py):

  • Actor 或 Critic 若有多个输出,直接抛出ValueError(DDPG 要求单一输出);
  • 若critic_action_input不在 critic 的输入列表中,抛出ValueError;
  • critic 的输入数量必须至少为 2(一个动作输入、一个观测输入)。

这些校验意味着「Actor 多输出」「Critic 缺动作输入」「Critic 输入不足」等常见错误会在构建 Agent 时立即暴露,而非等到训练中途。


3. 构造参数详解(含默认值与底层语义)

下表覆盖了构造函数中除三个网络对象外的全部参数。语义均对照 rl/agents/ddpg.py 源码核实:

参数默认值语义与底层实现
nb_actions必填连续动作空间的维度。select_action与训练批次均断言动作形状为(batch, nb_actions)
memory必填经验回放缓冲区,通常为SequentialMemory,见 rl/memory.py
gamma0.99折扣因子,用于计算r_t + gamma * max_a Q(s_{t+1}, a)形式的 TD 目标
batch_size32每次梯度更新采样的小批量大小
nb_steps_warmup_critic1000Critic 的预热步数:步数未超过该值时不对 Critic 做梯度更新,用于等待回放缓冲积累足够样本
nb_steps_warmup_actor1000Actor 的预热步数,语义同上
train_interval1每多少步执行一次网络训练(step % train_interval == 0时触发)
memory_interval1每多少步向回放缓冲写入一条经验
delta_rangeNone已弃用。若传入非None,源码会发出DeprecationWarning并自动回退为delta_clip = delta_range[1](见 rl/agents/ddpg.py),请改用delta_clip
delta_clipinfHuber loss 的截断阈值。为inf时退化为纯平方误差(MSE),见 rl/util.py
random_processNone探索噪声过程。训练模式下在 Actor 输出动作上叠加sample()的噪声(见 4.2 节)
custom_model_objects{}克隆目标网络时传递给model_from_config的自定义对象
target_model_update0.001目标网络更新策略:< 1为软更新比例tau;>= 1为每 N 步硬更新一次(见 4.3 节)

3.1 参数校验与软/硬更新判定

源码在__init__中对target_model_update做了归一化(rl/agents/ddpg.py):

  • target_model_update < 0:抛出ValueError;
  • >= 1:视为硬更新,转为整数,表示每 N 步把在线网络权重整体复制到目标网络;
  • 介于(0, 1):视为软更新,按(1 - tau) * old + tau * new逐权重混合。

delta_range与delta_clip的关系值得单独强调:delta_range是历史遗留参数(二元组形式),当前文档与源码均推荐直接使用单标量的delta_clip。


4. 关键机制与源码级原理

4.1 Actor 的策略梯度:链式法则的工程实现

文档指出 Actor 参数更新基于「对 Q 函数应用链式法则」。在源码中,这一过程通过组合模型实现(rl/agents/ddpg.py):

  1. 取出 critic 除动作输入外的所有状态输入(state_inputs);
  2. 在这些输入之上挂接self.actor(state_inputs),得到动作;
  3. 将动作填入 critic 的动作输入槽位,得到combined_output = critic(combined_inputs);
  4. 用actor_optimizer.get_updates(params=actor.trainable_weights, loss=-K.mean(combined_output))构造更新,即把「最大化 Q 均值」转化为「最小化负 Q 均值」,借助链式法则把梯度从 Q 反传到 Actor 参数;
  5. 最终打包成actor_train_fn(TensorFlow 后端时额外拼接K.learning_phase()输入)。

因此Actor 从未用 Keras 自带损失直接训练(rl/agents/ddpg.py 用sgd + mse编译 Actor 仅用于前向推断),真正的策略梯度由上述组合模型显式计算。

4.2 探索与平衡:Ornstein-Uhlenbeck 随机过程

文档强调:为了平衡利用(exploitation)与探索(exploration),可以引入random_process向 Actor 输出的动作叠加噪声。原论文采用Ornstein-Uhlenbeck(OU)过程,它带有惯性、适合物理控制类问题。

keras-rl 在 rl/random.py 中实现了OrnsteinUhlenbeckProcess,其离散递推为:

x = x_prev + theta * (mu - x_prev) * dt + current_sigma * sqrt(dt) * N(0, 1)

关键参数:theta(回归速度)、mu(均值)、sigma(噪声强度)、dt(时间步长)、size(与nb_actions匹配的维度)、sigma_min与n_steps_annealing(噪声随训练步数线性退火的下限与步数,见 rl/random.py 的AnnealedGaussianProcess)。

噪声只在训练模式下叠加:select_action中if self.training and self.random_process is not None(rl/agents/ddpg.py),并断言噪声形状与动作一致。仓库还提供了更简单的GaussianWhiteNoiseProcess(rl/random.py)作为替代。

4.3 目标网络与回放缓冲:DQN 同款稳定性手段

文档明确指出 DDPG 与 DQN 一样使用经验回放(replay buffer)与目标网络(target networks):

  • 回放缓冲:backward中按memory_interval将(observation, action, reward, terminal)写入 memory(rl/agents/ddpg.py),训练时从SequentialMemory.sample(batch_size)抽取不重复的随机批次(rl/memory.py)。SequentialMemory内部使用自研RingBuffer而非deque,以避免随机访问性能问题。
  • 目标网络:compile时用clone_model复制出target_actor与target_critic(rl/agents/ddpg.py)。训练中 critic 的 TD 目标由target_actor.predict_on_batch(state1_batch)产生目标动作、再经target_critic得到target_q_values,最终构成targets = reward + gamma * target_q_values * terminal1(rl/agents/ddpg.py)。
  • 软更新实现:软更新模式下,critic 优化器被包装为AdditionalUpdatesOptimizer,其get_updates会在普通梯度更新之外追加get_soft_target_model_updates返回的权重混合更新(rl/util.py 与 rl/util.py);actor 侧同样把软更新并入actor_train_fn的updates。硬更新模式则在backward中按step % target_model_update == 0调用update_target_models_hard(rl/agents/ddpg.py)。

4.4 Critic 的损失:带截断的 Huber loss

Critic 以clipped_error为损失(rl/agents/ddpg.py),即对 TD 误差施加huber_loss(rl/util.py):

  • delta_clip = inf时退化为0.5 * (y_true - y_pred)^2(MSE);
  • 有限值时,误差小于delta_clip用平方项、超过则用线性项,提升对大误差的鲁棒性(对 TensorFlow 使用tf.select/tf.where,对 Theano 使用T.switch)。

compile还会自动把mean_q追加进指标列表(rl/agents/ddpg.py),用于观测训练中 Q 值的平均水平;示例中额外传入的metrics=['mae']也会被加入。

4.5 训练时机与预热逻辑

backward(rl/agents/ddpg.py)是训练循环的核心:

  1. 按memory_interval写入经验;
  2. 仅在step > nb_steps_warmup_critic或step > nb_steps_warmup_actor且step % train_interval == 0时采样训练;
  3. critic 更新在step > nb_steps_warmup_critic后生效,actor 更新在step > nb_steps_warmup_actor后生效——两个网络可独立预热,这正是参数表中两个 warmup 参数分开的原因;
  4. 全部计算采用向量化实现(state0_batch、action_batch、reward_batch、terminal1_batch、state1_batch五个批次),并有大量形状断言(reward_batch.shape == (batch_size,)、action_batch.shape == (batch_size, nb_actions)等)用于提前发现维度错误。

4.6 模型持久化:Actor 与 Critic 分开存权重

save_weights/load_weights(rl/agents/ddpg.py)会把传入的文件名拆分为xxx_actor.h5f与xxx_critic.h5f两个文件分别保存。load_weights在加载完成后还会调用update_target_models_hard()同步目标网络。


5. 实战示例:Pendulum 连续控制(完整可运行)

文档最后指引读者参考 DDPG 的 Pendulum 示例。仓库中的 examples/ddpg_pendulum.py 是一个完整、可直接运行的脚本,下面按步骤拆解。

5.1 环境准备

ENV_NAME = 'Pendulum-v0' env = gym.make(ENV_NAME) np.random.seed(123) env.seed(123) assert len(env.action_space.shape) == 1 nb_actions = env.action_space.shape[0]

Pendulum-v0的动作空间是一维连续空间,故nb_actions = 1;断言保证动作空间为向量形式。

5.2 构建 Actor(确定性策略网络)

actor = Sequential() actor.add(Flatten(input_shape=(1,) + env.observation_space.shape)) actor.add(Dense(16)) actor.add(Activation('relu')) actor.add(Dense(16)) actor.add(Activation('relu')) actor.add(Dense(16)) actor.add(Activation('relu')) actor.add(Dense(nb_actions)) actor.add(Activation('linear'))

要点:输入为观测(加Flatten展平),输出层为linear激活且输出维度等于nb_actions,保证动作可以是任意连续值。

5.3 构建 Critic(状态-动作 Q 网络)

action_input = Input(shape=(nb_actions,), name='action_input') observation_input = Input(shape=(1,) + env.observation_space.shape, name='observation_input') flattened_observation = Flatten()(observation_input) x = Concatenate()([action_input, flattened_observation]) x = Dense(32)(x) x = Activation('relu')(x) x = Dense(32)(x) x = Activation('relu')(x) x = Dense(32)(x) x = Activation('relu')(x) x = Dense(1)(x) x = Activation('linear')(x) critic = Model(inputs=[action_input, observation_input], outputs=x)

要点:critic 是Model而非Sequential,显式声明[action_input, observation_input]两个输入;动作输入层action_input稍后作为critic_action_input传入 Agent,输出维度固定为 1(单个 Q 值)。

5.4 组装 Agent:记忆、噪声与配置

memory = SequentialMemory(limit=100000, window_length=1) random_process = OrnsteinUhlenbeckProcess(size=nb_actions, theta=.15, mu=0., sigma=.3) agent = DDPGAgent(nb_actions=nb_actions, actor=actor, critic=critic, critic_action_input=action_input, memory=memory, nb_steps_warmup_critic=100, nb_steps_warmup_actor=100, random_process=random_process, gamma=.99, target_model_update=1e-3) agent.compile(Adam(lr=.001, clipnorm=1.), metrics=['mae'])

几个值得注意的配置点:

  • SequentialMemory(limit=100000, window_length=1):容量 10 万条经验、观测窗口长度为 1(Pendulum 是低维向量观测,不需要帧堆叠);
  • OU 噪声参数theta=.15, mu=0., sigma=.3与原论文设定一致;
  • 示例把 warmup 从默认的 1000 步调低到 100 步,以加速在简单任务上的收敛;
  • compile接受单个优化器(如Adam),此时 Actor 与 Critic 会各自持有该优化器的一个副本(critic_optimizer = clone_optimizer(optimizer),见 rl/agents/ddpg.py);也可以传入两个优化器的列表分别用于 Actor 与 Critic,如集成测试 tests/integration/test_continuous.py 中的agent.compile([Adam(lr=1e-3), Adam(lr=1e-3)])。

5.5 训练、保存与评估

agent.fit(env, nb_steps=50000, visualize=True, verbose=1, nb_max_episode_steps=200) agent.save_weights('ddpg_{}_weights.h5f'.format(ENV_NAME), overwrite=True) agent.test(env, nb_episodes=5, visualize=True, nb_max_episode_steps=200)
  • fit训练 50000 步,visualize=True会渲染画面(源码在 rl/core.py 中通过Visualizer回调实现,示例注释提示可视化会显著拖慢训练,且Ctrl + C可安全中断);
  • save_weights按 4.6 节规则落盘两个权重文件;
  • test在training=False模式下运行(rl/core.py),此时不叠加探索噪声、不写回放缓冲,纯评估 5 个回合。

6. 测试与验证:从单元测试到集成测试

仓库对 DDPGAgent 提供了两层自动化验证,可作实现正确性的佐证:

  • 单元测试tests/rl/agents/test_ddpg.py:覆盖单观测输入(test_single_ddpg_input)与多观测输入(test_multi_ddpg_input)两种场景。后者通过MultiInputProcessor(nb_inputs=2)让 Actor/Critic 接收两个观测输入,验证了 4.1 节组合模型对多输入 critic 的通用性。
  • 集成测试tests/integration/test_continuous.py:在真实Pendulum-v0环境中用双优化器配置训练 400 步并测试 2 个回合,从端到端验证「构建网络 → 组装 Agent → 编译 → 训练 → 测试」全链路可运行。

7. 常见问题与使用建议

  1. 为什么 Actor 输出层用linear而非tanh?文档与示例均采用linear输出,因为 DDPG 的确定性策略应能输出任意连续值;若环境动作有界,可结合环境自身的 clip 机制或自定义处理器处理。
  2. warmup 步数太小的后果:SequentialMemory.sample在样本不足无法「无放回抽样」时会发出警告并退化为有放回抽样(rl/memory.py),因此 warmup 应保证缓冲中积累足够多样的经验。
  3. delta_range与delta_clip:delta_range已弃用,会触发DeprecationWarning并自动回退为delta_clip = delta_range[1],新代码请直接使用delta_clip。
  4. 权重文件命名:保存/加载时文件名会被拆分为*_actor.*与*_critic.*两个文件,缺失其一将导致加载失败;加载后目标网络会自动硬同步。
  5. 多观测输入的适配:当环境返回多路观测(如多摄像头画面)时,需要为 Actor 与 Critic 设计多输入 Keras 模型,并配合MultiInputProcessor,单元测试 tests/rl/agents/test_ddpg.py 给出了可复用的模板。

8. 延伸阅读

  • 算法原文:《Continuous control with deep reinforcement learning》,Lillicrap et al., 2015(即文档「References」部分所引论文,对应 arXiv:1509.02971);
  • keras-rl 文档体系的生成方式见 docs/autogen.py(本文档正文即由模板 docs/templates/agents/ddpg.md 中的{{autogenerated}}占位符自动填充DDPGAgent类签名与 docstring 而来);
  • 同仓库的其他连续控制算法:NAF(rl/agents/naf.md),以及离散动作空间对照实现 DQN(rl/agents/dqn.md)与 SARSA(rl/agents/sarsa.md);
  • 训练/评估循环的通用行为(fit、test、compile的完整参数说明)见 rl/core.py 与 docs/sources/agents/overview.md。
  • 人工智能
  • 强化学习
  • 机器学习

【免费下载链接】keras-rl

Deep Reinforcement Learning for Keras.

项目地址:https://gitcode.com/gh_mirrors/ke/keras-rl
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询