Training losses: design notes#
Why the losses in pyFDN.train.losses are shaped the way they are. The
reasoning is qualitative on purpose: what is stated here is a design choice and
its rationale, not a benchmark. Behaviour is FDN- and seed-dependent, so measure
your own case before assuming any of it transfers.
Flatness on the training grid depends on nfft#
FlatMagnitude measures |H| at the model’s DFT bins, so its
frequency resolution is the model’s nfft. The truncation to nfft
samples is a rectangular window, so the peak-to-median range of |H| grows
with nfft, and the mean-squared error weights the tallest modes ever more
heavily. Loss values are therefore comparable across runs at one nfft and
not across different ones. A multi-resolution loss
(FlatSpectrogram), whose analysis windows set their own
resolution, is the way out.
The optimization crosses long plateaus on FlatMagnitude; train_fdn’s
default patience=10 stops inside one. Raise it for a converged fit.
Asymmetric flatness: peaks over dips#
AsymmetricFlatMagnitude raises the two sides of the deviation
from flat to different powers so peaks cost more than dips. The exponent, not a
weight, is what makes it bite: at peak_power=4 a peak twice as tall costs
sixteen times as much. Flat stays the unique minimum at every peak_power
(normalizing by RMS forces <(1 + d)^2> = 1), and the loss is gain-invariant.
It is deliberately not in decibels: ∂dB/∂|H| ∝ 1/|H|, so in dB the
deepest nulls dominate the gradient however lightly weighted. In linear
magnitude the gradient is ∝ p·(d⁺)^(p-1), largest at the tallest peaks,
while a dip is bounded at d = -1.
The cost is steps and steadiness: that same gradient vanishes near the optimum,
so a higher exponent takes longer to converge and varies more from seed to seed.
The advantage over FlatMagnitude is not unconditional. Loss values are not
comparable across peak_power, or with FlatMagnitude; compare the
responses.
Multi-resolution flatness: average over frames first#
FlatSpectrogram averages the short-time magnitudes over frames
into a Welch estimate before measuring flatness. Asking each individual frame
to be flat instead is actively harmful: an isolated echo inside a short frame
already has a flat frame spectrum, so that objective rewards an impulsive,
comb-filtered IR.
Energy decay vs. spectrogram distance#
MatchEnergyDecay compares octave-band Schroeder curves. A
magnitude spectrogram distance is not a substitute for fitting a decay: it
compares two signals frame by frame, and two rooms with identical decay have
uncorrelated fine structure, so predicting silence scores better there than
predicting the right amount of the wrong detail. Fitted to a measured room, a
spectrogram distance is minimized by an FDN whose RT falls well short of the
measurement, where an energy-decay loss is not.
Doubly-cumulated energy#
MatchCumulativeEnergy integrates the short-time power spectrum
twice — backwards in time and along frequency — and scores the RMS difference of
the two surfaces after a compressive power.
Why cumulate twice. The time direction is Schroeder backward integration
(the reason MatchEnergyDecay exists). The frequency direction replaces
splitting into octave bands: band edges are an arbitrary quantization a fit can
satisfy on average while getting the shape wrong, whereas a cumulative sum is
the limit of ever-finer bands and is monotone and smooth in both axes, which a
gradient values. Read down the t = 0 edge and you have the integrated
spectrum (colour); read across the f = 0 edge and you have the full-band
decay; the interior ties them together band by band.
Compression, not decibels. The surface spans the whole dynamic range of the
decay, so a plain MSE would see only the first frames. Raising the normalized
surface to a fractional power (0.5 default) compresses that range while
staying bounded, its gradient ∝ x^(p-1) finite everywhere the floor allows.
A logarithm is worse: it turns the silence below the response into an
unbounded penalty dominated by whichever bin is nearest zero.
Which way the frequency cumulation runs. Cumulating downwards alone — the
default, and the plain reading of “energy above this frequency” — leaves the
bottom octave with almost no gradient, and a fit that has to find a decay
tends to abandon it there. frequency="both" scores both directions and
averages, which recovers the low end; it is the setting to reach for when the
decay is not given. This is a matter of weighting rather than frequency
resolution, so a longer analysis window is not the fix.