- 人工智能
- 大模型
- 机器学习
- 深度学习
- 本地部署
- 模型推理服务
【免费下载链接】candle
Minimalist ML framework for Rust
stable-diffusion是 candle 仓库中一个将 Hugging Face Diffusers 生态移植到 Rust/Candle 的端到端示例,支持 Stable Diffusion v1.5、v2.1、XL 1.0 以及 XL Turbo 四种模型版本。本文将以 candle-examples/examples/stable-diffusion/README.md 为核心,结合 main.rs 与 stable_diffusion 模块 源码,完整讲解从权重下载、命令行运行、调度器选择到 flash-attention 加速和内存优化的全过程,读完即可在 GPU 或 CPU 上自行生成高质量图像。
图:由 Stable Diffusion XL 在 Rust/Candle 下生成的"手持蜡烛的锈蚀机器人",出自 assets/stable-diffusion-xl.jpg。
项目定位:用 Rust 复刻 Diffusers API
stable-diffusion示例是 diffusers-rs 目录:
clip.rs:CLIP 文本编码器,负责把 prompt 编码为条件向量;unet_2d.rs/unet_2d_blocks.rs:UNet 2D 条件去噪网络(含跨注意力);vae.rs:AutoEncoderKL,负责图像与潜空间(latent space)之间的编解码;schedulers.rs:调度器抽象接口,以及ddim.rs、euler_ancestral_discrete.rs、uni_pc.rs、ddpm.rs等具体实现。
从源码结构可以推断,整个生成流程遵循经典扩散管线:文本编码 → 潜空间加噪 → 多步去噪 → VAE 解码为图像,与 Python Diffusers 的 API 设计一一对应。
支持的模型版本与权重获取
本示例支持以下版本(对应 main.rs 中的StableDiffusionVersion枚举):
| 版本 | --sd-version取值 | 对应 Hugging Face 仓库 |
|---|---|---|
| Stable Diffusion v1.5 | v1-5 | runwayml/stable-diffusion-v1-5 |
| Stable Diffusion v2.1 | v2-1 | stabilityai/stable-diffusion-2-1 |
| Stable Diffusion XL 1.0 | xl | stabilityai/stable-diffusion-xl-base-1.0 |
| SDXL Turbo | turbo | stabilityai/sdxl-turbo |
此外,源码中还定义了v1-5-inpaint、v2-inpaint、xl-inpaint三个修图(inpainting)版本(对应仓库stable-diffusion-v1-5/stable-diffusion-inpainting、stabilityai/stable-diffusion-2-inpainting、diffusers/stable-diffusion-xl-1.0-inpainting-0.1),用于带蒙版的局部重绘场景。
权重无需手动下载。首次运行时,程序会通过 candle-examples/src/hub.rs 中的Api(基于hf-hub封装)自动从 Hugging Face Hub 拉取所需文件,并按仓库结构分别下载unet/、vae/、text_encoder/(XL 还有text_encoder_2/)下的.safetensors权重以及tokenizer.json。若希望离线使用或指定自有权重,可通过--unet-weights、--clip-weights、--clip2-weights、--vae-weights、--tokenizer传入本地文件路径(见下文参数表);运行--help可以查看全部可用选项。
运行第一个示例
在仓库根目录执行以下命令即可用 CUDA + cuDNN 在 GPU 上生成图像:
cargo run --example stable-diffusion --release --features=cuda,cudnn \ -- --prompt "a cosmonaut on a horse (hd, realistic, high-def)"运行结束后,默认在当前目录生成sd_final.png。若没有 NVIDIA GPU,可去掉--features=cuda,cudnn并加--cpu改用 CPU 推理(速度会慢很多);macOS 用户可尝试--features=metal使用 Metal 后端。
体验 SDXL Turbo:一步成像
Turbo 版本基于对抗蒸馏(adversarial distillation)训练,去噪步数大幅减少,生成速度远快于前几个版本。仅需增加一个--sd-version turbo参数:
cargo run --example stable-diffusion --release --features=cuda,cudnn \ -- --prompt "a cosmonaut on a horse (hd, realistic, high-def)" --sd-version turbo这一加速的根源在于源码中的默认配置:从 mod.rs 可见,普通版本(v1-5 / v2-1 / xl)默认n_steps = 30,而 Turbo 默认仅n_steps = 1,同时默认引导系数guidance_scale从 7.5 降为 0(蒸馏模型本身已集成引导,无需再对无条件分支做加权外推)。
命令行参数全解析
以下参数均可在 main.rs 的Args结构中找到定义,覆盖 README 所述全部选项并额外列出源码中支持的进阶参数:
| 参数 | 说明 | 默认值 |
|---|---|---|
--prompt | 用于生成图像的提示词 | "A very realistic photo of a rusty robot walking on a sandy beach" |
--uncond-prompt | 可选的负向提示(无条件 prompt),用于引导系数计算 | 空字符串 |
--sd-version | 模型版本,取值v1-5/v2-1/xl/turbo | v2-1 |
--cpu | 强制使用 CPU 而非 GPU | 关闭 |
--height/--width | 生成图像的高宽,必须能被 8 整除(源码中assert_eq!(height % 8, 0)强制校验) | 随版本不同:v1-5 为 512×512,v2-1 为 768×768,XL/Turbo 为 1024×1024(Turbo 为 512×512) |
--n-steps | 扩散去噪步数 | 普通版本 30,Turbo 1 |
--num-samples | 迭代生成的样本数 | 1 |
--bsize | 同时生成的样本数(批大小) | 1 |
--final-image | 输出图片文件名 | sd_final.png |
--use-flash-attn | 启用 flash-attention 加速 | 关闭 |
--use-f16 | 使用 FP16 权重与半精度推理 | 关闭 |
--guidance-scale | 引导系数(CFG 权重) | 普通版本 7.5,Turbo 0 |
--seed | 随机种子,复现结果用;不指定时自动生成随机种子并在终端打印 | 随机 |
--sliced-attention-size | 切分注意力的大小,0 表示自动切分(默认关闭),用于显存受限场景 | 关闭 |
--intermediary-images | 每个去噪步骤都输出一张中间图像(文件名带-N后缀) | 关闭 |
--tracing | 启用 tracing,生成trace-timestamp.json供 Chrome tracing 分析 | 关闭 |
--unet-weights/--clip-weights/--clip2-weights/--vae-weights/--tokenizer | 指定本地.safetensors权重与 tokenizer 文件,跳过 Hub 下载 | 自动下载 |
当num_samples > 1时,输出文件会按basename.{idx}.png规则命名(见output_filename函数)。--num-samples与--bsize的区别在于:前者是串行迭代生成多张图,后者是单次去噪中并行生成一批图。
关于--use-f16有个值得注意的细节:SDXL/Turbo 在 FP16 下会改用社区修复版 VAE 仓库madebyollin/sdxl-vae-fp16-fix,这是为了规避 SDXL 官方 VAE 在 FP16 下数值溢出的已知问题(mod.rs 中的注释引用了相关 issue)。
调度器:DDIM 与 Euler Ancestral
调度器决定"噪声如何逐步去除",直接权衡生成速度与画质。本示例的默认调度器配置(mod.rs):
- v1.5、v2.1、XL 1.0:默认使用DDIM(Denoising Diffusion Implicit Model)调度器,即
ddim::DDIMSchedulerConfig。DDIM 通过隐式采样可以在更少的步数下获得不错的画质; - XL Turbo:默认使用Euler Ancestral 调度器(
euler_ancestral_discrete::EulerAncestralDiscreteSchedulerConfig),并配合timestep_spacing = Trailing的时间步划分,与 Turbo 蒸馏模型的训练设置保持一致。
调度器在代码层面被抽象为SchedulerConfig/Scheduler两个 trait(schedulers.rs),接口包括timesteps()(生成时间步序列)、add_noise()(向潜变量加噪)、init_noise_sigma()(初始噪声标准差)、scale_model_input()(缩放模型输入)与step()(单步去噪)。主循环在 main.rs 中按序调用:先scheduler.scale_model_input归一化输入,UNet 前向预测噪声,再按guidance_scale对条件/无条件两支预测做加权融合,最后scheduler.step更新潜变量,如此往复直到所有时间步完成。
使用 flash-attention 加速
自注意力在扩散模型中计算量占比很高,启用 flash-attention 可以显著提速并降低显存占用,代价是编译时间较长。需要同时满足两个条件(缺一不可):
- 特性开关:编译时加
--features flash-attn(该特性在 candle-examples/Cargo.toml 中定义为["cuda", "candle-transformers/flash-attn", "dep:candle-flash-attn"],即依赖candle-flash-attn这个 CUDA kernel 库); - 运行时开关:命令行加
--use-flash-attn。
cargo run --example stable-diffusion --release --features=cuda,cudnn,flash-attn \ -- --prompt "a cosmonaut on a horse (hd, realistic, high-def)" --use-flash-attn由于 flash-attention 内核需要针对不同 head 维度与精度编译大量 CUDA 变体(可在 candle-flash-attn/kernels/ 中看到按hdim、fp16/bf16、causal组合生成的众多.cu文件),建议设置环境变量CANDLE_FLASH_ATTN_BUILD_DIR指向固定目录以缓存编译产物,避免每次重新编译:
export CANDLE_FLASH_ATTN_BUILD_DIR=/home/user/.candle硬件前提:flash-attention-v2 仅兼容 Ampere、Ada 或 Hopper 架构的 NVIDIA GPU(如 A100/H100、RTX 3090/4090),旧架构无法使用。
图像到图像(img2img)与局部重绘(Inpainting)
README 中"Image to Image Pipeline"一节标记为占位内容,但对应能力已在 main.rs 中完整实现,这里结合源码补充说明:
img2img:基于输入图像生成变体
通过--img2img <图片路径>传入初始图像,程序会执行image_preprocess:先将宽高向下取整到 32 的倍数,用 CatmullRom 滤波缩放,再归一化到[-1, 1]并转为[1, 3, H, W]张量(main.rs),随后用 VAE 编码为初始潜变量。
--img2img-strength(取值 0~1,默认 0.8)控制对原图的保留程度:值越大变换越剧烈,为 1 时完全丢弃原图信息、退化为纯文生图。从源码看,强度通过跳过去噪前若干步实现:t_start = n_steps - (n_steps * strength) as usize(main.rs),并在起始步按对应时间步为初始潜变量添加噪声(scheduler.add_noise)。
cargo run --example stable-diffusion --release --features=cuda,cudnn \ -- --prompt "a cosmonaut on a horse" --img2img input.png --img2img-strength 0.8Inpainting:蒙版区域重绘
选择 inpainting 版本(v1-5-inpaint等)时必须同时提供--mask-path <蒙版图>和--img2img <原图>(源码中分别报错提示缺失)。流程(main.rs)为:
mask_preprocess把蒙版转为单通道灰度张量,白/黑分别表示"待重绘/保留"区域;- 用蒙版遮罩原图得到
masked_img,经 VAE 编码为mask_latents; - UNet 输入通道数从 4 扩为 9(潜变量、蒙版、蒙版潜变量拼接,见
in_channels = 9的分支); - 去噪结束后,若加了
--only-update-masked,则只把蒙版区域之外的像素还原为原图潜变量(latents * mask + latent_to_keep * (1-mask)),保证背景不变化。
常见问题:内存与显存优化
官方 FAQ 明确指出:默认配置(v2-1 768×768)需要超过 8GB 显存的 GPU。显存不足时可按优先级采取以下措施:
- 缩小分辨率:
--height/--width调小可显著降低显存占用,注意必须是 8 的倍数(源码断言强制约束); - 切分注意力:
--sliced-attention-size <N>将大尺寸注意力切成小块计算,是显存受限场景的有效手段; - 半精度:
--use-f16使用 FP16 权重与计算,显存占用接近减半(SDXL 会自动搭配 FP16 修复版 VAE); - 启用 flash-attention:
--use-flash-attn在提速的同时降低显存峰值(前提是 Ampere 及以上 GPU); - 最后兜底:
--cpu用 CPU 推理,速度显著变慢但无需 GPU。
另外,使用--seed可固定随机种子复现同一结果;主程序在未指定种子时也会打印所用种子,便于事后追溯。若开启--tracing,可结合 Chrome 的chrome://tracing对 UNet 各阶段耗时做性能分析。
小结
candle-stable-diffusion是理解"如何用纯 Rust 实现现代扩散模型推理"的最佳切入点:从 README 的启动命令出发,到 main.rs 的完整管线,再到 candle-transformers/src/models/stable_diffusion/ 的模型实现,整个链路清晰可读。它既可作为开箱即用的文生图工具,也可作为基于 Candle 二次开发扩散应用的参考模板——无论是替换调度器、接入新的模型仓库,还是移植 img2img / inpainting 能力到自有管线,都能从这套代码中直接获得实现路径。
- 人工智能
- 大模型
- 机器学习
- 深度学习
- 本地部署
- 模型推理服务
【免费下载链接】candle
Minimalist ML framework for Rust
相关推荐
device-year-class社区贡献指南:参与开源项目的完整流程
device year class社区贡献指南:参与开源项目的完整流程 device year class是一个Android库,它通过分析设备的规格(如RAM
人工智能AI 应用AI 技能/插件AI Agent金融科技在Docker中流畅运行:Stable Diffusion实践指南
在Docker中流畅运行:Stable Diffusion实践指南 项目核心价值 Stable Diffusion in Docker是一个革命性的解决方案,让
如何在Mac上原生运行Stable Diffusion:Mochi Diffusion完整指南
如何在Mac上原生运行Stable Diffusion:Mochi Diffusion完整指南 Mochi Diffusion是一款专为Apple Silico
人工智能AI 应用媒体生成本地部署
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考