← Writing
kernelsJuly 1, 2026 · 17 min readphysics-frontier ↗

Accelerating dense physics solves via FP16 Tensor Core accumulation

Dense matrix inversions, Gaussian process regression, and PDE Green's function applications reduce to large matrix multiplications that execute at half-rate on consumer Ampere GPUs. Enabling FP16 accumulation recovers 1.84–1.91× speedups at ~1e-3 relative error against FP64 reference solves.

1.91×faster dense solvesfp32-accfp16-acc

Dense linear algebra operations represent the core computational bottleneck across numerical physics workloads, including explicit linear solves, Gaussian Process (GP) regression, reduced-order modeling, and Partial Differential Equation (PDE) Green’s function evaluations. On consumer NVIDIA Ampere GPUs (such as the RTX 3080), these dense matrix multiplications default to half-rate execution on Tensor CoresDedicated matrix-multiply units on NVIDIA GPUs that multiply small fp16 tiles and add up the products, far faster than the general-purpose CUDA cores for dense matmul. when configured with FP32 accumulators.

By enabling FP16 accumulator execution via PyTorch’s allow_fp16_accumulation flag, matrix multiplication throughput increases by 1.91× for matrix inverse applications and 1.84× for PDE Green’s function solves, while maintaining relative errors near 103\sim 10^{-3} against double-precision (FP64) reference baselines.

1.91×
matrix-inverse apply
117.5 vs 61.6 TFLOP/s
1.84×
PDE Green's-function apply
120.0 vs 65.2 TFLOP/s
~1e-3
relative error vs fp64
2.3e-3 PDE · 3.4e-3 solve

Mathematical Equivalence Across Dense Physical Systems

Despite structural differences in underlying physics equations, four distinct scientific computing tasks reduce to identical linear algebra operations:

  1. Dense Linear Solves: Operator factorization is performed once, followed by multiple triangular solves across right-hand side (RHS) vector blocks.
  2. Gaussian Process / Kernel Ridge Regression: Dense covariance matrices are inverted once, followed by matrix-vector evaluations over evaluation queries.
  3. Reduced-Order Models: Physical systems are projected onto reduced basis subspaces, followed by repeated matrix-vector applications across parameter sweeps.
  4. PDE Green’s Functions: Discrete differential operators are inverted once to construct Green’s function representations, which are subsequently applied across spatial source distributions.

In each workload, operator construction occurs once, while operator application (a dense GEMMGeneral matrix-matrix multiply, the dense C = A·B kernel that sits at the center of all four workloads.) repeats across time steps, parameter samples, or batch inputs.

Mathematical reduction of physics solvers to GEMM operators

Each workload decomposes into a two-phase execution lifecycle:

  • Phase 1: Operator Formation (Amortized): Construct operator matrix AA or its inverse A1A^{-1}.
  • Phase 2: Operator Application (Hot Loop): Compute X=A1BX = A^{-1} B, where BRn×RB \in \mathbf{R}^{n \times R} contains RR right-hand side columns.

Because Phase 2 executes for every batch or ensemble evaluation, optimizing the underlying matrix-matrix product directly reduces total execution time.

Computational Amortization: Formation vs. Application

Profiling an 8192×81928192 \times 8192 matrix inversion demonstrates the performance disparity between operator formation and operator application:

  • Operator Formation (torch.linalg.inv): 202.0 ms (executed once in FP32).
  • Operator Application (A1BA^{-1} B for R=2048R=2048): 4.46 ms in FP32-accumulator mode vs. 2.34 ms in FP16-accumulator mode.

Because operator formation occurs once at initialization, optimizing application latency dominates total wall-clock time as the number of RHS evaluations grows.

Amortization for 8192×8192 matrix inverse (202 ms setup time followed by repeated application steps)
1101001k10k0.2 s1 s10 s40 s~100 applies: apply-dominatedfp32-accfp16-accapplies per formationtotal wall-clock

When R100R \ge 100 applications are performed per formation step, execution time becomes entirely application-dominated, and the speedup ratio approaches 4.46/2.34=1.91×4.46 / 2.34 = 1.91\times.

Amortization economics in ensemble simulations

In uncertainty quantification (UQ) and Monte Carlo sampling, an operator AA is initialized once and applied to thousands of RHS vectors. Under these conditions, setup overhead (202 ms202\text{ ms}) becomes negligible compared to cumulative application time (4.46 s4.46\text{ s} per 1,000 passes).

NVIDIA Ampere Tensor Core Accumulator Architecture

NVIDIA Tensor Cores process matrix multiply-accumulate (MMAMatrix multiply-accumulate: the tensor-core primitive that multiplies two input tiles and adds the product into a running accumulator. A GEMM is built from many of these.) primitives by multiplying 16×1616 \times 16 FP16 input tiles and accumulating products into a running sum:

Accnew=Accold+AtileBtile\text{Acc}_{\text{new}} = \text{Acc}_{\text{old}} + A_{\text{tile}} \cdot B_{\text{tile}}

On consumer NVIDIA Ampere hardware (microarchitecture sm_86, e.g., RTX 3080), Tensor Cores support two accumulation modes:

  • FP32 Accumulation (fp32-accumulateSumming the running dot product in single precision. Numerically safe on any input, but on sm_86 GeForce it issues at half the rate of fp16 accumulation.): Accumulates intermediate products in FP32 precision. On consumer Ampere, this instruction path executes at half hardware throughput.
  • FP16 Accumulation (fp16-accumulateSumming the running dot product in half precision. Same fp16 inputs, same cores, but on sm_86 it issues at the full MMA rate.): Accumulates intermediate products in FP16 precision, issuing at full hardware clock rates.

By default, cuBLASNVIDIA's dense linear-algebra library, the GEMM backend PyTorch calls. It defaults to fp32 accumulation because that is correct on any input. selects FP32 accumulation to prevent potential numerical overflow across arbitrary workloads.

Hardware issue rates on consumer vs. datacenter silicon

On consumer Ampere (sm_86), hardware design choices enforce a 1:2 issue rate penalty for FP32 accumulation relative to FP16 accumulation. On datacenter Ampere (sm_80, A100) and Hopper (sm_90, H100), FP32 and FP16 accumulation execute at identical issue rates. Consequently, FP16 accumulator speedups apply specifically to consumer-grade GPU hardware.

Evaluating Arithmetic Intensity for dense operator application

For an n=8192,R=2048n = 8192, R = 2048 matrix product (A1BA^{-1} B), total arithmetic work is 2n2R2.7×1011 FLOPs2 \cdot n^2 \cdot R \approx 2.7 \times 10^{11}\text{ FLOPs}. Total memory traffic for FP16 inputs and outputs is 0.2 GB\approx 0.2\text{ GB}.

This yields an arithmetic intensityFloating-point operations performed per byte of memory traffic. High intensity means a kernel is limited by compute, not by memory bandwidth. of 1400 FLOPs/byte\sim 1400\text{ FLOPs/byte}, placing execution deep within the compute-boundLimited by how fast the arithmetic units retire operations, not by memory bandwidth. This is the regime where the accumulator's issue rate binds. regime of GPU rooflineA model that plots achievable throughput against arithmetic intensity. Its ridge marks where a kernel flips from memory-bound to compute-bound. models. Because memory bandwidth is not the limiting factor, doubling instruction issue rates translates directly into throughput gains.

Precision Trade-Offs and Error Floor Bounds

Switching from FP32 to FP16 accumulation introduces small numerical truncation errors during intermediate dot-product summation. However, physical surrogate models, kernel regressions, and discrete PDE solvers already contain inherent discretization noise and input parameter uncertainty.

For well-conditioned physical operators (κ(A)200\kappa(A) \le 200), the error floor introduced by FP16 accumulation remains bounded near 103\sim 10^{-3} relative error. If input data uncertainties exceed 10310^{-3}, using higher-precision accumulators consumes compute throughput without improving model accuracy.

Benchmark Results and Experimental Design

FP16 accumulation is enabled via PyTorch runtime options:

import torch

# Enable full-rate FP16 accumulation on Tensor Cores (PyTorch >= 2.7)
torch.backends.cuda.matmul.allow_fp16_accumulation = True

# Execute operator application GEMM
X = A_inv @ B

To isolate accumulator throughput gains from architectural changes, benchmarks were evaluated across three configurations on an NVIDIA RTX 3080 GPU (10 GB):

  1. CUDA Core FP32: Standard FP32 execution on general CUDA cores (TF32 disabled).
  2. Tensor Core FP32-Accumulate: FP16 input tensors with FP32 accumulator (cuBLAS baseline).
  3. Tensor Core FP16-Accumulate: FP16 input tensors with FP16 accumulator (optimized configuration).
Experimental isolation protocol

To prevent confounding variables during timing:

torch.manual_seed(0)

# Configuration 1: Pure FP32 (CUDA Cores)
torch.backends.cuda.matmul.allow_tf32 = False
X_fp32 = A_fp32 @ B_fp32

# Configuration 2: FP16 Inputs, FP32 Accumulator (Tensor Cores)
torch.backends.cuda.matmul.allow_fp16_accumulation = False
X_acc32 = A_fp16 @ B_fp16

# Configuration 3: FP16 Inputs, FP16 Accumulator (Tensor Cores)
torch.backends.cuda.matmul.allow_fp16_accumulation = True
X_acc16 = A_fp16 @ B_fp16

Timings were captured using torch.cuda.Event metrics across 10 execution trials following warmup iterations.

Matrix inverse application throughput (n=8192, R=2048, RTX 3080)
CUDA Core FP32 (TF32 off)22.0 TFLOP/s · 12.51 ms · rel error 1.3e-6
Tensor Core FP32-Accumulate (baseline)61.6 TFLOP/s · 4.46 ms · rel error 3.9e-4
Tensor Core FP16-Accumulate (optimized)117.5 TFLOP/s · 2.34 ms · rel error 3.4e-3
PDE screened-Poisson application throughput (N=9216, R=4096, RTX 3080)
CUDA Core FP32 (TF32 off)23.1 TFLOP/s · 30.09 ms · rel error 1.4e-6
Tensor Core FP32-Accumulate (baseline)65.2 TFLOP/s · 10.67 ms · rel error 3.5e-4
Tensor Core FP16-Accumulate (optimized)120.0 TFLOP/s · 5.80 ms · rel error 2.3e-3

Changing the accumulator precision yields a 1.91× speedup on matrix inversion applications and a 1.84× speedup on PDE Green’s function applications compared to matched FP16-input baselines.

Relative Latency Comparison

Execution latency comparison for matrix inverse application (8192×8192, R=2048)
fp32-accumulate0.00 ms
fp16-accumulate0.00 ms

Disambiguating Cross-Path vs. Same-Kernel Speedups

Comparing FP16 accumulation directly against CUDA Core FP32 execution yields a nominal speedup of 5.35×5.35\times (12.51 ms2.34 ms12.51\text{ ms} \to 2.34\text{ ms}). However, this metric combines two distinct architectural transitions:

  1. Moving computation from general CUDA cores to Tensor Cores (22.061.6 TFLOP/s22.0 \to 61.6\text{ TFLOP/s}, a 2.8×2.8\times gain).
  2. Frictional accumulation rate doubling within Tensor Cores (61.6117.5 TFLOP/s61.6 \to 117.5\text{ TFLOP/s}, a 1.91×1.91\times gain).

To isolate the specific impact of the accumulator toggle, reported speedups (1.91×1.91\times and 1.84×1.84\times) reflect comparisons against matched Tensor Core FP16-input baselines.

Impact of TF32 execution on baseline comparisons

If TF32 execution is enabled for FP32 inputs (allow_tf32 = True), baseline FP32 performance increases from 22.0 TFLOP/s22.0\text{ TFLOP/s} to 45 TFLOP/s\sim 45\text{ TFLOP/s}. This reduces the cross-path ratio while leaving the same-kernel FP16 accumulator speedup (1.91×1.91\times) unchanged.

Numerical Accuracy vs FP64 Gold References

To measure numerical precision loss, outputs from each execution mode were compared against double-precision (FP64) reference solutions (XgoldX_{\text{gold}}) computed via torch.linalg.solve:

PDE operator application relative error vs FP64 reference
Precision ModeAccumulator PrecisionRelative Error vs FP64Residual Norm ||AX - B|| / ||B||
FP32 CUDA CoresFP323.4 × 10⁻⁷2.1 × 10⁻⁷
TF32 Tensor CoresFP321.2 × 10⁻⁴8.9 × 10⁻⁵
FP16 Tensor CoresFP322.3 × 10⁻³1.8 × 10⁻³
FP16 Tensor CoresFP163.4 × 10⁻³2.6 × 10⁻³

Relative error is defined as ||X - X_gold|| / ||X_gold||. For physical surrogates with input noise > 10⁻³, FP16 accumulation provides maximum throughput without compromising effective accuracy.

Relative error XXgold/Xgold\|X - X_{\text{gold}}\| / \|X_{\text{gold}}\| and residual norms AXB/B\|A X - B\| / \|B\| confirm that FP16 accumulation maintains numerical errors bounded between 2.3×1032.3 \times 10^{-3} and 3.4×1033.4 \times 10^{-3} for well-conditioned operators.

Why ill-conditioned operators require higher precision

Newton-Schulz matrix inversion iterations (Xk+1=Xk(2IAXk)X_{k+1} = X_k (2I - A X_k)) require high precision during final residual corrections. In FP16 arithmetic, correction magnitudes drop below machine epsilon (ϵfp169.77×104\epsilon_{\text{fp16}} \approx 9.77 \times 10^{-4}), causing iterative updates to stall.

In contrast, shift-invert PDE operators (Iα2I - \alpha \nabla^2) maintain bounded spectra, allowing FP16 accumulation to execute stably without convergence stalls.

Validity Boundaries and Condition Number Constraints

The application of FP16 accumulation is bounded by three specific numerical conditions:

  1. Condition Number Sensitivity: Test operators must remain well-conditioned. The PDE benchmark evaluates a screened PoissonThe operator I − α∇², a Poisson operator shifted away from singularity by a small α so its inverse stays well-conditioned. operator (Iα2I - \alpha \nabla^2 with α=2×103\alpha = 2 \times 10^{-3}), yielding a condition numberHow much a matrix amplifies error when inverted. Near 1 is benign; a large value magnifies whatever the accumulator rounds off. κ(A)146\kappa(A) \approx 146. Unshifted Poisson operators (2u=f\nabla^2 u = f) exhibit ill-conditioned spectra (κ(A)104\kappa(A) \gg 10^4), causing FP16 truncation errors to amplify significantly.
  2. Iterative Time-Stepping Accumulation: Explicit time-integration schemes (e.g., forward Euler PDE integration) compound rounding errors across sequential steps. FP16 accumulation should be restricted to single-pass matrix-vector applications or stationary solves.
  3. Residual Refinement Limits: Standard iterative refinement (Xk+1=Xk+A1(BAXk)X_{k+1} = X_k + A^{-1}(B - A X_k)) fails to recover lost precision under FP16 accumulation because small residual updates round to zero within FP16 dynamic ranges.
Screened vs unshifted Poisson operator spectra

Unshifted Poisson operators contain near-zero eigenvalues, making the inverse operator A1A^{-1} highly sensitive to perturbations. Adding a screening parameter αI\alpha I shifts the spectrum away from zero, enforcing λmin1\lambda_{\min} \ge 1 and bounding condition numbers to κ(A)200\kappa(A) \le 200.

Convergence mechanics of Newton-Schulz iterative refinement in FP16

Newton-Schulz matrix inversion iterations (Xk+1=Xk(2IAXk)X_{k+1} = X_k (2I - A X_k)) require high precision during final residual corrections. In FP16 arithmetic, correction magnitudes drop below machine epsilon (ϵfp169.77×104\epsilon_{\text{fp16}} \approx 9.77 \times 10^{-4}), causing iterative updates to stall.

Verification and Reproducibility Protocol

All benchmark measurements adhere to the following experimental constraints:

  • Reference Solves: Evaluated against FP64 reference ground truth (torch.linalg.solve).
  • Timing Measurement: Captured using asynchronous GPU CUDA events (torch.cuda.Event) across 10 trials (median reported).
  • Environment: NVIDIA RTX 3080 GPU (Ampere sm_86, 10 GB), PyTorch 2.12, CUDA 13.0.

Generalization to Dense Matrix Operations Across Domains

The performance characteristics of FP16 accumulator execution extend to any compute-bound dense GEMM workload tolerant of 103\sim 10^{-3} relative error:

Cross-domain benchmark results using `allow_fp16_accumulation` toggle
DomainImplementation OverheadThroughput SpeedupTarget Quality Metric
Dense Solves / PDE Green FunctionsPyTorch runtime flag1.84–1.91×Relative Error = 2.3e-3 vs FP64
Vector Retrieval & RankingPyTorch runtime flag1.59× matmulRecall@10 = 0.987
Neural Radiance Field (NeRF) RenderingFused CUDA kernel + flag1.69–1.81× renderPSNR = 35.70 dB

Across all three domains, enabling FP16 accumulation yields immediate throughput gains with negligible impact on domain-specific quality metrics.

1 line
of PyTorch
no custom kernel, no rebuild
0
custom CUDA in physics
~231 LOC of benchmark only
sm_86
consumer Ampere only
A100 not measured here
Why sparse matrix multiplication receives no speedup from FP16 accumulators

In contrast to dense GEMMs, unstructured sparse matrix multiplication (SpMM) is memory-bandwidth bound (Arithmetic Intensity10 FLOPs/byte\text{Arithmetic Intensity} \ll 10\text{ FLOPs/byte}). Because compute units spend time waiting for HBM memory transfers, increasing Tensor Core accumulator issue rates yields no wall-clock latency reduction.

Conclusion

Enabling FP16 accumulation via PyTorch’s allow_fp16_accumulation option recovers 1.84–1.91× throughput on consumer NVIDIA Ampere GPUs for compute-bound dense matrix operations. For well-conditioned operators (κ(A)200\kappa(A) \le 200), the resulting numerical error floor remains bounded at 103\sim 10^{-3}, providing significant acceleration for surrogate modeling, uncertainty quantification, and numerical PDE solves.

Glossary

Glossary — every term, defined
Tensor cores
Dedicated matrix-multiply units on NVIDIA GPUs. They multiply small fp16 input tiles and add up the products far faster than the general-purpose CUDA cores, which is why a dense GEMM belongs on them.
CUDA cores
The general-purpose arithmetic units on the GPU. They run the true-fp32 reference path and most memory-bound sparse work, both slower than the tensor cores on dense GEMM.
MMA (matrix multiply-accumulate)
The tensor-core primitive: multiply two input tiles and add the product into a running accumulator. A GEMM is built from many MMAs.
Accumulator
The running sum a matmul adds each product into. Its precision (fp16 or fp32) is chosen separately from the input precision, and it is the single knob this piece turns.
fp16 / fp32 accumulation
Summing the running dot product in half or single precision. On sm_86 GeForce the fp16 path issues at twice the rate of the fp32 path for identical fp16 inputs.
GEMM
General matrix-matrix multiply, the dense C = A·B kernel that every one of the four workloads reduces to.
cuBLAS
NVIDIA's dense linear-algebra library and the GEMM backend PyTorch calls. It defaults to fp32 accumulation because that is correct on any input.
Arithmetic intensity
Floating-point operations per byte of memory traffic. The inverse apply sits near 1,400 ops/byte, which places it deep in the compute-bound regime.
Roofline
A model plotting achievable throughput against arithmetic intensity. Its ridge marks where a kernel flips from memory-bound to compute-bound.
Compute-bound
Limited by how fast the arithmetic units retire operations rather than by memory bandwidth. This is the regime where the accumulator issue rate binds and the lever lands.
Condition number
How much a matrix amplifies error when inverted. Near 1 is benign; a large value magnifies whatever the accumulator rounds off, which is why ill-conditioned operators leave the lever.
Screened Poisson
The operator I − α∇², a Poisson operator shifted away from singularity by a small α=2e-3, giving cond ≈ 146 so its inverse stays well-conditioned.
The apply
Applying a formed operator to a block of many right-hand sides. It is a large dense GEMM and the cost that repeats, as opposed to the one-time formation.
fp64 gold
A double-precision reference solve. Every rung is scored against it, so the fp32 and fp16 errors share one ground truth.
TF32
NVIDIA's reduced-precision tensor-core format for fp32-typed math. It is switched off for the reference so the baseline is a genuine CUDA-core fp32 path.