flowforge

Model Card — FlowForge / FlowFuse

Author: 晨星 · v0.1.0 · MIT · last updated 2026-10-11


Model details

Field Value
Name FlowForge (FlowFuse = flagship)
Type Normalizing-flow density estimator (exact likelihood generative model)
Components RealNVP (6 affine-coupling blocks) · MAF-stack (2 masked-autoregressive blocks) · log-linear mixture fusion
Parameters 3,424 (flagship: RealNVP 2,130 + MAF 1,292 + 2 mixture weights)
Implementation pure NumPy + scikit-learn, CPU-only, no pretrained weights
Training exact maximum likelihood, Adam, cosine LR, early stopping on validation

Intended use

In scope

Out of scope (not validated)

Training data

Synthetic benchmarks generated by this repository (no external data, no PII):

Suite Datasets Purpose
Discriminative (d ≥ 3) warp6, warp8, banana6, banana8, torus3 primary evaluation — non-Gaussian, a GMM is not near-optimal
Diagnostic (2-D) checkerboard, moons, rings, gmm8, spirals visualisation / sanity only, not used for the gate

Each split is drawn independently from one fixed distribution; the standardiser is fitted on the training split only.

Performance (3 seeds, mean ± std, test NLL in nats, lower is better)

Measured on the delivery machine (CPython 3.13.14, NumPy 2.5.3, CPU, 73.4 s). “Strongest baseline” = lowest-NLL baseline on that dataset.

Dataset Strongest baseline FlowFuse Δ nats Δ % Verdict
warp6 Gauss-full 7.9924 7.7696 ± 0.0219 +0.2228 +2.79% WIN
warp8 Gauss-full 10.2360 10.1569 ± 0.0121 +0.0790 +0.77% WIN
banana6 GMM 7.9497 7.4582 ± 0.0633 +0.4915 +6.18% WIN
banana8 GMM 10.7880 10.1062 ± 0.0327 +0.6819 +6.32% WIN
torus3 GMM 3.3499 3.6812 ± 0.1064 −0.3313 −9.89% LOSE

Gate: 4/5. Significance rule: win iff Δmean > 0.5 · (σ_baseline + σ_flagship).

Ablation — fusion on vs. best single member (positive ⇒ fusion helped):

Dataset Best member FlowFuse Δ
warp6 RealNVP-b6 7.8233 7.7696 +0.0537
warp8 MAF-x2 10.1943 10.1569 +0.0374
banana6 MAF-x2 7.5845 7.4582 +0.1263
banana8 MAF-x2 10.2580 10.1062 +0.1518
torus3 RealNVP-b6 3.6959 3.6812 +0.0146

The fusion improves every dataset, including the one it loses — and it helps most where the two families disagree, because the winner is dataset-dependent (MAF wins the warps, RealNVP wins the bananas).

Known limitations

  1. torus3 is a genuine loss. A torus is a 2-D surface in 3-D that a 16-component GMM tiles cheaply; a smooth diffeomorphism must bend all of space to represent it. More training narrows but does not close the gap.
  2. Narrow wins are fragile. warp8 (+0.77%) is barely above the noise floor; do not read sub-2% gains as robust.
  3. 2-D toys are non-discriminative. See below.
  4. Under-training shows up as losses, not errors. A flow contains the Gaussian as a special case, so any loss to a Gaussian baseline is an optimisation-budget failure rather than a modelling failure.

Why the gate is defined on the d ≥ 3 suite

In 2-D, a 16-component full-covariance GMM is essentially Bayes-optimal; on gmm8 it is literally the generating process and therefore unbeatable by construction. Reporting a flow-vs-GMM win on 2-D toys would be unachievable by design, so those datasets are reported for diagnostics only and the performance gate is defined on the discriminative suite. Reproduce with python flowforge/examples/run_demo.py --diagnostic-2d.

Verification

Invariant Result
inverse(forward(x)) == x ≤ 4.4e-16
coupling log|det| == Σ s exactly 0.0
analytic vs finite-difference Jacobian log|det| < 1e-5
composite log|det| == Σ parts < 1e-12
analytic gradient vs central differences 1.8e-10 / 7.8e-10
MAF output c independent of x_{≥c} 0 violations
EM validation log-likelihood monotone never decreases
gain gate ships ≥ best single member enforced by test
same seed ⇒ bit-identical metrics worst abs diff 0.0
scaler fitted on train only asserted

50/50 tests pass; demo end-to-end 73.4 s on CPU.

Synthetic data only; no personal data, no licensed corpora, no pretrained weights. Dependencies are NumPy (BSD-3), SciPy (BSD-3), scikit-learn (BSD-3) — all MIT-compatible. Optional torch/nflows are excluded from the default path.