refactor: extract Flow-GRPO into a DiffusionAlgorithm plugin (prep for NFT / SFT)#52
Closed
niehen6174 wants to merge 5 commits into
Closed
refactor: extract Flow-GRPO into a DiffusionAlgorithm plugin (prep for NFT / SFT)#52niehen6174 wants to merge 5 commits into
niehen6174 wants to merge 5 commits into
Conversation
Introduce algorithm interfaces, registry, shared forward helpers, and the Flow-GRPO loss/label implementation so later algorithms can plug in without growing the FSDP actor further.
Delegate reward postprocess, train-data conversion, and PPO loss to the selected DiffusionAlgorithm, and add --diffusion-algorithm CLI selection.
Add fast tests for builtin registration and group-relative advantage normalization used by the default algorithm plugin.
Use a clearer name for reward-derived training signals (advantages / future NFT weights), and rename labels.py to signals.py accordingly.
Remove unused bsz in Flow-GRPO compute_loss and apply formatter fixes so the pre-commit CI job passes.
Collaborator
Author
|
This PR will be closed and continued in #63 . |
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.
Motivation
We want to support Flow-GRPO, DiffusionNFT, and SFT in one stack. These are not “different loss names on the same train pairs” — they diverge by process direction, which changes collection, train signals, example schema, and loss:
x0is enough)(x_t, x_{t+Δ}, logπ_old, A)(x0, nft_signals)(x0, …)flowchart TB subgraph grpo ["Flow-GRPO (reverse PG)"] direction LR G1["Collect: online SDE<br/>full trajectory + logπ"] --> G2["Signals: group advantage A"] G2 --> G3["Example: x_t, x_tΔ, logπ_old, A"] G3 --> G4["Loss: PPO-clip on logπ ratio"] end subgraph nft ["DiffusionNFT (forward matching)"] direction LR N1["Collect: online<br/>clean x0 + reward<br/>"] --> N2["Signals: soft +/− nft_signals"] N2 --> N3["Example: x0 + nft_signals"] N3 --> N4["Loss: FM with +/− branches"] end subgraph sft ["SFT (forward matching)"] direction LR S1["Collect: offline dataset<br/>x0 + prompt"] --> S2["Signals: none / trivial"] S2 --> S3["Example: x0"] S3 --> S4["Loss: plain FM MSE"] end grpo ~~~ nft nft ~~~ sft style G1 fill:#E8F1FF,stroke:#2F6FED style G4 fill:#E8F1FF,stroke:#2F6FED style N1 fill:#EAF8EF,stroke:#1B7F4E style N4 fill:#EAF8EF,stroke:#1B7F4E style S1 fill:#FFF6E5,stroke:#C47D00 style S4 fill:#FFF6E5,stroke:#C47D00Today those Flow-GRPO assumptions are baked into the actor / converter (
log_prob_old, step pairs, PPO). Adding NFT/SFT withif algorithm == …would keep growing that surface. The right cut is to keep infra and model family shared, and put algorithm decisions behind a plugin:flowchart TB subgraph shared ["Shared (stable)"] Loop["train_diffusion loop"] RM["RolloutManager / Collector"] Actor["FSDP actor: microbatch / optim"] Pipe["TrainPipelineConfig: DiT / CFG"] end subgraph plugin ["DiffusionAlgorithm (swappable)"] Spec["collection_spec"] Rew["postprocess_rewards"] Build["build_train_data"] Loss["compute_loss"] end subgraph impl ["Implementations"] GRPO["FlowGRPO — this PR"] NFT["DiffusionNFT — later"] SFTAlg["SFT — later"] end Loop --> RM --> Spec --> Rew --> Build --> Actor --> Loss --> Pipe GRPO -.-> Spec GRPO -.-> Rew GRPO -.-> Build GRPO -.-> Loss NFT -.-> Spec NFT -.-> Rew NFT -.-> Build NFT -.-> Loss SFTAlg -.-> Spec SFTAlg -.-> Rew SFTAlg -.-> Build SFTAlg -.-> Loss style plugin fill:#F3F0FF,stroke:#6B4FBB style GRPO fill:#E8F1FF,stroke:#2F6FED style NFT fill:#EAF8EF,stroke:#1B7F4E style SFTAlg fill:#FFF6E5,stroke:#C47D00TrainSignals= reward-derived scalars on each sample before building train examples (GRPO advantages, future NFT soft weights) — not classification labels.Modifications (this PR)
miles/algorithms/base(DiffusionAlgorithm,TrainSignals,CollectionSpec),flow_grpo,signals,train_forward_utils,registrymiles/backends/fsdp_utils/actor.pyvalidate_train_batch→prepare_rollout_data→compute_loss(PPO moved out of actor)miles/ray/rollout.pymiles/utils/arguments.py--diffusion-algorithm(defaultflow_grpo) + optional--diffusion-algorithm-pathmiles/utils/diffusion_protocol.pytests/fast/algorithms/Intentionally not changed
train_diffusionouter loop shapeTrainPipelineConfig/ model-family forwardcollection_specis declared but not yet driving sampling)Follow-up plan
nft_signals; relax collection (no traj/logπ); still online + reward.train_diffusioncollect side may need to be pluggable.A * FM), small incremental PR after NFT.collection_specinto rollout sampling params so NFT/SFT do not pay for unused SDE trajectory.Consistency verification
Refactor intent: Flow-GRPO numerically / behaviorally unchanged vs pre-refactor baseline on the main model families.