Topic hub

Hardware and acceleration

Why memory bandwidth rather than arithmetic decides most ML performance, how GPUs, TPUs, Apple Silicon, NPUs and FPGAs differ, and what mixed precision and custom kernels actually buy you.

Updated 13 Nov 2026 · GPU, TPU, HBM, memory bandwidth, mixed precision, FP8, CUDA kernels, FPGA

Overview

Almost every performance question in machine learning reduces to one of two numbers: how many bytes the accelerator can move per second, and how many floating-point operations it can do per second. The ratio of the two, together with the ratio of operations to bytes in your workload, tells you whether you are compute-bound or memory-bound before you write a line of code. The roofline model (Williams, Waterman and Patterson, 2009) is that argument drawn as a graph, and it is the single most useful idea in this hub.

This page is for engineers choosing hardware, sizing a job or wondering why a GPU reports 10 percent utilisation while training is slow. It covers the main accelerator families, the memory hierarchy, mixed precision and custom kernels. Buying advice goes stale, so the numbers here are the vendors’ published specifications at the time of writing and are given to show the shape of the problem, not to recommend a part.

Key ideas

Bandwidth is the budget

Take an NVIDIA H100 SXM. NVIDIA’s datasheet lists 80 GB of HBM3 at 3.35 TB/s and 989 TFLOPS of dense BF16 tensor-core throughput. Dividing those gives about 295 operations per byte. A matrix multiply with large batch sizes does far more than that per byte loaded and is compute-bound, which is why training saturates the chip. Decoding one token from a 7 B parameter model in bf16 reads 14 GB of weights to do roughly 14 GFLOP of work, an intensity of about one operation per byte, so it is bound entirely by memory: at most 3.35 TB/s divided by 14 GB, about 240 tokens per second, no matter how fast the arithmetic is. Batching requests, quantising weights and keeping the KV cache small all attack this same limit, which is why /topics/mlops-and-deployment/ and /topics/efficient-ml/ spend so long on them.

The same arithmetic ranks consumer parts. NVIDIA lists the RTX 4090 at 24 GB of GDDR6X and 1,008 GB/s. Apple lists the M4 Max at up to 128 GB of unified memory at 546 GB/s and the M3 Ultra at up to 512 GB at 819 GB/s. A Mac with 128 GB can hold a model that a 24 GB GPU cannot, and will decode it at roughly half the speed per token.

SM registers and shared memoryup to 228 kB shared per SM, 132 SMsfastest, tens of TB/s (not published)L2 cache50 MB, shared by all SMsHBM380 GB at 3.35 TB/sother GPUsNVLink 4, 900 GB/shost CPU and DRAMPCIe 5.0 x16, about 63 GB/s each wayone decode step7 B model, bf1614 GB of weights readabout 14 GFLOP done1 op per bytevs about 295 neededto be compute-boundso: memory-bound,at most ~240 tokens/sat batch size 1Each level is roughly an order of magnitude slower and larger than the one above it.A kernel that keeps data in shared memory, as FlashAttention does, avoids the HBM round trip.
Memory hierarchy around one H100 SXM GPU. Capacities and bandwidths are NVIDIA's published figures for the H100 SXM5 and NVLink 4. PCIe 5.0 x16 is the PCI-SIG figure per direction. On-chip register and shared-memory bandwidths are not published as single numbers.

The accelerator families

GPUs are the general choice: thousands of simple cores, tensor cores for matrix multiply, mature compilers and the largest library ecosystem. NVIDIA dominates through CUDA. AMD’s Instinct parts run PyTorch through ROCm with a thinner but improving stack. Google’s TPUs are systolic-array machines built for dense matrix multiply, programmed through JAX and XLA, and sold only as cloud instances. Google’s documentation lists the TPU v6e at 32 GB of HBM at 1,640 GB/s per chip, with chips connected in pods for large training runs. Apple Silicon puts CPU, GPU and a neural engine on one die with a shared memory pool, so a model can be larger than any discrete consumer GPU’s memory, at the cost of lower bandwidth and no CUDA. NPUs in phones and laptops are small fixed-function matrix engines aimed at a few watts, good for on-device inference of models already quantised to int8 or lower. FPGAs sit at the far end: they are reconfigurable logic that wins on latency-bound, odd-precision or sensor-attached inference and loses on anything that looks like a large dense matrix multiply. The sister site has a full hub on that case, linked below.

Mixed precision and kernels

Training in full fp32 wastes most of the tensor cores. Mixed precision (Micikevicius et al., 2017) keeps a master copy of weights in fp32 and runs the forward and backward passes in 16-bit. bf16 keeps fp32’s exponent range and needs no loss scaling, which is why it replaced fp16 on hardware that supports it. FP8, introduced with the Hopper generation, halves the bytes again for the matrix multiplies, with per-tensor scaling to stay in range.

Kernels are where the remaining factor of two or three hides. A fused kernel does several operations per trip to memory instead of one. FlashAttention (Dao et al., 2022) is the canonical example: it computes exact attention in tiles that stay in shared memory and never materialises the full attention matrix. torch.compile and Triton make fused kernels reachable without writing CUDA.

Where to start

Read /learn/beginner/04-training-loop-and-loss/ and /learn/beginner/07-your-first-neural-network/ first, then time the training loop from /reference/pytorch-training-loop/ on CPU, on MPS or CUDA, and in bf16 autocast, and compare. /reference/tensor-shapes-and-broadcasting/ covers the layout questions that decide whether a kernel is fast. The /projects/lora-fine-tune-apple-silicon/ project is a realistic unified-memory workload. The /topics/deep-learning/ hub covers the models these numbers apply to.

Tools and platforms

Tool What for Licence Platform
CUDA Toolkit, cuDNN, cuBLAS NVIDIA GPU programming and the libraries PyTorch calls Proprietary, free to use /platforms/nvidia/
Triton (OpenAI) Writing fused GPU kernels in Python MIT /platforms/openai/
torch.compile and PyTorch profiler Graph capture, kernel fusion and finding the slow operator BSD-3 /platforms/pytorch/
JAX and XLA TPU and GPU programming with a compiler in the loop Apache-2.0 /platforms/jax/
Cloud TPU Google’s accelerator, rented by the chip or pod Proprietary, metered /platforms/google/
MLX and Core ML Apple Silicon training and on-device inference MIT (MLX), proprietary (Core ML) /platforms/apple/
ROCm AMD GPU stack for PyTorch Mostly MIT and open source /platforms/opensource/
FPGA Guide Sister site covering FPGA inference flows n/a fpgaguide.com/topics/ai-ml/

Common mistakes

  • Comparing peak TFLOPS. Peak assumes dense matrix multiply with every unit busy. Compare measured throughput on your workload, and check whether a quoted figure includes structured sparsity.
  • Buying for compute when the job is memory-bound. For inference, bandwidth and capacity decide, and for training at scale, interconnect does.
  • Training in fp16 without loss scaling, or in fp32 on hardware with bf16 tensor cores.
  • Reading GPU utilisation as a measure of efficiency. A kernel waiting on memory shows 100 percent utilisation.
  • Running a data loader on two CPU workers and blaming the GPU.
  • Assuming a model that fits in memory will run. The KV cache, optimiser state and activations need room too.

Going deeper

Reference

  • Quantisation formats and what they cost

    FP32 to INT4, NF4, GGUF k-quants, AWQ and GPTQ on one page, with bytes per parameter, memory for 7 B and 70 B models, reported accuracy impact and hardware support.

Latest news on this topic

Recent papers

  • LazyWeights: Decode-on-Demand Edge LLMs

    A. Sanyal, G. Datta, S. P. Chinchali · arXiv cs.LG · digest

    Rather than invent a new quantisation format, this paper keeps GPTQ, AWQ and llama.cpp K- and I-quants, tunes GPTQ so its integer codes compress well, then Huffman-codes them losslessly and decodes them on demand in a small hardware unit between DRAM and L2, leaving GPU kernels untouched. At 1 per cent and 3.5 per cent perplexity budgets the coded Phi-3-mini, Mistral-7B and SmolLM-1.7B are 5.7 to 31.4 per cent smaller than the best llama.cpp format. A bit-exact 0.21 square millimetre decoder at 1 GHz on a 7 nm process cuts per-token latency and energy on a Jetson Orin Nano Super by up to 36 and 38 per cent, and a 4 GB Jetson Nano runs a streamed Mistral-7B 6.6 times faster at 3.89 bits per weight. The hardware unit is a proposal validated on a Zynq UltraScale+ FPGA, so the gains need new silicon or an FPGA companion to realise.

  • KernelMosaic: An Open Dataset and Agentic Framework for CUDA Kernel Generation

    N. Xi, Y. Lai, N. Miao · arXiv cs.LG · digest

    KernelMosaic is an open dataset of CUDA tasks paired with verified solutions and the reasoning trajectories that produced them, curated by human review and diversity-aware selection. An agentic framework walks a strong LLM through implementation, correctness fixes and performance tuning to generate the trajectories. Fine-tuning a small open-source model on the dataset substantially raises correctness on KernelBench Levels 1, 2 and 3 and increases the share of generated kernels that beat PyTorch eager execution. The authors also report that supervising on trajectories beats supervising on final answers alone. The abstract gives no absolute numbers and the release is under CC BY-NC-ND 4.0, which restricts commercial reuse of the data.