This project trains a PPO agent from screenshots from Mario Kart: Super Circuit
Video of learned agent after approx. 15 million steps: https://youtu.be/80bOWpP_WsE
This project is using:
BizHawkas the emulatorGymBizHawkas the Python <-> BizHawk bridgeGymnasiumas the environment APIStable-Baselines3andrl_zoo3for PPO training- a local Tkinter GUI in
main.pyfor editing hyperparameters, launching training, TensorBoard, and one-episode evaluation
The environment is registered as MKSC-v0 by mksc.py, and the reward/termination logic lives in mksc.lua.
- main.py: GUI for training, resume, TensorBoard, and evaluation
- mksc.py:
Gymnasiumenvironment registration - mksc.lua: BizHawk-side Lua environment logic
- mksc.yml: PPO hyperparameters used by
rl_zoo3 - enjoy_one_episode.py: run one full evaluation episode from a selected training run
.env: local paths for BizHawk and the MKSC ROM
- Windows
- Python
3.12+ uvinstalled: https://docs.astral.sh/uv/- BizHawk
2.11available locally - Mario Kart: Super Circuit ROM available locally
This repository expects the following local directories/files to exist:
- a BizHawk installation directory
- a MKSC ROM path
If this repo includes GymBizHawk and rl-baselines3-zoo as folders, a normal clone is enough.
git clone <your-repo-url>
cd MKSC-RLCreate a .env file in the project root with these variables:
BIZHAWK_DIR=D:\path\to\BizHawk-2.11-win-x64
MKSC_PATH=D:\path\to\Mario Kart - Super Circuit.gbaMeaning:
BIZHAWK_DIR: BizHawk installation directoryMKSC_PATH: full path to the MKSC ROM file
The environment is loaded automatically by mksc.py.
This project expects one small local patch on top of upstream GymBizHawk.
The patch file is:
patches/gymbizhawk-keep-string-info.patch
Apply it after cloning GymBizHawk:
git -C GymBizHawk apply ../patches/gymbizhawk-keep-string-info.patchWhat it changes:
- preserves non-numeric values in the Lua
infodictionary - keeps fields like
done_reasonavailable on the Python side
This project uses uv and the dependencies from pyproject.toml.
uv syncNotes:
tensorboardis includedsetuptools<81is pinned because current TensorBoard still relies onpkg_resources
You can verify the main files compile:
uv run python -m py_compile main.py
uv run python -m py_compile mksc.py
uv run python -m py_compile enjoy_one_episode.pyStart the training GUI:
uv run python main.pyThe GUI provides:
- editable PPO hyperparameters from
mksc.yml - save/load YAML
- training
- resume training from a saved
.zip - TensorBoard launcher
- run discovery from
logs/ppo/ - one-episode evaluation via
enjoy_one_episode.py
Hyperparameters are stored in mksc.yml.
Important fields:
n_timesteps: total training stepsn_steps: PPO rollout sizebatch_size: PPO mini-batch sizen_epochs: PPO epochs per rolloutlearning_rateclip_rangeframe_stack
For learning_rate and clip_range, the GUI accepts either:
- a constant numeric value, for example:
learning_rate: 2.5e-4
clip_range: 0.1- or a linear schedule string, for example:
learning_rate: lin_2.5e-4
clip_range: lin_0.1In the GUI:
- adjust hyperparameters if needed
- click
Save YAML - click
Train
Training is launched through rl_zoo3.train with:
--algo ppo--env MKSC-v0--gym-packages mksc--conf-file mksc.yml
Artifacts are written to:
logs/ppo/for models and run outputsruns/for TensorBoard logs
To continue from a previous saved model:
- click
Browsenext totrained_agent - select a saved
.zipfromlogs/ppo/... - click
Resume
Important behavior:
- the PPO weights are resumed
- optimizer state is resumed
- if you use schedule strings like
lin_2.5e-4, the schedule restarts at the beginning of the resumed training run
If you want simpler resume behavior, use constant values such as:
learning_rate: 2.5e-4
clip_range: 0.1From the GUI, click TensorBoard.
It starts on:
http://127.0.0.1:6006
Typical messages such as:
pkg_resources is deprecatedTensorFlow installation not found - running with reduced feature set
are warnings, not failures.
Use the Runs section:
- click
Refresh - select a run id
- click
Enjoy 1 Episode
This runs one full episode using enjoy_one_episode.py.
You can run one evaluation episode manually:
uv run python enjoy_one_episode.py --algo ppo --env MKSC-v0 --gym-packages mksc --folder logs --exp-id 2This script:
- loads the selected model
- creates a test environment
- runs until episode termination
- prints a compact episode summary
Environment logic is in mksc.lua.
Current behavior:
- observations are screenshots
- reward is computed in Lua
- termination happens in Lua
- after termination, Python resets the environment
- reset uses
savestate.loadslot(1)in BizHawk, so savestate 1 has to be created manually prior to learning
Typical terminal reasons include:
race_finishedstuckreverseslow_no_progress
- This setup is Windows-oriented.
- BizHawk must be available locally; it is not installed by
uv. - The ROM path must be provided by
.env. - The GUI assumes a single-environment PPO workflow on CPU.
uv sync
uv run python main.pyThen:
- verify
.envpaths are correct - adjust PPO hyperparameters if needed
- click
Train - use
TensorBoardto monitor progress - use
Enjoy 1 Episodeto inspect learned behavior
Your .env file is missing or incorrect. Check:
BIZHAWK_DIRMKSC_PATH
This is expected. As long as the web UI opens, it is fine.
Check:
- BizHawk is receiving inputs
- the savestate in slot
1is valid - the ROM matches the memory addresses expected by mksc.lua
If using lin_... schedules, that is expected. Try constant values such as:
learning_rate: 2.5e-4
clip_range: 0.1