BRAIDGROUP
RESEARCH & DEV
68. ML Library Docs

ML Standard Library

The Braid ML standard library (std/ml/) provides high-level building blocks for neural networks, training, optimization, and data processing — all implemented in Braid itself on top of the runtime tensor and autograd primitives.

std/ml/tensor.bd — Tensor Creation Helpers

Convenience functions for creating common tensors:

// Zeros: creates a tensor filled with 0.0
pub fn zeros(shape) {
    let t = std.tensor.create(ndim, shape, 0);
    std.tensor.fill(t, 0.0);
    return t;
}

// Ones: creates a tensor filled with 1.0
pub fn ones(shape) { /* fill with 1.0 */ }

// Randn: normal distribution via Box-Muller
pub fn randn(shape, mean?, stddev?) {
    let u1 = std.math.random();
    let u2 = std.math.random();
    let r = std.math.sqrt(-2.0 * std.math.log(u1 + 0.00001));
    let theta = 6.2832 * u2;
    let val = mean + stddev * r * std.math.cos(theta);
    std.tensor.set_flat(t, i, val);
}

// Arange: evenly spaced values
pub fn arange(start, end, step?) { ... }

std/ml/nn.bd — Neural Network Building Blocks

Wraps autograd operations with sensible defaults:

import std.autograd;

pub fn relu(x)          { return std.autograd.relu(x); }
pub fn gelu(x)          { return std.autograd.gelu(x); }
pub fn sigmoid(x)       { return std.autograd.sigmoid(x); }
pub fn tanh(x)          { return std.autograd.tanh(x); }
pub fn silu(x)          { return std.autograd.silu(x); }
pub fn softmax(x, axis) { /* defaults axis to -1 */ }

// Layer normalization with optional eps (default 1e-5)
pub fn layer_norm(x, gamma, beta, eps) { ... }

// Linear: matmul + bias
pub fn linear(x, weight, bias) {
    let out = std.autograd.matmul(x, weight);
    if bias != nil { out = std.autograd.add(out, bias); }
    return out;
}

// Dropout with default p=0.5
pub fn dropout(x, p, training) { ... }

// Loss functions
pub fn cross_entropy(pred, target)
    { return std.autograd.cross_entropy(pred, target); }

pub fn mse(pred, target) {
    let diff = std.autograd.sub(pred, target);
    let sq = std.autograd.mul(diff, diff);
    return std.autograd.mean(sq, -1);
}

pub fn binary_cross_entropy(pred, target) {
    let log_pred = std.autograd.log(pred);
    let term1 = std.autograd.mul(target, log_pred);
    // ... numerically stable BCE
}

std/ml/train.bd — Training Utilities

import std.autograd;
import std.train;

pub fn dataset(data, labels, batch_size?)  { ... }
pub fn batch(ds)                           { ... }

pub fn train_step(model, loss_fn, optimizer, x, y) {
    let pred = model.forward(x);
    let loss = loss_fn(pred, y);
    std.autograd.backward(loss);
    optimizer.step();
    optimizer.zero_grad();
    return loss;
}

pub fn evaluate(model, eval_fn, data)      { ... }
pub fn accuracy(pred, target)              { ... }

std/ml/optim.bd — Optimizers

import std.optim;

// SGD with optional momentum & weight decay
pub fn sgd(params, lr?, momentum?, weight_decay?) { ... }

// Adam (defaults: lr=1e-3, beta1=0.9, beta2=0.999)
pub fn adam(params, lr?, beta1?, beta2?, eps?, weight_decay?) { ... }

// AdamW with decoupled weight decay (default wd=0.01)
pub fn adamw(params, lr?, beta1?, beta2?, eps?, weight_decay?) { ... }

// Cosine LR scheduler
pub fn cosine_lr(optimizer, total_steps, min_lr?) { ... }

std/ml/data.bd — Data Utilities

import std.collections;

pub fn shuffle(ds, seed?)   { return std.collections.shuffle(ds, seed); }
pub fn batch(ds, size?)     { return std.collections.batch(ds, size); }
pub fn prefetch(ds, n?)     { /* async prefetch (default n=2) */ }
pub fn map(ds, fn)          { /* apply fn to each element */ }

Braid ML Language Features

Model Definitions

The model keyword declares a model configuration that inherits from a base and overrides specific fields:

model MyModel = DefaultConfig {
    d_model: 768
    num_layers: 12
    num_heads: 12
    vocab_size: 50257
}

Autograd Functions (@autograd fn)

Functions marked @autograd automatically track operations for gradient computation. The compiler emits OP_AUTOGRAD_FN opcodes that build the computation graph.

@autograd fn forward(x, weight) {
    return linear(x, weight, nil)
}

Layer Structs (@layer struct)

Layers are structs with @param fields that register parameters for optimization:

@layer struct TransformerBlock {
    @param w_query: Tensor
    @param w_key: Tensor
    @param w_value: Tensor
    @param w_output: Tensor
    @param gamma: Tensor
    @param beta: Tensor

    fn forward(self, x) {
        let ln = layer_norm(x, self.gamma, self.beta, 1e-5)
        let attn = scaled_dot_product_attention(
            matmul(ln, self.w_query),
            matmul(ln, self.w_key),
            matmul(ln, self.w_value),
            nil, 0.0, true)
        return add(x, attn)
    }
}

Device Operations

// Move tensor to device
let x = x.to("cuda")         // OP_TO_DEVICE

// Scoped device context
with device("cuda") {         // OP_WITH_DEVICE
    let y = matmul(a, b)
    // operations inside this block run on GPU
}

Slice Syntax

let x = [[1, 2, 3], [4, 5, 6]]
let row = x[0:1]       // [[1, 2, 3]]
let col = x[0:, 1:2]   // [[2], [5]]
let first = x[0, 0]    // 1

Complete Training Pipeline

import std.ml.tensor
import std.ml.nn
import std.ml.train
import std.ml.optim
import std.ml.data

@layer struct MLP {
    @param w1: Tensor
    @param w2: Tensor
    @param b1: Tensor
    @param b2: Tensor

    fn forward(self, x) {
        let h = linear(x, self.w1, self.b1)
        let a = relu(h)
        return linear(a, self.w2, self.b2)
    }
}

model TrainConfig = DefaultConfig {
    d_model: 256
    num_layers: 4
    learning_rate: 0.001
}

fn main() {
    let cfg = TrainConfig {}
    let model = MLP {
        w1: randn([256, 128], 0.0, 0.02),
        w2: randn([128, 10], 0.0, 0.02),
        b1: zeros([128]),
        b2: zeros([10])
    }

    let data = dataset(inputs, labels, 32)
    let optimizer = adamw(model.params(), 0.001, 0.9, 0.999, 1e-8, 0.01)
    let scheduler = cosine_lr(optimizer, 1000, 0.0)

    let epoch = 0
    while epoch < 10 {
        let shuffled = shuffle(data)
        let batches = batch(shuffled, 32)
        let i = 0
        while i < batches.length {
            let batch = batches[i]
            let loss = train_step(model, cross_entropy, optimizer,
                                  batch.x, batch.y)
            scheduler.step()
            i = i + 1
        }
        let acc = evaluate(model, accuracy, data)
        print("epoch " + string(epoch) + " acc=" + string(acc))
        epoch = epoch + 1
    }
}