Count-Based Exploration
Instead of exploring randomly, count-based exploration tracks how often states are visited and pays the agent an intrinsic bonus to venture into unfamiliar territory.
Why Does This Exist?
In sparse-reward reinforcement learning problems—such as navigating a labyrinth, solving Montezuma's Revenge, or discovering a robotic manipulation strategy—an agent relying solely on dithering strategies like -greedy or Gaussian action noise faces an exponential sample complexity. Because extrinsic rewards are zero almost everywhere, random motor twitching has a negligible probability of discovering the goal sequence.
In finite tabular Markov Decision Processes, the principle of Optimism in the Face of Uncertainty (OFU) solves this through Upper Confidence Bound (UCB) bonuses: states visited fewer times receive an intrinsic exploration incentive proportional to , driving the agent systematically toward unvisited states.
However, classic visitation counting breaks catastrophically in continuous or high-dimensional state spaces (e.g., Atari pixel frames or continuous robot joint configurations). Because raw pixel observations or floating-point vectors are never revisited identically twice, the empirical visitation count is trivially for every encountered state. Without a generalization mechanism, standard tabular count-based methods collapse. Count-based exploration with pseudo-counts and locality-sensitive hashing exists to extend tabular exploration guarantees to high-dimensional and continuous domains by deriving generalized visitation frequencies from density models or spatial projections.
Think of It Like This
The National Park Passport Stamp Book
Imagine an avid hiker exploring a sprawling national park system with a passport stamp book. Every time the hiker visits a ranger station for the first time, they receive an ink stamp in their book and feel a rush of novelty—earning high personal satisfaction (a large intrinsic reward). If they linger around the park entrance station and collect that same stamp 100 times, the thrill disappears entirely because the marginal novelty drops with each visit. The incentive to re-stamp decays inversely with the square root of visits: .
Now imagine the hiker treks into the untamed backcountry where there are no pre-built ranger stations or official stamps. Every campsite has slightly different fallen leaves, wind patterns, and twilight shadows, so no two coordinates are pixel-for-pixel identical. If the hiker treated every distinct leaf arrangement as a brand-new region, they would pitch their tent in the same valley forever, claiming infinite novelty.
Instead, the hiker pulls out a topographical map and a pocket camera (a density model). When they photograph a new valley, their visual memory model updates: "I have seen landscapes like this before." If the model's subjective probability of this terrain shifts by a noticeable margin, the hiker deduces: "This terrain has a low cumulative pseudo-count; I should explore it." As the hiker traverses more valleys of that type, the model becomes saturated, pseudo-counts climb, and the hiker is nudged deeper into unexplored mountain ranges.
Where the analogy stops: In real life, staring at shifting clouds or ripples on a stream feels relaxing, but an unconstrained visual density model might mistake turbulent cloud noise for endless geographic novelty (the "noisy TV" trap), allocating excessive pseudo-counts to irrelevant background entropy.
How It Actually Works
Tabular Count Bonuses to High-Dimensional Pseudo-Counts
In tabular environments, an agent maintains an exact state-action or state visitation counter . The total augmented reward presented to the reinforcement learning algorithm is:
where the intrinsic exploration bonus is governed by:
Here, controls the exploration strength, and prevents division by zero. By the upper confidence bound principle (e.g., in MBIE-EB or UCB1), this bonus ensures the agent seeks out states whose value estimates carry high epistemic uncertainty.
To scale this to continuous state spaces , Bellemare et al. (2016) introduced the pseudo-count derived from a sequential density model . Let denote the predictive probability of observing state given a history of states , and let denote the updated predictive probability after recording an additional observation of .
Under an idealized empirical count model with total steps , observing state with empirical count yields:
Solving this system of linear equations for the unknown state count and total pseudo-sample size produces the pseudo-count and pseudo-gain :
Whenever the density model is learning-positive (meaning observing strictly increases its future probability, ), the pseudo-count is well-defined and acts as a surrogate visitation frequency. The intrinsic reward bonus is then:
Locality-Sensitive Hashing (SimHash)
An alternative, computationally efficient approach to pseudo-counts in continuous state spaces is Locality-Sensitive Hashing (LSH) (Tang et al., 2017). A continuous state embedding is mapped to a discrete -bit hash code via a random projection matrix with entries drawn i.i.d. from :
Angular proximity between states is preserved: if two states are close in Euclidean space, the probability of them colliding into the exact same hash code is proportional to . The algorithm maintains a hash table of discrete bucket counts , updating:
Worked numerical example
Consider an agent exploring a 2D continuous environment evaluated with a predictive density model. We set exploration scale and smoothing constant .
Step 1: First exposure to state
- Before the observation, the density model assigns prior probability .
- After conditioning on observing , the updated density increases to .
- Compute the pseudo-count :
- Compute the intrinsic exploration bonus:
- If the environment returns zero external reward (), the augmented reward is .
Step 2: Re-visitation after multiple exposures
- After repeated passes through that corridor, the state has become familiar. The prior probability has risen to .
- A further observation yields updated density .
- Re-compute the pseudo-count :
- Compute the new intrinsic reward bonus:
- Notice the decay ratio:
The novelty bonus drops by , motivating the policy to allocate attention to other regions whose pseudo-counts remain near zero.
Code
Below is a complete, self-contained implementation demonstrating both Bellemare pseudo-count derivation and SimHash-based count exploration for continuous states.
from typing import Dict, Tuple, Unionimport numpy as np
class BellemarePseudoCount: """Computes high-dimensional pseudo-counts from sequential density estimates."""
def __init__(self, beta: float = 1.0, epsilon_smooth: float = 0.01) -> None: self.beta = beta self.epsilon_smooth = epsilon_smooth
def compute_pseudo_count(self, rho: float, rho_prime: float) -> float: """Computes pseudo-count N_hat given prior and posterior densities.
Formula: N_hat = rho * (1 - rho_prime) / (rho_prime - rho) """ diff = rho_prime - rho if diff <= 1e-12: # If the model didn't gain confidence, novelty is treated as very high return 0.0 n_hat = (rho * (1.0 - rho_prime)) / diff return max(0.0, float(n_hat))
def compute_bonus(self, n_hat: float) -> float: """Calculates exploration bonus: r_int = beta / sqrt(N_hat + c).""" bonus = self.beta / np.sqrt(n_hat + self.epsilon_smooth) return float(bonus)
class SimHashExploration: """Locality-Sensitive Hashing (SimHash) for continuous state count bonuses."""
def __init__( self, state_dim: int, hash_bits: int = 16, beta: float = 1.0, seed: int = 42, ) -> None: self.state_dim = state_dim self.hash_bits = hash_bits self.beta = beta rng = np.random.default_rng(seed) # Random hyperplanes drawn from standard Gaussian: (k, d) self.projection_matrix = rng.standard_normal((hash_bits, state_dim)) # Hash table recording visitation frequency per binary code self.counts: Dict[Tuple[int, ...], int] = {}
def hash_state(self, state: np.ndarray) -> Tuple[int, ...]: """Projects continuous state vector into discrete binary hash code.""" projected = self.projection_matrix @ state binary_code = tuple((projected >= 0).astype(int).tolist()) return binary_code
def step(self, state: np.ndarray) -> Tuple[float, int]: """Records state visitation, updates counter, and returns (bonus, count).""" code = self.hash_state(state) current_count = self.counts.get(code, 0) + 1 self.counts[code] = current_count bonus = self.beta / np.sqrt(current_count) return float(bonus), current_count
if __name__ == "__main__": # --- 1. Bellemare Pseudo-Count Verification --- bellemare = BellemarePseudoCount(beta=1.0, epsilon_smooth=0.01)
# Step 1: Initial exposure (rho = 0.05 -> rho' = 0.06) n_hat_1 = bellemare.compute_pseudo_count(rho=0.05, rho_prime=0.06) bonus_1 = bellemare.compute_bonus(n_hat_1) print(f"Observation 1 -> N_hat: {n_hat_1:.2f}, Bonus: {bonus_1:.4f}") assert np.isclose(n_hat_1, 4.70), f"Expected 4.70, got {n_hat_1}" assert np.isclose(bonus_1, 0.4608, atol=1e-4), f"Expected 0.4608, got {bonus_1}"
# Step 2: Familiar state (rho = 0.10 -> rho' = 0.11) n_hat_2 = bellemare.compute_pseudo_count(rho=0.10, rho_prime=0.11) bonus_2 = bellemare.compute_bonus(n_hat_2) print(f"Observation 2 -> N_hat: {n_hat_2:.2f}, Bonus: {bonus_2:.4f}") assert np.isclose(n_hat_2, 8.90), f"Expected 8.90, got {n_hat_2}" assert np.isclose(bonus_2, 0.3350, atol=1e-4), f"Expected 0.3350, got {bonus_2}"
# Decay ratio verification decay = bonus_2 / bonus_1 print(f"Bonus Decay Factor: {decay:.4f}") assert np.isclose(decay, 0.7270, atol=1e-3), f"Expected ~0.7270, got {decay}"
# --- 2. SimHash Continuous State Exploration --- simhash = SimHashExploration(state_dim=4, hash_bits=8, beta=1.0, seed=1337)
# State A (e.g. spawn zone) visited multiple times state_a = np.array([0.5, -0.2, 1.1, -0.8]) bonus_a1, count_a1 = simhash.step(state_a) bonus_a2, count_a2 = simhash.step(state_a) bonus_a3, count_a3 = simhash.step(state_a)
print(f"State A visit 1 -> Count: {count_a1}, Bonus: {bonus_a1:.4f}") print(f"State A visit 2 -> Count: {count_a2}, Bonus: {bonus_a2:.4f}") print(f"State A visit 3 -> Count: {count_a3}, Bonus: {bonus_a3:.4f}")
# State B (novel distant zone) visited for the first time state_b = np.array([-1.8, 2.4, -0.5, 3.1]) bonus_b1, count_b1 = simhash.step(state_b) print(f"State B visit 1 -> Count: {count_b1}, Bonus: {bonus_b1:.4f}")
assert count_a3 == 3 assert bonus_a3 == 1.0 / np.sqrt(3.0) assert count_b1 == 1 assert bonus_b1 == 1.0 # Novel state receives maximum exploration incentive print("All count-based exploration assertions passed successfully!")Observation 1 -> N_hat: 4.70, Bonus: 0.4608Observation 2 -> N_hat: 8.90, Bonus: 0.3350Bonus Decay Factor: 0.7270State A visit 1 -> Count: 1, Bonus: 1.0000State A visit 2 -> Count: 2, Bonus: 0.7071State A visit 3 -> Count: 3, Bonus: 0.5774State B visit 1 -> Count: 1, Bonus: 1.0000All count-based exploration assertions passed successfully!Watch Out For
The Noisy TV Problem and Background Pixel Dominance
When using raw sensory inputs (like RGB camera feeds or Atari frames), generative density models (such as PixelCNN or CTS) model every pixel joint distribution. If the environment contains unpredictable, task-irrelevant stochasticity—such as TV static, moving cloud patterns, or tree leaves rustling—the density model persistently experiences prediction error and density shifts.
Because pure white noise can never be memorized, the model continually updates probabilities with every new frame of static, keeping artificially high or fluctuating. The agent interprets the screen noise as a bottomless reservoir of novelty and permanently freezes in front of the television, ignoring the actual game objectives.
To eliminate this failure mode, never compute density models or SimHash projections directly on raw pixel inputs. Instead, project raw states into compact latent representations that only encode agent-controllable factors—such as features trained via inverse dynamics models (as in the Intrinsic Curiosity Module) or fixed random network distillation (RND).
The Quick Version
- Extending tabular bounds: Count-based exploration generalizes the tabular upper confidence bound bonus to continuous high-dimensional spaces where exact states are never visited twice.
- Pseudo-counts from density models: Bellemare's pseudo-count deduces effective visitation counts from the change in predictive probability assigned by a density model before and after observing the state.
- Locality-Sensitive Hashing (SimHash): Random hyperplanes project continuous state vectors into discrete bit vectors , allowing standard hash-table counting over angularly similar geometric clusters.
- Bonus decay and extinction: Intrinsic rewards naturally decay as unfamiliar states become familiar, eventually allowing extrinsic task rewards to dominate the agent's long-term value function.
- Representation sensitivity: Applying pseudo-counts directly to raw pixels causes agents to become trapped by environmental noise (the "noisy TV" trap); learned or invariant latent embeddings are required in visually complex domains.