Lens: Rethinking Training Efficiency for Foundational Text-to-Image Models

Paper: arXiv:2605.21573
Code: microsoft/Lens
Code reference: main @ 5bf0f0ce (2026-05-22)

1. Motivation (研究动机)

当前 foundational text-to-image(T2I)模型的主要矛盾不是“能不能继续堆大”,而是“继续堆大是否仍然值得”。论文指出,近期高质量 T2I 模型通常依赖巨大的训练成本:例如 Z-Image 需要约 314K H800 GPU hours 做 pre-training,而 Lens 用 3.8B 参数规模和 192K A100 GPU hours(按 peak BF16 TFLOPS 归一化后约为 Z-Image 训练算力的 19.3%)达到或超过多个更大模型的效果。这背后的问题是,生成质量、prompt following、文字渲染和多语言泛化都在持续提高,但训练一次 foundation-scale T2I model 的财务成本、工程周期和环境成本也随之急剧上升。

论文把“训练效率”拆成三个互相耦合的因素:第一是 model size,它决定每个 optimization step 的计算成本;第二是 data information density,它决定每个 batch 能给模型多少有用的 visual-semantic supervision;第三是 convergence speed,它决定达到同等质量需要多少 iterations。这个拆分很关键,因为它避免把效率问题简化成“参数少一点”。如果只是缩小模型,模型可能欠拟合、prompt following 下降、文字能力变差;如果只是减少训练步数,模型可能还没收敛;如果只是过滤数据,batch 中的信息密度仍然可能很低。Lens 的目标是在这三个因素上同时做设计,让较小的 3.8B T2I model 仍然能覆盖 high-resolution、text rendering、multilingual prompt following 和 arbitrary aspect-ratio generation。

这件事值得研究的原因在于:如果训练一个强 T2I 模型必须依赖 6B、9B、20B 甚至 MoE 80B 级别模型和数十万 GPU hours,只有极少数团队能迭代基础模型;相反,如果可以用更紧凑的模型、信息密度更高的数据和更快收敛的架构达到同等质量,就能显著降低基础生成模型研发门槛。Lens 试图证明:dense captions、mixed-resolution training、semantic VAE、strong language encoder、RL post-training、reasoner 和 distillation 可以组合成一个系统性效率方案,而不是某个单点 trick。

Figure 1 解读:这组 1440-resolution 样例展示 Lens 希望覆盖的能力范围:高分辨率细节、复杂场景布局、主体一致性、文字或标识渲染、风格多样性。它不是一个方法框图,而是论文对“训练效率不能以牺牲生成能力为代价”的直观声明:模型更小、训练算力更低,但输出仍要接近大模型的视觉质量。

2. Idea (核心思想)

核心 insight 是:T2I foundation model 的训练效率可以通过“每一步更便宜、每个 batch 更有信息、每轮训练更快收敛”共同提升,而不是单纯靠缩小参数量。Lens 把 3.8B compact backbone、Lens-800M dense-caption data、semantic VAE、GPT-OSS language encoder、taxonomy-driven RL prompts、rubric reward、reasoner prompt refinement 和 4-step distillation 串成一个效率优先的训练与推理系统。

相比 Z-Image、FLUX.2、Qwen-Image 等更大模型,Lens 的根本差异在于它把训练数据、架构和 post-training 都服务于效率目标:Lens-800M 用 GPT-4.1 生成长 caption,平均约 109 words;mixed-resolution bucket 让一个训练阶段覆盖 512、768、1024 base areas 和 9 个 aspect ratios;semantic VAE 和 strong language encoder 加速 text-image alignment;RL 不只优化少量 aesthetic prompt,而是用 Lens-RL-8K 的 taxonomy-driven prompt distribution 覆盖 Human、Object、Animal、Plant、Scene、Food、Event、Fictional World、Text、UI and Graphic Design 等生成场景。

Lens 与“纯 inference acceleration”方法也不同。DPM-Solver、UniPC 这类 solver 主要减少 sampling steps,但不改变模型学习到的分布;Lens-Turbo 的 few-step distillation 则从 Lens-RL teacher 学一个 4-step student,并用 DMD2、decoupled-DMD、SenseFlow 和 adversarial/R1 regularization 稳定训练。因此,Lens 的贡献不是某个新 loss 单独提升指标,而是把数据密度、架构选择、RL prompt coverage、reasoner 和 distillation 都统一到“训练/推理效率”这一目标下。

Figure 2 解读:两个 scatter plot 把 inference time、benchmark score 和 model size 放在同一张图中。Lens 和 Lens-Turbo 的 marker 位于较高 score 区域,同时横轴推理时间比许多大模型更低;marker 面积对应模型参数规模,说明 Lens 的 3.8B 不是靠巨大模型容量换来的结果。Figure 2 的重点是 efficiency frontier:Lens 在 OneIG 和 GenEval 上试图把高分、低延迟、小模型三个目标同时推进。

3. Method (方法)

3.1 Overall framework:Lens 的系统组成

Lens 的 pipeline 可以分成四层。第一层是 data layer:Lens-800M 提供 pre-training supervision,Lens-RL-8K 提供 post-training prompts 与 rubrics。第二层是 representation layer:FLUX.2 semantic VAE 把图像编码成更适合生成学习的 latent,GPT-OSS 20B-A3B 作为 text encoder 提供多层语义特征。第三层是 denoising backbone:一个 MMDiT-style latent diffusion Transformer 在 image stream 和 text stream 上做 joint attention,并用 flow-matching objective 训练。第四层是 alignment/inference layer:RL 用 DiffusionNFT 和 GPT-4.1-mini rubric reward 优化 Lens-Base;Reasoner 在推理前把模糊 prompt 改写为更适合图像生成的详细 prompt;Lens-Turbo 通过 few-step distillation 把 Lens-RL 压缩为 4-step generator。

Figure 6 解读:左侧展示 Lens latent diffusion Transformer 的输入输出路径:image 经过 VAE encoder 得到 latent,再 patchify;text prompt 经过 GPT-OSS,抽取第 4、12、18、24 层 hidden states 并 concat,再用 linear adapter 对齐到 image latent 维度。中间 48 个 MMDiT blocks 同时处理 image features 和 text features;右侧 block 展示 image/text 两个分支各自 RMSNorm、QKV、Self Attention、Gated MLP,并通过 timestep conditioning 做 adaptive modulation。这里的设计直觉是:image 和 text 不是简单 cross-attention,而是在 joint Transformer block 中共同演化,强 text encoder 的多层语义能持续影响 latent denoising。

3.2 Lens-800M:用 dense captions 提高 batch 信息密度

数据来源与清洗

Lens-800M 来自四类互补数据源:

  • public real-world data。
  • public synthetic data。
  • private data:包含 poster、slide、graphic design 等 text-heavy visual content 与 general-domain images。
  • text synthetic data:把文本渲染到随机背景上,并对 blur、color、font、scale、rotation 做增强。

论文随后用九步清洗管线提高质量:

  • 去除损坏文件。
  • 过滤小于 area 的图片。
  • 用 fine-tuned EVA 做 NSFW filtering。
  • 用 Aesthetic Predictor v2.5 丢弃 score < 3 的样本。
  • 用 fine-tuned SigLIP2 做 watermark filtering。
  • 用 Laplacian variance 做 blur/clarity filtering。
  • 用 grayscale entropy 去除低信息图。
  • 用 HSV V-channel mean 过滤欠曝/过曝。
  • 最后用 CLIP ViT-L/14 embedding 和 FAISS 在 cosine similarity > 0.985 阈值下做 near-duplicate removal。

过滤后得到约 800M high-quality images。

Dense caption 为什么提升训练效率

论文认为 caption 是训练效率的核心瓶颈。传统 web alt-text 往往短、含糊、错误,模型必须在训练中自己补全语义,这会浪费 capacity 并降低 learning signal。Lens 对每张图用 GPT-4.1 生成 long-form English caption;如果图像中出现其他语言文字,则 caption 保留原始语言文本,以保留 multilingual text rendering 能力。

Appendix E.1 给出的 caption system prompt 很具体:

  • 每张图生成 1 段、少于 500 words 的 dense caption。
  • 必须覆盖 salient objects、颜色/纹理/姿态等 attributes、关系/交互、可能的 object count、background。
  • 如果图里有 sign/label 等可见文字,要按原语言写出 text content。
  • 如果没有文字,明确禁止写 “no visible text” 这类负描述。
  • 如果包含 landmark、celebrity、characters、popular dishes 等 well-known contents,要写入相应 world knowledge,而不是只给通用描述。

这个 prompt 设计说明 Lens-800M 的“信息密度”不只是 caption 变长,而是把 object-level、relation-level、OCR/text-level 和 world-knowledge-level 的监督都压进同一个 text condition。Figure 3(c) 显示 Lens-800M caption 平均长度约 109 words。

Caption-length ablation

受控 ablation 使用 Lens-130M 子集训练三个 Lens-Toy(1.2B image backbone + Qwen3-0.6B text encoder):Brief、Detailed、Mixed。Figure 4 显示 dense captions 的 GenEval 曲线最好,说明更多细粒度视觉语义被直接放进 batch,而不是让模型从弱 caption 中猜。

Figure 3a–3c 解读:左图是 Lens-800M pre-training data 的类别分布,中图是 Lens-RL-8K prompt set 的类别分布,右图是 Lens-800M caption length distribution。把 pre-training data 和 RL prompts 都做成相对宽覆盖的分布,是为了避免模型只在少数 prompt 类型上提升;caption length 图则支持论文“长 caption 提高 data information density”的主张。

Figure 4 解读:caption-length ablation 显示 Detailed caption 比 Brief 和 Mixed 更快、更高地提升 GenEval。直觉上,dense caption 把 object attribute、spatial relation、count、style、background、text content 等监督直接写进文本条件,使每次 image-text update 学到的对应关系更多,因此同样 iteration 下利用数据更充分。

3.3 VAE 与 text encoder:不是只看重建,而是看生成可学性

VAE 方面,Lens 比较 classical VAE(如 FLUX.1、SD3 使用的 VAE)与 semantic VAE(如 FLUX.2、VTP 使用的 VAE)。论文刻意不把 rFID 当作主要选择标准,因为 reconstruction fidelity 只说明 VAE 能不能复原输入图像,不说明 latent space 是否适合 text-to-image generative learning;也不依赖 class-conditional ImageNet generation 作为 proxy。作者用 Lens-130M 训练 Lens-Toy,在真实 T2I setting 中直接比较 VAE 对生成质量和收敛速度的影响,最终选择 FLUX.2 VAE。这里的直觉是:更语义化、更紧凑的 latent space 会让 text-image alignment 更容易学,flow-matching 模型不需要在低层像素噪声上浪费太多容量。

Figure 5 解读:VAE ablation 不是在比较哪种 tokenizer 重建更像原图,而是在比较下游 T2I generation 的学习曲线。FLUX.2 VAE 在 Lens-Toy 上带来更好的 GenEval 表现与收敛速度,因此 Lens 采用它作为图像 latent 表示。

Text encoder 方面,Lens 使用 GPT-OSS,一个 20B-parameter MoE language model,其中 3B parameters activated,共 24 layers。Lens 抽取第 4、12、18、24 层 features,并沿 feature dimension concat,再用 linear adapter 投影到 image latent 同维度。论文用 Lens-Toy 比较 GPT-OSS-20B-A3B 与 Qwen3 0.6B/1.7B/4B,所有 variants 都只在 English-only Lens-130M 上训练。结果显示 GPT-OSS 不仅提升 prompt following 和收敛,还能让模型在 inference-time 支持 Chinese、French 等非英语 prompt。这说明 multilingual generalization 并不完全来自多语言图文数据,而部分来自强 language encoder 的语义空间。

Figure 7 解读:English GenEval 曲线比较 GPT-OSS 与不同规模 Qwen3 encoder。GPT-OSS 的优势说明 language encoder 的语义表征质量会直接影响 denoising backbone 的 text-image alignment,而不是仅影响 prompt tokenization。

Figure 8 解读:multilingual 评估进一步说明,强 language encoder 能把 English-only 图文训练中的视觉概念迁移到其他语言 prompt 上。它不能完全替代多语言图文训练,但能降低多语言数据不足带来的性能损失。

3.4 Latent Diffusion Transformer 与 flow matching

Denoising backbone 与 released code

Lens 的 denoising model 是 MMDiT-style latent diffusion Transformer。Released code 中 lens/transformer.pyLensTransformer2DModel 默认配置与论文图示一致:

  • patch_size=2
  • in_channels=128
  • num_layers=48
  • num_attention_heads=24
  • attention_head_dim=64
  • selected_layer_index=(5, 11, 17, 23)

代码使用 0-based layer index,对应论文文字中的第 4、12、18、24 层存在 off-by-one 表述差异的风险,实际实现以代码为准。

LensJointAttention 对 image/text stream 分别做 QKV projection 和 QK RMSNorm,并在 image/text RoPE 后做 joint attention;LensTransformerBlock 对 image/text 各自做 timestep-conditioned modulation、attention residual、Gated MLP residual。

Flow-matching objective

论文公式层面,pre-training 使用 standard flow-matching MSE objective。若 是 VAE latent, 是 noise-data interpolation 后的 latent,目标 velocity 为 ,则训练优化:

Pre-training schedule

Low-resolution pre-training 固定在

  • 使用 128 NVIDIA A100 80GB GPUs 训练 400K iterations。
  • FLUX.2 VAE 与 GPT-OSS language encoder frozen,只优化 diffusion Transformer。
  • 训练使用 bfloat16、gradient checkpointing、AdamW()、constant LR 、effective global batch size 3072、gradient clipping 1.0。

Mixed-resolution continual training 从 low-resolution checkpoint 继续 400K iterations,同样使用 128 A100:

  • bucket 来自 base areas 与 9 个 aspect ratios(1:2 到 2:1),共 27 个 buckets。
  • LR 改为
  • bucket batch sizes 对 512、768、1024 base 分别是 24、10、6,以平衡不同分辨率 rank 的 wall-clock time。

论文称虽然训练未覆盖 之间分辨率,也未覆盖预定义以外 aspect ratio,但推理可泛化到 1:2–2:1 和最大 area。

Paper-vs-code caveat

论文公式与 released code 实现差异:公开仓库主要提供 inference 代码,没有公开 Lens-800M 清洗脚本、pre-training launch config、RL training loop 或 distillation training script;因此上述训练超参来自论文正文/Appendix,而不是 released code 的实验配置文件。另一个容易误读的差异是:LensPipeline.__call__ 函数签名默认 num_inference_steps=50, guidance_scale=4.0,但 README checkpoint table 对 microsoft/Lens 明确推荐 20 steps、CFG 5.0,对 microsoft/Lens-Turbo 推荐 4 steps、CFG 1.0;写实验脚本时应显式传参,不应把函数签名默认值当作论文设置。

3.5 Lens-RL-8K 与 DiffusionNFT:让 post-training 覆盖真实生成分布

Lens-RL-8K 的覆盖目标

Pre-training 后的 Lens-Base 已能跟随 prompt,但仍可能产生 visual artifacts。Lens-RL-8K 是一个 8,406 prompts 的 RL prompt dataset,构造目标不是单一 aesthetic preference,而是覆盖真实 T2I generation scenario distribution。

构造方式分三层:

  • 先定义 category set:Human、Object、Animal、Plant、Scene、Food、Event、Fictional World、Text、UI and Graphic Design。
  • 每个 category 再细分 sub-categories,例如 Human 包括 Race、Occupation、Gender。
  • 每个 sub-category 包含大量 concrete items,总计 8,406 items;随后定义 description dimensions:Attribute、Spatial Relationship、Count、Interaction、Color。

Appendix E.2:prompt set 怎么生成

Appendix E.2 的实际 prompt 又把 description dimensions 细化为 keypoints:

  • global:描述整体构图、氛围和环境。
  • counting:指定数量。
  • position:指定空间位置或姿态。
  • attribute:指定形状、尺寸、材料、纹理、状态。
  • color:指定实体或环境颜色。
  • relation:指定与其他对象/人的空间或语义关系。
  • text:要求在场景中加入可见文字、label、sign 或 typography。

对每个 item 随机采样 1–4 个 dimensions,让 GPT-4.1 生成 image-generation prompt,得到 Lens-RL-8K。

Appendix E.2 还揭示了 prompt set 构造的几个约束,这些约束直接影响 RL 数据分布:

  • 系统提示要求 GPT-4.1 扮演 photo-realistic image generation 的 expert prompt engineer。
  • 给定 entity 和 required keypoints 时,必须一次生成 exactly 5 条 diverse、vivid prompts。
  • 每条 prompt 都要以该 entity 为 clear focal subject。
  • 所有 prompts 必须是 realistic photographic style,显式禁止 cartoon、anime、watercolor、pixel-art、low-poly、cel-shaded、painterly 等 non-photographic style。
  • 每条 prompt 长度 30–60 words、单段、无换行,要具体而 cinematic,写出 subject details、setting、lighting、camera angle、mood、realistic texture cues。
  • 5 条 prompt 之间要在 setting、lighting、composition、mood 上多样化。

输出格式也被严格约束为一个 JSON object,只有 "prompt-1""prompt-5" 五个 key,不允许 markdown fences、解释或额外 key。这说明 Lens-RL-8K 的 prompt diversity 不是让 LLM 自由发挥,而是用“entity taxonomy × keypoint sampling × 每个 entity 5 个 photographic variants”的方式控制覆盖面、可渲染性和可解析性。

Appendix E.3–E.4:rubric 和 reward 怎么定义

Rubric generation 也按 prompt 做 sample-aware 设计。给定 Lens-RL-8K 中的 prompt ,GPT-4.1 生成最多 10 条 prompt-specific rubrics。

Appendix E.3 对 rubric 输出格式有硬约束:

  • 必须是 Python json.loads() 可解析的 single JSON object。
  • key 是短 rubric name,value 是 brief explanation。
  • 不能输出 CSV,不能改 key name,不能 trailing comma 或 comments。

随后系统追加一个 global rubric:“Verify that the entire image is structurally coherent and physically plausible”。

在 RL step 中,系统随机采样 48 个 prompt-rubric pairs;每个 prompt 用当前 policy model 在不同分辨率下生成 24 张图;再把生成图和 rubrics 送入 GPT-4.1-mini 得到 reward。

Appendix E.4 的 reward SP 极简:给定 user prompt 和某条 evaluation criterion,让 GPT-4.1-mini 判断生成图是否 fully satisfies 该 criterion;满足输出 1,明显失败输出 0,禁止解释。

这等价于把复杂视觉偏好拆成一组二值 rubric checks,再由 DiffusionNFT 将这些 checks 汇总后的 raw reward 归一化成 optimality probability。RL policy 训练 180 steps,使用 64 NVIDIA A100 GPUs。

DiffusionNFT:把 reward 写进 flow-matching objective

DiffusionNFT 不用传统 policy-gradient,而是在 flow-matching objective 内把 reward 转成 desirable/undesirable generation direction。核心 loss 为: 其中 是 normalized reward / optimality probability, 是 target velocity field。正负 velocity 是 old policy velocity 与 current policy velocity 的线性组合: 高 reward 样本使正 velocity term 权重更大,把 current policy 推向 desirable directions;低 reward 样本使 negative velocity term 更重要,把模型推离 undesirable trajectories。raw reward 量纲可能随 prompt 变化,因此 DiffusionNFT 把 归一化到 bounded probability: 其中 通常设为 reward 的 global standard deviation。这个 normalization 让 RL 不因 reward scale 漂移而不稳定。

3.6 Reasoner:训练-free prompt refinement

Reasoner 放在什么位置

Reasoner 是放在 T2I model 前面的独立 language module,作用是把 raw user request 改写成更详细、更 coherent、更适合图像生成的 prompt。

论文默认使用 GPT-5.5,但也比较了 GPT-OSS-20B-A3B 与 Qwen3 系列作为 reasoner。Reasoner 与内部 text encoder 解耦,因此可以替换而无需重新训练 generation backbone;当使用 GPT-OSS 作为 reasoner 时,因为 GPT-OSS 已经是 text encoder,额外 GPU memory cost 为 0。

论文还提出 training-free system-prompt search:从初始 system prompt 出发,用 current reasoner 重写 prompts,再用 T2I model 生成图像并在 benchmarks 上评估,迭代选择更好的 system prompt。这个过程不训练 LLM,只搜索 system prompt。

General inference SP:不是简单“写详细”

Appendix E.5–E.8 说明所谓 SP(system prompt)并不是一条泛泛的“make it detailed”,而是按 general inference 与 benchmark 类型拆成多套 prompt rewriting policy。General inference SP 的核心约束是:

  • 输出 exactly one、single-image、precise descriptive prompt。
  • 禁止解释、推理、提问、多选项,也禁止 maybe/possibly/perhaps/or/might/could 这类不确定或备选表述。
  • faithfully preserve 用户明确给出的 objects、entities、attributes、actions、relationships、core setting。
  • 只允许加入能让图像更 concrete/coherent 的合理视觉细节,不能引入新的重要对象或改变含义。

对多主体场景,SP 要求逐个主体描述 appearance、color、size、shape、material、pose、expression、position,避免同类主体糊成一团。

对 text-heavy prompt,它特别强调可见文字必须被精确保留:不得省略、缩写、翻译、改写、总结或用 placeholder 替代;要保留 original language、capitalization、punctuation、numbers、dates、product names、URLs、prices、units、equations、labels、subtitles、captions、dialogue、button text,并描述 title/subtitle/body/footer/legend/axes/labels/callouts/icons/panels/arrows/reading order 等层级。

Benchmark-specific SP:更像 evaluation adapter

GenEval SP 把 metadata 当作 source of truth。因为 GenEval 用 object detection、instance segmentation、color classification 和 bounding-box spatial relations 计分,所以它要求保留每个 required object class、count、color 与 left/right/above/below relation,并让图像容易被检测器验证。

OneIG SP 覆盖 anime/tag-style prompts、realistic portraits、general objects/scenes、text-rendering tasks、knowledge-reasoning diagrams。它要求保留所有 benchmark-critical details,即使这些细节很怪、冗余、tag-like 或难渲染。

对 anime comma-separated tags,OneIG SP 要把 1girl2girlssoloupper bodyfrom behind 等 counts/composition tags 作为硬约束翻译成自然语言,同时保留 hair/eye colors、hairstyle、horns、tails、wings、clothing、accessories、pose、style tags,并且不能把 stylized prompt 强行改成 photorealism。

LongText/CVTG SP 专门最大化 visible text rendering:它覆盖 signs、labels、printed documents、webpages/app screens、slides、posters、video captions、news lower-thirds、subtitles、comic dialogue bubbles,要求文本大、正面、无遮挡、高对比,避免 tiny/distant/crowded/reflective/motion-blurred/partly hidden/highly stylized text。

对 signs、labels、printed materials、UI、slides、charts、diagrams,LongText/CVTG SP 分别给出布局和可读性规则。这个附录细节强化了 Table 6 的解读:reasoner 的收益来自一套针对可渲染性与评测可检测性的 prompt rewriting constraints,而不仅是“把 prompt 写长”。

Released code 对应路径

Released code 中 lens/reasoner.pyPromptReasoner 支持两种路径:

  • 无 API 时用 local GPT-OSS 的 generate
  • 有 OpenAI-compatible api_url/api_key/api_model 时走 API。

LensPipeline.refine_promptenable_reasoner=True 时调用它;_clean_reasoner_output 处理 harmony/final 格式并回退到原 prompt,避免 reasoner 输出解析失败时破坏生成。

3.7 Lens-Turbo:4-step distillation

Lens-Turbo 从 RL-aligned Lens-RL distill 出 4-step generator。作者从 Lens-800M 中按 aesthetic 与其他 quality metrics 筛出 100K image-caption subset,并平衡 portrait、landscape、visual content、artistic styles、text-rich images 等场景。student 和 fake score model 初始化自 RL checkpoint,teacher frozen。Distillation 目标结合 decoupled-DMD 的 CFG-augmented term 与 distribution-matching term ,再加 DMD2-style adversarial branch。

DMD 的 reverse-KL-style objective 写为: 由于 density intractable,使用 score-based gradient approximation。给定: 梯度近似由 frozen teacher score 与 fake score 的差给出。Adversarial branch 中,forward noising distribution 为: Discriminator 不直接用 fake score features,而是用 frozen teacher features 用 logistic loss ,discriminator objective 为: 其中 近似 R1 penalty,实践中 。Generator adversarial loss 是: Student 最终优化: 其中 。Fake score model 用 velocity-matching objective: 每个 global step 包含 4 次 fake score/discriminator update,再进行 1 次 student update;student update 后用 SenseFlow 的 IDA 策略更新 fake score model:,其中 。训练使用 8 NVIDIA A100 80GB GPUs、per-GPU batch size 4、AdamW;student/fake score LR 为 ,discriminator LR 为 ,最多 1K global steps。

3.8 Code-based pseudocode(基于 main@5bf0f0ce

公开仓库是 inference-first release,没有训练数据清洗、pre-training、RL、distillation 的 source code。下面 pseudocode 只把已公开实现映射成 Python/PyTorch style;训练相关 pseudocode 按论文公式描述,并明确不声称来自 released training script。

def lens_inference(pipe, prompt, base_resolution=1440, aspect_ratio="1:1",
                   steps=20, cfg=5.0, enable_reasoner=False, seed=0):
    height, width = resolve_resolution(base_resolution, aspect_ratio)
    prompts = [prompt]
    if enable_reasoner:
        prompts = pipe.reasoner.refine(prompts, enable=True)
 
    pos, pos_mask, neg, neg_mask = pipe.encode_prompt(
        prompt=prompts,
        negative_prompt="",
        max_sequence_length=512,
        device=pipe._execution_device,
    )
    pos, pos_mask, neg, neg_mask = pipe._align_text_features(pos, pos_mask, neg, neg_mask)
    encoder_features = [torch.cat([p, n], dim=0).to(pipe.transformer.dtype)
                        for p, n in zip(pos, neg)]
    encoder_mask = torch.cat([pos_mask, neg_mask], dim=0)
 
    latent_h, latent_w = height // pipe.vae_scale_factor, width // pipe.vae_scale_factor
    latents = pipe.prepare_latents(
        batch_size=1,
        num_channels_latents=pipe.latent_channels,
        height=height,
        width=width,
        dtype=pipe.transformer.dtype,
        device=pipe._execution_device,
        generator=torch.Generator("cuda").manual_seed(seed),
    )
 
    seq_len = latent_h * latent_w
    mu = compute_empirical_mu(seq_len, steps)
    sigmas = np.linspace(1.0, 1.0 / steps, steps)
    pipe.scheduler.set_timesteps(sigmas=sigmas, device=pipe._execution_device, mu=mu)
 
    for t in pipe.scheduler.timesteps:
        hidden = latents.repeat(2, 1, 1)
        timestep = t.expand(2).to(latents.dtype) / 1000
        noise = pipe.transformer(
            hidden_states=hidden,
            encoder_hidden_states=encoder_features,
            encoder_hidden_states_mask=encoder_mask,
            timestep=timestep,
            img_shapes=[(1, latent_h, latent_w)],
        )
        cond, uncond = noise.chunk(2)
        guided = uncond + cfg * (cond - uncond)
        guided = guided * (cond.norm(dim=-1, keepdim=True) / guided.norm(dim=-1, keepdim=True).clamp_min(1e-12))
        latents = pipe.scheduler.step(guided, t, latents, return_dict=False)[0]
 
    return pipe._to_pil(pipe._decode(latents, latent_h, latent_w))[0]
class LensMMDiTBlock(nn.Module):
    def forward(self, image_tokens, text_tokens, timestep_emb, image_text_rope):
        img_mod1, img_mod2 = self.img_time(timestep_emb).chunk(2, dim=-1)
        txt_mod1, txt_mod2 = self.txt_time(timestep_emb).chunk(2, dim=-1)
 
        img_attn_in, img_gate = modulate(self.img_norm1(image_tokens), img_mod1)
        txt_attn_in, txt_gate = modulate(self.txt_norm1(text_tokens), txt_mod1)
        txt_delta, img_delta = self.joint_attention(
            hidden_states=img_attn_in,
            encoder_hidden_states=txt_attn_in,
            image_rotary_emb=image_text_rope,
        )
        image_tokens = image_tokens + img_gate * img_delta
        text_tokens = text_tokens + txt_gate * txt_delta
 
        img_mlp_in, img_gate2 = modulate(self.img_norm2(image_tokens), img_mod2)
        txt_mlp_in, txt_gate2 = modulate(self.txt_norm2(text_tokens), txt_mod2)
        image_tokens = image_tokens + img_gate2 * self.img_mlp(img_mlp_in)
        text_tokens = text_tokens + txt_gate2 * self.txt_mlp(txt_mlp_in)
        return text_tokens, image_tokens
def reasoner_refine(reasoner, prompts, enable=True):
    if not enable:
        return list(prompts)
    refined = []
    for prompt in prompts:
        if reasoner.has_api():
            text = openai_compatible_chat(
                system_prompt=SYSTEM_PROMPT,
                user_prompt=prompt,
                max_tokens=reasoner.max_new_tokens,
                temperature=reasoner.temperature,
            )
        else:
            chat = reasoner.tokenizer.apply_chat_template(
                [{"role": "system", "content": SYSTEM_PROMPT},
                 {"role": "user", "content": prompt}],
                return_tensors="pt",
            )
            text = reasoner.text_encoder.generate(chat, max_new_tokens=reasoner.max_new_tokens)
        refined.append(clean_reasoner_output(text) or prompt)
    return refined
def paper_level_diffusionnft_update(old_policy, policy, reward_model, prompt_rubrics):
    # Paper-derived pseudocode: released repo has no RL training script.
    pairs = random_sample(prompt_rubrics, k=48)
    images = {p: policy.generate(p.prompt, num_images=24, mixed_resolutions=True) for p in pairs}
    raw_rewards = reward_model.score_with_rubrics(images, pairs)
    rewards = normalize_to_optimality_probability(raw_rewards)  # r in [0, 1]
 
    loss = 0.0
    for sample, r in zip(images, rewards):
        x_t, target_v, c, t = flow_matching_noising(sample)
        v_old = old_policy.velocity(x_t, c, t).detach()
        v_cur = policy.velocity(x_t, c, t)
        v_pos = (1 - beta) * v_old + beta * v_cur
        v_neg = (1 + beta) * v_old - beta * v_cur
        loss = loss + r * F.mse_loss(v_pos, target_v) + (1 - r) * F.mse_loss(v_neg, target_v)
    loss.backward()
    optimizer.step()

Code reference: main @ 5bf0f0ce (2026-05-22) — pseudocode and mapping based on this commit

Paper ConceptSource FileKey Class/Function
Lens inference pipelinelens/pipeline.pyLensPipeline.__call__, encode_prompt, _decode
Dynamic resolution/aspect bucketslens/resolution.pyRESOLUTION_BUCKETS, resolve_resolution
GPT-OSS multi-layer text featureslens/text_encoder.pyLensGptOssEncoder.set_selected_layers, encode_layers
MMDiT denoising backbonelens/transformer.pyLensTransformer2DModel, LensTransformerBlock, LensJointAttention
Prompt Reasonerlens/reasoner.pyPromptReasoner.refine, _refine_via_local, _refine_via_api
CLI inference entryinference.pyparse_args, main
Training / RL / distillationnot released论文只公开公式与超参,未公开训练脚本

4. Experimental Setup (实验设置)

Datasets:pre-training 使用 Lens-800M,约 800M high-quality images,caption 由 GPT-4.1 生成,平均约 109 words;caption/VAE/language encoder ablation 使用 Lens-130M,随机抽取自 Lens-800M;post-training 使用 Lens-RL-8K,包含 8,406 taxonomy-driven prompts,每个 prompt 关联 GPT-4.1 生成的 10 条 sample-aware rubrics 和 1 条 global rubric;distillation 使用 Lens-800M 中 curated 100K image-caption subset,并平衡 portraits、landscapes、visual content、artistic styles、text-rich images。

Baselines:主表比较 commercial models(Kolors 2.0、Seedream 3.0、Seedream 4.0、GPT Image 1 [High]、Nano Banana 2.0)和 open-source models(Janus-Pro 7B、BAGEL 14B、HiDream-I1-Full 17B、SD3.5 Large 8B、FLUX.1 [Dev] 12B、FLUX.2-Klein 9B、Z-Image-Turbo 6B、Z-Image 6B、Qwen-Image 20B、Hunyuan-Image-3.0 80B、LongCat-Image 6B)。Reasoner 表还比较 Lens w/o reasoner、Lens w/ GPT-5.5、Lens w/ GPT-OSS-20B-A3B、Lens w/ Qwen3 0.6B/1.7B/4B,以及 Qwen-Image w/ GPT-5.5。

Evaluation metrics:OneIG (EN/ZH) 是 OneIG-Bench 的英文/中文 split,OneIG (EN) 含 1,120 prompts,覆盖 general objects、portraits、anime/stylization、text rendering、knowledge/reasoning,并报告 Alignment、Text、Reasoning、Style、Diversity、Overall;GenEval 报告 Single、Two、Count、Color、Position、Attribute 与 Overall;LongText (EN) 评估长文本 prompt following;CVTG 是 text rendering benchmark,报告 2R、3R、4R、5R、Avg.、NED、CLIP。

Training config:Lens-Base low-resolution pre-training 在 128 A100 80GB 上训练 400K iterations,,AdamW,LR ,global batch 3072,BF16,gradient checkpointing,gradient clipping 1.0;mixed-resolution continual training 再训练 400K iterations,27 resolution buckets,LR

RL 用 Lens-RL-8K 训练 180 steps,64 A100,每步采样 48 prompt-rubric pairs,每 prompt 生成 24 images;distillation 使用 8 A100 80GB,per-GPU batch 4,最多 1K global steps,student/fake score LR ,discriminator LR 。Inference 中论文默认 Lens 20 steps、CFG 5.0;Lens-Turbo 4 steps、无 CFG/CFG 1.0;README checkpoint table 与此一致。

5. Experimental Results (实验结果)

主结果显示 Lens 在小模型和低训练成本下处在强 efficiency frontier。Table 2 中,Lens (20-step, 3.8B) 在 OneIG EN/ZH 上为 0.557/0.525,GenEval 0.930,LongText (EN) 0.937,CVTG Avg./NED/CLIP 为 0.869/0.951/0.814;Lens-Turbo (4-step, 3.8B) 在 OneIG EN/ZH 上为 0.554/0.519,GenEval 0.914,LongText 0.927,CVTG Avg./NED/CLIP 为 0.889/0.965/0.815。对比 Qwen-Image 20B(OneIG EN 0.539、GenEval 0.868、LongText 0.943、CVTG Avg. 0.829)和 Z-Image 6B(OneIG EN 0.546、GenEval 0.840、LongText 0.935、CVTG Avg. 0.867),Lens 在多项指标上有竞争力或更高。

更细分地看,Table 3 的 OneIG (EN) 中 Lens overall 0.557,Lens-Turbo 0.554,Z-Image 0.546,Qwen-Image 0.539;Lens 在 Alignment/Text/Reasoning/Style/Diversity 上分别是 0.891/0.960/0.343/0.404/0.186。Table 4 的 GenEval 中 Lens overall 0.930,Lens-Turbo 0.914,LongCat-Image 0.870,Qwen-Image 0.868,Z-Image 0.840;Lens 在 Position 和 Attribute 上分别达到 0.915 和 0.868,是强项之一。Table 5 的 LongText/CVTG 中 Lens LongText 0.937,Lens-Turbo 0.927;在 CVTG 上 Lens-Turbo Avg. 0.889、NED 0.965、CLIP 0.815,高于 Lens 的 Avg. 0.869、NED 0.951、CLIP 0.814,说明 4-step distillation 没有明显损害文本渲染指标,甚至在 CVTG 上更强。

RL ablation 说明 Lens-RL-8K 的覆盖度很重要。Table 1 中,GenEval 从 1/4 full set 的 0.916、1/2 full set 的 0.920 提升到 full set 的 0.930。去掉 text prompts 会明显损害 text rendering:full set w/o text 在 CVTG Avg./NED/CLIP 和 OneIG Text 上为 0.832/0.928/0.795/0.946,而 full set 为 0.869/0.951/0.814/0.960。结论是,RL prompt diversity 不是锦上添花;如果 post-training prompt 分布缺少 text-related scenarios,模型在文字渲染和综合生成上都会下降。

Reasoner 结果显示 prompt rewriting 对复杂 prompt following 有显著贡献。Table 6 中 Lens w/o reasoner 的 OneIG (EN)/GenEval/LongText/CVTG Avg./NED/CLIP 为 0.532/0.843/0.893/0.849/0.933/0.796;Lens w/ GPT-5.5 提升到 0.557/0.930/0.937/0.869/0.951/0.814;Lens w/ GPT-OSS-20B-A3B 为 0.559/0.874/0.924/0.888/0.958/0.821。GPT-OSS reasoner 虽然 GenEval 不如 GPT-5.5,但 OneIG 和 CVTG 部分指标很强,且因为复用 text encoder,额外 GPU memory cost 为 0。Qwen3 reasoner 也能带来提升,但整体低于 GPT-OSS/GPT-5.5。

Figure 9–10 解读:这两组 general gallery 展示 Lens 的 broad visual diversity、fine-grained details 和不同风格/场景覆盖。它们支持论文的 qualitative claim:Lens 的效率优化没有把模型限制在少数 demo prompt 上,而是能生成自然场景、设计图、物体组合和复杂视觉细节。

Figure 11–12 解读:portrait gallery 关注 identity diversity、facial details、lighting、cinematic composition。它说明 Lens-800M 与 RL prompt taxonomy 不只覆盖一般物体,也覆盖人像这一对细节、审美和社会偏差都更敏感的场景。

Figure 13–14 解读:text rendering samples 展示 Lens 在 storefront、poster、signage、graphic design 等 text-rich context 中生成可读 typography 的能力。结合 Table 1 的 no-text-prompt ablation 可以看出,text synthetic data、dense captions、Lens-RL-8K text prompts 与 rubrics 共同支撑了这类能力。

Figure 15–16 解读:multilingual gallery 覆盖 cuisines、landmarks、cultural identity、regional scenery 等场景。论文强调 Lens 主要用 English image-text pairs 训练,但 strong language encoder 让模型对 Chinese、French 等 prompt 有一定 generalization;这些图是该 claim 的 qualitative evidence。

Figure 17 解读:Lens-800M training sample visualization 展示 dense caption 的实际样子:caption 会描述主体、材质、颜色、光照、空间关系和背景细节。它解释了为什么平均 109 words 的 caption 能提高训练 batch 的 information density,也说明 dense caption 的成本被作者视为提升训练效率的一部分。

作者在 limitations 中承认三点。第一,Lens 主要在 English text-image pairs 上训练,虽然能泛化到中文、法语等 prompt,但非英语生成质量和 prompt-following 可能低于英语。第二,Lens 对日语、法语等非英语 visual text rendering 仍有困难,原因是训练数据中这些文字模式覆盖不足。第三,和多数 T2I 模型一样,Lens 在 rare object compositions、complex layouts、challenging visual concepts 或数据覆盖不足场景中仍可能产生 visual artifacts。安全上,模型可能被用于误导性、有害或带偏见的 visual content;Reasoner 可以拒绝不适当请求,但部署仍需要 content moderation、provenance tracking、misuse detection 和 social/cultural bias 评估。

总体结论:Lens 的实验最有价值的点不是单项指标刷新,而是证明 3.8B 模型在合适的数据密度、semantic latent、strong text encoder、RL prompt coverage、reasoner 和 distillation 配合下,可以接近或超过多个更大 T2I 模型,并显著降低 pre-training compute。对后续工作来说,Lens 更像一个 efficiency-first design recipe:先让每个 batch 更有监督,再让 representation 更易学,最后用 RL 和 distillation 对齐质量与速度。