Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Testing

Tensor operations

Shared tensor tests live in crates/burn-backend-tests/tests/tensor. Register new test modules in the corresponding mod.rs or tests/common/tensor.rs. The test executables reuse those modules across precisions; backend features select which runtime to test. Backend-specific implementation tests also live alongside the backend code.

Run the relevant shared suites using the backend aliases defined in crates/burn-backend-tests/.cargo/config.toml. Start from the repository root and change into the crate directory so Cargo discovers its aliases:

cd crates/burn-backend-tests
cargo test-flex --test tensor
cargo test-flex --test autodiff

These aliases run in release mode and select the backend features explicitly. Omit --test to run all test targets for that configuration, or append a test-name filter to narrow the run:

cargo test-flex
cargo test-flex --test tensor matmul

Choose the alias for the backend you are changing, such as cargo test-cuda, cargo test-vulkan, or cargo test-metal. Aliases for backends that support fusion enable it by default; their -no-fusion variants test without fusion. For example, run both configurations when changing CUDA operations or fusion behavior:

cargo test-cuda --test tensor
cargo test-cuda-no-fusion --test tensor

From the repository root, use cargo run-checks for the repository validation workflow. It defaults to Flex; select another backend with cargo run-checks --backend <backend> when working on backend-specific code.

Autodiff

Shared backward tests live in crates/burn-backend-tests/tests/autodiff and are registered through tests/common/autodiff.rs. Graph engine unit tests also live in burn-autodiff. For operations with multiple differentiable inputs, verify every input gradient.

Choose small inputs whose derivatives can be calculated independently. Create source leaves on an autodiff device and call require_grad() before the forward pass. Retrieve their gradients from the result of backward(). Check broadcasting and untracked inputs where relevant; a numerically correct forward pass does not establish a correct backward implementation.

You can also use PyTorch as a reference implementation to obtain expected outputs and gradients for Burn tests. For example, this small broadcasting case checks gradients for both operands:

import torch

x = torch.tensor([[1., 2.], [3., 4.]], requires_grad=True)
y = torch.tensor([5., 6.], requires_grad=True)
output = x * y
output.sum().backward()

print(output.detach().tolist())  # [[5.0, 12.0], [15.0, 24.0]]
print(x.grad.tolist())           # [[5.0, 6.0], [5.0, 6.0]]
print(y.grad.tolist())           # [4.0, 6.0]

Use the same inputs, operation parameters, and reduction in the Burn test, and record these values as expected data so the test does not depend on PyTorch. Here, the gradient for y sums contributions over the broadcast dimension. For other operations, check that the reference uses matching semantics and dtypes, and compare with an appropriate tolerance as described below.

Precision

Shared suites define FloatElem and IntElem aliases for each test executable and configure the device defaults before creating tensors. They are not associated types of a TestBackend. Use the aliases in expected data and use .elem() when a literal needs conversion.

For approximate floating-point comparisons, follow nearby tests:

actual.into_data().assert_approx_eq::<FloatElem>(&expected, Tolerance::default());

For integers, use IntElem and skip cases whose inputs cannot be represented by the selected dtype. Exercise additional precision targets when the change depends on dtype or numerical stability.