GizStack
View .mdOpen in ChatGPTOpen in Claude

gizml:grad

derivatives of tensor programs. A Graph records each operation on its values as it runs (a tape); backward walks it once in reverse for the gradient of a scalar against every value (reverse mode), and tangent walks it forward for the derivative along a direction (forward mode). Each rule is the textbook one over gizml:tensor's own operations, so gradients run fused on the CPU's lanes and cores like the forward pass.

gizlang
import * as Grad from "gizml:grad";

Types

Var

gizlang
type Var = { id: i64; }

A value in a Graph.

  • id: i64

Backward

gizlang
type Backward = (gradient: Tensor) => Vec<Tensor>

The vector-Jacobian product of a custom operation: the output's gradient to one gradient per input, in the inputs' shapes.

Graph

gizlang
type Graph = { nodes: Vec<Node>; customs: Vec<Custom>; compute: i64; }

A tape of tensor operations. Operations take and return Vars; value(v) reads one. A Graph is cheap: make one per step. compute is the autocast type (Graph.autocast).

  • nodes: Vec<M21.Node>
  • customs: Vec<M21.Custom>
  • compute: i64

Grads

gizlang
type Grads

Gradients by Var; a value the result does not depend on has a zero gradient.

Opaque: create and use it through this module's functions.

Functions

graph

gizlang
function graph(): Graph

An empty graph that computes in f32.

Methods

Graph.autocast

gizlang
function Graph.autocast(self: mut Graph, dtype: i64): void

Autocast, as torch.autocast: from now on the matrix products (matmul, batchMatmul, conv2d, forward and backward) of values on a GPU multiply in dtype (T.F16, T.BF16 or T.FP8) on its matrix cores, add in f32 and give dtype (T.productType; f32 for FP8, whose operands are scaled to its range, T.fp8Scaled). Elementwise operations on a product run in its store (T.lazyMatmul) and keep dtype while each other input has that type or one element. Every other operation reads any type and gives f32; T.F32 turns it off. On the CPU nothing changes.

Effects: fail.

Graph.input

gizlang
function Graph.input(self: mut Graph, value: Tensor): Var

A leaf: a value derivatives are taken against.

Effects: fail.

Graph.constant

gizlang
function Graph.constant(self: mut Graph, value: Tensor): Var

A leaf no derivative is taken against (data, labels): backward computes no gradient for it or for what depends on nothing else, as PyTorch skips a tensor without requires_grad; its gradient reads as zeros.

Effects: fail.

Graph.value

gizlang
function Graph.value(self: mut Graph, v: Var): Tensor

The value of V, computed now when it is still an expression.

Effects: fail, read, write, console, io.

Graph.add

gizlang
function Graph.add(self: mut Graph, x: Var, y: Var): Var

X + Y, element by element.

Effects: fail, read, write, console, io.

Graph.sub

gizlang
function Graph.sub(self: mut Graph, x: Var, y: Var): Var

X - Y, element by element.

Effects: fail, read, write, console, io.

Graph.mul

gizlang
function Graph.mul(self: mut Graph, x: Var, y: Var): Var

X * Y, element by element.

Effects: fail, read, write, console, io.

Graph.div

gizlang
function Graph.div(self: mut Graph, x: Var, y: Var): Var

X / Y, element by element.

Effects: fail, read, write, console, io.

Graph.maximum

gizlang
function Graph.maximum(self: mut Graph, x: Var, y: Var): Var

Elementwise larger; a tie sends the gradient to x.

Effects: fail, read, write, console, io.

Graph.minimum

gizlang
function Graph.minimum(self: mut Graph, x: Var, y: Var): Var

Elementwise smaller; a tie sends the gradient to x.

Effects: fail, read, write, console, io.

Graph.neg

gizlang
function Graph.neg(self: mut Graph, x: Var): Var

-X.

Effects: fail, read, write, console, io.

Graph.exp

gizlang
function Graph.exp(self: mut Graph, x: Var): Var

e to the power X, element by element.

Effects: fail, read, write, console, io.

Graph.log

gizlang
function Graph.log(self: mut Graph, x: Var): Var

The natural logarithm of X, element by element.

Effects: fail, read, write, console, io.

Graph.tanh

gizlang
function Graph.tanh(self: mut Graph, x: Var): Var

The hyperbolic tangent of X, element by element.

Effects: fail, read, write, console, io.

Graph.sigmoid

gizlang
function Graph.sigmoid(self: mut Graph, x: Var): Var

The sigmoid 1 / (1 + e^-x) of X, element by element.

Effects: fail, read, write, console, io.

Graph.relu

gizlang
function Graph.relu(self: mut Graph, x: Var): Var

max(x, 0); the gradient at 0 is 0.

Effects: fail, read, write, console, io.

Graph.square

gizlang
function Graph.square(self: mut Graph, x: Var): Var

X squared, element by element.

Effects: fail, read, write, console, io.

Graph.sqrt

gizlang
function Graph.sqrt(self: mut Graph, x: Var): Var

The square root of X, element by element.

Effects: fail, read, write, console, io.

Graph.abs

gizlang
function Graph.abs(self: mut Graph, x: Var): Var

|x|; the gradient at 0 is 0.

Effects: fail, read, write, console, io.

Graph.matmul

gizlang
function Graph.matmul(self: mut Graph, x: Var, y: Var): Var

(..., m, k) times (k, n), as Tensor.matmul.

Effects: fail, read, write, console, io.

Graph.transpose

gizlang
function Graph.transpose(self: mut Graph, x: Var): Var

X with its last two axes swapped.

Effects: fail, read, write, console, io.

Graph.reshape

gizlang
function Graph.reshape(self: mut Graph, x: Var, shape: Vec<i64>): Var

X with SHAPE (the same number of values).

Effects: fail, read, write, console, io.

Graph.sum

gizlang
function Graph.sum(self: mut Graph, x: Var): Var

The sum of every element (a scalar), in f64 lanes (Reduction.strict).

Effects: fail, read, write, console, io.

Graph.mean

gizlang
function Graph.mean(self: mut Graph, x: Var): Var

The mean of all values of X.

Effects: fail, read, write, console, io.

Graph.sumTo

gizlang
function Graph.sumTo(self: mut Graph, x: Var, shape: Vec<i64>): Var

Summed to shape over the axes it keeps as 1 (Tensor.sumTo): (b, n) to (b, 1) sums each row.

Effects: fail, read, write, console, io.

Graph.maxTo

gizlang
function Graph.maxTo(self: mut Graph, x: Var, shape: Vec<i64>): Var

Maxima to shape over the axes it keeps as 1 (Tensor.maxTo). Ties share the gradient evenly, as torch.amax.

Effects: fail, read, write, console, io.

Graph.logSoftmax

gizlang
function Graph.logSoftmax(self: mut Graph, x: Var): Var

Log softmax over the last axis: x - max - log(sum(exp(x - max))), from the operations above (both modes).

Effects: fail, read, write, console, io.

Graph.softmaxCrossEntropy

gizlang
function Graph.softmaxCrossEntropy(self: mut Graph, logits: Var, target: Var): Var

The mean over rows of -sum(target * log softmax(logits)) (logits and target (rows, classes); target is usually a constant, such as one-hot rows or soft labels). Graph.crossEntropy is the fused form for labels.

Effects: fail, read, write, console, io.

Graph.custom

gizlang
function Graph.custom(self: mut Graph, inputs: Vec<Var>, result: Tensor, backward: Backward): Var

An operation with its own gradient: value computed from inputs, and backward mapping the output's gradient to the inputs'. Reverse mode only.

Effects: fail.

Graph.checkpoint

gizlang
function Graph.checkpoint(self: mut Graph, inputs: Vec<Var>, f: (g: Graph, xs: Vec<Var>) => Graph): Var

f applied to inputs without keeping its intermediate values: only the result is stored, and the backward pass runs f again for its gradient (memory for time). f gets a fresh Graph and the inputs as its leaves and returns that Graph with the result as its last value.

Effects: fail, read, write, console, io.

Graph.gelu

gizlang
function Graph.gelu(self: mut Graph, x: Var): Var

GELU (tanh form, as torch's approximate="tanh").

Effects: fail, read, write, console, io.

Graph.geluErf

gizlang
function Graph.geluErf(self: mut Graph, x: Var): Var

GELU (erf form, torch's default).

Effects: fail, read, write, console, io.

Graph.attention

gizlang
function Graph.attention(self: mut Graph, q: Var, k: Var, v: Var, scale: f64, causal: bool, rate: f64, key: T.Key): Var

Scaled dot-product attention as N.attention: q (b, tq, d), k (b, tk, d), v (b, tk, e). The backward pass makes the weights P again from q and k (no (tq, tk) matrix is kept), then dv = Pdᵀ dy, dPd = dy vᵀ, dS = P (dP - rowsum(dP P)) and dq = dS k scale, dk = dSᵀ q scale, where Pd is P with the dropout mask and dP is dPd with it.

Effects: fail, read, write, console, io.

Graph.embedding

gizlang
function Graph.embedding(self: mut Graph, table: Var, ids: Vec<i64>): Var

Rows ids of table (rows, width): (ids, width).

Effects: fail, read, write, console, io.

Graph.layerNorm

gizlang
function Graph.layerNorm(self: mut Graph, x: Var, weight: Var, bias: Var, eps: f64): Var

Layer normalization of the last axis with weight and bias (its length).

Effects: fail, read, write, console, io.

Graph.softmax

gizlang
function Graph.softmax(self: mut Graph, x: Var): Var

Softmax over the last axis.

Effects: fail, read, write, console, io.

Graph.crossEntropy

gizlang
function Graph.crossEntropy(self: mut Graph, logits: Var, labels: Vec<i64>): Var

The mean over rows of the softmax cross-entropy of logits (rows, classes) at integer labels.

Effects: fail, read, write, console, io.

Graph.dropout

gizlang
function Graph.dropout(self: mut Graph, x: Var, k: T.Key, p: f64): Var

x with each element zeroed at rate p (the mask from key k) and the rest scaled by 1/(1-p).

Effects: fail, read, write, console, io.

Graph.slice

gizlang
function Graph.slice(self: mut Graph, x: Var, axis: i64, start: i64, end: i64): Var

Elements start..end of axis.

Effects: fail, read, write, console, io.

Graph.concat

gizlang
function Graph.concat(self: mut Graph, xs: Vec<Var>, axis: i64): Var

The values joined along axis.

Effects: fail, read, write, console, io.

Graph.permute

gizlang
function Graph.permute(self: mut Graph, x: Var, axes: Vec<i64>): Var

The axes reordered: output axis i is input axis axes[i].

Effects: fail, read, write, console, io.

Graph.batchMatmul

gizlang
function Graph.batchMatmul(self: mut Graph, x: Var, ta: bool, y: Var, tb: bool): Var

Batched matmul as T.batchMatmul: x (b, m, k) or, transposed, (b, k, m); y (b, k, n), (b, n, k), or one matrix for every batch.

Effects: fail, read, write, console, io.

Graph.conv2d

gizlang
function Graph.conv2d(self: mut Graph, x: Var, weight: Var, bias: Var, stride: i64, pad: i64): Var

A 2-D convolution of x (n, c, h, w) by weight (o, c, kh, kw) plus bias (o), at stride with pad zeros: (n, o, oh, ow), as one matmul over im2col's patches.

Effects: fail, read, write, console, io.

Graph.pool2d

gizlang
function Graph.pool2d(self: mut Graph, x: Var, size: i64, stride: i64, average: bool): Var

Max (or average) pooling over size x size windows at stride.

Effects: fail, read, write, console, io.

Grads.of

gizlang
function Grads.of (self: Grads, v: Var): Tensor

The gradient of v (each call computes it).

Effects: fail, read, write, console, io.

Grads.pending

gizlang
function Grads.pending(self: Grads, v: Var): Lazy

The gradient of v not yet computed: an optimizer extends it, so where it is a product, the update runs as the product is stored.

Effects: fail, read, write, console, io.

Graph.backward

gizlang
function Graph.backward(self: mut Graph, loss: Var): Grads

The gradient of loss, a one-element value, against every value before it.

Effects: fail, read, write, console, io.

Graph.backwardFrom

gizlang
function Graph.backwardFrom(self: mut Graph, output: Var, seed: Tensor): Grads

The vector-Jacobian product: seed (the output's shape) through the tape.

Effects: fail, read, write, console, io.

Graph.tangent

gizlang
function Graph.tangent(self: mut Graph, inputs: Vec<Var>, directions: Vec<Tensor>, output: Var): Tensor

The derivative of output along directions given for inputs (each the input's shape; other inputs held fixed): one forward walk of the tape (a Jacobian-vector product). Every built-in operation; not custom ones.

Effects: fail, read, write, console, io.