SenseNova-U1.5 部署实战

相关链接

关联GitHub Issues

系列目录

章节 内容 状态
第一章 SenseNova 介绍:原生统一范式、NEO-unify 与 MoT、U1.5 能力全景 ✅ 本篇
第二章 单卡 NVIDIA RTX 4090D 部署与踩坑:驱动泥潭、显存腾挪、8 步蒸馏、服务化 ✅ 本篇
第三章 AMD ROCm 部署实战 ✅ 本篇
第四章 国产GPU摩尔线程MTT S4000部署实战 ✅ 本篇
第五章 SenseNova-U1 在低资源本机(8GB 显存 + 16GB 内存)上的部署与运行指南 ✅ 本篇
第六章 华为Ascend部署案例,单卡910B部署与踩坑 ✅ 本篇
第七章 RTX Pro 6000(Blackwell)部署实战 🚧 待补
第八章 寒武纪MLU部署SenseNova 🚧 待补
第九章 海光信息DCU K100部署SenseNova 🚧 待补
第十章 壁仞科技BR100部署SenseNova 🚧 待补
第十一章 沐曦C500部署SenseNova 🚧 待补
第十二章 华为Ascend950DT部署SenseNova 🚧 待补
第十三章 上古老卡部署SenseNova测试验证(NVIDIA V100 / AMD MI50) 🚧 待补

Ascend910B视频演示:

9月4日

这篇文章记录我把 SenseNova-U1.5-8B-MoT 装进一张 4090 D 以及AMD,Moorethreads,Ascend-NPU等案例的完整过程:在4090D,驱动内核 7.0 上的编译泥潭、35.1 GB 权重与 24 GB 显存之间的腾挪、官方 8 步蒸馏 LoRA 的加速实测,以及 FastAPI 服务化封装。

  • 结论先行:SenseNova-U1.5-8B-MoT 的 BF16 权重实际是 17.53B 参数 / 35.1 GB(理解 8.12B + 生成 8.17B + 共享 1.25B),24 GB 显存装不下全量权重。官方 --vram_mode 卸载会把全部权重钉进锁页内存,32 GB 内存主机必 OOM;改用 --device_map 分片加载路线(第 2.9 节)把权重切到 GPU+CPU,峰值显存压到 ~20.5 GiB,单卡 4090 D 稳定出图——这也是本文全部实测数据的口径。

  • 8 步蒸馏 LoRA 真香:加载 814 MB 的 SenseNova-U1.5-8B-MoT-LoRA-8step,采样从 50 步降到 8 步、CFG 从 4.0 降到 1.0,同 Prompt 同 Seed 下 2048×2048 端到端从 178.0 s 降到 26.7 s,画质损失可控(对比图见第 2.7 节)。

  • 附可复用模板:一份 FastAPI + systemd 的 API 封装(第 2.10 节)、部署机防休眠配置(第 2.1 节)、低显存档位速查表(第 2.9 节),可直接抄作业。


第一章 SenseNova 介绍

1.1 从「模态拼装」到「原生统一」

近两年主流的多模态方案是「拼装」路线:大语言模型外挂视觉编码器(VE)做理解、再外接 VAE + 扩散模块做生成,模块之间靠适配器翻译彼此的表示。SenseNova-U 系列走的是另一条路——原生统一:商汤提出的 NEO-unify 架构从第一性原理出发,彻底摒弃视觉编码器与 VAE,让像素与文字在同一架构内端到端建模,理解、推理、生成由一个模型原生完成。用官方 README 的话说,这代表着多模态 AI 的范式转变:从模态集成走向真正的统一——不再依赖适配器在模态之间翻译,而是以原生方式跨语言与视觉进行思考与行动。

1.2 NEO-unify 的三个核心支柱

  • 🔗 端到端统一建模语言与视觉信息,打通从像素到文字的理解与生成;

  • 🖼️ 兼顾语义表达与像素级保真,既不丢语义、也不丢细节;

  • 🧠 原生 MoT(Mixture-of-Transformers) 高效完成跨模态推理,减少模态冲突。

MoT 是理解后文一切部署问题的钥匙,这里先交代结构:U1.5 不是「一个 LLM 外挂一个扩散头」,而是把理解与生成做成两条专家通路——视觉编码器、注意力与 FFN 权重各自成对(理解侧不带后缀、生成侧带 _mot_gen 后缀),只有词表的 embed_tokenslm_head(合计 1.25B)是两条通路共享的。这个结构对部署有两个直接推论(第 1.4 节展开):任意单任务时刻只有一半左右的权重是热的;文生图里混有自回归阶段(如 --think 先吐思考文本),所以推理日志里既会出现扩散采样步数,也会出现 LLM 式的 token 吞吐指标。

1.3 SenseNova-U1.5:六项用户可感知的升级

SenseNova-U1 于 2026-04-27 首发,2026-07-31 放出 U1.5-Preview,2026-08-20 正式发布 U1.5 正式版SenseNova-U1.5-8B-MoT),并同步发布 8 步蒸馏权重 SenseNova-U1.5-8B-MoT-LoRA-8step。正式版在 NEO-unify 基础上进一步强化了 patchify 层、数据质量与分布、任务定义、Prompt 增强和后训练流程,重点提升六项能力:

  1. 更高质量的图像生成:构图、色彩和谐度、材质渲染、光照、真实感与细粒度细节全面提升;

  2. 更好的文字渲染与信息图生成:中英文文字可读性更强,海报、信息图、品牌素材等信息层级更清晰;

  3. 更高效的原生 4K 生成:全局结构连贯性、高分辨率输出稳定性与生成效率提升;

  4. 更可靠的原生图像编辑:局部编辑、文字编辑、多参考图编辑中更好地保持主体身份与非编辑内容;

  5. 更强的复杂指令遵循:对象数量、空间关系、版式、风格及多约束请求执行更稳定;

  6. 更精确的视觉控制:通过边界框、视觉标记、单图/多图参考实现区域级与对象级控制。

加上 U1 时代就树立的原生图文交错生成(绘本、教程、多页 PPT 一次连贯产出)与高密度信息呈现(知识图解、海报、简历等信息密集场景),以及理解与生成双线的开源 SoTA 评测成绩,U1.5 是「原生统一」路线里目前工程完成度最高的开源权重之一。

1.4 名叫「8B」,实则 17.5B:部署前必须认清的参数账

部署之前,我先用仓库自带的 scripts/inspect_model_params.py 把参数构成摸清楚:

python scripts/inspect_model_params.py --model_path /path/to/SenseNova-U1.5-8B-MoT
Total params: 17.533B
Total memory: 35.066GB (bfloat16)
---------------------------------------------------------------------
group                              params memory (bfloat16)      ratio
---------------------------------------------------------------------
generation_transformer             8.167B         16.334GB     46.58%
understanding_transformer          8.121B         16.243GB     46.32%
shared                             1.245B          2.489GB      7.10%
---------------------------------------------------------------------
Pathway breakdown (shared counted in both):
---------------------------------------------------------------------
pathway                            params memory (bfloat16)      ratio
---------------------------------------------------------------------
understanding pathway              9.366B         18.732GB     53.42%
generation pathway                 9.412B         18.823GB     53.68%

注意这个数字:名字叫「8B」,实际总参数 17.53B、BF16 权重 35.1 GB——「8B」指的是单侧通路参数量。这是后文一切显存问题的根源,也是本次部署最大的认知坑:别按「8B 模型 16 GB 显存随便跑」来预估资源。跑文生图时前向实际经过「生成通路 + 共享层」约 9.41B 参数,跑图像理解时经过「理解通路 + 共享层」约 9.37B 参数——任意时刻只有一条通路是热的,这正是分层卸载 / 分片加载能把 24 GB 卡跑起来的结构性前提。

1.5 为什么选它做部署实战:低显存路径是官方一等公民

选 U1.5 正式版作为部署对象,理由有三:

  1. 能力全面:原生 2K/4K 生成、中英文文字渲染、信息图、图像编辑、图文交错生成,还有出图前先推理的 --think 模式,一个模型覆盖后续章节想玩的所有案例;

  2. 对消费级显卡友好:官方提供 --vram_mode 四档分层卸载(最低 ~5 GiB 显存即可跑)、--max_memory 显存预算约束、社区维护的 GGUF Q8 量化(19.9 GB),低显存路径不是社区补丁而是官方一等公民;

  3. 蒸馏加速官方化:官方直接放出 8 步蒸馏 LoRA,配套文档给出与 50 步基线的完整对比,「消费级单卡 + 8 步蒸馏」就能把 2K 出图压进半分钟,非常适合做部署调优选题。

SenseNova-U1.5 是一个「理解与生成原生统一、总参数 17.5B、官方把低显存与加速都做成一等公民」的模型——能力强、坑也明确,接下来就是把它塞进一张 24 GB 显卡的实战。


第二章 单卡 NVIDIA RTX 4090D 部署与踩坑

2.0 环境速查表

项目
系统 Ubuntu 24.04.4 LTS,内核 7.0.0-28-generic x86_64
CPU / 内存 Intel Core i9-14900KF / 32 GB
GPU NVIDIA GeForce RTX 4090 D,24GB 显存
驱动 / CUDA 595.45.04 / CUDA Toolkit 12.8(nvcc V12.8.61)
Python 环境 Python 3.11.15(uv 管理)
关键依赖 torch 2.8.0+cu128、torchvision 0.23.0+cu128、transformers 5.15.0、accelerate 1.14.0、safetensors 0.8.0、huggingface_hub 1.27.0、sentencepiece、numpy 2.2.0、pillow 12.0.0
模型 sensenova/SenseNova-U1.5-8B-MoT(BF16,33 GB / 8 个 safetensors 分片)
蒸馏权重 SenseNova-U1.5-8B-MoT-LoRA-8step.safetensors(814 MB)
仓库 GitHub OpenSenseNova/SenseNova-U1

2.1 部署机准备

部署机是一台i9-14900KF + 4090 D。正式安装前先做三件事,否则中途必踩坑:

第一,禁用自动休眠。 系统默认空闲一段时间就挂起——跑到一半的 50 步采样直接腰斩;更麻烦的是休眠唤醒后 GPU 状态可能异常,轻则推理进程段错误,重则整机死机。我在部署过程中被它打断了好几次,最后的处理是彻底屏蔽休眠:

sudo systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target
sudo sed -i 's/#HandleLidSwitch=.*/HandleLidSwitch=ignore/' /etc/systemd/logind.conf
sudo systemctl restart systemd-logind

第二,长任务一律放 tmuxnohup 33 GB 模型加载、50 步采样都是分钟级任务,终端一断前功尽弃。本文所有长跑命令都形如 nohup bash bench.sh > bench.log 2>&1 &,回来用 tail -f 接上现场。

第三,固化验证命令。 nvidia-sminvcc --versionuv pip list | grep torchdu -sh 模型目录 这四条在每次重启/更新后跑一遍,十秒钟确认环境没有悄悄坏掉——部署机最怕的就是「上次还好好的,这次不知道哪里坏了」。

2.2 驱动与 CUDA

2.2.1 先清场:屏蔽 nouveau

Ubuntu 24.04 默认带 nouveau,不屏蔽装 NVIDIA 驱动必翻车:

echo -e "blacklist nouveau\noptions nouveau modeset=0" | sudo tee /etc/modprobe.d/blacklist-nouveau.conf
sudo update-initramfs -u
sudo reboot
2.2.2 编译依赖不能少

.run 安装器需要现场编译内核模块,新内核尤其容易缺头文件:

sudo apt update
sudo apt install -y gcc make linux-headers-$(uname -r)
gcc -v   # 确认工具链可用

本机内核是 7.0.0-28-generic(24.04 的 HWE 新内核),这一点直接导致了下面的版本试错。

2.2.3 CUDA 版本试错:12.8 → 12.9 → 13.2

我按时间顺序踩了三个版本(都是官方 .run 安装包)。先说一个贯穿全程的关键认知:.run 安装包里「驱动」和「toolkit」是两个可以分开装的组件,理解了这一点,后面的操作就不奇怪了:

# 第一次:CUDA 12.8 整包(捆绑驱动 570.86.10)—— 驱动在 7.0 内核上编译内核模块失败
wget https://developer.download.nvidia.com/compute/cuda/12.8.0/local_installers/cuda_12.8.0_570.86.10_linux.run
# 第二次:CUDA 12.9 整包(捆绑驱动 575.51.03)—— 仍然失败,翻安装日志排查
cat /var/log/cuda-installer.log
cat /var/log/nvidia-installer.log | grep -i error
# 第三次:CUDA 13.2(捆绑驱动 595.45.04)—— 驱动终于编译通过,只装 Driver 组件
wget https://developer.download.nvidia.com/compute/cuda/13.2.0/local_installers/cuda_13.2.0_595.45.04_linux.run
sudo chmod +x cuda_13.2.0_595.45.04_linux.run
sudo ./cuda_13.2.0_595.45.04_linux.run
# 驱动通过后,toolkit 不必追 13.2:torch 官方 wheel 是 cu128,nvcc 只用于编译少量自定义扩展,
# 于是单独装 CUDA 12.8 的 toolkit,跳过它捆绑的老驱动组件:
sudo ./cuda_12.8.0_570.86.10_linux.run --toolkit --silent --override

验证(真机输出):

nvidia-smi    # NVIDIA-SMI 595.45.04 / Driver 595.45.04 / CUDA Version: 13.2
nvcc --version
# Cuda compilation tools, release 12.8, V12.8.61

这里有个极易误读的点:nvidia-smi 显示的 CUDA Version: 13.2 是「驱动支持的最高 CUDA 版本」,不是已安装的 toolkit 版本——本机实际 toolkit 以 nvcc --version 为准,是 12.8。说实话我最初整理环境信息时也把它误写成了「CUDA 13.2」,后来复核 /var/log/cuda-installer.log(里面清楚地写着 Installing: CUDA Toolkit 12.8)才纠正过来。这个误判新手几乎人人会犯,单独拿出来说一句。

根因分析,给遇到同类问题的同学一个判断框架:.run 安装器会现场编译内核模块,失败几乎都发生在「内核太新 × 驱动太老」的组合上——7.0 内核改动了不少内核态 API(内存管理、符号导出),老驱动的 nvidia.ko 源码根本编译不过去,症状是安装器报 Failed to build kernel module,或者装完 nvidia-smi 提示 Driver/library version mismatch。排查路径固定为三步:先 cat /var/log/nvidia-installer.log | grep -i error 看编译错误,再 dmesg | grep -i nvidia 看加载期报错,最后决定升驱动而不是降内核。我这次的选择是跟着内核走:24.04 的 HWE 内核会持续升级,与其钉死旧内核不如直接上最新驱动分支(595 系对 6.x/7.x 内核支持最完整),一次装好后续内核小版本升级也省心。

最后把 nvcc 加进 PATH(.run 安装不会自动写):

echo 'export PATH=/usr/local/cuda/bin:$PATH' >> ~/.bashrc
echo 'export LD_LIBRARY_PATH=/usr/local/cuda/lib64:$LD_LIBRARY_PATH' >> ~/.bashrc
source ~/.bashrc

检查点nvidia-smi 能显示 595.45.04 与 RTX 4090 D、nvcc --version 输出 12.8,驱动这一层才算过关。

2.2.4 关键结论:驱动、工具链、运行时三层解耦

PyTorch 官方 wheel 目前主流仍是 cu128(CUDA 12.8 运行时)。NVIDIA 驱动向下兼容:595 驱动跑 cu128 的 torch 完全没问题,不需要为了 torch 去降级驱动,也不需要等 cu13x 的 wheel。三层各自独立选型,最终组合:

  • 驱动层:595.45.04(新分支,对 7.0 内核支持完整,最高可支持 CUDA 13.2);

  • 工具链层:CUDA Toolkit 12.8(nvcc V12.8.61,编译扩展用,跟着 torch 生态走);

  • 应用层torch 2.8.0+cu128(pip wheel 自带 CUDA 12.8 运行时)。

2.3 Python 环境:uv 一条龙

传统 conda 太重,这次全程用 uv,从装 Python 到装依赖一条命令:

# 1) 安装 uv
curl -LsSf https://astral.sh/uv/install.sh | sh
source ~/.bashrc && uv --version
​
# 2) 创建 Python 3.11 虚拟环境(仓库要求 >=3.10,<3.14)
cd ~/SenseNova
uv venv --python=3.11
source .venv/bin/activate
​
# 3) 安装 PyTorch(cu128 wheel)
uv pip install torch torchvision --index-url https://download.pytorch.org/whl/cu128
​
# 4) 克隆仓库并以可编辑模式安装(自动注册模型到 transformers)
sudo apt install -y git        # 最小化装的 24.04 可能没有 git,先补上
git clone https://github.com/OpenSenseNova/SenseNova-U1.git SenseNova-U1-GitHub
cd SenseNova-U1-GitHub
uv pip install -e .

小坑一个:我这台机器最初没装 git,是直接在 GitHub 页面下载源码 zip 解压的(目录里没有 .gitgit log 用不了)。功能上没影响,但后续想 git pull 更新仓库就得整个重新下载,建议按上面命令装好 git 再 clone。

最终锁定版本(uv pip list 节选):

torch                2.8.0+cu128
torchvision          0.23.0+cu128
transformers         5.15.0
accelerate           1.14.0
safetensors          0.8.0
huggingface_hub      1.27.0
numpy                2.2.0
pillow               12.0.0
sentencepiece        0.2.1
sensenova-u1         0.1.0 (editable)

踩坑点:

  • transformers 需要 5.7+(仓库要求),直接装最新 5.15.0 即可,4.x 会报模型类不存在;

  • 没装 flash-attn 时,推理脚本的 --attn_backend auto 会自动回退到 SDPA,日志里会打印 effective='sdpa' 便于确认,不折腾也能跑;追求极限速度再考虑编译 flash-attn。

检查点python -c "import torch; print(torch.cuda.is_available(), torch.cuda.get_device_name(0))" 输出 True NVIDIA GeForce RTX 4090 D,Python 环境才算就绪。

2.4 模型下载:33 GB,8 个分片

国内环境直接用 ModelScope(仓库同名空间),速度稳定;有代理的话 Hugging Face 也可以。

# ModelScope 方式(本次实测使用)
pip install modelscope
modelscope download --model SenseNova/SenseNova-U1.5-8B-MoT --local_dir ~/SenseNova/SenseNova-U1.5-8B-MoT
​
# Hugging Face 方式(备选)
hf download sensenova/SenseNova-U1.5-8B-MoT --local-dir ~/SenseNova/SenseNova-U1.5-8B-MoT

实测:8 个分片(7×约 4.9 GB + 1×369 MB)共 33 GB,约 14 分钟下完,平均 ~40 MB/s。国内环境 Hugging Face 直连经常断流,能直连就优先 ModelScope,基本能跑满带宽,不需要任何代理配置。下载前先 df -h 确认空间:权重 33 GB + uv/pip 缓存 + 输出图片,至少预留 50 GB;本次部署结束时 233 GB 的盘已用 93 GB,其中 uv 缓存就占了 12 GB,可用 uv cache clean 在装完后安全回收。

du -sh ~/SenseNova/SenseNova-U1.5-8B-MoT
# 33G   /home/q/SenseNova/SenseNova-U1.5-8B-MoT

顺手把 8 步蒸馏 LoRA 也下了(只有 814 MB):

hf download sensenova/SenseNova-U1.5-8B-MoT-LoRAs \
    SenseNova-U1.5-8B-MoT-LoRA-8step.safetensors \
    --local-dir ~/SenseNova/SenseNova-U1.5-8B-MoT-LoRAs

⚠️ 官方特别提醒:U1.5 的 8 步 LoRA 只适配 SenseNova-U1.5-8B-MoT 正式版,不要用在 U1.5-Preview 或老版 U1 权重上。

2.5 首跑:50 步基线

官方文生图脚本是 examples/t2i/inference.py。先跑 50 步完整基线(官方推荐超参):

cd ~/SenseNova/SenseNova-U1-GitHub
​
python examples/t2i/inference.py \
    --model_path ~/SenseNova/SenseNova-U1.5-8B-MoT \
    --prompt 'A wooden greeting card lying on a desk, with readable Chinese text "生日快乐" written on it, a small bouquet of flowers beside it, soft morning sunlight through the window, photorealistic, high detail.' \
    --output outputs/base_50step_2048.png \
    --width 2048 --height 2048 \
    --cfg_scale 4.0 --cfg_norm none --timestep_shift 3.0 --num_steps 50 \
    --seed 42 --attn_backend sdpa --profile \
    --device_map auto --max_memory "0=20GiB,cpu=16GiB"

几个要点:

  1. 分片加载是 24 GB 显存 + 32 GB 内存能跑起来的关键--device_map auto --max_memory "0=20GiB,cpu=16GiB"(第 2.9 节路线二)让 Accelerate 按层把权重分片派发到 GPU(约 18.4 GiB)+ CPU(可换页,约 15 GiB),生成峰值 ~20.5 GiB;

  2. 为什么不照抄官方 --vram_mode fast:卸载模式会把 language_model.model.layers 全部 30.19 GiB 权重 pin_memory()不可换页的锁页内存,32 GB 内存装不下,直接 OOM/死机——本机真实踩过(fast 尝试卡死在 pinning 阶段、回退脚本被 OOM kill)。主机内存 ≥40 GB 才能用 fast(原理见第 2.9 节);

  3. --profile 会打印模型加载耗时、单图生成耗时、峰值显存、token 吞吐,调优必备;

  4. 分辨率不是任意的:模型按固定分辨率桶训练,2048×2048 属于官方 1:1 桶,乱填尺寸脚本会告警且质量下降:

比例 分辨率 比例 分辨率
1:1 2048×2048 16:9 2720×1536
3:2 2496×1664 4:3 2368×1760
2:3 1664×2496 3:4 1760×2368
1:2 1440×2880 2:1 2880×1440

--profile 的输出怎么读,这里交代一下,后面所有对比数据都出自它:它会依次打印模型加载耗时(含从磁盘读 8 个分片 + 反序列化)、生成阶段的平均单图耗时、峰值显存的 allocated / reserved 双值(前者是张量实际占用,后者是 caching allocator 向驱动申请的池子大小,OOM 排查看 reserved)、以及按图像 token 归一化的吞吐(tok/s,此处的 token 是潜空间 patch 序列长度,2048×2048 对应上万 token,不是文本 token)。第二次运行起权重已在页缓存里,加载耗时会明显变短,做对比时建议取热启动数据并注明。

50 步基线出图(2048×2048,seed=42):

⏱️ 实测数据(分片路线):50 步 2048×2048 模型加载 20.2 s、生成 178.0 s,峰值显存 20.51 GiB(reserved 21.07 GiB),CPU RSS 峰值 19.29 GiB,吞吐 23.0 tok/s;全程可用内存未低于 ~27.5 GiB,swap 几乎未用,32 GB 内存主机安全。

2.6 官方 README 四大示例,在 24 GB 卡上逐条实测

仓库 README「使用 Transformers 快速开始」给了四条命令:文生图、图像编辑、图文交错生成、视觉理解。我把它们逐条在这台 4090 D 上跑了一遍,先说结论:四条都能跑通,但原样照抄跑不了,要改两个地方

  1. 所有脚本的默认 --vram_mode full 需要 ~35 GB 显存,24 GB 卡必须显式换卸载/分片路线(本机 32 GB 内存用 --device_map 分片,见 2.5 节);

  2. 默认分辨率就是最大的 2048×2048 桶,首次验证可以换小桶提速,正式出图再用默认。

① 文生图examples/t2i/inference.py):即上一节的命令(分片路线),顺利出图。

② 图像编辑examples/editing/inference.py):输入官方样例图 1.webp,把画面中左侧人物的夹克改成亮黄色:

python examples/editing/inference.py \
    --model_path ~/SenseNova/SenseNova-U1.5-8B-MoT \
    --image examples/editing/data/images/1.webp \
    --prompt "Change the jacket of the person on the left to bright yellow." \
    --output outputs/edited.png --vram_mode fast

这个示例第一次跑直接 OOM 了:理解通路(编码原图 + 指令)的注意力峰值把显存顶到 20.58 GiB,还差最后 2.2 GiB 没处放。编辑任务比纯文生图多一段「读原图」的理解前向,激活峰值更高,这是 24 GB 卡跑编辑的共性问题;修正方式是降低 GPU 预算档位或回退 balanced(见 2.9 节)。

③ 图文交错生成examples/interleave/inference.py):给一个主题,模型自动规划「文字 + 多张配图」,适合做教程、绘本类内容:

python examples/interleave/inference.py \
    --model_path ~/SenseNova/SenseNova-U1.5-8B-MoT \
    --prompt "I want to learn how to cook tomato and egg stir-fry. Please give me a beginner-friendly illustrated tutorial." \
    --resolution "16:9" \
    --output_dir outputs/interleave/ \
    --stem demo \
    --vram_mode fast --profile

④ 视觉理解examples/vqa/inference.py):拍一张菜单问模型「两人吃饭怎么点菜」,走的是理解通路,不产生图像:

python examples/vqa/inference.py \
    --model_path ~/SenseNova/SenseNova-U1.5-8B-MoT \
    --image examples/vqa/data/images/menu.jpg \
    --question "My friend and I are dining together tonight. Looking at this menu, can you recommend a good combination of dishes for 2 people?" \
    --output outputs/answer.txt \
    --max_new_tokens 8192 --do_sample --temperature 0.6 --top_p 0.95 --top_k 20 \
    --repetition_penalty 1.05 --vram_mode fast --profile

⚠️ 注:以上命令中的 --vram_mode fast 是官方低显存路线,适合主机内存 ≥40 GB 的机器;本机 32 GB 内存请一律按 2.5 节换成 --device_map 分片路线,否则锁页内存打满死机(2.9 节)。这一轮实测也给了我给官方仓库的一条具体建议:README 快速开始应标注低显存用法——四条示例的默认参数都按大显存卡设计,24 GB 及以下用户照抄必 OOM,建议在每条命令旁加注 --vram_mode fast/balanced(我会整理成 Issue 提交)。四大示例的逐案例出图效果与耗时细账,留到第三、四章展开。

2.7 8 步蒸馏 LoRA:步数砍到 1/6

官方 8 步 LoRA 是 flow-matching 蒸馏权重,使用方式 = 基线权重 + 合并 LoRA + 换一组超参(CFG 必须降到 1.0):

python examples/t2i/inference.py \
    --model_path ~/SenseNova/SenseNova-U1.5-8B-MoT \
    --lora_path ~/SenseNova/SenseNova-U1.5-8B-MoT-LoRAs/SenseNova-U1.5-8B-MoT-LoRA-8step.safetensors \
    --prompt 'A wooden greeting card lying on a desk, with readable Chinese text "生日快乐" written on it, a small bouquet of flowers beside it, soft morning sunlight through the window, photorealistic, high detail.' \
    --output outputs/smoke_8step_2048.png \
    --width 2048 --height 2048 \
    --cfg_scale 1.0 --cfg_norm none --timestep_shift 3.0 --num_steps 8 \
    --seed 42 --attn_backend sdpa --profile \
    --device_map auto --max_memory "0=20GiB,cpu=16GiB"

同 Prompt、同 Seed、同分辨率的对比:

维度 50 步基线 8 步蒸馏 说明
采样步数 50 8 蒸馏 LoRA 官方配置
CFG 4.0 1.0 蒸馏后无需强引导,CFG=1 还能省一半前向
生成耗时 178.0 s 26.7 s 同机同参实测(--profile),端到端 6.7×
峰值显存 20.51 GiB 19.80 GiB 步数不影响显存峰值,两者接近;CPU RSS 均 ~19.3 GiB
画质观感 细节最完整 整体一致,极细纹理略软 见对比图,中文「生日快乐」两者均渲染正确

加速原理算笔账:8 步模式的提速来自两方面——步数 50→8(约 6.25×),以及 CFG 4.0→1.0 后每步不再做双份前向(CFG 需要同时算条件/无条件分支)。把两笔账合起来算 NFE(网络前向次数):50 步 × 2(CFG 双分支)= 100 次前向,对比 8 步 × 1 = 8 次前向,理论计算量之比是 12.5×;实际端到端达不到这个倍数,因为还有权重搬运、调度与图像解码等固定开销,且分片模式下 PCIe 带宽是共同瓶颈,但方向一致。

使用建议:对批量出图、API 服务、快速试 Prompt 的场景,8 步 LoRA 应作为默认配置;最终交付图再切回 50 步。另一个容易踩的坑是沿用 50 步的 CFG=4.0 跑蒸馏权重——画面会明显过饱和甚至崩坏,蒸馏权重的 CFG 就固定 1.0。

2.8 推理超参调优手册

inference.py 的超参空间整理成一张速查表:

参数 默认 可选值 调优建议
--cfg_scale 4.0 float 基线模型 3.5~5.0;过高会过饱和、构图僵硬;8 步 LoRA 固定 1.0
--cfg_norm none none / global / channel / cfg_zero_star CFG 偏高出现色彩溢出时,用 global/channel 把输出拉回条件分支的范数
--timestep_shift 3.0 float flow-matching 时间表偏移,高分辨率可适当调大,一般不动
--cfg_interval 0 1 LO HI 只在部分步数区间施加 CFG,可缓解后期细节被 CFG「拽变形」
--num_steps 50 int 50 为质量基线;8 配蒸馏 LoRA
--seed 42 int 复现与 A/B 对比必固定
--attn_backend auto auto / flash / sdpa 没装 flash-attn 就显式 sdpa,日志里会打印 effective 值便于确认
--think off flag T2I 推理模式:先输出 <think> 思考块再出图,复杂构图任务有增益,耗时增加
--enhance off flag 短 Prompt 先过一遍 LLM 增强(配 U1_ENHANCE_* 环境变量),信息图类任务推荐

两个常用变体示例:

# 变体 A:思考模式 + Prompt 增强(复杂海报/信息图)
python examples/t2i/inference.py \
    --model_path ~/SenseNova/SenseNova-U1.5-8B-MoT \
    --prompt "一张介绍太阳系八大行星的中文信息图" \
    --output outputs/think_demo.png --width 2048 --height 2048 \
    --cfg_scale 4.0 --num_steps 50 --vram_mode fast \
    --think --print_think --enhance
​
# 变体 B:批量跑官方样例(jsonl 模式,每条可自带宽高/seed)
python examples/t2i/inference.py \
    --model_path ~/SenseNova/SenseNova-U1.5-8B-MoT \
    --jsonl examples/t2i/data/samples.jsonl \
    --output_dir outputs/u1_5_base/ \
    --cfg_scale 4.0 --cfg_norm none --timestep_shift 3.0 --num_steps 50 \
    --vram_mode fast --profile

2.9 低配显卡生存指南(量化 · 显存卸载)

这是本章最有复用价值的一节。先看问题本质:

BF16 全量权重 = 17.533B × 2 byte ≈ 35.1 GB  >  24 GB(RTX 4090 D)

所以「全量上卡」(--vram_mode full)需要 ~35 GB 显存(H100/A100-40G+ 级别)。24 GB 及以下必须走下面三条路之一。

2.9.1 路线一:--vram_mode 分层卸载(官方原生,零额外依赖)

原理:权重常驻 CPU 内存,按层流式搬上 GPU;fast 模式额外把生成阶段的热层留在显存预算内,用异步预取重叠 H2D 与计算。官方在 H100 上的实测(2048×2048、50 步、BF16、SDPA):

--vram_mode 策略 生成峰值显存 (GiB) 平均耗时 (s) 吞吐 (tok/s)
full 整模型常驻 GPU(默认) 34.79 / 35.72 20.9 196.0
fast 异步预取 + 生成层常驻显存预算内 19.68 / 20.41 22.9 179.3
balanced 异步预取,H2D 与计算重叠 5.68 / 9.34 31.5 130.2
low 每层同步 CPU↔GPU 交换 4.96 / 5.53 51.5 79.5

(表格来源:仓库 docs/gpu_mem_profiler_CN.md,四种模式输出图像逐像素一致)

补充一点机制说明,方便按需调参:四种模式在数学上完全等价(同一套权重、同一个采样器),差异只在权重存放位置与搬运时机——balanced 用 pinned memory + 异步 H2D 让搬运与计算重叠,fast 更进一步在显存预算内把生成阶段反复访问的热层钉在 GPU 上,只有冷层参与搬运,所以它相对 full 只损失 ~10% 速度。「输出逐像素一致」意味着你可以先用 low 模式在小显卡上验证流程与超参,再在资源充足时切回 fast/full 提速,不用担心结果漂移,这对调参工作流非常友好。相关微调参数:--fast_vram_fraction(默认 0.90)、--fast_vram_headroom_gib(默认 2)、--fast_activation_reserve_gib(默认 4)、--fast_vram_budget_gib(绝对预算,优先级最高)。

⚠️ 32 GB 内存主机警告:以上四档的代价是全部层权重被钉在不可换页的锁页内存——本机实测仅 language_model.model.layers 就占 30.19 GiB,锁页既不能 swap 也不能被内核回收,主机内存必须 ≥ ~40 GB,否则 OOM/死机(本机实测:fast 尝试卡死在 pinning 阶段,回退脚本被 OOM kill)。32 GB 内存主机请走路线二(--device_map 分片)或路线三(GGUF),本文全部实测命令均为路线二。

# 8 GB 显存极限生存示例
python examples/t2i/inference.py \
    --model_path ~/SenseNova/SenseNova-U1.5-8B-MoT \
    --prompt "..." --output outputs/low_vram.png \
    --width 2048 --height 2048 --cfg_scale 4.0 --num_steps 50 \
    --vram_mode low --attn_backend sdpa --profile
2.9.2 路线二:--device_map + --max_memory 显存预算约束

用 Accelerate 把模型按层切到「GPU + CPU」,显式给 GPU 设预算(建议比物理显存低 3~4 GB 留余量):

python examples/t2i/inference.py \
    --model_path ~/SenseNova/SenseNova-U1.5-8B-MoT \
    --prompt "..." --output outputs/budget.png \
    --cfg_scale 4.0 --num_steps 50 \
    --device_map auto --max_memory "0=20GiB,cpu=80GiB" --profile

官方按此方法模拟各档显卡的数据(50 步 2048×2048):

GPU 预算 目标显卡 生成峰值显存 (GiB) CPU 内存 (GiB) 平均耗时 (s) 吞吐 (tok/s)
27 GiB RTX 5090 (32 GB) 27.76 10.3 87.7 46.7
20 GiB RTX 4090 (24 GB) 20.58 19.5 175.0 23.4
13 GiB RTX 4080 (16 GB) 13.39 24.1 250.8 16.3
9 GiB RTX 4070 (12 GB) 9.79 28.8 290.0 14.1
7 GiB RTX 4060 (8 GB) 7.64 28.8 316.3 13.0

注意 max_memory 路线因为切得更碎,比 vram_mode fast 慢(175 s vs 23 s 级别,H100 口径)——内存充足的主机上单卡优先 --vram_mode,多卡才用 --device_map。CPU 内存需求:预算越低、驻留 CPU 的权重越多,建议 ≥32 GB 内存。但本结论有一个例外:32 GB 内存主机跑不了 --vram_mode 卸载(30.2 GiB 锁页,见 2.9.1),分片是唯一活路——本机实测 50 步 2048×2048 为 178 s、8 步为 26.7 s,这就是分片的代价。

2.9.3 路线三:GGUF 量化(显存直接砍半)

社区(HF 用户 smthem)维护了 Q8 GGUF 权重(19.9 GB),官方脚本原生支持:

uv pip install "gguf>=0.10.0" "diffusers>=0.30.0"
python examples/t2i/inference.py \
    --model_path ~/SenseNova/SenseNova-U1.5-8B-MoT \
    --gguf_checkpoint /path/to/SenseNova-U1.5-8B-MoT-Q8.gguf \
    --prompt "..." --output outputs/gguf_q8.png \
    --width 2048 --height 2048 --cfg_scale 4.0 --num_steps 50

Q8 权重 19.9 GB + 激活,24 GB 卡可以走 full 模式全量上卡,绕开所有卸载开销,是「显存够不着 35 GB 但够得着 20 GB」场景的另一条快路。更低显存还可以找社区的更低比特量化或等待官方量化发布。

2.9.4 档位速查(建议收藏)
你的显存 推荐方案
≥40 GB(A100/H100) --vram_mode full,性能无损
24 GB(4090/3090/4090D) BF16 + --device_map 分片(本文实测,32 GB 内存主机);主机内存 ≥40 GB 可换 --vram_mode fast;或 Q8 GGUF + full
16 GB --vram_mode balanced 或 Q8 GGUF + fast
12 GB --vram_mode balanced/low + 降分辨率桶(1536 档)
8 GB --vram_mode low + 1024/1536 档,或 GGUF 更低比特量化

2.10 服务化:FastAPI + systemd 与官方 Docker 方案

2.10.1 自己包一层 FastAPI(24 GB 单卡够用)

推理脚本本身是一次性命令行,想给别的应用调用,最轻的做法是包一层 HTTP。我写了一个单文件 u1_api_server.py(完整代码见附录 C),核心设计只有四点:

  1. 进程启动时一次性加载模型 + 合并 8 步 LoRA,之后常驻显存,请求零加载开销;

  2. 全局互斥锁串行生成:24 GB 单卡并发出图必 OOM,锁是最简单可靠的保护;

  3. 请求体只需 prompt,宽高/步数/CFG/seed 均可选,缺省用 8 步蒸馏配置;

  4. 返回 base64 PNG + 耗时/参数元数据,前端一行 atob 即可渲染。

# 部署机上安装依赖并启动
uv pip install --python ~/SenseNova/.venv/bin/python fastapi uvicorn
~/SenseNova/.venv/bin/python ~/SenseNova/SenseNova-U1-GitHub/u1_api_server.py \
    --model_path ~/SenseNova/SenseNova-U1.5-8B-MoT \
    --lora_path  ~/SenseNova/SenseNova-U1.5-8B-MoT-LoRAs/SenseNova-U1.5-8B-MoT-LoRA-8step.safetensors \
    --vram_mode fast --num_steps 8 --cfg_scale 1.0 --port 8000

⚠️ 32 GB 内存主机注意:--vram_mode fast 同样会触发锁页内存打满(2.9.1 节)。给 u1_api_server.py 增加 --device_map/--max_memory 两个透传参数(直接传给 SenseNovaU1T2I 构造器,附录 C 代码加两行即可)换分片路线后再启动。

用 systemd 托管,开机自启、崩溃自动拉起:

# /etc/systemd/system/u1-api.service
[Unit]
Description=SenseNova-U1.5 T2I API (FastAPI)
After=network.target
​
[Service]
Type=simple
User=q
WorkingDirectory=/home/q/SenseNova/SenseNova-U1-GitHub
ExecStart=/home/q/SenseNova/.venv/bin/python /home/q/SenseNova/SenseNova-U1-GitHub/u1_api_server.py \
    --model_path /home/q/SenseNova/SenseNova-U1.5-8B-MoT \
    --lora_path /home/q/SenseNova/SenseNova-U1.5-8B-MoT-LoRAs/SenseNova-U1.5-8B-MoT-LoRA-8step.safetensors \
    --vram_mode fast --num_steps 8 --cfg_scale 1.0 --port 8000
Restart=on-failure
RestartSec=10
​
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload && sudo systemctl enable --now u1-api
curl -s http://localhost:8000/health            # 等 status 变 ok
curl -s -X POST http://localhost:8000/v1/images/generations \
    -H "Content-Type: application/json" \
    -d '{"prompt":"A red panda holding a camera, studio lighting","seed":7}' \
    | python3 -c "import sys,json,base64;open('api_out.png','wb').write(base64.b64decode(json.load(sys.stdin)['b64_image']))"
2.10.2 官方 Docker 方案(LightLLM + LightX2V)

多卡或高并发场景,官方推荐 LightLLM + LightX2V 的 Docker 部署(详见仓库 docs/deployment_CN.md),核心是 colocate(理解与生成共享 GPU,单卡友好)与 separate(理解/生成分卡,类似 PD 分离,避免长生成阻塞短理解)两种模式。单卡 24 GB 场景本文的 FastAPI 轻量方案更合适,多卡/高并发再上 LightLLM,这里不展开。

2.11 踩坑清单

踩坑清单

  1. 内核太新 → 驱动编译失败:24.04 的 7.0 内核算老驱动就是编译不过,直接上最新驱动分支(595 系);

  2. 忘记装 linux-headers-$(uname -r):.run 安装器静默失败,日志在 /var/log/nvidia-installer.log

  3. 被「8B」命名误导:实际 17.53B / 35.1 GB,不做显存规划直接 OOM;

  4. torch 版本与驱动强行对齐:其实驱动向下兼容,595 驱动 + cu128 wheel 是更稳的组合;

  5. nvidia-smi 的 CUDA Version 当成已装 toolkit 版本:那是驱动支持的最高版本,本机 toolkit 以 nvcc --version 为准(12.8);

  6. README 示例原样照抄:四个官方示例默认 --vram_mode full,24 GB 卡必 OOM,一律换低显存路线(见 2.6 节实测);

  7. 8 步 LoRA 沿用 50 步的 CFG=4.0:画面明显过饱和/崩坏,蒸馏权重必须 --cfg_scale 1.0

  8. 任意分辨率出图:出了训练桶质量劣化且脚本会告警,老老实实用官方分辨率桶;

  9. 下载 33 GB 不做断点准备:用 hf download / ModelScope 官方 CLI 都有断点续传,别用裸 wget 拼链接;

  10. 32 GB 内存主机用 --vram_mode 卸载:卸载把 30.19 GiB 层权重 pin_memory() 成锁页,锁页不能 swap,内存瞬间打满死机;32 GB 内存主机请 --device_map auto --max_memory "0=20GiB,cpu=16GiB" 分片加载(2.9.2 节),峰值显存 ~20.5 GiB、RSS ~19.3 GiB。

2.12 本章小结

  • 最小可用组合:驱动 595 + CUDA Toolkit 12.8 + torch cu128 + uv/py3.11 + --device_map 分片加载 + 8 步 LoRA,可直接抄作业(内存 ≥40 GB 主机可换 --vram_mode fast 提速);

  • 两个认知坑:「8B」实为 17.53B / 35.1 GB;nvidia-smi 的 CUDA Version 不是 toolkit 版本;

  • 一个内存坑:32 GB 内存主机别碰 --vram_mode 卸载的锁页内存,分片是唯一活路;

部署到此完成:单卡 4090 D 上,50 步基线 178 s、8 步蒸馏 26.7 s 稳定出 2048×2048 图,API 服务常驻待命。


第三章 案例实战 AMD ROCm 部署实战

3.1设备与运行环境

3.1.1. 硬件 / 驱动 / ROCm 一览
类别 实测值
操作系统 Ubuntu 22.04.5 LTS,内核 6.8.0-79-generic(x86_64)
CPU 2 × AMD EPYC 9334 32-Core(共 64 核 / 128 线程)
内存 1.0 TiB(free -h 实测可用约 950 GiB)
GPU AMD Radeon PRO W7900(gfx1100,48 GiB / 49136 MiB VRAM)
驱动 amdgpu 6.14.14,AMD-SMI 26.2.2,VBIOS 00162356
ROCm 7.2.1/opt/rocm-7.2.1
Python 3.10.12
模型 SenseNova/SenseNova-U1.5-8B-MoT,经 ModelScope 下载

先用 amd-smi 确认驱动与 ROCm 版本:

可见:amdgpu version: 6.14.14ROCm version: 7.2.1,GPU 为 Radeon PRO W7900(0x744b,49136 MB 显存)。

CPU / 内存概况(free -h + lscpu):

可见:内存 1.0 TiB;CPU 为 2 路 AMD EPYC 9334(每路 32 核 / 64 线程)。

3.1.2. 实测性能(单卡 48 GB,2048×2048)
指标 数值
注意力后端 torch SDPA(未装 flash-attn,--attn_backend auto 自动使用 SDPA)
8 步冒烟生成耗时 44.8 s/张(模型加载约 20.1 s,吞吐 91.34 tok/s)
50 步正式生成耗时 274.0 s/张(稳态约 5.5 s/步,吞吐 14.95 tok/s)
图像编辑耗时 493.2 s/张(吞吐 8.17 tok/s,图像约 4029 token)
生成阶段峰值显存 allocated 34.87 GiB / reserved 35.82 GiB(CPU RSS 约 14.4 GiB)
运行时 GPU 状态 显存约 36.2 GiB / 48 GiB,GFX-Uti ~100%,233/241 W,66 °C

模型加载完成后开始生成时,用 watch -n 1 amd-smi 观测到的 GPU 状态:

结论:48 GB 单卡可以 --vram_mode full 完整跑通 U1.5-8B-MoT 的 2K 生成;更小显存的卡请用 --vram_mode balanced/low 或 GGUF。


3.2环境安装

3.2.0. 前提
  • ROCm 已安装且驱动正常(amd-smi / rocm-smi 能看到 GPU,见第一节);

  • apt/curl 等基础工具可用,网络可访问 PyPI 与 download.pytorch.org

  • 模型已下载到 ./SenseNova-U1.5-8B-MoT

# 方式一:ModelScope
modelscope download --model SenseNova/SenseNova-U1.5-8B-MoT --local_dir ./SenseNova-U1.5-8B-MoT
# 方式二:HuggingFace
huggingface-cli download SenseNova/SenseNova-U1.5-8B-MoT --local-dir ./SenseNova-U1.5-8B-MoT

关于安装方式: 仓库默认把 torch==2.8.0 / torchvision==0.23.0 固定到 CUDA 12.8 的 index(download.pytorch.org/whl/cu128),仅对 NVIDIA 适用。AMD ROCm 机器要按正常安装步骤重新装 ROCm 版 torch,而不是 uv sync 直接装 cu128 的 NVIDIA 版。本文用 uv 建独立 venv + 从 ROCm index 装 torch,全程不使用任何系统/其它 venv 的“桥接”。

3.2.1. 安装 uv
# 官方安装脚本(推荐)
curl -LsSf https://astral.sh/uv/install.sh | sh
source "$HOME/.local/bin/env"        # 将 uv 加入 PATH
uv --version                          # 0.12.6
​
# 或使用 pip
# python3 -m pip install -U uv
3.2.2. 创建独立虚拟环境
cd /root/sensenova
uv venv .venv --python 3.10            # 与本机系统 Python 3.10 一致
source .venv/bin/activate
python -V                              # Python 3.10.12
3.2.3. 安装 ROCm 版 torch / torchvision(关键一步)
uv pip install torch torchvision --index-url https://download.pytorch.org/whl/rocm7.2

这一步会用带 HIP 后端的 ROCm 7.2 wheel(torch... +rocm7.2)替换仓库默认的 CUDA 12.8 版本。装完后确认 torch.version.hip 非空、torch.cuda.is_available() 为 True(见第 6 步验证)。

若个别传递依赖在 torch index 上找不到,可追加 PyPI 作为补充源:

uv pip install torch torchvision \
--index-url https://download.pytorch.org/whl/rocm7.2 \
--extra-index-url https://pypi.org/simple
3.2.4. 安装项目本体与其余依赖(正常 uv 流程)
# 以可编辑模式安装项目本体(跳过 torch/torchvision,已由第 3 步提供 ROCm 版)
uv pip install -e . --no-deps
​
# 安装其余纯 Python 依赖(与 requirements.txt 中除 torch/torchvision 外的条目一致)
uv pip install "transformers>=4.57.1,<6" "accelerate>=1.1,<2" \
  "huggingface-hub>=0.34,<2" "safetensors>=0.4.3,<1" "sentencepiece==0.2.1" \
  "numpy>=1.24,<3" "pillow==12.0.0" "tqdm==4.67.1" "packaging==25.0" "httpx>=0.27,<1"

为什么 --no-deps pyproject.tomltorch==2.8.0 / torchvision==0.23.0 固定到 cu128 index,直接带依赖安装会被拉回 NVIDIA 版 torch 并覆盖 ROCm 版;所以项目本体用 --no-deps,剩余纯 Python 依赖单独正常安装。

若想省去手写依赖,也可直接从 requirements.txt 排除 torch 两行后安装:

uv pip install -r <(grep -vE '^(torch|torchvision|--|#|$)' requirements.txt)
3.2.5.(可选)GGUF 低显存扩展
uv pip install "gguf>=0.10.0" "diffusers>=0.30.0"
3.2.6. 验证环境
python -c "
import torch, sensenova_u1
print('torch:', torch.__version__, '| hip:', torch.version.hip)
print('cuda available:', torch.cuda.is_available(), '| devices:', torch.cuda.device_count())
x = torch.randn(1024, 1024, device='cuda', dtype=torch.bfloat16)
print('bf16 matmul OK:', float((x @ x).sum()))
"

预期输出(节选):

torch: 2.9.x+rocm7.2.y | hip: 7.2.xxxxx
cuda available: True | devices: 1
bf16 matmul OK: ...

ROCm index 提供多个版本(如 2.9.x / 2.11 / 2.12),具体 torch.__version__ 以后缀 +rocm7.2...torch.version.hip7.2... 即可判断正确;cuda available 在 ROCm 下也会显示为 True(HIP 兼容 CUDA 运行时命名空间),属预期。


3.3运行推理示例

所有示例统一用 .venv 的 Python 启动(source .venv/bin/activate 后直接用 python,或直接用 .venv/bin/python);--model_path 指向本地模型目录。公共参数:

参数 建议值 说明
--attn_backend auto(默认)或 sdpa ROCm 上未装 flash-attn 时自动回退 SDPA,无需改动
--dtype bfloat16(默认) gfx1100 原生支持 bf16
--num_steps 50(默认) 冒烟测试可设 8 快速验证流程
--cfg_scale 4.0(默认) 8-step 蒸馏 LoRA 才用 1.0
--profile 建议开启 打印耗时与峰值显存
3.3.1. 文生图(t2i)

8 步冒烟测试

python examples/t2i/inference.py \
  --model_path ./SenseNova-U1.5-8B-MoT \
  --prompt "A serene mountain lake at sunrise, mist drifting over calm water, snow-capped peaks in the background, photorealistic, high detail" \
  --output outputs/rocm_smoke.png \
  --num_steps 8 --profile

终端输出:模型加载约 20.1 s、8 步生成 44.8 s、吞吐 91.34 tok/s。

生成结果(outputs/rocm_smoke.png,2048×2048):

50 步正式生成(默认 2048×2048,约 4.6 分钟):

python examples/t2i/inference.py \
  --model_path ./SenseNova-U1.5-8B-MoT \
  --prompt "A serene mountain lake at sunrise, mist drifting over calm water, snow-capped peaks in the background, photorealistic, high detail" \
  --output outputs/rocm_full50.png \
  --num_steps 50 --profile

终端输出:50 步生成 274.0 s、吞吐 14.95 tok/s、生成阶段峰值显存 allocated 34.87 GiB / reserved 35.82 GiB。

生成结果(outputs/rocm_full50.png,2048×2048):

批量 / 其他分辨率(训练档位见 examples/README_CN.md,如 16:9 → 2720×1536);带推理的 think 模式可追加 --think --print_think

3.3.2. 视觉理解(VQA)
python examples/vqa/inference.py \
  --model_path ./SenseNova-U1.5-8B-MoT \
  --image examples/vqa/data/images/image1.jpg \
  --question "Describe the image content."

模型会先输出 think 推理再给出描述,实测可正常识别画面主体(城堡、光线、前景等):

批量:--jsonl examples/vqa/data/samples.jsonl --output_dir outputs/vqa/

3.3.3. 图像编辑(editing)

输入图(examples/editing/data/images/1.webp,672×1024):

python examples/editing/inference.py \
  --model_path ./SenseNova-U1.5-8B-MoT \
  --prompt "Change the jacket of the person on the left to bright yellow." \
  --image examples/editing/data/images/1.webp \
  --cfg_scale 4.0 --img_cfg_scale 1.0 --timestep_shift 3.0 --num_steps 50 \
  --output outputs/edited.png --profile

终端输出:1 张输入图自动按 4096 pixel 上限处理,50 步编辑耗时 493.2 s、吞吐 8.17 tok/s、峰值显存 allocated 39.39 GiB / reserved 40.30 GiB。

编辑结果(outputs/edited.png):

3.3.4. 图文交错生成(interleave)
python examples/interleave/inference.py \
  --model_path ./SenseNova-U1.5-8B-MoT \
  --prompt "I want to learn how to cook tomato and egg stir-fry. Please give me a beginner-friendly illustrated tutorial." \
  --resolution "16:9" \
  --output_dir outputs/interleave/ --stem demo_text

模型在生成文本的同时按段落插图(<image 1><image 2> …),文本与图片交替输出:

带输入图交错:--prompt "<image>\n图文交错生成小猫游览故宫的场景" --image examples/interleave/data/images/image0.jpg


3.4显存不够时的降级方案

方案 命令 说明
分层卸载 --vram_mode balanced(或 low / fast 项目自带 layer offload,比 accelerate CPU offload 快;与 --device_map 互斥
GGUF 量化 --gguf_checkpoint /path/x.gguf(需第 5 步的扩展) 社区 Q4/Q8 权重;Q4 + balanced 可在 10–12 GB 显存运行
多卡切分 --device_map auto --max_memory "0=22GiB,1=22GiB" 多 GPU 机器用
降分辨率 / 步数 --width/--height--num_steps 直接降低激活显存与耗时

3.5ROCm 适配说明与已知问题

  1. 官方支持口径:仓库 FAQ 声明官方仅支持 Linux + CUDA;本文是社区级移植路线。推理代码本身是设备无关的,因此 transformers 路径在 ROCm 上可正常运行。

  2. flash-attn:ROCm 上未安装 flash-attn(仓库 pyproject.toml 把它列为可选 [flash] extra),--attn_backend auto 自动回退 torch SDPA(ROCm 版 SDPA 自带 AOTriton/CK 内核),无需任何修改。如介意日志噪音,可显式 --attn_backend sdpa

  3. MIOpen 警告:首次卷积自动调优时可能打印 MIOpen(HIP): Error [EvaluateInvokers] ... invalid configuration argument,这是候选内核淘汰信息,非致命,不影响结果。

  4. 版本对应:仓库默认 pin 的 torch 2.8.0/cu128 仅适用于 NVIDIA;AMD 机器按第二节重新装 +rocm7.2 版 torch 即可,版本号不同属预期。


3.6一页速查

# 环境(一次性)
curl -LsSf https://astral.sh/uv/install.sh | sh && source "$HOME/.local/bin/env"
cd /root/sensenova
uv venv .venv --python 3.10 && source .venv/bin/activate
uv pip install torch torchvision --index-url https://download.pytorch.org/whl/rocm7.2
uv pip install -e . --no-deps
uv pip install "transformers>=4.57.1,<6" "accelerate>=1.1,<2" "huggingface-hub>=0.34,<2" \
  "safetensors>=0.4.3,<1" "sentencepiece==0.2.1" "numpy>=1.24,<3" "pillow==12.0.0" \
  "tqdm==4.67.1" "packaging==25.0" "httpx>=0.27,<1"

# 运行(每次)
python examples/t2i/inference.py \
  --model_path ./SenseNova-U1.5-8B-MoT \
  --prompt "你的提示词" \
  --output outputs/out.png --num_steps 50 --profile

第四章 SenseNova-U1.5 在摩尔线程 MUSA(MTT S4000)上的部署与运行指南

本章记录在国产 GPU 摩尔线程 MTT S4000(MUSA 软件栈)上部署 SenseNova-U1.5-8B-MoT 的完整过程。MUSA 路线使用 torch_musa 提供的 musa 设备类型,仓库代码需要 3 处小补丁(均为设备命名空间 / 内核兼容性问题,不涉及算法逻辑),整体仍属低成本移植。

4.1设备与运行环境

4.1.1. 硬件 / 驱动 / MUSA 一览
类别 实测值
操作系统 Ubuntu 22.04 LTS,内核 5.15.0-105-generic(x86_64)
CPU Intel Xeon Gold 6430
内存 1.0 TB
GPU 摩尔线程 MTT S4000 × 1(PCI vendor 0x1ed5,48 GB GDDR6,实测可用 47.91 GB)
驱动 mtgpu 内核驱动
MUSA toolkit 3.1.0/usr/local/musa-3.1.0,mcc 3.1.0 / mublas 1.6.0 / mufft 1.6.0,2024-09 构建)
torch 2.2.0a0+git8ac9b20(摩尔线程定制构建)
torch_musa 1.3.0+81caf0a
Python 3.10(miniconda u1 环境)
模型 SenseNova/SenseNova-U1.5-8B-MoT

先用 musaInfo 确认 MUSA 环境与显卡型号:

可见:device#0 为 MTT S4000,显存 47.91 GB(100% 空闲),56 个多处理器,核心频率 1.6 GHz,compute capability major 2 / minor 2。MUSA toolkit 版本可查 cat /usr/local/musa/version.json

CPU / 内存概况:

可见:内存 1.0 TB;CPU 为 Intel Xeon Gold 6430(容器分配 15 核)。大内存对 --vram_mode balanced/low 的分层卸载模式非常有利。

4.1.2. 实测性能(单卡 48 GB,2048×2048)

以 4.3 节 2048×2048 文生图任务实测(BF16、SDPA、vram_mode=full、单卡):

指标 8 步冒烟 50 步正式生成
模型加载耗时 8.09 s 8.15 s
加载峰值显存(allocated / reserved) 32.66 / 32.98 GB 32.66 / 32.98 GB
生成耗时(wall) 31.97 s 171.24 s
生成吞吐(图像 token) 128.12 tok/s 23.92 tok/s
生成峰值显存(allocated / reserved) 34.71 / 35.69 GB 34.71 / 35.69 GB

48 GB 显存对 2048×2048 任务余量充足(峰值约 35.7 GB,尚余约 12 GB)。先行参考:BF16 GEMM(8192³ 矩阵乘)实测约 82.5 TFLOPS,达到 S4000 标称 100 TFLOPS BF16 张量算力的约 83%。


4.2环境安装

4.2.0. 前提
  • MUSA 驱动已安装且正常(musaInfo 能看到 GPU);

  • miniconda 可用;网络可访问 PyPI(国内建议走镜像源);

  • 模型已下载到 ./SenseNova-U1.5-8B-MoT

# 方式一:ModelScope(国内推荐)
modelscope download --model SenseNova/SenseNova-U1.5-8B-MoT --local_dir ./SenseNova-U1.5-8B-MoT
# 方式二:HuggingFace
huggingface-cli download SenseNova/SenseNova-U1.5-8B-MoT --local-dir ./SenseNova-U1.5-8B-MoT
  • 版本配套关系(关键)torch_musa 的版本号与其适配的 PyTorch 版本对应,且对 MUSA SDK 有最低版本要求:

torch_musa PyTorch MUSA SDK 最低要求
1.3.0 2.2.0 3.1.x(KUAE 1.3.0,本文环境)
2.0.0 2.2.0 全量支持,新增 2.5.0 高于 3.1(以发布说明为准)
2.7.0 / 2.7.1 2.7.1 以发布说明为准
2.9.0 2.9.0 ≥ 4.3.2
2.9.1 2.9.1 ≥ 5.1.0
2.11.0 2.11 5.1 / 5.2

注意两点:① torch_musa 的版本号跳过了 PyTorch 2.8(从 2.7.1 直接到 2.9.0),仓库默认 pin 的 torch==2.8.0 在 MUSA 上没有对应版本;② 本机 MUSA toolkit 为 3.1.0,只能配套 torch_musa 1.3.0 + torch 2.2.0。如果机器的 MUSA SDK 更新(≥5.1),建议直接选用 torch_musa 2.9.1.post1(torch 2.9.1),算子覆盖更全、性能更好,本文流程同样适用(依赖版本相应替换)。

关于安装方式: 仓库把 torch==2.8.0 / torchvision==0.23.0 固定到 CUDA 12.8 的 index(download.pytorch.org/whl/cu128),仅对 NVIDIA 适用。torch_musa 不在 PyPI 上,只能从摩尔线程官方渠道获取(GitHub Releases 的 wheel、mcconline 镜像仓库,或厂商镜像预装)。本文用 miniconda 建独立环境 u1 + 复用厂商镜像在 base 环境预装的 torch 栈,全程不污染 base 环境。

4.2.1. 创建独立 conda 环境
conda create -n u1 python=3.10 -y

Python 版本需与预编译 torch wheel 的 ABI 一致(此处为 cp310,与镜像自带 Python 3.10.8 相同)。

4.2.2. 安装 torch / torch_musa / torchvision(关键一步)

方式 A(本文采用):镜像已在 base 环境预装 → 复制到新环境

AutoDL 等国产卡实例的镜像通常已在 base conda 预装好配套的 torch / torch_musa / torchvision(本例为 torch 2.2.0 + torch_musa 1.3.0)。直接整包复制到新环境:

SRC=/root/miniconda3/lib/python3.10/site-packages
DST=/root/miniconda3/envs/u1/lib/python3.10/site-packages
for p in torch torch_musa torchvision functorch torchgen \
         torch-*.dist-info torch_musa-*.dist-info torchvision-*.dist-info; do
  cp -a $SRC/$p $DST/
done

方式 B:全新机器 / 自建驱动 → 安装官方 wheel 或 Docker 镜像

# 从 https://github.com/MooreThreads/torch_musa/releases 下载与 MUSA SDK 版本匹配的 wheel
pip install torch-2.2.0*.whl torch_musa-1.3.0*.whl torchvision-0.17.2*.whl
​
# 或直接使用官方容器镜像
docker run -it --privileged --pull always --network=host \
  --env MTHREADS_VISIBLE_DEVICES=all \
  registry.mthreads.com/mcconline/musa-pytorch-release-public:latest /bin/bash

注意:torch_musa 1.3.0 不会import torch 时自动注册,必须显式 import torch_musatorch.musa 命名空间才存在(新版 torch_musa 会自动加载)。4.2.4 的补丁①已处理该问题。

4.2.3. 安装项目本体与其余依赖
# 编辑模式构建需要 hatchling;项目本体跳过依赖解析(防止拉回 cu128 版 torch)
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple hatchling
pip install -e . --no-deps
​
# 其余依赖:torch 2.2 的纯 Python 运行依赖 + 模型推理依赖
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple \
  typing_extensions sympy networkx jinja2 filelock fsspec \
  "numpy>=1.24,<2" pillow requests \
  "transformers>=4.57.1,<5" "accelerate>=1.1,<2" "safetensors>=0.4.3,<1" \
  sentencepiece==0.2.1 tqdm packaging httpx

三个坑:

  1. 为什么 --no-depspyproject.toml 把 torch/torchvision 固定到 cu128 index,带依赖安装会拉回 NVIDIA 版 torch;

  2. transformers 必须 <5:transformers 5.x 要求 torch≥2.5,在 torch 2.2 下会打印 Disabling PyTorch because PyTorch >= 2.5 is required 并禁用模型加载,只剩 tokenizer 功能;仓库声明的 <6 上界在 MUSA + torch 2.2 组合下要收紧为 <5(实测 4.57.6 正常);

  3. torch 2.2 的纯 Python 依赖:新 conda 环境是干净的,需补齐 typing_extensionssympy 等,否则 import torch 直接报错。

4.2.4. MUSA 设备适配补丁

ROCm 路线零代码改动;MUSA 路线需要 3 处小补丁。

补丁① src/sensenova_u1/utils/accel.py — 注册 musa 设备类型

仓库的设备抽象层原本只认 ("cuda", "xpu")musa 设备会被 require_accelerator() 拒绝。改动:SUPPORTED_DEVICE_TYPES 加入 "musa"accel_module() 返回 torch.musabest_available_device() 按 CUDA → MUSA → XPU → CPU 顺序选择;并在模块顶部显式 import torch_musa(老版本不自动注册):

+# Register Moore Threads MUSA support when torch_musa is installed. Older
+# torch_musa releases only expose ``torch.musa`` after an explicit import.
+try:  # pragma: no cover - environment dependent
+    import torch_musa  # noqa: F401
+except ImportError:
+    pass
+
-SUPPORTED_DEVICE_TYPES: tuple[str, ...] = ("cuda", "xpu")
+SUPPORTED_DEVICE_TYPES: tuple[str, ...] = ("cuda", "musa", "xpu")
​
 def accel_module(device: torch.device):
     if device.type == "cuda":
         return torch.cuda
+    if device.type == "musa":
+        if not hasattr(torch, "musa"):
+            raise RuntimeError("device type 'musa' requires the torch_musa package")
+        return torch.musa
     if device.type == "xpu":
         return torch.xpu

is_available / best_available_device / empty_cache / synchronize / manual_seed_all 同步加入 musa 分支,完整 diff 见仓库 git diff src/sensenova_u1/utils/accel.py。)

补丁①还包含一个 torch.cat 垫片:torch_musa 1.3.0 将 1-D 空张量numel == 0)与高维张量拼接时报 Wrong Cat dim 错误,而标准 PyTorch 会静默忽略这类操作数——transformers 的 DynamicCache 懒初始化(torch.cat([torch.tensor([]), key_states], dim=-2))恰好依赖该语义,不打垫片会在首次推理时直接报错。补丁在 MUSA 可用时包装 torch.cat,过滤 1-D 空张量操作数以复现标准行为:

+if hasattr(torch, "musa") and torch.musa.is_available():  # pragma: no cover
+    _orig_cat = torch.cat
+
+    def _cat_ignore_empty_1d(tensors, dim=0, *args, **kwargs):
+        filtered = [t for t in tensors if not (t.dim() == 1 and t.numel() == 0)]
+        return _orig_cat(filtered if filtered else tensors, dim, *args, **kwargs)
+
+    torch.cat = _cat_ignore_empty_1d

补丁② src/sensenova_u1/utils/profiler.py — 显存统计泛化到加速卡模块

--profile 的峰值显存统计原本硬编码 torch.cuda.*,改为通过补丁①的 accel_module() 分发(torch.musa.memory_allocated / max_memory_allocated / max_memory_reserved 等 API 与 CUDA 同名),_sync() 同步计时同理。改动后 --profile 在 MUSA 上可正常打印显存占用。

补丁③ src/sensenova_u1/models/neo_unify/modeling_qwen3.py — SDPA scale 与 block-causal 掩码兼容

torch_musa 1.3.0 的 scaled_dot_product_attention 只接受默认 scale 值 1/sqrt(head_dim),显式传入其它值会抛 RuntimeError: Now torch_musa only allows explicit value of scale parameter...。而 Qwen3 注意力的 self.scaling 恰好等于该默认值,因此补丁为:与默认值相等时不显式传 scale,并把异常回退分支从 TypeError 扩展到 (TypeError, RuntimeError)

+    # Moore Threads' torch_musa SDPA only accepts the default scale
+    # (1/sqrt(head_dim)); drop an explicit scale equal to the default so the
+    # same call works on MUSA devices.
+    if softmax_scale is not None:
+        head_dim = q.shape[-1]
+        if head_dim > 0 and abs(softmax_scale - head_dim ** -0.5) < 1e-12:
+            softmax_scale = None
+
     try:
         out = torch.nn.functional.scaled_dot_product_attention(
             q_bhsd, k_bhsd, v_bhsd,
             dropout_p=dropout_p, is_causal=causal, scale=softmax_scale,
         )
-    except TypeError:
+    except (TypeError, RuntimeError):

同文件第二处改动在 create_block_causal_mask:原实现用 CPU 0 维标量张量torch.where 的填充值(CUDA 会自动提升这类操作数),torch_musa 不接受——本章首次冒烟测试正是在此失败(RuntimeError: t == kMUSA INTERNAL ASSERT FAILED at ".../csrc/core/GuardImpl.h":29)。修复为在掩码同设备上构造填充标量:

-    return torch.where(mask[None, None, :, :] > 0, torch.tensor(0.0), torch.tensor(float('-inf')))
+    # Build the fill scalars on the mask's device: torch_musa does not accept
+    # CPU scalar tensors in torch.where (CUDA auto-promotes them).
+    return torch.where(
+        mask[None, None, :, :] > 0,
+        torch.tensor(0.0, device=index.device),
+        torch.tensor(float('-inf'), device=index.device),
+    )
4.2.5. (可选)GGUF 低显存扩展
pip install "gguf>=0.10.0" "diffusers>=0.30.0"
4.2.6. 验证环境
python -c "
import torch, torch_musa, transformers
import sensenova_u1
from sensenova_u1.utils.accel import best_available_device
print('torch:', torch.__version__, '| torch_musa:', torch_musa.__version__)
print('transformers:', transformers.__version__)
print('musa available:', torch.musa.is_available(), '|', torch.musa.get_device_name(0))
print('best device:', best_available_device())
x = torch.randn(1024, 1024, device='musa', dtype=torch.bfloat16)
print('bf16 matmul OK:', float((x @ x).float().sum()))
"

算子级验证(建议跑一遍,覆盖本模型实际用到的关键算子):

import torch, torch_musa, time
import torch.nn.functional as F
dev = "musa"
# 1) 真实注意力形状:S≈4200(4096 图像 token + 文本),Hq=32/Hkv=8,D=128,bf16
S = 4200
q = torch.randn(1, S, 32, 128, device=dev, dtype=torch.bfloat16)
k = torch.randn(1, S, 8, 128, device=dev, dtype=torch.bfloat16).repeat_interleave(4, dim=2)
v = torch.randn(1, S, 8, 128, device=dev, dtype=torch.bfloat16).repeat_interleave(4, dim=2)
o = F.scaled_dot_product_attention(q.transpose(1,2), k.transpose(1,2), v.transpose(1,2))
torch.musa.synchronize(); print("sdpa plain ok", tuple(o.shape))
# 2) block-causal float mask(create_block_causal_mask 的输出形态)
# ……(构造 (1,1,L,L) 的 0/-inf mask 后 attn_mask= 传入 SDPA,见仓库验证脚本)
# 3) U1.5 ConvDecoder 关键算子:PixelShuffle + 3x3 Conv
y = torch.nn.Conv2d(384, 384, 3, padding=1, device=dev, dtype=torch.bfloat16)(
    torch.pixel_shuffle(torch.randn(1, 1536, 64, 64, device=dev, dtype=torch.bfloat16), 2))
torch.musa.synchronize(); print("pixelshuffle+conv ok", tuple(y.shape))
# 4) BF16 GEMM 吞吐
a = torch.randn(8192, 8192, device=dev, dtype=torch.bfloat16)
b = torch.randn(8192, 8192, device=dev, dtype=torch.bfloat16)
t0 = time.time(); n = 10
for _ in range(n): c = a @ b
torch.musa.synchronize(); dt = (time.time() - t0) / n
print(f"bf16 GEMM 8k^3: {dt*1000:.1f} ms -> {2*8192**3/dt/1e12:.1f} TFLOPS")

实测输出:

sdpa plain ok (1, 32, 4200, 128)
sdpa block-causal mask ok (1, 32, 4200, 128)
pixelshuffle+conv ok (1, 384, 128, 128)
bf16 GEMM 8k^3: 13.3 ms -> 82.5 TFLOPS

四项全过:普通 SDPA、block-causal 掩码 SDPA(生成路径的实际用法)、U1.5 解码器的 PixelShuffle+卷积、BF16 GEMM(82.5 TFLOPS,约为标称 100 TFLOPS 的 83%)。


4.3运行推理示例

本章验证聚焦文生图(8 步冒烟 + 50 步正式生成,实测数据与结果图见 4.3.1)。以下命令与上一章一致,--device 无需显式指定:补丁①生效后 best_available_device() 会自动选择 musa(也可显式 --device musa)。

公共参数建议:

参数 建议值 说明
--attn_backend sdpa MUSA 无 flash-attn;auto 会自动回退,显式指定更直观
--dtype bfloat16(默认) S4000 原生支持 bf16 张量算力
--num_steps 50(默认) 冒烟测试可设 8 快速验证流程
--cfg_scale 4.0(默认) 8-step 蒸馏 LoRA 才用 1.0
--profile 建议开启 打印耗时与峰值显存(补丁②已支持 MUSA)
4.3.1. 文生图(t2i)

8 步冒烟测试

python examples/t2i/inference.py \
  --model_path ./SenseNova-U1.5-8B-MoT \
  --prompt "A serene mountain lake at sunrise, mist drifting over calm water, snow-capped peaks in the background, photorealistic, high detail" \
  --output outputs/musa_smoke.png \
  --num_steps 8 --attn_backend sdpa --profile

50 步正式生成

python examples/t2i/inference.py \
  --model_path ./SenseNova-U1.5-8B-MoT \
  --prompt "A serene mountain lake at sunrise, mist drifting over calm water, snow-capped peaks in the background, photorealistic, high detail" \
  --output outputs/musa_full50.png \
  --num_steps 50 --attn_backend sdpa --profile

实测结果--profile 输出,2048×2048、4096 图像 token):

================================================================
Profile summary
================================================================
  config              : vram_mode=full, fast_vram_fraction=0.9,
                        fast_vram_headroom_gib=2.0, fast_activation_reserve_gib=4.0,
                        attn_backend=sdpa, dtype=bfloat16
  model load          :    8.090 s
  load peak memory    : allocated 32.66 GiB, reserved 32.98 GiB, cpu RSS 13.79 GiB
  generations         : 1 call(s), 1 image(s) total, 31.971 s wall
  avg per image       :   31.971 s
  image tokens        : patch_size=32, avg 4096 tok/image (4096)
  throughput          :   128.12 tok/s
  generation peak mem : allocated 34.71 GiB, reserved 35.69 GiB, cpu RSS 13.79 GiB
================================================================
8 步冒烟 50 步正式
生成耗时(wall) 31.97 s 171.24 s
吞吐 128.12 tok/s 23.92 tok/s
峰值显存(allocated / reserved) 34.71GB 同左

8 步冒烟生成结果:

50 步正式生成结果:

50 步成图的构图完整度与细节明显优于 8 步;两者峰值显存一致(34.71 GiB),48 GB 单卡余量约 12 GiB。耗时比 171.24 / 31.97 ≈ 5.36,与步数比(50/8 = 6.25,扣除 VAE 解码等固定开销后近似线性)相符,说明扩散步占总耗时主导、无额外同步瓶颈。

4.3.2. 其余示例(VQA / 编辑 / 交错生成)

这三类示例的命令与上一章完全一致(同样追加 --attn_backend sdpa 即可),在 MUSA 上的差异仅 4.2.4 的 3 处补丁;本章验证聚焦文生图,不再逐一展开实测,命令模板供参考:

# 视觉理解 VQA
python examples/vqa/inference.py --model_path ./SenseNova-U1.5-8B-MoT \
  --image examples/vqa/data/images/image1.jpg --question "Describe the image content." \
  --attn_backend sdpa --profile
​
# 图像编辑 editing
python examples/editing/inference.py --model_path ./SenseNova-U1.5-8B-MoT \
  --prompt "Change the jacket of the person on the left to bright yellow." \
  --image examples/editing/data/images/1.webp \
  --cfg_scale 4.0 --img_cfg_scale 1.0 --timestep_shift 3.0 --num_steps 50 \
  --output outputs/edited.png --attn_backend sdpa --profile
​
# 图文交错生成 interleave(多图峰值显存更高,建议配合 4.4 的降级方案)
python examples/interleave/inference.py --model_path ./SenseNova-U1.5-8B-MoT \
  --prompt "I want to learn how to cook tomato and egg stir-fry. Please give me a beginner-friendly illustrated tutorial." \
  --resolution "16:9" --output_dir outputs/interleave/ --stem demo_text \
  --attn_backend sdpa --profile

4.4显存不够时的降级方案

方案 命令 说明
分层卸载 --vram_mode balanced(或 low / fast 项目自带 layer offload,比 accelerate CPU offload 快;与 --device_map 互斥。本机 1 TiB 内存下该方案余量很大
GGUF 量化 --gguf_checkpoint /path/x.gguf(需 4.2.5 的扩展) 社区 Q8 权重约 19.9 GB;Q4 + balanced 可在 10–12 GB 显存运行
多卡切分 --device_map auto --max_memory "0=22GiB,1=22GiB" S4000 支持 MTLink + MCCL(torch_musa 分布式后端为 mccl);本实例仅透出单卡,未验证
降分辨率 / 步数 --width/--height--num_steps 直接降低激活显存与耗时

4.5MUSA 适配说明与已知问题

  1. 官方支持口径:仓库 FAQ 声明官方仅支持 Linux + CUDA;本章为社区级移植路线。推理代码本身基本设备无关,MUSA 上仅需 4.2.4 的 3 处小补丁(均向后兼容 CUDA 路线,可提交上游)。

  2. flash-attn: 无 flash-attn,统一走 --attn_backend sdpa。torch_musa 1.3.0 的 SDPA 由 muDNN 支撑;新版 torch_musa(≥2.9.1)已支持 Flash SDPA(含 headdim≥256),升级后可望进一步提速。

  3. SDPA scale 限制:torch_musa 1.3.0 仅接受默认 scale=1/sqrt(head_dim),显式传其它值会抛 RuntimeError。本模型 Qwen3 注意力的缩放恰为默认值,补丁③已处理;若未来引入非默认 scale 的注意力变体,需关注该限制(新版 torch_musa 已放宽)。

  4. torch 版本空档:仓库默认 torch==2.8.0,而 torch_musa 版本号跳过 PyTorch 2.8(2.7.1 → 2.9.0)。MUSA SDK 3.1.0 只能配 torch_musa 1.3.0 + torch 2.2.0;SDK ≥5.1 的机器建议直接上 torch_musa 2.9.1.post1 + torch 2.9.1(算子覆盖"全量 CUDA 对齐",且支持 torch.compile)。

  5. transformers 版本:必须 <5(5.x 要求 torch≥2.5,在 torch 2.2 下会禁用 PyTorch)。

  6. 老版 torch_musa 需显式 importtorch.musa 命名空间在 import torch_musa 之后才存在(新版自动加载),补丁①已在 accel.py 顶部处理。

  7. torchvision.io 警告Failed to load image Python extension(缺 libjpeg/libpng)不影响本仓库示例(用 PIL 读图),可忽略;如需 torchvision.ioapt install libjpeg-dev libpng-dev 后重装。

  8. 数值一致性:建议以相同种子对比 NVIDIA 与 MUSA 的输出;仓库的 --profile 与固定种子(默认 42)便于复现对照。

  9. torch.cat 1-D 空张量:torch_musa 1.3.0 将 1-D 空张量(numel == 0)与高维张量拼接时报 Wrong Cat dim(CUDA / 标准 PyTorch 静默忽略该操作数),transformers DynamicCache 懒初始化会触发;补丁①的 shim 复现标准语义。

  10. torch.where CPU 标量张量:torch_musa 的 torch.where 不接受 CPU 0 维标量张量作操作数(CUDA 自动提升),create_block_causal_mask 原实现因此在 GuardImpl.h 触发内部断言;补丁③第二处改为设备侧构造填充标量。


4.6一页速查

# ===== 环境(一次性) =====
conda create -n u1 python=3.10 -y
​
# torch 栈:方式 A(镜像已预装,复制到新环境)
SRC=/root/miniconda3/lib/python3.10/site-packages
DST=/root/miniconda3/envs/u1/lib/python3.10/site-packages
for p in torch torch_musa torchvision functorch torchgen \
         torch-*.dist-info torch_musa-*.dist-info torchvision-*.dist-info; do
  cp -a $SRC/$p $DST/
done
# torch 栈:方式 B(官方 wheel,版本须与 MUSA SDK 配套)
# pip install torch-2.2.0*.whl torch_musa-1.3.0*.whl torchvision-0.17.2*.whl
​
conda activate u1
cd /root/autodl-tmp/SenseNova-U1
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple hatchling
pip install -e . --no-deps
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple \
  typing_extensions sympy networkx jinja2 filelock fsspec \
  "numpy>=1.24,<2" pillow requests \
  "transformers>=4.57.1,<5" "accelerate>=1.1,<2" "safetensors>=0.4.3,<1" \
  sentencepiece==0.2.1 tqdm packaging httpx
​
# 打 3 个 MUSA 适配补丁(见 4.2.4):
#   ① src/sensenova_u1/utils/accel.py          注册 musa 设备 + torch.cat 空张量 shim
#   ② src/sensenova_u1/utils/profiler.py       显存统计泛化
#   ③ src/sensenova_u1/models/neo_unify/modeling_qwen3.py   SDPA scale + block-causal 掩码设备兼容
​
# 验证
python -c "import torch, torch_musa; print(torch.musa.is_available(), torch.musa.get_device_name(0))"
​
# ===== 运行(每次) =====
python examples/t2i/inference.py \
  --model_path ./SenseNova-U1.5-8B-MoT \
  --prompt "你的提示词" \
  --output outputs/out.png --num_steps 50 --attn_backend sdpa --profile

第五章 SenseNova-U1 在低资源本机(8GB 显存 + 16GB 内存)上的部署与运行指南

适用场景:在 8GB 显存的消费级 GPU + 16GB 系统内存的 Linux 笔记本上,从零部署 SenseNova-U1 文生图推理并跑通验证案例。本章记录一次完整落地部署的真实环境、安装流程、案例运行与实测结果

5.1设备与运行环境

5.1.1. 硬件 / 驱动 / 软件一览
类别 实测值
操作系统 Ubuntu 26.04 LTS,内核 7.0.0-14-generic(x86_64)
CPU Intel Core i7‑14700HX
内存 16 GB
磁盘 1.8 TB
GPU NVIDIA GeForce RTX 4070 Laptop GPU(8 GB )
驱动 NVIDIA 595.84(支持 CUDA 13.2)
Python 3.11.16(uv 管理的 venv)
torch / torchvision 2.8.0+cu128 / 0.23.0+cu128
关键依赖 transformers 5.15.0、diffusers 0.37.1、gguf 0.19.0、accelerate 1.14.0、numpy 2.2.0、pillow 12.0.0
源码 SenseNova-U1 main@8f354e0(Apache 2.0)
模型 SenseNova-U1-8B-MoT-8step Q4_K_S GGUF(13.9 GB,社区量化,sha256 已校验)
5.1.2. 实测性能(8 GB 显存 + 16 GB 内存,1024×1024)
指标 数值
注意力后端 torch SDPA--attn_backend sdpa 显式指定)
模型加载耗时 4.2 s(mmap 零拷贝加载后 CPU RSS 仅 5.71 GiB)
8 步生成耗时 759.0 s/张(1024×1024,逐层 CPU↔GPU 搬运是瓶颈)
生成吞吐 1.35 tok/s(平均 1024 token/张)
生成峰值显存 allocated 2.95 GiB / reserved 3.11 GiB(~3.3 GiB / 8 GiB,余量充足)
生成峰值内存 CPU RSS 8.28 GiB(低于 10 G cgroup 护栏)
运行时系统可用内存 ≥ 8 GB,桌面 / 其他应用无感知

资源约束与方案选择(为什么需要改造):

方案 需求 本机结果
bf16 全量模型 ≥ 36 GB 显存 不可行
GGUF Q4_K_S(13.9 GB),官方默认加载 权重整体拷入内存并 pin 锁定(~14 GB RAM) 16 GB 内存下必然卡死系统
GGUF + mmap 零拷贝改造(本文方案) 权重按需调页、内核自动回收 加载后仅 5.7 GB,可行

结论:8 GB 显存 + 16 GB 内存的消费级机器,走「GGUF 量化 + mmap 零拷贝 + 层卸载」路线可以完整跑通 U1 8-step Q4_K_S 的文生图;生成峰值显存约 3.3 GiB、内存峰值不超 10 G 护栏,系统全程流畅。


5.2环境安装

5.2.0. 前提
nvidia-smi        # 能看到 GPU
python3 --version # >= 3.10
systemd-run --user --scope -p MemoryMax=100M -- /bin/true
# 输出 "Running as unit: ..." → 内存护栏依赖的用户级 cgroup 可用
5.2.1. 安装 uv
# 官方安装脚本(推荐)
curl -LsSf https://astral.sh/uv/install.sh | sh
uv --version
5.2.2. 获取代码与安装依赖(含 GGUF 扩展)
git clone https://github.com/OpenSenseNova/SenseNova-U1.git
cd SenseNova-U1
​
# 安装(含 gguf 扩展;国内加 HF_ENDPOINT 走镜像)
HF_ENDPOINT=https://hf-mirror.com uv sync --extra gguf

--extra gguf 扩展提供量化推理所需的 diffusers / gguf 权重解析(diffusers 0.37.1、gguf 0.19.0)。8 GB 显存必须走 GGUF 路线:bf16 全量权重需要 ≥ 36 GB 显存(见 5.1.2 资源约束分析)。

5.2.3. 应用低内存补丁(关键一步)
git apply lowram_patches.diff    # 仓库自带的已验证补丁
​
# 验证(须 24 passed)
uv pip install pytest
.venv/bin/python -m pytest tests/test_layer_offload.py -q

补丁内容(默认关闭、环境变量开启,不改变上游默认行为):

环境变量 功能
U1_GGUF_MMAP=1 权重 mmap 零拷贝加载(核心:加载内存 14 G → 5.7 G)
U1_LAYER_OFFLOAD_DISABLE_PIN=1 层卸载跳过 pin_memory 物理锁定
U1_LAYER_OFFLOAD_UNPINNED_FALLBACK=1 锁定失败时降级为普通内存而非崩溃

为什么要打补丁: 官方默认 GGUF 加载会把权重整体拷入内存并 pin 锁定(~14 GB RAM),16 GB 内存的机器必然卡死系统;mmap 零拷贝按需调页、内核自动回收,加载后 RSS 仅 5.7 GB。

5.2.4. 下载模型权重(13.9 GB)
mkdir -p models && cd models

ModelScope

curl -L -C - -o SenseNova-U1-8B-MoT-8step-Q4_K_S.gguf \
  "https://modelscope.cn/api/v1/models/smthem/SenseNova-U1-8B-MoT/repo?Revision=master&FilePath=SenseNova-U1-8B-MoT-8step-Q4_K_S.gguf"
5.2.5. 补齐配套资源文件

GGUF 权重不含 config/tokenizer,需从官方 8step-preview 仓库补齐 8 个小文件:

mkdir -p SenseNova-U1-8B-MoT-8step-preview && cd SenseNova-U1-8B-MoT-8step-preview
for f in config.json tokenizer_config.json special_tokens_map.json \
         added_tokens.json vocab.json merges.txt chat_template.jinja \
         model.safetensors.index.json; do
  curl -sL -o "$f" \
    "https://hf-mirror.com/sensenova/SenseNova-U1-8B-MoT-8step-preview/resolve/main/$f"
done
cd ../..

⚠️ curl 必须带 -L 跟随重定向,否则保存下来的是 307 跳转页而非文件。可用 head -c 100 config.json 抽查:应是 JSON 而非 HTML。

5.2.6. 完整性校验
sha256sum models/SenseNova-U1-8B-MoT-8step-Q4_K_S.gguf
# f7ca062ce4f2c8ee09aa624d2158620eeaab7afb8ce8e4e9d23987738f2b8930
​
stat -c%s models/SenseNova-U1-8B-MoT-8step-Q4_K_S.gguf
# 13881801248
5.2.7. 安装启动脚本

创建 run_u1.sh,放在仓库根目录并赋权:

#!/bin/bash
# SenseNova-U1 低内存推理启动器(8GB 显存 / 16GB 内存机器专用)
# 用法:
#   ./run_u1.sh "你的提示词"                    # 默认 1024x1024
#   ./run_u1.sh "提示词" 2048 2048              # 指定宽高
#   ./run_u1.sh "提示词" 2720 1536 my_out.png   # 指定输出文件
set -euo pipefail
​
REPO=/home/nnly29/SenseNova-U1
PROMPT="${1:?用法: ./run_u1.sh \"提示词\" [宽] [高] [输出.png]}"
W="${2:-1024}"; H="${3:-1024}"
OUT="${4:-$REPO/outputs_lowram/gen_$(date +%m%d_%H%M%S).png}"
​
# 分辨率档位检查(与官方 SUPPORTED_RESOLUTIONS 对齐)
case "$W"x"$H" in
  2048x2048|2720x1536|1536x2720|2496x1664|1664x2496|2368x1760|1760x2368|2880x1440|1440x2880|3456x1152|1152x3456) ;;
  *) echo "[提示] ${W}x${H} 不在官方训练档位内,质量可能下降;推荐 2048x2048 或 2720x1536" >&2 ;;
esac
​
mkdir -p "$(dirname "$OUT")"
​
# cgroup 内存护栏: 超过上限只杀推理进程,不会拖死系统
exec systemd-run --user --scope \
  -p MemoryHigh=7G -p MemoryMax=10G -p MemorySwapMax=256M \
  --setenv=U1_GGUF_MMAP=1 \
  --setenv=U1_LAYER_OFFLOAD_DISABLE_PIN=1 \
  --setenv=U1_LAYER_OFFLOAD_UNPINNED_FALLBACK=1 \
  --setenv=HF_HUB_OFFLINE=1 \
  --setenv=PYTHONUNBUFFERED=1 \
  "$REPO/.venv/bin/python" "$REPO/examples/t2i/inference.py" \
    --model_path "$REPO/models/SenseNova-U1-8B-MoT-8step-preview" \
    --gguf_checkpoint "$REPO/models/SenseNova-U1-8B-MoT-8step-Q4_K_S.gguf" \
    --vram_mode low \
    --prompt "$PROMPT" \
    --width "$W" --height "$H" \
    --cfg_scale 1.0 --cfg_norm none --timestep_shift 3.0 --num_steps 8 \
    --seed 42 --attn_backend sdpa --profile \
    --output "$OUT"
chmod +x run_u1.sh

脚本内置三层保障:

  1. cgroup 内存护栏MemoryHigh=7G(软限开始回收)、MemoryMax=10G(硬限只杀进程)、MemorySwapMax=256M(防 swap 抖动)——任何异常都不会拖死系统

  2. 三个内存优化环境变量(见 5.2.3 表格);

  3. 离线运行HF_HUB_OFFLINE=1),推理过程不依赖网络。

5.2.8.(可选)注册 nova生图 快捷命令

将以下函数追加到 ~/.bashrc 并重开终端。之后任意目录nova生图 即可自动 cd 到仓库、显示状态与用法提示(防遗忘)、带提示词直接启动生图。

# ═══ nova 生图助手(SenseNova-U1 低内存推理)═══
nova生图() {
  cd "$HOME/SenseNova-U1" || { echo "❌ 找不到 ~/SenseNova-U1"; return 1; }
  if [ $# -eq 0 ]; then
    echo "═══════ nova 生图助手 ═══════"
    if [ -f models/SenseNova-U1-8B-MoT-8step-Q4_K_S.gguf ]; then
      echo "✅ 模型文件就绪 (13.9GB Q4_K_S 已校验)"
    else
      echo "❌ 模型文件缺失,需要重新下载后再用"
    fi
    echo ""
    echo "启动生图: ./run_u1.sh \"你的提示词\""
    echo "带尺寸:   ./run_u1.sh \"你的提示词\" 2048 2048"
    echo "示例:     nova生图 \"一只橘猫在窗台晒太阳\""
    echo "(等效于:  ./run_u1.sh \"一只橘猫在窗台晒太阳\")"
    return 0
  fi
  echo "🚀 正在启动生图(内存护栏 MemoryMax=10G 已开启,预计约 12 分钟/张)..."
  ./run_u1.sh "$@"
  local rc=$?
  if [ $rc -eq 0 ]; then
    echo "✅ 生图完成,图片在 ~/SenseNova-U1/outputs_lowram/"
  else
    echo "❌ 生图失败 (exit $rc),可查看上方日志定位原因"
  fi
  return $rc
}

5.2.9. 验证环境
.venv/bin/python -c "import torch; print(torch.__version__, torch.cuda.is_available())"
# 期望输出: 2.8.0+cu128 True

torch 为 cu128 构建,此处返回 True 即说明 CUDA 链路可用;配合 nvidia-smi 可见 GPU,环境就绪。推理时脚本内置 HF_HUB_OFFLINE=1,无需联网。


5.3运行推理示例

所有示例统一通过 run_u1.sh 启动(内置 cgroup 内存护栏与三个 U1_* 环境变量);--model_path 指向本地配套资源目录,--gguf_checkpoint 指向量化权重。公共参数:

参数 建议值 说明
--vram_mode low 8 GB 显存用分层卸载;显存富余可改 balanced 提速(异步预取)
--attn_backend sdpa 显式使用 torch SDPA,避免回退争议
--num_steps 8 8step 蒸馏模型专用步数,勿随意调高
--cfg_scale 1.0 8-step 蒸馏权重使用 1.0
--profile 建议开启 打印耗时与峰值显存
5.3.1. 文生图(t2i)验证案例

使用官方 README 的 GGUF 示例提示词运行文生图:

./run_u1.sh "A male peacock trying to attract a female"
# 或使用官方训练档位分辨率(质量更好,约 25-40 分钟)
./run_u1.sh "A male peacock trying to attract a female" 2048 2048

实测终端输出:量化张量全部解析、592 个在线反量化层激活,全程约 13 分钟(模型加载仅 4.2 秒,其余为 8 步去噪采样的逐层 CPU↔GPU 搬运):

Running as unit: run-xxxxx.scope; invocation ID: ...
[attn] backend='sdpa' (effective='sdpa')
[gguf] loading quantized checkpoint from .../SenseNova-U1-8B-MoT-8step-Q4_K_S.gguf
[gguf] parsed 1116 tensors                      ← 量化张量全部解析成功
[gguf] 592 GGUFLinear modules active            ← 592 个在线反量化层激活
[warn] (1024x1024) is outside the trained resolution set; ...
[saved] /home/nnly29/SenseNova-U1/outputs_lowram/peacock_1024.png
5.3.2. 生成结果

产物为 outputs_lowram/peacock_1024.png,1024×1024 PNG(2.3 MB);内容为一只开屏的雄性蓝孔雀与一只侧立的雌孔雀,羽毛眼状斑纹与背景虚化自然,完全符合提示词语义("A male peacock trying to attract a female")。

可见:画面主体与提示词完全一致。该图为本次部署验证案例的实际产出(Q4_K_S 量化 + vram_mode low + 8 步采样),未做任何后期处理。

5.3.3. 性能档案(--profile 输出原文)
================================================================
Profile summary
================================================================
  config              : vram_mode=low, attn_backend=sdpa, dtype=bfloat16, gguf=...Q4_K_S.gguf
  model load          :    4.238 s
  load peak memory    : cpu RSS 5.71 GiB        ← mmap 加载生效的标志
  generations         : 1 call(s), 1 image(s) total, 759.000 s wall
  avg per image       :  759.000 s
  image tokens        : patch_size=32, avg 1024 tok/image (1024)
  throughput          :     1.35 tok/s
  generation peak mem : allocated 2.95 GiB, reserved 3.11 GiB, cpu RSS 8.28 GiB
5.3.4. 资源占用汇总(实测)
指标 数值 对照
加载后内存 5.71 GiB RSS 官方默认方式需 ~14 GB,本方案降 60%
生成期内存峰值 8.28 GiB RSS 低于 10 G 护栏,系统全程流畅
显存峰值 ~3.3 GiB / 8 GiB 余量充足
单张耗时 759 s(1024×1024,8 步) vram_mode low 逐层搬运是瓶颈
生成中系统可用内存 ≥ 8 GB 桌面 / 其他应用无感知

5.4日常使用

nova生图                          # 显示状态与用法提示
nova生图 "一只橘猫在窗台晒太阳"      # 生图,约 12 分钟
nova生图 "提示词" 2048 2048        # 官方训练档位,质量最佳

推荐分辨率(官方训练档位):2048x20482720x1536(16:9)、2496x1664(3:2)、2368x1760(4:3)、2880x1440(2:1)、3456x1152(3:1)。非档位分辨率可用但质量会下降(运行时自动提示)。

其他调参(改 run_u1.sh 内对应行):

参数 当前值 说明
--seed 42 换随机效果
--vram_mode low 显存富余可改 balanced 提速(异步预取)
--num_steps 8 8step 蒸馏模型专用步数,勿随意调高

5.5低资源适配说明与已知问题

  1. 方案定位:官方 bf16 全量权重需 ≥ 36 GB 显存;本章是社区级低资源路线——「Q4_K_S 量化 + mmap 零拷贝 + 层卸载」让 8 GB 显存 + 16 GB 内存的机器跑通,且不改变上游默认行为(补丁全部由环境变量开启)。

  2. 加载内存U1_GGUF_MMAP=1 开启后,加载 RSS 从 ~14 GB 降至 5.7 GB;--profile 输出中 load peak memory: cpu RSS 5.71 GiB 即为生效标志。

  3. pin_memory:可用内存不足以页锁定时会打印 pin_memory failed 警告,属预期降级(性能略降可继续),不会拖死系统。

  4. 推理耗时vram_mode low 的逐层 CPU↔GPU 搬运是瓶颈,1024×1024 约 13 分钟/张、2048×2048 约 25–40 分钟/张,属正常水平。

  5. 离线运行:脚本内置 HF_HUB_OFFLINE=1,推理不依赖网络;如遇 HF 网络超时,先确认该项生效。

故障排查速查:

现象 原因 处理
sha256 校验不过 下载不完整/被跳转页污染 删除重下;确认 curl 带 -L
下载速度 KB/s 级 hf-mirror 限流 换 ModelScope 源(5.2.4 方式 A)
IndexError in layer_offload 补丁未应用或不完整 重新 git apply lowram_patches.diff
内存吃满/系统卡顿 三个 U1_* 环境变量未生效 确认通过 run_u1.sh(或附录 B 函数)启动
pin_memory failed 警告 可用内存不足以页锁定 属预期降级,性能略降可继续
HF 网络超时 推理时未离线 确认 HF_HUB_OFFLINE=1(脚本已内置)
提示分辨率不在训练档位 非标准宽高 换 5.4 节列出的官方档位

5.6一页速查

# 环境(一次性)
curl -LsSf https://astral.sh/uv/install.sh | sh
git clone https://github.com/OpenSenseNova/SenseNova-U1.git && cd SenseNova-U1
HF_ENDPOINT=https://hf-mirror.com uv sync --extra gguf
git apply lowram_patches.diff
​
mkdir -p models && cd models
curl -L -C - -o SenseNova-U1-8B-MoT-8step-Q4_K_S.gguf \
  "https://modelscope.cn/api/v1/models/smthem/SenseNova-U1-8B-MoT/repo?Revision=master&FilePath=SenseNova-U1-8B-MoT-8step-Q4_K_S.gguf"
sha256sum SenseNova-U1-8B-MoT-8step-Q4_K_S.gguf
# f7ca062ce4f2c8ee09aa624d2158620eeaab7afb8ce8e4e9d23987738f2b8930
cd ..
​
# 补齐 8 个 config/tokenizer 小文件(见 5.2.5),安装 run_u1.sh(附录 A)并 chmod +x
​
# 运行(每次)
./run_u1.sh "你的提示词"                # 默认 1024x1024,约 13 分钟
./run_u1.sh "你的提示词" 2048 2048      # 官方训练档位,质量最佳

第六章 SenseNova-U1.5 在华为昇腾 910B(NPU)上的部署与运行指南

6.1设备与运行环境

6.1.1. 硬件 / 驱动 / CANN 一览
类别 实测值
操作系统 Ubuntu 22.04.5 LTS(容器环境,aarch64 / 鲲鹏)
CPU / 内存 20 核 / 2.0 TB(free -h
NPU 华为昇腾 910B264 GB HBM(65536 MB,系统常驻约 3.2 GB)
驱动 npu-smi 25.2.1
CANN 8.5.1(含 nnal/atb), /usr/local/Ascend/
Python 3.11.14(/usr/local/python3.11.14
关键软件栈 torch 2.9.0 + torch_npu 2.9.0 + transformers 5.3.0
模型 SenseNova/SenseNova-U1.5-8B-MoT
目录 仓库 /root/SenseNova-U1;模型 /root/SenseNova-U1.5-8B-MoT

先用 npu-smi 确认驱动与芯片状态:

npu-smi info

输出:

CPU / 内存概况(free -h + lscpu):

非交互 shell 注意: 通过脚本/非交互 SSH 执行命令时 .bashrc 不会加载,需要手动:

export PATH=/usr/local/python3.11.14/bin:$PATH
source /usr/local/Ascend/ascend-toolkit/set_env.sh

否则会出现 npu-smi: error while loading shared libraries: libc_sec.sopython3: command not found——这两个都不是环境故障,只是环境变量未加载。交互式登录时 .bashrc 已自动加载,无需处理。

6.1.2. 实测性能(单卡 64 GB,2048×2048)
指标 W7900 参考(第三章,SDPA) 910B2 实测
注意力后端 torch SDPA torch SDPA(auto 生效值,同)
模型加载 约 20.1 s 7.0–7.3 s
8 步冒烟生成 44.8 s/张(91.34 tok/s) 29.4 s/张(139.32 tok/s)(首跑含 TBE 算子编译)
50 步正式生成 274.0 s/张(14.95 tok/s) 56.1 s/张(72.96 tok/s),稳态约 1.1 s/步
图像编辑 493.2 s/张(8.17 tok/s) 66.1 s/张(60.96 tok/s,4029 tok)
图文交错生成 - 797 s(13.3 分钟):7 张 2048×1152 + 长文本,单图速率 1.77→1.14 it/s 随上下文递减
生成阶段峰值显存 allocated 34.87–39.39 GiB HBM 40427 / 65536 MB(约 39.5 GiB,含系统常驻 3.2 GB)npu-smi 采样观测

模型加载完成后开始生成时,用 watch -n 1 npu-smi info 观测到的运行时状态:


6.2环境安装

6.2.0. 前提
  • 平台镜像「Pytorch2.9-Ascend」已预装 torch 2.9.0 / torch_npu 2.9.0 / CANN 8.5.1 / Python 3.11.14

  • 网络实测:pypi.org 正常、modelscope.cn 正常

  • 仓库已克隆到 /root/SenseNova-U1,模型下载到 /root/SenseNova-U1.5-8B-MoT

# 仓库(已完成)
cd /root
git clone https://github.com/OpenSenseNova/SenseNova-U1.git
​
# 模型(约 33 GB)
modelscope download --model SenseNova/SenseNova-U1.5-8B-MoT --local_dir ./SenseNova-U1.5-8B-MoT
6.2.1. 安装项目本体与缺失依赖(关键一步:--no-deps
cd /root/SenseNova-U1
​
# 项目本体:跳过依赖自动安装,避免 pip 把 torch==2.8.0+cu128 拉回来覆盖 torch_npu
pip install -e . --no-deps
​
# 镜像里缺的纯 Python 依赖(实测缺口:sentencepiece;tqdm/httpx 一并补上)
pip install sentencepiece==0.2.1 tqdm==4.67.1 "httpx>=0.27,<1" "packaging>=25.0"
​
# CANN TBE 算子编译组件的 Python 依赖(实测必装,否则首个卷积算子报 EC0010,见 6.5)
pip install decorator attrs cloudpickle
镜像实测 项目要求 判定
torch / torch_npu 2.9.0 / 2.9.0 FAQ 认可 aarch64 用 torch 2.9
transformers 5.3.0 >=4.57.1,<6
accelerate 1.13.0 >=1.1,<2
safetensors 0.7.0 >=0.4.3,<1
numpy 2.4.3 >=1.24,<3
huggingface-hub 1.7.1 >=0.34,<2
pillow 12.1.1 ==12.0.0 ⚠️ 小版本差异,--no-deps 下不冲突,运行无影响
sentencepiece 未安装 ==0.2.1 ❌ 需补装(命令已含)
6.2.2.(可选)GGUF 低显存扩展

64 GB 的 910B2 走 full 模式用不到;仅在把本指南套用到 32 GB 卡(910B3/B4)时才需要:

pip install "gguf>=0.10.0" "diffusers>=0.30.0"
6.2.3. NPU 设备补丁(唯一必需的代码改动)

推理代码本身设备无关,但 src/sensenova_u1/utils/accel.py 的设备白名单只有 ("cuda", "xpu")不打补丁的两个后果:

  1. 示例脚本的默认设备由 best_available_device() 决定,NPU 机器上会静默返回 CPU(慢到不可用,且无报错);

  2. --vram_mode fast/balanced/lowlayer_offload.py 里调用 require_accelerator(),对 npu 直接抛 NotImplementedError

在仓库根目录执行一次性补丁脚本(原理:仿照文件内 flash-attn 的 try/except 导入模式,把 torch.npu 纳入 accel_module 抽象;CUDA / XPU 机器行为完全不变):

cd /root/SenseNova-U1
python3 - <<'EOF'
from pathlib import Path
​
f = Path("src/sensenova_u1/utils/accel.py")
s = f.read_text()
​
# 1) 顶部守护导入 torch_npu(未安装时自动降级,不影响其它后端)
s = s.replace(
    "from __future__ import annotations\n\nimport torch\n",
    "from __future__ import annotations\n\nimport torch\n\n"
    "try:\n    import torch_npu  # type: ignore[import-untyped]\n\n"
    "    _HAS_TORCH_NPU = True\nexcept ImportError:\n    _HAS_TORCH_NPU = False\n",
)
​
# 2) 设备白名单加 npu
s = s.replace(
    'SUPPORTED_DEVICE_TYPES: tuple[str, ...] = ("cuda", "xpu")',
    'SUPPORTED_DEVICE_TYPES: tuple[str, ...] = ("cuda", "xpu", "npu")',
)
​
# 3) accel_module 加 npu 命名空间
s = s.replace(
    '    if device.type == "xpu":\n        return torch.xpu\n',
    '    if device.type == "xpu":\n        return torch.xpu\n    if device.type == "npu":\n        return torch.npu\n',
)
​
# 4) is_available 加 npu 分支
s = s.replace(
    '    if device_type == "xpu":\n        return torch.xpu.is_available()\n    return False',
    '    if device_type == "xpu":\n        return torch.xpu.is_available()\n'
    '    if device_type == "npu":\n        return _HAS_TORCH_NPU and torch.npu.is_available()\n    return False',
)
​
# 5) best_available_device 优先级:CUDA > NPU > XPU > CPU
s = s.replace(
    '    if torch.cuda.is_available():\n        return torch.device("cuda")\n'
    '    if torch.xpu.is_available():\n        return torch.device("xpu")\n    return torch.device("cpu")',
    '    if torch.cuda.is_available():\n        return torch.device("cuda")\n'
    '    if _HAS_TORCH_NPU and torch.npu.is_available():\n        return torch.device("npu")\n'
    '    if torch.xpu.is_available():\n        return torch.device("xpu")\n    return torch.device("cpu")',
)
​
# 6) empty_cache(device=None) 分支
s = s.replace(
    '        if torch.xpu.is_available():\n            torch.xpu.empty_cache()\n        return',
    '        if torch.xpu.is_available():\n            torch.xpu.empty_cache()\n'
    '        if _HAS_TORCH_NPU and torch.npu.is_available():\n            torch.npu.empty_cache()\n        return',
)
​
# 7) synchronize(device=None) 分支
s = s.replace(
    '        if torch.xpu.is_available():\n            torch.xpu.synchronize()\n        return',
    '        if torch.xpu.is_available():\n            torch.xpu.synchronize()\n'
    '        if _HAS_TORCH_NPU and torch.npu.is_available():\n            torch.npu.synchronize()\n        return',
)
​
# 8) manual_seed_all 分支
s = s.replace(
    '    if torch.xpu.is_available():\n        torch.xpu.manual_seed_all(seed)',
    '    if torch.xpu.is_available():\n        torch.xpu.manual_seed_all(seed)\n'
    '    if _HAS_TORCH_NPU and torch.npu.is_available():\n        torch.npu.manual_seed_all(seed)',
)
​
f.write_text(s)
print("accel.py patched OK")
EOF

补丁共 8 处,全部集中在 accel.py 一个文件;require_accelerator() 读白名单,无需单独改。手工修改也可,对应关系即上表 8 条。

零改动备选方案: python -c "from torch_npu.contrib import transfer_to_npu" 的 shim 会把 torch.cuda.* 全部映射到 torch.npu.*,不改编译码即可运行(best_available_device() 会返回 "cuda" 并落到 NPU)。本章主路线采用显式补丁(设备名清晰、不依赖 shim 的全局替换行为),shim 仅作快速验证备选。

6.2.4. 验证环境
python3 -c "
import torch, torch_npu
print('torch:', torch.__version__, '| torch_npu:', torch_npu.__version__)
print('npu available:', torch_npu.npu.is_available(), '| devices:', torch_npu.npu.device_count())
x = torch.randn(1024, 1024, device='npu', dtype=torch.bfloat16)
print('bf16 matmul OK:', float((x @ x).sum()))
q = torch.randn(1, 8, 4096, 128, device='npu', dtype=torch.bfloat16)
o = torch.nn.functional.scaled_dot_product_attention(q, q, q)
print('SDPA OK:', tuple(o.shape))
"

预期输出(节选):

torch: 2.9.0+cpu | torch_npu: 2.9.0
npu available: True | devices: 1
bf16 matmul OK: ...
SDPA OK: (1, 8, 4096, 128)

SDPA 是 U1.5 在 NPU 上的实际注意力路径(见 6.5),单独验证一次可以提前暴露内核问题。


6.3运行推理示例

所有命令在 /root/SenseNova-U1 下执行;--model_path 指向 /root/SenseNova-U1.5-8B-MoT。公共参数:

参数 建议值 说明
--device npu(打了 6.2.3 补丁后可省略,默认自动选 NPU) 补丁前省略会静默跑 CPU
--attn_backend auto(默认)或 sdpa NPU 上无 flash-attn,auto 自动落 SDPA;如介意日志噪音可显式 sdpa
--dtype bfloat16(默认) 910B2 原生支持 bf16
--num_steps 50(默认) 冒烟测试设 8 快速验证链路
--cfg_scale 4.0(默认) 8-step 蒸馏 LoRA 才用 1.0
--profile 建议开启 打印耗时;显存统计仅 cuda 设备采集(见 6.5)

运行时观测 NPU 状态

watch -n 1 npu-smi info
6.3.1. 文生图(t2i)

8 步冒烟测试

python examples/t2i/inference.py \
  --model_path /root/SenseNova-U1.5-8B-MoT \
  --prompt "A serene mountain lake at sunrise, mist drifting over calm water, snow-capped peaks in the background, photorealistic, high detail" \
  --device npu \
  --output /root/outputs/npu_smoke.png \
  --num_steps 8 --profile

终端输出:attn backend='auto' (effective='sdpa')、模型加载 7.26 s、8 步生成 29.4 s、吞吐 139.32 tok/s(首跑含一次性 TBE 算子编译,见 6.1.2):

生成结果(outputs/npu_smoke.png,2048×2048):

50 步正式生成(默认 2048×2048):

python examples/t2i/inference.py \
  --model_path /root/SenseNova-U1.5-8B-MoT \
  --prompt "A serene mountain lake at sunrise, mist drifting over calm water, snow-capped peaks in the background, photorealistic, high detail" \
  --device npu \
  --output /root/outputs/npu_full50.png \
  --num_steps 50 --profile

终端输出:模型加载 7.0 s、50 步生成 56.1 s、吞吐 72.96 tok/s(对比 W7900 的 274 s,快约 4.9 倍):

生成结果(outputs/npu_full50.png,2048×2048):

批量 / 其他分辨率(训练档位见 examples/README_CN.md,如 16:9 → 2720×1536);带推理的 think 模式可追加 --think --print_think

6.3.2. 视觉理解(VQA)
python examples/vqa/inference.py \
  --model_path /root/SenseNova-U1.5-8B-MoT \
  --device npu \
  --image examples/vqa/data/images/image1.jpg \
  --question "Describe the image content."

模型先输出 think 推理再给出描述:全程 4 分 05 秒(含加载),正确识别画面主体(山丘上的哥特风格城堡、白色石墙、暖金色夕照、远山与雾谷等)。实测输出节选:

6.3.3. 图像编辑(editing)

输入图(examples/editing/data/images/1.webp):

python examples/editing/inference.py \
  --model_path /root/SenseNova-U1.5-8B-MoT \
  --prompt "Change the jacket of the person on the left to bright yellow." \
  --image examples/editing/data/images/1.webp \
  --device npu \
  --cfg_scale 4.0 --img_cfg_scale 1.0 --timestep_shift 3.0 --num_steps 50 \
  --output /root/outputs/edited.png --profile

终端输出:1 张输入图自动按 4096 pixel 上限处理(4029 tok),模型加载 7.0 s、50 步编辑 66.1 s、吞吐 60.96 tok/s(对比 W7900 的 493.2 s,快约 7.5 倍):

编辑结果(outputs/edited.png):

6.3.4. 图文交错生成(interleave)
python examples/interleave/inference.py \
  --model_path /root/SenseNova-U1.5-8B-MoT \
  --prompt "I want to learn how to cook tomato and egg stir-fry. Please give me a beginner-friendly illustrated tutorial." \
  --resolution "16:9" \
  --device npu \
  --output_dir /root/outputs/interleave/ --stem demo_text

模型在生成文本的同时按段落插图(<image1><image7>),全程 797 s(13.3 分钟):共 7 张 2048×1152 插图 + 长文本教程;单图 50 步速率从 1.77 it/s 逐张递减到 1.14 it/s(上下文增长带来的注意力开销,属预期):

交错输出样例:


6.4显存不够时的降级方案

64 GB 的 910B2 全量模式即可跑 2K;以下方案主要供 32 GB 卡(910B3/B4)或更高分辨率时参考:

方案 命令 说明
分层卸载 --vram_mode balanced(或 low / fast 需 6.2.3 补丁(白名单含 npu 后即可用);本机 2 TiB 内存,CPU 侧余量极大;与 --device_map 互斥
GGUF 量化 --gguf_checkpoint /path/x.gguf(需 6.2.2 扩展) 社区 Q4/Q8 权重;GGUF 反量化是纯 torch 算子,理论可在 NPU 运行,未实测;仓库称 Q4 + balanced 可在 10–12 GB 显存运行
降分辨率 / 步数 --width/--height--num_steps 直接降低激活显存与耗时
多卡切分 --device_map auto --max_memory ... accelerate 的 NPU device_map 支持未验证,本章单卡 910B2 不涉及

6.5NPU 适配说明与已知问题

  1. flash-attn:没有 NPU 版本,本路线不安装。

  2. torch 版本:仓库默认 pin torch 2.8.0 + cu128 仅适用 NVIDIA;本路线直接使用镜像预装的 torch_npu 2.9.0 配套(FAQ 亦认可 aarch64 上 torch 2.9)。--no-deps 安装项目本体是防止覆盖的关键。

  3. 非交互 shell:脚本/远程执行需手动 export PATH=/usr/local/python3.11.14/bin:$PATHsource /usr/local/Ascend/ascend-toolkit/set_env.sh,否则出现 libc_sec.so 加载失败、python3/npu-smi 找不到等假性故障(见 6.1.1)。

  4. profiler 显存统计--profile 的峰值显存采集代码仅对 cuda 设备生效,NPU 上只打印耗时、不打印显存。观测显存请用 watch -n 1 npu-smi info(HBM-Usage 列)。

  5. pillow 版本:镜像 12.1.1 与项目 pin 12.0.0 的小版本差异在 --no-deps 安装下不产生冲突,推理路径未观察到影响。

  6. TBE 算子编译的 Python 依赖(实测踩过的坑):首次推理触发卷积算子编译时,CANN TBE 组件要导入 decorator 模块,镜像未预装会报 Environment_Error_Import_Python_Module_Failed(EC0010): No module named 'decorator' 并连带 SetPrecisionMode ... error code is 500001 等长串错误。补装 decorator attrs cloudpickle 即可(已写入 6.2.2),这是纯环境问题、与模型代码无关。


6.6一页速查

# ===== 环境(一次性)=====
export PATH=/usr/local/python3.11.14/bin:$PATH          # 非交互 shell 需要
source /usr/local/Ascend/ascend-toolkit/set_env.sh      # 非交互 shell 需要
npu-smi info                                            # 确认 910B2 / 64 GB / 驱动正常
​
cd /root/SenseNova-U1
pip install -e . --no-deps                              # 关键:不覆盖 torch_npu
pip install sentencepiece==0.2.1 tqdm==4.67.1 "httpx>=0.27,<1" "packaging>=25.0"
pip install decorator attrs cloudpickle                 # CANN TBE 算子编译依赖(必装)
# + 执行 6.2.3 的 accel.py 补丁脚本(唯一必需代码改动)
python3 -c "import torch, torch_npu; print(torch.__version__, torch_npu.__version__, torch_npu.npu.is_available())"
​
# ===== 运行(每次)=====
python examples/t2i/inference.py \
  --model_path /root/SenseNova-U1.5-8B-MoT \
  --prompt "你的提示词" \
  --device npu --num_steps 50 --profile \
  --output /root/outputs/out.png
​
watch -n 1 npu-smi info                                 # 另开终端观测 HBM 占用

附录 A:一键复现命令汇总

# 0) 驱动(Ubuntu 24.04,新内核)
echo -e "blacklist nouveau\noptions nouveau modeset=0" | sudo tee /etc/modprobe.d/blacklist-nouveau.conf
sudo update-initramfs -u && sudo reboot
sudo apt install -y gcc make linux-headers-$(uname -r)
sudo ./cuda_13.2.0_595.45.04_linux.run            # 只装 Driver 组件(595.45.04)
sudo ./cuda_12.8.0_570.86.10_linux.run --toolkit --silent --override   # 只装 12.8 toolkit
​
# 1) 环境
curl -LsSf https://astral.sh/uv/install.sh | sh
uv venv --python=3.11 && source .venv/bin/activate
uv pip install torch torchvision --index-url https://download.pytorch.org/whl/cu128
sudo apt install -y git
git clone https://github.com/OpenSenseNova/SenseNova-U1.git && cd SenseNova-U1 && uv pip install -e .
​
# 2) 权重(33GB + 814MB LoRA)
modelscope download --model SenseNova/SenseNova-U1.5-8B-MoT --local_dir ~/SenseNova/SenseNova-U1.5-8B-MoT
hf download sensenova/SenseNova-U1.5-8B-MoT-LoRAs SenseNova-U1.5-8B-MoT-LoRA-8step.safetensors \
    --local-dir ~/SenseNova/SenseNova-U1.5-8B-MoT-LoRAs
​
# 3) 50 步基线 / 8 步蒸馏
python examples/t2i/inference.py --model_path ~/SenseNova/SenseNova-U1.5-8B-MoT \
    --prompt "你的提示词" --output outputs/base.png --width 2048 --height 2048 \
    --cfg_scale 4.0 --timestep_shift 3.0 --num_steps 50 --seed 42 --profile \
    --device_map auto --max_memory "0=20GiB,cpu=16GiB"   # 32GB 内存主机用分片;≥40GB 内存可换 --vram_mode fast
python examples/t2i/inference.py --model_path ~/SenseNova/SenseNova-U1.5-8B-MoT \
    --lora_path ~/SenseNova/SenseNova-U1.5-8B-MoT-LoRAs/SenseNova-U1.5-8B-MoT-LoRA-8step.safetensors \
    --prompt "你的提示词" --output outputs/fast.png --width 2048 --height 2048 \
    --cfg_scale 1.0 --timestep_shift 3.0 --num_steps 8 --seed 42 --profile \
    --device_map auto --max_memory "0=20GiB,cpu=16GiB"

附录 B:参考资料

  • SenseNova-U1 GitHub 仓库:docs/deployment_CN.md(LightLLM 部署)、docs/base_vs_distill.md(蒸馏对比)、docs/gpu_mem_profiler_CN.md(显存剖析)、docs/parameter_breakdown_CN.md(参数分解)

  • 模型权重:Hugging Face sensenova/SenseNova-U1.5-8B-MoT、ModelScope 同名空间

附录 C:u1_api_server.py 完整代码

放在仓库根目录(~/SenseNova/SenseNova-U1-GitHub/u1_api_server.py),配合第 2.10 节的 systemd 单元使用:

"""
启动示例(≥40 GB 内存主机):
python u1_api_server.py \
        --model_path ~/SenseNova/SenseNova-U1.5-8B-MoT \
        --lora_path  ~/SenseNova/SenseNova-U1.5-8B-MoT-LoRAs/SenseNova-U1.5-8B-MoT-LoRA-8step.safetensors \
        --vram_mode fast --num_steps 8 --cfg_scale 1.0 --port 8000
"""
from __future__ import annotations
​
import argparse
import base64
import io
import threading
import time
from pathlib import Path
​
import torch
import uvicorn
from fastapi import FastAPI
from pydantic import BaseModel, Field
​
REPO = Path(__file__).resolve().parent
import sys
sys.path.insert(0, str(REPO / "examples" / "t2i"))
​
import sensenova_u1  # noqa: E402  (import 时向 transformers 注册模型)
from inference import SenseNovaU1T2I  # noqa: E402
from sensenova_u1.utils import load_and_merge_lora_weight_from_safetensors  # noqa: E402
​
app = FastAPI(title="SenseNova-U1.5 T2I API", version="1.0")
​
ENGINE: SenseNovaU1T2I | None = None
GEN_LOCK = threading.Lock()
DEFAULTS: dict = {}
​
​
class GenRequest(BaseModel):
    prompt: str
    width: int = Field(default=2048, description="仅支持官方分辨率桶, 如 2048x2048 / 2720x1536")
    height: int = 2048
    num_steps: int | None = None
    cfg_scale: float | None = None
    seed: int = 42
​
​
class GenResponse(BaseModel):
    created: int
    model: str = "sensenova-u1.5-8b-mot"
    b64_image: str
    width: int
    height: int
    num_steps: int
    cfg_scale: float
    seed: int
    elapsed_sec: float
​
​
@app.get("/health")
def health():
    return {
        "status": "ok" if ENGINE is not None else "loading",
        "vram_mode": DEFAULTS.get("vram_mode"),
        "default_steps": DEFAULTS.get("num_steps"),
        "default_cfg": DEFAULTS.get("cfg_scale"),
        "gpu": torch.cuda.get_device_name(0) if torch.cuda.is_available() else "cpu",
    }
​
​
@app.post("/v1/images/generations", response_model=GenResponse)
def generate(req: GenRequest):
    assert ENGINE is not None, "engine not ready"
    steps = req.num_steps or DEFAULTS["num_steps"]
    cfg = req.cfg_scale if req.cfg_scale is not None else DEFAULTS["cfg_scale"]
    t0 = time.time()
    with GEN_LOCK:  # 24GB 单卡串行, 防止并发 OOM
        images = ENGINE.generate(
            req.prompt,
            image_size=(req.width, req.height),
            cfg_scale=cfg,
            num_steps=steps,
            seed=req.seed,
        )
    buf = io.BytesIO()
    images[0].save(buf, format="PNG")
    return GenResponse(
        created=int(time.time()),
        b64_image=base64.b64encode(buf.getvalue()).decode(),
        width=req.width,
        height=req.height,
        num_steps=steps,
        cfg_scale=cfg,
        seed=req.seed,
        elapsed_sec=round(time.time() - t0, 2),
    )
​
​
def main():
    global ENGINE, DEFAULTS
    p = argparse.ArgumentParser()
    p.add_argument("--model_path", required=True)
    p.add_argument("--lora_path", default=None)
    p.add_argument("--vram_mode", default="fast")
    p.add_argument("--num_steps", type=int, default=8)
    p.add_argument("--cfg_scale", type=float, default=1.0)
    p.add_argument("--port", type=int, default=8000)
    p.add_argument("--host", default="0.0.0.0")
    args = p.parse_args()
​
    sensenova_u1.set_attn_backend("sdpa")
    t0 = time.time()
    ENGINE = SenseNovaU1T2I(args.model_path, dtype=torch.bfloat16, vram_mode=args.vram_mode)
    if args.lora_path:
        ENGINE.model = load_and_merge_lora_weight_from_safetensors(ENGINE.model, args.lora_path)
        print(f"[api] merged lora: {args.lora_path}")
    DEFAULTS = {
        "vram_mode": args.vram_mode,
        "num_steps": args.num_steps,
        "cfg_scale": args.cfg_scale,
    }
    print(f"[api] engine ready in {time.time() - t0:.1f}s, listening on {args.host}:{args.port}")
    uvicorn.run(app, host=args.host, port=args.port)
​
​
if __name__ == "__main__":
    main()
Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐