Skip to content

Optional GPU training via CUDA backend (--features cuda)#7

Open
bddap-bot wants to merge 1 commit into
mainfrom
gpu-cuda
Open

Optional GPU training via CUDA backend (--features cuda)#7
bddap-bot wants to merge 1 commit into
mainfrom
gpu-cuda

Conversation

@bddap-bot

Copy link
Copy Markdown
Collaborator

Optional GPU training (CUDA)

Adds a cuda Cargo feature that moves training/inference onto the GPU
(cubecl-cuda) on the RTX 2080. CPU (ndarray) stays the default — it's faster
for the current small model and needs no GPU or toolkit. Enable GPU with
cargo run --features cuda.

Why not wgpu

wgpu was the portable first choice and a dead end on burn 0.20: its wgpu module
is !Send (wgpu-core 26's PendingWrites is !Sync), but both
AutodiffModule::valid() and Optimizer::step require Send, so
Autodiff<Wgpu> won't compile. The CUDA backend is Send-clean and works as-is.

Design

  • Cargo.toml: cuda = ["burn/cuda"]; ndarray stays on always, so cargo test and the default build need no GPU.
  • session.rs: TrainBackend is cfg-selected (ndarray | cuda). InferBackend
    and Device derive from it via associated types, so the rest of the code is
    backend-agnostic — no cfg scattered through the logic.
  • shell.nix: allowUnfree + cudaPackages.cudatoolkit + CUDA_PATH, and the
    host driver lib (/run/opengl-driver/lib, where libcuda lives) appended to
    LD_LIBRARY_PATH.

Measured (honest)

Headless training, both backends learn identically (reward 866→1010, crab stands,
every episode runs the full 500 steps):

backend steady steps/s
CPU (ndarray) ~670
GPU (cuda) ~500–530

GPU is slower at this scale — single env, a 256-wide MLP, m=1 matmuls, so
kernel-launch overhead dominates and there's a one-time ~30 s kernel autotune.
The GPU win arrives with bigger models and batched/parallel envs, where the
matmuls become compute-bound. This lands the capability now so scaling up is a
flip of a feature flag, not a porting project.

Verification

  • Default (CPU): cargo fmt --check, clippy --all-targets -D warnings,
    cargo test (5) — green.
  • --features cuda: cargo check + clippy -D warnings — green; training
    verified live on the 2080 (cubecl initialises device 0, JIT-compiles kernels).
  • Built/run in a sandbox; the GPU run used a locked-down bwrap that exposes the
    NVIDIA devices + driver while keeping $HOME/secrets hidden.

Not bundled here: per-episode pose metrics (height/uprightness) and a way to
render a trained crab — next up, to make iterating measurable.

CPU (ndarray) stays the default — faster for the current small model and
needs no GPU. Enabling the cuda feature switches the backend to
cubecl-cuda on the RTX 2080. (wgpu was a dead end: burn 0.20's wgpu
module is !Send, which valid() and Optimizer::step reject; CUDA is
Send-clean.)

- Cargo: cuda feature gates burn/cuda; ndarray always on so tests and the
  default build need no GPU.
- session.rs: TrainBackend is cfg-selected (ndarray | cuda); InferBackend
  and Device derive from it, keeping the rest backend-agnostic.
- shell.nix: allowUnfree + cudaPackages.cudatoolkit + CUDA_PATH, and the
  host driver lib (/run/opengl-driver/lib, libcuda) on LD_LIBRARY_PATH.

Both configs green (fmt/clippy -D warnings/tests). Verified training on
the GPU: identical learning curve, ~500 vs ~670 steps/s on CPU — slower
at this tiny single-env scale (kernel-launch overhead on m=1 matmuls);
the win comes with bigger models / batched envs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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