vLLM-Omni 图生图实战:使用 image_edit.py 完成 Qwen-Image-Edit 单图与多图编辑
【免费下载链接】vllm-omniA framework for efficient model inference with omni-modality models项目地址: https://gitcode.com/GitHub_Trending/vl/vllm-omni
本篇指南基于 vLLM-Omni 仓库的离线图生图(image-to-image)示例,讲解如何用image_edit.pyCLI 驱动Qwen/Qwen-Image-Edit系列模型完成单图编辑与多图融合,覆盖完整命令行参数、缓存加速(Cache-DiT / TeaCache)、CFG 并行与显存优化选项,并结合仓库源码说明请求是如何从 CLI 参数被组装为扩散采样参数与多模态 prompt 的,读完后你可以直接在本地复制命令运行图像编辑任务,并理解每个参数背后的实现逻辑。
场景与文件位置
vLLM-Omni 的离线推理示例位于examples/offline_inference/下,图生图任务的三个文件都在 examples/offline_inference/image_to_image 目录中:
- image_edit.py:核心 CLI 脚本,负责加载模型、构造请求、执行生成并保存结果;
- run_qwen_image_edit_2511.sh:基于
Qwen/Qwen-Image-Edit-2511的示例启动脚本,演示了开启cache_dit缓存加速的完整命令; - 对应文档为 docs/user_guide/examples/offline_inference/image_to_image.md。
整体流程为:CLI 解析参数 → 构造Omni引擎实例 → 通过build_image_to_image_prompt组装多模态 prompt → 填充OmniDiffusionSamplingParams采样参数 → 调用omni.generate()得到输出图片并落盘。
单图编辑:最小可运行示例
1. 下载示例输入图
wget https://vllm-public-assets.s3.us-west-2.amazonaws.com/omni-assets/qwen-bear.png2. 运行编辑命令
默认模型即Qwen/Qwen-Image-Edit(--model的默认值),因此单图场景可以省略--model:
python image_edit.py \ --image qwen-bear.png \ --prompt "Let this mascot dance under the moon, surrounded by floating stars and poetic bubbles such as 'Be Kind'" \ --output output_image_edit.png \ --num-inference-steps 50 \ --cfg-scale 4.0脚本执行成功时会在标准输出打印生成耗时(Total generation time),并将结果保存到--output指定的 PNG 路径。
多图编辑:Qwen-Image-Edit-2509 / 2511
多图输入需要使用支持多图条件融合的Qwen/Qwen-Image-Edit-2509或Qwen/Qwen-Image-Edit-2511(脚本帮助文本指出它们走QwenImageEditPlusPipeline路径)。--image参数支持传入任意多个图片路径:
python image_edit.py \ --model Qwen/Qwen-Image-Edit-2509 \ --image img1.png img2.png \ --prompt "Combine these images into a single scene" \ --output output_image_edit.png \ --num-inference-steps 50 \ --cfg-scale 4.0 \ --guidance-scale 1.0脚本内部对单图与多图的区分逻辑很直接:加载全部输入图后,若只有一张则以单个Image对象作为条件,否则以list[Image]传入(见 image_edit.py)。
仓库提供的 run_qwen_image_edit_2511.sh 在此基础上额外开启了 Cache-DiT 加速:
python image_edit.py \ --model Qwen/Qwen-Image-Edit-2511 \ --image qwen_bear.png \ --prompt "Add a white art board written with colorful text 'vLLM-Omni' on grassland. Add a paintbrush in the bear's hands. position the bear standing in front of the art board as if painting" \ --output output_image_edit.png \ --num-inference-steps 50 \ --cfg-scale 4.0 \ --cache-backend cache_dit核心参数详解
以下参数说明以 image_edit.py 中argparse定义为准,默认值均摘自源码。
模型与输入
| 参数 | 默认值 | 说明 |
|---|---|---|
--model | Qwen/Qwen-Image-Edit | 模型名或本地路径。多图输入需使用Qwen/Qwen-Image-Edit-2509或更新版本 |
--image | 必填 | 输入图片路径(PNG/JPG 等),可指定多张;脚本会先用 PIL 打开并转为--color-format指定的色彩格式 |
--prompt | 必填 | 描述要做的图像编辑的文本 prompt |
--negative-prompt | None | 负向提示词;与--cfg-scale > 1同时存在时才真正启用 CFG |
--deploy-config | None | 部署 YAML 路径,用于部署配置未被自动加载的多阶段图编辑流水线 |
--trust-remote-code | 关 | 信任并执行模型仓库中的自定义建模代码(如 HunyuanImage-3.0 需要) |
生成质量与引导强度
--cfg-scale(默认4.0):true classifier-free guidance 强度。由cfg_scale > 1且提供negative_prompt共同启用 CFG;数值越高,生成结果越贴近文本描述,通常以画质下降为代价。--guidance-scale(默认1.0,即关闭):面向 guidance-distilled 模型的引导强度。与 CFG 不同,蒸馏模型把 guidance scale 直接作为输入参数,> 1时生效,非蒸馏模型上该参数被忽略。--guidance-scale-2(默认None):图生图场景下的 image guidance scale(脚本帮助文本注明其用于 I2I 生成)。--num-inference-steps(默认50):扩散采样去噪步数,步数越多质量越高、耗时越长。--seed(默认0):随机种子,保证结果可复现;脚本用它初始化与设备匹配的torch.Generator。--num-outputs-per-prompt(默认1):每个 prompt 生成的图片数量,多输出时保存为stem_0.png、stem_1.png等。--extra-args:一个 JSON 对象,被拷贝进OmniDiffusionSamplingParams.extra_args,例如'{"cfg_text_scale": 4.0}';若模型声明了额外 body 参数,脚本会通过apply_declared_extra_args做白名单过滤。
分辨率控制
--width/--height:输出图像宽、高(像素),默认None,由 pipeline 决定。--resolution:取值为 640 或 1024 的分辨率桶,决定条件图与输出分辨率;若未提供 width/height/resolution 中任何一个,脚本默认设置resolution=640。- 三者存在互斥与优先级约束:
--resolution不能与--width/--height同时指定,且 width/height 必须为正整数(见 image_edit.py 的校验逻辑)。
显存优化(OOM 处理首选)
--vae-use-slicing:启用 VAE slicing 降低解码显存占用;--vae-use-tiling:启用 VAE tiling 降低解码显存占用;--enable-cpu-offload:对扩散模型启用 CPU offload;--enable-layerwise-offload:对 DiT 模块启用逐层(blockwise)offload;--vae-patch-parallel-size(默认1):VAE patch/tile 并行解码使用的 GPU 数。
遇到 OOM 时,优先尝试同时开启
--vae-use-slicing与--vae-use-tiling;更大规模模型可叠加 CPU offload。
并行与加速
--cfg-parallel-size(默认1,可选 1/2/3):CFG 并行分支数,设为 2 即启用 CFG Parallel,将 CFG 的多个分支并行到多卡上;更多用法见 CFG 并行文档。--tensor-parallel-size(默认1):DiT 内部的张量并行(TP)卡数。--ulysses-degree/--ulysses-mode/--ring-degree:Ulysses 与 Ring 序列并行的卡数及模式(strict或advanced_uaa)。--enable-expert-parallel:为 MoE 层启用专家并行。--use-hsdp/--hsdp-shard-size/--hsdp-replicate-size:HSDP(混合分片数据并行)开关与分片/复制规模。--enforce-eager:禁用 torch.compile 强制 eager 执行;注意该参数默认值为None,只有显式传入时才会覆盖 per-stage 部署 YAML 中的取值。--enable-diffusion-pipeline-profiler与--profiler-config:前者打印各阶段耗时;后者接收 JSON(如'{"profiler":"torch","torch_profiler_dir":"./perf"}'),脚本会先调用omni.start_profile(),在生成结束后stop_profile()并输出各 rank 的 trace 路径。
缓存加速(Cache-DiT 与 TeaCache)
--cache-backend可选cache_dit或tea_cache,默认不启用:
Cache-DiT(DBCache + SCM + TaylorSeer 组合),相关参数与默认值:
| 参数 | 默认值 | 说明 |
|---|---|---|
--cache-dit-fn-compute-blocks | 1 | 前向计算块数,针对单 transformer 模型优化 |
--cache-dit-bn-compute-blocks | 0 | 反向计算块数 |
--cache-dit-max-warmup-steps | 4 | 最大 warmup 步数(对小步数模型有效) |
--cache-dit-residual-diff-threshold | 0.24 | 残差差异阈值,越大缓存越激进 |
--cache-dit-max-continuous-cached-steps | 3 | 最大连续缓存步数,防止精度退化 |
--cache-dit-enable-taylorseer | 关 | 启用 TaylorSeer 加速(不适配小步数模型) |
--cache-dit-taylorseer-order | 1 | TaylorSeer 多项式阶数 |
--cache-dit-scm-steps-mask-policy | None | SCM 掩码策略:slow / medium / fast / ultra |
--cache-dit-scm-steps-policy | dynamic | SCM 步数策略:dynamic 或 static |
TeaCache(Timestep Embedding Aware Cache):仅需--tea-cache-rel-l1-thresh(默认0.2,累积相对 L1 距离阈值);回归系数按model_type使用模型特定默认值。
一个典型的 cache_dit 组合用法(摘自脚本头部 docstring):
python image_edit.py \ --image input.png \ --prompt "Edit description" \ --cache-backend cache_dit \ --cache-dit-max-continuous-cached-steps 3 \ --cache-dit-residual-diff-threshold 0.24 \ --cache-dit-enable-taylorseer脚本会把上述 CLI 值组装成cache_config字典(键如residual_diff_threshold、rel_l1_thresh)传给Omni构造器(见 image_edit.py)。
Layered 模型专属参数
--layers(默认4):将输入图分解的层数;--color-format(默认RGB,Layered 模型设为RGBA):输入图的 PIL 转换色彩格式;--output在 Layered 场景下作为文件前缀使用。
分层输出场景示例:
python image_edit.py \ --model "Qwen/Qwen-Image-Layered" \ --image input.png \ --prompt "" \ --output "layered" \ --num-inference-steps 50 \ --cfg-scale 4.0 \ --layers 4 \ --color-format "RGBA"源码视角:请求是如何构造的
理解脚本的内部流程有助于排查多模态输入或多阶段模型的问题。核心调用链如下(均在 image_edit.py):
组装多模态 prompt:
build_image_to_image_prompt(...)按模型类名查询 vllm_omni/model_extras/registry.py 中注册的 per-model prompt builder;未注册的模型回退到default_image_to_image_prompt,其产物为:{ "prompt": prompt, "multi_modal_data": {"image": input_image}, # 单张 Image 或 list[Image] "negative_prompt": ..., # 仅在显式提供时加入 }从源码结构看,不同模型可以在 registry 中声明自定义的
image_to_image_prompt_builder来改写这一封装,脚本本身保持模型无关。构造扩散采样参数:
OmniDiffusionSamplingParams承载generator(由--seed播种)、true_cfg_scale、guidance_scale、guidance_scale_2、num_inference_steps、num_outputs_per_prompt、layers、resolution、height、width等字段(见 image_edit.py)。多阶段参数分发:若引擎为多阶段模型提供
default_sampling_params_list,脚本会逐段克隆,并把扩散段替换为上面构造的diffusion_params;--extra-args中声明的键会合并进extra_args。AR 阶段输入(如 HunyuanImage-3.0):声明了
ar_input_builder的模型会额外走_apply_ar_stage_inputs,用AutoTokenizer加载字节级对齐的 HF tokenizer,构造 AR prefill 与 stop tokens 并写入对应阶段;tokenizer 加载失败默认直接报错(fail fast),只有显式加--allow-tokenizer-fallback才降级为字符串 prompt。生成与保存:
omni.generate(prompt_dict, sampling_params_list=...)返回输出后,脚本优先取output.images,取不到则用extract_images_from_outputs兜底提取;单图直接存--output,多输出(或分层输出)按stem_{idx}[_{sub_idx}].png规则命名保存。
常见问题与排障提示
- OOM:按文档建议先加
--vae-use-slicing --vae-use-tiling;仍不足时叠加--enable-cpu-offload或--enable-layerwise-offload。 - 结果不遵循 prompt:确认
--cfg-scale > 1且提供了--negative-prompt,否则 CFG 实际未启用;蒸馏模型改用--guidance-scale > 1。 - 首次运行慢/编译问题:可用
--enforce-eager关闭 torch.compile 定位是否是编译路径的问题。 - 结果不可复现:检查
--seed是否一致,随机种子决定了torch.Generator的初始状态。
延伸阅读
- CFG 并行等扩散并行加速细节:docs/user_guide/diffusion/parallelism/cfg_parallel.md
- 同目录的在线服务示例:examples/online_serving/image_to_image
- 图生图离线文档入口:docs/user_guide/examples/offline_inference/image_to_image.md
【免费下载链接】vllm-omniA framework for efficient model inference with omni-modality models项目地址: https://gitcode.com/GitHub_Trending/vl/vllm-omni
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考