Overview
Overview
All kernels in rl-triton share a single architectural idea: express the RL recurrence as a linear recurrence of the form
and solve it in \(O(\log N)\) parallel steps using an associative scan on the GPU, rather than the \(O(N)\) sequential loop a naïve implementation requires. The scan runs entirely inside Streaming Multiprocessor SRAM, avoiding repeated round-trips to High Bandwidth Memory (HBM).
For sequences that fit in a single thread block (seq_len ≤ 131072), a
fully-fused kernel computes every intermediate quantity - TD errors, IS
ratios, decay products - without materialising any intermediate tensors.
Longer sequences fall back to a chunked scan that stitches results across
blocks.
Choosing the Right Kernel
| Situation | Kernel |
|---|---|
| On-policy PPO / A2C advantage estimation | compute_gae |
| Off-policy actor-critic (IMPALA, APPO) | compute_vtrace |
| Off-policy Q-learning, discrete actions | compute_retrace |
| Critic targets with bias-variance control | compute_lambda_returns |
| Simple reward-to-go baseline | compute_discounted_returns |
| TD(λ) parameter updates with traces | compute_eligibility_traces |
| Episode-scoped cumulative statistics | compute_episodic_prefix_sum |
API Reference
rl_triton.ops.gae.compute_gae(rewards, values, terminateds, truncateds=None, gamma=0.99, lambda_=0.95, bootstrap_values=None, last_value=None)
Compute Generalized Advantage Estimation via a backward associative scan.
Recurrence:
- A[t] = δ[t] + β[t] * A[t+1], A[T] = 0
- δ[t] = r[t] + γ·(1-terminated[t]) * v_next[t] - V(s_t)
- β[t] = γ·λ·(1-done[t]) (scan decay coefficient)
- done[t] = terminated[t] | truncated[t]
terminated[t] gates the one-step bootstrap inside δ[t]: set to 1 for true
episode ends (s_{t+1} is a reset state with no meaningful value).
truncated[t] stops trace propagation and injects the true continuation
value bootstrap_values[env, t] = V(s_{t+1}^true) into δ[t].
bootstrap_values supplies the true continuation value V(s_{t+1}) wherever the stored values[t+1] is invalid. Two situations require this, under one rule: (a) truncated steps, where values[t+1] belongs to the next episode; and (b) the final column t=T-1, where values[t+1] lies past the buffer. In both cases set bootstrap_values to the true continuation value; leave it zero everywhere else.
The final column feeds delta[T-1] as the next-state value ONLY. The scan's additive boundary carry A[T] is always 0: an advantage carry represents trace mass from steps past the buffer, and there is none there. (β[T-1], the multiplicative decay coefficient, is unaffected by this -- only the additive A[T] term changes.) A single entry in bootstrap_values[:, -1] is sufficient -- set it to V(s_T) if the episode continues past the window, or 0 if it terminated at T-1.
Most users have no interior truncations and should use the last_value
argument (shape [num_envs]) instead, which populates the boundary column
automatically.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
rewards
|
Tensor
|
Per-step rewards, [num_envs, seq_len], float32, CUDA. |
required |
values
|
Tensor
|
V(s_t), [num_envs, seq_len], float32, CUDA. |
required |
terminateds
|
Tensor
|
True termination flags (1.0=terminated), [num_envs, seq_len], float32, CUDA. |
required |
truncateds
|
Tensor | None
|
Time-limit truncation flags (1.0=truncated), [num_envs, seq_len], float32, CUDA. If None, terminateds is used for both gating roles (conservative: treats all boundaries as terminations). |
None
|
gamma
|
float
|
Discount factor (default 0.99). |
0.99
|
lambda_
|
float
|
GAE trace parameter in [0, 1] (default 0.95). |
0.95
|
bootstrap_values
|
Tensor | None
|
True continuation values V(s_{t+1}^true), [num_envs, seq_len], float32, CUDA. Set bootstrap_values[env, t] = V(s_{t+1}^true) at every truncated step and at t=T-1 if the window ends mid-episode. Zero elsewhere. If None, defaults to all zeros. Mutually exclusive with last_value. |
None
|
last_value
|
Tensor | None
|
Convenience arg for the common case of no interior truncations: V(s_T) per environment, shape [num_envs], float32, CUDA. Populates bootstrap_values[:, -1] automatically. Mutually exclusive with bootstrap_values. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
advantages |
Tensor
|
A[t], shape [num_envs, seq_len], float32. |
Source code in rl_triton/ops/gae.py
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 | |
rl_triton.ops.vtrace.compute_vtrace(log_pi_target, log_pi_behavior, values, rewards, terminateds, truncateds=None, gamma=0.99, rho_bar=1.0, c_bar=1.0, bootstrap_values=None, last_value=None)
Compute V-Trace targets and advantages via a backward associative scan.
V-Trace (Espeholt et al. 2018, IMPALA) corrects for off-policy data using clipped importance sampling ratios ρ and c.
Recurrence:
- Δ[t] = δ[t] + β[t] * Δ[t+1], Δ[T] = 0
- δ[t] = ρ[t] * (r[t] + γ * V(s_{t+1}) * (1 - terminated[t]) - V(s_t))
- β[t] = γ * c[t] * (1 - done[t]), done[t] = terminated[t] | truncated[t] (scan decay coefficient)
- ρ[t] = min(ρ_bar, π_target[t] / π_behavior[t])
- c[t] = min(c_bar, π_target[t] / π_behavior[t])
Outputs:
- vs[t] = Δ[t] + V(s_t) (critic targets)
- A[t] = ρ[t] * (r[t] + γ * vs[t+1] * (1 - terminated[t]) - V(s_t)) (actor advantages)
bootstrap_values supplies the true continuation value V(s_{t+1}) wherever the stored values[t+1] is invalid. Two situations require this, under one rule: (a) truncated steps, where values[t+1] belongs to the next episode; and (b) the final column t=T-1, where values[t+1] lies past the buffer. In both cases set bootstrap_values to the true continuation value; leave it zero everywhere else.
The final column feeds delta[T-1] as the next-state value ONLY. The scan's additive boundary carry Δ[T] is always 0: an advantage carry represents trace mass from steps past the buffer, and there is none there. (β[T-1], the multiplicative decay coefficient above, is unaffected by this -- only the additive Δ[T] term changes.) A single entry in bootstrap_values[:, -1] is sufficient -- set it to V(s_T) if the episode continues past the window, or 0 if it terminated at T-1. (The same bootstrap_values[:, -1] is also used directly, not as a carry, when computing next_vtrace_targets[:, -1] for the advantage formula -- that use is single-counted and correct as-is.)
Most users have no interior truncations and should use the last_value
argument (shape [num_envs]) instead, which populates the boundary column
automatically.
terminated[t] gates the one-step bootstrap in δ[t]: set to 1 at true episode
ends. truncated[t] stops trace propagation and injects bootstrap_values[env, t]
= V(s_{t+1}^true), correcting for stale reset observations in the values buffer
under Gymnasium next-step autoreset.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
log_pi_target
|
Tensor
|
Log probabilities under target policy, [num_envs, seq_len], float32, CUDA. |
required |
log_pi_behavior
|
Tensor
|
Log probabilities under behavior policy, [num_envs, seq_len], float32, CUDA. |
required |
values
|
Tensor
|
V(s_t), [num_envs, seq_len], float32, CUDA. |
required |
rewards
|
Tensor
|
Per-step rewards, [num_envs, seq_len], float32, CUDA. |
required |
terminateds
|
Tensor
|
True termination flags (1.0=terminated), [num_envs, seq_len], float32, CUDA. |
required |
truncateds
|
Tensor | None
|
Time-limit truncation flags (1.0=truncated), [num_envs, seq_len], float32, CUDA. If None, terminateds is used for both gating roles. |
None
|
gamma
|
float
|
Discount factor (default 0.99). |
0.99
|
rho_bar
|
float
|
IS ratio clip for δ (default 1.0). |
1.0
|
c_bar
|
float
|
IS ratio clip for decay (default 1.0). |
1.0
|
bootstrap_values
|
Tensor | None
|
True continuation values V(s_{t+1}^true), [num_envs, seq_len], float32, CUDA. Set bootstrap_values[env, t] = V(s_{t+1}^true) at every truncated step and at t=T-1 if the window ends mid-episode. Zero elsewhere. If None, defaults to all zeros. Mutually exclusive with last_value. |
None
|
last_value
|
Tensor | None
|
Convenience arg for the common case of no interior truncations: V(s_T) per environment, shape [num_envs], float32, CUDA. Populates bootstrap_values[:, -1] automatically. Mutually exclusive with bootstrap_values. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
vtrace_targets |
Tensor
|
vs[t], shape [num_envs, seq_len], float32. |
vtrace_advantages |
Tensor
|
A[t], shape [num_envs, seq_len], float32. |
Source code in rl_triton/ops/vtrace.py
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 | |
rl_triton.ops.retrace.compute_retrace(action_probs_target, action_probs_behavior, q_values, next_q_values_all, actions, rewards, terminateds, truncateds, gamma, lambda_=1.0, c_bar=1.0, rho_bar=1.0)
Compute Retrace(λ) Q-value targets and advantages via a backward associative scan.
Retrace(λ) (Munos et al. 2016) corrects off-policy Q-value estimates using truncated IS traces applied only to the decay factor, not the TD error. Discrete actions only -- use compute_vtrace for continuous action spaces.
Recurrence:
- Δ[t] = δ[t] + decay[t] * Δ[t+1], Δ[T] = 0
- δ[t] = r[t] + γ · E_π[Q(s_{t+1},a)] · (1-terminated[t]) - Q(s_t,a_t)
- decay[t] = γ · c[t+1] · (1-done[t]), done[t] = terminated[t] | truncated[t]
- c[t] = λ · min(c_bar, π(a_t|s_t) / μ(a_t|s_t))
Q-value targets: Q_ret[t] = Q(s_t, a_t) + Δ[t] Advantages: A[t] = ρ[t] · (r[t] + γ · Q_ret[t+1] · (1-terminated[t]) - Q(s_t,a_t)) ρ[t] = min(rho_bar, π(a_t|s_t) / μ(a_t|s_t))
The Q-bootstrap γ·E_π[Q(s_{t+1},·)] is folded into δ[t] via
next_q_values_all, so no separate bootstrap_values argument is needed.
terminated gates the one-step bootstrap in δ[t]; terminated | truncated
gates trace decay in β[t].
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
action_probs_target
|
Tensor
|
Target policy probabilities over all actions, [num_envs, seq_len, num_actions], float32, CUDA. |
required |
action_probs_behavior
|
Tensor
|
Behavior policy probability of the taken action, [num_envs, seq_len], float32, CUDA. |
required |
q_values
|
Tensor
|
Q(s_t, a_t) for the taken action, [num_envs, seq_len], float32, CUDA. |
required |
next_q_values_all
|
Tensor
|
Q(s_{t+1}, a) for all actions, [num_envs, seq_len, num_actions], float32, CUDA. |
required |
actions
|
Tensor
|
Indices of the taken action, [num_envs, seq_len], int64, CUDA. |
required |
rewards
|
Tensor
|
Per-step rewards, [num_envs, seq_len], float32, CUDA. |
required |
terminateds
|
Tensor
|
True termination flags (1.0 = terminated). Zeros the bootstrap γ·E_π[Q(s_{t+1},·)] in δ[t]. [num_envs, seq_len], float32, CUDA. |
required |
truncateds
|
Tensor
|
Time-limit truncation flags (1.0 = truncated). Keeps the bootstrap in δ[t] but severs the trace. [num_envs, seq_len], float32, CUDA. |
required |
gamma
|
float
|
Discount factor. |
required |
lambda_
|
float
|
Trace decay parameter (default 1.0). |
1.0
|
c_bar
|
float
|
IS ratio clip for trace weights (default 1.0). |
1.0
|
rho_bar
|
float
|
IS ratio clip for advantage scaling (default 1.0). |
1.0
|
Returns:
| Name | Type | Description |
|---|---|---|
retrace_targets |
Tensor
|
Q_ret[t], shape [num_envs, seq_len], float32. |
advantages |
Tensor
|
A[t], shape [num_envs, seq_len], float32. |
Source code in rl_triton/ops/retrace.py
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 | |
rl_triton.ops.returns.compute_lambda_returns(rewards, next_values, terminateds, truncateds=None, gamma=0.99, lambda_=0.95, bootstrap_values=None)
Compute TD(λ) targets (λ-returns) via a backward associative scan.
Recurrence:
- G[t] = r[t] + γ(1-done[t]) * [(1-λ)V(s_{t+1}) + λG[t+1]] + γtruncated[t]*bootstrap[t]
- done[t] = terminated[t] | truncated[t]
Special cases: λ=0 reduces to one-step TD; λ=1 reduces to discounted returns.
terminated[t] stops both the value bootstrap and trace propagation.
truncated[t] stops trace propagation and injects bootstrap_values[env, t]
= V(s_{t+1}^true) as the continuation value. The caller must zero
next_values[env, t] at truncated steps to avoid double-counting.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
rewards
|
Tensor
|
Per-step rewards, [num_envs, seq_len], float32, CUDA. |
required |
next_values
|
Tensor
|
V(s_{t+1}), [num_envs, seq_len], float32, CUDA. Must be zeroed by caller at truncated steps. |
required |
terminateds
|
Tensor
|
True termination flags (1.0=terminated), [num_envs, seq_len], float32, CUDA. |
required |
truncateds
|
Tensor | None
|
Time-limit truncation flags (1.0=truncated), [num_envs, seq_len], float32, CUDA. If None, terminateds is used for both gating roles. |
None
|
gamma
|
float
|
Discount factor (default 0.99). |
0.99
|
lambda_
|
float
|
Trace parameter in [0, 1] (default 0.95). |
0.95
|
bootstrap_values
|
Tensor | None
|
True continuation values V(s_{t+1}^true), [num_envs, seq_len], float32, CUDA. Nonzero at truncated steps and at t=T-1 when the window ends mid-episode; zero elsewhere. If None, defaults to all zeros. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
lambda_returns |
Tensor
|
G[t], shape [num_envs, seq_len], float32. |
Source code in rl_triton/ops/returns.py
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | |
rl_triton.ops.returns.compute_discounted_returns(rewards, terminateds, truncateds=None, gamma=0.99, bootstrap_values=None)
Compute discounted returns (reward-to-go) via a backward associative scan.
Recurrence:
- G[t] = r[t] + γ(1-done[t])G[t+1] + γtruncated[t]bootstrap[t]
- done[t] = terminated[t] | truncated[t]
terminated[t] stops the return propagation (episode ends, G[t+1]=0).
truncated[t] also stops propagation but injects bootstrap_values[env, t]
= V(s_{t+1}^true) as the continuation value instead of zero.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
rewards
|
Tensor
|
Per-step rewards, [num_envs, seq_len], float32, CUDA. |
required |
terminateds
|
Tensor
|
True termination flags (1.0=terminated), [num_envs, seq_len], float32, CUDA. |
required |
truncateds
|
Tensor | None
|
Time-limit truncation flags (1.0=truncated), [num_envs, seq_len], float32, CUDA. If None, terminateds is used for both gating roles. |
None
|
gamma
|
float
|
Discount factor (default 0.99). |
0.99
|
bootstrap_values
|
Tensor | None
|
True continuation values V(s_{t+1}^true), [num_envs, seq_len], float32, CUDA. Nonzero at truncated steps and at t=T-1 when the window ends mid-episode; zero elsewhere. If None, defaults to all zeros. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
returns |
Tensor
|
G[t], shape [num_envs, seq_len], float32. |
Source code in rl_triton/ops/returns.py
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 | |
rl_triton.ops.returns.compute_eligibility_traces(gradients, dones, gamma, lambda_, seed_values=None)
Compute accumulating eligibility traces via a forward associative scan.
Recurrence:
- z[t] = g[t] + γ·λ·(1 - done[t]) * z[t-1], z[-1] = seed
g[t] is the per-step input: the value-function gradient ∇_w V̂(s_t) for general function approximation, or the feature vector x(s_t) in the linear case. Unlike all other kernels, this scan runs forward in time. Limited to seq_len <= 131072.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
gradients
|
Tensor
|
g[t] -- value-function gradients or feature vectors, [num_envs, seq_len], float32, CUDA. |
required |
dones
|
Tensor
|
Episode termination flags (1.0=done), [num_envs, seq_len], float32, CUDA. |
required |
gamma
|
float
|
Discount factor. |
required |
lambda_
|
float
|
Trace decay parameter. |
required |
seed_values
|
Tensor | None
|
Initial trace z[-1] per environment, shape [num_envs]. Defaults to zeros. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
traces |
Tensor
|
z[t], shape [num_envs, seq_len], float32. |
Source code in rl_triton/ops/returns.py
rl_triton.ops.prefix_sum.compute_episodic_prefix_sum(inputs, dones, seed_values=None)
Cumulative sum that resets to zero at episode boundaries.
Recurrence:
- C[t] = x[t] + (1 - done[t]) * C[t-1], C[-1] = seed
- done[t]=1: accumulator resets, C[t] = x[t]
- done[t]=0: accumulator continues, C[t] = x[t] + C[t-1]
Limited to seq_len <= 131072.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
inputs
|
Tensor
|
Values to accumulate x[t], [num_envs, seq_len], float32, CUDA. |
required |
dones
|
Tensor
|
Episode termination flags (1.0=done), [num_envs, seq_len], float32, CUDA. |
required |
seed_values
|
Tensor | None
|
Initial carry C[-1] per environment, shape [num_envs]. Defaults to zeros. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
prefix_sums |
Tensor
|
C[t], shape [num_envs, seq_len], float32. |