用pytorch实现DDPG算法

DDPG算法原理的示意以及程序实现

  1. 基本原理与结构:

DDPG算法是Actor-Critic (AC) 框架下的一种在线式深度强化学习算法,因此算法内部包括Actor网络和Critic网络,每个网络分别遵从各自的更新法则进行更新,从而使得累计期望回报最大化。

DDPG算法将确定性策略梯度算法和DQN算法中的相关技术结合在一起,之前我们在讲DQN算法时,详细说明了其中的两个重要的技术:经验回放和目标网络。具体而言,DDPG算法主要包括以下三个关键技术:

(1)经验回放:智能体将得到的经验数据(s,a,r,s,)放入Replay Buffer中,更新网络参数时按照批量采样。

(2)目标网络:在Actor网络和Critic网络外再使用一套用于估计目标的目标 Actor网络和目标 Critic网络。在更新目标网络时,为了避免参数更新过快,采用软更新方式。

(3)噪声探索:确定性策略输出的动作为确定性动作,缺乏对环境的探索。在训练阶段,给Actor网络输出的动作加入噪声,从而让智能体具备一定的探索能力。

DDPG算法属于AC(Actor-critic)架构,且具有四个网络,即Critic当前网络、Critic目标网络和Actor的当前网络、Actor目标网络,Actor策略网络与DQN相似,但具有确定性策略,因此不需要ϵ−贪婪法这样的选择方法。而对经验回放池中采样的下一状态S′使用贪婪法选择动作A′,这部分工作由于用来估计目标Q值,因此可以放到Actor目标网络完成。Actor策略网络基于经验回放池提供的S′,A′计算目标Q值,Critic策略网络用于评估。而Critic目标网络计算出目标Q值一部分后,Critic当前网络会计算目标Q值,并进行网络参数的更新,并定期将网络参数复制到Critic目标网络。

简化的模型如下:

这四个网络的作用分别如下:

Actor当前网络:负责策略网络参数θ的迭代更新,即

负责根据当前状态S选择当前动作A,用于和环境交互生成S',R

Actor目标网络:负责根据经验回放池中采样的下一状态S'(或叫st+1)选择最优下一动作A'。网络参数θ'定期从θ复制。用于预测下一状态的行为取值。

Critic当前网络:输出为当前状态 s 和实际执行的动作 a ,其输出首先用于计算损失函数,公式为:

还用于 Actor 部分的参数更新,即:

Critic目标网络: 输入为下一状态st+1 和 Actor 目标网络中输出的策略,输出用于计算 TD 目标,即:

详细结构图如下:

具体算法流程如下:

2 代码实现

代码分为两个部分,一是Training,用来完成DDPG算法测试,二是DDPG_brain,实现算法网络结构。

Training的主要结构:①获取环境的参数②建立DDPG网路③还原环境参数,进行训④打印训练结果。

DDPG的主要结构:

__init__方法用来初始化网络模型,获取记忆库等

Store_transition用来存储训练结果。

Choose_action 用来选择行为

Learn进行网络的学习

 3.个人理解:

DDPG算法的目的是为了得到一个输出正确动作的神经网络,而这个网络无法获得动作后的收益,也就是无法获得机器学习中的y_label,所以需要critic网络对动作后的收益进行估计,也就是获得动作的q值,让action网络利用critic得到的q值进行学习,从而获得最大的q值(收益)。而critic网络如何知道当前动作会产生多大的q值(收益)呢,它需要知道当前动作从环境中获得了多少奖励,并且需要知道这个动作后的未来可能获得的奖励有多少(不能鼠目寸光),将这两种奖励以某种权重叠加得到q值告知action网络,从而完成对action网络的更新。那么如何更新critic网络的参数呢,也就是说如何让critic网络看清真正的q值呢,我们最初的训练好的网络什么都不知道,但它也会对action网络进行指导,也就是探索者机制,action网络进行更新后获得了更多的数据集,从而获得了一些q值,选择其中最大的q值作为奖励,将这些奖励加入到critic网络的更新中,就可以让critic网络明白什么是奖励。

  • 4
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
以下是一份使用Pytorch实现DDPG算法的示例代码: ```python import torch import torch.nn as nn import torch.optim as optim import numpy as np # 定义神经网络,包括ActorCritic class Actor(nn.Module): def __init__(self, state_dim, action_dim, max_action): super(Actor, self).__init__() self.layer1 = nn.Linear(state_dim, 256) self.layer2 = nn.Linear(256, 256) self.layer3 = nn.Linear(256, action_dim) self.max_action = max_action def forward(self, state): x = torch.relu(self.layer1(state)) x = torch.relu(self.layer2(x)) x = self.max_action * torch.tanh(self.layer3(x)) return x class Critic(nn.Module): def __init__(self, state_dim, action_dim): super(Critic, self).__init__() self.layer1 = nn.Linear(state_dim + action_dim, 256) self.layer2 = nn.Linear(256, 256) self.layer3 = nn.Linear(256, 1) def forward(self, state, action): x = torch.cat([state, action], 1) x = torch.relu(self.layer1(x)) x = torch.relu(self.layer2(x)) x = self.layer3(x) return x # 定义DDPG算法 class DDPG(object): def __init__(self, state_dim, action_dim, max_action): self.actor = Actor(state_dim, action_dim, max_action).to(device) self.actor_target = Actor(state_dim, action_dim, max_action).to(device) self.actor_target.load_state_dict(self.actor.state_dict()) self.actor_optimizer = optim.Adam(self.actor.parameters(), lr=1e-3) self.critic = Critic(state_dim, action_dim).to(device) self.critic_target = Critic(state_dim, action_dim).to(device) self.critic_target.load_state_dict(self.critic.state_dict()) self.critic_optimizer = optim.Adam(self.critic.parameters(), lr=1e-3) self.max_action = max_action def select_action(self, state): state = torch.FloatTensor(state.reshape(1, -1)).to(device) return self.actor(state).cpu().data.numpy().flatten() def train(self, replay_buffer, batch_size=256, discount=0.99, tau=0.005): # 从缓冲区采样一批数据 state, action, next_state, reward, not_done = replay_buffer.sample(batch_size) state = torch.FloatTensor(state).to(device) action = torch.FloatTensor(action).to(device) next_state = torch.FloatTensor(next_state).to(device) reward = torch.FloatTensor(reward).to(device) not_done = torch.FloatTensor(1 - not_done).to(device) # 更新critic网络 next_action = self.actor_target(next_state) target_Q = self.critic_target(next_state, next_action).detach() target_Q = reward + (discount * not_done * target_Q) current_Q = self.critic(state, action) critic_loss = nn.functional.mse_loss(current_Q, target_Q) self.critic_optimizer.zero_grad() critic_loss.backward() self.critic_optimizer.step() # 更新actor网络 pred_action = self.actor(state) actor_loss = -self.critic(state, pred_action).mean() self.actor_optimizer.zero_grad() actor_loss.backward() self.actor_optimizer.step() # 更新目标网络 for param, target_param in zip(self.actor.parameters(), self.actor_target.parameters()): target_param.data.copy_(tau * param.data + (1 - tau) * target_param.data) for param, target_param in zip(self.critic.parameters(), self.critic_target.parameters()): target_param.data.copy_(tau * param.data + (1 - tau) * target_param.data) # 定义replay buffer class ReplayBuffer(object): def __init__(self, state_dim, action_dim, max_size=int(1e6)): self.max_size = max_size self.ptr = 0 self.size = 0 self.state = np.zeros((max_size, state_dim)) self.action = np.zeros((max_size, action_dim)) self.next_state = np.zeros((max_size, state_dim)) self.reward = np.zeros((max_size, 1)) self.not_done = np.zeros((max_size, 1)) def add(self, state, action, next_state, reward, done): self.state[self.ptr] = state self.action[self.ptr] = action self.next_state[self.ptr] = next_state self.reward[self.ptr] = reward self.not_done[self.ptr] = 1 - done self.ptr = (self.ptr + 1) % self.max_size self.size = min(self.size + 1, self.max_size) def sample(self, batch_size): idx = np.random.randint(0, self.size, size=batch_size) return ( self.state[idx], self.action[idx], self.next_state[idx], self.reward[idx], self.not_done[idx] ) # 定义训练过程 def train(env, agent, episodes, steps_per_episode, batch_size, discount, tau): for episode in range(episodes): state = env.reset() total_reward = 0 for step in range(steps_per_episode): action = agent.select_action(state) next_state, reward, done, _ = env.step(action) replay_buffer.add(state, action, next_state, reward, done) if replay_buffer.size > batch_size: agent.train(replay_buffer, batch_size, discount, tau) state = next_state total_reward += reward if done: break print("Episode: {}, total reward: {:.2f}".format(episode, total_reward)) # 测试代码 device = torch.device("cuda" if torch.cuda.is_available() else "cpu") 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 = DDPG(state_dim, action_dim, max_action) replay_buffer = ReplayBuffer(state_dim, action_dim) train(env, agent, episodes=100, steps_per_episode=500, batch_size=256, discount=0.99, tau=0.005) ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值