【强化学习】深度确定性策略梯度算法(DDPG)详解(附代码)

【强化学习】深度确定性策略梯度算法(DDPG)详解(附代码)
        📢本篇文章是博主强化学习(RL)领域学习时,用于个人学习、研究或者欣赏使用,并基于博主对相关等领域的一些理解而记录的学习摘录和笔记,若有不当和侵权之处,指出后将会立即改正,还望谅解。文章分类在👉强化学习专栏:

       【强化学习】- 【单智能体强化学习】(10)---《深度确定性策略梯度算法(DDPG)详解》

深度确定性策略梯度算法(DDPG)详解

目录

DDPG算法详细介绍

算法特点

核心改进点

算法公式推导

1. Q值函数更新

2. 策略更新(Actor网络)

3. 目标网络更新

算法流程

[Python] DDPG算法实现

1. 导入必要库

2. 定义 Actor 网络

3. 定义 Critic 网络

4. 定义经验回放池

5. 定义 DDPG 智能体

6. 动作选择方法

7. 训练方法

8. 训练智能体

 9.可视化学习曲线

完整代码

[Results] 运行结果

[Notice] 代码说明

优势

通俗类比

应用场景


DDPG算法详细介绍

        深度确定性策略梯度(Deep Deterministic Policy Gradient、DDPG)算法是一种基于深度强化学习的算法,适用于解决连续动作空间的问题,比如机器人控制中的连续运动。它结合了确定性策略和深度神经网络,是一种模型无关的强化学习算法,属于Actor-Critic框架,并且同时利用了DQN和PG(Policy Gradient)的优点。


算法特点

适用于连续动作空间:

        DDPG直接输出连续值动作,无需对动作进行离散化。

利用确定性策略:

        与随机策略不同,DDPG输出的是每个状态下一个确定的最优动作。

结合目标网络:

        使用延迟更新的目标网络,稳定了训练过程,避免了过大的参数波动。

经验回放机制:

        通过经验回放缓解数据相关性,提升样本利用率。

高效学习:

        使用Critic网络评估动作的质量,使得策略优化过程更加高效。


核心改进点

1.从DQN继承的目标网络:

        避免Q值的估计震荡问题。

        提高算法的训练稳定性。

2.从PG继承的策略梯度优化:

        通过Actor网络直接优化策略,适应连续动作问题。

3.经验回放(Replay Buffer):

        将交互环境中的经验(状态、动作、奖励、下一状态)存储起来,训练时从中随机采样,减少数据相关性和样本浪费。

4.双网络架构:

        Actor网络负责生成动作;Critic网络评估动作的质量。


算法公式推导

1. Q值函数更新

DDPG使用Bellman方程更新Critic网络的目标Q值:

y = r + \gamma Q'(s', \mu'(s'; \theta^{\mu'}); \theta^{Q'})
s', \mu'(s')

是下一状态和目标动作。

\gamma

是折扣因子。

\mu'

是目标Actor网络。

Q'

是目标Critic网络。

Critic网络的优化目标是最小化以下损失函数:

L(\theta^Q) = \frac{1}{N} \sum_{i} \left( Q(s_i, a_i; \theta^Q) - y_i \right)^2

其中:

y_i

是目标值。

\theta^Q

是Critic网络的参数。

2. 策略更新(Actor网络)

Actor网络通过最大化Critic网络的Q值来优化策略,其目标函数为:

J(\theta^\mu) = \frac{1}{N} \sum_{i} Q(s_i, \mu(s_i; \theta^\mu); \theta^Q)

使用梯度上升法更新Actor网络:

\nabla_{\theta^\mu} J \approx \frac{1}{N} \sum_{i} \nabla_a Q(s, a; \theta^Q) \big|{a=\mu(s)} \nabla{\theta^\mu} \mu(s; \theta^\mu)
3. 目标网络更新

目标网络采用软更新方式,缓慢地向当前网络靠近:

\theta^{Q'} \leftarrow \tau \theta^Q + (1 - \tau) \theta^{Q'} ] [ \theta^{\mu'} \leftarrow \tau \theta^\mu + (1 - \tau) \theta^{\mu'}

其中

\tau \in (0, 1)

是软更新系数。


算法流程

  1. 初始化:初始化Actor、Critic网络和它们对应的目标网络。
    初始化经验回放池。
  2. 更新Actor网络:使用Critic网络的梯度来调整Actor网络的参数。
  3. 目标网络更新:按照软更新公式更新目标网络的参数。
  4. 重复以上步骤,直到达到学习目标。

更新Critic网络:使用采样数据和目标Critic网络计算目标值

y_i

,最小化Critic的损失函数。

采样训练:从经验池中随机采样小批量数据

(s_i, a_i, r_i, s'_i)

存储经验:将

(s_t, a_t, r_t, s_{t+1})

存储到经验回放池。

交互环境:在状态

s_t

下,通过Actor网络生成动作

a_t


执行动作

a_t

,获取奖励

r_t

和下一状态

s_{t+1}


[Python] DDPG算法实现

        下面给出了DDPG(深度确定性策略梯度)算法的完整Python实现。该实现包括Actor-Critic架构、缓冲区和目标网络等。

 项目代码我已经放入GitCode里面,可以通过下面链接跳转:🔥

【强化学习】--- DDPG算法 

后续相关单智能体强化学习算法也会不断在【强化学习】项目里更新,如果该项目对你有所帮助,请帮我点一个星星✨✨✨✨✨,鼓励分享,十分感谢!!!

若是下面代码复现困难或者有问题,也欢迎评论区留言

1. 导入必要库

import gym # 导入 Gym 库,用于创建和管理强化学习环境 import numpy as np # 导入 NumPy,用于处理数组和数学运算 import torch # 导入 PyTorch,用于构建和训练神经网络 import torch.nn as nn # 导入 PyTorch 的神经网络模块 import torch.optim as optim # 导入 PyTorch 的优化器模块 from collections import deque # 导入双端队列,用于实现经验回放池 import random # 导入随机模块,用于从经验池中采样
  • gym:用于创建和管理强化学习环境(例如Pendulum-v1)。
  • numpy:处理数组和数值计算。
  • torch:用于深度学习模型的构建和训练。
  • deque:一个双端队列,适用于存储经验回放池。
  • random:用于从经验池中随机抽样。

2. 定义 Actor 网络

# 定义 Actor 网络(策略网络) class Actor(nn.Module): def __init__(self, state_dim, action_dim, max_action): super(Actor, self).__init__() self.layer1 = nn.Linear(state_dim, 256) # 输入层到隐藏层1,大小为 256 self.layer2 = nn.Linear(256, 256) # 隐藏层1到隐藏层2,大小为 256 self.layer3 = nn.Linear(256, action_dim) # 隐藏层2到输出层,输出动作维度 self.max_action = max_action # 动作的最大值,用于限制输出范围 def forward(self, state): x = torch.relu(self.layer1(state)) # 使用 ReLU 激活函数处理隐藏层1 x = torch.relu(self.layer2(x)) # 使用 ReLU 激活函数处理隐藏层2 x = torch.tanh(self.layer3(x)) * self.max_action # 使用 Tanh 激活函数,并放大到动作范围 return x # 返回输出动作 
解析
  • Actor 网络的作用是生成给定状态下的最优动作。
  • 输入
    • state_dim:环境状态的维度。
    • action_dim:动作空间的维度。
    • max_action:动作的最大值,用于约束输出动作的范围。
  • 网络结构
    • 两层隐藏层(256个神经元,每层使用ReLU激活函数)。
    • 输出层使用tanh激活函数(将动作限制在 ([-1, 1])),再乘以 max_action 缩放到实际动作范围。

3. 定义 Critic 网络

# 定义 Critic 网络(价值网络) class Critic(nn.Module): def __init__(self, state_dim, action_dim): super(Critic, self).__init__() self.layer1 = nn.Linear(state_dim + action_dim, 256) # 将状态和动作拼接后输入到隐藏层1 self.layer2 = nn.Linear(256, 256) # 隐藏层1到隐藏层2,大小为 256 self.layer3 = nn.Linear(256, 1) # 隐藏层2到输出层,输出 Q 值 def forward(self, state, action): x = torch.cat([state, action], dim=1) # 将状态和动作拼接为单个输入 x = torch.relu(self.layer1(x)) # 使用 ReLU 激活函数处理隐藏层1 x = torch.relu(self.layer2(x)) # 使用 ReLU 激活函数处理隐藏层2 x = self.layer3(x) # 输出 Q 值 return x # 返回 Q 值
解析
  • Critic 网络评估给定状态和动作的质量(即 Q 值)。
  • 输入
    • state:环境的当前状态。
    • action:给定状态下的动作。
  • 网络结构
    • 将状态和动作拼接作为输入。
    • 两层隐藏层,使用ReLU激活。
    • 输出层是一个标量 Q 值,表示该状态动作对的质量。

4. 定义经验回放池

# 定义经验回放池 class ReplayBuffer: def __init__(self, max_size): self.buffer = deque(maxlen=max_size) # 初始化一个双端队列,设置最大容量 def add(self, state, action, reward, next_state, done): self.buffer.append((state, action, reward, next_state, done)) # 将经验存入队列 def sample(self, batch_size): batch = random.sample(self.buffer, batch_size) # 随机采样一个小批量数据 states, actions, rewards, next_states, dones = zip(*batch) # 解压采样数据 return (np.array(states), np.array(actions), np.array(rewards), np.array(next_states), np.array(dones)) # 返回 NumPy 数组格式的数据 def size(self): return len(self.buffer) # 返回经验池中当前存储的样本数量
解析
  • 作用:存储智能体与环境交互的经验数据,打破样本间的时间相关性。
  • 方法
    • add:将 ((state, action, reward, next_state, done)) 存入经验池。
    • sample:从经验池中随机采样,返回小批量的训练数据。
    • size:返回经验池中的样本数量。

5. 定义 DDPG 智能体

# 定义 DDPG 智能体 class DDPGAgent: def __init__(self, state_dim, action_dim, max_action, gamma=0.99, tau=0.005, buffer_size=100000, batch_size=64): self.actor = Actor(state_dim, action_dim, max_action) # 初始化 Actor 网络 self.actor_target = Actor(state_dim, action_dim, max_action) # 初始化目标 Actor 网络 self.actor_target.load_state_dict(self.actor.state_dict()) # 将 Actor 网络的权重复制到目标网络 self.actor_optimizer = optim.Adam(self.actor.parameters(), lr=1e-4) # 定义 Actor 网络的优化器 self.critic = Critic(state_dim, action_dim) # 初始化 Critic 网络 self.critic_target = Critic(state_dim, action_dim) # 初始化目标 Critic 网络 self.critic_target.load_state_dict(self.critic.state_dict()) # 将 Critic 网络的权重复制到目标网络 self.critic_optimizer = optim.Adam(self.critic.parameters(), lr=1e-3) # 定义 Critic 网络的优化器 self.max_action = max_action # 动作的最大值 self.gamma = gamma # 折扣因子 self.tau = tau # 目标网络软更新参数 self.replay_buffer = ReplayBuffer(buffer_size) # 初始化经验回放池 self.batch_size = batch_size # 批量大小
解析
  • 初始化网络
    • Actor 和 Critic 网络分别有目标网络(actor_target 和 critic_target),用于稳定训练。
  • 优化器
    • Adam 优化器分别优化 Actor 和 Critic 网络。
  • 超参数
    • gamma:折扣因子。
    • tau:目标网络更新的系数。
    • buffer_size:经验池的容量。
    • batch_size:每次训练使用的样本数量。

6. 动作选择方法

# 根据状态选择动作 def select_action(self, state): state = torch.FloatTensor(state.reshape(1, -1)) # 将状态转换为 PyTorch 张量 action = self.actor(state).detach().cpu().numpy().flatten() # 使用 Actor 网络生成动作,并转为 NumPy 数组 return action # 返回动作
  • 作用:根据当前状态 (s),生成一个连续动作 (a)。
  • 流程
    • 将输入状态转换为 Torch 张量。
    • 用 Actor 网络预测动作。
    • 动作转换为 NumPy 数组返回。

7. 训练方法

 # 训练方法 def train(self): # 如果回放池中样本数量不足,直接返回 if self.replay_buffer.size() < self.batch_size: return # 从回放池中采样一批数据 states, actions, rewards, next_states, dones = self.replay_buffer.sample(self.batch_size) # 将采样的数据转换为张量 states = torch.FloatTensor(states) actions = torch.FloatTensor(actions) rewards = torch.FloatTensor(rewards).unsqueeze(1) # 添加一个维度以匹配Q值维度 next_states = torch.FloatTensor(next_states) dones = torch.FloatTensor(dones).unsqueeze(1) # 添加一个维度以匹配Q值维度 # 计算critic的损失 with torch.no_grad(): # 关闭梯度计算 next_actions = self.actor_target(next_states) # 使用目标actor网络预测下一步动作 target_q = self.critic_target(next_states, next_actions) # 目标Q值 # 使用贝尔曼方程更新目标Q值 target_q = rewards + (1 - dones) * self.gamma * target_q # 当前Q值 current_q = self.critic(states, actions) # 均方误差损失 critic_loss = nn.MSELoss()(current_q, target_q) # 优化critic网络 self.critic_optimizer.zero_grad() critic_loss.backward() self.critic_optimizer.step() # 计算actor的损失 actor_loss = -self.critic(states, self.actor(states)).mean() # 策略梯度目标为最大化Q值 # 优化actor网络 self.actor_optimizer.zero_grad() actor_loss.backward() self.actor_optimizer.step() # 更新目标网络参数(软更新) for target_param, param in zip(self.critic_target.parameters(), self.critic.parameters()): target_param.data.copy_(self.tau * param.data + (1 - self.tau) * target_param.data) for target_param, param in zip(self.actor_target.parameters(), self.actor.parameters()): target_param.data.copy_(self.tau * param.data + (1 - self.tau) * target_param.data) # 将样本添加到回放池中 def add_to_replay_buffer(self, state, action, reward, next_state, done): self.replay_buffer.add(state, action, reward, next_state, done)
解析
  1. Actor 网络更新:优化目标:最大化 Critic 网络的 Q 值。
  2. 目标网络更新:使用软更新方式(通过 (\tau))平滑更新目标网络参数。

Critic 网络更新:计算目标 Q 值

y = r + \gamma Q'(s', \mu'(s'))


使用均方误差 (MSE) 更新 Critic 网络。


8. 训练智能体

def train_ddpg(env_name, episodes=1000, max_steps=200): # 创建环境 env = gym.make(env_name) state_dim = env.observation_space.shape[0] # 状态空间维度 action_dim = env.action_space.shape[0] # 动作空间维度 max_action = float(env.action_space.high[0]) # 动作最大值 # 初始化DDPG智能体 agent = DDPGAgent(state_dim, action_dim, max_action) rewards = [] # 用于存储每个episode的奖励 for episode in range(episodes): state, _ = env.reset() # 重置环境,获取初始状态 episode_reward = 0 # 初始化每轮奖励为0 for step in range(max_steps): # 选择动作 action = agent.select_action(state) # 执行动作,获取环境反馈 next_state, reward, done, _, _ = env.step(action) # 将样本存入回放池 agent.add_to_replay_buffer(state, action, reward, next_state, done) # 训练智能体 agent.train() # 更新当前状态 state = next_state # 累加奖励 episode_reward += reward if done: # 如果完成(到达终止状态),结束本轮 break # 记录每轮的累计奖励 rewards.append(episode_reward) print(f"Episode: {episode + 1}, Reward: {episode_reward}") 
解析
  • 训练流程
    1. 初始化环境和智能体。
    2. 在每个 episode 中:
      • 使用 Actor 网络生成动作与环境交互。
      • 将经验存储到经验池。
      • 更新 Actor 和 Critic 网络。
      • 打印 episode 的累计奖励。

 9.可视化学习曲线

    # 绘制学习曲线的方法 import matplotlib.pyplot as plt # 绘制学习曲线     plt.plot(rewards)     plt.title("Learning Curve")     plt.xlabel("Episodes")     plt.ylabel("Cumulative Reward")     plt.show()

完整代码

"""《DDPG算法的代码》 时间:2024.12 环境:gym 作者:不去幼儿园 """ import gym # 导入 Gym 库,用于创建和管理强化学习环境 import numpy as np # 导入 NumPy,用于处理数组和数学运算 import torch # 导入 PyTorch,用于构建和训练神经网络 import torch.nn as nn # 导入 PyTorch 的神经网络模块 import torch.optim as optim # 导入 PyTorch 的优化器模块 from collections import deque # 导入双端队列,用于实现经验回放池 import random # 导入随机模块,用于从经验池中采样 # 定义 Actor 网络(策略网络) class Actor(nn.Module): def __init__(self, state_dim, action_dim, max_action): super(Actor, self).__init__() self.layer1 = nn.Linear(state_dim, 256) # 输入层到隐藏层1,大小为 256 self.layer2 = nn.Linear(256, 256) # 隐藏层1到隐藏层2,大小为 256 self.layer3 = nn.Linear(256, action_dim) # 隐藏层2到输出层,输出动作维度 self.max_action = max_action # 动作的最大值,用于限制输出范围 def forward(self, state): x = torch.relu(self.layer1(state)) # 使用 ReLU 激活函数处理隐藏层1 x = torch.relu(self.layer2(x)) # 使用 ReLU 激活函数处理隐藏层2 x = torch.tanh(self.layer3(x)) * self.max_action # 使用 Tanh 激活函数,并放大到动作范围 return x # 返回输出动作 # 定义 Critic 网络(价值网络) class Critic(nn.Module): def __init__(self, state_dim, action_dim): super(Critic, self).__init__() self.layer1 = nn.Linear(state_dim + action_dim, 256) # 将状态和动作拼接后输入到隐藏层1 self.layer2 = nn.Linear(256, 256) # 隐藏层1到隐藏层2,大小为 256 self.layer3 = nn.Linear(256, 1) # 隐藏层2到输出层,输出 Q 值 def forward(self, state, action): x = torch.cat([state, action], dim=1) # 将状态和动作拼接为单个输入 x = torch.relu(self.layer1(x)) # 使用 ReLU 激活函数处理隐藏层1 x = torch.relu(self.layer2(x)) # 使用 ReLU 激活函数处理隐藏层2 x = self.layer3(x) # 输出 Q 值 return x # 返回 Q 值 # 定义经验回放池 class ReplayBuffer: def __init__(self, max_size): self.buffer = deque(maxlen=max_size) # 初始化一个双端队列,设置最大容量 def add(self, state, action, reward, next_state, done): self.buffer.append((state, action, reward, next_state, done)) # 将经验存入队列 def sample(self, batch_size): batch = random.sample(self.buffer, batch_size) # 随机采样一个小批量数据 states, actions, rewards, next_states, dones = zip(*batch) # 解压采样数据 return (np.array(states), np.array(actions), np.array(rewards), np.array(next_states), np.array(dones)) # 返回 NumPy 数组格式的数据 def size(self): return len(self.buffer) # 返回经验池中当前存储的样本数量 # DDPG智能体类定义 class DDPGAgent: # 初始化方法,设置智能体的参数和模型 def __init__(self, state_dim, action_dim, max_action, gamma=0.99, tau=0.005, buffer_size=100000, batch_size=64): # 定义actor网络(策略网络)及其目标网络 self.actor = Actor(state_dim, action_dim, max_action) self.actor_target = Actor(state_dim, action_dim, max_action) # 将目标actor网络的参数初始化为与actor网络一致 self.actor_target.load_state_dict(self.actor.state_dict()) # 定义actor网络的优化器 self.actor_optimizer = optim.Adam(self.actor.parameters(), lr=1e-4) # 定义critic网络(值网络)及其目标网络 self.critic = Critic(state_dim, action_dim) self.critic_target = Critic(state_dim, action_dim) # 将目标critic网络的参数初始化为与critic网络一致 self.critic_target.load_state_dict(self.critic.state_dict()) # 定义critic网络的优化器 self.critic_optimizer = optim.Adam(self.critic.parameters(), lr=1e-3) # 保存动作的最大值,用于限制动作范围 self.max_action = max_action # 折扣因子,用于奖励的时间折扣 self.gamma = gamma # 软更新系数,用于目标网络的更新 self.tau = tau # 初始化经验回放池 self.replay_buffer = ReplayBuffer(buffer_size) # 每次训练的批量大小 self.batch_size = batch_size # 选择动作的方法 def select_action(self, state): # 将状态转换为张量 state = torch.FloatTensor(state.reshape(1, -1)) # 使用actor网络预测动作,并将结果转换为NumPy数组 action = self.actor(state).detach().cpu().numpy().flatten() return action # 训练方法 def train(self): # 如果回放池中样本数量不足,直接返回 if self.replay_buffer.size() < self.batch_size: return # 从回放池中采样一批数据 states, actions, rewards, next_states, dones = self.replay_buffer.sample(self.batch_size) # 将采样的数据转换为张量 states = torch.FloatTensor(states) actions = torch.FloatTensor(actions) rewards = torch.FloatTensor(rewards).unsqueeze(1) # 添加一个维度以匹配Q值维度 next_states = torch.FloatTensor(next_states) dones = torch.FloatTensor(dones).unsqueeze(1) # 添加一个维度以匹配Q值维度 # 计算critic的损失 with torch.no_grad(): # 关闭梯度计算 next_actions = self.actor_target(next_states) # 使用目标actor网络预测下一步动作 target_q = self.critic_target(next_states, next_actions) # 目标Q值 # 使用贝尔曼方程更新目标Q值 target_q = rewards + (1 - dones) * self.gamma * target_q # 当前Q值 current_q = self.critic(states, actions) # 均方误差损失 critic_loss = nn.MSELoss()(current_q, target_q) # 优化critic网络 self.critic_optimizer.zero_grad() critic_loss.backward() self.critic_optimizer.step() # 计算actor的损失 actor_loss = -self.critic(states, self.actor(states)).mean() # 策略梯度目标为最大化Q值 # 优化actor网络 self.actor_optimizer.zero_grad() actor_loss.backward() self.actor_optimizer.step() # 更新目标网络参数(软更新) for target_param, param in zip(self.critic_target.parameters(), self.critic.parameters()): target_param.data.copy_(self.tau * param.data + (1 - self.tau) * target_param.data) for target_param, param in zip(self.actor_target.parameters(), self.actor.parameters()): target_param.data.copy_(self.tau * param.data + (1 - self.tau) * target_param.data) # 将样本添加到回放池中 def add_to_replay_buffer(self, state, action, reward, next_state, done): self.replay_buffer.add(state, action, reward, next_state, done) # 绘制学习曲线的方法 import matplotlib.pyplot as plt def train_ddpg(env_name, episodes=1000, max_steps=200): # 创建环境 env = gym.make(env_name) state_dim = env.observation_space.shape[0] # 状态空间维度 action_dim = env.action_space.shape[0] # 动作空间维度 max_action = float(env.action_space.high[0]) # 动作最大值 # 初始化DDPG智能体 agent = DDPGAgent(state_dim, action_dim, max_action) rewards = [] # 用于存储每个episode的奖励 for episode in range(episodes): state, _ = env.reset() # 重置环境,获取初始状态 episode_reward = 0 # 初始化每轮奖励为0 for step in range(max_steps): # 选择动作 action = agent.select_action(state) # 执行动作,获取环境反馈 next_state, reward, done, _, _ = env.step(action) # 将样本存入回放池 agent.add_to_replay_buffer(state, action, reward, next_state, done) # 训练智能体 agent.train() # 更新当前状态 state = next_state # 累加奖励 episode_reward += reward if done: # 如果完成(到达终止状态),结束本轮 break # 记录每轮的累计奖励 rewards.append(episode_reward) print(f"Episode: {episode + 1}, Reward: {episode_reward}") # 绘制学习曲线 plt.plot(rewards) plt.title("Learning Curve") plt.xlabel("Episodes") plt.ylabel("Cumulative Reward") plt.show() env.close() # 关闭环境 # 主函数运行 if __name__ == "__main__": # 定义环境名称和训练轮数 env_name = "Pendulum-v1" episodes = 500 # 开始训练 train_ddpg(env_name, episodes=episodes) 

[Results] 运行结果


[Notice] 代码说明

演员和评论家网络:

        演员网络预测给定当前状态的动作。

        批评家网络评估状态-行为对的q值。

Replay Buffer:

        存储过去的经验,并使有效的采样训练。

训练:

        Critic使用Bellman方程更新评论家。

        Actor被更新以最大化期望q值。

目标网络:

        平滑更新以稳定训练。

环境:

        代理在Pendulum-v1环境中进行训练作为演示。

​# 环境配置 Python 3.11.5 torch 2.1.0 torchvision 0.16.0 gym 0.26.2
        由于博文主要为了介绍相关算法的原理和应用的方法,缺乏对于实际效果的关注,算法可能在上述环境中的效果不佳或者无法运行,一是算法不适配上述环境,二是算法未调参和优化,三是没有呈现完整的代码,四是等等。上述代码用于了解和学习算法足够了,但若是想直接将上面代码应用于实际项目中,还需要进行修改。

优势

  • 解决连续动作问题: 它可以直接输出一个连续值动作,而不像传统的离散强化学习算法需要动作离散化。
  • 样本效率高: 使用了经验回放和目标网络,这减少了样本相关性问题,提高了学习效率和稳定性。

通俗类比

可以把DDPG算法想象成一个赛车手(Actor)和他的教练(Critic):

  • **赛车手(Actor)**决定转弯的角度、加速的力度,直接控制赛车。
  • **教练(Critic)**则通过观察赛车手的表现,告诉他哪些动作是好的,哪些是需要改进的。
  • 经验回放池就是赛车手在训练中不断回看他之前的比赛录像,找到改进的地方。
  • 目标网络则类似于赛车手的长期目标,比如平稳驾驶,而不是今天开得快、明天开得慢。

应用场景

  1. 机器人运动控制(机械臂、无人机)
  2. 自动驾驶中的连续控制任务
  3. 游戏中的复杂策略设计
 更多强化学习文章,请前往:【强化学习(RL)】专栏

        博客都是给自己看的笔记,如有误导深表抱歉。文章若有不当和不正确之处,还望理解与指出。由于部分文字、图片等来源于互联网,无法核实真实出处,如涉及相关争议,请联系博主删除。如有错误、疑问和侵权,欢迎评论留言联系作者,或者添加VX:Rainbook_2,联系作者。✨

Read more

C++11新特性(下)----《Hello C++ Wrold!》(26)--(C/C++)

C++11新特性(下)----《Hello C++ Wrold!》(26)--(C/C++)

文章目录 * 前言 * lambda表达式 * 可变参数模板 * 展开参数包的方法 * 应用 * 包装器 * fiction包装器 * bind函数 * 作业部分 前言 在 C++11 标准带来的诸多革命性特性中,“简化代码编写” 与 “统一可调用对象管理” 是两大核心目标。lambda 表达式解决了传统仿函数 “定义繁琐、复用性低” 的痛点,让局部场景下的自定义逻辑(如排序规则、回调函数)能以更简洁的匿名函数形式实现;可变参数模板则打破了模板参数数量固定的限制,为 STL 容器(如emplace_back)和通用函数设计提供了灵活的参数处理能力;而 function 包装器与 bind 函数,则进一步整合了函数指针、仿函数、lambda 等不同类型的可调用对象,实现了统一管理与参数适配,甚至让可调用对象存储到容器中成为可能。 这些特性并非孤立存在 ——lambda 的底层依赖仿函数实现,可变参数模板为emplace系列接口提供了技术支撑,

By Ne0inhk

为什么你的UE6项目必须立即支持C++26?,90%团队忽视的性能红利

第一章:为什么UE6项目必须立即拥抱C++26 随着Unreal Engine 6正式支持C++26标准,开发者迎来了前所未有的性能优化与语言表达能力提升。C++26不仅引入了模块化系统(Modules)的最终形态,还增强了协程、反射和元编程能力,这些特性在大型游戏项目中具有决定性意义。 模块化架构大幅提升编译效率 传统头文件包含机制在UE项目中常导致编译时间呈指数级增长。C++26的模块系统彻底解决了这一痛点。 // 声明一个模块接口单元 export module MathUtils; export namespace math { constexpr float PI = 3.14159f; float CalculateDistance(float x, y); } 上述代码将数学工具封装为模块,其他源文件可通过 import MathUtils; 直接使用,避免重复解析头文件,平均缩短构建时间达40%以上。 统一反射系统赋能运行时动态逻辑 C++26原生支持静态反射,结合UE6的UObject系统可实现零开销的序列化与蓝图交互。 1. 定义带有反射属性的类

By Ne0inhk
C++:set/multiset和map/multimap文档详细解析

C++:set/multiset和map/multimap文档详细解析

Hello大家好! 很高兴与大家见面! 给生活添点快乐,开始今天的编程之路。 我的博客:<但愿. 我的专栏:C语言、题目精讲、算法与数据结构、C++ 欢迎点赞,关注 目录   前言   一 容器的分类(根据容器中各个数据之间的关系)          1.1序列式容器                  1.1.1序列式容器的概念                  1.1.2序列式容器的例子           1.2关联式容器                  1.2.1关联式容器的概念                  1.2.2关联式容器的例子   二  set/multiset           2.1参考文档(multiset包在set中所以其没有头文件)           2.2set类的介绍                   2.2.1set类的实现的简单介绍                  2.2.2set类的接口介绍                           2.

By Ne0inhk
【C++:C++11收尾】解构C++可调用对象:从入门到精通,掌握function包装器与bind适配器包装器详解

【C++:C++11收尾】解构C++可调用对象:从入门到精通,掌握function包装器与bind适配器包装器详解

🎬 个人主页:艾莉丝努力练剑 ❄专栏传送门:《C语言》《数据结构与算法》《C/C++干货分享&学习过程记录》 《Linux操作系统编程详解》《笔试/面试常见算法:从基础到进阶》《Python干货分享》 ⭐️为天地立心,为生民立命,为往圣继绝学,为万世开太平 🎬 艾莉丝的简介: 🎬 艾莉丝的C++专栏简介: 文章目录 * C++学习阶段的三个参考文档 * 8 ~> 包装器 * 8.1 function * 8.1.1 结构 * 8.1.2 概念 * 8.1.3 function实现 * 8.1.4 重写逆波兰表达式求值 * 8.2 bind

By Ne0inhk