specsr.models.blocks

Building blocks shared across the SR1, ZHead and SR2 architectures.

Attribute names and numerical behaviour here are load-bearing: published checkpoints are keyed on them, so changing a submodule name breaks weight loading. Keep signatures stable and add new behaviour behind defaults.

Functions

build_param_groups(model, lr, weight_decay)

Split parameters into decayed and non-decayed groups.

get_activation(name)

Resolve an activation by name.

highpass(x[, k])

Remove the smooth component, leaving small-scale structure.

largest_divisor_at_most(channels[, groups])

Largest g <= groups that divides channels exactly.

odd_kernel(k, length)

Clamp k to an odd kernel size that fits in a sequence of length.

smooth1d(x[, k])

Moving-average smooth along the last axis with reflect padding.

Classes

ResidualBlock1D(*args, **kwargs)

Pre-activation 1D residual block with a scaled residual branch.

class specsr.models.blocks.ResidualBlock1D(*args, **kwargs)[source]

Bases: Module

Pre-activation 1D residual block with a scaled residual branch.

The residual is scaled by alpha rather than added at unit weight, which keeps activations well conditioned when many blocks are stacked.

Parameters:
forward(x)[source]
Parameters:

x (torch.Tensor)

Return type:

torch.Tensor

specsr.models.blocks.get_activation(name)[source]

Resolve an activation by name.

elu is the Exponential Linear Unit: x for x > 0 and alpha * (exp(x) - 1) otherwise. Unlike ReLU it has non-zero gradient for negative inputs, which avoids dead units, and its output mean sits closer to zero.

Parameters:

name (str)

Return type:

torch.nn.Module

specsr.models.blocks.build_param_groups(model, lr, weight_decay)[source]

Split parameters into decayed and non-decayed groups.

Weight decay is applied only to multi-dimensional weight tensors. Biases and normalisation parameters are excluded, which is standard practice: decaying them tends to hurt without regularising anything meaningful.

Parameters:
Return type:

list[dict]

specsr.models.blocks.smooth1d(x, k=31)[source]

Moving-average smooth along the last axis with reflect padding.

k is forced odd and clipped to the sequence length, so the output always has the same length as the input.

Parameters:
Return type:

torch.Tensor

specsr.models.blocks.highpass(x, k=51)[source]

Remove the smooth component, leaving small-scale structure.

Parameters:
Return type:

torch.Tensor

specsr.models.blocks.largest_divisor_at_most(channels, groups=8)[source]

Largest g <= groups that divides channels exactly.

GroupNorm requires the channel count to be divisible by the group count. Hyperparameter sweeps produce channel widths that are not multiples of 8 (e.g. 108), so the group count is chosen adaptively rather than fixed: 108 resolves to 6 groups (108/6 = 18) while 96 keeps 8 (96/8 = 12).

Parameters:
Return type:

int

specsr.models.blocks.odd_kernel(k, length)[source]

Clamp k to an odd kernel size that fits in a sequence of length.

Reflect-padding by k // 2 on each side and pooling with stride 1 returns the input length only when k is odd. The original code had two inconsistent versions of this clamp — one rounding even k down (k -= 1) and one rounding up (k | 1) — and the rounding-up variant could leave k even after being clipped to the sequence length, silently returning a sequence one sample longer than the input.

Both agree for odd k, which is what every shipped config uses, so this did not affect published results. It is fixed here so it cannot.

Parameters:
Return type:

int