Flow-GRPO: Training Flow Matching Models via Online RL

Authors: Jie Liu*, Gongye Liu*, Jiajun Liang, Yangguang Li, Jiaheng Liu, Xintao Wang, Pengfei Wan, Di Zhang, Wanli Ouyang† Affiliations: MMlab CUHK, Tsinghua University, Kling Team (Kuaishou Technology), Nanjing University, Shanghai AI Laboratory arXiv: 2505.05470 Project Page: gongyeliu.github.io/Flow-GRPO GitHub: yifan123/flow_grpo Venue: NeurIPS 2025

1. Motivation(研究动机)

Flow Matching 模型(如 SD3.5、FLUX)已成为当前文生图(T2I)领域的主流骨干,其理论基础扎实、生成质量高。然而,这类模型在处理多物体组合(数量计数、空间关系、属性绑定)及文字渲染等复杂任务时仍存在明显短板。

与此同时,在线强化学习(Online RL)在提升大语言模型推理能力上取得了巨大成功(DeepSeek-R1、OpenAI-o1),但将 RL 应用于 Flow Matching 模型面临两个根本矛盾:

  1. 随机性矛盾:RL 依赖随机采样来探索环境,而 Flow Matching 模型基于确定性 ODE 进行生成,无法提供 policy gradient 所需的转移概率 ;确定性采样下不同初始 seed 产生的轨迹几乎一致,导致探索极度匮乏。

  2. 效率矛盾:Online RL 需要反复从当前策略采样数据,而 Flow Matching 推理通常需要 28–40 步去噪,数据收集代价高昂,制约了大规模 RL 训练的可行性。

本文提出 Flow-GRPO,通过两项关键策略——ODE-to-SDE 转换和 Denoising Reduction——首次将 online policy gradient RL(GRPO)成功引入 Flow Matching 模型。


2. Idea(核心思想)

Flow-GRPO 的核心思路可用一句话概括:把 Flow Matching 的确定性 ODE 采样器替换为等价的 SDE 采样器,引入随机性以支持在线 RL,同时大幅减少训练阶段的去噪步数以提升效率。

具体而言:

  • ODE-to-SDE 转换:构造与原始 ODE 在每个时间步边际分布完全一致的反向时间 SDE,引入受控随机性,使 policy 转移概率可计算,KL 散度可闭合求解。
  • Denoising Reduction:训练时仅使用 步去噪(相比推理默认的 步减少 4×),通过少量低质量但信息丰富的样本驱动 RL 更新,推理时恢复完整步数,性能不降。
  • GRPO on Flow:沿用 GRPO 的组相对优势估计,避免 value network,在 flow matching 的多步 MDP 框架上高效优化 policy。

3. Method(方法)

3.1 整体框架

Figure 2 解读:框架图展示了 Flow-GRPO 的完整训练流程。左侧为 SDE Sampling 模块:给定 prompt,Flow Matching T2I 模型在 Markov Decision Process 框架下执行 SDE 采样,状态从 经过 步(Denoising Reduction)去噪到 ,每步动作 对应 SDE 更新规则 。右侧为 Group Relative Policy Optimization 模块:对同一 prompt 生成 条轨迹,计算各自的奖励 ,通过组内归一化得到优势 ,最终通过 GRPO 目标 更新模型。Denoising Reduction()保证了样本收集的高效性。

3.2 将去噪过程建模为 MDP

如 Section 3 所述,Flow Matching 的迭代去噪过程可以被形式化为一个 Markov Decision Process(MDP)

  • 状态 :文本条件 、时间步 、当前 latent
  • 动作 :模型预测的去噪样本
  • 策略 (确定性 ODE 下难以计算)
  • 初始状态分布
  • 奖励 仅在终止步给出: 时),其余步为 0

RL 目标是最大化期望累积奖励(含 KL 正则):

3.3 GRPO on Flow Matching

GRPO 放弃 value network,改用组相对优势估计。对于 prompt ,flow model 生成 张图像 及对应的反向时间轨迹 。第 张图的优势通过组内奖励归一化计算:

Flow-GRPO 的优化目标为:

其中:

重要性权重比率为:

3.4 ODE-to-SDE 转换(核心推导)

问题:Flow Matching 原始采样过程是确定性 ODE:

确定性转移导致 退化为 Dirac delta,RL 所需的 无法计算,且缺乏探索。

目标:构造等价 SDE,使其在每个时间步的边际概率密度函数与原始 ODE 完全一致。

推导步骤(详见 Appendix A):

步骤 1:设通用 SDE 形式为 ,其边际密度 满足 Fokker-Planck 方程:

步骤 2:要使 SDE 边际分布与 ODE(Eq. 6)一致,对比两式的 Fokker-Planck 方程,利用:

解出前向 SDE 的漂移系数:

步骤 3:利用前向-反向 SDE 对应关系(Anderson 1982)。若前向 SDE 为 ,则对应反向时间 SDE 为:

步骤 4:令 ,代入前向 SDE 漂移 ,得到反向时间 SDE:

步骤 5:对于 Rectified Flow(),利用条件分布:

推导出 score function:

步骤 6:代入 Eq. 21,得到 Rectified Flow 专用的反向时间 SDE:

步骤 7:应用 Euler-Maruyama 离散化,得到最终更新规则:

其中 为控制噪声水平的标量超参数(本文取 )。

KL 散度的闭合解:由 Eq. 9 可见, 是均值为 、方差为 的各向同性高斯分布。两个高斯 policy 之间的 KL 散度可以闭合求解:

这是 Flow-GRPO 能够高效计算 KL 正则项的关键所在。

3.5 Denoising Reduction

Flow Matching 模型推理通常需要 步,数据收集成本高昂。Flow-GRPO 的关键发现是:RL 训练阶段并不需要高质量样本,只需样本包含足够的奖励信号

策略:训练时使用 步去噪,推理时保留完整的 步(SD3.5-M 默认值)。

效果:与 相比, 在三个任务上均实现了超过 的训练加速,且最终收敛奖励无明显差异。进一步减至 反而不稳定。

3.6 伪代码

伪代码 1:ODE-to-SDE 转换(单步实现)

# 对应 sd3_sde_with_logprob.py: sde_step_with_logprob()
def ode_to_sde_step(model_output, timestep, sample, noise_level=0.7, generator=None):
    """
    将 Flow Matching ODE 单步转换为等价 SDE 单步,并计算 log-prob。
    对应论文 Eq. 9 (Euler-Maruyama 离散化)。
    """
    # 获取当前和上一时间步的 sigma
    step_index = scheduler.index_for_timestep(timestep)
    sigma = scheduler.sigmas[step_index]        # σ_t
    sigma_prev = scheduler.sigmas[step_index+1] # σ_{t-1}(反向:t 减小)
    dt = sigma_prev - sigma                      # Δt < 0(反向时间)
 
    # 计算 σ_t^{SDE} = a * sqrt(t/(1-t)) (Eq. 9 中的 σ_t)
    std_dev_t = sqrt(sigma / (1 - sigma)) * noise_level
 
    # SDE 均值更新(Eq. 9):
    # x_{t+Δt} = x_t + [v_θ + σ_t²/(2t) * (x_t + (1-t)*v_θ)] * Δt
    prev_sample_mean = (sample * (1 + std_dev_t**2 / (2*sigma) * dt)
                       + model_output * (1 + std_dev_t**2 * (1-sigma) / (2*sigma)) * dt)
 
    # 注入随机性:σ_t * sqrt(|Δt|) * ε,ε ~ N(0, I)
    variance_noise = randn_tensor(model_output.shape, generator=generator)
    prev_sample = prev_sample_mean + std_dev_t * sqrt(-dt) * variance_noise
 
    # 计算 log π_θ(x_{t-1} | x_t):高斯 log-prob(忽略常数项)
    log_prob = (
        -((prev_sample.detach() - prev_sample_mean)**2)
        / (2 * (std_dev_t * sqrt(-dt))**2)
        - log(std_dev_t * sqrt(-dt))
        - log(sqrt())
    ).mean(dim=(1,2,3))  # 对空间维度求均值,保留 batch 维
 
    return prev_sample, log_prob, prev_sample_mean, std_dev_t

伪代码 2:含 log-prob 的轨迹采样

# 对应 sd3_pipeline_with_logprob.py: pipeline_with_logprob()
def sample_trajectory_with_logprob(prompt, pipeline, noise_level=0.7, num_steps=10):
    """
    从当前策略 π_θ 采样完整去噪轨迹,记录所有中间 latent 和 log-prob。
    对应论文中"Markov Decision Process via SDE Sampling"。
    """
    # 编码文本条件
    prompt_embeds, pooled_embeds = pipeline.encode_prompt(prompt)
 
    # 初始状态 x_T ~ N(0, I)
    x_t = randn_tensor(latent_shape)
    all_latents = [x_t]
    all_log_probs = []
 
    # 反向时间去噪:T → 0(Denoising Reduction: num_steps=10)
    for t in reversed(scheduler.timesteps):  # 10 步
        # 预测速度场 v_θ(x_t, t)(含 CFG)
        noise_pred_uncond, noise_pred_text = transformer(x_t, t, prompt_embeds)
        v_pred = noise_pred_uncond + guidance_scale * (noise_pred_text - noise_pred_uncond)
 
        # SDE 单步 + log-prob(Eq. 9)
        x_t, log_prob, _, _ = sde_step_with_logprob(
            scheduler, v_pred, t, x_t, noise_level=noise_level
        )
        all_latents.append(x_t)
        all_log_probs.append(log_prob)
 
    # VAE 解码
    image = vae.decode(x_t / vae.config.scaling_factor)
    return image, all_latents, all_log_probs

伪代码 3:轨迹采样 + 奖励收集

# 对应 train_sd3.py: 采样阶段
def collect_trajectories(prompts, pipeline, reward_fn, G=24, num_steps=10):
    """
    对每个 prompt 生成 G 条轨迹,计算奖励和组相对优势。
    对应论文 Eq. 4 (组相对优势估计)。
    """
    all_trajectories = []
 
    for prompt in prompts:
        trajectories = []
        images = []
 
        # 生成 G 条轨迹(组采样)
        for i in range(G):
            image, latents, log_probs = sample_trajectory_with_logprob(
                prompt, pipeline, num_steps=num_steps
            )
            trajectories.append({'latents': latents, 'log_probs': log_probs})
            images.append(image)
 
        # 计算奖励(可并行,ThreadPoolExecutor)
        rewards = reward_fn(images, prompt)  # shape: [G]
 
        # 组相对优势(Eq. 4)
        advantages = (rewards - rewards.mean()) / (rewards.std() + 1e-8)
 
        all_trajectories.append({
            'trajectories': trajectories,
            'rewards': rewards,
            'advantages': advantages,
            'prompt': prompt,
        })
 
    return all_trajectories

伪代码 4:Flow-GRPO 策略更新

# 对应 train_sd3.py: 训练阶段
def flow_grpo_update(trajectories, model, ref_model, optimizer,
                     epsilon=0.2, beta=0.04, inner_epochs=1):
    """
    基于收集的轨迹执行 GRPO 策略梯度更新。
    对应论文 Eq. 5 (Flow-GRPO 目标函数)。
    """
    for epoch in range(inner_epochs):
        for batch in trajectories:
            total_loss = 0.0
 
            for t_idx in range(num_timesteps):  # T=10 步
                x_t = batch['latents'][t_idx]
                x_prev = batch['latents'][t_idx + 1]
                old_log_prob = batch['log_probs'][t_idx]  # π_θ_old
                advantage = batch['advantages']
 
                # 用当前 θ 重新计算 log-prob
                v_pred = model(x_t, timestep, prompt_embeds)
                _, new_log_prob, prev_mean, std_dev = sde_step_with_logprob(
                    scheduler, v_pred, timestep, x_t,
                    prev_sample=x_prev  # 固定 x_{t-1} 计算 log-prob
                )
 
                # 重要性权重比率 r_t^i(θ)(Eq. 5)
                log_ratio = new_log_prob - old_log_prob
                ratio = torch.exp(log_ratio)
 
                # PPO-clip 目标(Eq. 5)
                unclipped = -advantage * ratio
                clipped = -advantage * torch.clamp(ratio, 1-epsilon, 1+epsilon)
                policy_loss = torch.max(unclipped, clipped).mean()
 
                # KL 正则项(闭合解)
                if beta > 0:
                    v_ref = ref_model(x_t, timestep, prompt_embeds)
                    kl_loss = compute_kl_divergence(v_pred, v_ref, std_dev, dt)
                    total_loss += policy_loss + beta * kl_loss
                else:
                    total_loss += policy_loss
 
            # 梯度更新(跨时间步累积)
            (total_loss / num_timesteps).backward()
 
        optimizer.step()
        optimizer.zero_grad()

3.7 代码与论文对应关系

论文概念代码位置关键变量/函数
SDE 更新规则 Eq. 9sd3_sde_with_logprob.pyprev_sample_meanstd_dev_tdt
sd3_sde_with_logprob.pystd_dev_t = sqrt(sigma/(1-sigma)) * noise_level
sd3_sde_with_logprob.pylog_prob 计算块
含 log-prob 的 pipelinesd3_pipeline_with_logprob.pypipeline_with_logprob(),返回 all_latents, all_log_probs
轨迹采样 + Denoising Reductiontrain_sd3.pyconfig.sample.num_steps=10pipeline_with_logprob 调用
组相对优势 Eq. 4train_sd3.pyadvantages = (rewards - mean) / std
GRPO loss Eq. 5train_sd3.pyratiotorch.clamppolicy_loss
KL 正则(闭合解)train_sd3.pykl_lossconfig.train.beta
奖励函数flow_grpo/rewards.pyocr_score()geneval_score()pickscore()
LoRA 配置train_sd3.pylora_config
多 GPU 训练train_sd3.py + fsdp_utils.py24 × NVIDIA A800

4. Experimental Setup(实验设置)

基础模型与任务

Flow-GRPO 在 Stable Diffusion 3.5 Medium(SD3.5-M) 上训练,并通过 LoRA()进行参数高效微调。评估三类任务:

任务 1:组合图像生成(Compositional Image Generation)

  • 基准:GenEval(6 个子任务:Single Object、Two Objects、Counting、Colors、Position、Attribute Binding)
  • Prompt 比例(训练集):Position : Counting : Attribute Binding : Colors : Two Objects : Single Object = 7:5:3:1:1:0
  • 奖励(rule-based):
    • Counting:
    • Position / Color:物体数量正确给部分奖励,位置/颜色也正确再给剩余奖励

任务 2:视觉文字渲染(Visual Text Rendering)

  • Prompt 模板:"A sign that says 'text'"
  • 使用 GPT-4o 生成 20K 训练 prompt + 1K 测试 prompt
  • 奖励(rule-based): 为最小编辑距离, 为 prompt 中引号内的字符数

任务 3:人类偏好对齐(Human Preference Alignment)

  • 奖励模型:PickScore(基于人类配对标注的偏好模型)
  • 评估数据集:DrawBench(多样化 prompt 集)

核心超参数

参数
训练去噪步数 10
推理去噪步数 40
组大小 24
噪声水平 0.7
KL 系数 (GenEval/OCR)0.04
KL 系数 (PickScore)0.01
图像分辨率512
计算资源24 × NVIDIA A800 GPU

图像质量评估指标

为检测 reward hacking,在 DrawBench 上评估四项自动图像质量指标:

  • Aesthetic Score:CLIP-based 线性回归器,预测美学分数
  • DeQA Score:多模态 LLM,评估低级图像质量(失真、纹理损坏等)
  • ImageReward:通用 T2I 人类偏好奖励模型
  • UnifiedReward:最新统一奖励模型,当前 SOTA

5. Experimental Results(实验结果)

5.1 主要结果

GenEval 结果(Table 1)

Figure 3 解读:GenEval benchmark 上的定性对比。从左至右六列分别对应:四只长颈鹿(Counting)、白色三明治(Single Object + Color)、红狗(Attribute Binding)、褐色长颈鹿和白色停车标志(Two Objects + Binding)、红橙子和紫色西兰花(Colors)、熊左侧的长椅(Position)。SD3.5-M + Flow-GRPO(最后一行)在所有维度均明显优于 FLUX.1 Dev、GPT-4o 和原始 SD3.5-M,特别是在 Counting(四只长颈鹿)和 Position(长椅左侧)任务上体现出 RL 训练后的精确控制能力。

模型OverallSingle Obj.Two Obj.CountingColorsPositionAttr. Binding
SD3.5-M(基准)0.630.980.780.500.810.240.52
FLUX.1 Dev0.660.980.810.740.790.220.45
SANA-1.5 4.8B0.810.990.930.860.840.590.65
GPT-4o0.840.990.920.850.920.750.61
SD3.5-M + Flow-GRPO0.951.000.990.950.920.990.86

Flow-GRPO 将 SD3.5-M 的 GenEval Overall 从 0.63 提升至 0.95,超越当前最优的 GPT-4o(0.84)。

OCR 与 PickScore 结果(Table 2)

模型GenEvalOCR Acc.PickScoreAestheticDeQAImgRwdPickScoreUniRwd
SD3.5-M0.630.5921.725.394.070.8722.343.33
Flow-GRPO (w/o KL) - GenEval0.954.932.770.4421.162.94
Flow-GRPO (w/ KL) - GenEval0.955.254.011.0322.373.51
Flow-GRPO (w/o KL) - OCR0.935.133.660.5821.793.15
Flow-GRPO (w/ KL) - OCR0.925.324.060.9522.443.42
Flow-GRPO (w/o KL) - PickScore23.416.154.161.2423.563.57
Flow-GRPO (w/ KL) - PickScore23.315.924.221.2823.533.66

关键数字:OCR 准确率从 0.59 提升至 0.92(KL 版本),PickScore 从 21.72 提升至 23.31

5.2 训练过程可视化

Figure train_geneval 解读:GenEval 训练过程中评估图像质量的演变。随着训练步数增加,模型逐渐从错误的物体数量和属性,学习到精确的计数(如四只长颈鹿)和正确的颜色属性绑定,体现了 RL 持续优化的过程。

Figure train_ocr 解读:OCR 任务训练过程可视化。模型从无法正确渲染文字,逐步习得精确的字符排列和清晰的文字渲染能力,说明 RL 信号能有效驱动文字生成质量的提升。

Figure train_pickscore 解读:PickScore 人类偏好对齐任务的训练过程。图像整体美观度、与 prompt 的相关性随训练持续提升,且视觉多样性得以保持(KL 正则的作用)。

5.3 消融分析

Denoising Reduction 的影响

Figure 7a 解读:不同去噪步数(Step=5、10、40)对 GenEval 训练效率的影响。横轴为 GPU 训练时间(小时),纵轴为 GenEval Score。Step=10 收敛最快,约 800 GPU 小时达到 0.90+ 的 GenEval;Step=40 最终性能相当但耗时超过 4×;Step=5 出现不稳定现象,最终性能略低。结论:T=10 是最优的 Denoising Reduction 选择

Figure 7a_ocr 解读:OCR 任务上 Denoising Reduction 的消融实验。与 GenEval 结论一致,Step=10 在训练效率和最终性能上均优于其他设置。

噪声水平 的影响

Figure 7b 解读:噪声水平参数 对 OCR 任务训练效果的影响。 时探索不足,收敛极慢; 改善明显; 达到最优,平衡探索与图像质量; 噪声过大,图像质量下降,奖励归零导致训练失败。适中噪声水平()是最佳选择

KL 正则的影响

Figure 6 解读:KL 正则对抑制 reward hacking 的作用。左侧”Quality Degradation”组(GenEval/OCR 任务):无 KL 时(w/o KL),模型为追求高奖励而生成图像质量明显下降(如苹果变形、燃料低显示界面风格崩坏);加入 KL(w/ KL)后图像质量保持接近原始 SD3.5-M 水平。右侧”Diversity Decline”组(PickScore 任务):无 KL 时不同 seed 生成几乎完全相同的亚伯拉罕·林肯演讲图(多样性坍塌);加入 KL 后图像多样性得以维持。

Figure KL_geneval 解读:不同 KL 系数 下 GenEval 训练曲线。适当的 值能在保持图像质量的同时达到与无 KL 相近的任务奖励,但需要更长的训练时间才能收敛至高奖励。

与其他对齐方法的比较

Figure 4 解读:Flow-GRPO 与 SFT、Online/Offline DPO、RWR 在组合生成任务上的训练曲线对比。Flow-GRPO(红线)始终领先所有基线,在相同 prompt 数量下取得最高 GenEval Score。Online DPO 优于 Offline DPO(与 SkyReels-v2 的发现一致),但均显著落后于 Flow-GRPO。Offline RWR 基本原地踏步,说明 reward-weighted 回归对 flow matching 效果有限。

Figure compare_3tasks 解读:三个任务(GenEval、OCR、PickScore)上 Flow-GRPO 与其他方法的综合对比,进一步验证 Flow-GRPO 在所有任务上的一致性优势。

5.4 泛化性分析

Flow-GRPO 展示了强泛化能力(Table 4):

  • Unseen Objects:在 60 个训练物体类别上训练,在 20 个未见类别上评估,Overall 从 0.64 提升至 0.90
  • Unseen Counting:在 2-4 个物体数量上训练,在 5-6 个(0.13→0.48)和 12 个(0.02→0.12)物体上评估

T2I-CompBench++ 上 Flow-GRPO 在 Color(0.80→0.84)、3D-Spatial(0.37→0.68)等维度大幅领先基线。

5.5 Teaser 图

Figure 1 解读:三栏展示 Flow-GRPO 的整体效果。(a) GenEval Performance:SD3.5-M+Flow-GRPO(橙线)随训练时间稳定上升至 0.95,超过 GPT-4o(0.84)和 FLUX.1 Dev(0.66),而基础 SD3.5-M 仅 0.63。(b) Image Quality:在 DrawBench 上,Aesthetic Score(5.25 vs 5.39,略微下降)和 DeQA Score(4.01 vs 4.07)基本保持不变,说明图像质量无明显损失。(c) Preference Score:ImageReward(0.67→1.03)、PickScore(22.34→22.97)、UnifiedReward(3.33→3.51)均有提升,证明 Flow-GRPO 在提升目标能力的同时不造成明显 reward hacking。