SD3.5 Medium模型端侧部署

SD3.5 Medium QNN 端侧推理使用指南

本项目基于 ai-engine-direct-helper (QAI_AppBuilder)
                  https://github.com/quic/ai-engine-direct-helper.git

模型下载地址 (包含对应的上下文二进制文件)
                  https://www.aidevhome.com/?id=51



第一部分:Windows PC 平台使用

本部分介绍如何在 Windows Snapdragon X Elite 平台上,通过 qai_appbuilder全流程 in-process HTP 方案 运行 SD3.5 Medium 图像生成

1.1 压缩包内容

sd3.5_qnn_for_windows-8380/
├── sd3.5_medium_pc.py                              # PC 推理入口脚本
├── qai_appbuilder-2.38.0-cp312-cp312-win_amd64.whl # qai_appbuilder 安装包
├── time_text_embed.pt                              # timestep 嵌入权重 (~32 MB)
├── requirements.txt                                # Python 依赖
├── README.md / README_PC.md
├── libs/                                           # QNN 运行时库(已包含,无需额外下载)
│   ├── QnnHtp.dll                                    HTP 后端
│   ├── QnnHtpPrepare.dll                             HTP 预处理
│   ├── QnnHtpV73Stub.dll                             v73 DSP stub
│   ├── QnnHtpNetRunExtensions.dll                    运行扩展
│   ├── QnnSystem.dll                                 系统库
│   ├── Genie.dll
│   └── ...                                           其他运行时文件
├── serialized_binaries/                            # QNN 模型文件
│   ├── text_encoder.serialized.bin                 (~238 MB)  CLIP-L 文本编码器
│   ├── text_encoder_2.serialized.bin               (~1.4 GB)  CLIP-G 文本编码器
│   ├── transformer.serialized.bin                  (~2.3 GB)  MMDiT 去噪网络
│   └── vae_decoder.serialized.bin                  (~102 MB)  VAE 解码器
├── tokenizer/                                      # CLIP-L tokenizer
│   ├── vocab.json
│   ├── merges.txt
│   ├── special_tokens_map.json
│   └── tokenizer_config.json
└── tokenizer_2/                                    # CLIP-G tokenizer
    ├── vocab.json
    ├── merges.txt
    ├── special_tokens_map.json
    └── tokenizer_config.json
💡 路径自动适配:    sd3.5_medium_pc.py 同时兼容两种目录结构:
  • 扁平结构(新版默认):serialized_binaries/tokenizer/libs/ 等直接位于脚本同级目录。

  • 注意:总大小约 4.6 GB(含模型权重文件和 QNN 运行时库)。

1.2 环境要求

  • 硬件:Windows Snapdragon X Elite(HTP v73)或更高

  • 内存:建议 32GB RAM(transformer 模型约 2.3GB,加载到 HTP 上下文中)

  • Python:3.12 (x86_64 emulated on ARM64)

  • QNN Libs:已包含在压缩包中,脚本会自动定位无需手动配置

1.3 资源下载与准备

  1. 下载模型文件:

     SD3.5 Medium 骁龙 X Elite 平台(8380)模型下载 

    将下载的压缩包解压到工作目录下。压缩包已包含所需的 QNN 运行时库(libs/ 目录),无需额外下载。

1.4 安装依赖

① 创建虚拟环境(推荐):

python -m venv venv
venv\Scripts\activate

② 安装 qai_appbuilder:压缩包中已包含 qai_appbuilder 的预编译安装包,直接安装即可:

pip install qai_appbuilder-2.38.0-cp312-cp312-win_amd64.whl
⚠ 注意:qai_appbuilder 目前仅提供预编译 whl 包,不在 PyPI 上发布。
  • cp312-win_amd64:适用于 Python 3.12 + Windows x86_64(ARM64 平台上通过模拟运行)

  • 如使用其他 Python 版本或架构,需使用对应的 whl 文件

③ 安装其他 Python 依赖:使用压缩包中的 requirements.txt

pip install -i https://mirrors.aliyun.com/pypi/simple/ -r requirements.txt

requirements.txt 内容:

torch>=2.4.1
transformers>=4.44.0
diffusers==0.34.0
Pillow>=9.0.0
numpy>=1.24.0

1.5 QNN Libs 说明

QNN 运行时库已包含在压缩包的 libs/ 目录中,脚本会自动检测使用,无需手动配置路径。脚本的查找顺序为:

  1. 优先尝试 <脚本目录>/models/libs(带 models/ 子目录的旧版结构)

  2. 未找到则使用 <脚本目录>/libs(扁平结构 / 新版默认)

libs/ 目录包含以下关键文件:

  • QnnHtp.dll — HTP 后端库(推理核心)

  • QnnHtpPrepare.dll — HTP 预处理

  • QnnHtpV73Stub.dll — v73 DSP stub

  • QnnHtpNetRunExtensions.dll — 运行时扩展

  • QnnSystem.dll — 系统库

  • Genie.dll — Genie 框架库

1.6 运行推理

基本用法:

python sd3.5_medium_pc.py --prompt "A cat holding a sign that says hello world"

完整参数示例:

python sd3.5_medium_pc.py ^
  --prompt "A beautiful sunset over the ocean" ^
  --negative_prompt "blurry, low quality" ^
  --steps 20 ^
  --cfg 3.5 ^
  --seed 42 ^
  --output output.png

参数说明:

参数默认值说明
--prompt"A cat..."正向提示词
--negative_prompt""负向提示词
--steps20去噪步数(5 步快速测试,20 步高质量)
--cfg3.5CFG 引导强度
--seed42随机种子(相同种子 = 可复现结果)
--outputoutput.png输出图片路径

1.7 推理流程如下:

1. [CPU] 加载 tokenizer + time_text_embed 权重 + scheduler
2. [一次性] 通过 qai_appbuilder 加载 4 个 QNN 模型到 HTP 上下文
   (text_encoder / text_encoder_2 / vae_decoder / transformer)
3. [NPU] CLIP-L + CLIP-G 文本编码(正向 + 负向 prompt)
4. [CPU] 初始化随机 latent 噪声
5. [循环 N 步去噪]:
   a. [CPU] 计算时间步嵌入 (temb)
   b. [NPU] transformer 条件推理 → 噪声预测
   c. [NPU] transformer 无条件推理 → 噪声预测
   d. [CPU] CFG 合并 + 调度器更新 latent
6. [NPU] VAE 解码 → 像素图像
7. [CPU] 后处理 → 保存 PNG (1024×1024)


第二部分:Android 平台使用

本部分介绍如何通过 Host PC + Android 设备 协作完成 SD3.5 Medium 图像生成:

  • Host PC(Linux/Windows):负责 tokenizer 编解码、调度器计算、前后处理

  • Android 设备 NPU:通过 ADB 调用 qnn-net-run简单推理,执行 4 个 QNN 模型推理

支持两个平台版本:

版本DSP 架构SOC ID芯片平台
GEN4V7969Snapdragon (Sun)
GEN5V8187Snapdragon 8 Elite

2.1 压缩包内容

  SD3.5 Medium骁龙 8 至尊版平台 (8750) 模型下载 

 SD3.5 Medium第五代骁龙 8 至尊版平台 (8850) 模型下载

sd3.5/
├── sd3.5_medium_inference_android.py   # 推理入口脚本
├── qnn-net-run                         # QNN CLI 推理工具 (aarch64-android)
├── time_text_embed.pt                  # 时间嵌入权重 (~32MB)
├── htp_config.json                     # HTP 配置参考
├── htp_backend.json                    # HTP 后端配置参考
├── libs/                               # QNN 运行时库 (~300MB, 约71个 .so)
│   ├── libQnnHtp.so
│   ├── libQnnHtpV79Stub.so             # GEN4: V79 / GEN5: V81
│   ├── libQnnHtpV79CalculatorStub.so
│   ├── libQnnHtpV79Skel.so
│   ├── libQnnSystem.so
│   └── ... (其他 QNN .so 库)
├── serialized_binaries/                # GEN4 用 "serialized_binaries/"
│   │                                   # GEN5 用 "serialized_binaries_gen5/"
│   ├── text_encoder.serialized.bin     ~238MB
│   ├── text_encoder_2.serialized.bin   ~1.4GB
│   ├── transformer.serialized.bin      ~2.3GB
│   └── vae_decoder.serialized.bin      ~105MB
├── tokenizer/                          # CLIP tokenizer 文件
└── tokenizer_2/                        # CLIP tokenizer_2 文件

注意:总大小约 4.3GB(主要是模型权重文件)。

2.2 环境准备

安装 ADB:

# Ubuntu / Debian
sudo apt install android-tools-adb

# 验证安装
adb version

创建 Python 虚拟环境并安装依赖:

# 创建虚拟环境
python3 -m venv sd35_env
source sd35_env/bin/activate    # Linux / macOS
# sd35_env\Scripts\activate     # Windows

# 安装依赖
pip install -i https://mirrors.aliyun.com/pypi/simple/ torch transformers diffusers Pillow numpy

2.3 连接设备

# 连接设备后验证
adb devices
# 输出示例:
# List of devices attached
# 24e74add    device      ← 设备已连接

# 多设备场景:指定目标设备
export ANDROID_SERIAL=24e74add

确保设备状态显示为 device(不是 unauthorizedoffline)。

2.4 首次运行(含设备初始化)

首次运行需要加 --setup 参数,脚本会自动将库和模型推送到设备 /data/local/tmp/sd35/

# 激活虚拟环境
source sd35_env/bin/activate

# 进入工作目录
cd sd3.5_qnn_for_android_gen4/sd3.5/    # GEN4
# cd sd3.5_qnn_for_android_gen5/sd3.5/  # GEN5

# 首次运行(推送文件 + 推理)
python sd3.5_medium_inference_android.py \
    --setup \
    --prompt "A cat holding a sign that says hello world"
⚠ 首次推送耗时:约 5-10 分钟(需推送约 4GB 文件到设备)。推送完成后,脚本会自动开始推理流程。

2.5 日常使用(后续推理)

首次设置完成后,无需再加 --setup

# 基本用法
python sd3.5_medium_inference_android.py --prompt "A beautiful sunset over the ocean"

# 指定步数和种子
python sd3.5_medium_inference_android.py \
    --prompt "A futuristic city at night" \
    --steps 30 \
    --seed 123 \
    --output future_city.png

# 使用负向提示词
python sd3.5_medium_inference_android.py \
    --prompt "Portrait of a woman, oil painting style" \
    --negative_prompt "blurry, low quality, distorted" \
    --guidance_scale 5.0

# 强制重新推送文件到设备
python sd3.5_medium_inference_android.py \
    --force_setup \
    --prompt "测试提示词"

完整参数列表:

参数默认值说明
--prompt"A cat..."正向提示词
--negative_prompt""负向提示词
--steps20去噪步数
--guidance_scale3.5CFG 引导强度
--seed42随机种子
--output"output.png"输出图片路径
--setupFalse首次运行,推送文件到设备
--force_setupFalse强制重新推送所有文件
--model_dir"."tokenizer 所在目录
--bins_dir"serialized_binaries"模型 bin 文件目录
--device_base"/data/local/tmp/sd35"设备端工作目录

2.6 集成Apk说明

 整体的编译后端库流程请查看项目代码ai-engine-direct-helper-main\samples\android


模型调用推理

Java_com_example_DDColor_MainActivity_DDColor(...) {
    float* inputBuffer = (float*)env->GetDirectBufferAddress(j_inputBuffer);
    float* outputBuffer = (float*)env->GetDirectBufferAddress(j_outputBuffer);
    // 1. 指定后端 (例如:libQnnHtp.so 表示在DSP上运行)
    std::string backend_lib_path = libs_dir + "/libQnnHtp.so";
    std::string system_lib_path = libs_dir + "/libQnnSystem.so";
   
    // 2. 初始化模型
    libAppBuilder.ModelInitialize(MODEL_NAME, model_path, backend_lib_path, ...);
    // 3. 执行推理
    libAppBuilder.ModelInference(MODEL_NAME, ...);
    // 4. 拷贝结果
    memcpy(outputBuffer, outputBuffers.at(0), outputSize[0]);
   
    // ... 释放资源 ...
    return 0;
}