Packages

Tensor library for Gleam/BEAM with a pure Gleam API, zero-copy views, and optional native acceleration

Retired package: Release invalid

Current section

Files

Jump to
viva_tensor src viva_tensor@core@config.erl
Raw

src/viva_tensor@core@config.erl

-module(viva_tensor@core@config).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/viva_tensor/core/config.gleam").
-export([conv2d/0, conv2d_new/4, conv2d_same/2, with_stride/2, with_stride_hw/3, with_padding/2, with_padding_hw/3, with_dilation/2, with_groups/2, with_kernel/3, pool/0, pool_new/2, pool_with_size/3, pool_with_stride/2, pool_with_padding/2, nf4/0, nf4_with_block_size/2, nf4_with_double_quant/2, int8/0, int8_with_block_size/2, awq/0, awq_with_block_size/2, awq_with_calibration/2, attention_causal/1, attention_with_dropout/2, attention_with_scale/2, attention/2]).
-export_type([conv2d_config/0, pool_config/0, n_f4_config/0, int8_config/0, a_w_q_config/0, attention_config/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(
" Configuration Types with Builder Pattern\n"
"\n"
" Builder pattern: Gang of Four called, they want royalties.\n"
" But seriously, this beats magic numbers in function calls any day.\n"
"\n"
" The idea: sensible defaults + fluent customization. You get a working config\n"
" out of the box, then override only what you need. No more googling\n"
" \"what's the default stride for conv2d in pytorch\".\n"
"\n"
" ## Design Philosophy\n"
"\n"
" 1. Defaults are production-ready, not toy examples\n"
" 2. Labelled arguments for required params, builders for optional ones\n"
" 3. Every config should be printable for debugging (thanks Gleam!)\n"
"\n"
" ## Example\n"
" ```gleam\n"
" import viva_tensor/core/config\n"
"\n"
" // Start with defaults, customize what matters\n"
" let cfg = config.conv2d()\n"
" |> config.with_stride(2)\n"
" |> config.with_padding(1)\n"
"\n"
" // Or be explicit about everything\n"
" let cfg = config.conv2d_new(\n"
" kernel_h: 5,\n"
" kernel_w: 5,\n"
" stride: 2,\n"
" padding: 1,\n"
" )\n"
" ```\n"
).
-type conv2d_config() :: {conv2d_config,
integer(),
integer(),
integer(),
integer(),
integer(),
integer(),
integer(),
integer(),
integer()}.
-type pool_config() :: {pool_config,
integer(),
integer(),
integer(),
integer(),
integer(),
integer()}.
-type n_f4_config() :: {n_f4_config, integer(), boolean()}.
-type int8_config() :: {int8_config, integer(), boolean()}.
-type a_w_q_config() :: {a_w_q_config, integer(), integer(), float()}.
-type attention_config() :: {attention_config,
integer(),
integer(),
float(),
boolean(),
float()}.
-file("src/viva_tensor/core/config.gleam", 91).
?DOC(
" Default Conv2d: 3x3 kernel, stride 1, no padding, no dilation.\n"
"\n"
" Why 3x3? VGGNet (2014) showed stacking 3x3s beats larger kernels.\n"
" Two 3x3s have the same receptive field as one 5x5 but fewer params.\n"
" Three 3x3s = one 7x7 receptive field. This is why ResNet uses 3x3 everywhere.\n"
"\n"
" Warning: stride=1 + no padding shrinks output by (kernel-1) pixels per side.\n"
" For \"same\" output size, use conv2d_same() or add padding=kernel/2.\n"
).
-spec conv2d() -> conv2d_config().
conv2d() ->
{conv2d_config, 3, 3, 1, 1, 0, 0, 1, 1, 1}.
-file("src/viva_tensor/core/config.gleam", 109).
?DOC(
" Explicit Conv2d config with labelled arguments.\n"
"\n"
" Use this when you know exactly what you want and don't need\n"
" the builder pattern's incremental customization.\n"
).
-spec conv2d_new(integer(), integer(), integer(), integer()) -> conv2d_config().
conv2d_new(Kernel_h, Kernel_w, Stride, Padding) ->
{conv2d_config,
Kernel_h,
Kernel_w,
Stride,
Stride,
Padding,
Padding,
1,
1,
1}.
-file("src/viva_tensor/core/config.gleam", 135).
?DOC(
" \"Same\" padding: output spatial size equals input spatial size.\n"
"\n"
" Computes padding = kernel_size / 2 (integer division).\n"
" Only works correctly for odd kernel sizes with stride=1.\n"
" For even kernels or stride>1, you need asymmetric padding (not supported here).\n"
"\n"
" Note: PyTorch's \"same\" padding does asymmetric padding. We keep it simple.\n"
).
-spec conv2d_same(integer(), integer()) -> conv2d_config().
conv2d_same(Kernel_h, Kernel_w) ->
{conv2d_config,
Kernel_h,
Kernel_w,
1,
1,
Kernel_h div 2,
Kernel_w div 2,
1,
1,
1}.
-file("src/viva_tensor/core/config.gleam", 156).
?DOC(
" Set uniform stride (same for H and W).\n"
"\n"
" stride=2 is the standard way to downsample - halves spatial dimensions.\n"
" More efficient than conv+maxpool and learns the downsampling.\n"
).
-spec with_stride(conv2d_config(), integer()) -> conv2d_config().
with_stride(Config, Stride) ->
{conv2d_config,
erlang:element(2, Config),
erlang:element(3, Config),
Stride,
Stride,
erlang:element(6, Config),
erlang:element(7, Config),
erlang:element(8, Config),
erlang:element(9, Config),
erlang:element(10, Config)}.
-file("src/viva_tensor/core/config.gleam", 162).
?DOC(
" Set separate strides for height and width.\n"
" Rarely needed, but here for completeness.\n"
).
-spec with_stride_hw(conv2d_config(), integer(), integer()) -> conv2d_config().
with_stride_hw(Config, Stride_h, Stride_w) ->
{conv2d_config,
erlang:element(2, Config),
erlang:element(3, Config),
Stride_h,
Stride_w,
erlang:element(6, Config),
erlang:element(7, Config),
erlang:element(8, Config),
erlang:element(9, Config),
erlang:element(10, Config)}.
-file("src/viva_tensor/core/config.gleam", 175).
?DOC(
" Set uniform padding.\n"
"\n"
" padding=1 with 3x3 kernel maintains spatial size (stride=1).\n"
" padding=2 with 5x5 kernel maintains spatial size (stride=1).\n"
" General rule: padding = (kernel_size - 1) / 2 for \"same\" output.\n"
).
-spec with_padding(conv2d_config(), integer()) -> conv2d_config().
with_padding(Config, Padding) ->
{conv2d_config,
erlang:element(2, Config),
erlang:element(3, Config),
erlang:element(4, Config),
erlang:element(5, Config),
Padding,
Padding,
erlang:element(8, Config),
erlang:element(9, Config),
erlang:element(10, Config)}.
-file("src/viva_tensor/core/config.gleam", 180).
?DOC(" Set separate paddings for height and width.\n").
-spec with_padding_hw(conv2d_config(), integer(), integer()) -> conv2d_config().
with_padding_hw(Config, Padding_h, Padding_w) ->
{conv2d_config,
erlang:element(2, Config),
erlang:element(3, Config),
erlang:element(4, Config),
erlang:element(5, Config),
Padding_h,
Padding_w,
erlang:element(8, Config),
erlang:element(9, Config),
erlang:element(10, Config)}.
-file("src/viva_tensor/core/config.gleam", 196).
?DOC(
" Set uniform dilation for atrous/dilated convolution.\n"
"\n"
" dilation=2 means skip every other pixel when applying kernel.\n"
" Effective kernel size = dilation * (kernel - 1) + 1\n"
" So 3x3 with dilation=2 has 5x5 receptive field but only 9 params.\n"
"\n"
" DeepLab uses this for semantic segmentation - large receptive field\n"
" without the parameter explosion of large kernels.\n"
).
-spec with_dilation(conv2d_config(), integer()) -> conv2d_config().
with_dilation(Config, Dilation) ->
{conv2d_config,
erlang:element(2, Config),
erlang:element(3, Config),
erlang:element(4, Config),
erlang:element(5, Config),
erlang:element(6, Config),
erlang:element(7, Config),
Dilation,
Dilation,
erlang:element(10, Config)}.
-file("src/viva_tensor/core/config.gleam", 208).
?DOC(
" Set number of groups for grouped convolution.\n"
"\n"
" groups=1: standard convolution, all inputs connect to all outputs\n"
" groups=in_channels: depthwise convolution (MobileNet, EfficientNet)\n"
" groups=N: grouped convolution, splits channels into N independent groups\n"
"\n"
" Depthwise + 1x1 pointwise = depthwise separable convolution\n"
" Cuts compute by ~kernel_size^2 with minimal accuracy loss.\n"
).
-spec with_groups(conv2d_config(), integer()) -> conv2d_config().
with_groups(Config, Groups) ->
{conv2d_config,
erlang:element(2, Config),
erlang:element(3, Config),
erlang:element(4, Config),
erlang:element(5, Config),
erlang:element(6, Config),
erlang:element(7, Config),
erlang:element(8, Config),
erlang:element(9, Config),
Groups}.
-file("src/viva_tensor/core/config.gleam", 213).
?DOC(" Set kernel size (height and width).\n").
-spec with_kernel(conv2d_config(), integer(), integer()) -> conv2d_config().
with_kernel(Config, Kernel_h, Kernel_w) ->
{conv2d_config,
Kernel_h,
Kernel_w,
erlang:element(4, Config),
erlang:element(5, Config),
erlang:element(6, Config),
erlang:element(7, Config),
erlang:element(8, Config),
erlang:element(9, Config),
erlang:element(10, Config)}.
-file("src/viva_tensor/core/config.gleam", 259).
?DOC(
" Default pooling: 2x2 window, stride 2, no padding.\n"
"\n"
" The classic maxpool config: halves spatial dimensions.\n"
" Non-overlapping windows (stride = pool_size).\n"
"\n"
" Fun fact: Hinton thinks pooling is a mistake because it throws away\n"
" spatial information. Capsule networks are his proposed fix.\n"
" The jury's still out.\n"
).
-spec pool() -> pool_config().
pool() ->
{pool_config, 2, 2, 2, 2, 0, 0}.
-file("src/viva_tensor/core/config.gleam", 271).
?DOC(" Create pool config with explicit size and stride.\n").
-spec pool_new(integer(), integer()) -> pool_config().
pool_new(Pool_size, Stride) ->
{pool_config, Pool_size, Pool_size, Stride, Stride, 0, 0}.
-file("src/viva_tensor/core/config.gleam", 283).
?DOC(" Set pool window size.\n").
-spec pool_with_size(pool_config(), integer(), integer()) -> pool_config().
pool_with_size(Config, Pool_h, Pool_w) ->
{pool_config,
Pool_h,
Pool_w,
erlang:element(4, Config),
erlang:element(5, Config),
erlang:element(6, Config),
erlang:element(7, Config)}.
-file("src/viva_tensor/core/config.gleam", 292).
?DOC(" Set pool stride.\n").
-spec pool_with_stride(pool_config(), integer()) -> pool_config().
pool_with_stride(Config, Stride) ->
{pool_config,
erlang:element(2, Config),
erlang:element(3, Config),
Stride,
Stride,
erlang:element(6, Config),
erlang:element(7, Config)}.
-file("src/viva_tensor/core/config.gleam", 297).
?DOC(" Set pool padding.\n").
-spec pool_with_padding(pool_config(), integer()) -> pool_config().
pool_with_padding(Config, Padding) ->
{pool_config,
erlang:element(2, Config),
erlang:element(3, Config),
erlang:element(4, Config),
erlang:element(5, Config),
Padding,
Padding}.
-file("src/viva_tensor/core/config.gleam", 337).
?DOC(
" Default NF4: block_size=64, double_quant=True (paper settings).\n"
"\n"
" These are the settings from QLoRA that achieved results matching\n"
" full-precision finetuning. Don't change unless you know why.\n"
).
-spec nf4() -> n_f4_config().
nf4() ->
{n_f4_config, 64, true}.
-file("src/viva_tensor/core/config.gleam", 347).
?DOC(
" Override NF4 block size.\n"
"\n"
" Smaller = better quality, more scale overhead.\n"
" 32: ~0.69 bits/param overhead, slightly better quality\n"
" 64: ~0.5 bits/param overhead (default, paper setting)\n"
" 128: ~0.44 bits/param overhead, slightly worse quality\n"
).
-spec nf4_with_block_size(n_f4_config(), integer()) -> n_f4_config().
nf4_with_block_size(Config, Block_size) ->
{n_f4_config, Block_size, erlang:element(3, Config)}.
-file("src/viva_tensor/core/config.gleam", 353).
?DOC(
" Enable/disable double quantization.\n"
" There's really no reason to disable this, but the option exists.\n"
).
-spec nf4_with_double_quant(n_f4_config(), boolean()) -> n_f4_config().
nf4_with_double_quant(Config, Enabled) ->
{n_f4_config, erlang:element(2, Config), Enabled}.
-file("src/viva_tensor/core/config.gleam", 381).
?DOC(
" Default INT8: per-tensor symmetric quantization.\n"
"\n"
" Simplest and fastest. Works well when weight distributions are roughly\n"
" symmetric around zero (which they usually are for trained models).\n"
).
-spec int8() -> int8_config().
int8() ->
{int8_config, 0, true}.
-file("src/viva_tensor/core/config.gleam", 387).
?DOC(
" Set INT8 block size for per-block quantization.\n"
" 0 = per-tensor quantization (default, fastest).\n"
).
-spec int8_with_block_size(int8_config(), integer()) -> int8_config().
int8_with_block_size(Config, Block_size) ->
{int8_config, Block_size, erlang:element(3, Config)}.
-file("src/viva_tensor/core/config.gleam", 419).
?DOC(
" Default AWQ: block_size=64, 128 calibration samples, scale=1.0.\n"
"\n"
" scale_factor=1.0 is a placeholder - in practice you'd tune this\n"
" per-layer using calibration data. See the paper for the grid search procedure.\n"
).
-spec awq() -> a_w_q_config().
awq() ->
{a_w_q_config, 64, 128, 1.0}.
-file("src/viva_tensor/core/config.gleam", 424).
?DOC(" Set AWQ block size.\n").
-spec awq_with_block_size(a_w_q_config(), integer()) -> a_w_q_config().
awq_with_block_size(Config, Block_size) ->
{a_w_q_config,
Block_size,
erlang:element(3, Config),
erlang:element(4, Config)}.
-file("src/viva_tensor/core/config.gleam", 429).
?DOC(" Set number of calibration samples for saliency estimation.\n").
-spec awq_with_calibration(a_w_q_config(), integer()) -> a_w_q_config().
awq_with_calibration(Config, N) ->
{a_w_q_config, erlang:element(2, Config), N, erlang:element(4, Config)}.
-file("src/viva_tensor/core/config.gleam", 497).
?DOC(
" Enable causal (autoregressive) masking.\n"
"\n"
" For decoder-only models (GPT, LLaMA, etc.) that should only attend\n"
" to past tokens, not future ones. Implemented as a triangular mask.\n"
).
-spec attention_causal(attention_config()) -> attention_config().
attention_causal(Config) ->
{attention_config,
erlang:element(2, Config),
erlang:element(3, Config),
erlang:element(4, Config),
true,
erlang:element(6, Config)}.
-file("src/viva_tensor/core/config.gleam", 506).
?DOC(
" Set dropout probability on attention weights.\n"
"\n"
" 0.0 for inference (always).\n"
" 0.1 is typical for training.\n"
" Higher (0.2-0.3) for small datasets or aggressive regularization.\n"
).
-spec attention_with_dropout(attention_config(), float()) -> attention_config().
attention_with_dropout(Config, Dropout) ->
{attention_config,
erlang:element(2, Config),
erlang:element(3, Config),
Dropout,
erlang:element(5, Config),
erlang:element(6, Config)}.
-file("src/viva_tensor/core/config.gleam", 520).
?DOC(
" Override the softmax scaling factor.\n"
"\n"
" Default is 1/sqrt(head_dim) which prevents attention logits from growing\n"
" too large as dimension increases. You might override this for:\n"
" - Cosine attention (scale=1, use normalized Q and K)\n"
" - ALiBi without scaling (Press et al., 2022)\n"
" - Experimental attention variants\n"
).
-spec attention_with_scale(attention_config(), float()) -> attention_config().
attention_with_scale(Config, Scale) ->
{attention_config,
erlang:element(2, Config),
erlang:element(3, Config),
erlang:element(4, Config),
erlang:element(5, Config),
Scale}.
-file("src/viva_tensor/core/config.gleam", 542).
-spec positive_int_to_float(integer(), float()) -> float().
positive_int_to_float(I, Acc) ->
case I of
0 ->
Acc;
_ ->
positive_int_to_float(I - 1, Acc + 1.0)
end.
-file("src/viva_tensor/core/config.gleam", 535).
-spec int_to_float(integer()) -> float().
int_to_float(I) ->
case I >= 0 of
true ->
positive_int_to_float(I, +0.0);
false ->
+0.0 - positive_int_to_float(0 - I, +0.0)
end.
-file("src/viva_tensor/core/config.gleam", 479).
?DOC(
" Create attention config with required parameters.\n"
"\n"
" Scale is automatically set to 1/sqrt(head_dim) per Vaswani et al. (2017).\n"
" Override with attention_with_scale() if you're doing something exotic\n"
" (e.g., cosine attention, ALiBi without scaling).\n"
).
-spec attention(integer(), integer()) -> attention_config().
attention(Num_heads, Head_dim) ->
Scale = case math:sqrt(int_to_float(Head_dim)) of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> 1.0 / Gleam@denominator
end,
{attention_config, Num_heads, Head_dim, +0.0, false, Scale}.