EasyReinforcement Learning

Replay Buffer Sample

Reinforcement Learning

Easy

Problem

A replay buffer (or experience replay memory) stores past transitions that an agent has experienced. During training, a random batch of transitions is sampled from the buffer to break temporal correlations and stabilize learning. This technique is used in DQN, SAC, DDPG, and many other off-policy algorithms.

Given a buffer of transitions, a batch size, and a random seed, sample a batch of transitions uniformly at random without replacement.

Algorithm

  1. Set the random seed for reproducibility

  2. Sample batch_size transitions from the buffer uniformly at random without replacement

Return the sampled transitions as a list ordered by ascending sampled index.

Theory

A replay buffer (also called experience replay memory) is a data structure that stores past experiences and allows random sampling for training.

Instead of learning from experiences in the order they occur, the agent samples random minibatches from the buffer. This technique dramatically improves learning stability and efficiency.

Introduced in the context of Deep Q-Networks (DQN) by Mnih et al. (2013).


Why Experience Replay?

Training neural networks with reinforcement learning faces several challenges:

1. Correlated data:

Consecutive experiences are highly correlated (same region of state space). Neural networks learn poorly from correlated data.

2. Non-stationary distribution:

As the policy improves, the data distribution changes. This can cause catastrophic forgetting.

3. Sample inefficiency:

Each experience is used only once and then discarded.

Experience replay addresses all three issues.


How It Works

1. Store: After each transition (s, a, r, s', \text{done}), add it to the buffer.

2. Sample: When training, randomly sample a minibatch of transitions from the buffer.

3. Learn: Update the neural network using the sampled minibatch.

4. Manage: When the buffer is full, remove old experiences (typically FIFO).


The Transition Tuple

Each experience stored in the buffer is a tuple:

(s_t, a_t, r_{t+1}, s_{t+1}, \text{done})

Components:

This is all the information needed for a TD update.


Buffer Operations

Initialization:

Push (store):

Sample:

Size:


Uniform Random Sampling

The simplest approach samples each transition with equal probability:

P(\text{select transition } i) = \frac{1}{|\text{buffer}|}

Process:

  1. Generate B random indices from [0, |\text{buffer}| - 1]
  2. Retrieve transitions at those indices
  3. Return as minibatch

Properties:


Worked Example: Sampling

Buffer contents (capacity 5):

Position 0: (s_1, a_1, r_1, s_2, \text{False})

Position 1: (s_2, a_2, r_2, s_3, \text{False})

Position 2: (s_3, a_3, r_3, s_4, \text{False})

Position 3: (s_4, a_4, r_4, s_5, \text{True})

Position 4: (s_5, a_5, r_5, s_6, \text{False})

Sample batch of size 3:

Random indices: [2, 0, 4]

Returned batch:


Buffer Size Considerations

Small buffer (e.g., 10,000):

Large buffer (e.g., 1,000,000):

Typical values: 100,000 to 1,000,000 transitions

DQN uses 1 million transitions.


Circular Buffer Implementation

The most common implementation uses a circular (ring) buffer:

Variables:

Push operation:

  1. Store transition at write pointer position
  2. Increment write pointer: \text{ptr} = (\text{ptr} + 1) \mod N
  3. Update size: \text{size} = \min(\text{size} + 1, N)

Properties:


Breaking Correlation

Without replay, consecutive samples are correlated:

(s_1, a_1, r_1, s_2), (s_2, a_2, r_2, s_3), (s_3, a_3, r_3, s_4), ...

State s_2 appears as both "next state" and "current state" in adjacent samples.

With replay: Random sampling decorrelates the data:

(s_{47}, a_{47}, r_{47}, s_{48}), (s_{12}, a_{12}, r_{12}, s_{13}), (s_{89}, a_{89}, r_{89}, s_{90}), ...

This is similar to i.i.d. sampling assumption in supervised learning.


Data Efficiency

Without replay, each experience is used once:

Updates per experience: 1

With replay, each experience can be sampled multiple times:

Updates per experience: Many (until removed from buffer)

This dramatically improves sample efficiency, especially important when environment interactions are expensive.


Prioritized Experience Replay

Not all experiences are equally valuable for learning. Prioritized replay samples important transitions more frequently.

Priority: Often based on TD error magnitude:

p_i = |\delta_i| + \epsilon

where \delta_i is the TD error for transition i.

Sampling probability:

P(i) = \frac{p_i^\alpha}{\sum_k p_k^\alpha}

\alpha controls how much prioritization affects sampling (0 = uniform, 1 = full prioritization).


Importance Sampling Correction

Prioritized sampling introduces bias. To correct:

w_i = \left(\frac{1}{N \cdot P(i)}\right)^\beta

where \beta is annealed from 0 to 1 during training.

The loss is weighted:

L = \frac{1}{B}\sum_{i=1}^{B} w_i \cdot (y_i - Q(s_i, a_i))^2


When to Start Learning

The buffer should have enough diverse experiences before training begins:

Warm-up period:

Typical values: 10,000 to 50,000 initial transitions

This ensures the first minibatches are reasonably diverse.


Update Frequency

Every step: Update network after each new transition

Every N steps: Update after N transitions

DQN approach:


Replay Buffer for Different Algorithms

DQN:

DDPG (continuous actions):

SAC:

PPO (on-policy):


Memory Considerations

State representation matters:

If states are images (84x84x4 = 28,224 floats):

Optimizations:


Handling Episode Boundaries

When sampling transitions across episode boundaries:

Terminal transitions: (s, a, r, s', \text{done}=\text{True})

The next state s' is meaningless (episode ended). During training:

\text{target} = r \quad \text{(not } r + \gamma \max_a Q(s', a) \text{)}

The done flag tells us not to bootstrap from the next state.


Advantages of Experience Replay

1. Data efficiency: Reuse experiences multiple times

2. Decorrelation: Random sampling breaks temporal correlation

3. Stability: Diverse minibatches stabilize neural network training

4. Off-policy learning: Can learn from old policy experiences


Disadvantages and Limitations

1. Memory usage: Large buffers require significant RAM

2. Stale data: Old experiences may be from very different policies

3. On-policy incompatibility: Does not work with purely on-policy methods

4. Delayed learning: Cannot learn immediately from new experiences


Variations and Extensions

Hindsight Experience Replay (HER):

Combined Experience Replay (CER):

Distributed Replay:

Examples

Example 1

Input
buffer = [[0, 0, 1, 1, 0], [1, 1, 0.5, 2, 0], [2, 0, -1, 3, 1], [3, 1, 2, 4, 0], [4, 0, 0, 0, 1]], batch_size = 3, seed = 42
Output
[[1, 1, 0.5, 2, 0], [2, 0, -1, 3, 1], [4, 0, 0, 0, 1]]
Explanation
The seeded NumPy generator selects three distinct indices, which are sorted before retrieving transitions.

Example 2

Input
buffer = [[0, 0, 1, 1, 0], [1, 1, 0.5, 2, 0], [2, 0, -1, 3, 1], [3, 1, 2, 4, 0], [4, 0, 0, 0, 1]], batch_size = 1, seed = 7
Output
[[0, 0, 1, 1, 0]]

Hints

  1. Create a local generator with np.random.RandomState(seed).
  2. Choose indices without replacement, sort them, and retrieve those buffer entries.

Requirements

Constraints

Starter Code

import numpy as np

def replay_buffer_sample(buffer: list, batch_size: int, seed: int) -> list:
    """
    Returns a deterministic sample of transitions.
    """
    # Write code here
    pass

Test Cases

CaseMatches
batch3public
batch1public