图像生成与编辑
Qwen-Image-2.1 可以把提示词变成图像,也可以把提示词加一张或多张参考图变成编辑后的图像。本页包含下载、运行示例、默认值,以及决定出图耗时的设置。
这些命令遵循与文本模型示例相同的约定:Hugging Face CLI、从仓库根目录源码构建,并把 --backend 换成与你硬件匹配的值。参见按家族下载与运行。
Qwen-Image-2.1(提示词 → 图像,提示词 + 图像 → 编辑后的图像)
最短路径是现成的 config/qwen-image-2.1.json。它固定仓库修订版本与 SHA-256 校验,缺什么下什么(共四个文件,约 10.29 GiB),存放到 $TENSORSHARP_MODELS/qwen-image-2.1/;未设置 TENSORSHARP_MODELS 时为仓库内的 models/qwen-image-2.1/。该配置选择 ggml_metal;在已构建 CUDA 后端的 NVIDIA 机器上追加 --backend ggml_cuda;原生 CPU 后端为 ggml_cpu,--backend cpu 则全部用纯 C# 运行(见在 CPU 上运行)。
dotnet build TensorSharp.Cli/TensorSharp.Cli.csproj -c Release
dotnet build TensorSharp.Server.Host/TensorSharp.Server.Host.csproj -c Release
# 文生图
dotnet run --project TensorSharp.Cli -c Release --no-build -- \
--config config/qwen-image-2.1.json \
--prompt 'A small orange cat beside a blue ceramic vase, soft daylight, detailed photograph' \
--width 2048 --height 2048 --diffusion-steps 40 --cfg 1 \
--diffusion-seed 42 --output generated.png
# 图像编辑
dotnet run --project TensorSharp.Cli -c Release --no-build -- \
--config config/qwen-image-2.1.json \
--image generated.png \
--prompt 'Change the blue vase to a red vase. Preserve the cat, lighting and composition.' \
--width 2048 --height 2048 --diffusion-steps 40 --cfg 1 \
--diffusion-seed 42 --output edited.png
# 服务端 + Web UI
dotnet run --project TensorSharp.Server.Host -c Release --no-build -- \
--config config/qwen-image-2.1.json --host 127.0.0.1 --port 5000
如需自己下载这四个文件,请显式传入伴随文件:
hf download Abiray/Qwen-Image-2.1-GGUF qwen_image_2.1_Q4_K_M.gguf --local-dir models
hf download Comfy-Org/Qwen-Image-2.1 vae/qwen_image_2.1_vae_bf16.safetensors --local-dir models
hf download Qwen/Qwen3-VL-8B-Instruct-GGUF Qwen3VL-8B-Instruct-Q4_K_M.gguf mmproj-Qwen3VL-8B-Instruct-F16.gguf --local-dir models
dotnet TensorSharp.Server.Host/bin/TensorSharp.Server.Host.dll --model models/qwen_image_2.1_Q4_K_M.gguf \
--qwen-image-vae models/vae/qwen_image_2.1_vae_bf16.safetensors \
--qwen-image-vl models/Qwen3VL-8B-Instruct-Q4_K_M.gguf \
--qwen-image-mmproj models/mmproj-Qwen3VL-8B-Instruct-F16.gguf \
--backend ggml_cuda
| 组件 | 文件 | 来源 |
|---|---|---|
| 扩散 Transformer | qwen_image_2.1_Q4_K_M.gguf | Abiray/Qwen-Image-2.1-GGUF |
| 专用 VAE | qwen_image_2.1_vae_bf16.safetensors | Comfy-Org/Qwen-Image-2.1 |
| 文本编码器 | Qwen3VL-8B-Instruct-Q4_K_M.gguf | Qwen/Qwen3-VL-8B-Instruct-GGUF |
| 编辑用视觉编码器 | mmproj-Qwen3VL-8B-Instruct-F16.gguf | 同一个 Qwen3-VL 仓库 |
下载大小并不等于推理峰值内存:运行时内存还包括激活值、解码缓冲区和工作权重,更大的图像和多张参考图都会提高内存需求。
其他 Qwen-Image-2.1 GGUF 也能加载。完全不带元数据的文件,例如 Unsloth 的 qwen-image-2.1-Q8_0.gguf(包括张量带 model.diffusion_model. 前缀的情形),会依据张量布局识别——从不依据文件名。伴随文件扫描只匹配 qwen_image_2.1_vae 的 safetensors 文件,以及名字里含 qwen3vl-8b 或 qwen3-vl-8b 的文件,因此名为 mmproj-BF16.gguf 的投影器需要用 --qwen-image-mmproj 指定。在 M5 Pro 上,这个 Unsloth Q8_0 文件生成 1024×1024、40 步用时 337.7 秒,同一次单次对比中 stable-diffusion.cpp 为 383.1 秒。只有 2.1 能加载:更早的 Qwen-Image 或 Qwen-Image-Edit-2511 Transformer 会在加载时被拒绝(退出码 2)。
Qwen-Image-2.1-Turbo(8 步)
Qwen-Image-2.1-Turbo 是同一个 7B Transformer 蒸馏为 8 步 Euler、CFG 1、使用一个固定调度的版本;它的 VAE、文本编码器与视觉投影器就是上面的 2.1 文件。config/qwen-image-2.1-turbo.json 把 AtomicChat 的 Qwen-Image-2.1-Turbo-AD-Q4_K.gguf(4.20 GB)下载到模型根目录下的 qwen-image-2.1/,与上面那些按发布名称存放的 2.1 文件放在一起,因此已存有这些文件的目录只需下载 Transformer。Qwen-Image-2.1-Turbo-Q8_0.gguf(7.59 GB)的 Transformer 最接近全精度检查点(模型卡中相对 BF16 的 LPIPS:0.037,AD-Q4_K 为 0.147);两者使用同一个 Q4_K_M 文本编码器,按模型卡的测量,它让图片偏离的程度与 AD-Q4_K 相当。
dotnet run --project TensorSharp.Cli -c Release --no-build -- \
--config config/qwen-image-2.1-turbo.json \
--prompt 'a neon sign that reads "OPEN LATE", rainy night' \
--width 1024 --height 1024 --diffusion-seed 42 --output turbo.png
- 声明,而不是检测。GGUF 没有元数据,Turbo 的张量又与基础检查点相同,所以配置文件用
"qwen-image-variant": "turbo"声明它(CLI 与服务端为--qwen-image-variant,进程内为TS_QWEN_IMAGE_VARIANT;TensorAgent 的 Turbo 条目自行声明)。不声明时,文件名含单词turbo即按 Turbo 处理并在加载时打印这一假定,因为合并进基础检查点的步数蒸馏 LoRA 也以同样的文件名发布。 - 自己的调度。
model_index.json中的sample_sigmas[1.0, 0.978453, 0.95418, 0.926626, 0.89508, 0.845148, 0.704534, 0.414568]加上最后的 0,在任何尺寸下都原样使用,CFG 为 1。其他步数会被拒绝:Qwen 没有评估过其他调度。显式的 CFG 大于 1 时仍会加上负向前向。 - LoRA 插件。带采样配方的插件(四个步数蒸馏插件)在 Turbo 上会被拒绝并说明原因;不带配方的插件可以加载。Film Stills 与 Grainscape 已在 Turbo 上验证(风格会生效,并且与在基础检查点上一样,部分场景会被重画),TensorAgent 在 Turbo 上提供这两个,以及实验性 Casual Phone Photo 与 Voxel Style;这些新插件的目录可用性不代表跨设备质量验证。
- 一致性与速度。在 M5 Pro 上 1024×1024 的一张 Turbo 图片,AD-Q4_K 用 69 秒,Q8_0 用 68 秒,而基础模型 40 步要 320 秒:Turbo 每步的开销与基础模型相同(7.6–7.9 秒),Q8_0 还略快一些。在相同文件、提示词、种子与噪声下,TensorSharp 的图片与 stable-diffusion.cpp 的 PSNR 为 39–60 dB(三个提示词与一次编辑);文生图每步快 12–13%,编辑每步快 40%。详见模型卡。
图像生成与编辑(Qwen-Image-2.1)
所加载的 qwen_image GGUF 是 Qwen-Image-2.1 扩散 Transformer。TensorSharp 在其旁解析伴随文件——专用 2.1 VAE、Qwen3-VL-8B 文本编码器,以及编辑时使用的 Qwen3-VL mmproj 视觉编码器——也可以用 --qwen-image-vae / --qwen-image-vl / --qwen-image-mmproj 指定(环境变量:TS_QWEN_IMAGE_VAE / TS_QWEN_IMAGE_TE / TS_QWEN_IMAGE_MMPROJ)。原生 RGBA 输入与 PNG 输出保留透明度:Qwen3-VL 条件分支把参考图合成到白色背景上,而 VAE 保留 alpha 通道。
- 生成还是编辑。不带
--image时执行生成;带一个或多个--image时执行编辑,参考图按给出的顺序使用。也可以用--input prompt.txt代替--prompt提供提示词。 - 采样默认值。省略设置时使用 40 步 Euler 和 CFG 1.0,遵循 Qwen 推荐的无引导采样——每步只做一次 Transformer 预测。显式设置大于 1 的 CFG 会增加负向预测并应用
--negative-prompt;在 CFG 1 下负向提示词不起作用。 - 尺寸。省略尺寸时,生成为 2048×2048;编辑则取与第一张参考图宽高比一致、像素面积大致相同的尺寸。要覆盖此行为,请同时设置宽度和高度,且都取 32 的倍数。在服务端,
--width与--height(两者都要给)设置未指定尺寸的请求所用的默认尺寸——而 Web UI 从不指定尺寸。每张参考图以约 1 百万像素(若输出面积更小,则以输出面积)作为条件输入。按面积决定尺寸的编辑会把比该面积大的图片缩小;--keep-source-size(请求中为keepSourceSize,Web UI 与 TensorAgent 的每次编辑都会发送)改为返回第一张图的精确尺寸,采样不超过该面积与图片自身的面积,因此对编辑结果再次编辑时尺寸保持不变。 - 调度。遵循官方调度器配置:指数动态偏移(序列长度/偏移锚点为 256/0.5 与 8192/0.9),随后终端拉伸到 0.02,并以最后一个 Euler 步走到零。
- 种子。
--diffusion-seed(API 中为seed,默认 0)决定初始噪声。文生图噪声只由种子和尺寸决定,与 stable-diffusion.cpp 相同。编辑的噪声还取决于参考图(用其 8 位像素的哈希选出单独的噪声流),因此用画出某张图的种子和尺寸去编辑它,不会从生成它的那份噪声开始——从那份噪声出发,模型可能照原样重描这张图而忽略指令。相同的图片与设置仍得到相同的编辑结果。TS_QWEN21_EDIT_NOISE=seed让编辑只按种子取噪声,用于噪声对齐的对比。见种子与编辑。 - 执行。在 GGML 后端(
ggml_metal、ggml_cuda、ggml_vulkan或ggml_cpu)上,扩散 Transformer 以常驻量化权重运行一张完整的 GGML 图;在纯 C# 的cpu后端上,它对同样的文件映射权重运行托管前向(见在 CPU 上运行)。CUDA 与 Metal 会在多次预测之间保留这张图(TS_QWEN21_GRAPH_REUSE=1,默认开启)。没有 CPU 权重流式加载模式;内存不足时请先用较小的尺寸。VAE 在 CUDA 与 Metal 上默认作为一整张图解码——M5 Pro 上 1024×1024 用时 5.0 秒,逐卷积路径为 13.0 秒;在 Vulkan 上则逐卷积在设备上运行,输入按 2 的整数次幂精确缩放,以落在 Vulkan F16 矩阵操作数的范围内;TS_QWEN21_VAE_FUSED=0在任何后端上都选择逐卷积路径。--tp N可把 Transformer 切分到多张 GPU(见下文)。LoRA 插件在这五个后端上都能运行(见下文)。
提速的关键是分辨率和步数。削减步数最多的是步数蒸馏 LoRA 插件,它把默认的 40 步换成 4–8 次 Transformer 前向:在 M5 Pro 上,1024×1024、Viggle Turbo 的 6 步整体用时 54.5 秒(见 LoRA 插件)。2K 正方形的潜在图像 token 数是 1K 正方形的四倍,注意力计算也更多,因此 --width 1024 --height 1024 是草图设置。--diffusion-steps 25 --cfg 1 是官方 ComfyUI 生成与编辑工作流使用的更快配置;默认仍为 40 步,更少的步数是质量与速度之间的权衡,并不代表质量相当。CFG 1 本身就意味着每步只做一次 Transformer 前向。快速冒烟测试可用 256×256、一步,它只验证加载和端到端数据通路,不说明图像质量。图像编辑还会从默认开启的前缀 KV 缓存中获益。
可从 CLI(--prompt,编辑时再加 --image)、Web UI(不带附件的提示词会生成图像;附加一张或多张图像即可编辑,并有实时去噪预览)、HTTP API(/api/image-generate 与 /api/image-edit,各有 /stream 变体),或在进程内从 C# 通过 QwenImageModel.GenerateImage() / EditImage() 运行。由于扩散流水线共享可变的工作状态,图像操作会串行执行。完整细节见仓库的 Qwen-Image-2.1 卡片(验证记录见英文版)。
编辑选定区域
在 TensorAgent 或服务端 Web UI 中附加照片,选择缩略图旁的选择区域,涂选或擦除区域,再选择使用选区。该照片成为编辑目标,其余照片保留为参考图。加载 Qwen-Image 2.1,描述修改并发送。编辑器支持鼠标、触摸、触控笔、缩放/平移、撤销/重做、反选和边缘柔化。比较原图用于检查结果;再次编辑恢复照片、选区与提示词。
保存的选区保留目标的原始尺寸,以及选区外精确的解码 RGB/alpha 像素。灰度蒙版中白色编辑、黑色保护;alpha 蒙版中透明像素编辑。蒙版必须与第一张图的尺寸相同。边缘柔化向内渐变。可选裁剪模式仅处理带上下文的选区,再放回原始画布,可减少工作量,但会减少周围上下文。选区内是否按指令修改仍取决于模型。
dotnet run --project TensorSharp.Cli -c Release --no-build -- \
--config config/qwen-image-2.1.json \
--image photo.png --mask selection.png --mask-mode grayscale \
--prompt 'Change the selected vase to red ceramic' \
--mask-feather 8 --mask-crop --mask-crop-padding 96 \
--width 1024 --height 1024 --diffusion-seed 42 --output edited.png
--mask-invert 反转选区。柔化范围为 0–1024 个源图像素;裁剪留边为 0–16384(默认 64)。编辑器支持最多 1600 万像素、每边最多 8192 像素,并使用单独的全分辨率 PNG 编辑 HEIC/HEIF 选区。同一套蒙版字段支持 JSON、multipart 与 SSE 图像编辑 API 及 C# 的 QwenImageParams。详细语义与验证边界见模型卡。
在 CPU 上运行(--backend cpu)
--backend cpu 用托管 C# 运行整条流水线,不调用任何 GGML:Transformer(像 ggml-cpu 那样使用 8 位激活、在多行整数 GEMM 上计算;分块 flash attention;不合并的 LoRA)、位于主机内存的前缀 KV 缓存、同样基于整数 GEMM 的 Qwen3-VL 文本编码器与基于 packed F32 GEMM 的视觉编码器,以及以隐式 im2col packed 卷积实现、在每个逻辑 CPU 一个线程的线程池上运行的 VAE。在这个后端上,未指定尺寸的请求输出 1024×1024(1 百万像素);ggml_cpu 与 GPU 后端保持 2048×2048。这个后端会拒绝 --tp。在 i7-11800H(8 核 16 线程、AVX-512、32 GB)上实测,文生图,种子 42:
| 运行 | cpu | ggml_cpu | 与 ggml_cpu 图像对比 |
|---|---|---|---|
| 256×256、2 步 | 16.9–17.1 s(VAE 解码 2.8–2.9 s) | 36.1–36.4 s(VAE 解码 10.8–11.2 s) | PSNR 37.7 dB,SSIM 0.984 |
| 512×512、Pruna 5 步 LoRA | 118 s(每步 17.6–21.7 s) | 295.7 s(VAE 解码 50.3 s) | PSNR 32.9 dB,SSIM 0.972 |
两者图像不同,是因为托管 Transformer 的求和顺序与 ggml-cpu 不同,并且在 ggml-cpu 使用 F16 GELU 表的地方保持 F32。TS_QWEN21_CPU_MATMUL=f32(F32 激活乘以反量化的权重分块,之前的默认值)更慢(上面两次运行分别为 20.4 s 与 169.6 s),数值更稳定。另有两次更大的运行是用这个 F32 Transformer 测的:1024×1024、Pruna LoRA 用时 756 s,ggml_cpu 为 1101 s;512×512 编辑为 224 s 对 353 s。在 CPU 上,内存是限制所在:估计峰值放不下的尺寸会在开始任何工作之前被拒绝(TS_QWEN_IMAGE_CPU_MEMORY_CHECK=0 可跳过);1024×1024 的 Pruna 生成提交内存峰值为 3.7 GiB,2048×2048 的 VAE 编码加解码为 10.5 GiB。内核开关(TS_QWEN21_CPU_*、TS_QWEN_TE_CPU_MATMUL、TS_CPU_GEMM_THREADS)见模型卡。
前缀 KV 缓存
文本与参考图 token 用 t = 0 调制,并且从不关注正在生成的图像,因此它们的 K 和 V 在每个去噪步都相同。TensorSharp 实现了官方的前缀 KV 缓存:第一步运行整个序列,把每个块前缀部分的 K 和 V 存到设备上;之后每一步只计算目标图像的 token。它默认开启(TS_QWEN21_PREFIX_CACHE=0 关闭),存的正是注意力读取的类型——Metal 与 CUDA flash attention 为 F16,其他为 F32——因此在默认存储下输出 PNG 与不用缓存时逐字节相同。CFG 运行为每个分支各保留一份缓存,所有缓存都在 VAE 解码前释放。代价是内存:F16 下每个前缀 token、每个分支 512 KiB,每张约 1 百万像素的参考图约 2 GiB。一份缓存最多使用设备报告的空闲内存的一半(TS_QWEN21_PREFIX_CACHE_MAX_MIB 可进一步限制),放不下时会被拒绝并给出警告;TS_QWEN21_PREFIX_CACHE_TYPE=q8_0 或 q8_0_v 以 8 位存储,节省内存,但每步慢 5–13%,输出也会有少量舍入。
收益与前缀在序列中所占的比例成正比。M5 Pro 上 1024² 编辑,单参考图每步从 17.97 秒降至 9.65–10.38 秒,双参考图从 33.32 秒降至 11.46 秒(2.91×);A40(ggml_cuda)上单参考图编辑从 2.547 秒降至 1.328 秒。文生图的前缀只有提示词,只快 1–3%;2048² 时目标 token 占主导,编辑的收益也更小。细节见 Qwen-Image-2.1 卡片,Vulkan 数据见英文版卡片。
多 GPU
在 ggml_cuda 或 ggml_vulkan 上,--tp N 按 Megatron 方式切分扩散 Transformer:每张卡持有 32/N 个完整注意力头与 12,288/N 个 MLP 列,每个块的两个行并行乘积在 GPU 之间求和,每张卡只缓存自己那些头的前缀。N 必须整除 32 个注意力头——单机上为 2、4、8 或 16——且切分每个权重时都不能拆开它的量化块,加载时会按权重类型逐一检查;实测只覆盖 2 卡。文本编码器、视觉编码器与 VAE 留在第一张卡上;不支持多节点组。在两张 A40 上,1024² 文生图每步快 1.34×,1024² 单参考图编辑快 1.42×,2048² 快 1.54–1.57×;ggml_vulkan 经主机内存归约,为 0.86×——比单卡还慢。部分和的相加顺序不同,因此输出与单卡不逐位相同:构图与质量一致,细节可能不同。每张卡的内存与数值检查见卡片。
LoRA 插件
CLI 与服务端都可以用 --lora 给扩散 Transformer 加上一个 LoRA:一种风格、一项编辑能力,或者把默认 40 步换成 4–8 次 Transformer 前向的步数蒸馏适配器。重复该参数可叠加插件;--lora-scale 设置前一个 --lora 的强度,--lora-config 指定它的伴随配置(TensorSharp LoRA 配置、PEFT adapter_config.json 或 VideoX-Fun pdd_config.json)。config/lora/ 中的十四个现成 Qwen-Image-2.1 插件(qwen-image-2.1-*.json)会在首次使用时下载并校验权重哈希,并带有适配器的强度与采样配方。该目录还有两个 MiniMax-H3 Turbo 插件,Qwen-Image-2.1 不接受它们。
# Viggle Turbo:插件配方给出 6 步、CFG 1(支持 4–8 步)
dotnet run --project TensorSharp.Cli -c Release --no-build -- \
--config config/qwen-image-2.1.json \
--lora config/lora/qwen-image-2.1-viggle-turbo.json \
--prompt 'A small orange cat beside a blue ceramic vase, soft daylight, detailed photograph' \
--width 1024 --height 1024 --diffusion-seed 42 --output turbo.png
# 服务端把启动时的这组插件应用到每个图像请求
dotnet run --project TensorSharp.Server.Host -c Release --no-build -- \
--config config/qwen-image-2.1.json --lora config/lora/qwen-image-2.1-pruna-8step.json
- 随附插件。步数蒸馏:
viggle-turbo(6 步,支持 4–8 步)、pruna-8step、pruna-5step与fun-acc-4step(带逐步输出头的 PDD 包)。风格与编辑能力:film-stills、grainscape、casual-phone(触发词lbxstyle)、voxel-style(附上照片)、fix(DoRA)、detail-enhancer、natural-exposure、anime-consistency、object-remover与object-mover。每个文件的注释给出了模型卡、触发短语与许可证;其中数个仅限非商业用途。 - 采样优先级。显式的
--diffusion-steps/--cfg(或请求中的steps/cfg)优先于插件的配方,配方又优先于模型默认值。配方没有调度的步数会被拒绝并列出支持的步数;每次运行只能有一个插件带配方,在检查点自带调度的 Turbo 上则一个也不行。 - 格式。Diffusers / PEFT、ComfyUI / ai-toolkit、DiffSynth / ModelScope 与 kohya 命名;alpha 取自逐模块的
.alpha张量、diffusers 保存器嵌入文件中的 PEFT 元数据、adapter_config.json或插件自己的alpha,都没有时等于 rank——kohya 的ss_network_alpha是训练元数据,会被忽略,与 ComfyUI 和 diffusers 一致;DoRA;VideoX-Fun PDD 包。LoKr、LoHa、文本编码器 LoRA 以及为其他模型制作的 LoRA 会被拒绝并给出说明;不会静默跳过任何张量。 - 执行。以不合并的方式应用,即
y = W x + B (A x),叠加在量化权重之上,因为把蒸馏 LoRA 的微小增量合并进 Q8_0 或 Q4 权重会让其中大部分被舍入掉。与前缀 KV 缓存及--tp N兼容,此时每张 GPU 持有自己那部分因子。 - 服务端。启动时的这组插件作用于每次生成与编辑;尚未实现按请求选择 LoRA。
参数说明与插件配置格式见仓库的 USAGE_zh-cn.md,打包与张量并行细节见 Qwen-Image-2.1 卡片。