00 - Getting Started¶
This notebook covers:
- Legal notice for the Atari ROM license
- Installation - Conda, pip, and Docker options
- Environment checks - verifying every package (including Atari) is working
- Gymnasium tutorial - the core API you will use in every subsequent notebook
Legal Notice - Atari ROM License¶
The Atari 2600 game ROMs used by the Arcade Learning Environment (ALE) are proprietary software owned by Atari, Inc.
They are distributed with ale-py under a limited, non-commercial research licence.
What the licence allows¶
- Academic research and personal study
- Non-commercial educational use (courses, tutorials, textbooks)
- Publication of results obtained with these environments
What the licence prohibits¶
- Commercial use, sale, or distribution of the ROMs themselves
- Shipping the ROMs as part of a commercial product without a separate Atari licence
- Any use outside the scope of research and education
Accepting the licence¶
When you install ale-py, the ROMs are bundled but require explicit acceptance of the licence terms.
Run the one-time command below (or pass --accept-license / install the helper package shown in the installation section):
# Accept the Atari ROM licence — required before first use
AutoROM --accept-license
Alternatively, install the convenience package that accepts the licence automatically:
pip install autorom[accept-rom-license]
Full licence text:
python -c "import ale_py; print(ale_py.__file__)"and look forROM_LICENCE.mdin the same directory, or visit the Farama ALE repository.
1. Packages¶
| Package | Purpose |
|---|---|
| PyTorch | Deep learning backend for neural-network policies |
| Gymnasium | Standard single-agent RL environment API |
| ale-py | Atari 2600 game environments (see legal notice above) |
| Pygame | Rendering backend used by many environments |
| PettingZoo | Multi-agent RL environments |
| Stable-Baselines3 | Production-quality single-agent RL algorithms |
| SB3-Contrib | Extra algorithms for Stable-Baselines3 (TQC, TRPO, MaskablePPO, …) |
| Ray RLlib | Scalable, distributed RL framework |
| MLflow | Experiment tracking, model registry, and run comparison |
| SuperSuit | Environment wrappers for PettingZoo + SB3 |
| Shimmy | Gymnasium compatibility shims |
| TensorBoard | Training metrics visualisation |
2. Installation¶
Choose one of the three options below. All three install the same set of packages.
Option A - Conda (recommended for local development)¶
The repository ships an environment.yml that pins channels and versions for reproducibility.
# Create and activate the environment (one-time setup)
conda env create -f environment.yml
conda activate rl-python
# Accept the Atari ROM licence (required once per environment)
AutoROM --accept-license
GPU support: open environment.yml, remove the cpuonly line, and add pytorch-cuda=12.1 (or whichever CUDA version matches your driver).
Option B - pip (virtualenv / system Python)¶
# Create a virtual environment (recommended)
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
# GPU only: install PyTorch with CUDA first, then the rest of the requirements
# pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121
pip install -r requirements.txt
# Accept the Atari ROM licence (required once per environment)
AutoROM --accept-license
# - or - install the licence-acceptance helper in one step:
# pip install autorom[accept-rom-license]
Option C - Docker (reproducible, isolated, no host dependencies)¶
The repository includes a Dockerfile that builds a self-contained CPU image.
# Build the image (run once; re-run after requirements.txt changes)
docker build -t rl-lab .
# Launch a Jupyter server inside the container
docker run --rm -it \
-p 8888:8888 \
-v "$(pwd)":/workspace \
rl-lab \
jupyter notebook --ip=0.0.0.0 --no-browser --allow-root
Then open the URL printed in the terminal (e.g. http://127.0.0.1:8888/...).
GPU inside Docker: swap the base image in
Dockerfileto
FROM pytorch/pytorch:2.3.0-cuda12.1-cudnn8-runtime
and add--gpus allto thedocker runcommand.
3. Installation Checks¶
Run every cell in this section. All checks should print OK. If any fail, follow the hint printed beneath the error.
import warnings
import ale_py
import cv2
import gymnasium as gym
import matplotlib.pyplot as plt
import minigrid
import mlflow
import numpy as np
import pettingzoo
import pygame
import ray
import sb3_contrib
import shimmy
import stable_baselines3
import supersuit
import tensorboard
import torch
import torchvision
from torch.utils.tensorboard import SummaryWriter
def pprint(statement, max_length=85):
fmt = int(0.5 * (max_length - len(statement)))
print(f"{'-'*fmt} {statement} {'-'*fmt}\n")
pprint("All imports successful!")
------------------------------- All imports successful! -------------------------------
Check if CUDA or MPS enables PyTorch is Installed
# Check if CUDA/MPS are available
if torch.cuda.is_available():
pprint("CUDA is available.")
elif torch.backends.mps.is_available():
pprint("MPS is available.")
else:
pprint("CUDA/MPS are not available.")
----------------------------- CUDA/MPS are not available. -----------------------------
Test Gymnasium Environments
env_warning_flag = False
# Classic control environments
try:
env = gym.make("CartPole-v1")
obs, _ = env.reset()
env.close()
except Exception as e:
raise RuntimeError("Error installing Gymnasium.") from e
# ALE environments
try:
gym.register_envs(ale_py)
env = gym.make("ALE/Breakout-v5")
obs, _ = env.reset()
env.close()
except Exception:
env_warning_flag = True
warnings.warn("ALE environments are not installed.")
# MuJoco environments
try:
env = gym.make("Reacher-v5")
obs, _ = env.reset()
env.close()
except Exception:
env_warning_flag = True
warnings.warn("MuJoco environments are not installed.")
# Box2D environments
try:
env = gym.make("CarRacing-v3")
obs, _ = env.reset()
env.close()
except Exception:
env_warning_flag = True
warnings.warn("Box2D environments are not installed.")
# MiniGrid environments
try:
env = gym.make("MiniGrid-Empty-Random-5x5-v0")
obs, _ = env.reset()
env.close()
except Exception:
env_warning_flag = True
warnings.warn("MiniGrid environments are not installed.")
if not env_warning_flag:
pprint("All environments are working correctly!")
----------------------- All environments are working correctly! -----------------------
A.L.E: Arcade Learning Environment (version 0.11.2+ecc1138) [Powered by Stella]
4. Gymnasium Tutorial¶
Every algorithm in this repository interacts with environments through the Gymnasium API. This section walks through the core API using FrozenLake-v1 - a small grid world where an agent must cross a frozen lake without falling into holes.
S = start
F = frozen (safe)
H = hole (episode ends, reward = 0)
G = goal (episode ends, reward = 1)
FrozenLake is a good first environment because:
- Both observation and action spaces are
Discrete- easy to inspect and reason about - Episodes are short, so feedback is fast
is_slippery=True(default) makes the dynamics stochastic - the agent does not always move in the intended direction
4.1 Creating an environment¶
gym.make(id, render_mode=None) is the single entry point for every environment.
render_mode |
Effect |
|---|---|
None (default) |
No rendering - fastest, use for training |
"human" |
Opens a window - use for interactive demos |
"ansi" |
Returns a text string - useful for grid worlds in notebooks |
"rgb_array" |
Returns pixel arrays - use for video recording |
import gymnasium as gym
import matplotlib.pyplot as plt
from IPython import display
env = gym.make("FrozenLake-v1", is_slippery=True, render_mode="rgb_array")
print("Environment:", env.spec.id)
print()
print("Observation space:", env.observation_space)
print("n (grid cells):", env.observation_space.n)
print("Interpretation: integer 0-15 representing position on the 4x4 grid")
print()
print("Action space:", env.action_space)
print("n (actions):", env.action_space.n)
print("Meanings: 0 = left, 1 = down, 2 = right, 3 = up")
Environment: FrozenLake-v1 Observation space: Discrete(16) n (grid cells): 16 Interpretation: integer 0-15 representing position on the 4x4 grid Action space: Discrete(4) n (actions): 4 Meanings: 0 = left, 1 = down, 2 = right, 3 = up
4.2 Resetting an episode¶
Call env.reset(seed=...) at the start of every episode.
Pass a seed to make episodes reproducible.
For FrozenLake the initial observation is always 0 (top-left cell), but seeding matters for the stochastic slip dynamics.
obs, info = env.reset(seed=42)
print(f"Initial observation (grid cell index): {obs}")
frame = env.render()
plt.imshow(frame)
plt.axis('off')
Initial observation (grid cell index): 0
(np.float64(-0.5), np.float64(255.5), np.float64(255.5), np.float64(-0.5))
4.3 The step loop¶
obs, reward, terminated, truncated, info = env.step(action)
done = terminated or truncated
| Return value | Type | Meaning |
|---|---|---|
obs |
int | New grid cell index (0–15) |
reward |
float | 1.0 if goal reached, 0.0 otherwise |
terminated |
bool | True when the agent reaches the goal or falls in a hole |
truncated |
bool | True when the episode time limit is hit |
info |
dict | {"prob": p} — transition probability of the step that was taken |
Note on
is_slippery: when slip is enabled,info["prob"]is often1/3— the agent only moves in the intended direction with probability 1/3.
It is also good practice to close the environment as it is important when external software is used.
def display_env(env):
frame = env.render()
plt.imshow(frame)
plt.axis("off")
plt.show()
obs, info = env.reset(seed=0)
print("Step-by-step episode (first 6 steps shown)\n")
display_env(env)
for step in range(6):
action = env.action_space.sample()
action_name = ["left", "down", "right", "up"][action]
obs, reward, terminated, truncated, info = env.step(action)
print(f"Step {step + 1}: action={action_name}, cell={obs}, reward={reward}, "
f"terminated={terminated}, prob={info['prob']:.2f}")
display_env(env)
if terminated or truncated:
print("Episode over.")
break
env.close()
Step-by-step episode (first 6 steps shown)
Step 1: action=up, cell=1, reward=0, terminated=False, prob=0.33
Step 2: action=up, cell=2, reward=0, terminated=False, prob=0.33
Step 3: action=right, cell=6, reward=0, terminated=False, prob=0.33
Step 4: action=up, cell=5, reward=0, terminated=True, prob=0.33
Episode over.
4.4 Slippery vs deterministic¶
By default FrozenLake is stochastic (is_slippery=True). Comparing the two variants illustrates how environment dynamics affect a random policy's success rate.
def run_episodes(env, n=1000):
"""Return the fraction of episodes that reached the goal."""
successes = 0
for ep in range(n):
obs, _ = env.reset(seed=ep)
done = False
while not done:
obs, reward, terminated, truncated, _ = env.step(env.action_space.sample())
done = terminated or truncated
if reward == 1.0:
successes += 1
return successes / n
slippery = gym.make("FrozenLake-v1", is_slippery=True)
deterministic = gym.make("FrozenLake-v1", is_slippery=False)
slip_rate = run_episodes(slippery)
det_rate = run_episodes(deterministic)
slippery.close()
deterministic.close()
print(f"Random policy success rate - slippery: {slip_rate:.1%}")
print(f"Random policy success rate - deterministic: {det_rate:.1%}")
Random policy success rate - slippery: 1.5% Random policy success rate - deterministic: 1.2%