The project has three execution layers: a CPU-first educational Matrix path,
a backend-aware BackendMatrix path, and a rank-aware f32 Tensor runtime.
Only the latter two can select a GPU. A value having type Tensor makes its
operations backend-neutral; it does not by itself prove that a GPU was selected.
src/matrix.zigpowers the high-levelNetwork,Layer, training experiments, and default inference helpers.src/backend.zig,src/cpu_backend.zig,src/metal_backend.zig,src/cuda_backend.zig, andsrc/rocm_backend.zigpower the backend-awareBackendMatrixAPI. CUDA and ROCm share their buffer, batching, fallback, and operation orchestration insrc/compiled_gpu_backend.zig; their public modules retain the vendor ABI adapters and error identities.- Metal support is available for backend matrix operations on macOS.
- CUDA support is available for backend matrix operations on Linux with the NVIDIA driver, CUDA toolkit headers, and NVRTC libraries available.
- ROCm support is available for backend matrix operations on Linux with AMD ROCm HIP, HIPRTC, and rocBLAS libraries available.
Network.forwardBackendandNetwork.predictBackendcan run inference withBackendMatrixinputs through the selected backend.Network.trainBatchBackendandNetwork.trainBackendcan train withBackendMatrixinputs and targets through the selected backend.BackendNetworksnapshots can run repeated backend inference without re-copying CPU parameters on every forward pass.BackendTrainercan train standard and gated networks while keeping trainable parameters on the backend across batches.BackendTraineruses plain SGD by default and can keep momentum optimizer state on the backend throughNetwork.backendTrainerWithOptimizer.- The default
Network.trainBatchandNetwork.trainmethods still use the CPUMatrixpath. Network.trainBatchBackendandNetwork.trainBackendremain available for direct CPU-owned backend training calls.Device,Tensor, andExecutionContextprovide the backend-neutral f32 runtime for rank-aware model code. Explicitmetal,cuda, androcmselections fail when unavailable; onlyautomay fall back to CPU.Modules.MlpandTraining.Optimizerkeep forward/backward tensors, optimizer moments, gradient accumulation, clipping, and parameter updates on the selected backend.- The optimizer, padding-mask, Word2Vec, text-classifier, autoencoder, GRU, Transformer encoder, Seq2Seq, semantic-search, and DQN lessons use that device path. Their experiments report training-time readbacks so unintended host boundaries remain visible.
- Batched matmul, masked softmax and its backward pass, split/merge-head transforms, embedding gradients, cross-attention, and symmetric InfoNCE are composed through the tensor runtime. Native Metal, CUDA, and ROCm kernels or vendor GEMM paths execute them when that backend is enabled and selected.
- Tokenization, BPE merge learning, CRF inference/training, and next-token sampling are discrete host algorithms. Semantic-search top-k ranking also runs on the host after one explicit embedding readback.
Spatial.Conv2dand max pooling are intentionally CPU-first reference implementations. Their matching CNN lesson prioritizes readable indexing and gradients over accelerator kernels.- DQN runs its MLP updates on the selected backend but intentionally reads Q values to the host for environment actions and Bellman-target construction. The experiment reports this boundary instead of presenting it as device-resident.
Transformer.Decoderkeeps embeddings, decoder blocks, optimizer updates, and KV caches on one backend. Linear/GELU/layer-normalization, causal attention, their backward passes, and embedding gradients have native Metal, CUDA, and ROCm kernels.ExecutionContext.beginBatchandendBatchform an explicit synchronization boundary. Runtime telemetry reports allocations, transfers, kernels, vendor GEMMs, and synchronizations so tests can catch accidental host round trips.
TinyGPT checkpoint/config/model logic now lives in the reusable library, while
the experiment paths remain compatibility adapters. Inference.TextSession
loads existing TGPT v1–v3 files, splits their combined QKV weights into a
device decoder once, and keeps that decoder, its KV cache, and sampling buffers
alive across generation calls. Serving does not rebuild or re-upload the model
for each request.
Run full-model SGD training on the automatically selected backend:
zig build run_tiny_gpt -Dgpu=auto -- \
--train-full --backend auto --optimizer sgd --full-batch-size 1 \
--weight-decay 0 --no-corpus-priorUse --backend metal, --backend cuda, or --backend rocm to require that
exact accelerator. Device training currently supports SGD, one context window
per update, and no weight decay. AdamW, gradient accumulation, and multi-window
device batches remain on the CPU educational trainer for now.
With --no-corpus-prior, backend-selected generation uses per-layer KV caches.
The cache appends projected keys and values in place and replays the current
window only when context rollover is required.
The CPU backend packs persistent inference weights into vector-width-padded
rows, reuses a bounded intermediate-matrix workspace, vectorizes f32 linear
accumulation, and fuses linear-plus-bias-plus-GELU. Wide layers can opt into
deterministic parallel output-column tiles with
SessionOptions.cpu_output_tiles; the default is one. The readable scalar and
unfused paths remain numerical references. Live-buffer, physical-storage,
transfer, kernel, GEMM, and synchronization assertions make steady-state
allocation or host-boundary regressions testable.
Use the same selection rules through the CLI:
nnctl serve --model tiny-gpt.bin --gpu auto
nnctl chat --model tiny-gpt.bin --gpu metalAn explicit accelerator must be both compiled and available; it never silently
becomes CPU. Only auto permits that fallback.
On macOS, run:
zig build -Dgpu=metal test-metal_backend --summary all
zig build -Dgpu=metal run_gpuTo compare Metal against CPU matrix multiplication:
zig build run_gpu_benchmark -Dgpu=metal -Doptimize=ReleaseFastThe benchmark prints CPU timing, Metal timing, speedup, and a small sampled
error check. It also supports --format ndjson for the browser learning lab,
where synchronized median timings and runtime counters are rendered together.
The lab uses native Metal compute and does not substitute browser WebGPU.
On Linux with an NVIDIA GPU and CUDA toolkit, run:
zig build -Dgpu=cuda test-cuda_backend --summary all
zig build -Dgpu=cuda run_gpuIf CUDA is installed somewhere other than /usr/local/cuda, pass the toolkit
root explicitly:
zig build -Dgpu=cuda -Dcuda-path=/opt/cuda test-cuda_backend --summary allTo compare CUDA against CPU matrix multiplication:
zig build run_gpu_benchmark -Dgpu=cuda -Doptimize=ReleaseFastOn Linux with an AMD GPU and ROCm toolkit, run:
zig build -Dgpu=rocm test-rocm_backend --summary all
zig build -Dgpu=rocm run_gpuIf ROCm is installed somewhere other than /opt/rocm, pass the toolkit root
explicitly:
zig build -Dgpu=rocm -Drocm-path=/path/to/rocm test-rocm_backend --summary allTo compare ROCm against CPU matrix multiplication:
zig build run_gpu_benchmark -Dgpu=rocm -Doptimize=ReleaseFastThe broader benchmark suite emits cpu, metal, cuda, and rocm rows. On
machines without a particular GPU backend, that backend is reported as skipped.
On non-macOS targets, or when GPU support is not enabled, use the normal CPU test paths:
zig build test --summary all
zig build test-acceptance --summary allThe low-level generic backend factory can fall back to CPU while probing.
Tensor.Device rejects that fallback for explicit metal, cuda, and rocm
preferences; only auto accepts it.
Use nnctl doctor to print local tool versions, platform-specific backend
availability, and the exact Metal/CUDA/ROCm verification commands for the
current machine.
Use BackendMatrix when testing backend behavior directly. Use
Network.forwardBackend, Network.predictBackend, BackendNetwork,
BackendTrainer, Network.backendTrainerWithOptimizer,
Network.trainBatchBackend, or Network.trainBackend when testing
backend-aware network execution. Use Matrix, Network.forward, and the
default training methods when working on the learning-oriented CPU path.
The next backend optimization targets are mixed precision, dynamic sequence batches, fused/tiled attention, accelerator-native top-k, and spatial kernels. The current kernels prioritize explicit, testable semantics over peak hardware throughput.