~/bend-docscommunity

math_activation.bend source

math_activation.bend on the hub · documented module

# FP32 activations, imported by callers as Act: Act.silu() is a value for# F.conv2d or F.activate, Act.silu_value the scalar function. Each built-in# states its operations per element for the planners, counted from the emitted# C and assembly: arithmetic, comparisons, selects and word operations;# addressing, moves and loop control are excluded. The sigmoid, SiLU, tanh and# GELU run eight lanes at a time, so their counts are the instructions per# eight lanes divided by eight; the others are scalar counts. The sigmoid and# tanh use ordered FP32 arithmetic and word operations (lib/math_fp32.bend).# Sigmoid and SiLU scale their negative tails before the final underflow;# accuracy is measured against MPFR rather than a global rounding guarantee.import Baseimport ./math_fp32.bend as Fp32# Custom is a caller-supplied function; only its operation count lives here.type Activation is Data:  Identity{}  ReLU{}  ReLU6{}  LeakyReLU{slope: F32}  Sigmoid{}  SiLU{}  Tanh{}  HardSigmoid{}  HardSwish{}  GELUTanh{}  Custom{operations: F32}def identity_value(value: F32) -> F32:  valuedef relu_value(value: F32) -> F32:  F32.max(value,0.0)def relu6_value(value: F32) -> F32:  F32.min(F32.max(value,0.0),6.0)def leaky(slope: F32,+value: F32) -> F32:  Bool.pick(F32,F32.is_lt(value,0.0),(value * slope : F32),value)# x for x >= 0, slope * x otherwise.def leaky_relu_value(value: F32,slope: F32) -> F32:  leaky(slope,value)def sigmoid_value(value: F32) -> F32:  Fp32.sigmoid(value)def silu_value(value: F32) -> F32:  Fp32.activate(value,True{})def tanh_value(value: F32) -> F32:  Fp32.tanh(value)# PyTorch's order: relu6(x + 3) / 6 and x * relu6(x + 3) / 6.def hard_sigmoid_value(value: F32) -> F32:  (relu6_value((value + 3.0 : F32)) / 6.0 : F32)def swished(+value: F32) -> F32:  ((value * relu6_value((value + 3.0 : F32)) : F32) / 6.0 : F32)def hard_swish_value(value: F32) -> F32:  swished(value)# PyTorch's gelu(approximate='tanh'): 0.5 x (1 + tanh(sqrt(2/pi) (x + 0.044715 x^3))).def gelu_tanh_of(+value: F32) -> F32:  +cube = ((value * value : F32) * value : F32)  ((0.5 * value : F32) * (1.0 + tanh_value((0.7978845608 * (value + (0.044715 * cube : F32) : F32) : F32)) : F32) : F32)def gelu_tanh_value(value: F32) -> F32:  gelu_tanh_of(value)def identity() -> Activation:  Identity{}def relu() -> Activation:  ReLU{}def relu6() -> Activation:  ReLU6{}def leaky_relu(slope: F32) -> Activation:  LeakyReLU{slope}def sigmoid() -> Activation:  Sigmoid{}def silu() -> Activation:  SiLU{}def tanh() -> Activation:  Tanh{}def hard_sigmoid() -> Activation:  HardSigmoid{}def hard_swish() -> Activation:  HardSwish{}def gelu_tanh() -> Activation:  GELUTanh{}# The identity needs no pass at all.def is_identity(activation: Activation) -> Bool:  match activation:    case Identity{}: True{}    case activation: False{}# Operations per element, excluding the pass that applies them.def operations(activation: Activation) -> F32:  match activation:    case Identity{}: 0.0    # compare and select    case ReLU{}: 2.0    case ReLU6{}: 4.0    # compare, multiply and select    case LeakyReLU{slope}: 3.0    # 31 arithmetic, comparison, select and word instructions per eight lanes    case Sigmoid{}: 3.875    # 34 per eight lanes: scaled numerator and positive-tail selection    case SiLU{}: 4.25    # 54 per eight lanes    case Tanh{}: 6.75    # add, relu6 and divide; hard_swish also multiplies    case HardSigmoid{}: 6.0    case HardSwish{}: 7.0    # 62 per eight lanes: the PyTorch expression around the tanh    case GELUTanh{}: 7.75    case Custom{operations}: operations# A custom function (F.conv2d_custom, F.apply) states its scalar operations per# element: one per arithmetic, comparison or select; F32.exp about 37 and# F32.tanh about 82 with their conversions. The count only steers parallel# planning; results never depend on it. When unsure, use this conservative# count: a call into the C math library and a few operations around it.def unknown_operations() -> F32:  90.0