训练效果
DDPG算法是一种基于演员-评论家(Actor-Critic)框架的深度强化学习(Deep Reinforcement Learning)算法,它可以处理连续动作空间的问题。DDPG算法描述如下:
GPT-4 Turbo
Copilot GPT-4
DDPG算法伪代码:
深度确定性策略梯度(DDPG)算法,用于训练一个智能体解决OpenAI Gym中的LunarLanderContinuous-v2环境示例代码
import argparse # 用于解析命令行参数
from collections import deque # 提供了一个双端队列
import itertools # 用于对迭代对象执行多种操作
import random # 提供随机数相关的函数
import time # 提供时间相关的函数
import torch.optim as optim # 提供了模型优化器
import gymnasium as gym # 强化学习环境的库
import numpy as np # 数学库,用于数组和矩阵等数学运算
import torch.nn.functional as F # PyTorch的函数接口
import torch # 神经网络库
import torch.nn as nn # 用于构建神经网络
from torch.utils.tensorboard import SummaryWriter # 用于可视化的工具
# 定义一个高斯噪声类,用于给动作添加一些随机性,增加探索性
class GaussianNoise:
def __init__(self, dim, mu=None, std=None):
# 初始化高斯噪声的均值和标准差,如果没有给定,就默认为零向量和0.1的常数向量
self.mu = mu if mu else np.zeros(dim)
self.std = std if std else np.ones(dim) * .1
def sample(self):
# 从高斯分布中采样一个噪声
return np.random.normal(self.mu, self.std)
# 定义一个回放缓冲区类,用于存储和采样转移
class ReplayMemory:
__slots__ = ['buffer']
def __init__(self, capacity):
# 初始化回放缓冲区的容量,使用一个双端队列来实现
self.buffer = deque(maxlen=capacity)
def __len__(self):
# 返回回放缓冲区的长度
return len(self.buffer)
def append(self, *transition):
# 将一个转移(状态,动作,奖励,下一个状态,是否结束)添加到回放缓冲区中
# 使用tuple和map函数来将转移转换为元组的形式
self.buffer.append(tuple(map(tuple, transition)))
def sample(self, batch_size, device):
'''sample a batch of transition tensors'''
# 从回放缓冲区中随机采样一批转移,返回一个生成器,每个元素是一个张量
# 使用random.sample函数来随机采样
# 使用torch.tensor函数来将转移转换为张量,并指定数据类型为浮点数和设备为device
# 使用zip和*操作符来将转移按照元素分组
transitions = random.sample(self.buffer, batch_size)
return (torch.tensor(x, dtype=torch.float, device=device)
for x in zip(*transitions))
# 定义一个演员网络类,用于输出一个确定性的动作
# ActorNet动作空间是2的原因是因为它需要适应环境的动作空间。
# 在LunarLanderContinuous-v2环境中,智能体需要控制着陆器的两个引擎,
# 一个是主引擎,一个是方向引擎。主引擎的推力范围是0到1,方向引擎的
# 推力范围是-1到1。因此,智能体的动作空间是一个2维的向量,每个维度
# 的取值范围是-1到1。为了让ActorNet能够输出这样的动作,它的动作空间
# 也需要设置为2,即输出层的神经元个数为2,同时使用Tanh激活函数,
# 使得输出在-1到1之间。
class ActorNet(nn.Module):
def __init__(self, state_dim=8, action_dim=2, hidden_dim=(400, 300)):
# 调用父类的初始化方法
super().__init__()
# 解包隐藏层的维度
h1, h2 = hidden_dim
# 定义演员网络的头部,使用一个全连接层和一个ReLU激活函数
self.actor_head = nn.Sequential(
nn.Linear(state_dim, h1),
nn.ReLU(),
)
# 定义演员网络的主体,使用一个全连接层和一个ReLU激活函数
self.actor = nn.Sequential(
nn.Linear(h1, h2),
nn.ReLU(),
)
# 定义演员网络的输出,使用一个全连接层和一个Tanh激活函数,使得输出在-1到1之间
self.actor_output = nn.Sequential(
nn.Linear(h2, action_dim),
nn.Tanh(),
)
def forward(self, x):
# 定义演员网络的前向传播,输入一个状态,输出一个动作
# 先通过演员网络的头部
x = self.actor_head(x)
# 再通过演员网络的主体
x = self.actor(x)
# 最后通过演员网络的输出
x = self.actor_output(x)
# 返回输出的动作
return x
#