Skip to content

Feature: add opt-in bfloat16 mixed precision to PPO and Distillation#219

Open
lzyang2000 wants to merge 1 commit into
leggedrobotics:mainfrom
lzyang2000:main
Open

Feature: add opt-in bfloat16 mixed precision to PPO and Distillation#219
lzyang2000 wants to merge 1 commit into
leggedrobotics:mainfrom
lzyang2000:main

Conversation

@lzyang2000

@lzyang2000 lzyang2000 commented Jun 28, 2026

Copy link
Copy Markdown

Add opt-in bfloat16 mixed precision to PPO and Distillation

Adds an opt-in use_mixed_precision option to PPO and Distillation. When enabled, the forward pass and loss run under torch.amp.autocast in bfloat16; backward, gradient clipping, multi-GPU all-reduce, and the optimizer step stay in fp32. Off by default — existing runs are unchanged. (Hopefully I did not step on any toes)

API

use_mixed_precision (default False):

value behavior
False fp32 everywhere (default)
True force bf16 autocast over forward + loss
"auto" bf16 only on bf16-capable CUDA devices, else fp32
alg = PPO(actor, critic, storage, use_mixed_precision="auto", device="cuda")

What changed

  • rsl_rl/utils/utils.py: new resolve_mixed_precision(setting, device_type) helper (interprets "auto"), exported from utils/__init__.py.
  • ppo.py / distillation.py: new use_mixed_precision: bool | str = False arg; update() wraps only the forward + loss in torch.amp.autocast(..., dtype=torch.bfloat16). Backward/clip/all-reduce/step stay outside (gradients stay fp32, so the distributed path is unchanged). save()/load() untouched.
  • Tests for the resolver and both algorithms.

Validation

Full test suite passes (181). Isolated update() benchmark (RTX 4090, MLP [1024,1024,512]):

fp32 bf16
time / update() 446.9 ms 187.2 ms (2.39×)
peak memory 1718 MB 1144 MB (−33%)

End-to-end (mjlab Go1 velocity, 4096 envs × 300 iters):

fp32 bf16 (auto)
total wall 157 s 153 s
↳ collection (env sim) 137 s 138 s
↳ learning (update()) 20.2 s 15.6 s
reward (start → end) −0.13 → 62.1 −0.13 → 64.9
non-finite metrics 0 0

bf16 is stable (no non-finite values, reward matches fp32). The end-to-end gain is small only because this task is collection-bound — env sim is ~87% of wall time; the update itself is 1.3× faster.

fp32 bf16 (auto)
go1_fp32 go1_bf16

Default is False, so the change is purely additive and backward compatible.

Add a `use_mixed_precision` option (True / False / "auto", default False) that
runs the forward pass and loss computation under torch.amp.autocast in bfloat16,
while keeping backward, gradient clipping, multi-GPU gradient reduction, and the
optimizer step in fp32. No GradScaler is required since bfloat16 shares fp32's
exponent range.

"auto" enables bf16 only on bfloat16-capable CUDA devices and falls back to fp32
otherwise. Advantage normalization and the adaptive-LR/KL step stay in fp32
(outside the autocast region). The default is off to preserve existing numerics
and reproducibility; "auto" is the recommended value when opting in.
@lzyang2000 lzyang2000 changed the title feat: add opt-in bfloat16 mixed precision to PPO and Distillation Feature: add opt-in bfloat16 mixed precision to PPO and Distillation Jun 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant