Skip to content

Intermediate and advanced kernel workshops

You can now write a masked row reduction. The next step is to support real tensor layouts, derive a backward pass, fuse a useful operation, and handle computations too large to keep in one program. These six workshops provide that progression.

Each has a lesson, a starter, a separately implemented answer and named checks. Every GPU starter begins with a commented outline: the kernel signature, which arguments are compile-time constants, and the wrapper steps. Use it as scaffolding or delete it for more challenge. Unfamiliar terms are in the glossary. The checked answers are working code. Your starters are deliberately unfinished. The validation and measured results show what was actually executed, including slow cases.

Choose your level

Level Workshop Prerequisite Deliverable
Intermediate I1 Strided softmax Beginner strides + Triton softmax Correct transposes/slices; compare direct access with copying
Intermediate I2 Softmax backward Softmax + basic derivatives Explicit vector-Jacobian product, checked against autograd
Intermediate I3 GEMM with bias and ReLU Beginner GEMM + reductions Fused epilogue and a grouped tile sweep
Advanced A1 Online normalization Stable softmax CPU merge state that survives a changing maximum
Advanced A2 Wide-row split softmax A1 + masked Triton reductions Three ordered kernels with per-call scratch
Advanced A3 Streaming attention I3 + A1; A2 helpful Tiled causal/noncausal attention without a full score tensor

Budget 2-4 focused sessions for each intermediate workshop and 3-5 for each advanced workshop. A session is 60-90 minutes. These are suggested study times, not a deadline or a claim that completing six exercises makes a production expert.

Run from the repo root

The CPU workshop needs only Python's standard library:

python -S -m learning.workshops.check --list
python -S -m learning.workshops.check online_normalizer --hint
# Edit learning/workshops/exercises/online_normalizer.py first:
python -S -m learning.workshops.check online_normalizer

The CPU workshop runs in any PowerShell or WSL terminal. GPU workshops run in the GPU environment from the setup guide, PowerShell or WSL; activate it as described in every new terminal. Check the environment with the reference answer first; it should pass:

python -m learning.workshops.check strided_softmax --solution

Then work on your own file:

python -m learning.workshops.check strided_softmax --hint
python -m learning.workshops.check strided_softmax
python -m learning.workshops.check all --level intermediate --include-gpu
python -m learning.workshops.check all --level advanced --include-gpu
# Opt in to checking the supplied answers instead of your work:
python -m learning.workshops.check all --include-gpu --solution

all runs CPU workshops unless --include-gpu is given. A specifically named GPU workshop always attempts GPU execution. No selected work or unavailable dependencies return exit code 3; TODO returns 2; wrong answers return 1. The runner never marks skipped work as complete and never overwrites starters.

Measure after correctness passes

# Defaults to YOUR implementation; --solution explicitly selects reference code.
python -m learning.workshops.benchmark --op strided_softmax --output results/local/i1.json
python -m learning.workshops.benchmark --op all --solution --timing graph --output results/local/workshops-graph.json
python -m learning.workshops.benchmark --op all --solution --timing events --output results/local/workshops-events.json

Each operation has two fixed reproducible shapes. JSON includes raw samples, errors against a double-precision oracle, configuration labels, environment and source hashes. The main softmax backward baseline is an eager FP32 expression; the attention baseline is PyTorch SDPA with automatic backend selection. GEMM uses an FP32 expression to preserve the one-rounding epilogue contract. Read the individual lesson before interpreting a speedup: these baselines differ.

Graph timing measures warmed captured execution. Event timing surrounds repeated Python calls and can include GPU idle time caused by host dispatch. Neither is end-to-end model latency. Copies inside a callable are timed in both modes. Allocations are timed only with --timing events: graph capture serves torch.empty from the graph's memory pool, so replay never pays allocator cost. Compare allocation strategies with events timing. Compilation is warmed up before measurement.

Use the experiment worksheet and capstones to record your work, then compare with the answer explanations. Reference results validate the course; they are not evidence that you personally completed it.

Scope and contracts

All GPU functions allocate fresh contiguous outputs on the input device. Inputs must be NVIDIA CUDA tensors with supported floating dtypes and finite values, and must not require gradients while autograd is enabled. Values must keep the stated FP32 intermediates finite. Wrappers validate metadata but do not scan values, which would add extra GPU work. Tensor address spans and allocated output element counts must fit signed 32-bit indexing.

Function Input and options Output and limits
strided_softmax.softmax 2D FP32/FP16/BF16; nonnegative strides, including zero strides; num_warps=4/8 Same shape/dtype; 1-8192 columns; empty row count allowed
softmax_backward.backward Matching 2D y/g; same dtype/device; each may have different strides; num_warps=4/8 VJP using the supplied y; same limits as I1; no autograd registration
fused_gemm.matmul_bias_relu Contiguous A[M,K], B[K,N], bias[N]; FP16/BF16; same dtype/device; group_m=1/4/8, tile_m=16/32/64 FP32 accumulation + bias + ReLU, then one output cast; all zero dimensions allowed
split_softmax.softmax Contiguous 2D FP32/FP16/BF16; chunk_size=256/1024/4096 Same shape/dtype; 1-131072 columns; empty row count allowed
streaming_attention.attention Contiguous matching Q/K/V[N,D], FP16/BF16; causal bool, block_n=32/64 Same shape/dtype; N=0-2048, D=16/32/64; scale=1/sqrt(D), diagonal included when causal

Attention is single-head self-attention, forward only, without dropout, padding lengths, arbitrary masks, cross-attention or batching. P is converted to input precision for the PV dot product. Causal masking currently traverses every key tile, including future tiles: it teaches correctness, not an optimal causal schedule. These limitations are explicit extension opportunities, not implemented features.

Back to the beginner course or portfolio.