Repository navigation
✨ DDSP trainable filters, .compile()/.freeze(), CLI pipeline + .fxg, realtime param ramping - #103
Merged
Merged
Conversation
…e + .fxg, realtime param ramping Back-ports six design ideas from the Fluxion proposal (PROJECT.md) into the PyTorch codebase. Deterministic filters are unchanged (still @torch.no_grad()), so non-DDSP users pay no overhead. - ddsp (new, opt-in): LearnableFilter abstract base (extension point: sos()) with LearnableLowpass/Highpass/Peaking/ParametricEQ; BiquadFunction analytic VJP (reuses the native forward kernel; no autograd unrolling) + differentiable_sos_cascade; LearnableGain shows trainable effects. freeze() bridges any of these to a deterministic filter.SOSFilter for fast inference. - filters/chains: FX.compile(fs)/freeze() eagerly design coefficients (lazy stays the default); _frozen forward guard; FilterChain.summary(); shared apply_fs (src/torchfx/_config.py) and build_fused_plan extracted from Wave. - cli: `torchfx pipe` SoX-style positional pipeline, `torchfx compile` -> .fxg artifact, `torchfx process --compiled`; new parse_pipeline reuses the registry. - realtime: set_parameter(name, value, ramp_ms=...) block-rate smoothing; filter coeffs recomputed per block without resetting DF1 state (clickless sweep). - tests: gradcheck + scipy parity + train/freeze (test_ddsp.py), CLI pipeline + .fxg roundtrip (test_cli_pipeline.py), ramp tests (test_realtime.py). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Upgrade deps
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adds an opt-in differentiable DSP (DDSP) stack for trainable IIR filters, introduces explicit coefficient “eagerization” via .compile(fs) / .freeze(), and extends the CLI with a SoX-style pipeline plus a portable compiled .fxg artifact, alongside realtime smoothed parameter ramping.
Changes:
- Introduce
torchfx.ddsp(learnable filters/effects, differentiable SOS cascade w/ analytic VJP, DDSP losses) plus deterministicfilter.SOSFilterfor “train → freeze → fast inference”. - Add explicit
.compile(fs)/.freeze()onFXandFilterChain, plus shared fs-injection helpers and shared fused-plan building. - Add CLI positional pipeline parsing (
torchfx pipe) and compiled pipeline artifacts (torchfx compile/torchfx process --compiled), and realtime block-rate ramping for parameters.
Reviewed changes
Copilot reviewed 28 out of 29 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/test_realtime.py | Adds tests for gradual parameter ramping and filter cutoff ramping. |
| tests/test_ddsp.py | Adds DDSP gradcheck, parity, training, and freeze-bridge tests. |
| tests/test_cli_pipeline.py | Adds tests for pipeline parsing, .fxg roundtrip, and CLI commands. |
| src/torchfx/wave.py | Refactors plan building and fs-application to shared helpers. |
| src/torchfx/realtime/processor.py | Adds ramp_ms parameter automation with worker-thread ramp stepping. |
| src/torchfx/filter/sos.py | Introduces deterministic SOSFilter wrapper over precomputed SOS. |
| src/torchfx/filter/iir.py | Adds frozen-mode guard to skip fs/fingerprint recompute checks. |
| src/torchfx/filter/fused.py | Extracts shared build_fused_plan for SOS fusion lowering. |
| src/torchfx/filter/biquad.py | Adds frozen-mode guard to skip fs/fingerprint recompute checks. |
| src/torchfx/filter/init.py | Exports SOSFilter. |
| src/torchfx/filter/__base.py | Adds _frozen flag to AbstractFilter for freeze semantics. |
| src/torchfx/effect.py | Adds FX.compile(fs) and FX.freeze(fs=None) APIs. |
| src/torchfx/ddsp/losses.py | Adds DDSP multi-resolution STFT reconstruction loss. |
| src/torchfx/ddsp/filter.py | Adds LearnableFilter base + learnable filter implementations and freeze() bridge. |
| src/torchfx/ddsp/effect.py | Adds LearnableGain (trainable pointwise effect) + discussion of limitations. |
| src/torchfx/ddsp/coeffs.py | Adds differentiable RBJ SOS coefficient helpers + SOS frequency response. |
| src/torchfx/ddsp/_autograd.py | Adds differentiable SOS cascade and BiquadFunction analytic backward. |
| src/torchfx/ddsp/init.py | Exposes DDSP public API surface. |
| src/torchfx/chain.py | Adds FilterChain.compile/fs, freeze, and summary() including fused-plan. |
| src/torchfx/_config.py | Adds shared apply_fs / freeze_fx helpers for eager coefficient design. |
| src/torchfx/init.py | Exposes torchfx.ddsp from package root. |
| src/cli/parsing.py | Adds SoX-style positional pipeline parsing on top of the effect registry. |
| src/cli/commands/process.py | Adds --compiled support to apply a precompiled .fxg pipeline. |
| src/cli/commands/pipeline.py | Adds torchfx pipe command to process files with positional pipelines. |
| src/cli/commands/compile.py | Adds torchfx compile and .fxg save/load helpers. |
| src/cli/app.py | Registers new pipe and compile CLI commands. |
| examples/ddsp_graphic_eq.py | Updates example to use torchfx.ddsp time-domain differentiable cascade. |
| CHANGELOG | Documents new DDSP, compile/freeze, CLI pipeline + .fxg, and realtime ramps. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Address Copilot review on #103: - BiquadFunction.forward/backward flatten any leading dims to [N, T] for the native kernel (which TORCH_CHECKs x.dim()==2) and restore the shape, matching the convention used by every other torchfx._ops dispatcher. The docstring already advertised [B, C, T]; it now actually works. - multires_stft_loss builds the Hann window with dtype=x.dtype to avoid a latent float32->float64 promotion inside torch.stft. - Add a [B, C, T] regression test (per-channel parity + grad flow). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Back-ports six design ideas from the Fluxion proposal (
PROJECT.md) into the PyTorch codebase. Deterministic filters are unchanged (still@torch.no_grad()), so non-DDSP users pay zero overhead.What's included
1.
torchfx.ddsp— opt-in differentiable filtersLearnableFilterabstract base (extension point: implementsos()), mirroringfilter.AbstractFilter'scompute_coefficients().LearnableLowpass,LearnableHighpass,LearnablePeaking,LearnableParametricEQ.BiquadFunction— atorch.autograd.Functionwith a hand-derived analytic backward that reuses the native forward kernel (the adjoint of an LTI filter is itself a filter), avoiding the ~30× cost of unrolling the IIR recursion under autograd.differentiable_sos_cascadecomposes a cascade.LearnableGain— shows trainable effects (pointwise → plain autograd). Recursive/native-kernel effects (Delay/Reverb/dynamics) would each need their own analytic-backwardFunction; documented, not auto-covered.freeze()bridges any learnable module to a deterministicfilter.SOSFilterfor fast inference.2. Explicit
.compile()/.freeze()Lazy coefficient design stays the default;
FX.compile(fs)/FilterChain.compile(fs)eagerly design coefficients (no first-forward mutation),freeze()locks them. Works on a lone filter or a chain.FilterChain.summary()renders the topology + fused SOS plan.3. CLI
torchfx pipe IN OUT lowpass --cutoff 800 reverb --mix 0.4(SoX-style positional pipeline)torchfx compile "<pipeline>" --fs 48000 -o chain.fxg→ portable.fxgartifact (filters as precomputed SOS, other effects as specs)torchfx process --compiled chain.fxg4. Realtime smoothed parameter automation
set_parameter(name, value, ramp_ms=...)ramps a parameter at block granularity instead of jumping (no zipper noise); filter coefficients recompute each block without resetting DF1 state, so sweeps stay continuous.Internal
Shared
apply_fs(_config.py) andbuild_fused_planextracted fromWave; newfilter.SOSFilter(raw-SOS deterministic node).Testing
tests/test_ddsp.py(gradcheck of the VJP, scipy forward parity, train + freeze, custom subclass, learnable gain),tests/test_cli_pipeline.py(parser +.fxgroundtrip + CLI), realtime ramp tests intests/test_realtime.py.Known limitation
.compile()/.freeze()remove the lazy first-forward mutation (sotorch.compileworks, graph-breaking around the native kernel), but fulltorch.exportof the forward additionally needs the native SOS kernel registered as a custom op — left as a follow-up. CUDA tests not run locally (no GPU here); the differentiable path only calls the already-CUDA-testedbiquad_forward.🤖 Generated with Claude Code