概述

利用图像生成模型的先验知识来做 CV 任务的研究有不少。代表性的例子包括 Marigold、Lotus-2、SDPose 等。
这些方法虽然利用了预训练图像生成模型,但最终仍然是为各自任务专门设计的。
不过,在指令式图像编辑模型已经变得常见的今天,也出现了另一种思路:从图像进行深度估计或分割这类任务,是否也可以在更宽泛的意义上当作 图像编辑 来处理?Google DeepMind 的 Vision Banana 就是这样的研究。
受到这个方向的启发,我想试试看 FLUX.2 [klein] 是否也能做类似的事情。
结果当然谈不上达到 SOTA 性能。不过我希望这个实验能说明,仅靠简单的 LoRA 训练,也可以在本地模型上尝试接近 Vision Banana 方向的行为。
发布地址
任务设定
Vision Banana 主要处理 depth / normal / segmentation。
这次没有完全照搬它的任务构成,而是选择了 ComfyUI / 图像生成社区里更熟悉的,也就是类似 ControlNet Preprocessor 的输出。
我个人把这些任务称为 image2schematic,这次创建的 LoRA 名称里也都包含 schematic 这个词。
| task | output |
|---|---|
| relative depth | near = white / far = black |
| normal map | RGB normal map |
| pose body | OpenPose 风 body skeleton |
| pose full | body + hands + face |
| binary segmentation | visible region mask |
| amodal segmentation | 包含 occluded parts 的 mask |
amodal segmentation

这里面,可能有人没听过 amodal segmentation 这个任务。
- 普通 segmentation 只会 mask 对象 实际可见的区域。
- amodal segmentation 会把遮挡物后面看不见的部分也包含进去,推定对象整体形状并生成 mask。
比如鹿的前面被树枝遮住时,普通 segmentation 不会输出树枝后面被挡住的部分。
而 amodal segmentation 会把被树枝挡住的部分也包括进去,输出鹿整体的 mask。
因为需要推定看不见的部分,所以它与其说是单纯分类,不如说更接近生成。
反过来说,这也是图像生成模型可能比较能发挥能力的任务,所以这次尝试了一下。
按任务分别训练 LoRA
一开始我打算把所有任务训练到一个 LoRA 里,但内部任务混在了一起,单靠 prompt 无法稳定切换。
因此这次采用 1 个任务 1 个 LoRA 的构成。
数据集
| task | positive | negative | total |
|---|---|---|---|
| depth | 300 | 0 | 300 |
| normal | 300 | 0 | 300 |
| pose body | 300 | 30 | 330 |
| pose full | 300 | 30 | 330 |
| binary segmentation | 300 | 30 | 330 |
| amodal segmentation | 300 | 30 | 330 |
Depth / Normal
从 Open Images 获取图像,并用 Lotus-2 创建 teacher。
- depth
- relative depth
- near = white
- far = black
- normal
- RGB normal map
depth 和 normal 使用同一组输入图像。
Pose
从 Open Images 获取人物图像,并用 DWPose 创建 teacher。
- pose body
- pose full
候选图像经过目视检查,排除了人群图像以及输出明显崩坏的图像。
Amodal Segmentation
amodal segmentation 是为对象创建 mask 的任务,不只包含可见部分,也包含被遮挡的部分。
手头没有现成数据集,也没有能直接生成它的 teacher,所以这次结合图像生成和图像编辑来制作。
制作流程:

- 让 GPT-5.5 创建包含明确 subject 和自然 occluder 的 occlusion scene prompt
- 用 Z-Image-Turbo 生成 source image
- GPT-5.5 检查 source image
- 用 FLUX.2 [klein] 9B image edit 去除 occluder
- 从去除后的图像中,用 SAM 3.1 对 target object 做 segmentation
- 将 source image 和 complete-object mask 配对
- 目视检查
- 使用 BiRefNet 以及手动方式修正
mask 只靠 SAM 3.1 并不稳定,所以几乎全部都用 BiRefNet 和手动方式修正过。
这不是主线内容,但如果让 LLM 大量生成图像 prompt,结果会容易偏向:
- 相似的对象
- 相似的 occluder
- 相似的构图
因此我把 Open Images 的随机图像作为 inspiration 给它看,用来增加 scene variation。
Binary Segmentation
复用 amodal segmentation 用的 source image。
对输入图像中实际可见的 target object 区域,用 SAM 3.1 做 segmentation,并手动修正。
Negative Samples
pose / segmentation 都会遇到一个问题:当输入图像里不存在目标对象时,模型容易 hallucination。
例如,输入图像里没有猫,却给出 generate mask of the cat 这样的指令时,模型可能会随便生成一个猫形状的 mask。
为了解决这个问题,我加入了一部分 all-black target 的 negative pair。
- segmentation
- 当指定的 target 不存在于图像中时,返回 all-black mask
- 例:cond 图像里只有长颈鹿,却要求生成
cat的 amodal mask
- pose
- 输入图像里没有人物时,返回 all-black pose image
不过,以这次的规模来看,没有确认到明确改善。尤其在 pose 上,反而可能让训练变得不稳定。
训练
使用 AI Toolkit 训练。
| item | value |
|---|---|
| base model | black-forest-labs/FLUX.2-klein-base-9B |
| architecture | flux2_klein_9b |
| LoRA rank | linear 32 / conv 16 |
| optimizer | adamw8bit |
| lr | 5e-5 |
| dtype | bf16 |
| quantization | transformer / text encoder: qfloat8 |
| batch size | 4 |
| text encoder | frozen |
| caption dropout | 0.05 |
| EMA | enabled |
为了降低计算量,分辨率基本使用 768 bucket。
只有 pose full 因为脸和手的细节更重要,所以加入了 768 / 1024 bucket 来训练。
每 100 step 保存一次 checkpoint。
然后在 ComfyUI 中实际运行,选择看起来比较好的 step。所有 LoRA 大约都在 2000~2500 step 左右收敛。
workflow
下面是用于在 ComfyUI 中使用这些 LoRA 的 workflow。
需要注意,基于 FLUX.2 [klein] Base 训练的 LoRA,在 FLUX.2 [klein] Distilled 模型上运行效果不好。请使用 Base 模型,或者使用 Distilled 与 Base 的差分 LoRA(Klein 4B/9B Base to Turbo Lora)。
模型下载
基础模型是 FLUX.2 [klein]。
- LoRA
- flux2-klein-schematic-relative-depth-lora.safetensors
- flux2-klein-schematic-surface-normal-lora.safetensors
- flux2-klein-schematic-body-pose-lora.safetensors
- flux2-klein-schematic-full-pose-lora.safetensors
- flux2-klein-schematic-binary-segmentation-lora.safetensors
- flux2-klein-schematic-amodal-segmentation-lora.safetensors
📂ComfyUI/
└── 📂models/
└── 📂loras/
├── flux2-klein-schematic-relative-depth-lora.safetensors
├── flux2-klein-schematic-surface-normal-lora.safetensors
├── flux2-klein-schematic-body-pose-lora.safetensors
├── flux2-klein-schematic-full-pose-lora.safetensors
├── flux2-klein-schematic-binary-segmentation-lora.safetensors
└── flux2-klein-schematic-amodal-segmentation-lora.safetensors
image edit Base

实践测试
relative depth
Generate a relative depth map of the input image.
| input | Depth Anything V2 | FLUX.2 [klein] LoRA |
|---|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
normal map
Generate a surface normal map of the input image.
| input | Lotus-2 | FLUX.2 [klein] LoRA |
|---|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
pose body
Generate a body pose map of all visible people in the input image.
| input | DWPose | FLUX.2 [klein] LoRA |
|---|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
pose full
Generate a full pose map of all visible people in the input image.
| input | DWPose | FLUX.2 [klein] LoRA |
|---|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
binary segmentation
Generate a binary segmentation mask of the stretcher in the input image.
Generate a binary segmentation mask of the tuna sushi in the input image.
Generate a binary segmentation mask of all jars in the input image.
| input | SAM 3.1 | FLUX.2 [klein] LoRA |
|---|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
amodal segmentation
Generate an amodal segmentation mask of the woman in the input image.
Generate an amodal segmentation mask of the bench in the input image.
Generate an amodal segmentation mask of the steam locomotive in the input image.
| input | SAM 3.1 visible mask | FLUX.2 [klein] LoRA |
|---|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
局限与问题
Depth / Normal
teacher 使用的是 Lotus-2,但 Lotus-2 自身带来的噪声也会被 LoRA 一起学进去。
对于这类任务,本来应该也考虑使用 3D 模型生成的合成数据。
顺便一提,在使用 Lotus-2 之前,我也用 DSINE 创建的 target 图像训练过。DSINE 生成的 Normal map 比 Lotus-2 平很多,结果 LoRA 的输出也同样变得很平。
teacher 的质量会直接反映到 LoRA 的输出上,这让我再次感受到数据集质量的重要性。
pose
首先,pose 是这次任务中最不适合用 RGB 图像表达的任务。
即使能输出 OpenPose 风格图像,把它再转换回 keypoint 也并不容易,实际使用上会比较麻烦。另外,颜色和骨骼数量都有严格规则,所以一点点偏差也会很显眼。
我原本以为这是一个容易训练的任务,但实际比想象中更容易崩。动物图像和非人物图像上的 hallucination 也没有防住。
segmentation
我原本期待文本编码器 Qwen3 8B 的 prompt 理解力能发挥作用,但控制能力没有达到预期。
它可以听懂“删除某某人物”这样的指令,但在应用 LoRA 后要求“segment 某某人物”时,会失败,或者 segment 到另一个人物。
因此,这可能不只是 prompt 理解力的问题。模型也可能没有从数据集中很好地理解 segmentation 任务本身。
细节抠图精度方面,我本来期待能接近 matting 那种更平滑的边界,但目前还停留在 SAM 3.1 左右的粗糙程度。
整体
整体来看,数据集数量不够。
这次 amodal segmentation 的数据集制作非常重,所以为了统一规模,所有任务大致都控制在 300 张左右。
不过如果要认真切分原因,我觉得每个任务大概需要 2000~3000 张。
还有很多改进点,但预算和时间已经花得太多,所以这次先到这里。
如果有机会,希望能用更大的数据集再试一次。
结语
先不谈质量如何,仅靠小规模 LoRA 训练,也确实能让 FLUX.2 [klein] 在一定程度上学会 CV 任务风格的 RGB 输出。
不过真正重要的,并不是“是否完成了 CV 任务”,而是根据 我们把什么东西当作图像编辑来处理,图像编辑模型的用途还可以继续扩展。
一提到图像编辑,最先想到的通常是画风转换或对象移除。
但像这次这种 CV 任务风格输出,或者让模型生成自定义中间表示,也可以在广义上当作图像编辑。
原本只是“画图”的图像生成模型,逐渐变得像通用视觉模型一样,这一点很有趣。
参考
- Marigold: Repurposing Diffusion-Based Image Generators for Monocular Depth Estimation
- Lotus: Diffusion-based Visual Foundation Model for High-quality Dense Prediction
- Lotus-2: Advancing Geometric Dense Prediction with Powerful Image Generative Model
- Vision Banana: Image Generators are Generalist Vision Learners
- Vision Banana Project Page

















































