news 2026/8/13 8:38:28

stable-diffusion.cpp 的 FLUX.2 Klein 9B 分步

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
stable-diffusion.cpp 的 FLUX.2 Klein 9B 分步

核心理念

2026/7/7

每次仅加载一个模型,中间结果暂存于系统内存,最终输出才写入磁盘。
与 ComfyUI / sd-cli 一次性加载所有模型的策略不同,分步管线确保每一步骤可独占全部资源(尤其是显存)。


架构图

text

Step 1 Step 2 Step 3 ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ 加载 Qwen3 │ │ 加载 DiT │ │ 加载 VAE │ │ text encoder│ │ diffusion │ │ decode │ │ │ │ │ │ │ │ prompt ─────→│ cond │ cond ───────→│ latent │ latent ─────→│ img │ (CPU 5GB) │ float[] │ (GPU 3-4GB) │ float[] │ (GPU 0.5GB) │ png │ │ │ │ │ │ │ ↓ 释放 Qwen3 │ │ ↓ 释放 DiT │ │ ↓ 释放 VAE │ │ VRAM: 0 │ │ VRAM: 0 │ │ 写磁盘完成 │ └──────────────┘ └──────────────┘ └──────────────┘ 内存中传递: cond (float array) → latent (float array) → image (sd_image_t)

具体改动:给 DLL 加三个导出函数

1. sd_encode_condition — 只跑文本编码

将 prompt 编码为 conditioning tensor,并以平铺的 float 数组返回。

c

SD_API bool sd_encode_condition( sd_ctx_t* sd_ctx, const char* prompt, const char* negative_prompt, const sd_lora_t* loras, int lora_count, float** cond_data, // 输出:condition float 数组(调用者 free) int64_t* cond_size // 输出:数组元素个数 );
  • 需要暴露StableDiffusionGGML::get_learned_condition()(原私有方法)。

  • cond_data包含c_crossattn+c_vector+c_concat的序列化拼接。

  • 返回后调用者需调用free_sd_ctx()释放 Qwen3 模型。

2. sd_sample — 只跑采样

输入 condition,输出 latent。

c

SD_API bool sd_sample( sd_ctx_t* sd_ctx, const float* cond_data, int64_t cond_size, int width, int height, int steps, float cfg_scale, int64_t seed, float** latent_data, // 输出:latent float 数组 int64_t* latent_size );
  • 需要暴露StableDiffusionGGML::sample()(原私有方法)。

  • 内部反序列化cond_data还原为SDCondition结构。

  • latent_data为采样结果(例如 FLUX.2 的 latent 尺寸为 64×64×16)。

  • 可通过--backend diffusion=vulkan1指定后端。

3. sd_decode_latent — 只跑 VAE 解码

输入 latent,输出最终图像。

c

SD_API sd_image_t sd_decode_latent( sd_ctx_t* sd_ctx, const float* latent_data, int64_t latent_size );
  • 需要暴露StableDiffusionGGML::decode_first_stage()(原私有方法)。

  • 可通过--backend vae=vulkan1让 VAE 在 GPU 上运行(模型仅 164 MB)。


调用方主程序逻辑

text

1. 创建 sd_ctx,仅传入 --llm(Qwen3),其余路径置空 sd_ctx_params.llm_path = "flux2-klein-9b-uncensored-q4_k_m.gguf" sd_ctx_params.diffusion_model_path = NULL sd_ctx_params.vae_path = NULL ctx = new_sd_ctx(&params) 2. sd_encode_condition(ctx, prompt, loras, &cond_data, &cond_size) 此时 cond_data 为内存中的 float 数组 3. free_sd_ctx(ctx) // Qwen3 完全释放,显存归零 4. 新建 sd_ctx,仅传入 --diffusion-model(DiT) sd_ctx_params.diffusion_model_path = "flux-2-klein-9b-Q4_0.gguf" sd_ctx_params.llm_path = NULL sd_ctx_params.backend = "diffusion=vulkan1" ctx = new_sd_ctx(&params) 5. sd_sample(ctx, cond_data, cond_size, 512, 512, 4, 1.0, 42, &latent_data, &latent_size) 此时 latent_data 存于内存中 6. free(cond_data) // 释放 condition free_sd_ctx(ctx) // DiT 完全释放,显存归零 7. 新建 sd_ctx,仅传入 --vae sd_ctx_params.vae_path = "flux2-vae.safetensors" sd_ctx_params.backend = "vae=vulkan1" ctx = new_sd_ctx(&params) 8. img = sd_decode_latent(ctx, latent_data, latent_size) stbi_write_png("output.png", img) 9. free(latent_data) free_sd_images(&img, 1) free_sd_ctx(ctx) // VAE 释放

每步内存占用

步骤加载模型大小VRAMRAM备注
1Qwen3 文本编码器5.0 GB0 GB5.0 GBCPU 推理,不占显存
释放0 GB0 GB回归零
2DiT (Q4_0)5.3 GB~3 GB0 GB权重 offload 至 GPU
释放0 GB0 GB回归零
3VAE164 MB<0.5 GB0 GB全量置于 GPU

总 VRAM 峰值:~3 GB(远低于 RX 580 的 8 GB 上限)


对 img2img / inpainting 的支持

在 Step 1 与 Step 2 之间插入一步即可:

text

Step 1.5: VAE 编码原图 加载 VAE(可复用 Step 3 逻辑) 原图 → VAE encode → init_latent(内存 float[]) 随后 Step 2 的 sd_sample 接收 init_latent + cond 作为输入

此额外步骤耗时约 3~5 秒(VAE 编码走 GPU)。


编译方法

bash

git clone https://github.com/leejet/stable-diffusion.cpp cd stable-diffusion.cpp mkdir build && cd build cmake .. -DGGML_VULKAN=ON -DCMAKE_BUILD_TYPE=Release cmake --build . --config Release

编译产出:

  • build/bin/Release/stable-diffusion.dll→ 替换D:\files\FLUX.2\

  • 自行编译调用方 exe,链接该 DLL


需要修改的源文件

文件改动
include/stable-diffusion.h增加 3 个SD_API函数声明
src/stable-diffusion.cpp实现这 3 个函数,调用内部私有方法
src/stable-diffusion.h(内部)encode_first_stage()sample()decode_first_stage()设为 public 或添加 public wrapper

与 ComfyUI / sd-cli 对比

ComfyUIsd-cli 一次加载本方案
模型加载方式全加载全加载分步加载
中间结果显存常驻显存常驻内存 float array
VRAM 峰值高(~6-7 GB)中(~3 GB)低(~3 GB)
img2img 额外开销小(均在显存)小(均在显存)略大(多一次 VAE 加载)
跨 prompt 复用 condition节点缓存不支持代码层手动缓存
控制粒度节点级CLI 参数级函数调用级
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/13 8:37:44

嵌入式安全基石:国民技术芯片UID/UCID获取与应用实践

1. 项目概述&#xff1a;从“查成分”到芯片安全 最近在B站、微博这些社区里&#xff0c;“查成分”这个词挺火的&#xff0c;简单说就是通过用户的UID&#xff08;用户唯一标识&#xff09;去翻看他的历史发言、关注列表&#xff0c;来判断这是个“自己人”还是“乐子人”。这…

作者头像 李华
网站建设 2026/8/13 8:35:15

Python爬虫实战:Fiddler抓包解析微信公众号历史文章数据

1. 项目缘起&#xff1a;一个被“历史数据”困扰的日常需求做内容运营或者自媒体分析的朋友&#xff0c;估计都遇到过这个头疼事&#xff1a;想回顾一下自己公众号过去几年的数据表现&#xff0c;看看哪篇文章爆了&#xff0c;哪个话题凉了&#xff0c;用户增长曲线是怎么走的。…

作者头像 李华
网站建设 2026/8/13 8:34:46

《波比的游戏时间》原型体1006:恐怖游戏终极Boss设计与叙事解析

最近&#xff0c;游戏圈里有个名字反复被提起&#xff1a; 波比 。如果你关注过《波比的游戏时间》系列&#xff0c;或者被那些“玩具工厂惊魂”的短视频刷过屏&#xff0c;那你一定知道&#xff0c;这个看似可爱的蓝色毛绒玩具&#xff0c;背后藏着的是让无数玩家手心冒汗的…

作者头像 李华
网站建设 2026/8/13 8:34:43

AI辅助数学研究实战:基于Claude构建黎曼ζ函数零点搜索系统

最近在尝试将 Claude 等大语言模型应用于数学研究&#xff0c;特别是像黎曼猜想这样的经典难题时&#xff0c;发现了一个普遍痛点&#xff1a;网上资料要么是纯数学理论&#xff0c;要么是简单的 API 调用&#xff0c;缺少一个将前沿 AI 工具与严肃数学研究相结合的、可实操的工…

作者头像 李华
网站建设 2026/8/13 8:32:55

3分钟掌握安卓投屏神器:QtScrcpy跨屏协作终极指南

3分钟掌握安卓投屏神器&#xff1a;QtScrcpy跨屏协作终极指南 【免费下载链接】QtScrcpy Android real-time display control software 项目地址: https://gitcode.com/GitHub_Trending/qt/QtScrcpy 还在为手机屏幕太小而烦恼吗&#xff1f;想要在电脑上流畅操控安卓设备…

作者头像 李华
网站建设 2026/8/13 8:31:10

统信UOS ARM宿主机部署银河麒麟V10 ARM虚拟机全攻略

1. 项目缘起&#xff1a;为何要在统信UOS ARM上跑麒麟V10 ARM虚拟机&#xff1f; 最近在折腾国产化软硬件环境&#xff0c;手头有一台基于飞腾或鲲鹏处理器的ARM架构主机&#xff0c;预装了统信UOS桌面版。有个需求挺有意思&#xff1a;需要在UOS系统里&#xff0c;再安装一个银…

作者头像 李华