基于“蘑菇书”的强化学习知识点(二十):第十二章的代码:DDPG.ipynb及其涉及的其他代码的更新以及注解(gym版本 >= 0.26)

第七章的代码:DDPG.ipynb及其涉及的其他代码的更新以及注解(gym版本 >= 0.26)

摘要

本系列知识点讲解基于蘑菇书EasyRL中的内容进行详细的疑难点分析!具体内容请阅读蘑菇书EasyRL


对应蘑菇书附书代码——DDPG.ipynb


# -*- coding: utf-8 -*-


"""1. 定义算法"""
"""
1.1. 定义模型
"""
import torch
import torch.nn as nn
import torch.nn.functional as F
class Actor(nn.Module):
    def __init__(self, n_states, n_actions, hidden_dim = 256, init_w=3e-3):
        super(Actor, self).__init__()  
        self.linear1 = nn.Linear(n_states, hidden_dim)
        self.linear2 = nn.Linear(hidden_dim, hidden_dim)
        self.linear3 = nn.Linear(hidden_dim, n_actions)
        '''
        作用:对第三层的权重使用均匀分布初始化,范围为 [-0.003, 0.003]。
        数值例子:每个权重值在 [-0.003, 0.003] 之间,这有助于输出层初始时较小的值,防止过大输出。
        '''
        self.linear3.weight.data.uniform_(-init_w, init_w)
        '''
        作用:对第三层的偏置同样使用均匀分布初始化,范围为 [-0.003, 0.003]。
        数值例子:例如,偏置可能被初始化为 [0.001, -0.002]。
        '''
        self.linear3.bias.data.uniform_(-init_w, init_w)
    def forward(self, x):
        x = F.relu(self.linear1(x))
        x = F.relu(self.linear2(x))
        x = torch.tanh(self.linear3(x))
        return x

"""
注意DDGP中critic网络的输入是state加上action。
"""        
class Critic(nn.Module):
    def __init__(self, n_states, n_actions, hidden_dim=256, init_w=3e-3):
        super(Critic, self).__init__()
        self.linear1 = nn.Linear(n_states + n_actions, hidden_dim)
        self.linear2 = nn.Linear(hidden_dim, hidden_dim)
        self.linear3 = nn.Linear(hidden_dim, 1)
        # 随机初始化为较小的值
        self.linear3.weight.data.uniform_(-init_w, init_w)
        self.linear3.bias.data.uniform_(-init_w, init_w)
        self.count = 0
    def forward(self, state, action):
        # 按维数1拼接

        x = torch.cat([state, action], 1)
        x = F.relu(self.linear1(x))
        x = F.relu(self.linear2(x))
        x = self.linear3(x)
        return x
    
    
"""
1.2 定义经验回放
"""    
from collections import deque
import random
class ReplayBuffer:
    """
    作用:定义一个名为 ReplayBuffer 的类,用于存储强化学习中的经验(transition)。
    说明:ReplayBuffer 常用于经验重放,存储训练过程中收集的状态、动作、奖励等数据。
    """
    def __init__(self, capacity: int) -> None:
        self.capacity = capacity
        self.buffer = deque(maxlen=self.capacity)
    def push(self,transitions):
        '''
        transitions 通常是一个元组,包含 (state, action, reward, next_state, done) 等数据。
        '''
        self.buffer.append(transitions)
    def sample(self, batch_size: int, sequential: bool = False):
        if batch_size > len(self.buffer):
            batch_size = len(self.buffer)
        if sequential: # sequential sampling
            rand = random.randint(0, len(self.buffer) - batch_size)
            batch = [self.buffer[i] for i in range(rand, rand + batch_size)]
            # return zip(*batch)
            return tuple(zip(*batch))
        else:
            batch = random.sample(self.buffer, batch_size)
            # return zip(*batch)
            return tuple(zip(*batch))
    def clear(self):
        self.buffer.clear()
    def __len__(self):
        return len(self.buffer) 
    
    
import torch.optim as optim
import numpy as np
class DDPG:
    """
    作用:定义一个名为 DDPG 的类,用于实现深度确定性策略梯度算法。
    说明:该类封装了 actor/critic 网络、目标网络、优化器、经验回放以及相关更新操作。
    """
    def __init__(self, models,memories,cfg):
        self.device = torch.device(cfg['device'])
        self.critic = models['critic'].to(self.device)
        self.target_critic = models['critic'].to(self.device)
        self.actor = models['actor'].to(self.device)
        self.target_actor = models['actor'].to(self.device)
        # 复制参数到目标网络
        '''
        作用:遍历目标 critic 和在线 critic 网络的每个参数,将在线网络参数复制到目标网络中,使其完全一致。
        '''
        for target_param, param in zip(self.target_critic.parameters(), self.critic.parameters()):
            target_param.data.copy_(param.data)
        '''
        作用:同样对 actor 网络进行参数复制,使目标 actor 与在线 actor 完全一致
        '''
        for target_param, param in zip(self.target_actor.parameters(), self.actor.parameters()):
            target_param.data.copy_(param.data)
        self.critic_optimizer = optim.Adam(self.critic.parameters(),  lr=cfg['critic_lr'])
        self.actor_optimizer = optim.Adam(self.actor.parameters(), lr=cfg['actor_lr'])
        self.memory = memories['memory']
        self.batch_size = cfg['batch_size']
        self.gamma = cfg['gamma']
        self.tau = cfg['tau']  # 软更新参数
    def sample_action(self, state):
        """
        作用:定义方法 sample_action,根据当前 actor 网络采样一个动作用于执行。
        """
        
        if isinstance(state, tuple):
            state = state[0]
        state = torch.FloatTensor(state).unsqueeze(0).to(self.device)
        action = self.actor(state)
        '''
        作用:
        - detach():切断计算图,防止梯度传播;
        - cpu():将张量移动到 CPU;
        - numpy():转换为 NumPy 数组;
        - [0, 0]:取第一行第一列的数值,作为最终动作数值返回。
        '''
        return action.detach().cpu().numpy()[0, 0]
    @torch.no_grad()
    def predict_action(self, state):
        ''' 用于预测,不需要计算梯度
        '''
        if isinstance(state, tuple):
            state = state[0]
        state = torch.FloatTensor(state).unsqueeze(0).to(self.device)
        action = self.actor(state)
        return action.cpu().numpy()[0, 0]
    def update(self):
        if len(self.memory) < self.batch_size: # 当memory中不满足一个批量时,不更新策略
            return
        # 从经验回放中中随机采样一个批量的transition
        state, action, reward, next_state, done = self.memory.sample(self.batch_size)
        # 转变为张量
        processed_state = []
        for s in state:
            if isinstance(s, tuple):
                # 如果元素是元组,则取元组的第一个元素
                processed_state.append(s[0])
            else:
                processed_state.append(s)

        state = torch.FloatTensor(np.array(processed_state)).to(self.device)
        next_state = torch.FloatTensor(np.array(next_state)).to(self.device)
        action = torch.FloatTensor(np.array(action)).to(self.device)
        reward = torch.FloatTensor(reward).unsqueeze(1).to(self.device)
        done = torch.FloatTensor(np.float32(done)).unsqueeze(1).to(self.device)
        # 注意看伪代码,这里的actor损失就是对应策略即actor输出的action下对应critic值的负均值
        '''
        计算当前状态下,通过 actor 网络得到的动作,再传入 critic 网络评估其价值;
        得到的输出是每个状态-动作对的 Q 值。
        '''
        actor_loss = self.critic(state, self.actor(state))
        actor_loss = - actor_loss.mean()

        next_action = self.target_actor(next_state)
        target_value = self.target_critic(next_state, next_action.detach())
        # 这里的expected_value就是伪代码中间的y_i  
        expected_value = reward + (1.0 - done) * self.gamma * target_value
        expected_value = torch.clamp(expected_value, -np.inf, np.inf)

        actual_value = self.critic(state, action)
        critic_loss = nn.MSELoss()(actual_value, expected_value.detach())
        
        self.actor_optimizer.zero_grad()
        actor_loss.backward()
        self.actor_optimizer.step()
        self.critic_optimizer.zero_grad()
        critic_loss.backward()
        self.critic_optimizer.step()
        # 各自目标网络的参数软更新
        '''作用:遍历目标 critic 网络与在线 critic 网络的每一对参数,准备进行软更新。'''
        for target_param, param in zip(self.target_critic.parameters(), self.critic.parameters()):
            '''new_target = (1−τ) × old_target + τ × current_parameter'''
            target_param.data.copy_(
                target_param.data * (1.0 - self.tau) +
                param.data * self.tau
            )
        '''作用:同样遍历目标 actor 与在线 actor 的参数对。'''
        for target_param, param in zip(self.target_actor.parameters(), self.actor.parameters()):
            '''new_target = (1−τ) × old_target + τ × current_parameter'''
            target_param.data.copy_(
                target_param.data * (1.0 - self.tau) +
                param.data * self.tau
            )  
    
    
'''
2. 定义训练
注意测试函数中不需要动作噪声
'''    
class OUNoise(object):
    '''Ornstein–Uhlenbeck噪声
    文档字符串说明该类用于生成 Ornstein–Uhlenbeck 噪声,这种噪声常用于连续控制任务中的动作探索。
    '''
    def __init__(self, action_space, mu=0.0, theta=0.15, max_sigma=0.3, min_sigma=0.3, decay_period=100000):
        """
        action_space:环境的动作空间对象。它包含两个关键属性:
        action_space.shape:例如假设动作空间是 1 维,则 action_space.shape[0] 为 1。
        action_space.low 与 action_space.high:分别表示动作的下界和上界(如低=-1,高=1)。
        """
        '''作用:将均值参数保存到实例属性中。'''
        self.mu           = mu # OU噪声的参数
        '''作用:保存 theta 参数,控制噪声回归到均值的速度。'''
        self.theta        = theta # OU噪声的参数
        '''作用:初始 sigma(噪声标准差)设置为 max_sigma。'''
        self.sigma        = max_sigma # OU噪声的参数
        '''作用:记录最大噪声标准差,用于后续衰减计算。'''
        self.max_sigma    = max_sigma
        '''作用:记录最小噪声标准差。'''
        self.min_sigma    = min_sigma
        '''作用:记录衰减周期,即在多少步内从 max_sigma 衰减到 min_sigma。'''
        self.decay_period = decay_period
        '''作用:从动作空间中获取动作数量(维度数),用于生成噪声向量。'''
        self.n_actions    = action_space.shape[0]
        '''作用:保存动作空间的下界,用于后续对噪声后的动作进行剪切。'''
        self.low          = action_space.low
        '''作用:保存动作空间的上界。'''
        self.high         = action_space.high
        '''作用:调用 reset 方法,初始化噪声状态(内部状态 obs)。'''
        self.reset()
    def reset(self):
        """
        作用:重置 OU 噪声的内部状态 obs。
        - 使用 np.ones(self.n_actions) 创建一个全 1 数组,长度等于动作数。
        - 乘以 mu,使得所有初始噪声均值为 mu。
        数值例子:若 n_actions=1 且 mu=0.0,则 np.ones(1) → [1.0],
                 乘以 0.0 得到 [0.0],因此 self.obs = [0.0].
        """
        self.obs = np.ones(self.n_actions) * self.mu
    def evolve_obs(self):
        """作用:将当前噪声状态赋给局部变量 x。"""
        x  = self.obs
        '''
        作用:计算噪声变化量 dx。公式解释:
        - self.theta * (self.mu - x):表示噪声向均值回归的部分;
        - self.sigma * np.random.randn(self.n_actions):表示随机部分,
          np.random.randn 生成标准正态分布的数值。
        数值例子:
        - 假设 self.mu=0.0,x = [0.0],self.theta=0.15,self.sigma=0.3;
        - np.random.randn(self.n_actions) 生成 [0.5](假设随机值为 0.5);
        - 则 dx = 0.15 * (0.0 - 0.0) + 0.3 * 0.5 = 0 + 0.15 = 0.15,即 dx = [0.15].
        '''
        dx = self.theta * (self.mu - x) + self.sigma * np.random.randn(self.n_actions)
        '''作用:更新内部状态 obs 为原始 x 加上变化 dx'''
        self.obs = x + dx
        return self.obs
    def get_action(self, action, t=0):
        """
        作用:定义 get_action 方法,用于给定一个原始动作,在其基础上添加 OU 噪声,并进行剪切。
        """
        '''作用:调用 evolve_obs 生成更新后的噪声向量 ou_obs。'''
        ou_obs = self.evolve_obs()
        '''
        作用:更新 sigma,使其随着时间步 t 逐渐衰减到 min_sigma。
        - 计算 t / self.decay_period,取最小值和 1.0,确保衰减比例不超过 1。
        - 用公式:sigma = max_sigma - (max_sigma - min_sigma) * (衰减比例)。
        数值例子:
        - 假设 max_sigma = 0.3,min_sigma = 0.3(此处两者相等,噪声不会衰减),
          t=50,decay_period=100000。
          - t / decay_period = 50/100000 = 0.0005,min(1.0, 0.0005)=0.0005,
          - sigma = 0.3 - (0.3 - 0.3) * 0.0005 = 0.3 - 0*0.0005 = 0.3。
        - 如果 min_sigma 与 max_sigma 不同(例如 max_sigma=0.3, min_sigma=0.1),
          那么当 t=50000 时,
          - t / decay_period = 50000/100000 = 0.5,
          - sigma = 0.3 - (0.3 - 0.1) * 0.5 = 0.3 - 0.2*0.5 = 0.3 - 0.1 = 0.2。
        '''
        self.sigma = self.max_sigma - (self.max_sigma - self.min_sigma) * min(1.0, t / self.decay_period) # sigma会逐渐衰减
        '''
        作用:
        - 将原始 action 加上噪声 ou_obs 得到扰动后的动作;
        - 使用 np.clip 将结果限制在动作空间的下界和上界之间,确保动作有效。
        '''
        return np.clip(action + ou_obs, self.low, self.high) # 动作加上噪声后进行剪切

def train(cfg, env, agent):
    """
    作用:定义 train 函数,接收配置字典 cfg、环境 env 和智能体 agent。实现训练过程。
    参数说明:
    - cfg:包含训练参数,如 'train_eps'(训练回合数)、'max_steps'(每回合最大步数)等。
    - env:Gym 环境实例。
    - agent:强化学习智能体,具有 sample_action、update 以及 memory 属性。
    """
    print("开始训练!")
    print("Using "+cfg['device']+"!")
    '''作用:利用环境的动作空间创建一个 OU 噪声对象,用于后续在动作上添加噪声。'''
    ou_noise = OUNoise(env.action_space)  # 动作噪声
    '''作用:初始化一个空列表,用于存储每个回合获得的累计奖励。'''
    rewards = [] # 记录所有回合的奖励
    for i_ep in range(cfg['train_eps']):
        state = env.reset()
        ou_noise.reset()
        ep_reward = 0
        for i_step in range(cfg['max_steps']):
            action = agent.sample_action(state)
            action = ou_noise.get_action(action, i_step+1) 
            result = env.step(action)
            if len(result) == 5:
                next_state, reward, done, truncated, info = result
                done = done or truncated  # 可合并 terminated 和 truncated 标志
            else:
                next_state, reward, done, info = result
            # next_state, reward, done, truncated, info = env.step(action)
            # next_state, reward, done, _ = env.step(action)
            ep_reward += reward
            agent.memory.push((state, action, reward, next_state, done))
            '''
            作用:调用 agent 的 update 方法,对智能体进行一次参数更新
                 (从经验回放中采样、计算损失、反向传播)。
            说明:此处每步更新,更新策略依赖于采样到的批量经验。
            '''
            agent.update()
            state = next_state
            if done:
                break
        if (i_ep+1)%10 == 0:
            print(f"回合:{i_ep+1}/{cfg['train_eps']},奖励:{ep_reward:.2f}")
        rewards.append(ep_reward)
    print("完成训练!")
    return {'rewards':rewards}
def test(cfg, env, agent):
    print("开始测试!")
    rewards = [] # 记录所有回合的奖励
    for i_ep in range(cfg['test_eps']):
        state = env.reset() 
        ep_reward = 0
        for i_step in range(cfg['max_steps']):
            action = agent.predict_action(state)
            result = env.step(action)
            if len(result) == 5:
                next_state, reward, done, truncated, info = result
                done = done or truncated  # 可合并 terminated 和 truncated 标志
            else:
                next_state, reward, done, info = result
            # next_state, reward, done, truncated, info = env.step(action)
            # next_state, reward, done, _ = env.step(action)
            ep_reward += reward
            state = next_state
            if done:
                break
        rewards.append(ep_reward)
        print(f"回合:{i_ep+1}/{cfg['test_eps']},奖励:{ep_reward:.2f}")
    print("完成测试!")
    return {'rewards':rewards}    
    
    
"""3. 定义环境"""
import gym
import os
import torch
import numpy as np
import random
class NormalizedActions(gym.ActionWrapper):
    ''' 将action范围重定在[0.1]之间
    '''
    """
    作用:定义一个继承自 gym.ActionWrapper 的类,用于对环境的动作进行包装,
         使其输出动作自动归一化到环境的动作范围内。
    说明:该包装器可以将神经网络输出(通常在 [-1, 1] 范围内)映射到环境实际允许的动作范围。
    """
    def action(self, action):
        """
        作用:重写 gym.ActionWrapper 中的 action 方法,用于将神经网络输出的动作进行转换。
        例子:输入参数 action 通常为一个在 [-1, 1] 范围内的数或数组,例如 0.5 或 [0.5].
        """
        low_bound   = self.action_space.low
        upper_bound = self.action_space.high
        '''
        作用:将原始动作(假设在 [-1, 1] 范围内)线性映射到 [low_bound, upper_bound] 范围内。公式说明:
        - 首先,action + 1.0 将区间 [-1, 1] 变为 [0, 2];
        - 乘以 0.5 后变为 [0, 1];
        - 再乘以 (upper_bound - low_bound) 得到 [0, upper_bound - low_bound];
        - 最后加上 low_bound 使区间变为 [low_bound, upper_bound]。
        数值例子:
        - 若 action = 0.5,low_bound = -2,upper_bound = 2,则:
          - action + 1.0 = 1.5;
          - 1.5 * 0.5 = 0.75;
          - (upper_bound - low_bound) = 4,所以 0.75 * 4 = 3;
          - 最后 action = -2 + 3 = 1。
        - 这样就将原始 0.5 映射到动作区间中的 1。
        '''
        action = low_bound + (action + 1.0) * 0.5 * (upper_bound - low_bound)
        '''
        作用:使用 np.clip 限制映射后的动作不超出环境的动作范围。
        例子:如果计算结果超过上界或低于下界,将被剪切。例如计算结果为 2.5,则 clip 后为 2;
                                                              若为 -2.5,则 clip 后为 -2。
        '''
        action = np.clip(action, low_bound, upper_bound)
        return action

    def reverse_action(self, action):
        """
        作用:重写 reverse_action 方法,用于将环境动作转换回包装器中原始动作空间。
             通常在一些算法中需要逆向转换(例如,回放数据时)。
        例子:输入 action 为环境动作,如 1.0,转换回 [-1, 1] 范围。
        """
        low_bound   = self.action_space.low
        upper_bound = self.action_space.high
        '''
        作用:执行逆向变换,将动作从 [low_bound, upper_bound] 映射回 [-1, 1]。公式解释:
        - 首先计算 (action - low_bound) / (upper_bound - low_bound),
          将 [low_bound, upper_bound] 映射为 [0, 1];
        - 乘以 2 得到 [0, 2],减去 1 则变成 [-1, 1]。
        数值例子:
        - 若 action = 1.0(环境动作),low_bound = -2,upper_bound = 2,则:
          - (1.0 - (-2)) = 3.0, (upper_bound - low_bound) = 4, 3.0/4 = 0.75;
          - 0.75 * 2 = 1.5, 1.5 - 1 = 0.5;
          - 得到逆向映射后的值为 0.5。
        '''
        action = 2 * (action - low_bound) / (upper_bound - low_bound) - 1
        '''
        作用:对逆向映射后的动作再做一次 clip(注意:这里 clip 范围仍用原始动作空间的边界,
             通常不改变结果,但可以保证数值稳定)。
        例子:如果计算结果异常,仍确保在 [low_bound, upper_bound] 内。
        '''
        action = np.clip(action, low_bound, upper_bound)
        return action
    
def all_seed(env,seed = 1):
    ''' 万能的seed函数
    '''
    if not hasattr(env, 'seed'):
        def seed_fn(self, seed=None):
            env.reset(seed=seed)
            return [seed]
        env.seed = seed_fn.__get__(env, type(env))
    # env.seed(seed) # env config
    np.random.seed(seed)
    random.seed(seed)
    torch.manual_seed(seed) # config for CPU
    torch.cuda.manual_seed(seed) # config for GPU
    os.environ['PYTHONHASHSEED'] = str(seed) # config for python scripts
    # config for cudnn
    torch.backends.cudnn.deterministic = True # 保证使用确定性算法;
    torch.backends.cudnn.benchmark = False    # 关闭 CuDNN 的自动优化搜索;
    torch.backends.cudnn.enabled = False      # 禁用 CuDNN,从而确保每次计算结果一致。
    
def env_agent_config(cfg):
    """
    作用:定义一个函数,用于根据配置 cfg 创建环境和智能体,并更新 cfg 中状态和动作维度信息。
    参数说明:cfg 是一个包含各种配置参数(例如环境名称、种子、隐藏层大小等)的字典。
    """
    '''
    作用:
    - 调用 gym.make(cfg['env_name']) 创建指定名称的环境;
    - 使用 NormalizedActions 包装该环境,使得动作输出被重新映射到环境允许的范围。
    '''
    env = NormalizedActions(gym.make(cfg['env_name'])) # 装饰action噪声
    if cfg['seed'] !=0:
        all_seed(env,seed=cfg['seed'])
    n_states = env.observation_space.shape[0]
    n_actions = env.action_space.shape[0]
    '''
    作用:将计算得到的 n_states 和 n_actions 更新到配置字典中,
         以便后续使用(例如构造网络时需要知道状态和动作维度)。
    数值例子:
    - 若 n_states=3, n_actions=1,则 cfg 中新增键值对 {"n_states": 3, "n_actions": 1}。
    '''
    cfg.update({"n_states":n_states,"n_actions":n_actions}) # 更新n_states和n_actions到cfg参数中
    '''
    作用:
    - 根据更新后的 n_states 和 n_actions 以及配置中指定的隐藏层大小,创建 Actor 和 Critic 模型;
    - 将两个模型放入一个字典 models 中,键分别为 "actor" 和 "critic"。
    '''
    models = {"actor":Actor(n_states,n_actions,hidden_dim=cfg['actor_hidden_dim']),
              "critic":Critic(n_states,n_actions,hidden_dim=cfg['critic_hidden_dim'])}
    '''
    作用:使用配置中给定的 memory_capacity 创建一个 ReplayBuffer 对象,并放入字典 memories 中,键为 "memory"。
    '''
    memories = {"memory":ReplayBuffer(cfg['memory_capacity'])}
    '''
    作用:利用上面创建的 models、memories 和配置 cfg 构造一个 DDPG 智能体实例。
    例子:agent 将封装 actor、critic 网络、目标网络、经验重放及相应的优化器等,便于后续训练和更新。
    '''
    agent = DDPG(models,memories,cfg)
    return env,agent   
    
    
"""4. 设置参数"""    
import argparse
import matplotlib.pyplot as plt
import seaborn as sns
def get_args():
    """ 超参数
    """
    parser = argparse.ArgumentParser(description="hyperparameters")      
    parser.add_argument('--algo_name',default='DDPG',type=str,help="name of algorithm")
    parser.add_argument('--env_name',default='Pendulum-v1',type=str,help="name of environment")
    parser.add_argument('--train_eps',default=300,type=int,help="episodes of training")
    parser.add_argument('--test_eps',default=20,type=int,help="episodes of testing")
    parser.add_argument('--max_steps',default=100000,type=int,help="steps per episode, much larger value can simulate infinite steps")
    parser.add_argument('--gamma',default=0.99,type=float,help="discounted factor")
    parser.add_argument('--critic_lr',default=1e-3,type=float,help="learning rate of critic")
    parser.add_argument('--actor_lr',default=1e-4,type=float,help="learning rate of actor")
    parser.add_argument('--memory_capacity',default=8000,type=int,help="memory capacity")
    parser.add_argument('--batch_size',default=128,type=int)
    parser.add_argument('--target_update',default=2,type=int)
    parser.add_argument('--tau',default=1e-2,type=float)
    parser.add_argument('--critic_hidden_dim',default=256,type=int)
    parser.add_argument('--actor_hidden_dim',default=256,type=int)
    parser.add_argument('--device',default='cuda',type=str,help=" or cuda")  
    parser.add_argument('--seed',default=1,type=int,help="random seed")
    args = parser.parse_args([])    
    args = {**vars(args)} # 将args转换为字典  
    # 打印参数
    print("训练参数如下:")
    print(''.join(['=']*80))
    tplt = "{:^20}\t{:^20}\t{:^20}"
    print(tplt.format("参数名","参数值","参数类型"))
    for k,v in args.items():
        print(tplt.format(k,v,str(type(v))))   
    print(''.join(['=']*80))                  
    return args
def smooth(data, weight=0.9):  
    '''用于平滑曲线,类似于Tensorboard中的smooth

    Args:
        data (List):输入数据
        weight (Float): 平滑权重,处于0-1之间,数值越高说明越平滑,一般取0.9

    Returns:
        smoothed (List): 平滑后的数据
    '''
    last = data[0]  # First value in the plot (first timestep)
    smoothed = list()
    for point in data:
        smoothed_val = last * weight + (1 - weight) * point  # 计算平滑值
        smoothed.append(smoothed_val)                    
        last = smoothed_val                                
    return smoothed

def plot_rewards(rewards,cfg,path=None,tag='train'):
    sns.set()
    plt.figure()  # 创建一个图形实例,方便同时多画几个图
    plt.title(f"{tag}ing curve on {cfg['device']} of {cfg['algo_name']} for {cfg['env_name']}")
    plt.xlabel('epsiodes')
    plt.plot(rewards, label='rewards')
    plt.plot(smooth(rewards), label='smoothed')
    plt.legend()   
    plt.show()
 
    
    
# 获取参数
cfg = get_args() 
# 训练
env, agent = env_agent_config(cfg)
res_dic = train(cfg, env, agent)
 
plot_rewards(res_dic['rewards'], cfg, tag="train")  
# 测试
res_dic = test(cfg, env, agent)
plot_rewards(res_dic['rewards'], cfg, tag="test")  # 画出结果  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值