netcl wiki
main

Quickstart Guide

Quickstart Guide

This guide takes you from a clean installation to a working netcl training loop in under ten minutes. It assumes basic familiarity with Python and NumPy.


Prerequisites

  • Python 3.9 or newer: netcl relies on modern Python features including structural pattern matching.
  • An OpenCL driver for your hardware:
  • Linux: Install your vendor ICD (intel-opencl-icd, mesa-opencl-icd, or amdgpu-pro).
  • Windows: Included with standard GPU display drivers from AMD, Intel, or NVIDIA.
  • macOS: Built into the operating system OpenCL framework.
  • CPU fallback: If no GPU is present or pyopencl is not installed, netcl automatically falls back to its NumPy CPU backend.

Installation

python3 -m venv .venv
source .venv/bin/activate        # On Windows: .venv\Scripts\activate
pip install netcl

10-Second Smoke Test

Verify that netcl can discover your device and execute a matrix multiplication kernel:

import numpy as np
from netcl.core.device import manager
from netcl.core.tensor import Tensor

dev = manager.default("auto")
q = dev.queue
print(f"Device: {dev.device_name} (Backend: {dev.backend})")

# Allocate two identity matrices on the device
a = Tensor.from_host(q, np.eye(4, dtype=np.float32))
b = Tensor.from_host(q, np.eye(4, dtype=np.float32))
out = a @ b

print("Result shape:", out.shape)
assert np.allclose(out.to_host(), np.eye(4))
print("Smoke test passed successfully.")

Expected output: Backend: cl (or cpu if running on CPU fallback).


Your First Device Tensor

In netcl, Tensor.from_host copies data from host RAM to GPU device memory (cl_mem). The method .to_host() transfers the data back into a NumPy array. While resident on the device, all mathematical operations execute as OpenCL GPU kernels:

import numpy as np
from netcl.core.device import manager
from netcl.core.tensor import Tensor

q = manager.default("auto").queue

# Move data to GPU
a = Tensor.from_host(q, np.arange(12, dtype=np.float32).reshape(3, 4))
b = Tensor.from_host(q, np.ones((3, 4), dtype=np.float32))

print(f"Shape: {a.shape}, Dtype: {a.dtype}, Backend: {a.backend}")

# Elementwise addition executes entirely on the GPU
c = a + b

# Transfer result back to host RAM for inspection
print(c.to_host())

Complete Training Loop

The script below trains a 3-layer Multi-Layer Perceptron (MLP) on synthetic classification data. It demonstrates the standard netcl training pattern: model construction, the autograd Tape, gradient clipping, optimizer step, and scalar loss extraction.

import numpy as np
import netcl.autograd as ag
from netcl.core.device import manager
from netcl.core.tensor import Tensor
from netcl.nn import Linear, ReLU, Dropout, Sequential
from netcl.optim import AdamW, CosineAnnealingLR, clip_grad_norm

dev = manager.default("auto")
q = dev.queue

# 1. Define network architecture
model = Sequential(
    Linear(q, 16, 64), ReLU(), Dropout(p=0.1),
    Linear(q, 64, 64), ReLU(),
    Linear(q, 64, 4),
)
opt = AdamW(model.parameters(), lr=1e-3, weight_decay=1e-4)
sched = CosineAnnealingLR(max_lr=1e-3, min_lr=1e-5, T_max=10)

# 2. Synthetic dataset: 512 samples, 16 features, 4 classes
rng = np.random.default_rng(42)
x_all = rng.standard_normal((512, 16)).astype(np.float32)
y_all = rng.integers(0, 4, size=512).astype(np.int32)

# 3. Training epochs
for epoch in range(10):
    epoch_losses = []
    for i in range(0, 512, 64):
        x = Tensor.from_host(q, x_all[i:i+64])
        y = Tensor.from_host(q, y_all[i:i+64])

        # Active Tape records operations for autograd
        with ag.Tape() as tape:
            # Wrap raw tensors into graph Nodes
            x_node = ag.tensor(x)
            y_node = ag.tensor(y)
            logits = model(x_node)
            loss = ag.cross_entropy(logits, y_node)

        # Backpropagation and optimizer update
        tape.backward(loss)
        clip_grad_norm(model.parameters(), max_norm=1.0)
        opt.step()
        opt.zero_grad()

        epoch_losses.append(loss.value.to_host()[0])

    opt.lr = sched.step()
    mean_loss = float(np.mean(epoch_losses))
    print(f"Epoch {epoch+1:2d}: Mean Loss = {mean_loss:.4f}, LR = {opt.lr:.2e}")

Saving and Loading Models

NetCL provides portable model serialization:

from netcl.io import save_model, load_model

# Save model parameters and architecture configuration
save_model(model, "mlp_classifier.netcl")

# Load model weights back onto the active command queue
restored_model = load_model("mlp_classifier.netcl", queue=q)

For full training checkpoints that preserve optimizer moments, learning rate schedules, and epoch counters, see Checkpointing Concepts.


Key NetCL Concepts to Remember

  1. Explicit Command Queues: OpenCL has no global device context. Pass queue when constructing layers (Linear(q, ...)).
  2. Tensor vs. Node: A Tensor represents raw GPU buffer memory. To track operations for backpropagation, wrap tensors with ag.tensor(x) inside a with ag.Tape(): context.
  3. Extracting Scalars: Output loss is an autograd Node. Access the underlying device tensor via loss.value, then call .to_host() to inspect values in NumPy.
  4. Kernel Compilation Latency: The very first forward pass triggers OpenCL JIT compilation and caches the binary. Subsequent steps run at full hardware speed.

Next Steps