Implementing Reinforcement Learning with OpenAI Gym in PyTorch: A Complete Guide
You can implement reinforcement learning in PyTorch by creating a policy network that maps environment states to action probabilities, then training it with the REINFORCE algorithm using experience collected from OpenAI Gym environments.
The microsoft/AI-For-Beginners curriculum provides a production-ready implementation of deep reinforcement learning through a complete PyTorch example. This guide explains implementing reinforcement learning with OpenAI Gym in PyTorch using the repository’s CartPole-RL-PyTorch.ipynb notebook, which demonstrates policy gradient methods for training autonomous agents.
Core Architecture Components
The implementation follows the standard actor-critic pattern where a neural network acts as the policy function, directly learning action probabilities from raw environment states.
Policy Network Design
The solution uses a simple feed-forward architecture defined in torch.nn.Module. According to the source code in lessons/6-Other/22-DeepRL/CartPole-RL-PyTorch.ipynb, the network consists of two fully-connected layers with ReLU activation. The forward pass accepts observation vectors and returns raw logits for each possible action, which are then converted to probabilities using torch.softmax.
Environment Interface
While the notebook imports gymnasium (the maintained successor to OpenAI Gym), the API remains fully compatible with standard Gym environments. The code initializes environments using gym.make() and processes the standard five-tuple return (state, reward, terminated, truncated, info) from each env.step() call.
The REINFORCE Training Loop
The policy gradient method updates network weights based on the likelihood of actions that resulted in high cumulative rewards.
Experience Collection
During each episode, the agent samples actions from a categorical distribution created via torch.distributions.Categorical(probs). The code stores log_prob tensors and received rewards in separate lists until the episode terminates or truncates. This separation allows the algorithm to compute returns retrospectively after the complete trajectory is observed.
Policy Gradient Update
The algorithm computes discounted returns using the formula $G_t = r_t + \gamma G_{t+1}$, then applies the REINFORCE loss: -(log_prob * return).mean(). This loss is backpropagated through the network and optimized using torch.optim.Adam with a configurable learning rate (referenced as alpha in the curriculum).
Complete Implementation Example
Below is a minimal, self-contained script that mirrors the repository’s approach. This implementation works with any Gym-compatible environment by adjusting the obs_dim and act_dim variables.
import gymnasium as gym
import torch
import torch.nn as nn
import torch.optim as optim
# ---------- 1. Define the policy network ----------
class PolicyNet(nn.Module):
def __init__(self, obs_dim, act_dim):
super().__init__()
self.net = nn.Sequential(
nn.Linear(obs_dim, 128),
nn.ReLU(),
nn.Linear(128, act_dim),
)
def forward(self, x):
return self.net(x)
# ---------- 2. Hyper-parameters ----------
env_name = "CartPole-v1" # replace with any Gym env
num_episodes = 500
gamma = 0.99 # discount factor
learning_rate = 1e-3
# ---------- 3. Initialise environment & policy ----------
env = gym.make(env_name)
obs_dim = env.observation_space.shape[0]
act_dim = env.action_space.n
policy = PolicyNet(obs_dim, act_dim)
optimizer = optim.Adam(policy.parameters(), lr=learning_rate)
# ---------- 4. REINFORCE training loop ----------
for episode in range(num_episodes):
state, _ = env.reset()
log_probs = []
rewards = []
done = False
while not done:
state_tensor = torch.from_numpy(state).float()
logits = policy(state_tensor)
probs = torch.softmax(logits, dim=-1)
action_dist = torch.distributions.Categorical(probs)
action = action_dist.sample()
log_probs.append(action_dist.log_prob(action))
state, reward, terminated, truncated, _ = env.step(action.item())
done = terminated or truncated
rewards.append(reward)
# Compute discounted returns
returns = []
G = 0.0
for r in reversed(rewards):
G = r + gamma * G
returns.insert(0, G)
returns = torch.tensor(returns)
# Policy gradient update
loss = -(torch.stack(log_probs) * returns).mean()
optimizer.zero_grad()
loss.backward()
optimizer.step()
if (episode + 1) % 50 == 0:
total_reward = sum(rewards)
print(f"Episode {episode+1:3d} – Return: {total_reward:.1f}")
print("Training complete!")
Adapting to Custom Gym Environments
You can apply this same pattern to any Gym-compatible environment by following these modifications:
-
Install dependencies: Ensure
gymnasium(orgym) andtorchare listed in yourenvironment.ymlorrequirements.txtas shown in the repository root files. -
Adjust dimensions: Modify
obs_dimto matchenv.observation_space.shape[0]andact_dimto matchenv.action_space.nfor discrete environments. -
Handle continuous spaces: For continuous action spaces, replace the
Categoricaldistribution withtorch.distributions.Normaland adjust the network output to predict mean and standard deviation parameters.
Key Files in the Repository
Understanding the codebase structure helps when extending the implementation:
-
lessons/6-Other/22-DeepRL/CartPole-RL-PyTorch.ipynb: The full Jupyter notebook containing the complete REINFORCE implementation with visualization code. -
environment.yml: Conda environment definition specifying Python 3.11, PyTorch, andgymnasiumdependencies. -
requirements.txt: Root-level dependency list for the entire curriculum. -
examples/README.md: Quick-start guide for running Python scripts within the repository framework.
Summary
-
The microsoft/AI-For-Beginners repository provides a complete REINFORCE implementation in
CartPole-RL-PyTorch.ipynbusing PyTorch and Gymnasium. -
The architecture requires only a simple two-layer network, a categorical distribution for sampling, and the policy gradient loss
-(log_prob * return).mean(). -
Training involves collecting full episodes before computing discounted returns and performing optimizer steps with
torch.optim.Adam. -
The same code structure works for any Gym environment by adjusting observation dimensions and action space configurations.
Frequently Asked Questions
Does this implementation work with the original OpenAI Gym or only Gymnasium?
The code works with both. The repository uses gymnasium (the maintained fork of OpenAI Gym), but the API is identical. You can replace import gymnasium as gym with import gym if using the original package, though Gymnasium is recommended for bug fixes and continued support.
What hyperparameters should I tune for more complex environments?
Start by adjusting the learning rate (typically between 1e-4 and 1e-2 for Adam) and the discount factor gamma (usually 0.95 to 0.99). For high-dimensional state spaces, increase the hidden layer size beyond 128 units or add additional layers, ensuring you modify the PolicyNet class architecture accordingly.
How do I know if my policy is converging?
Monitor the episode return (sum of rewards) as shown in the logging code. In the CartPole environment, convergence is typically indicated when the return reaches 500 (the maximum episode length) consistently across multiple consecutive episodes. For other environments, look for a stable upward trend in the rolling average return over 100 episodes.
Can I use this code for continuous action spaces like MuJoCo environments?
No, not without modification. The provided PolicyNet outputs discrete action probabilities using Categorical. For continuous actions, you must change the network to output mean and log-standard-deviation parameters, then use torch.distributions.Normal for sampling. The REINFORCE loss formula remains the same, but you will backpropagate through the Gaussian log probabilities instead.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →