Skip to content

autograd #

Node is a member of a computational graph that contains a reference to a gate, as well as the parents of the operation and the payload that resulted from the operation. Payload is a simple wrapper around a Variable. It is only abstracted out to be a bit more explicit that it is being passed around through an operation

fn abs_gate #

fn abs_gate[T](a &Variable[T]) &AbsGate[T]

fn add_gate #

fn add_gate[T]() &AddGate[T]

fn clamp_gate #

fn clamp_gate[T](min_val T, max_val T, a &vtl.Tensor[T]) &ClampGate[T]

fn concat_gate #

fn concat_gate[T](axis int, splits []int) &ConcatGate[T]

fn cos_gate #

fn cos_gate[T](a &Variable[T]) &CosGate[T]

fn ctx #

fn ctx[T]() &Context[T]

Contexts can only be initialized as empty, and a generic type must be provided

fn divide_gate #

fn divide_gate[T](a &Variable[T], b &Variable[T]) &DivideGate[T]

fn exp_gate #

fn exp_gate[T](a &Variable[T]) &ExpGate[T]

fn gate_backward #

fn gate_backward[T](gate Gate[T], payload &Payload[T]) ![]&vtl.Tensor[T]

gate_backward is kept for backwards compatibility but now delegates directly through the Gate[T] interface instead of a manual match.

fn log_gate #

fn log_gate[T](a &Variable[T]) &LogGate[T]

fn matmul_gate #

fn matmul_gate[T](a &Variable[T], b &Variable[T]) &MatMulGate[T]

fn mean_gate #

fn mean_gate[T](shape []int, axis int, num_elems int) &MeanGate[T]

fn multiply_gate #

fn multiply_gate[T](a &Variable[T], b &Variable[T]) &MultiplyGate[T]

fn node #

fn node[T](gate Gate[T], parents []&Variable[T], payload &Payload[T], name string) &Node[T]

node

fn payload #

fn payload[T](variable &Variable[T]) &Payload[T]

fn pow_gate #

fn pow_gate[T](a &Variable[T], b &Variable[T]) &PowGate[T]

fn register #

fn register[T](name string, gate Gate[T], result &Variable[T], parents []&Variable[T]) !

fn reshape_gate #

fn reshape_gate[T](orig_shape []int) &ReshapeGate[T]

fn sin_gate #

fn sin_gate[T](a &Variable[T]) &SinGate[T]

fn sqrt_gate #

fn sqrt_gate[T](a &Variable[T]) &SqrtGate[T]

fn subtract_gate #

fn subtract_gate[T]() &SubtractGate[T]

fn sum_gate #

fn sum_gate[T](shape []int, axis int) &SumGate[T]

fn tan_gate #

fn tan_gate[T](a &Variable[T]) &TanGate[T]

fn tanh_gate #

fn tanh_gate[T](cache &vtl.Tensor[T]) &TanhGate[T]

fn transpose_gate #

fn transpose_gate[T](perm []int) &TransposeGate[T]

fn variable #

fn variable[T](context &Context[T], value &vtl.Tensor[T], data VariableData) &Variable[T]

variable

interface CacheParam #

interface CacheParam {}

interface Gate #

interface Gate[T] {
	backward(payload &Payload[T]) ![]&vtl.Tensor[T]
}

Gate is a generic interface for autograd operations. Any struct that implements backward for a given T satisfies Gate[T]. This allows both core math gates (AddGate, MatMulGate, …) and higher-level nn gates (LinearGate, ReLUGate, …) to participate in backpropagation without circular imports.

fn (AbsGate[T]) backward #

fn (g &AbsGate[T]) backward[T](payload &Payload[T]) ![]&vtl.Tensor[T]

fn (AbsGate[T]) cache #

fn (g &AbsGate[T]) cache[T](mut result Variable[T], args ...CacheParam) !

fn (AddGate[T]) backward #

fn (g &AddGate[T]) backward[T](payload &Payload[T]) ![]&vtl.Tensor[T]

fn (AddGate[T]) cache #

fn (g &AddGate[T]) cache[T](mut result Variable[T], args ...CacheParam) !

fn (ClampGate[T]) backward #

fn (g &ClampGate[T]) backward[T](payload &Payload[T]) ![]&vtl.Tensor[T]

fn (ClampGate[T]) cache #

fn (g &ClampGate[T]) cache[T](mut result Variable[T], args ...CacheParam) !

fn (ConcatGate[T]) backward #

fn (g &ConcatGate[T]) backward[T](payload &Payload[T]) ![]&vtl.Tensor[T]

fn (ConcatGate[T]) cache #

fn (g &ConcatGate[T]) cache[T](mut result Variable[T], args ...CacheParam) !

fn (Context[T]) set_compute_backend #

fn (mut ctx Context[T]) set_compute_backend(backend vtl.Backend)

set_compute_backend configures backend preference for runtime dispatch.

fn (Context[T]) set_compute_strict #

fn (mut ctx Context[T]) set_compute_strict(strict bool)

set_compute_strict toggles strict mode for runtime backend dispatch.

fn (Context[T]) len #

fn (ctx &Context[T]) len() int

fn (Context[T]) push #

fn (mut ctx Context[T]) push[T](node &Node[T])

fn (Context[T]) last #

fn (ctx &Context[T]) last[T]() !&Node[T]

fn (Context[T]) pop #

fn (mut ctx Context[T]) pop[T]() !&Node[T]

fn (Context[T]) variable #

fn (ctx &Context[T]) variable[T](value &vtl.Tensor[T], data ContextVariableData) &Variable[T]

fn (Context[T]) str #

fn (ctx &Context[T]) str() string

fn (CosGate[T]) backward #

fn (g &CosGate[T]) backward[T](payload &Payload[T]) ![]&vtl.Tensor[T]

fn (CosGate[T]) cache #

fn (g &CosGate[T]) cache[T](mut result Variable[T], args ...CacheParam) !

fn (DivideGate[T]) backward #

fn (g &DivideGate[T]) backward[T](payload &Payload[T]) ![]&vtl.Tensor[T]

fn (DivideGate[T]) cache #

fn (g &DivideGate[T]) cache[T](mut result Variable[T], args ...CacheParam) !

fn (ExpGate[T]) backward #

fn (g &ExpGate[T]) backward[T](payload &Payload[T]) ![]&vtl.Tensor[T]

fn (ExpGate[T]) cache #

fn (g &ExpGate[T]) cache[T](mut result Variable[T], args ...CacheParam) !

fn (LogGate[T]) backward #

fn (g &LogGate[T]) backward[T](payload &Payload[T]) ![]&vtl.Tensor[T]

fn (LogGate[T]) cache #

fn (g &LogGate[T]) cache[T](mut result Variable[T], args ...CacheParam) !

fn (MatMulGate[T]) backward #

fn (g &MatMulGate[T]) backward[T](payload &Payload[T]) ![]&vtl.Tensor[T]

fn (MatMulGate[T]) cache #

fn (g &MatMulGate[T]) cache[T](mut result Variable[T], args ...CacheParam) !

fn (MeanGate[T]) backward #

fn (g &MeanGate[T]) backward[T](payload &Payload[T]) ![]&vtl.Tensor[T]

fn (MeanGate[T]) cache #

fn (g &MeanGate[T]) cache[T](mut result Variable[T], args ...CacheParam) !

fn (MultiplyGate[T]) backward #

fn (g &MultiplyGate[T]) backward[T](payload &Payload[T]) ![]&vtl.Tensor[T]

fn (MultiplyGate[T]) cache #

fn (g &MultiplyGate[T]) cache[T](mut result Variable[T], args ...CacheParam) !

fn (PowGate[T]) backward #

fn (g &PowGate[T]) backward[T](payload &Payload[T]) ![]&vtl.Tensor[T]

fn (PowGate[T]) cache #

fn (g &PowGate[T]) cache[T](mut result Variable[T], args ...CacheParam) !

fn (ReshapeGate[T]) backward #

fn (g &ReshapeGate[T]) backward[T](payload &Payload[T]) ![]&vtl.Tensor[T]

fn (ReshapeGate[T]) cache #

fn (g &ReshapeGate[T]) cache[T](mut result Variable[T], args ...CacheParam) !

fn (SinGate[T]) backward #

fn (g &SinGate[T]) backward[T](payload &Payload[T]) ![]&vtl.Tensor[T]

fn (SinGate[T]) cache #

fn (g &SinGate[T]) cache[T](mut result Variable[T], args ...CacheParam) !

fn (SqrtGate[T]) backward #

fn (g &SqrtGate[T]) backward[T](payload &Payload[T]) ![]&vtl.Tensor[T]

fn (SqrtGate[T]) cache #

fn (g &SqrtGate[T]) cache[T](mut result Variable[T], args ...CacheParam) !

fn (SubtractGate[T]) backward #

fn (g &SubtractGate[T]) backward[T](payload &Payload[T]) ![]&vtl.Tensor[T]

fn (SubtractGate[T]) cache #

fn (g &SubtractGate[T]) cache[T](mut result Variable[T], args ...CacheParam) !

fn (SumGate[T]) backward #

fn (g &SumGate[T]) backward[T](payload &Payload[T]) ![]&vtl.Tensor[T]

fn (SumGate[T]) cache #

fn (g &SumGate[T]) cache[T](mut result Variable[T], args ...CacheParam) !

fn (TanGate[T]) backward #

fn (g &TanGate[T]) backward[T](payload &Payload[T]) ![]&vtl.Tensor[T]

fn (TanGate[T]) cache #

fn (g &TanGate[T]) cache[T](mut result Variable[T], args ...CacheParam) !

fn (TanhGate[T]) backward #

fn (g &TanhGate[T]) backward[T](payload &Payload[T]) ![]&vtl.Tensor[T]

fn (TanhGate[T]) cache #

fn (g &TanhGate[T]) cache[T](mut result Variable[T], args ...CacheParam) !

fn (TransposeGate[T]) backward #

fn (g &TransposeGate[T]) backward[T](payload &Payload[T]) ![]&vtl.Tensor[T]

fn (TransposeGate[T]) cache #

fn (g &TransposeGate[T]) cache[T](mut result Variable[T], args ...CacheParam) !

fn (Variable[T]) abs_op #

fn (v &Variable[T]) abs_op[T]() !&Variable[T]

abs_op computes the absolute value of the variable element-wise. Backward: grad * sign(x) (0 at x=0)

Named abs_op (not abs) to avoid collision with the built-in abs method on Tensor[T] which does not participate in the autograd graph.

Example

x := ctx.variable(vtl.from_1d[f64]([-3.0, 0.0, 4.0]))
y := x.abs_op[f64]()!
// y.value = [3.0, 0.0, 4.0]

fn (Variable[T]) add #

fn (v &Variable[T]) add[T](other &Variable[T]) !&Variable[T]

add Adds two variables together.

fn (Variable[T]) backprop #

fn (mut v Variable[T]) backprop[T]() !

backprop Back propagates an operation along a computational graph. This operation will destroy the operational graph, populating the gradients for all variables that are predecessors of the Variable this is called on. Even if this is called on the first node in a graph, it will destroy all descendents of this variable stored by the Context

fn (Variable[T]) clamp #

fn (v &Variable[T]) clamp[T](min_val T, max_val T) !&Variable[T]

clamp clips the variable element-wise to the range [min_val, max_val]. Backward: grad is passed through where min_val < x < max_val, zero otherwise.

Example

x := ctx.variable(vtl.from_1d[f64]([-2.0, 0.5, 3.0]))
y := x.clamp[f64](-1.0, 1.0)!
// y.value = [-1.0, 0.5, 1.0]

fn (Variable[T]) cos #

fn (v &Variable[T]) cos[T]() !&Variable[T]

cos Cosine of a variable.

fn (Variable[T]) divide #

fn (v &Variable[T]) divide[T](other &Variable[T]) !&Variable[T]

divide Divides two variables.

fn (Variable[T]) exp #

fn (v &Variable[T]) exp[T]() !&Variable[T]

exp Exponentiates a variable.

fn (Variable[T]) is_grad_needed #

fn (v &Variable[T]) is_grad_needed() bool

fn (Variable[T]) log #

fn (v &Variable[T]) log[T]() !&Variable[T]

log computes the natural logarithm of the variable element-wise. Backward: grad * (1 / x)

Note: inputs must be positive; behaviour for x <= 0 is undefined.

Example

x := ctx.variable(vtl.from_1d[f64]([1.0, math.e, math.exp(2.0)]))
y := x.log[f64]()!
// y.value ≈ [0.0, 1.0, 2.0]

fn (Variable[T]) matmul #

fn (v &Variable[T]) matmul[T](other &Variable[T]) !&Variable[T]

matmul Multiplies two matrices.

fn (Variable[T]) multiply #

fn (v &Variable[T]) multiply[T](other &Variable[T]) !&Variable[T]

multiply Multiplies two variables.

fn (Variable[T]) pow #

fn (v &Variable[T]) pow[T](other &Variable[T]) !&Variable[T]

pow raises a variable to a power.

fn (Variable[T]) reshape #

fn (v &Variable[T]) reshape[T](new_shape []int) !&Variable[T]

reshape returns a new variable with the same data but a different shape. The total number of elements must be preserved. Backward: gradient is reshaped back to the original shape.

Example

x := ctx.variable(vtl.from_array[f64]([1.0, 2.0, 3.0, 4.0], [2, 2]))
y := x.reshape[f64]([4])!
// y.value.shape = [4]

fn (Variable[T]) sin #

fn (v &Variable[T]) sin[T]() !&Variable[T]

sin Sine of a variable.

fn (Variable[T]) slice #

fn (v &Variable[T]) slice[T](idx ...[]int) !&Variable[T]

fn (Variable[T]) slice_hilo #

fn (v &Variable[T]) slice_hilo[T](idx1 []int, idx2 []int) !&Variable[T]

fn (Variable[T]) sqrt_op #

fn (v &Variable[T]) sqrt_op[T]() !&Variable[T]

sqrt_op computes the element-wise square root of the variable. Backward: grad * (1 / (2 * sqrt(x)))

Note: inputs must be non-negative.

Named sqrt_op (not sqrt) to avoid collision with Tensor.sqrt which does not participate in the autograd graph.

Example

x := ctx.variable(vtl.from_1d[f64]([1.0, 4.0, 9.0]))
y := x.sqrt_op[f64]()!
// y.value = [1.0, 2.0, 3.0]

fn (Variable[T]) str #

fn (v &Variable[T]) str() string

fn (Variable[T]) subtract #

fn (v &Variable[T]) subtract[T](other &Variable[T]) !&Variable[T]

subtract Subtracts two variables.

fn (Variable[T]) tan #

fn (v &Variable[T]) tan[T]() !&Variable[T]

tan Tan of a variable.

fn (Variable[T]) tanh_op #

fn (v &Variable[T]) tanh_op[T]() !&Variable[T]

tanh_op computes the element-wise hyperbolic tangent of the variable. Backward: grad * (1 - tanh²(x))

Named tanh_op (not tanh) to avoid collision with Tensor.tanh which does not participate in the autograd graph.

Example

x := ctx.variable(vtl.from_1d[f64]([0.0, 1.0, -1.0]))
y := x.tanh_op[f64]()!
// y.value ≈ [0.0, 0.762, -0.762]

fn (Variable[T]) transpose_op #

fn (v &Variable[T]) transpose_op[T](perm []int) !&Variable[T]

transpose_op permutes the axes of the variable according to perm. perm must be a permutation of [0, 1, ..., ndim-1]. Backward: gradient is transposed with the inverse permutation.

Named transpose_op (not transpose) to avoid collision with Tensor.transpose.

Example

x := ctx.variable(vtl.from_array[f64]([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], [2, 3]))
y := x.transpose_op[f64]([1, 0])!
// y.value.shape = [3, 2]

struct AbsGate #

struct AbsGate[T] {
pub:
	a &Variable[T] = unsafe { nil }
}

AbsGate implements abs(x) element-wise. backward: grad * sign(x)

struct AddGate #

struct AddGate[T] {}

struct ClampGate #

struct ClampGate[T] {
pub:
	min_val T
	max_val T
	a       &vtl.Tensor[T] = unsafe { nil }
}

ClampGate implements clamp(x, min, max) element-wise. backward: grad where x is within [min, max], 0 otherwise

struct ConcatGate #

struct ConcatGate[T] {
pub:
	axis   int
	splits []int // size of each input along the concat axis
}

ConcatGate concatenates multiple tensors along an axis. backward: split gradient back into original inputs

struct Context #

@[heap]
struct Context[T] {
pub mut:
	// A list of all variables present in an operation.
	// This list can contain duplicates
	nodes []&Node[T]
	// If no_grad is set to true, operations will not
	// be cached, and backpropagation will not be possible
	no_grad bool
	// Backend preference used by NN/LA runtime dispatch.
	compute_backend vtl.Backend = .auto
	// If true, fail when preferred backend is unavailable.
	compute_strict bool
}

Context keeps track of the computational graph for a number of operations. Variables that interact with each other must belong to the same context, or state will be lost while tracking operations done.

struct ContextVariableData #

@[params]
struct ContextVariableData {
pub:
	requires_grad bool = true
}

struct CosGate #

struct CosGate[T] {
pub:
	a &Variable[T] = unsafe { nil }
}

struct DivideGate #

struct DivideGate[T] {
pub:
	a &Variable[T] = unsafe { nil }
	b &Variable[T] = unsafe { nil }
}

struct ExpGate #

struct ExpGate[T] {
pub:
	a &Variable[T] = unsafe { nil }
}

struct LogGate #

struct LogGate[T] {
pub:
	a &Variable[T] = unsafe { nil }
}

LogGate implements log(x) element-wise. backward: grad * (1/x)

struct MatMulGate #

struct MatMulGate[T] {
pub:
	a &Variable[T] = unsafe { nil }
	b &Variable[T] = unsafe { nil }
}

struct MeanGate #

struct MeanGate[T] {
pub:
	shape     []int
	axis      int
	num_elems int
}

MeanGate implements mean reduction. backward: grad broadcast to input shape / num_elements

struct MultiplyGate #

struct MultiplyGate[T] {
pub:
	a &Variable[T] = unsafe { nil }
	b &Variable[T] = unsafe { nil }
}

struct Node #

@[heap]
struct Node[T] {
pub:
	// A Gate[T] containing a backward function for this node.
	// Using the generic interface allows any gate (core math or nn)
	// to participate in backpropagation without circular imports.
	gate Gate[T]
pub mut:
	// The variables that created this node
	parents []&Variable[T]
	// Wrapper around a Tensor, contains operation data
	payload &Payload[T] = unsafe { nil }
	// Debug use only, contains a name for a node
	name string
}

struct Payload #

@[heap]
struct Payload[T] {
pub:
	// Contents of the paylod
	variable &Variable[T] = unsafe { nil }
}

struct PowGate #

struct PowGate[T] {
	a &Variable[T] = unsafe { nil }
	b &Variable[T] = unsafe { nil }
}

struct ReshapeGate #

struct ReshapeGate[T] {
pub:
	orig_shape []int
}

ReshapeGate stores the original shape for backward pass. backward: grad reshaped back to original shape

struct SinGate #

struct SinGate[T] {
pub:
	a &Variable[T] = unsafe { nil }
}

struct SqrtGate #

struct SqrtGate[T] {
pub:
	a &Variable[T] = unsafe { nil }
}

SqrtGate implements sqrt(x) element-wise. backward: grad * (1 / (2 * sqrt(x)))

struct SubtractGate #

struct SubtractGate[T] {}

struct SumGate #

struct SumGate[T] {
pub:
	shape []int
	axis  int
}

SumGate implements sum reduction. backward: grad broadcast back to input shape

struct TanGate #

struct TanGate[T] {
pub:
	a &Variable[T] = unsafe { nil }
}

struct TanhGate #

struct TanhGate[T] {
pub:
	cache &vtl.Tensor[T] = unsafe { nil }
}

TanhGate implements tanh(x) element-wise. backward: grad * (1 - tanh(x)^2) = grad * (1 - cached^2)

struct TransposeGate #

struct TransposeGate[T] {
pub:
	perm  []int
	iperm []int
}

TransposeGate stores the permutation for backward. backward: grad transposed back with inverse permutation

struct Variable #

@[heap]
struct Variable[T] {
pub mut:
	// The value of the Variable.  This should not be edited outside
	// of Variable operations, as other edits will not be tracked
	// and will lead to incorrect results
	value &vtl.Tensor[T] = unsafe { nil }
	// The graph the variable is associated with.  This is a reference,
	// as a variable does not own its context
	context &Context[T] = unsafe { nil }
	// The gradient of the Variable.  This is set as a reference to
	// the value of a Variable unless `backprop` has been called, in
	// which case all related Variables will have their gradient
	// updated correctly
	grad &vtl.Tensor[T] = unsafe { nil }
	// If set to true, this variable will track its operations,
	// otherwise it will act similar to a vtl.Tensor, only calculating
	// forward operations
	requires_grad bool
}

Variable is an abstraction of a vtl.Tensor that tracks the operations done to the vtl.Tensor. It also keeps track of the gradient of the operation if a Variable needs to backpropagate. This is the fundamental object used in automatic differentiation, as well as the neural network aspects of VTL

struct VariableData #

@[params]
struct VariableData {
	requires_grad bool = true
}