159 lines
6.8 KiB
C++
159 lines
6.8 KiB
C++
//
|
||
// sana_diffusion_demo.cpp
|
||
//
|
||
// Sana Diffusion 演示程序
|
||
//
|
||
// 展示如何使用Sana模型进行文生图和图像编辑:
|
||
// 1. 使用Qwen3-0.6B LLM处理文本prompt
|
||
// 2. 通过Connector和Projector桥接特征
|
||
// 3. 使用DiT Transformer进行去噪生成
|
||
// 4. VAE解码得到最终图像
|
||
//
|
||
|
||
#include <iostream>
|
||
#include "diffusion/diffusion.hpp"
|
||
#include "diffusion/sana_llm.hpp"
|
||
#define MNN_OPEN_TIME_TRACE
|
||
#include <MNN/AutoTime.hpp>
|
||
#include <MNN/expr/ExecutorScope.hpp>
|
||
|
||
using namespace MNN::DIFFUSION;
|
||
using namespace MNN::Express;
|
||
|
||
int main(int argc, const char* argv[]) {
|
||
if (argc < 3) {
|
||
MNN_PRINT("=====================================================================================================================\n");
|
||
MNN_PRINT("Sana Diffusion Demo - 基于Qwen3-0.6B的高效文生图模型\n");
|
||
MNN_PRINT("=====================================================================================================================\n");
|
||
MNN_PRINT("Usage: ./sana_diffusion_demo <resource_path> <mode> <prompt> [input_image] [output_image] [width] [height] [steps] [seed] [use_cfg] [cfg_scale]\n");
|
||
MNN_PRINT("\n");
|
||
MNN_PRINT("参数说明:\n");
|
||
MNN_PRINT(" resource_path : 模型资源路径(包含llm/connector/projector/transformer/vae等模型)\n");
|
||
MNN_PRINT(" mode : 'text2img' 文生图模式, 'img2img' 图像编辑模式\n");
|
||
MNN_PRINT(" prompt : 文本描述(支持复杂语义,由Qwen3-0.6B处理)\n");
|
||
MNN_PRINT(" input_image : 输入图像路径(img2img模式必需,text2img模式忽略,默认: \"\")\n");
|
||
MNN_PRINT(" output_image : 输出图像路径(默认: sana_out.jpg)\n");
|
||
MNN_PRINT(" width : 输出图像宽度(默认: 512,必须是32的倍数)\n");
|
||
MNN_PRINT(" height : 输出图像高度(默认: 512,必须是32的倍数)\n");
|
||
MNN_PRINT(" steps : 推理步数(默认: 5,通过蒸馏可用较少步数获得高质量)\n");
|
||
MNN_PRINT(" seed : 随机种子(默认: 42)\n");
|
||
MNN_PRINT(" use_cfg : 是否使用CFG引导, 0或1(默认: 0)\n");
|
||
MNN_PRINT(" cfg_scale : CFG引导强度(默认: 4.5,仅use_cfg=1时生效)\n");
|
||
MNN_PRINT("\n");
|
||
MNN_PRINT("示例:\n");
|
||
MNN_PRINT(" 文生图(512x512): ./sana_diffusion_demo models text2img \"一只可爱的猫咪\" \"\" output.jpg 512 512 5 42 1 4.5\n");
|
||
MNN_PRINT(" 文生图(1024x1024): ./sana_diffusion_demo models text2img \"一只可爱的猫咪\" \"\" output.jpg 1024 1024 5 42 1 4.5\n");
|
||
MNN_PRINT(" 图像编辑: ./sana_diffusion_demo models img2img \"添加彩虹\" input.jpg output.jpg 512 512 5 42 0 4.5\n");
|
||
MNN_PRINT("=====================================================================================================================\n");
|
||
return 0;
|
||
}
|
||
|
||
std::string resource_path = argv[1];
|
||
std::string mode = argv[2];
|
||
std::string prompt = argv[3];
|
||
std::string image_path = (argc > 4) ? argv[4] : "";
|
||
std::string output_name = (argc > 5) ? argv[5] : "sana_out.jpg";
|
||
int width = (argc > 6) ? atoi(argv[6]) : 512;
|
||
int height = (argc > 7) ? atoi(argv[7]) : 512;
|
||
int steps = (argc > 8) ? atoi(argv[8]) : 5;
|
||
int seed = (argc > 9) ? atoi(argv[9]) : 42;
|
||
bool use_cfg = (argc > 10) ? (atoi(argv[10]) != 0) : false;
|
||
float cfg_scale = (argc > 11) ? atof(argv[11]) : 4.5f;
|
||
|
||
int memory_mode = 2; // standard,0:卸载
|
||
int backend_type = MNN_FORWARD_CPU;
|
||
|
||
// 验证mode参数
|
||
if (mode != "text2img" && mode != "img2img") {
|
||
MNN_ERROR("Error: mode must be 'text2img' or 'img2img'\n");
|
||
return -1;
|
||
}
|
||
|
||
// 验证img2img模式需要输入图像
|
||
if (mode == "img2img" && image_path.empty()) {
|
||
MNN_ERROR("Error: img2img mode requires input image path\n");
|
||
return -1;
|
||
}
|
||
|
||
MNN_PRINT("\n========== 配置信息 ==========\n");
|
||
MNN_PRINT("模式: %s\n", mode.c_str());
|
||
MNN_PRINT("提示词: %s\n", prompt.c_str());
|
||
if (mode == "img2img") {
|
||
MNN_PRINT("输入图像: %s\n", image_path.c_str());
|
||
}
|
||
MNN_PRINT("输出图像: %s\n", output_name.c_str());
|
||
MNN_PRINT("输出分辨率: %dx%d\n", width, height);
|
||
MNN_PRINT("推理步数: %d \n", steps);
|
||
MNN_PRINT("随机种子: %d\n", seed);
|
||
MNN_PRINT("使用CFG: %s\n", use_cfg ? "是" : "否");
|
||
if (use_cfg) {
|
||
MNN_PRINT("CFG强度: %.2f\n", cfg_scale);
|
||
}
|
||
MNN_PRINT("==============================\n\n");
|
||
|
||
// ========== 步骤1: 初始化Qwen3-0.6B LLM ==========
|
||
MNN_PRINT("[1/4] 初始化Qwen3-0.6B LLM(文本编码器)...\n");
|
||
std::string llm_path = resource_path + "/llm/";
|
||
SanaLlm sana_llm(llm_path);
|
||
|
||
// ========== 步骤2: 初始化Diffusion模型 ==========
|
||
MNN_PRINT("[2/4] 初始化Diffusion模型(Connector + Projector + DiT + VAE)...\n");
|
||
std::unique_ptr<Diffusion> diffusion(Diffusion::createDiffusion(
|
||
resource_path,
|
||
SANA_DIFFUSION,
|
||
(MNNForwardType)backend_type,
|
||
memory_mode
|
||
));
|
||
diffusion->load();
|
||
|
||
// ========== 步骤3: LLM处理文本 ==========
|
||
MNN_PRINT("[3/4] LLM处理文本prompt...\n");
|
||
VARP llm_out;
|
||
|
||
if (use_cfg) {
|
||
// CFG模式:同时生成正负样本特征(batch_size=2)
|
||
MNN_PRINT(" CFG模式:生成正负样本特征\n");
|
||
llm_out = sana_llm.process(prompt, true, "");
|
||
} else {
|
||
// 非CFG模式:只生成正样本特征(batch_size=1)
|
||
MNN_PRINT(" 非CFG模式:生成单一特征\n");
|
||
llm_out = sana_llm.process(prompt, false);
|
||
}
|
||
|
||
if (llm_out.get() == nullptr) {
|
||
MNN_ERROR("LLM处理失败\n");
|
||
return -1;
|
||
}
|
||
|
||
// ========== 步骤4: Diffusion生成图像 ==========
|
||
MNN_PRINT("[4/4] Diffusion生成图像...\n");
|
||
auto progress = [](int p) {
|
||
std::cout << " 生成进度: " << p << "%\r" << std::flush;
|
||
};
|
||
|
||
bool success = diffusion->run(
|
||
llm_out, // LLM特征(来自Qwen3-0.6B)
|
||
mode, // 模式:text2img或img2img
|
||
image_path, // 输入图像(img2img模式)
|
||
output_name, // 输出路径
|
||
width, // 输出宽度
|
||
height, // 输出高度
|
||
steps, // 推理步数(蒸馏加速)
|
||
seed, // 随机种子
|
||
use_cfg, // 是否使用CFG
|
||
cfg_scale, // CFG强度
|
||
progress // 进度回调
|
||
);
|
||
|
||
if (success) {
|
||
MNN_PRINT("\n\n========== 生成完成 ==========\n");
|
||
MNN_PRINT("✓ 图像已保存至: %s\n", output_name.c_str());
|
||
MNN_PRINT("==============================\n");
|
||
} else {
|
||
MNN_ERROR("\n生成失败\n");
|
||
return -1;
|
||
}
|
||
|
||
return 0;
|
||
}
|