Layers¶
Multiplicative nn.Module building blocks: the dense SigmaPiLinear, the
convolutional ConvSigmaPi2d block, and the low-rank bilinear PolyLinear.
polyweave.layers ¶
nn.Module building blocks that wrap the low-level ops.
PolyLinear ¶
PolyLinear(in_features: int, out_features: int | None = None, *, rank: int = 8, bias: bool = True, symmetric: bool = False, quad_scale_init: float = QUAD_SCALE_INIT)
Bases: Module
Linear + low-rank quadratic (degree-2 factorization-machine) layer.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
in_features
|
int
|
size of each input sample's last dimension. |
required |
out_features
|
int | None
|
size of each output's last dimension. Defaults to
|
None
|
rank
|
int
|
number of rank-1 bilinear factors in the quadratic branch. |
8
|
bias
|
bool
|
whether the linear branch carries a bias term (default |
True
|
symmetric
|
bool
|
if |
False
|
quad_scale_init
|
float
|
initial per-output gate (default |
QUAD_SCALE_INIT
|
Parameter count: out*in + (bias?out:0) + 2*rank*in + out*rank + out
(with symmetric=True the 2*rank*in term becomes rank*in).
Source code in polyweave/layers/poly_linear.py
quad_scale_mean ¶
Polynomial-recruitment diagnostic exp(quad_scale).mean().
Returns 0.0 when the quadratic branch is disabled (rank == 0),
matching "no multiplicative branch".
Source code in polyweave/layers/poly_linear.py
ConvSigmaPi2d ¶
ConvSigmaPi2d(channels: int, kernel_size: int = 3, padding: int = 1, pi_scale_init: float = PI_SCALE_INIT, max_exponent: float = DEFAULT_MAX_EXPONENT, max_log: float = DEFAULT_MAX_LOG, signed_products: bool = False, center_product: bool = False, eps: float = DEFAULT_EPS)
Bases: Module
Sigma-Pi convolutional block with a genuine geometric-product pi branch.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
channels
|
int
|
number of input == output channels. |
required |
kernel_size
|
int
|
conv kernel size for both branches (default 3). |
3
|
padding
|
int
|
conv padding (default 1, i.e. "same" for kernel 3). |
1
|
pi_scale_init
|
float
|
initial value of the per-channel |
PI_SCALE_INIT
|
max_exponent
|
float
|
bound on each log-space exponent; the pi conv weight is
|
DEFAULT_MAX_EXPONENT
|
max_log
|
float
|
the log-space accumulation is clamped to |
DEFAULT_MAX_LOG
|
signed_products
|
bool
|
if |
False
|
center_product
|
bool
|
if |
False
|
eps
|
float
|
stabiliser inside |
DEFAULT_EPS
|
Source code in polyweave/layers/sigmapi_conv.py
pi_weight ¶
exponent_abs_mean ¶
Recruitment metric A — mean(|exponent|) over the pi weights.
The geometric product is prod |x| ** w; w = 0 means that factor is
|x| ** 0 = 1 (a no-op). So the mean absolute exponent measures how far the
learned product departs from doing nothing — it starts ~0 and grows as the
block recruits multiplicative structure. Unlike pi_scale this is meaningful
even when the product starts at the identity (exp(u) form), because it reads
the product's SHAPE, not its amplitude/volume.
Source code in polyweave/layers/sigmapi_conv.py
branch_energy ¶
Recruitment metric B — how much each branch moves the output.
Returns {"sigma_rms", "pi_rms", "pi_share", "pi_effect_postbn"}.
pi_share = pi_rms / (sigma_rms + pi_rms)is the pre-BN scale share of the pi branch. This OVERSTATES the branch's functional role: the geometric productexp(u)is heavy-tailed, so its RMS is inflated by outliers that BatchNorm then renormalises away. Read with caution.pi_effect_postbnis the honest, post-normalisation measure: the relative L2 change in the block's actual output (relu(bn(.)), in eval mode so running stats are used and untouched) when the pi branch is removed,||relu(bn(sigma+pi)) - relu(bn(sigma))|| / ||relu(bn(sigma+pi))||. Because BatchNorm IS a z-score, this reflects how much the pi branch moves the activations the rest of the network sees — ~0 = pi functionally idle.
Source code in polyweave/layers/sigmapi_conv.py
pi_scale_mean ¶
SigmaPiLinear ¶
SigmaPiLinear(in_features: int, out_features: int | None = None, *, bias: bool = True, pi_scale_init: float = PI_SCALE_INIT, max_exponent: float = DEFAULT_MAX_EXPONENT, max_log: float = DEFAULT_MAX_LOG, signed_products: bool = False, center_product: bool = False, eps: float = DEFAULT_EPS)
Bases: Module
Sigma-Pi fully-connected layer with a genuine geometric-product pi branch.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
in_features
|
int
|
size of each input sample's last dimension. |
required |
out_features
|
int | None
|
size of each output sample's last dimension.
Defaults to |
None
|
bias
|
bool
|
whether the sigma (additive) branch carries a bias term
(default |
True
|
pi_scale_init
|
float
|
initial value of the per-output-feature |
PI_SCALE_INIT
|
max_exponent
|
float
|
bound on the magnitude of each log-space exponent; weights are
|
DEFAULT_MAX_EXPONENT
|
max_log
|
float
|
the log-space accumulation is clamped to |
DEFAULT_MAX_LOG
|
signed_products
|
bool
|
if |
False
|
center_product
|
bool
|
if |
False
|
eps
|
float
|
stabiliser inside |
DEFAULT_EPS
|
Source code in polyweave/layers/sigmapi_linear.py
pi_weight ¶
exponent_abs_mean ¶
Recruitment metric A — mean(|exponent|) over the pi weights.
The geometric product is prod_i |x_i| ** w_i; w_i = 0 means that
factor is |x_i| ** 0 = 1 (a no-op). So the mean absolute exponent measures
how far the learned product departs from doing nothing — it starts ~0 and
grows as the layer recruits multiplicative structure. Unlike pi_scale,
this is meaningful even when the product starts at the identity (exp(u)
form), because it reads the product's SHAPE, not its amplitude/volume.
Source code in polyweave/layers/sigmapi_linear.py
branch_energy ¶
Recruitment metric B — how much each branch moves the output.
Returns {"sigma_rms", "pi_rms", "pi_share"} where pi_share =
pi_rms / (sigma_rms + pi_rms) on the given batch: the fraction of the
output's scale carried by the multiplicative branch. ~0 = pi branch idle,
toward 1 = output dominated by the product. A direct, if noisier, complement
to metric A (which reads the weights; this reads the actual activations).