欢迎访问宙启技术站
智能推送

在Python中使用RolloutStorage()进行多步状态回放的实践

发布时间:2024-01-02 15:54:37

在PyTorch中,可以使用RolloutStorage类来实现多步状态回放。Rollout是一种在强化学习中常用的技术,用于存储并更新多个时间步骤的数据。

首先,导入所需的库:

import torch
from torch.distributions import Categorical

接下来,定义RolloutStorage类,并初始化相应的变量:

class RolloutStorage:
    def __init__(self, num_steps, num_processes, obs_shape, action_space):
        self.num_steps = num_steps
        self.num_processes = num_processes
        self.obs_shape = obs_shape
        self.action_space = action_space

        self.obs = torch.zeros(num_steps + 1, num_processes, *obs_shape)
        self.rewards = torch.zeros(num_steps, num_processes, 1)
        self.value_preds = torch.zeros(num_steps + 1, num_processes, 1)
        self.returns = torch.zeros(num_steps + 1, num_processes, 1)
        self.action_log_probs = torch.zeros(num_steps, num_processes, 1)
        self.actions = torch.zeros(num_steps, num_processes, 1).long()
        self.masks = torch.ones(num_steps + 1, num_processes, 1)

        self.recurrent_hidden_states = torch.zeros(num_steps + 1, num_processes, 1)
        self.recurrent_hidden_states = self.recurrent_hidden_states.view(-1, *self.recurrent_hidden_states.size())

- num_steps:定义每个序列的时间步长。

- num_processes:指定要并行运行的过程数量。

- obs_shape:表示观测空间的形状。

- action_space:表示动作空间。

在RolloutStorage类的初始化函数中,创建了存储不同数据的张量。其中,obsrewardsvalue_predsreturnsaction_log_probsmasks都是大小为(num_steps + 1) x num_processes x shape的张量,用于存储状态、奖励、预测值、回报、动作概率和掩码的数据。actions是一个大小为num_steps x num_processes x 1的张量,用于存储动作数据。recurrent_hidden_states是一个大小为(num_steps + 1) x num_processes x 1的张量,用于存储递归的隐藏状态。

接下来,定义一个insert()方法,用于插入一个时间步的数据:

    def insert(self, step, obs, recurrent_hidden_states, action, action_log_prob,
               value_pred, reward, mask):
        self.obs[step + 1].copy_(obs)
        self.recurrent_hidden_states[step + 1].copy_(recurrent_hidden_states)
        self.actions[step].copy_(action)
        self.action_log_probs[step].copy_(action_log_prob)
        self.value_preds[step].copy_(value_pred)
        self.rewards[step].copy_(reward)
        self.masks[step + 1].copy_(mask)

在插入数据时,通过copy_()方法将数据复制到对应的张量中。

然后,定义一个compute_returns()方法,用于计算回报值:

    def compute_returns(self, next_value, use_gae, gamma, tau):
        if use_gae:
            self.value_preds[-1] = next_value
            gae = 0
            for step in reversed(range(self.rewards.size(0))):
                delta = self.rewards[step] + gamma * self.value_preds[step + 1] * self.masks[step + 1] - self.value_preds[step]
                gae = delta + gamma * tau * self.masks[step + 1] * gae
                self.returns[step] = gae + self.value_preds[step]
        else:
            self.returns[-1] = next_value
            for step in reversed(range(self.rewards.size(0))):
                self.returns[step] = self.returns[step + 1] * gamma * self.masks[step + 1] + self.rewards[step]

根据使用的Generalized Advantage Estimation(GAE)的方法,该方法计算回报值。其中,next_value是最后一个时间步的值,use_gae表示是否使用GAE,gamma表示折扣因子,tau表示GAE的权重。

最后,定义一个after_update()方法,用于删除旧的数据,并保留最新的数据:

    def after_update(self):
        self.obs[0].copy_(self.obs[-1])
        self.recurrent_hidden_states[0].copy_(self.recurrent_hidden_states[-1])
        self.masks[0].copy_(self.masks[-1])

这样,就可以实现在训练过程中对RolloutStorage进行多步状态回放。

以下是RolloutStorage的使用示例:

import gym

env = gym.make('CartPole-v1')
obs = env.reset()

num_steps = 10
num_processes = 1
obs_shape = env.observation_space.shape
action_space = env.action_space

rollouts = RolloutStorage(num_steps, num_processes, obs_shape, action_space)

for step in range(num_steps):
    with torch.no_grad():
        value = model.get_value(obs)
        action, action_log_prob, recurrent_hidden_state = model.act(obs)

    next_obs, reward, done, _ = env.step(action.item())

    mask = torch.FloatTensor([[0.0] if done else [1.0]])
    
    rollouts.insert(step, obs, recurrent_hidden_state, action, action_log_prob, value, reward, mask)

    obs = next_obs

with torch.no_grad():
    next_value = model.get_value(obs)

rollouts.compute_returns(next_value, True, 0.99, 0.95)

model.update(rollouts)
rollouts.after_update()

上述代码中,首先创建一个环境并获取初始观测值。然后,定义了一些训练的参数,并初始化了RolloutStorage对象。在每个时间步中,通过模型选择一个动作,并执行该动作,获得下一个观测值、奖励以及done标志。然后,将这些数据插入到RolloutStorage中,并更新当前观测值。在所有时间步完成后,使用最后一个观测值计算回报值,并调用模型的更新函数进行参数更新。最后,通过调用rollouts.after_update()方法,删除旧的数据,并保留最新的数据。