Pendulum_DDPG代码走读之pendulum.py

Pendulum_DDPG.py中引入:

# 初始化环境状态
state = env.reset()

# 获取当前时刻的状态
state_next, reward, terminal, _ = env.step(action)

# 其中env.step(action)是进入 time_limit.py的step函数 再进入 pendulum.py的step函数

其中time_limit.py主要是对倒立摆的时间进行限制,绝大多数系统中默认max_episode_steps=200,也就是说在一个episode中执行200个step就会将terminal设置为True,防止其无限进行下去,这里不做赘述,主要是介绍pendulum.py,首先将pendulum.py中的step函数贴出来。

state_next, reward, terminal, _ = env.step(action)
    def step(self,u):
        # th:角度,thdot:角速度
        th, thdot = self.state # th := theta

        g = 10.
        m = 1.
        l = 1.
        dt = self.dt

        u = np.clip(u, -self.max_torque, self.max_torque)[0]
        self.last_u = u    # for rendering
        costs = angle_normalize(th)**2 + .1*thdot**2 + .001*(u**2)

        newthdot = thdot + (-3*g/(2*l) * np.sin(th + np.pi) + 3./(m*l**2)*u) * dt
        newth = th + n
import torch import torch.nn as nn import torch.optim as optim import gym import numpy as np import matplotlib.pyplot as plt # 定义Actor网络 class Actor(nn.Module): def __init__(self, state_dim, action_dim, max_action): super(Actor, self).__init__() self.layer = nn.Sequential( nn.Linear(state_dim, 400), nn.ReLU(), nn.Linear(400, 300), nn.ReLU(), nn.Linear(300, action_dim), nn.Tanh() ) self.max_action = max_action def forward(self, state): return self.max_action * self.layer(state) # 定义Critic网络 class Critic(nn.Module): def __init__(self, state_dim, action_dim): super(Critic, self).__init__() self.layer = nn.Sequential( nn.Linear(state_dim + action_dim, 400), nn.ReLU(), nn.Linear(400, 300), nn.ReLU(), nn.Linear(300, 1) ) def forward(self, state, action): return self.layer(torch.cat([state, action], 1)) # DDPG智能体 class DDPG: def __init__(self, env): self.env = env self.state_dim = env.observation_space.shape[0] self.action_dim = env.action_space.shape[0] self.max_action = float(env.action_space.high[0]) # 创建网络 self.actor = Actor(self.state_dim, self.action_dim, self.max_action) self.actor_target = Actor(self.state_dim, self.action_dim, self.max_action) self.actor_target.load_state_dict(self.actor.state_dict()) self.actor_optimizer = optim.Adam(self.actor.parameters(), lr=1e-4) self.critic = Critic(self.state_dim, self.action_dim) self.critic_target = Critic(self.state_dim, self.action_dim) self.critic_target.load_state_dict(self.critic.state_dict()) self.critic_optimizer = optim.Adam(self.critic.parameters(), lr=1e-3) self.replay_buffer = [] self.buffer_size = 100000 self.batch_size = 64 self.gamma = 0.99 self.tau = 0.005 def select_action(self, state, noise=True): state = torch.FloatTensor(state.reshape(1, -1)) action = self.actor(state).cpu().data.numpy().flatten() if noise: action += np.random.normal(0, 0.1, size=self.action_dim) return np.clip(action, -self.max_action, self.max_action) def train(self): if len(self.replay_buffer) < self.batch_size: return # 采样批次数据 batch = np.random.choice(len(self.replay_buffer), self.batch_size) states, actions, rewards, next_states, dones = zip(*[self.replay_buffer[i] for i in batch]) states = torch.FloatTensor(np.array(states)) actions = torch.FloatTensor(np.array(actions)) rewards = torch.FloatTensor(np.array(rewards)).unsqueeze(1) next_states = torch.FloatTensor(np.array(next_states)) dones = torch.FloatTensor(1 - np.array(dones)).unsqueeze(1) # 更新Critic target_actions = self.actor_target(next_states) target_q = self.critic_target(next_states, target_actions) target_q = rewards + (dones * self.gamma * target_q).detach() current_q = self.critic(states, actions) critic_loss = nn.MSELoss()(current_q, target_q) self.critic_optimizer.zero_grad() critic_loss.backward() self.critic_optimizer.step() # 更新Actor actor_loss = -self.critic(states, self.actor(states)).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_(self.tau * param.data + (1 - self.tau) * target_param.data) for param, target_param in zip(self.critic.parameters(), self.critic_target.parameters()): target_param.data.copy_(self.tau * param.data + (1 - self.tau) * target_param.data) # 训练函数 def train_ddpg(env_name="Pendulum-v1", target_reward=-200, max_episodes=500): env = gym.make(env_name) agent = DDPG(env) rewards = [] for episode in range(max_episodes): state = env.reset() episode_reward = 0 while True: action = agent.select_action(state) next_state, reward, done, _ = env.step(action) agent.replay_buffer.append((state, action, reward, next_state, done)) if len(agent.replay_buffer) > agent.buffer_size: agent.replay_buffer.pop(0) episode_reward += reward state = next_state agent.train() if done: break # 测试阶段 test_reward = 0 state = env.reset() while True: action = agent.select_action(state, noise=False) state, reward, done, _ = env.step(action) test_reward += reward if done: break rewards.append(test_reward) avg_reward = np.mean(rewards[-10:]) # 计算最近10轮平均奖励 # 可视化 plt.clf() plt.plot(rewards, label='Episode Reward') plt.plot([np.mean(rewards[max(0,i-10):i+1]) for i in range(len(rewards))], label='Moving Average') plt.xlabel('Episode') plt.ylabel('Reward') plt.title(f'DDPG Training Progress ({env_name})') plt.legend() plt.pause(0.001) print(f"Episode: {episode+1}, Reward: {test_reward:.2f}, Avg Reward: {avg_reward:.2f}") # 达到目标则停止训练 if avg_reward >= target_reward: print(f"\nReached target average reward of {target_reward} at episode {episode+1}!") break env.close() plt.show() return agent # 启动训练 if __name__ == "__main__": trained_agent = train_ddpg() 请在上面代码中加入在训练结束后渲染一次最终的成功表现
最新发布
05-31
<think>好的,用户想在DDPG训练代码中加入训练结束后的渲染功能,展示智能体的最终表现。我需要先理解用户的具体需求。用户可能已经有一个DDPG的实现,现在希望在训练完成后自动运行一个演示,用渲染功能显示训练后的智能体如何与环境互动。首先,我得回忆一下gym环境的渲染方法。通常,在训练过程中,渲染可能会被关闭以提高速度,而在测试或展示时开启。用户可能需要在训练循环结束后,调用env.render()来显示智能体的行为。接下来,我需要考虑如何在现有的DDPG代码结构中插入渲染部分。通常,DDPG的训练代码包括训练循环,收集经验,更新网络等步骤。训练结束后,用户希望运行一个测试回合,并在其中启用渲染。因此,可能需要添加一个单独的测试函数,或者在训练结束后运行一个循环,使用训练好的策略网络选择动作,同时每一步都调用渲染。 需要注意,有些gym环境需要在创建时指定render_mode,或者调用特定的渲染方法。例如,较新的gym版本可能需要使用render_mode="human"来初始化环境。因此,用户可能需要修改环境初始化的部分,或者在测试时重新创建一个用于渲染的环境实例。 另外,渲染可能会影响性能,所以在训练过程中应保持关闭,只在最终演示时开启。同时,需要确保在渲染时没有数据收集或网络更新的步骤,只是单纯地展示智能体的行为。可能还需要处理环境重置的问题。在测试回合开始时,需要调用env.reset()来获取初始状态,然后循环执行动作,直到回合结束。每一步执行后,调用env.render()来更新可视化界面。最后,需要确保代码的兼容性,比如不同版本的gym库可能有不同的渲染方式,需要检查用户使用的版本,并给出相应的建议。例如,对于较新的gym(v0.26+),可能需要使用不同的渲染方法,或者处理返回参数的变化。总结步骤:在训练结束后,创建一个新的环境实例或使用现有环境,循环执行策略网络生成的动作,每一步调用渲染函数,直到回合结束。需要处理环境初始化和渲染模式,确保渲染正确显示,并在代码中适当的位置插入这部分逻辑。</think>以下是在DDPG训练代码中添加渲染功能的实现方法,以Pendulum-v1环境为例: ### 修改步骤说明 1. **环境初始化阶段** 在原有环境创建后添加`test_env`专用测试环境: ```python # 训练环境(关闭渲染) env = gym.make("Pendulum-v1") # 测试环境(开启渲染) test_env = gym.make("Pendulum-v1", render_mode="human") # v0.26+版本需要显式指定渲染模式[^1] ``` 2. **训练结束后添加渲染逻辑** 在训练主循环后插入测试代码: ```python def train_ddpg(): # ...原有训练代码... # 训练结束后渲染演示 state = test_env.reset() total_reward = 0 while True: action = actor_network.select_action(state) # 使用训练好的策略网络 next_state, reward, done, _ = test_env.step(action) test_env.render() # 关键渲染调用 total_reward += reward state = next_state if done: break print(f"Render demo total reward: {total_reward}") ``` ### 完整代码示例 ```python import gym # 原有DDPG类定义保持不变... class DDPG: def __init__(self, state_dim, action_dim): # ...初始化网络... def train(self, env, test_env, episodes=1000): for ep in range(episodes): # ...原有训练循环... # 新增渲染演示 state = test_env.reset() total_reward = 0 while True: action = self.actor.select_action(state) next_state, reward, done, _ = test_env.step(action) test_env.render() total_reward += reward state = next_state if done: break print(f"Final demonstration reward: {total_reward}") # 主程序修改 if __name__ == "__main__": env = gym.make("Pendulum-v1") test_env = gym.make("Pendulum-v1", render_mode="human") # 创建专用渲染环境 agent = DDPG(env.observation_space.shape[0], env.action_space.shape[0]) agent.train(env, test_env) # 传入测试环境 ``` ### 关键修改说明 | 修改点 | 作用 | 注意事项 | |--------|------|----------| | `render_mode="human"` | 指定可视化渲染模式 | 仅适用于gym>=0.26.0版本 | | 独立测试环境 | 避免训练时意外触发渲染 | 保持训练环境的高性能 | | `test_env.render()` | 强制刷新可视化窗口 | 需在每个step后调用 | ### 版本兼容性处理 对于不同gym版本,需调整渲染方式: ```python # gym<0.26.0的旧版本 test_env = gym.make("Pendulum-v1") test_env.render() # 直接调用环境方法 # gym>=0.26.0的新版本 test_env = gym.make("Pendulum-v1", render_mode="human") # 通过参数启用渲染 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值