Files

168 lines
5.9 KiB
Python
Raw Permalink Normal View History

import gymnasium as gym
import torch
import os
import pickle
from agents.dpac import DPACAgent
from agents.ddpg import DDPGAgent
from utils import plot_comparison
RESULTS_DIR = 'training_results'
# ---------- 路径工具 ----------
def _path(agent_class, env_name, num_episodes, suffix):
os.makedirs(RESULTS_DIR, exist_ok=True)
return os.path.join(RESULTS_DIR, f'{agent_class.__name__}_{env_name}_{num_episodes}{suffix}')
def result_path(agent_class, env_name, num_episodes):
return _path(agent_class, env_name, num_episodes, '.pkl')
def model_path(agent_class, env_name, num_episodes):
return _path(agent_class, env_name, num_episodes, '_model.pt')
# ---------- 训练 & 保存 ----------
def train(env_name, agent_class, device, num_episodes):
rp = result_path(agent_class, env_name, num_episodes)
mp = model_path(agent_class, env_name, num_episodes)
if os.path.exists(rp) and os.path.exists(mp):
with open(rp, 'rb') as f:
rewards = pickle.load(f)
print(f"[{agent_class.__name__}] 已加载训练结果: {rp}")
return rewards
print(f"[{agent_class.__name__}] 开始训练 ...")
if agent_class.__name__ == 'DDPGAgent':
rewards, agent = _train_ddpg(env_name, agent_class, device, num_episodes)
else:
rewards, agent = _train_dpac(env_name, agent_class, device, num_episodes)
with open(rp, 'wb') as f:
pickle.dump(rewards, f)
agent.save(mp)
print(f"[{agent_class.__name__}] 训练完成 | 曲线: {rp} | 模型: {mp}")
return rewards
def _train_dpac(env_name, agent_class, device, num_episodes):
env = gym.make(env_name)
state_dim = env.observation_space.shape[0] # type: ignore
action_dim = env.action_space.shape[0] # type: ignore
max_action = float(env.action_space.high[0]) # type: ignore
agent = agent_class(state_dim, action_dim, max_action, device)
rewards = []
for ep in range(num_episodes):
state, _ = env.reset()
episode_reward = 0
while True:
action = agent.select_action(state)
ns, reward, terminated, truncated, _ = env.step(action)
agent.update(state, action, reward, ns, None, terminated or truncated)
state = ns
episode_reward += reward # type: ignore
if terminated or truncated:
break
rewards.append(episode_reward)
if (ep + 1) % 50 == 0:
avg = sum(rewards[-50:]) / 50
print(f" 回合 {ep+1}/{num_episodes}, 近50回合均分: {avg:.2f}")
env.close()
return rewards, agent
def _train_ddpg(env_name, agent_class, device, num_episodes, batch_size=64, start_steps=2000):
env = gym.make(env_name)
state_dim = env.observation_space.shape[0] # type: ignore
action_dim = env.action_space.shape[0] # type: ignore
max_action = float(env.action_space.high[0]) # type: ignore
agent = agent_class(state_dim, action_dim, max_action, device)
rewards = []
total_steps = 0
for ep in range(num_episodes):
state, _ = env.reset()
episode_reward = 0
while True:
action = agent.select_action(state)
ns, reward, terminated, truncated, _ = env.step(action)
agent.replay_buffer.add(state, action, reward, ns, terminated or truncated)
total_steps += 1
state = ns
episode_reward += reward # type: ignore
if total_steps > start_steps:
agent.update(batch_size)
if terminated or truncated:
break
rewards.append(episode_reward)
if (ep + 1) % 50 == 0:
avg = sum(rewards[-50:]) / 50
print(f" 回合 {ep+1}/{num_episodes}, 近50回合均分: {avg:.2f}")
env.close()
return rewards, agent
# ---------- 视频演示 ----------
def demo(env_name, agent_class, device, num_demo=5, num_episodes=600):
mp = model_path(agent_class, env_name, num_episodes)
if not os.path.exists(mp):
print(f"[{agent_class.__name__}] 未找到模型权重 {mp},跳过演示。")
return
video_dir = os.path.join(RESULTS_DIR, 'videos')
os.makedirs(video_dir, exist_ok=True)
base_env = gym.make(env_name, render_mode='rgb_array')
env = gym.wrappers.RecordVideo(base_env, video_dir, name_prefix=f'{agent_class.__name__}_demo')
state_dim = env.env.observation_space.shape[0] # type: ignore
action_dim = env.env.action_space.shape[0] # type: ignore
max_action = float(env.env.action_space.high[0]) # type: ignore
agent = agent_class(state_dim, action_dim, max_action, device)
agent.load(mp)
print(f"[{agent_class.__name__}] 加载模型: {mp},录制 {num_demo} 局演示 ...")
for ep in range(num_demo):
state, _ = env.reset()
total_reward = 0.0
while True:
action = agent.select_action(state)
state, reward, terminated, truncated, _ = env.step(action)
total_reward += float(reward)
if terminated or truncated:
break
print(f" 回合 {ep+1}/{num_demo}, 总奖励: {total_reward:.2f}")
env.close()
base_env.close()
print(f"[{agent_class.__name__}] 视频已保存至: {video_dir}")
# ---------- 主程序 ----------
if __name__ == "__main__":
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"计算设备: {device}\n")
ENV_NAME = 'Pendulum-v1'
EPISODES = 600
dpac_rewards = train(ENV_NAME, DPACAgent, device, EPISODES)
ddpg_rewards = train(ENV_NAME, DDPGAgent, device, EPISODES)
results = {
'DPAC': dpac_rewards,
'DDPG': ddpg_rewards,
}
plot_comparison(results, window=50, save_path='compare_dpac_vs_ddpg.png')
demo(ENV_NAME, DPACAgent, device)
demo(ENV_NAME, DDPGAgent, device)