CoolFace
Apppublic

nicktup/reverb-extractor

sourceHugging Facemitupdated 16d agoView on Hugging Face
0likes
train.py89 linesDownload Raw Back to dfdn
1"""White-box system identification: fit a DifferentiableFDN to a target RIR.2 3Single-RIR optimisation (no batching), following the paper: Adam with a fairly4large learning rate on the perceptual EDC + soft-EDP loss. Every FDN parameter,5including the delay lengths, is updated by backpropagation.6"""7 8from __future__ import annotations9 10from dataclasses import dataclass, field11import torch12 13from .fdn import DifferentiableFDN, FDNConfig14from .losses import total_loss, EDPConfig15 16 17@dataclass18class TrainConfig:19    iters: int = 50020    lr: float = 0.121    lam: float = 0.1              # weight on the soft-EDP term22    betas: tuple = (0.9, 0.999)23    log_every: int = 2524    fdn: FDNConfig = field(default_factory=FDNConfig)25    edp: EDPConfig = field(default_factory=EDPConfig)26    seed: int = 027 28 29def fit_fdn(30    h_target: torch.Tensor,31    cfg: TrainConfig | None = None,32    verbose: bool = True,33):34    """Fit an FDN to ``h_target``. Returns ``(model, history, h_init, h_final)``."""35    cfg = cfg or TrainConfig()36    torch.manual_seed(cfg.seed)37 38    L = h_target.shape[-1]39    # Ensure the frequency-sampling grid is comfortably longer than the RIR to40    # curb time-domain aliasing of the IIR response.41    n_fft = 142    while n_fft < 2 * L:43        n_fft *= 244    fdn_cfg = FDNConfig(45        n_delays=cfg.fdn.n_delays,46        sample_rate=cfg.fdn.sample_rate,47        n_fft=n_fft,48        max_delay_ms=cfg.fdn.max_delay_ms,49        beta_a=cfg.fdn.beta_a,50        beta_b=cfg.fdn.beta_b,51    )52    edp_cfg = EDPConfig(53        window_ms=cfg.edp.window_ms,54        sample_rate=cfg.fdn.sample_rate,55        kappa_start=cfg.edp.kappa_start,56        kappa_end=cfg.edp.kappa_end,57    )58 59    model = DifferentiableFDN(fdn_cfg).to(h_target.device)60    with torch.no_grad():61        h_init = model.render(L).detach().clone()62 63    opt = torch.optim.Adam(model.parameters(), lr=cfg.lr, betas=cfg.betas)64 65    history = {"total": [], "edc": [], "edp": []}66    for it in range(cfg.iters):67        opt.zero_grad()68        h_pred = model.render(L)69        loss, l_edc, l_edp = total_loss(h_pred, h_target, lam=cfg.lam, edp_cfg=edp_cfg)70        loss.backward()71        opt.step()72 73        history["total"].append(float(loss))74        history["edc"].append(float(l_edc))75        history["edp"].append(float(l_edp))76        if verbose and (it % cfg.log_every == 0 or it == cfg.iters - 1):77            dmin = float(model.delays.min())78            dmax = float(model.delays.max())79            print(80                f"iter {it:4d} | L={float(loss):.5e} "81                f"(EDC={float(l_edc):.5e}, EDP={float(l_edp):.5e}) "82                f"| delays[{dmin:.1f},{dmax:.1f}] samp"83            )84 85    with torch.no_grad():86        h_final = model.render(L).detach().clone()87 88    return model, history, h_init, h_final89