tt-rl
Reinforcement learning on Tenstorrent hardware, built directly on
TT-NN. Networks, gradients, the Adam
step and the device trace all run on the chip through ttnn. Environments
and replay buffers stay on the host.
Pong, DQN |
Breakout, DQN |
Boxing, DQN |
Hopper, SAC |
- Algorithms: DQN (double, n-step, prioritized replay), PPO (GAE, clipping, optional GRU memory) and SAC (twin critics, learned temperature).
- Environments: Atari pixels, MuJoCo state vectors, and any environment you write against a small protocol.
- Single or multiple chips: a run trains on one chip, or data-parallel across several with one replica per chip.
- Deploy anywhere: export a trained policy to numpy or ONNX and run it on any CPU.
Results
Measured on one Blackhole chip. Atari scores are the mean over 30 evaluation
episodes with sticky actions (0.25), which is harder than the
NoFrameskip-v4 setting most published numbers use. A step is one agent
action, four Atari frames. Each score is the best evaluation of its run.
| Task | Algorithm | Steps | Score | Weights |
|---|---|---|---|---|
| Pong | DQN | 10M | 17.8 | ttrl-dqn-pong |
| Breakout | DQN | 10M | 144.8 | ttrl-dqn-breakout |
| Boxing | DQN | 10M | 91.0 | ttrl-dqn-boxing |
| Hopper-v5 | SAC | 1M | 3604 | ttrl-sac-hopper |
Each config in configs/ records how it was measured in its docstring. The
trained policies are on Hugging Face as ONNX and numpy weights, with a
play.py that runs them on CPU.
Learning
From an untrained agent to the final one, at fixed checkpoints of the same run (Atari clips play at 3x speed):
Breakout and Boxing
Requirements
- Linux and Python 3.12.
ttnn0.80 ships wheels for 3.10 and 3.12, and 3.10 is dropped because current Pillow and filelock no longer support it. - A Tenstorrent Blackhole chip with its driver and firmware installed. Developed on a TT-QuietBox with four Blackhole chips.
Install
ttrl installs from source for now. A PyPI release as tt-rl is on its way,
after which pip install tt-rl will be enough.
git clone https://github.com/scaleresearch/tt-rl && cd tt-rl
pip install -e '.[atari]' # Atari
pip install -e '.[mujoco]' # MuJoCo
pip install -e '.[dev]' # both, plus the test suite's dependencies
ttnn installs from PyPI as a dependency. Then check the machine:
ttrl doctor
It reports versions, which chips exist and who holds each one, and opens a free chip to confirm a trace captures and replays.
Train
A run is a Python config. Arguments after the path override any field by its dotted name:
ttrl train configs/pong_dqn.py device.chip=0
ttrl train configs/pong_dqn.py total_frames=3000 algo_cfg.learning_starts=500 log_dir=runs/smoke
The same from Python:
import ttrl
config = ttrl.load_config("configs/pong_dqn.py", overrides=["device.chip=0"])
result = ttrl.run(config)
A run writes metrics, checkpoints and checkpoint-best.npz to its
log_dir. ttrl train --resume best <config> continues from the best one;
DQN and SAC runs also need checkpoint_replay=True so the replay buffer is
saved with them.
examples/atari-dqn and examples/mujoco-sac are standalone projects that
use ttrl as a library.
A chip is exclusive to one process. device.chip=N names a physical chip,
the N in /dev/tenstorrent/N; leave it unset to take the lowest free one.
Multiple chips
device.chips trains one replica per chip. Each replica steps its own
environments and runs its own updates, and every device.sync_every updates
(50 by default) the replicas average their parameters, so they stay one model.
ttrl train configs/pong_ppo.py device.chips=4 # any 4 chips
ttrl train configs/pong_ppo.py device.chips=all # every chip on the machine
ttrl train configs/pong_ppo.py 'device.chips=[0,1]' # these physical chips
config = ttrl.load_config("configs/pong_ppo.py", overrides=["device.chips=4"])
ttrl.run(config)
N replicas collect N times the experience per update round, so a multi-chip run is a different recipe from its single-chip config, and learning rates or batch sizes may need retuning. PPO, which already runs many environments at once, is the natural fit.
Deploy without a chip
import ttrl
artifact = ttrl.export_policy("runs/pong/checkpoint-best.npz", "pong.policy.npz")
ttrl.export_onnx(artifact, "pong.onnx") # needs the [onnx] extra
policy = ttrl.load_policy(artifact) # numpy only
action = policy(obs) # obs: one raw observation
The ONNX graph has one input, obs, and two outputs, action and head
(the Q-values or action distribution). It runs with onnxruntime, and the
Atari DQN graph also compiles unchanged with Tenstorrent's TT-Forge-ONNX.
Your own environment
An environment is any object with obs_spec, action_spec, episode_bound,
reset, step and close. Nothing needs subclassing:
import numpy as np
import ttrl
from ttrl.envs import check_env
from ttrl.envs.registry import register
from ttrl.envs.wrappers import RecordEpisodeStatistics
class Slider:
"""Move a point to the origin. Reward is the step's reduction in |x|."""
obs_spec = ttrl.ObsSpec.vector(2)
action_spec = ttrl.ActionSpec.discrete(3)
episode_bound = 64
def reset(self, *, seed=None):
self.rng = np.random.default_rng(seed)
self.x, self.t = float(self.rng.uniform(-1.0, 1.0)), 0
return self._obs(), {}
def _obs(self):
return np.array([self.x, self.t / self.episode_bound], dtype=np.float32)
def step(self, action):
before = abs(self.x)
self.x = float(np.clip(self.x + (int(action) - 1) * 0.05, -1.0, 1.0))
self.t += 1
return self._obs(), before - abs(self.x), False, self.t >= self.episode_bound, {}
def close(self):
pass
register("slider", lambda **kw: RecordEpisodeStatistics(Slider(**kw)))
check_env(RecordEpisodeStatistics(Slider()))
config = ttrl.TrainConfig(
algo="dqn",
total_frames=4_000,
eval_interval=4_000,
log_dir="runs/slider",
env=ttrl.EnvConfig(name="slider", n_envs=1),
algo_cfg=ttrl.DQNConfig(batch_size=64, learning_starts=500, buffer_capacity=4_000),
)
ttrl.run(config)
check_env raises on the first contract violation with a message saying what
was expected. RecordEpisodeStatistics is required: evaluation reads each
episode's score from it.
Tests
pytest # host suite, no chip needed
pytest -m tt # hardware suite, needs a chip
License
MIT
Metadata
Release files for tt-rl 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| tt_rl-0.1.0.tar.gz | 452.5 kB | With provenance | Details for tt_rl-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| tt_rl-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for tt_rl-0.1.0-py3-none-any.whl |
Total release size: 983.1 kB
Release files / tt_rl-0.1.0.tar.gz
| Download URL | tt_rl-0.1.0.tar.gz |
|---|---|
| Size | 452.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
864c516857866c2c3d44b2eabfc22476a74e417627a41ceea41124612ad3722f
|
|
BLAKE2b-256 checksum How to use checksums |
175c2df433c6367d43de32a8443f3aff5dd08cd3cfeb45e94f5360429ae96a8d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
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 Nov 6, 2026.
Transparency logRelease files / tt_rl-0.1.0-py3-none-any.whl
| Download URL | tt_rl-0.1.0-py3-none-any.whl |
|---|---|
| Size | 530.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
fc41119d4ff0bb1ec59904b7f89f3d9f124ae4698022f107f7f8caef8e4152dc
|
|
BLAKE2b-256 checksum How to use checksums |
5f86268730888c1fd61ee8180e81ee3eea63cad0b9dba88d539f4df5af57d213
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
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 Nov 6, 2026.
Transparency logSecurity for tt-rl 0.1.0
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
Both files in this release have been uploaded with provenance metadata.
Attestation for tt_rl-0.1.0.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 Nov 6, 2026.
Transparency logA 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.
To learn more about protecting yourself from malicious actors, visit our package security documentation.