Tutorial — Image Classification with SNEPPX¶
Notebook: classification.ipynb
(download)
What you'll build¶
A small MLP classifier trained on synthetic 8×8 image data, using the
SNEPPX nn module and AdamW optimizer. You'll see how Tensor operator
overloads, Linear, LayerNorm, and CrossEntropyLoss compose, and how to
log loss with the built-in Profiler.
Setup¶
$env:PYTHONPATH = "bindings/python"
import numpy as np
from SneppX_ALG import (
Tensor, Module, Sequential, Linear, LayerNorm, GELU, Dropout,
AdamW, CrossEntropyLoss, CosineAnnealingLR, Profiler, Timer,
)
HAS_C = __import__("SneppX_ALG")._HAS_C_BACKEND
1. Synthetic data¶
We use 8×8 "images" with 10 classes:
def make_data(n=640):
rng = np.random.default_rng(0)
X = rng.standard_normal((n, 64)).astype(np.float32)
y = rng.integers(0, 10, size=(n,)).astype(np.int64)
return Tensor.from_numpy(X), Tensor.from_numpy(y)
2. The model¶
class Classifier(Module):
def __init__(self, in_dim=64, hidden=128, classes=10):
super().__init__()
self.net = Sequential(
Linear(in_dim, hidden), GELU(),
LayerNorm(hidden),
Linear(hidden, hidden), GELU(),
Dropout(0.1),
Linear(hidden, classes),
)
def forward(self, x):
return self.net(x)
model = Classifier()
3. Train (needs C backend for backward)¶
X, y = make_data()
opt = AdamW(model.parameters(), lr=2e-3, weight_decay=1e-4)
sched = CosineAnnealingLR(opt, min_lr=1e-5, max_lr=2e-3, total_steps=200)
prof = Profiler(enabled=True)
for step in range(200):
idx = np.random.randint(0, X.shape[0], 64)
xb, yb = X[idx], y[idx]
with Timer(prof, "forward"):
logits = model(xb)
loss = CrossEntropyLoss()(logits, yb)
if not HAS_C:
print("C backend not available — skipping backward/step")
break
opt.zero_grad(); loss.backward(); opt.step(); sched.step()
if step % 25 == 0:
print(step, loss.item())
prof.print_summary()
4. Evaluate¶
def accuracy(model, X, y, batch=128):
if not HAS_C:
return 0.0
correct = 0
for i in range(0, len(X), batch):
preds = model(X[i:i+batch]).data.argmax(-1)
correct += (preds == y[i:i+batch].data).sum()
return correct / len(X)
print("accuracy:", accuracy(model, X, y))
Key takeaways¶
Tensoroverloads+,@,*— write math, notmatmul()calls.Linearuses PyTorch layout(out, in)weight, i.e.x @ W.T + b.CrossEntropyLossexpects logits of shape(N, C)and targets(N,).- Without the C backend,
backward()/step()are unavailable — build the extension first (cmake --build build --config Release).
Next steps¶
- Swap
ClassifierforTransformer(see Generation). - Add
DistributedWrapperfor multi-GPU (see Distributed Training).