Fast Python 3.14 wheels for stable-retro RL workloads
Project description
Fast Python 3.14 wheels for stable-retro RL workloads
stable-retro-turbo publishes installable macOS Apple Silicon and Linux wheels for the upstream stable-retro API surface.
Use it when you want stable_retro game environments without building the package and bundled public libretro cores from source yourself.
What changed from upstream
This fork keeps the upstream stable_retro API and adds a small set of
RL-throughput features:
- Python
3.14wheels for macOSarm64and Linuxx86_64. - Bundled Game Boy, NES, SNES, and Genesis/Master System public cores.
- Worker-local crop, resize, grayscale, frame skip, frame stack, max-pool, no-op reset, sticky actions, and reward clipping.
- Native C++ screen processing and fused
step_repeat_and_process(). StableRetroSubprocVecEnvshared-memory observations to reduce IPC copying.STABLE_RETRO_DISABLE_AUDIO=1for RGB-only agents.scripts/benchmark_vec_env.pyfor baseline versus optimized throughput runs.
In local Mario benchmarks using SuperMarioBros-Nes-v0, the optimized path was
materially faster than the baseline Python/SB3 vector setup. The best measured
direct-ROM 8-env run was about 9,756 steps/s versus about 4,076 steps/s for
the baseline, roughly 2.39x faster. Broader sweeps showed fused native
preprocessing helping most as env count rises, while true multi-env-per-process
batching is still blocked by stable-retro's current one-emulator-instance-per-process
native frontend.
Install
python -m pip install stable-retro-turbo
Use it from Python:
import stable_retro as retro
env = retro.make("Alleyway-GameBoy-v0", render_mode="rgb_array")
RL preprocessing and SB3
For reinforcement-learning loops, image preprocessing can be done inside each
environment worker before observations are returned to the caller. This is useful
with SubprocVecEnv, where sending smaller observations across process
boundaries can be much faster than returning full-size RGB frames and resizing
later. This is the main speedup this fork adds over the upstream wrapper stack.
import stable_retro as retro
env = retro.make(
"SuperMarioBros-Nes-v0",
render_mode="rgb_array",
obs_resize=(84, 84),
obs_resize_algorithm="nearest", # nearest, bilinear, or area
obs_grayscale=True,
)
Available image kwargs:
obs_resize=(height, width): resize image observations before they leave the env.obs_resize_algorithm="nearest": choosenearest,bilinear, orarea;nearestis fastest, whileareais downscale-only and does more averaging work.obs_grayscale=True: return grayscale observations with shape(height, width, 1).obs_crop=(top, bottom, left, right): crop pixels before grayscale and resize.frame_skip=4: repeat each selected action inside the worker and sum rewards.frame_stack=4: stack recent observations inside the worker before IPC.maxpool_last_two=True: max-pool the last two skipped image frames.noop_reset_max=30: apply a random number of no-op reset steps.sticky_action_prob=0.25: probabilistically repeat the previous action.reward_clip=True: clip rewards to[-1, 1].
Pass the same options through Stable-Baselines3 with env_kwargs:
from stable_baselines3.common.env_util import make_vec_env
from stable_baselines3.common.vec_env import SubprocVecEnv, VecTransposeImage
def make_mario_env(**kwargs):
return retro.make(
"SuperMarioBros-Nes-v0",
render_mode="rgb_array",
**kwargs,
)
env = make_vec_env(
make_mario_env,
n_envs=8,
vec_env_cls=SubprocVecEnv,
vec_env_kwargs={"start_method": "spawn"},
env_kwargs={
"obs_resize": (84, 84),
"obs_resize_algorithm": "nearest",
"obs_grayscale": True,
},
)
env = VecTransposeImage(env) # (n_envs, 1, 84, 84) for grayscale
For lower IPC overhead than SubprocVecEnv, use the shared-memory vector env:
from stable_retro import StableRetroSubprocVecEnv
env = StableRetroSubprocVecEnv([make_mario_env for _ in range(8)])
The shared-memory vector env keeps observations in a parent-owned shared buffer, so workers only send rewards, done flags, and infos through pipes on each step. For Atari-style image rollouts this pairs well with env-local preprocessing and fused native frame skipping:
env = StableRetroSubprocVecEnv(
[
lambda: retro.make(
"SuperMarioBros-Nes-v0",
render_mode="rgb_array",
obs_resize=(84, 84),
obs_grayscale=True,
frame_skip=4,
frame_stack=4,
maxpool_last_two=True,
)
for _ in range(16)
],
)
When possible, image preprocessing and repeated-step processing use native C++
helpers instead of Python image loops. The native path is selected automatically
for single-player image observations with no rotation or movie recording. Set
STABLE_RETRO_DISABLE_NATIVE_IMAGEOPS=1 or
STABLE_RETRO_DISABLE_NATIVE_FUSED_STEP=1 to force the Python fallback while
debugging or benchmarking.
StableRetroChunkedSubprocVecEnv is also available as an experimental generic
Gymnasium vector env that puts multiple envs in each worker process:
from stable_retro import StableRetroChunkedSubprocVecEnv
env = StableRetroChunkedSubprocVecEnv(env_fns, chunk_size=4)
This is useful for envs that support multiple instances per process. Current
native stable-retro emulator instances do not: the C++ libretro frontend has
one active emulator/core callback target per process, so stable-retro games must
still use one emulator process per env. For stable-retro games, prefer
StableRetroSubprocVecEnv until the native frontend is refactored for true
multi-instance execution.
If your agent does not use audio, set STABLE_RETRO_DISABLE_AUDIO=1 before
creating environments. This keeps RGB observations enabled while skipping audio
capture and supported core-side audio generation.
The deprecated compatibility import still works:
import retro
For local development:
git clone https://github.com/tsilva/stable-retro-turbo.git
cd stable-retro-turbo
brew install cmake pkg-config lua@5.4 libzip
python -m pip install -U pip build cibuildwheel pytest pre-commit
python -m pip install -e .
Commands
python -m pip install stable-retro-turbo # install the published package
python -m pip install -e . # build and install this checkout
python -m build --wheel # build a local wheel
python -m cibuildwheel . --output-dir wheelhouse # build release-style wheels
pytest # run Python tests
pre-commit run --all-files # run repository hooks
cmake . && make -j2 && make -j2 -f tests/Makefile && ctest --progress --verbose
python scripts/benchmark_vec_env.py --game SuperMarioBros-Nes-v0 --num-envs 8
Notes
- Published wheels target Apple Silicon
arm64on macOS14.0+andx86_64on Linux, for Python3.14. - Package versions follow the upstream
stable-retrobase version with this fork's patch number as a PEP 440 post-release suffix, for example1.0.0.post1. - The public wheel build includes Game Boy, NES, SNES, and Sega Master System cores:
gambatte,fceumm,snes9x, andgenesis_plus_gx. - CapnProto is disabled in the public wheel build path.
- SNES on Apple Silicon uses an automatic Rosetta helper because the native arm64
snes9xpath is not stable across the bundled integrations. - If Rosetta is not installed yet, install it once:
softwareupdate --install-rosetta --agree-to-license
- Release automation builds macOS arm64 and Linux x86_64 wheels, publishes them to PyPI, and attaches matching wheel files to GitHub Releases.
- See
PUBLISHING.mdfor the release checklist. - Upstream API and integration docs are still useful:
docs/supported_emulators.md,docs/supported_games.md, anddocs/macos_installation.md.
Architecture
License
MIT. Bundled third-party notices are listed in LICENSES.md.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file stable_retro_turbo-1.0.0.post1-cp314-cp314-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl.
File metadata
- Download URL: stable_retro_turbo-1.0.0.post1-cp314-cp314-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl
- Upload date:
- Size: 103.0 MB
- Tags: CPython 3.14, manylinux: glibc 2.26+ x86-64, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b7c08343059bb9eabc836123f5447c7c3b818cee0e4ba6848d81aa55f71f23e3
|
|
| MD5 |
47f371fa1eb4176c9a8e672b75ff87f9
|
|
| BLAKE2b-256 |
4aec95521e015b91676f4971ac316611d2729c8d2d8e4414351c09c63619cf12
|
Provenance
The following attestation bundles were made for stable_retro_turbo-1.0.0.post1-cp314-cp314-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl:
Publisher:
release.yml on tsilva/stable-retro-turbo
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
stable_retro_turbo-1.0.0.post1-cp314-cp314-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl -
Subject digest:
b7c08343059bb9eabc836123f5447c7c3b818cee0e4ba6848d81aa55f71f23e3 - Sigstore transparency entry: 1808196182
- Sigstore integration time:
-
Permalink:
tsilva/stable-retro-turbo@c3b3c6aa441e1d96780539977a2ccef29c0ab182 -
Branch / Tag:
refs/tags/v1.0.0.post1 - Owner: https://github.com/tsilva
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@c3b3c6aa441e1d96780539977a2ccef29c0ab182 -
Trigger Event:
release
-
Statement type:
File details
Details for the file stable_retro_turbo-1.0.0.post1-cp314-cp314-macosx_14_0_arm64.whl.
File metadata
- Download URL: stable_retro_turbo-1.0.0.post1-cp314-cp314-macosx_14_0_arm64.whl
- Upload date:
- Size: 101.9 MB
- Tags: CPython 3.14, macOS 14.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
29165c7b9244c0148a352781149fd0a0c85c0e4f962c2f9fa2a395aa42360d95
|
|
| MD5 |
1ea77897a57c96b7780e683e1be9f82a
|
|
| BLAKE2b-256 |
5b9e9d708fffadfc1e36003a717adadc1ceebc885b1409793dbeb5240538e779
|
Provenance
The following attestation bundles were made for stable_retro_turbo-1.0.0.post1-cp314-cp314-macosx_14_0_arm64.whl:
Publisher:
release.yml on tsilva/stable-retro-turbo
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
stable_retro_turbo-1.0.0.post1-cp314-cp314-macosx_14_0_arm64.whl -
Subject digest:
29165c7b9244c0148a352781149fd0a0c85c0e4f962c2f9fa2a395aa42360d95 - Sigstore transparency entry: 1808196176
- Sigstore integration time:
-
Permalink:
tsilva/stable-retro-turbo@c3b3c6aa441e1d96780539977a2ccef29c0ab182 -
Branch / Tag:
refs/tags/v1.0.0.post1 - Owner: https://github.com/tsilva
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@c3b3c6aa441e1d96780539977a2ccef29c0ab182 -
Trigger Event:
release
-
Statement type: