Configuration Reference
A Sage production run is controlled by two files that live alongside the run script:
``config.py`` —
RunCFGandDataCFG: training loop settings, paths to data files.``gwconfig.yaml`` — parameter priors, constraints, and waveform transforms for the signal sampler.
The run script (train.py) registers these configs once at startup via
register_configs and then reads them anywhere in the codebase via
get_cfg() / get_data_cfg().
The files shown here are taken directly from the O3b production run under runs/o3b/.
Run configuration (config.py)
RunCFG
Controls the training loop and hardware settings.
class O3bCFG:
export_dir = "./run_export"
batch_size = 128
device = "cuda:0"
dtype = torch.float32
detectors = ["H1", "L1"]
do_point_estimate = ["tc", "mchirp"]
autocast = True
class_balance = 0.5
clip_norm = 1.0
num_epochs = 80
training_iterations = int(2_000_000 / batch_size)
validation_iterations = int(200_000 / batch_size)
Field |
Default |
Description |
|---|---|---|
|
|
Directory where checkpoints, loss logs, and exported artefacts are written. |
|
|
Number of samples per training step. Halving this roughly halves peak VRAM usage. |
|
|
PyTorch device string. Use |
|
|
Floating-point precision for model weights and activations. |
|
|
Active detector network. Each entry must have a corresponding noise file in
|
|
|
Parameters for which the model produces a heteroscedastic regression output
(mean + uncertainty) in addition to the detection score. Must be a subset of
the parameters listed in |
|
|
Enables |
|
|
Fraction of each batch drawn from the signal class. |
|
|
Maximum L2 norm for gradient clipping (passed to |
|
|
Total number of training epochs. |
|
|
Number of batches per training epoch, expressed as total samples divided by
batch size. With |
|
|
Number of batches per validation pass. Validation runs on epoch 0 and then every 5 epochs. |
DataCFG
Controls data paths and signal processing parameters shared across the entire pipeline.
class O3bDataCFG:
data_dir = "/path/to/data_dir"
training_noise_files = [
"/path/to/data_H1_O3b.bin",
"/path/to/data_L1_O3b.bin",
]
validation_noise_files = [
"/path/to/data_H1_O3a.bin",
"/path/to/data_L1_O3a.bin",
]
sample_rate = 2048.0 # Hz
noise_low_frequency_cutoff = 15.0 # Hz
signal_low_frequency_cutoff = 20.0 # Hz
sample_length_in_s = 12.0 # seconds
padding_length_in_s = 2.0 # seconds
Field |
Default (O3b) |
Description |
|---|---|---|
|
(path) |
Parent directory for all intermediate data products (PSDs, processed segments). |
|
O3b H1 + L1 |
Monolithic noise files produced by the data priming step, one per detector,
used for the training split. Order must match |
|
O3a H1 + L1 |
Noise files for the validation split. Using a different observing run here (O3a vs O3b) provides an out-of-distribution test of noise generalisation. |
|
|
Target sample rate in Hz after downsampling. All time-domain operations use this rate. |
|
|
Low-frequency cutoff applied when downloading and whitening noise data, in Hz. |
|
|
Low-frequency cutoff applied during waveform generation, in Hz. |
|
|
Total duration of each data sample fed to the network, in seconds. |
|
|
Extra data fetched at both edges of each noise window before whitening.
Whitening corrupts the edges of the time series; the padding region absorbs
this corruption and is trimmed away, leaving a clean |
Signal prior configuration (gwconfig.yaml)
gwconfig.yaml is read by read_from_config and passed to the signal sampler.
It defines which waveform parameters are sampled, their prior distributions,
physical constraints, and transforms applied before waveform generation.
variable_params:
- mass1
- mass2
- ra
- dec
- inclination
- coa_phase
- polarization
- chirp_distance
- spin1_a
- spin1_azimuthal
- spin1_polar
- spin2_a
- spin2_azimuthal
- spin2_polar
- injection_time
- tc
variable_params
Lists every parameter that is sampled per injection. All entries must have a
corresponding prior defined under priors.
priors
Parameter |
Prior |
Notes |
|---|---|---|
|
|
GPS start time of the noise window. Range spans the O3b observing period (November 2019 – March 2020). |
|
|
Coalescence time in seconds, measured within the 12 s sample window. Placing the merger near the end leaves a long inspiral visible to the network. |
|
|
Primary component mass. The |
|
|
Secondary component mass. |
|
|
Spin magnitude of the primary, in units of the maximum Kerr spin. |
|
|
Spin tilt and azimuthal angle sampled uniformly on the unit sphere via
|
|
|
Spin magnitude of the secondary. |
|
|
Spin orientation of the secondary, sampled as above. |
|
|
Right ascension and declination sampled uniformly over the sphere. |
|
|
Binary inclination angle; the |
|
|
Coalescence phase, uniform on [0, 2π). |
|
|
Gravitational-wave polarisation angle, uniform on [0, 2π). |
|
|
Distance parameterised by the chirp-mass–weighted luminosity distance.
|
constraints
constraints:
- name: mass_order
mass_order rejects samples where mass1 < mass2, enforcing the convention
that the primary is always the heavier component.
waveform_transforms
Applied after sampling, before waveform generation.
Transform |
Effect |
|---|---|
|
Converts |
|
Same conversion for the secondary spin. |
|
Computes |
|
Converts |
Training graph (train.py)
Signal sampler
param_sampler = read_from_config("./gwconfig.yaml", seed=150914)
waveform_project = ConstantProjection()
snrscaler = OptimalSNRRescaler(HalfNorm(scale=4.0, loc=5.0, seed=150914))
signal_sampler = IMRPhenomPv2(param_sampler, waveform_project, augment=snrscaler)
The seeds used here (150914, 170817) match the GPS dates of GW150914 and
GW170817 — the first binary black hole and binary neutron star detections respectively.
Validation uses the alternate seed to guarantee independent sampling.
Component |
Role |
|---|---|
|
Parses |
|
Projects the waveform onto the detector network using antenna pattern factors that are held fixed over the duration of the signal. This is accurate for CBC signals, which are short enough that the detector orientation relative to the source does not change appreciably due to Earth’s rotation. |
|
Samples target optimal SNR values from a half-normal distribution with location 5 and scale 4 (most injections fall between SNR 5 and ~15). |
|
Rescales each waveform amplitude so its optimal SNR matches the sampled target. |
|
Wraps all of the above; calling |
Noise sampler
recolour = RecolourPostprocess(
p_recolour=0.37,
recolour_dataset_dir="/path/to/o3a",
)
noise_sampler = MemmapNoiseSampler(postprocess_fn=recolour, prefetch=8, seed=150914)
Parameter |
Description |
|---|---|
|
Probability that a noise window is recoloured with a PSD drawn from a different
segment. |
|
Directory containing the O3a data used as the recolouring PSD library. |
|
Number of batches prefetched to the GPU ahead of training. Increase on disk-bound systems; decrease if VRAM is tight. |
Preprocessor
whitener = FiducialWhitening()
binning = DyadicPyramidBinning(bounds)
mrsampler = MultirateSampler(binning_method=binning)
processor = Preprocessor([whitener, mrsampler])
Applies whitening followed by multirate compression. The binning boundaries are
derived from the parameter prior bounds so that the time-resolution allocation
matches the signal’s frequency evolution across the full prior volume.
Note
Inverse Spectrum Truncation (IST) is intentionally disabled during PSD
estimation (apply_inverse_spectrum_truncation=False in dataset.py). IST
smooths sharp spectral lines by windowing the inverse PSD in the time domain, but
this also removes fine spectral features. Preserving those features keeps the PSD
library more varied, which benefits recolouring augmentation during training.
Model and optimisation (train.py)
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)
model = torch.compile(model, mode="max-autotune", fullgraph=True, dynamic=True)
loss_function = BCEWithPEsigmaLoss(regression_weight=0.005, coupling_weight=0.005)
optimiser = optim.Adam(model.parameters(), lr=2e-4, weight_decay=1e-6, fused=True)
scheduler = CosineAnnealingWarmRestarts(optimiser, T_0=5, T_mult=2, eta_min=1e-6)
scaler = torch.amp.GradScaler(cfg.device, enabled=cfg.autocast)
Setting |
Notes |
|---|---|
|
Number of convolutional filters in the multi-scale frontend. |
|
Largest kernel size in the frontend; controls the longest time-scale feature the network can detect at full resolution. |
|
ResNet depth for the 2-D backend (50, 101, or 152). ResNet-50 is the recommended default; larger sizes increase VRAM usage substantially. |
|
Normalisation layer type. |
|
Kernel auto-tuning; the first epoch is slow but steady-state throughput improves
significantly. |
|
Combined binary cross-entropy (detection) and heteroscedastic regression (parameter estimation) loss. |
|
Relative weight of the regression term in the total loss. |
|
Relative weight of the uncertainty coupling term. |
|
Initial learning rate. Reduce if training shows NaN losses early on. |
|
Learning rate schedule that restarts every |