🧩Modular Design
Why Modularity Matters
Deep RL research requires comparing algorithms fairly. If two implementations differ in subtle ways beyond the algorithm itself—network initialization, gradient clipping, learning rate schedules—performance differences become meaningless.
SLM Lab solves this with modular design: algorithms share the same base code, networks, memory, and training loops. When you compare PPO to A2C in SLM Lab, the only differences are the algorithmic ones.
Benefits:
Fair comparison
Algorithms share base classes; only algorithmic differences matter
Code reuse
New algorithms inherit tested components
Fewer bugs
Less code to review and maintain
Easy extension
Add new algorithms by overriding specific methods
Core Components
SLM Lab is built around three base classes:
Agent
├── Algorithm Handles interaction with env, computes loss, runs training
│ └── Net Neural network function approximator
└── Memory Data storage and retrieval for training
Algorithm
Implements the RL algorithm logic:
Action selection (exploration vs exploitation)
Loss computation (policy loss, value loss)
Training step (gradient updates)
Key methods:
Memory
Handles experience storage:
Store transitions
(s, a, r, s', done)Sample batches for training
Signal when it's time to train
Types:
Replay- Off-policy ring bufferPrioritizedReplay- Priority-based samplingOnPolicyBatchReplay- On-policy with fixed batch size
Net
Neural network architectures:
Configurable hidden layers and activations
Automatic input/output sizing
Optimizer and scheduler management
Types:
MLPNet- Fully connected layersConvNet- Convolutional + fully connectedRecurrentNet- LSTM/GRU for sequences
Inheritance in Action
Consider how algorithms are related:
PPO inherits from ActorCritic and only overrides:
init_algorithm_params()- Add PPO-specific hyperparametersinit_nets()- Add old_net for ratio computationcalc_policy_loss()- Implement clipped surrogate objectivetrain()- Multi-epoch minibatch training
Everything else—value function computation, advantage estimation, network initialization—is inherited from ActorCritic.
Result: PPO is ~280 lines of code instead of thousands for a standalone implementation.
See Class Inheritance: A2C > PPO for the detailed walkthrough.
Composability
Components can be mixed and matched via the spec file:
Example compositions:
DQN + Replay + MLPNet
Standard DQN
DoubleDQN + PrioritizedReplay + MLPNet
DDQN+PER
DQN + Replay + RecurrentNet
DRQN (recurrent DQN)
PPO + OnPolicyBatchReplay + ConvNet
PPO for Atari
Why This Design?
Henderson et al. (2017) showed that implementation details dramatically affect RL results. Two "correct" implementations of the same algorithm can have vastly different performance due to:
Random seed selection
Network initialization
Hyperparameter defaults
Gradient clipping values
Frame preprocessing
SLM Lab addresses this by:
Shared base code - Algorithms inherit common functionality
Explicit configuration - All hyperparameters in spec files
Reproducibility - Spec + git SHA fully defines an experiment
Benchmarking - Validated implementations with published results
Extending SLM Lab
To add a new algorithm:
Then register in slm_lab/agent/algorithm/__init__.py and create a spec file.
Further Reading
Algorithm Taxonomy - Visual overview of algorithm relationships
Class Inheritance: A2C > PPO - Detailed code comparison
Architecture - Full system design
Last updated
Was this helpful?