Skip to main content

Alberta Framework

CI PyPI License Python 3.13+ DOI

Warning: This framework is under active research development. The API is unstable and subject to breaking changes between releases. It is not intended for production use.

A JAX-based research framework implementing components of The Alberta Plan for AI Research in the pursuit of building the foundations of Continual AI.

"The agents are complex only because they interact with a complex world... their initial design is as simple, general, and scalable as possible." — Sutton et al., 2022

Overview

The Alberta Framework provides foundational components for continual reinforcement learning research. Built on JAX for hardware acceleration, the framework emphasizes temporal uniformity every component updates at every time step, with no special training phases or batch processing.

Project Context

This framework is developed as part of my D.Eng. work focusing on the foundations of online, continuious Reinforcement Learning (RL). For more background and context see:

Roadmap

Depending on my research trajectory I may or may not implement components required for the Alberta Plan. The current focus of this framework is the Step 1 Baseline Study, investigating the interaction between adaptive optimizers and online normalization.

Step Focus Status
1 Meta-learned step-sizes (IDBD, Autostep) Complete
2 Nonlinear function approximation (MLP, ObGD) In Progress
3 GVF predictions, Horde architecture Planned
4 Actor-critic with eligibility traces Planned
5-6 Off-policy learning, average reward Planned
7-12 Hierarchical, multi-agent, world models Future

Installation

pip install alberta-framework

# With optional dependencies
pip install alberta-framework[gymnasium]  # RL environment support
pip install alberta-framework[dev]        # Development (pytest, ruff)

Requirements: Python >= 3.13, JAX >= 0.4, NumPy >= 2.0

Quick Start

import jax.random as jr
from alberta_framework import (
    LinearLearner, MLPLearner, LMS, IDBD, Autostep,
    ObGDBounding, AGCBounding, EMANormalizer, WelfordNormalizer,
    RandomWalkStream, run_learning_loop, run_mlp_learning_loop,
)

stream = RandomWalkStream(feature_dim=10, drift_rate=0.001)

# --- Optimizers ---

# Fixed step-size baseline
learner = LinearLearner(optimizer=LMS(step_size=0.01))

# IDBD: per-weight adaptive step-sizes via gradient correlation (Sutton, 1992)
learner = LinearLearner(optimizer=IDBD())

# Autostep: tuning-free adaptation with gradient normalization (Mahmood et al., 2012)
learner = LinearLearner(optimizer=Autostep())

# --- Adding a Normalizer ---

# EMA normalization for non-stationary feature scales
learner = LinearLearner(optimizer=IDBD(), normalizer=EMANormalizer(decay=0.99))

# Welford normalization for stationary distributions
learner = LinearLearner(optimizer=Autostep(), normalizer=WelfordNormalizer())

# --- Adding a Bounder ---

# ObGD bounding prevents overshooting (Elsayed et al., 2024)
learner = LinearLearner(optimizer=Autostep(), bounder=ObGDBounding(kappa=2.0))

# --- MLP Learner ---

# MLP with Autostep + ObGD bounding + normalization
mlp = MLPLearner(
    hidden_sizes=(128, 128),
    optimizer=Autostep(),
    bounder=ObGDBounding(kappa=2.0),
    normalizer=EMANormalizer(decay=0.99),
)

# MLP with AGC bounding — per-unit clipping scaled by weight norm (Brock et al., 2021)
mlp = MLPLearner(
    hidden_sizes=(128, 128),
    optimizer=Autostep(),
    bounder=AGCBounding(clip_factor=0.01),
)

# --- Training ---

# Linear: JIT-compiled training via jax.lax.scan
state, metrics = run_learning_loop(learner, stream, num_steps=10000, key=jr.key(42))

# MLP: same interface
state, metrics = run_mlp_learning_loop(mlp, stream, num_steps=10000, key=jr.key(42))

Core Components

Composable Architecture

Learners accept three independent, composable concerns:

  • Optimizer — per-weight step-size adaptation (LMS, IDBD, Autostep)
  • Bounder — optional global update bounding (ObGDBounding)
  • Normalizer — optional online feature normalization (EMANormalizer, WelfordNormalizer)
from alberta_framework import (
    LinearLearner, MLPLearner, Autostep, ObGDBounding, AGCBounding, EMANormalizer
)

# Linear learner with Autostep + normalization
learner = LinearLearner(
    optimizer=Autostep(),
    normalizer=EMANormalizer(decay=0.99),
)

# MLP with Autostep + ObGD bounding + normalization
mlp = MLPLearner(
    hidden_sizes=(128, 128),
    optimizer=Autostep(),
    bounder=ObGDBounding(kappa=2.0),
    normalizer=EMANormalizer(decay=0.99),
)

# MLP with AGC bounding (per-unit clipping scaled by weight norm)
mlp_agc = MLPLearner(
    hidden_sizes=(128, 128),
    optimizer=Autostep(),
    bounder=AGCBounding(clip_factor=0.01),
    normalizer=EMANormalizer(decay=0.99),
)

Optimizers

Supervised Learning:

  • LMS: Fixed step-size baseline
  • IDBD: Per-weight adaptive step-sizes via gradient correlation (Sutton, 1992). MLP support via Meyer's adaptation — replaces x² with (∂y/∂w)² in the h-decay term (Meyer)
  • Autostep: Tuning-free adaptation with gradient normalization (Mahmood et al., 2012)

TD Learning:

  • TDIDBD: TD learning with per-weight adaptive step-sizes and eligibility traces (Kearney et al., 2019)
  • AutoTDIDBD: TD learning with AutoStep-style normalization for improved stability

Bounders

  • ObGDBounding: Dynamic update bounding to prevent overshooting (Elsayed et al., 2024). Decoupled from the optimizer so it can be composed with any optimizer.
  • AGCBounding: Adaptive Gradient Clipping — per-unit clipping scaled by weight norm (Brock et al., 2021). Finer-grained than ObGD's global scaling.

Normalizers

Online feature normalization for handling varying feature scales:

  • EMANormalizer: Exponential moving average — suitable for non-stationary distributions
  • WelfordNormalizer: Welford's algorithm with Bessel's correction — suitable for stationary distributions

MLP Learner

Multi-layer perceptron for nonlinear function approximation (Elsayed et al., 2024):

from alberta_framework import MLPLearner, ObGDBounding, RandomWalkStream, run_mlp_learning_loop
import jax.random as jr

stream = RandomWalkStream(feature_dim=10)
learner = MLPLearner(
    hidden_sizes=(128, 128),
    step_size=1.0,
    bounder=ObGDBounding(kappa=2.0),
    sparsity=0.9,
)
state, metrics = run_mlp_learning_loop(learner, stream, num_steps=10000, key=jr.key(42))

Streams

Non-stationary experience generators implementing the ScanStream protocol:

  • RandomWalkStream: Gradual target drift
  • AbruptChangeStream: Sudden target switches
  • PeriodicChangeStream: Sinusoidal oscillation
  • DynamicScaleShiftStream: Time-varying feature scales
  • ScaleDriftStream: Continuous feature scale drift

TD Learning

For temporal-difference learning with value function approximation:

from alberta_framework import TDLinearLearner, TDIDBD, run_td_learning_loop

learner = TDLinearLearner(optimizer=TDIDBD(trace_decay=0.9))
state, metrics = run_td_learning_loop(learner, td_stream, num_steps=10000, key=jr.key(42))

Gymnasium Integration

from alberta_framework.streams.gymnasium import collect_trajectory, learn_from_trajectory, PredictionMode
import gymnasium as gym

env = gym.make("CartPole-v1")
observations, targets = collect_trajectory(env, policy, num_steps=10000, mode=PredictionMode.REWARD)
state, metrics = learn_from_trajectory(learner, observations, targets)

Publication Tools

Multi-seed experiments with statistical analysis and publication-ready outputs:

from alberta_framework.utils import ExperimentConfig, run_multi_seed_experiment, pairwise_comparisons

results = run_multi_seed_experiment(configs, seeds=30, parallel=True)
significance = pairwise_comparisons(results, test="ttest", correction="bonferroni")

Documentation

Full documentation available at j-klawson.github.io/alberta-framework or build locally:

pip install alberta-framework[docs]
mkdocs serve  # http://localhost:8000

Contributing

Contributions are welcome, particularly for upcoming roadmap steps. Please ensure tests pass and follow the existing code style.

pytest tests/ -v

Citation

If you use this framework in your research, please cite:

@software{alberta_framework,
  title = {Alberta Framework: A JAX Implementation of Alberta Plan components},
  author = {Lawson, Keith},
  year = {2026},
  url = {https://github.com/j-klawson/alberta-framework},
  doi = {10.5281/zenodo.18814470}
}

Key References

@article{sutton2022alberta,
  title = {The Alberta Plan for AI Research},
  author = {Sutton, Richard S. and Bowling, Michael and Pilarski, Patrick M.},
  year = {2022},
  eprint = {2208.11173},
  archivePrefix = {arXiv}
}

@inproceedings{sutton1992idbd,
  title = {Adapting Bias by Gradient Descent: An Incremental Version of Delta-Bar-Delta},
  author = {Sutton, Richard S.},
  booktitle = {Proceedings of the AAAI Conference on Artificial Intelligence},
  year = {1992}
}

@software{meyer2025idbdmlp,
  title = {IDBD for MLPs: Adapting Per-Weight Step-Sizes in Deep Networks},
  author = {Meyer, Edan},
  year = {2025},
  url = {https://github.com/ejmejm/phd_research/blob/main/phd/jax_core/optimizers/idbd.py},
  note = {Generalizes Sutton 1992 IDBD to nonlinear models by replacing x² with (∂y/∂w)² in the h-decay term}
}

@inproceedings{mahmood2012autostep,
  title = {Tuning-free Step-size Adaptation},
  author = {Mahmood, A. Rupam and Sutton, Richard S. and Degris, Thomas and Pilarski, Patrick M.},
  booktitle = {IEEE International Conference on Acoustics, Speech and Signal Processing},
  year = {2012}
}

@inproceedings{kearney2019tidbd,
  title = {Learning Feature Relevance Through Step Size Adaptation in Temporal-Difference Learning},
  author = {Kearney, Alex and Veeriah, Vivek and Travnik, Jaden and Sutton, Richard S. and Pilarski, Patrick M.},
  booktitle = {International Conference on Machine Learning},
  year = {2019}
}

@article{brock2021high,
  title = {High-Performance Large-Scale Image Recognition Without Normalization},
  author = {Brock, Andrew and De, Soham and Smith, Samuel L. and Simonyan, Karen},
  journal = {arXiv preprint arXiv:2102.06171},
  year = {2021}
}

@article{elsayed2024streaming,
  title = {Streaming Deep Reinforcement Learning Finally Works},
  author = {Elsayed, Mohamed and Lan, Gautham and Lim, Shuze and Mahmood, A. Rupam},
  journal = {arXiv preprint arXiv:2410.14606},
  year = {2024}
}

License

Apache License 2.0

Metadata

Release files for alberta-framework 0.17.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for alberta-framework 0.17.1
File Size Uploaded Provenance
alberta_framework-0.17.1.tar.gz 218.3 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for alberta-framework 0.17.1
File Interpreter ABI Platform
alberta_framework-0.17.1-py3-none-any.whl Python 3 none any Details

Total release size: 321.7 kB

Release files / alberta_framework-0.17.1.tar.gz

Download URL alberta_framework-0.17.1.tar.gz
Size 218.3 kB
Tags Source
SHA-256 checksum
How to use checksums
ec8f354037ce08da964d8af0a17d4ddf0c157561fdf4116315613552995524f1
BLAKE2b-256 checksum
How to use checksums
1dd46fa24d02605055e529d623917ef771228e4fb0a0e62fc100f5169e6cee3b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 17, 2026.

Transparency log

Release files / alberta_framework-0.17.1-py3-none-any.whl

Download URL alberta_framework-0.17.1-py3-none-any.whl
Size 103.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b548dd3abe76fc3ed0ab78ec30cd3f292baa7509dd504db6602921319bf06d7f
BLAKE2b-256 checksum
How to use checksums
b92cfa1252f8024de1097947df64761f00b7d5ac8ed173c06a2081d822f7dbc2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 17, 2026.

Transparency log

Security for alberta-framework 0.17.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for alberta_framework-0.17.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 17, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

0.17.1 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page