DeepGen 1.0: A Lightweight Unified Multimodal Model for Advancing Image Generation and Editing

Paper: arXiv:2602.12205 Code: DeepGenTeam/DeepGen Code reference: main @ 7261969 (2026-03-02) RL code reference: deepgenteam/deepgen_rl main @ c4d5dc2 (2026-02-21)

1. Motivation (研究动机)

现有统一图像生成/编辑 multimodal model 往往依赖很大的参数规模:论文点名的统一模型通常超过 10B,且 LongCat-Image / HunyuanImage 3.0 级别方法使用 1.2B–5B 训练样本。DeepGen 要解决的问题不是单一 text-to-image,而是在 5B 参数预算内同时覆盖 general generation、reasoning generation、text rendering、general editing、reasoning editing,并降低训练与部署成本。

核心瓶颈在于:VLM 的最后层偏高层语义,容易丢掉 DiT 生成所需的细粒度视觉信息;如果只取单层 hidden states,条件信号还会受 layer-specific bias 影响。另一方面,RL 对齐虽然能提升偏好与文字渲染,但只靠 KL 约束会在长训练中出现能力漂移,尤其是复杂 instruction / reasoning generation。

这件事值得做,因为它把“大模型靠规模堆能力”的路线改成“VLM-DiT 结构耦合 + 数据分阶段 + 多奖励 RL”:若成立,5B 级模型就可以在开放权重场景中提供接近甚至超过 14B–80B 模型的生成、编辑和推理型视觉能力。

2. Idea (核心思想)

DeepGen 的核心 insight 是:不要只把 VLM 当作最终语义 encoder,而是把多层 VLM 表征当作一组低/中/高层条件通道,通过 Stacked Channel Bridging (SCB) 深度注入 DiT;同时用 learnable think tokens 让 VLM 在输出给 DiT 前先形成一段隐式 reasoning state。

方法上,它用 Qwen2.5-VL-3B 做理解与推理,用 SD3.5-Medium 2B DiT 做生成,并通过三阶段训练把轻量模型补齐:Stage 1 只对齐 SCB / think tokens,Stage 2 解冻 DiT 并用 VLM LoRA 做 joint SFT,Stage 3 用 MR-GRPO 的多奖励 + auxiliary SFT loss 做偏好对齐。

与 OmniGen / BAGEL / LongCat-Image 等统一生成编辑模型相比,DeepGen 的差异不只是换 backbone:它显式保留多层 VLM channel 信息并把 reference-image VAE latents 与 target noise tokens 放入同一个 DiT self-attention 序列;RL 阶段还对不同 reward 分量独立 group normalize,避免单个 reward 的尺度吞掉其它信号。

3. Method (方法)

3.1 Overall framework

Figure 3 解读:DeepGen 是 VLM-DiT 双分支结构。参考图像先走 ViT / Qwen2.5-VL 获取语义 token,同时也经 VAE 得到 DiT latent;目标图像以 noise token 形式进入 DiT。SCB 在 VLM 与 DiT 之间做多层特征融合,右侧冻结/可训练标记对应 Pre-Training、SFT、RL 三个阶段。

Figure 4 解读:训练数据覆盖 text-to-image、image editing、reasoning generation/editing、text rendering 和应用型场景。论文强调只用约 50M 样本完成三阶段训练,而不是依赖十亿级样本规模。

直觉上,DiT 需要的是“可生成”的条件,而 VLM 最终层更像“可回答”的语义摘要。SCB 把 VLM 多层 hidden states 作为 channel 拼接,等价于把细节、布局、语义和推理状态一起交给 DiT;think tokens 则提供一组固定可学习 query,在 VLM 自注意力中吸收上下文,最后变成 DiT 的 prompt embeddings。

3.2 Stacked Channel Bridging (SCB)

论文写法:给定 VLM hidden states ,从六个分布在低/中/高层的 layer 取 ,沿 channel 维拼接后送入 connector:

released code 的 SCB 路径在 qwen2_5_vl_sd3_hf_dynamic_fusion.py 中实现:output_hidden_states=True 后用 selected_layers = list(range(num_layers - 1, 0, -6)) 取多层 hidden states,并用 torch.cat(selected_hiddens, dim=-1) 做 channel concatenation;projector_1 因此从 llm.config.hidden_size * 6 投到 connector hidden size。

论文公式与 released code 实现差异:论文描述为“six uniformly distributed VLM layers”;代码按 num_layers - 1, num_layers - 7, ... 的步长规则选择层,并未在该行显式写死 6 个 layer,但 projector_1 的输入维度固定为 hidden_size*6,实际要求选出 6 组 hidden states。

def scb_forward(llm, connector, projector_1, projector_2, projector_3,
                input_embeds, attention_mask, position_ids, meta_queries):
    # released path: qwen2_5_vl_sd3_hf_dynamic_fusion.py
    output = llm(
        inputs_embeds=input_embeds,
        attention_mask=attention_mask,
        position_ids=position_ids,
        output_hidden_states=True,
        return_dict=True,
    )
    hidden_states = output.hidden_states
    num_layers = len(hidden_states) - 1
    selected_layers = list(range(num_layers - 1, 0, -6))  # expected six layers
    selected_hiddens = [hidden_states[i] for i in selected_layers]
    merged_hidden = torch.cat(selected_hiddens, dim=-1)
 
    x = projector_1(merged_hidden)
    x = connector(x)
    pooled_prompt_embeds = projector_2(x.mean(dim=1))
    prompt_embeds = projector_3(x)
    return pooled_prompt_embeds, prompt_embeds

3.3 Unified generation/editing diffusion loss

Text-to-image 训练中,target image 先经 VAE 得到 latent ,随机采样 flow-matching timestep / sigma,构造 noisy latent:

代码中的 diff_loss() 目标是 velocity / flow target ,loss 为加权 MSE:

image editing 与 text-to-image 共用 DiT loss,但 editing 会把 reference images 编码为两类条件:一类是 VLM semantic image embeds,用于 Qwen2.5-VL prompt;另一类是 VAE latents,作为 cond_hidden_states 传给 transformer。

def deepgen_sft_loss(model, batch):
    # released path: qwen2_5_vl_sd3_hf_dynamic_fusion.py
    if batch["type"] == "text2image":
        target_latents = [model.pixels_to_latents(img[None])[0]
                          for img in batch["pixel_values"]]
        text_inputs = model.prepare_text2image_prompts(batch["texts"])
        query = model.meta_queries[None].expand(len(target_latents), model.num_queries, -1)
        inputs = model.prepare_forward_input(query_embeds=query, **text_inputs)
        pooled, seq = scb_forward_from_inputs(model, inputs)
        return model.diff_loss(target_latents, pooled, seq)
 
    if batch["type"] == "image2image":
        ref_latents = [[model.pixels_to_latents(ref[None])[0] for ref in refs]
                       for refs in batch["pixel_values_src"]]
        image_embeds, image_grid = model.get_semantic_features_dynamic(flatten_refs(batch))
        target_latents = [model.pixels_to_latents(img[None])[0]
                          for img in batch["pixel_values"]]
        text_inputs = model.prepare_image2image_prompts(
            batch["texts"], num_refs=[len(r) for r in batch["pixel_values_src"]],
            ref_lens=[len(x) for x in image_embeds],
        )
        query = model.meta_queries[None].expand(len(target_latents), model.num_queries, -1)
        inputs = model.prepare_forward_input(
            query_embeds=query,
            image_embeds=torch.cat(image_embeds),
            image_grid_thw=image_grid,
            **text_inputs,
        )
        pooled, seq = scb_forward_from_inputs(model, inputs)
        return model.diff_loss(target_latents, pooled, seq, cond_intput=ref_latents)

3.4 MR-GRPO with auxiliary SFT loss

MR-GRPO 对每个 prompt 采样 张图,分别计算 preference / CLIP similarity / OCR 等 reward。对第 个 reward,先在同组内归一化:

再加权合并并做 batch-wise normalization 得到 。GRPO objective 使用 per-step importance ratio:

总 loss 加上 velocity-space KL 和 auxiliary SFT:

released DeepGen-RL 中 atrain_adv_type="gdpo" 对每个 reward function 分别 group normalize;compute_loss() 先 rollout、算 rewards、算 advantages,再按 micro-batch/timestep 累积梯度,最后每步额外 backward 一次 SFT-Aux loss。

def mr_grpo_train_step(trainer, model, prompts):
    images, old_logp, prev_latents, next_latents, timesteps = [], [], [], [], []
    for _ in range(trainer.rollout_accumulation_steps):
        traj = trainer._generate_images_with_trajectory(model, prompts, cfg_prompts=[""] * len(prompts))
        images += traj.images
        old_logp.append(traj.log_probs)
        prev_latents.append(traj.prev_latents)
        next_latents.append(traj.pred_latents)
        timesteps.append(traj.timesteps)
 
    rewards, rewards_per_func = trainer._compute_rewards(prompts, images)
    adv = trainer._compute_advantages(rewards, rewards_per_func, prompts)
    adv = torch.clamp(adv, -trainer.adv_clip_max, trainer.adv_clip_max)
 
    for step_idx in sample_training_timesteps(timesteps, fraction=trainer.timestep_fraction):
        for mb in micro_batches(prev_latents, next_latents, timesteps, old_logp, adv):
            v_pred = trainer._compute_diffusion_loss_single_batch(model, mb.x_t, mb.t, mb.cond)
            _, logp, mean_policy, std_policy = sde_step_with_logprob(
                trainer.scheduler, v_pred, mb.t, mb.x_t, mb.x_next,
                eta=trainer.sde_eta, sampler_type=trainer.atrain_sde_sampler,
            )
            ratio = torch.exp(logp - mb.old_logp)
            unclipped = -mb.adv * ratio
            clipped = -mb.adv * torch.clamp(ratio, 1 - trainer.clip_range, 1 + trainer.clip_range)
            policy_loss = torch.maximum(unclipped, clipped).mean()
            kl_loss = velocity_kl(v_pred, trainer.reference_prediction(mb))
            trainer.accelerator.backward(policy_loss + trainer.beta * kl_loss)
 
    if trainer.sftaux_coef > 0 and trainer.global_step % trainer.sftaux_every_n_steps == 0:
        sft_loss = trainer._compute_sftaux_loss(model, trainer._next_sftaux_batch())
        trainer.accelerator.backward(trainer.sftaux_coef * sft_loss)

3.5 Code-to-paper mapping

Code reference: main @ 7261969 (2026-03-02) — pseudocode and mapping based on this commit. RL-specific rows additionally use deepgen_rl main @ c4d5dc2 (2026-02-21).

Paper ConceptSource FileKey Class/Function
SCB model config, 128 think tokens, Qwen2.5-VL + SD3.5-Mediumconfigs/models/deepgen_scb.pymodel.num_queries=128, connector.num_hidden_layers=6, freeze_lmm=True
SCB multi-layer channel concatenationsrc/models/sd3_kontext/qwen2_5_vl_sd3_hf_dynamic_fusion.pyQwen2p5VLStableDiffusion3HF, selected_layers, torch.cat(..., dim=-1)
Connector transformersrc/models/connector/modeling_connector.pyConnectorEncoder, ConnectorEncoderLayer, ConnectorAttention
Unified T2I / I2I SFT losssrc/models/sd3_kontext/qwen2_5_vl_sd3_hf_dynamic_fusion.pytext2image_loss, image2image_loss, diff_loss
Pre-training configconfigs/pretrain/deepgen_joint_pretrain_scb.pymax_iters=200000, lr=1e-4, freeze_transformer=True, lora_modules=None
Joint SFT configconfigs/finetune/deepgen_joint_sft_scb.pymax_iters=400000, lr=5e-5, freeze_transformer=False, lora_rank=64
RL entrypointdeepgen_rl/grpo_deepgen.pydefault rollout_n=8, learning_rate=2e-6, beta=5e-7, clip_range=1e-4, sftaux_coef=0.0001
MR-GRPO trainerdeepgen_rl/trainer/grpo_deepgen_trainer.py_compute_advantages, _compute_rewards, compute_loss, sde_step_with_logprob
Reward mixture configassets/rl_datasets/deepgen/deepgen_train.yamltext rendering rewards 0.2/0.1/0.7, general T2I rewards 0.7/0.3

4. Experimental Setup (实验设置)

Datasets. Pre-Training 使用 general generation 35M(text-to-image-2M、LAION-Aesthetic-6M、Megalith-10M、RedCaps-5M、CC-12M)和 general editing 6.6M(NHR-Edit、GPT-Image-Edit、ShareGPT-4o-Image-Edit、OpenGPT4o-Image-Edit、Nano-banana-consist、Pico-Banana、X2I2、Uniworld-Edit、in-house editing)。SFT 继续使用 general generation 11M、general editing 6.6M,并加入 UniReason-T2I 150K、UniReason-Edit 100K、text rendering / poster / Chinese poem 560K。RL prompts 分两类:text rendering 采样权重 3.0×,general T2I 采样权重 1.0×;auxiliary SFT data 同样提高 text rendering 权重。

Baselines. General generation/editing 比较 Nano Banana、GPT-Image-1、Seedream 4.0、FLUX.1 Kontext Pro、Janus-Pro、FLUX.1 Dev、OmniGen2、BAGEL、Hunyuan-Image 3.0、Qwen-Image、LongCat-Image、Z-Image-Turbo 等;reasoning generation/editing 还包含 STAR、UniWorld-V1、Qwen-Image edit、Lumina-DiMOO;text rendering 比较 FLUX.1 dev、Z-Image-Turbo、GLM-Image 等。

Metrics. GenEval 衡量 compositional semantic alignment;DPG-Bench 衡量 long-prompt instruction following;UniGenBench 给 general generation 综合分和 text 子分;WISE / T2I-CoREBench 衡量 world-knowledge 与哲学分类 reasoning generation;ImgEdit / GEdit-EN 衡量 editing consistency 和 output quality;RISE / UniREditBench 衡量 reasoning editing;CVTG-2K 用 Word Accuracy、NED、CLIPScore 衡量文字渲染。

Training config. Paper Table 9/10 给出的论文级训练数字:Stage-I Pre-Training 200000 iters、LR 1e-4、warmup ratio 0.01、global batch size 512、只训练 SCB connector;Stage-II SFT 400000 iters、LR 5e-5、warmup ratio 0.01、global batch size 768、训练 SCB connector + DiT + VLM LoRA(rank 64, alpha 128, dropout 0.05)。Released configs 可直接核到:configs/pretrain/deepgen_joint_pretrain_scb.py 设置 max_iters=200000lr=1e-4warmup_ratio=0.01accumulative_counts=4configs/finetune/deepgen_joint_sft_scb.py 设置 max_iters=400000lr=5e-5warmup_ratio=0.01accumulative_counts=3;对应 dataloader 文件 configs/datasets/deepgen_512_fix_pixels/{joint_pretrain.py,joint_sft_zh.py} 暴露的是 per-dataloader batch_sizes=[4,4] / batch_size=4。因此 512/768 是 paper-derived global batch size,released code 未提供可复现该 global batch 的 GPU count / distributed launcher 配置。RL 使用 resolution 512×512、denoising steps 50、group size G=8、timestep fraction 0.6、LR 2e-6、total steps 1500、KL coefficient 5e-7、clip range 1e-4、SFT auxiliary coefficient 1e-4、global batch size 256、DeepSpeed ZeRO-2、BF16。

论文公式与 released code 实现差异:paper Table 10 明确 RL total training steps 为 1,500deepgen_rl/scripts/train.sh 当前只显式传 --num_train_epochs 10,没有显式传 --max_steps 1500,因此复现实验需要额外确认 dataset/epoch 换算或手动设置 max steps。

5. Experimental Results (实验结果)

Figure 2 解读:气泡图把模型参数量和 generation/editing 指标放在一起,DeepGen 的位置体现了论文主张:不是参数最大的点,但在多项 generation/editing benchmark 上接近或超过大模型。

5.1 Main benchmark numbers

ModelParamsGenEval↑DPGBench↑UniGenBench↑ImgEdit↑GEdit-EN↑
DeepGen 1.0 (SFT)3B + 2B0.8687.0574.184.097.12
DeepGen 1.0 (RL)3B + 2B0.8787.9075.744.147.17

Reasoning generation: WISE overall 从 SFT 0.72 到 RL 0.73;T2I-CoREBench overall 从 45.746.5。Reasoning editing: RISE overall SFT 13.3、RL 10.8;UniREditBench overall SFT 77.5、RL 75.7。Text rendering: CVTG-2K 中 DeepGen RL Word Accuracy 0.7533、NED 0.8936、CLIPScore 0.8278,相比 SFT 的 0.6605/0.8426/0.8227 主要提升在可读文字准确度。

Figure 5 解读:RL 训练 1,500 steps 内 UniGenBench overall 约从 0.747 升到 0.756,text 子分约从 0.25 升到 0.34。这支持论文关于 MR-GRPO 同时提升 general quality 与 text rendering 的结论。

5.2 Ablations

SettingGenEval↑DPGBench↑GEdit-EN↑WISE↑RISE↑
DeepGen 1.0 Settings0.8687.057.120.7213.3
w/o SCB0.8685.556.750.7012.6
w/o Think Tokens0.8786.357.020.6811.7
w/o Activate VLM0.8586.746.930.7112.9

SCB 的主要收益体现在长指令/编辑与 reasoning:移除 SCB 后 DPGBench 87.05 → 85.55、GEdit-EN 7.12 → 6.75、RISE 13.3 → 12.6;移除 think tokens 对 WISE/RISE 伤害更明显,说明 learnable query 对推理型条件压缩有作用。

Figure 6a 解读:overall curve 显示 auxiliary SFT loss 对 RL 稳定性关键;没有 SFT loss 时约 300 steps 后开始退化,低于起点。

Figure 6b 解读:text generation 子分中,所有 RL 变体都能提升文字渲染,但移除 SFT loss 后提升更慢且更不稳定,说明 KL 是过程约束,SFT loss 是结果分布锚点。

Table 7 的 RL ablation 数字:full RL 为 GenEval 0.87、DPGBench 87.75、GEdit-EN 7.05、UniGenBench Text 35.06、Overall 75.69;w/o Auxiliary SFT Loss 为 0.87 / 87.40 / 6.99 / 33.33 / 74.33;w/o Velocity KL 为 0.87 / 87.32 / 7.02 / 32.47 / 75.07;w/o Reward-wise Norm 为 0.86 / 87.73 / 7.02 / 32.18 / 75.27

5.3 Limitations / caveats

论文没有集中列出 limitations。实现侧可见的风险是:DeepGen 主 repo 的 pretrain/SFT configs 使用占位 model/data/checkpoint 路径;DeepGen-RL script 也要求本地 reward service 与 checkpoint 路径,且 scripts/train.sh 没显式固定 paper Table 10 的 1500 max steps。因此阅读结论可信,但严格复现实验仍需要作者的实际数据路径、checkpoint 和 service 配置。

整体结论:DeepGen 证明 5B VLM-DiT 只要用多层 VLM-to-DiT alignment、分阶段多任务数据和多奖励 RL,就能在 generation/editing/reasoning/text rendering 上达到接近或超过大得多模型的综合能力。