feat(diffusion): Added Flow Matching - #1931
Conversation
CODEOWNERS review mapCurrent for commit ⏳ @CharlelieLrt — 21 file(s)
⏳ @megnvidia — 2 file(s)
No CODEOWNER
Comment |
Greptile SummaryThe PR adds rectified flow matching to the diffusion stack, including a scheduler, training loss, velocity conversions, and timestep scaling support.
Important Files Changed
Reviews (1): Last reviewed commit: "Added Flow Matching" | Re-trigger Greptile |
laserkelvin
left a comment
There was a problem hiding this comment.
Just two minor general comments.
I think the broader one that I have, which affects the interface more is if we wanted to mask loss contributions before the reduction. For example in a chemistry case where we have a padded batch of atoms, we would want to apply a padding mask
For parity with the denoising score matching loss, we should have a @laserkelvin would this work for the chemistry case you mentioned? |
Dibyajyoti-Chakraborty
left a comment
There was a problem hiding this comment.
Updated done based on the comments:
- Named rectified flow matching:
RectifiedFlowNoiseScheduler, (@CharlelieLrt) - Name changes -
"flow"(named to avoid clashing with v-prediction),flow_predictor/x0_to_flow/flow_to_x0support. (@CharlelieLrt) PredictorType(name changed @CharlelieLrt ) .- Added
WeightedFlowMatchingLoss(support masking etc. @laserkelvin) - Simplified the loss to delegate to the scheduler's
add_noise/x0_to_flowinstead of duplicating the noise-path formula. (@CharlelieLrt )
Yeah |
f80e35f to
f668d72
Compare
|
/ok to test cc0b84d |
Signed-off-by: Charlelie Laurent <claurent@nvidia.com>
Signed-off-by: Charlelie Laurent <claurent@nvidia.com>
Signed-off-by: Charlelie Laurent <claurent@nvidia.com>
| # Resolve the flow-conversion provider. For a | ||
| # DomainParallelNoiseScheduler, the conversion methods live on the | ||
| # wrapped inner scheduler. | ||
| coeff = getattr(noise_scheduler, "inner_scheduler", noise_scheduler) | ||
| if not callable(getattr(coeff, "x0_to_flow", None)): | ||
| raise ValueError( | ||
| "FlowMatchingLoss requires a noise scheduler (or a " | ||
| "DomainParallelNoiseScheduler wrapping one) that exposes " | ||
| f"x0_to_flow; {type(coeff).__name__} does not. " | ||
| "LinearGaussianNoiseScheduler subclasses provide this." | ||
| ) |
There was a problem hiding this comment.
IMO that's not a good pattern because it deviates too much from the existing MSEDSMLoss. Nothing wrong in the implementation in itself, but it would be preferrable to have API parity with the existing loss.
For example, the [optional] conversion methods should be provided as callbacks rather than inferred from the scheduler object. This can be useful when one needs to change just the prediction type without defining a new scheduler class. So, there is redundancy, but it improves API flexibility
There was a problem hiding this comment.
One detail though: the denoising score matching losses expose conversion to x0 (score-to-x0 and noise-to-x0). That is because the loss formulation is based on x0, and any conversion is just an adaptation of this. IMO, the basis prediction for the FlowMatching loss should be the flow prediction, so it should expose callbacks to convert to x0 (x0-to-flow, epsilon-to-flow, score-to-flow)
There was a problem hiding this comment.
Done, both points. The noise_scheduler parameter is documented as the NoiseScheduler protocol only, and the implementation no longer inspects the scheduler type.
The flow matching losses now expose x0_to_flow_fn, score_to_flow_fn, and epsilon_to_flow_fn callbacks with the same pattern as MSEDSMLoss. Flow is the base prediction: every prediction type converts to flow. One note: x0_to_flow_fn is required for all prediction types because it also computes the regression target from clean data.
There was a problem hiding this comment.
The new tests should be reorganized for clarity:
- All pytest configs at the top
- Constructor tests together
- Non regression tests for the non-weighted losses (both DSM and flow mathcing)
- Same for the weighted version
There was a problem hiding this comment.
Done. The file now follows this layout, and the FM losses run through the same classes as the DSM losses via LOSS_CONFIGS/WEIGHTED_LOSS_CONFIGS rows (loss_cls, sched_cls, kwargs, name) — analogous to SCHEDULER_CONFIGS. Same for the multi-diffusion loss/predictor test files.
CharlelieLrt
left a comment
There was a problem hiding this comment.
Two major concerns:
- The PR claims to add support for "flow" prediction, but this support is only very partial with missing conversion callbacks at multiple place in the module
- New tests are a not great, with massive amounts of code duplication, new class-specific configs and tests, while it would be much better to extend the existing tests, etc...
Add rectified flow matching to
physicsnemo.diffusionAdds rectified flow matching (conditional optimal transport) support to the diffusion framework, following the same design as the existing noise scheduler / loss / denoiser stack.
Added
physicsnemo.diffusion.noise_schedulers.FlowMatchingNoiseScheduler— linear interpolation path (α(t) = 1-t,σ(t) = t) with a closed-formget_denoiserRHS.physicsnemo.diffusion.metrics.losses.FlowMatchingLoss— velocity-objective training loss; also supportsx0/epsilon/scoreprediction types on anyLinearGaussianNoiseScheduler.LinearGaussianNoiseScheduler.x0_to_velocity/.velocity_to_x0conversions, andvelocity_predictorsupport inget_denoiser(shared by all linear-Gaussian schedulers, not just flow matching).ConcatConditionWrapper.time_scale— rescales[0,1]-valued flow-matching times into a backbone's expected embedding range (e.g.999.0). Backward compatible (defaults to1.0, not a registered buffer, so old checkpoints load unchanged).Docs
noise_schedulers.rst/metrics.rst.CHANGELOG.mdupdated.Tests
test/diffusion/test_flow_matching.py(new) — scheduler constructor, coefficients, timesteps/sampling,get_denoiser(velocity/x0/epsilon/score/SDE), sampling round-trip.FlowMatchingLosscoverage added totest_losses.py(constructor, non-regression, gradient flow, compile).velocity_predictor/x0_to_velocity/velocity_to_x0coverage added totest_noise_schedulers.py.time_scalecoverage added totest_wrappers.py.Verified on a CPU node: full
test/diffusion/suite.Checklist
Dependencies
Review Process
All PRs are reviewed by the PhysicsNeMo team before merging.
Depending on which files are changed, GitHub may automatically assign a maintainer for review.
We are also testing AI-based code review tools (e.g., Greptile), which may add automated comments with a confidence score.
This score reflects the AI’s assessment of merge readiness and is not a qualitative judgment of your work, nor is
it an indication that the PR will be accepted / rejected.
AI-generated feedback should be reviewed critically for usefulness.
You are not required to respond to every AI comment, but they are intended to help both authors and reviewers.
Please react to Greptile comments with 👍 or 👎 to provide feedback on their accuracy.