6.2.12GPU Architecture

Tensor cores and matrix operations

3,098 words14 min readdifficulty · medium2 backlinks

What Are Tensor Cores?

How Matrix Multiplication Works (From Scratch)

Figure — Tensor cores and matrix operations

Traditional Approach: Element-by-Element

For C = A × B where A is M×K, B is K×N, C is M×N:

C[i][j]=k=0K1A[i][k]B[k][j]C[i][j] = \sum_{k=0}^{K-1} A[i][k] \cdot B[k][j]

On CUDA cores: Each thread computes one C[i][j] by:

  1. Loading row i of A (K elements)
  2. Loading column j of B (K elements)
  3. Performing K multiply-adds serially
  4. Writing result to C[i][j]

Problem: For 1024×1024 matrices, that's 1024³ ≈ 1 billion FMAs (≈ 2 billion FLOPs). At 10 TFLOPS (10×10¹² FLOPS), that's about 2×109/10130.22\times10^9 / 10^{13} \approx 0.2 ms of pure compute — but memory stalls and poor reuse make the real CUDA-core time much worse.

Tensor Core Approach: Tiled Matrix Operations

Key insight: Break large matrix multiply into small tiles and use specialized hardware for each tile.

Complete Algorithm for Large Matrix Multiply

Problem: Multiply 1024×1024 matrices using 4×4 Tensor Cores.

Solution: Tiled multiply with accumulation

# Pseudocode for C = A × B using Tensor Cores
M, N, K = 1024, 1024, 1024
TILE = 4
 
for i in range(0, M, TILE):          # Tile rows of A
    for j in range(0, N, TILE):      # Tile columns of B
        D_tile = zeros(TILE, TILE)   # Accumulator
        for k in range(0, K, TILE):  # Tile inner dimension
            A_tile = A[i:i+TILE, k:k+TILE]
            B_tile = B[k:k+TILE, j:j+TILE]
            # SINGLE TENSOR CORE INSTRUCTION
            D_tile = mma_sync(A_tile, B_tile, D_tile)
        
        C[i:i+TILE, j:j+TILE] = D_tile

Why this works:

  1. Tiling preserves correctness: Matrix multiply is associative, so we can sum partial products
  2. Each iteration computes a 4×4 partial product: A[i:i+4, k:k+4] × B[k:k+4, j:j+4]
  3. Accumulation in D_tile sums all K/4 partial products for final result
  4. Outer loops cover all tiles of output matrix C

Performance calculation:

  • Scalar FMAs: 1024³ ≈ 1.07 billion FMAs
  • Number of Tensor Core ops: (1024/4)³ = 256³ ≈ 16.8 million
  • Ratio: 10243/2563=43=641024^3 / 256^3 = 4^3 = 6464× instruction reduction compared to scalar (each Tensor Core op does 4×4×4 = 64 FMAs)

Precision Modes and Their Impact

Programming Tensor Cores

WMMA API (Warp-level Matrix Multiply Accumulate)

#include <mma.h>
using namespace nvcuda::wmma;
 
__global__ void matmul_tensor_core(
    half *A, half *B, float *C, int M, int N, int K) {
    // Each warp computes a 16×16 tile of C
    int warpM = (blockIdx.x * blockDim.x + threadIdx.x) / 32;
    int warpN = (blockIdx.y * blockDim.y + threadIdx.y);
    
    // Declare fragments (distributed across warp)
    fragment<matrix_a, 16, 16, 16, half, row_major> a_frag;
    fragment<matrix_b, 16, 16, 16, half, col_major> b_frag;
    fragment<accumulator, 16, 16, 16, float> c_frag;
    fill_fragment(c_frag, 0.0f);  // Initialize accumulator
    
    // Tile K dimension
    for (int i = 0; i < K; i += 16) {
        // Load tiles (each thread gets its portion)
        load_matrix_sync(a_frag, A + warpM*16*K + i, K);
        load_matrix_sync(b_frag, B + i*N + warpN*16, N);
        
        // TENSOR CORE OPERATION
        mma_sync(c_frag, a_frag, b_frag, c_frag);
    }
    
    // Store result
    store_matrix_sync(C + warpM*16*N + warpN*16, c_frag, N, mem_row_major);
}

Why each step?

  • fragment: Data distributed across 32 threads of warp (each thread holds a piece of the tile)
  • load_matrix_sync: Warp-level load, each thread fetches its portion from global memory
  • mma_sync: The Tensor Core instruction — all 32 threads participate cooperatively
  • store_matrix_sync: Warp-level store, accumulator fragment → global memory

cuBLAS and cuDNN Automatic Use

import torch
 
# PyTorch automatically uses Tensor Cores when:
# 1. Input dtype is float16, bfloat16, or TF32
# 2. Dimensions are multiples of 8
# 3. torch.backends.cuda.matmul.allow_tf32 = True (default on Ampere+)
 
A = torch.randn(1024, 1024, dtype=torch.float16, device='cuda')
B = torch.randn(1024, 1024, dtype=torch.float16, device='cuda')
 
# Uses Tensor Cores automatically
C = torch.matmul(A, B)

Why dimensions should be multiples of 8?

  • Tensor Core API tiles are 16×16 (with K in multiples of 8/16 depending on precision)
  • Padding to multiples ensures full tile coverage
  • Partial tiles need fallback handling (performance cliff)

Common Mistakes and Fixes

Performance Characteristics

Memory Layout and Optimization

When to Use Tensor Cores vs CUDA Cores

Scenario Choice Reason
Matrix multiply, M=N=K=4096, FP16 Tensor Cores Perfect fit: large, aligned, FP16
Matrix multiply, M=N=K=32, FP16 CUDA Cores Too small, overhead dominates
Element-wise ops (ReLU, exp) CUDA Cores No matrix structure to exploit
Convolution (large channels) Tensor Cores Conv2D is matrix multiply via im2col
Attention mechanism (Q, K, V) Tensor Cores Multiple batched matmuls
FP64 scientific computing CUDA Cores / FP64 TC Early Tensor Cores lacked FP64
Sparse matrix multiply Special Use Ampere sparse Tensor Cores (2:4 sparsity)
Recall Explain to a 12-Year-Old

Imagine you have a huge pile of homework: 1000 multiplication problems.

CUDA cores are like having a calculator. You solve one problem, write down the answer, solve the next, write that down... It works, but it's slow. Tensor Cores are like having a magic calculator that solves 64 problems at once. You show it a big grid of numbers, and it instantly gives you the whole grid of answers.

But there's a catch: the magic calculator only works if you give it exactly 64 problems arranged in a neat grid. If you give it 7 problems, it can't help — you have to use the regular calculator.

Deep learning (teaching computers to recognize images, understand speech) is FULL of these big grids of multiplication problems. That's why Tensor Cores make AI computers so much faster!

Connections

  • 6.2.1-GPU-vs-CPU-architecture — Why GPUs need specialized units
  • 6.2.8-Memory-hierarchy-in-GPUs — How shared memory enables tiling
  • 6.2.10-Warp-scheduling-and-execution — How warps map to Tensor Core fragments
  • 8.3.4-Mixed-precision-training — Using Tensor Cores in deep learning
  • 8.4.2-Quantization-techniques — INT8 and INT4 Tensor Core modes
  • 9.1.5-Roofline-model — Analyzing Tensor Core performance limits
  • 7.3.6-cuBLAS-and-cuDNN — Libraries that abstract Tensor Core usage

#flashcards/hardware

What is a Tensor Core?
A specialized hardware unit in NVIDIA GPUs that performs matrix multiply-accumulate (MMA) operations on small matrix tiles (internally 4×4, exposed as 16×16 at the API level) in a single instruction, achieving 8-16× higher throughput than CUDA cores for matrix workloads.
What operation does a Tensor Core perform in one instruction?
D = A × B + C, where A, B, C, D are small matrices. Internally a 4×4 sub-multiply does up to 64 multiply-adds per clock.
Why do Tensor Cores use mixed precision (FP16 input, FP32 accumulate)?
FP16 inputs are 2× smaller (better memory bandwidth) and multipliers are smaller (higher compute density), while FP32 accumulation prevents error buildup from summing many low-precision products.
What is the minimum matrix size to efficiently use Tensor Cores?
Approximately 512×512. Smaller matrices have too much overhead relative to compute, and may not saturate the hardware.
Why should matrix dimensions be multiples of 8 or 16 for Tensor Cores?
Tensor Cores operate on fixed API tile sizes (16×16). Non-multiple dimensions require padding or fallback handling, reducing efficiency.
What is the instruction-count reduction from scalar FMAs to 4×4 Tensor Core ops?
64×, because each Tensor Core instruction performs 4×4×4 = 64 FMAs.
What is the correct PTX instruction name for Tensor Core matrix multiply?
mma.sync (exposed in the WMMA API as wmma::mma_sync).
How is a 4×4 Tensor Core sub-multiply distributed across a warp on Volta?
A warp of 32 threads is split into 4 groups of 8 threads; each 4×4 sub-multiply is executed cooperatively by one 8-thread group, not one element per thread.

What is the theoretical speedup of A100 Tensor Cores over CUDA cores? :::

Concept Map

dominated by

slow on

1 FMA per clock

motivates

computes

one instruction

uses

exposed via

issued as

amortizes

evolved across

added precisions

Deep learning

Matrix multiply C = A x B

CUDA cores scalar FMA

Poor throughput

Tensor Core

Matrix multiply-accumulate D = A x B + C

8-16x throughput

Tiled 4x4 sub-partition

WMMA 16x16 API

mma.sync instruction

64 FMAs per instruction

Volta Turing Ampere Hopper

FP16 INT8 TF32 BF16 FP8

Hinglish (regional understanding)

Intuition Hinglish mein samjho

Hinglish (regional understanding)

Intuition Hinglish mein samjho

Dekho, yahan core intuition simple hai: deep learning me sabse zyada kaam matrix multiplication ka hota hai — jaise C = A × B — aur ye kaam bahut bada hota hai, 1000×1000 matrices me billions of multiply-add operations lag jaate hain. Traditional CUDA cores ek clock me sirf ek multiply-add karte hain, matlab har number ko digit-by-digit multiply karne jaisa slow process. Isiliye NVIDIA ne Tensor Cores banaye — ye special fixed-function hardware units hain jo ek hi instruction me pura chhota matrix tile (jaise 4×4) ka multiply-accumulate D = A×B + C kar dete hain. Ek instruction me 64 FMAs, matlab CUDA cores se 8-16× zyada throughput!

Ab kaam kaise hota hai bade matrices ke liye? Simple — bada matrix ko chhote-chhote tiles me tod dete hain, phir har tile pe Tensor Core ka mma_sync instruction chalate hain aur results ko accumulate karte jaate hain (woh tiled loop wala pseudocode yahi kar raha hai). Ek interesting detail ye hai ki Volta me ek warp ke 32 threads ko 4 groups of 8 threads me baanta jaata hai, aur har 4×4 sub-multiply cooperatively 8 threads milke karte hain — har thread apna chhota fragment hold karta hai, aur ye mapping WMMA API internally manage karta hai, humein tension lene ki zaroorat nahi. Alag-alag generations (Volta, Turing, Ampere, Hopper) me precision support badhta gaya — FP16 se lekar INT8, INT4, BF16, TF32, aur FP8 tak.

Ye matter isliye karta hai ki aaj ke saare AI models — chahe woh image recognition ho ya ChatGPT jaise LLMs — inki speed literally Tensor Cores pe depend karti hai. Jab tum sunte ho ki koi GPU "AI ke liye fast" hai, toh mostly uske Tensor Cores ki wajah se hi hai. Agar tum ML ya hardware field me jaana chahte ho, toh ye samajhna zaroori hai ki hardware ko matrix operations ke around specialize karke hi itni bari performance gains milti hai — yahi modern deep learning ka backbone hai.

Go deeper — visual, from zero

Test yourself — GPU Architecture

Connections