☰
PiD(Pixel Diffusion Decoder)在 stable-diffusion.cpp 中的部署与像素扩散超分实战
2026/9/28 7:46:56 网站建设 项目流程
  • 人工智能
  • 大模型
  • 本地部署
  • 推理引擎
  • 媒体生成

【免费下载链接】stable-diffusion.cpp

Diffusion model(SD,Flux,Wan,Qwen Image,Z-Image,...) inference in pure C/C++

项目地址:https://gitcode.com/GitHub_Trending/st/stable-diffusion.cpp
点击查看免费下载

PiD 是 NVIDIA 提出的 Pixel Diffusion Decoder,它用像素空间的扩散解码器替代传统 VAE 解码或"先解码再放大"的流程,以源图像 latent 与文本提示为条件,直接扩散生成高分辨率 RGB 像素。本文基于 stable-diffusion.cpp 仓库中的 docs/pid.md 官方文档,结合仓库内src/model/diffusion/pid.hpp、src/pipeline/diffusion_engine.cpp等源码实现,完整讲解 PiD(含 PiD 1.5)的权重准备、命令行配置、核心参数语义与底层工作原理,帮助读者在纯 C/C++ 推理环境中把一张低分辨率图像端到端放大为高分辨率结果。

PiD 是什么:一条替代 VAE 解码的超分路径

在常规扩散模型管线中,去噪完成后通常由 VAE 的 decoder 把 latent 解码回像素,若要高清还需再接一个独立 upscaler(如 ESRGAN)。PiD 的思路不同:它本身就是一个以扩散方式工作的解码器,直接以源 latent 和文本提示为条件,在像素空间逐步去噪生成高分辨率 RGB 图像,从而把"解码"与"放大"合并进同一条扩散路径。两个版本均受支持:

  • 原版 PiD;
  • PiD 1.5(带 pit/LQ 注入增强的版本)。

在 stable-diffusion.cpp 中,PiD 目前以图像编辑(image edit)管线的形式运行:通过-r/--ref-image提供一张参考图像,用与该 PiD 检查点骨干网络匹配的 VAE 将该图编码为 latent,随后 PiD 扩散模型直接以这些 latent 为条件解码/放大到 RGB。

权重准备:四类文件缺一不可

PiD 的推理链路由扩散模型、文本编码器、tokenizer、VAE 四部分组成,需要分别下载,共五步。

  1. PiD 扩散模型(safetensors 格式):从 Hugging Face 上 Comfy-Org 的 PixelDiT 仓库diffusion_models目录获取(例如pid_flux1_512_to_2048_4step_bf16.safetensors)。
  2. Gemma 2 2B 文本编码器(safetensors 格式):同样来自 Comfy-Org 的 PixelDiT 仓库text_encoders目录。
  3. Gemma 2 2B 的tokenizer.json:来自 Gemma 2 2B 的官方模型仓库。
  4. 与 PiD 检查点骨干网络匹配的 VAE(safetensors 格式):来自 nvidia/PiD 官方检查点仓库。

第 4 步的 VAE 必须与 PiD 的骨干网络严格对应,具体对应关系如下:

PiD 骨干网络使用的 VAE命令行参数
Flux / Z-Image PiDFlux VAE--vae-format flux
SD3 PiDSD3 VAE--vae-format sd3
Flux.2 PiDFlux.2 VAE--vae-format flux2
Qwen-Image PiDQwen-Image 2D VAE--vae-format wan

许可证提醒:官方 PiD 模型卡应在使用前确认。在 PiD 首次发布时,官方权重使用 NSCLv1 非商业许可证,请据此评估使用场景。

Gemma 2 tokenizer:必须外置

PiD 与 PiD 1.5 都需要一个与文本编码器检查点匹配的外部 Gemma 2tokenizer.json。tokenizer 并未内嵌在 stable-diffusion.cpp 中,需要将其保存为tokenizer_gemma2.json,并通过--tokenizer参数传入。这一点在 docs/tokenizers.md 中有更完整的说明:PiD(含 1.5)和 Lens(含 Lens Turbo)必须外置 JSON tokenizer,主 tokenizer 缺失时初始化会直接失败;而其他模型在省略该选项时会继续使用内嵌 tokenizer。

C API 用法与 CLI 一致,把同样的字符串填入sd_ctx_params_t::tokenizer;该值不能为空,CLI 原样透传,由TokenizerConfig在文本编码器初始化时解析与校验。

端到端命令行示例

以下命令取自 docs/pid.md(Windows 路径写法;Linux/macOS 下把sd-cli.exe换成对应构建产物的可执行文件路径即可):

.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\pid_flux1_512_to_2048_4step_bf16.safetensors --llm "..\models\text_encoders\gemma_2_2b_it_elm_bf16.safetensors" --tokenizer ..\models\tokenizers\tokenizer_gemma2.json --vae ..\models\vae\ae.sft --vae-format flux --cfg-scale 1.0 -p "a lovely cat" -r ..\assets\ernie_image\turbo_example.png --diffusion-fa -v --steps 4 -H 2048 -W 2048 --rng cpu

这条命令完成了完整的"参考图 → 512×512 → 2048×2048"超分放大。下面是仓库中对应的实际运行效果(输入参考图与输出结果):

对比可见:输出在保留原图构图与色调的基础上,毛发、面部细节与地毯纤维纹理的清晰度显著提升——这正是"像素空间扩散解码"而非简单插值放大带来的效果。

核心参数逐项解析

参数作用备注
--diffusion-model FILEPiD 扩散模型 safetensors对应源码中的Pid::PiDRunner,权重前缀为model.diffusion_model.net(见 src/pipeline/model_builders.cpp)
--llm FILEGemma 2 2B 文本编码器PiD 的条件器使用LLMEmbedder加载该文本编码器
--tokenizer FILE外置 Gemma 2tokenizer.json必须与文本编码器检查点匹配,保存为tokenizer_gemma2.json后传入
--vae FILE独立 VAE 文件需要与 PiD 骨干网络匹配(见上表)
--vae-format FORMATVAE latent 布局覆盖:auto、flux、sd3、flux2、wan(默认auto)使用独立 VAE 文件时必须显式指定,因为 PiD 扩散检查点本身不携带 VAE 格式信息(见 examples/common/common.cpp)
-r/--ref-image FILE参考图像路径,可多次使用必填。PiD 使用第一张参考图编码得到的 latent 作为源条件(见 docs/pid.md 与 src/pipeline/image.cpp)
-p TEXT提示词作为文本条件与源 latent 一起驱动像素空间扩散
--cfg-scale 1.0CFG 引导强度官方 4 步示例使用 1.0(无分类器引导),结合 PiD 的 flow 调度使用
--steps 4扩散步数PiD 官方 4 步检查点;源码中 PiD 的默认采样方法为 LCM(见 src/pipeline/request.cpp),与低步数采样适配
-H/-W输出高度/宽度示例为 2048×2048;实际请依据硬件显存调整
--diffusion-fa仅在扩散模型中使用 flash attention降低大分辨率下的注意力显存开销(见 examples/common/common.cpp)
-v输出 verbose 日志便于观察 PiD 版本检测与各阶段耗时
--rng cpu使用 CPU 端 RNG示例中用于保证可复现的随机性

--vae-format为什么如此关键

从源码看,PiD 在构建 VAE 时有一个专门的逻辑:当检测到版本为 PiD 且vae_format不是auto时,会用 VAE 格式反推 VAE 对应的模型版本来构建 VAE(见 src/pipeline/model_builders.cpp 与 src/pipeline/model_builders.cpp):

  • flux→VERSION_FLUX;
  • sd3→VERSION_SD3;
  • flux2→VERSION_FLUX2;
  • wan→VERSION_WAN2(Qwen-Image 2D VAE 采用 Wan 系列 VAE 布局)。

因为 PiD 扩散检查点本身不携带 VAE 格式信息,若--vae-format与 VAE 实际 latent 布局不匹配,会导致参考图编码出的 latent 与扩散模型的输入预期不一致,产生错误结果——这也是官方文档将其列为最重要注意事项的原因。

源码级原理:PixelDiT 是如何工作的

配置自动检测:PiD 与 PiD 1.5

Pid::PixelDiTConfig::detect_from_weights会在加载权重时自动识别版本:若权重中存在lq_proj.pit_head.weight,则判定为PiD 1.5(pit_lq_inject = true),否则为原版PiD,并在日志中打印pid: version = 1.5或pid: version = 1(见 src/model/diffusion/pid.hpp)。同时它还从权重张量形状推导patch_depth、pixel_depth、patch_mlp_hidden_dim、LQ 通道数等关键结构参数:

  • PiD 1.5 的 LQ 注入路径中,latent_proj_in_channels == 16时使用 16 通道、down factor 8 的 LQ 配置;为 32 时使用 128 通道、down factor 16、unpatchify factor 2 的配置,并将 RoPE 参考网格扩展为 128×128,开启replicate_padding;
  • lq_gate_per_token通过gate_modules.0.content_proj.weight的最后一维是否为 1 判定。

双分支架构:patch 分支 + pixel 分支

从 src/model/diffusion/pid.hpp 的PixelDiT::forward可以看到,模型由两大处理流组成:

  1. patch 分支(高维语义):输入像素图先patchify为 16×16 patch token,经s_embedder嵌入;文本 token 经y_embedder嵌入并叠加可学习的位置嵌入后,在patch_depth(默认 14)个MMDiTBlockT2I中与图像 token 做联合注意力(MMDiTJointAttention),图像/文本各自使用 RMSNorm 与 adaLN 调制,MLP 为 SiLU 门控的FeedForward。
  2. pixel 分支(像素精修):pixel_depth(默认 2)个PiTBlock在完整像素网格上工作,通过compress_to_attn/expand_from_attn把 patch 内像素压缩到注意力维度做自注意力,再展开回像素,最后由FinalLayer输出 RGB 并通过unpatchify还原为像素图。

值得注意的是,默认配置in_channels = 3、hidden_size = 1536、pixel_hidden_size = 16、patch_size = 16、txt_embed_dim = 2304、txt_max_length = 300等(见 src/model/diffusion/pid.hpp)表明该模型直接处理 3 通道像素空间——这与"像素空间扩散解码器"的定位一致。

LQ 潜空间注入与 sigma-aware gate

PiD 1.5 的核心增强是LQProjection2D:参考图像编码得到的 latent 经过卷积下采样与残差块(PiDResBlock)提取 LQ(低质量)特征,在patch_depth层中每隔lq_interval(默认 2)层通过SigmaAwareGate注入扩散主干(见 src/model/diffusion/pid.hpp 与 src/model/diffusion/pid.hpp)。SigmaAwareGate的开关信号是content_logit减去alpha * sigma后过 sigmoid——即注入强度随噪声水平动态调节,噪底高时门控减弱、噪底低时加强,使参考信息在去噪后期发挥更大作用。

四类位置编码

PiDRunner::build_graph(见 src/model/diffusion/pid.hpp)在构图时预生成四组位置编码:

  • pos_img:图像 token 的二维交错 RoPE(theta=10000,scale=16,参考网格来自配置,PiD 1.5 为 128×128);
  • pos_txt:文本 token 的一维 RoPE(theta=10000);
  • pixel_pos_full:完整像素网格的绝对位置(x/y 各半维度的 timestep embedding);
  • pixel_pos_comp:压缩后像素注意力的二维 RoPE。

采样流程中的特殊处理

在 src/pipeline/diffusion_engine.cpp 中,PiD 还享有多处专门适配:

  • 预测类型为flow 预测(FLOW_PRED),默认 flow shift 为 1.5(见 src/pipeline/diffusion_engine.cpp),配合--cfg-scale 1.0的官方 4 步用法;
  • get_vae_scale_factor()对 PiD 返回1(见 src/pipeline/diffusion_engine.cpp)——解码直接在像素空间完成,不再有 VAE 8 倍下采样概念;
  • get_latent_channel()对 PiD 返回3(见 src/pipeline/diffusion_engine.cpp),即 RGB 三通道;
  • 参考图编码阶段,PiD跳过参考图预缩放(resize_before_vae对 PiD 不生效,见 src/pipeline/image.cpp),直接以原始参考图编码 latent;若未提供任何参考图,则报错PiD requires a reference image并中止(见 src/pipeline/image.cpp)。

使用注意事项

  1. -r/--ref-image为必填项。PiD 使用第一张参考图像编码出的 latent 作为源条件;若传多张,则取第一张(源码中compute()使用diffusion_params.ref_latents->front(),见 src/model/diffusion/pid.hpp)。
  2. --vae-format必须与 PiD 检查点所用 VAE 的 latent 布局匹配(Flux→flux、SD3→sd3、Flux.2→flux2、Qwen-Image→wan)。使用独立 VAE 文件时尤其重要,因为 PiD 扩散检查点本身不携带 VAE 格式信息。
  3. tokenizer 必须外置:将 Gemma 2 2B 的tokenizer.json保存为tokenizer_gemma2.json并传入--tokenizer;缺失时初始化失败,不会回退到内嵌 tokenizer。
  4. 输出分辨率与显存直接相关,官方示例为 2048×2048(4 步),实际部署请结合自身硬件调整-H/-W,必要时使用--diffusion-fa降低注意力显存占用。
  5. 使用前请核对官方模型卡,首次发布时的官方权重为 NSCLv1 非商业许可。

延伸阅读

  • docs/pid.md:PiD 官方使用文档(本文依据);
  • docs/tokenizers.md:外部 JSON tokenizer 的 CLI 与 C API 用法、支持组件清单;
  • src/model/diffusion/pid.hpp:PixelDiT 完整实现(配置检测、双分支架构、LQ 注入、位置编码);
  • src/pipeline/diffusion_engine.cpp:PiD 的 flow 调度、VAE scale、latent 通道与参考图管线适配;
  • src/pipeline/model_builders.cpp:PiD 条件器/扩散模型/VAE 的构建与--vae-format映射;
  • examples/common/common.cpp:--vae-format、--diffusion-fa、-r/--ref-image等 CLI 参数定义。
  • 人工智能
  • 大模型
  • 本地部署
  • 推理引擎
  • 媒体生成

【免费下载链接】stable-diffusion.cpp

Diffusion model(SD,Flux,Wan,Qwen Image,Z-Image,...) inference in pure C/C++

项目地址:https://gitcode.com/GitHub_Trending/st/stable-diffusion.cpp
点击查看免费下载

相关推荐

上一篇:3分钟快速上手:用ChromeKeePass告别密码记忆烦恼
下一篇:字节跳动重磅发布M3-Agent-Control大模型,328亿参数开启AI普惠新纪元

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询