Complete Networks
Both complete networks share the same frontend–backend architecture and differ only in how the regression head is structured.
MSCNN1D_2DResNetCBAM
MSCNN1D_2DResNetCBAM outputs point estimates
— a single scalar per regression target. Used with
BCEWithPEregLoss.
from sage.architecture.network import MSCNN1D_2DResNetCBAM
model = MSCNN1D_2DResNetCBAM(
frontend_filters=32, # base filter count in ConvBlock
frontend_kernel=64, # base kernel size in ConvBlock
backend_resnet_size=50, # 18 | 34 | 50 | 101 | 152
norm_type="instancenorm", # "batchnorm" | "layernorm" | "instancenorm"
).to(dtype=cfg.dtype, device=cfg.device)
Forward pass:
ranking_stat, point_estimates = model(x)
# x: (B, n_det, compressed_samples)
# ranking_stat: (B, 1) — raw logit for BCE classification
# point_estimates: (B, num_pe) — one scalar per regression target
MSCNN1D_2DResNetCBAM_Heteroscedastic
MSCNN1D_2DResNetCBAM_Heteroscedastic outputs
both the predicted mean and the predicted log-variance for each regression
target. The log-variance is learned alongside the mean, allowing the network to
express varying confidence about each prediction. Used with
BCEWithPEsigmaLoss.
This is the model used in production (O3b run).
from sage.architecture.network import MSCNN1D_2DResNetCBAM_Heteroscedastic
model = MSCNN1D_2DResNetCBAM_Heteroscedastic(
frontend_filters=32,
frontend_kernel=64,
backend_resnet_size=50,
norm_type="instancenorm",
).to(dtype=cfg.dtype, device=cfg.device, memory_format=torch.channels_last)
Forward pass:
ranking_stat, point_estimates = model(x)
# ranking_stat: (B, 1)
# point_estimates: (B, 2 * num_pe)
# columns 0..num_pe-1 = predicted means μ
# columns num_pe..2*num_pe-1 = predicted log-variances log σ²
The predicted uncertainty σ = exp(0.5 * log_var) can be converted to a 1-sigma
confidence interval in physical units after unstandardisation.
Compiling with torch.compile
Both networks are compatible with torch.compile. In production use
mode="max-autotune" for maximum throughput:
model = torch.compile(model, mode="max-autotune", fullgraph=True, dynamic=True)
Compile adds a one-time warmup cost (typically 2–10 minutes) but reduces per-batch inference time by 20–40% on A100/H100 hardware.
Parameter count
For the default configuration (frontend_filters=32, resnet50, 2 detectors,
2 regression targets — tc and mchirp):
total_params = sum(p.numel() for p in model.parameters())
trainable_params = sum(p.numel() for p in model.parameters() if p.requires_grad)
print(f"Total parameters: {total_params:,}")
print(f"Trainable parameters: {trainable_params:,}")
# Total parameters: 36,692,411
# Trainable parameters: 36,692,411
Normalisation choice
The norm_type argument selects the input normalisation layer applied before
the frontend:
|
Behaviour |
|---|---|
|
Normalises each sample independently across the time axis. Recommended —
robust to batch-size variation and compatible with |
|
Normalises across the batch. Sensitive to batch size; less stable with
|
|
Normalises across all features of a sample. Rarely used for 1D signals. |