engineportf's picture
Upload folder using huggingface_hub
558db1e verified
Raw
History Blame Contribute Delete
2.38 kB
import numpy as np
import torch
import random
from typing import Dict, List, Tuple
class ReplayBuffer:
"""
A simple sequence replay buffer for Dreamer training.
Expects episodes of shape (seq_len, dim) to be added.
"""
def __init__(self, capacity: int = 10000, seq_len: int = 50):
self.capacity = capacity
self.seq_len = seq_len
self.episodes = []
def add_episode(self, obs: np.ndarray, actions: np.ndarray, rewards: np.ndarray):
"""
obs: (time, obs_dim)
actions: (time, action_dim)
rewards: (time,)
"""
if len(self.episodes) >= self.capacity:
self.episodes.pop(0)
self.episodes.append({
'obs': obs,
'actions': actions,
'rewards': rewards
})
def sample_batch(self, batch_size: int) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
"""
Samples a batch of sequence chunks.
Returns tensors of shape (batch, seq_len, dim)
"""
if len(self.episodes) == 0:
raise ValueError("Replay buffer is empty.")
obs_batch, action_batch, reward_batch = [], [], []
for _ in range(batch_size):
ep_idx = random.randint(0, len(self.episodes) - 1)
ep = self.episodes[ep_idx]
ep_len = len(ep['obs'])
if ep_len <= self.seq_len:
start = 0
pad_len = self.seq_len - ep_len
obs = np.pad(ep['obs'], ((0, pad_len), (0, 0)), mode='edge')
acts = np.pad(ep['actions'], ((0, pad_len), (0, 0)), mode='edge')
rews = np.pad(ep['rewards'], (0, pad_len), mode='constant', constant_values=0)
else:
start = random.randint(0, ep_len - self.seq_len)
obs = ep['obs'][start:start + self.seq_len]
acts = ep['actions'][start:start + self.seq_len]
rews = ep['rewards'][start:start + self.seq_len]
obs_batch.append(obs)
action_batch.append(acts)
reward_batch.append(rews)
return (
torch.FloatTensor(np.stack(obs_batch)),
torch.FloatTensor(np.stack(action_batch)),
torch.FloatTensor(np.stack(reward_batch))
)