在Python中使用RolloutStorage()进行多步状态回放的实践
在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类的初始化函数中,创建了存储不同数据的张量。其中,obs、rewards、value_preds、returns、action_log_probs和masks都是大小为(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()方法,删除旧的数据,并保留最新的数据。
