🏠 Home ⚡ Features 📚 API Reference 💡 Examples 📦 Installation 📋 Changelog
📚 API Reference

Complete API Documentation

Every class, function, and parameter — fully documented with code examples.

🧮 Tensors

lm.Tensor is the core data structure — an N-dimensional array with automatic gradient tracking.

lm.Tensor(data, requires_grad=False, device='cpu', name=None, persistent=False)
ParameterTypeDescription
datalist / ndarray / scalarThe underlying data
requires_gradboolEnable gradient computation. Default False.
devicestr'cpu' (Raspberry Pi optimized)
namestrMemory management identifier
persistentboolPrevent automatic LRU cleanup

Factory Functions

python
import lowmind as lm

lm.zeros(3, 4)          # shape (3,4) filled with 0
lm.ones(2, 2)           # shape (2,2) filled with 1
lm.randn(10, 10)        # random normal
lm.rand(5, 5)           # random uniform [0,1]
lm.arange(0, 10, 2)    # [0, 2, 4, 6, 8]
lm.from_numpy(arr)      # wrap a numpy array

Arithmetic Operations

python
a + b    # addition (with autograd)
a - b    # subtraction
a * b    # element-wise multiply
a / b    # element-wise divide
a ** 2   # power
a @ b    # matrix multiply
-a       # negation

Reduction Methods

python
x.sum()                         # scalar sum
x.sum(axis=0)                   # axis-wise sum
x.sum(axis=1, keepdims=True)   # keepdims
x.mean()                         # scalar mean
x.mean(axis=(2, 3))              # tuple axis (CNN global pooling)
x.max(axis=1)                   # row-wise max
x.min()                          # global min

Shape Operations

python
x.reshape(6, 4)             # reshape
x.flatten(start_dim=1)       # flatten from dim 1
x.transpose((0, 2, 1))       # permute axes
x.T                           # transpose last two dims
x.squeeze(axis=1)             # remove size-1 dims
x.unsqueeze(axis=0)           # add new dim
x[0]                          # index (gradient flows through)

Utility Properties & Methods

python
t.shape         # shape tuple
t.ndim          # number of dimensions
t.size          # total number of elements
t.dtype         # numpy dtype (float32)
t.item()        # extract Python scalar
t.numpy()       # get underlying numpy array
t.detach()      # new tensor without grad tracking
t.copy()        # full copy including grad
t.zero_grad()   # fill grad with zeros
🔄 Autograd
python
# Compute dy/dx at x=3 for y = x² + 2x + 1
x = lm.Tensor(3.0, requires_grad=True)
y = x**2 + 2*x + 1
y.backward()
print(x.grad)   # 8.0  (dy/dx = 2x+2 = 8)

# Gradient clipping
lm.clip_grad_norm(model.parameters(), max_norm=1.0)

# Disable autograd for inference (v2.1)
with lm.no_grad():
    out = model(X_test)

# As decorator
@lm.no_grad
def predict(model, x):
    return model(x)
🏗️ Module Base Class
python
# All layers subclass lm.Module
class MyBlock(lm.Module):
    def __init__(self, in_f, out_f):
        super().__init__()
        self.fc = lm.Linear(in_f, out_f)
        self.bn = lm.BatchNorm1d(out_f)

    def forward(self, x):
        return self.bn(self.fc(x)).relu()

model.parameters()        # generator of all params
model.named_parameters()  # generator of (name, param)
model.train()             # set training mode
model.eval()              # set eval mode (disables Dropout)
model.num_parameters()    # total trainable param count
model.summary()           # print architecture table
model.state_dict()        # dict of weight arrays
model.load_state_dict(sd)  # restore from dict
model.save('/path/model.lmz')   # save (gzip)
model.load('/path/model.lmz')   # load
⬛ Layers
lm.Linear(in_features, out_features, bias=True)

Fully-connected layer. Input: (N, in_features) → Output: (N, out_features)

lm.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, bias=True)

2D convolution with im2col-based backward. Input: (N, C, H, W) → Output: (N, out_channels, H', W')

python
conv = lm.Conv2d(3, 32, kernel_size=3, padding=1)
# Input (N, 3, H, W) → Output (N, 32, H, W)
lm.BatchNorm1d(num_features) / lm.BatchNorm2d(num_features)

Batch normalization with learnable gamma/beta and running stats for eval mode.

lm.MaxPool2d(kernel_size, stride=None) / lm.AvgPool2d(kernel_size)

Spatial pooling. Default stride equals kernel_size. Halves H and W when kernel_size=stride=2.

lm.Dropout(p=0.5)

Randomly zeros elements with probability p during training. Disabled automatically in eval mode.

lm.Embedding(num_embeddings, embedding_dim)

Learnable lookup table. Input: integer indices → Output: (len(indices), embedding_dim)

lm.LSTM(input_size, hidden_size, num_layers=1, dropout=0.0) v2.1

Long Short-Term Memory with multi-layer and dropout support.

lm.GRU(input_size, hidden_size, num_layers=1, dropout=0.0) v2.1

Gated Recurrent Unit. Lighter than LSTM with comparable performance for many tasks.

⚡ Activations

Can be used as layer classes in Sequential or called as methods on Tensors.

python
# As layers in Sequential
model = lm.Sequential(lm.Linear(128, 64), lm.ReLU())

# As Tensor methods
x.relu()
x.sigmoid()
x.tanh()
x.leaky_relu(alpha=0.01)
x.elu(alpha=1.0)
x.gelu()
x.softmax(axis=-1)

# Layer classes
lm.ReLU()       lm.LeakyReLU(negative_slope=0.01)
lm.ELU()        lm.GELU()
lm.Sigmoid()    lm.Tanh()
lm.Softmax(axis=-1)    lm.LogSoftmax(axis=-1)
📋 Sequential
python
from collections import OrderedDict

# Positional
model = lm.Sequential(
    lm.Linear(784, 256),
    lm.ReLU(),
    lm.BatchNorm1d(256),
    lm.Dropout(0.3),
    lm.Linear(256, 10),
)

# Named (OrderedDict)
model = lm.Sequential(OrderedDict([
    ('fc1',  lm.Linear(784, 256)),
    ('relu', lm.ReLU()),
    ('fc2',  lm.Linear(256, 10)),
]))

print(model)              # shows architecture
model.num_parameters()   # total trainable params
📉 Loss Functions

All loss functions return a scalar Tensor with requires_grad=True.

python
# Cross Entropy — logits (N,C), targets (N,) int
loss = lm.cross_entropy_loss(logits, targets)
loss = lm.cross_entropy_loss(logits, targets, reduction='sum')

# Binary Cross Entropy
loss = lm.binary_cross_entropy_loss(output, targets)
loss = lm.binary_cross_entropy_loss(logits, targets, from_logits=True)

# MSE — regression
loss = lm.mse_loss(predictions, targets)

# MAE — outlier-robust
loss = lm.mae_loss(predictions, targets)

# Huber (smooth L1) — quadratic near 0, linear for outliers
loss = lm.huber_loss(predictions, targets, delta=1.0)

# NLL — use after LogSoftmax
log_probs = lm.LogSoftmax()(logits)
loss = lm.nll_loss(log_probs, targets)
⚙️ Optimizers
New in v2.1: All optimizers support parameter groups — pass a list of dicts with per-group lr/weight_decay, same as PyTorch.
python
# Standard interface for all optimizers
optimizer.zero_grad()   # reset gradients
loss.backward()         # compute gradients
optimizer.step()        # update weights

# SGD with Nesterov momentum
opt = lm.SGD(model.parameters(), lr=0.01,
            momentum=0.9, weight_decay=1e-4, nesterov=True)

# Adam
opt = lm.Adam(model.parameters(), lr=1e-3,
             betas=(0.9, 0.999), amsgrad=False)

# AdamW (decoupled weight decay)
opt = lm.AdamW(model.parameters(), lr=1e-3, weight_decay=0.01)

# RMSprop
opt = lm.RMSprop(model.parameters(), lr=1e-3, alpha=0.99)

# AdaGrad
opt = lm.AdaGrad(model.parameters(), lr=0.01)

# Parameter groups (v2.1)
opt = lm.Adam([
    {'params': backbone.parameters(), 'lr': 1e-4},
    {'params': head.parameters(), 'lr': 1e-3},
])
📅 LR Schedulers
python
# StepLR — decay every N epochs
scheduler = lm.StepLR(optimizer, step_size=10, gamma=0.5)

# CosineAnnealingLR — smooth decay
scheduler = lm.CosineAnnealingLR(optimizer, T_max=50, eta_min=1e-6)

# ReduceLROnPlateau — reduce when stuck
scheduler = lm.ReduceLROnPlateau(
    optimizer, mode='min', patience=5, factor=0.5)
scheduler.step(val_loss)   # pass the metric

# MultiStepLR
scheduler = lm.MultiStepLR(optimizer, milestones=[30, 60, 90], gamma=0.1)

# LinearWarmupLR
scheduler = lm.LinearWarmupLR(optimizer, warmup_steps=1000, target_lr=1e-3)

# CyclicLR — call per batch
scheduler = lm.CyclicLR(optimizer, base_lr=1e-4, max_lr=1e-1,
                        step_size=2000, mode='triangular')

# LR Finder (v2.1) — auto-detect optimal LR
finder = lm.LRFinder(model, optimizer, loss_fn)
best_lr = finder.find(train_loader)
📦 Data Utilities
python
# TensorDataset
ds = lm.TensorDataset(X_train, y_train)
X, y = ds[0]             # first sample

# Custom Dataset
class MyDataset(lm.Dataset):
    def __len__(self): return len(self.X)
    def __getitem__(self, idx): return self.X[idx], self.y[idx]

# DataLoader
loader = lm.DataLoader(ds, batch_size=64, shuffle=True, drop_last=False)
for X_b, y_b in loader: pass

# train_test_split
X_tr, X_val, y_tr, y_val = lm.train_test_split(
    X, y, test_size=0.2, shuffle=True, seed=42
)

# Data Transforms (v2.1)
transform = lm.Compose([
    lm.Normalize(mean=0.5, std=0.5),
    lm.RandomHorizontalFlip(p=0.5),
    lm.RandomCrop(size=28),
    lm.GaussianNoise(std=0.1),
])
📊 Metrics
python
# All metrics accept Tensors or numpy arrays

# Classification
lm.accuracy(predictions, targets)
lm.top_k_accuracy(logits, targets, k=5)
lm.precision(logits, targets, num_classes=10)
lm.recall(logits, targets, num_classes=10)
lm.f1_score(logits, targets, num_classes=10)
lm.confusion_matrix(logits, targets)  # → (C, C) ndarray

# average='macro' (default), 'micro', or 'none' (per class)
per_class_f1 = lm.f1_score(logits, targets,
                           num_classes=10, average='none')

# Regression
lm.r2_score(predictions, targets)
lm.mean_squared_error(predictions, targets)
lm.mean_absolute_error(predictions, targets)
🏋️ Trainer
python
trainer = lm.Trainer(
    model=model,
    optimizer=lm.Adam(model.parameters(), lr=1e-3),
    loss_fn=lm.cross_entropy_loss,
    callbacks=[lm.EarlyStopping(patience=10)],
    clip_grad=1.0,            # gradient norm clipping
    grad_accum_steps=4,       # gradient accumulation (v2.1)
    verbose=1,                 # print every N epochs
)

# Train
history = trainer.fit(train_loader, val_loader, epochs=100)
# → {'train_loss': [...], 'val_loss': [...], 'val_acc': [...]}

# Evaluate
val_loss, val_acc = trainer.evaluate(val_loader)

# Inference
preds = trainer.predict(X_test)        # class indices
probs = trainer.predict_proba(X_test)  # softmax probs (v2.1)
🔔 Callbacks
python
# EarlyStopping
lm.EarlyStopping(patience=10, min_delta=1e-4,
                 mode='min', verbose=True)

# ModelCheckpoint
lm.ModelCheckpoint(filepath='/tmp/best.lmz',
                   monitor='val_loss', mode='min',
                   save_best_only=True, verbose=True)

# LRSchedulerCallback
sched = lm.ReduceLROnPlateau(optimizer, patience=5)
lm.LRSchedulerCallback(sched, monitor='val_loss')

# History
history_cb = lm.History()
# After training:
history_cb.history['train_loss']
🤖 Pre-built Models
python
# MicroMLP — tabular/flat data
model = lm.MicroMLP(
    input_size=784,
    hidden_sizes=[256, 128],
    output_size=10,
    dropout=0.3,
)

# MicroCNN — small images (32×32)
model = lm.MicroCNN(
    in_channels=3,     # 3=RGB, 1=grayscale
    num_classes=10,
    input_size=32,
    dropout=0.2,
)

# TinyResNet — residual connections
model = lm.TinyResNet(
    in_channels=3,
    num_classes=10,
    input_size=32,
    base_filters=16,  # use 8 for very constrained devices
)
🖥️ System Monitor
python
# Configure memory limit
lm.configure_memory(max_mb=256)

# System health monitor
monitor = lm.SystemMonitor()
monitor.print_status()       # print CPU/RAM/temp
score = monitor.health_score()   # 0-100
stats = monitor.get_stats()      # dict of all stats

# Trace memory for a code block
with lm.memory_trace("Forward Pass"):
    out = model(X)

# Memory manager
lm.memory_manager.optimize_for_inference()
lm.memory_manager.free_unused()
info = lm.memory_manager.get_memory_info()

# Model Profiler (v2.1)
profiler = lm.ModelProfiler(model)
profiler.profile(input_shape=(1, 784))  # params, FLOPs, memory
🎯 Weight Initialization v2.1
python
import lowmind.init as init

# Apply to individual parameter
init.xavier_uniform_(layer.weight)
init.xavier_normal_(layer.weight)
init.kaiming_uniform_(layer.weight, mode='fan_in')
init.kaiming_normal_(layer.weight)
init.orthogonal_(layer.weight)
init.normal_(layer.weight, mean=0, std=0.01)
init.zeros_(layer.bias)

# Apply to whole module recursively
init.init_module(model, method='xavier_uniform')