LTX-2.3 本地部署完整复盘
先把结论放前面:LTX-2.3(22B)这条 pipeline 在 4×RTX 3090(24GB)这套硬件上,按官方默认推理方式基本跑不起来。我最终得到的不是“没跑通”,而是一个更有价值的结果:把它为什么跑不起来、卡在哪、该怎么判断“物理不可行”,完整验证了一遍。
这篇文章是一次本地部署的工程复盘:从模型文件下载、依赖链补齐、环境和代码层踩坑,到显存拆分、多卡 device 规划,再到最终 OOM 的边界判断。希望你在遇到类似“看起来只要把权重放进去就能跑”的大模型工程时,可以少走很多弯路。
TL;DR(1 分钟读完)
- LTX-2.3 不是单模型,而是一个多组件 pipeline:文本编码器(Gemma)+ 视频 diffusion 主模型(22B)+ 可能的增强/上采样等。
- 仅下载
ltx-2.3-22b-distilled.safetensors(≈46GB)并不够,运行时会继续依赖 HuggingFace 生态的一整套配置文件与子模型。 - 我在 3090 上遇到两类 OOM:
- Gemma(12B)加载阶段先爆一次(prompt encoder 直接吃掉接近一张 3090 的可用显存)。
- diffusion 主模型推理阶段仍然爆(不是调小分辨率/帧数就能解决的那种)。
- 做到“能跑”的三条现实路线:
- CPU / NVMe offload(能出结果但会很慢);
- 真正意义上的模型并行/张量并行(需要改造实现,不是简单多卡);
- 换更现实的模型/蒸馏版本。
1. 背景
目标很直接:
- 在本地 GPU 服务器上部署 LTX-2.3(22B)视频生成模型
- 硬件:4×RTX 3090(每张 24GB)
- 系统:Ubuntu 24.04
- 网络受限:需要手工下载模型(避免 git-lfs 拉爆、断点续传等)
我以为这会是一件“把权重下载下来、装依赖、跑脚本”的事。事实证明:当模型规模跨过某个阈值后,部署问题本质上会从“软件配置”变成“系统工程 + 资源规划”。
2. 一个关键认知:LTX 是 pipeline,不是“一个模型”
很多部署失败,是从最初的心理模型就错了。
LTX-2.3 的推理链路更像这样:
Prompt(文本)
↓
Text Encoder(Gemma)
↓
Diffusion 主模型(视频生成)
↓
(可选) Upsampler / Enhancer
↓
Video Output
也就是说你不是在部署一个 .safetensors,而是在部署一条 由多个模型 + 多套配置 + 多段推理代码组成的 pipeline。
只要这条链上的任何一环缺文件、缺 config、版本不匹配,你就会看到“看似随机”的报错。
3. 第一步:下载主权重,但很快发现“这只是开始”
我先手工下载了 diffusion 主模型的权重:
ltx-2.3-22b-distilled.safetensors ≈ 46GB
这一步本身没什么技术含量,但它会带来一个误导:你会以为“权重有了就能跑”。
很快,运行就报错(典型的第一类缺失):
找不到 preprocessor_config.json
这意味着:代码实际上在按 HuggingFace 的模型目录结构去找东西——不仅是权重文件,还包括 tokenizer / processor / config 这一整套元数据。
4. 最大的坑:Gemma 依赖与版本匹配
继续顺着报错和代码路径往下挖,我定位到:
PromptEncoder → GemmaTextEncoder
结论很明确:必须提供 Gemma 模型。并且不是“随便一个 Gemma”。
我走了三次典型的错误分支:
4.1 gemma-2:架构不匹配
这类错误的特征是:你能加载一部分,然后在模型结构对齐/层数/命名上出现不兼容。
4.2 gemma-3-4b:尺寸不匹配
报错类似:
hidden_size mismatch(2560 vs 3840)
这基本可以断定:上游代码/权重期望的是更大规格的文本编码器。
4.3 gemma-3-12b-it:终于对上
最终匹配的版本是 gemma-3-12b-it。除了分片权重外,还必须补齐:
- tokenizer
- processor
- config
- preprocessor_config.json(关键)
到这一步,依赖链才算完整。
5. 环境与依赖:不是“装不装得上”,而是“能不能稳定复现”
我这次遇到的环境问题并不花哨,但非常常见:
5.1 Conda strict priority 导致依赖不可解
典型报错:
LibMambaUnsatisfiableError
如果你用了国内镜像(例如开启 strict priority),很容易把解空间卡死。处理方式也很工程化:
- 切回默认源,或
- 调整 channel priority 策略
5.2 uv / pip / .venv 混用导致“看起来装了但其实没装”
我这里踩到的是:项目自带 .venv 与我的 conda 环境产生混乱。一个简单但重要的结论是:
- 项目自带
.venv不等于必须使用 - 你完全可以用 conda + pip 管理,只要保证解释器和 site-packages 指向一致
6. 第一次真正跑起来前:Gemma 先 OOM
当依赖补齐之后,我第一次遇到的硬性问题是:Gemma(12B)加载/初始化阶段直接 OOM。
报错类似:
CUDA out of memory(发生在 PromptEncoder)
直觉上也合理:
- Gemma 12B 本身就接近 20GB+ 的显存消耗
- 3090 标称 24GB,但可用显存会被 buffer、碎片和 runtime 开销进一步挤压
6.1 解决:手动做“分卡”而不是幻想多卡自动分摊
我采取的策略:
- GPU1:Gemma / PromptEncoder
- GPU0:LTX diffusion 主模型
我在 DistilledPipeline.__init__ 里增加了类似 text_device 的参数,把 prompt encoder 显式放到 cuda:1,而 diffusion 放到 cuda:0。
这类改动的意义在于:多卡不是自动解决显存问题的。你必须明确:每个大组件在哪张卡上。
7. 代码层的“工程坑”(不难但很耗时间)
在继续推进时,我遇到了一组很典型的“不是算法问题,但会让你卡很久”的坑:
SyntaxError:复制/粘贴残留(例如多余的引号、括号)TabError:tabs vs spaces(Python 最经典的坑)- 我用
sed -i 's/\\t/ /g'统一掉缩进
- 我用
- 双
__init__:后定义覆盖前定义,导致你以为参数传进去了但实际没生效 CUDA device ordinal:你以为有cuda:1,但其实进程只看见一张卡- 典型原因是设置了
CUDA_VISIBLE_DEVICES=0 - 解决:
unset CUDA_VISIBLE_DEVICES
- 典型原因是设置了
这些问题都不“高级”,但它们会把你从“调模型”拖进“调工程”泥潭。
8. 第二次 OOM:主模型推理阶段依然爆
当 Gemma 分卡后,我以为最难的部分过去了。但真正决定“能不能跑”的,是 diffusion 主模型推理阶段的显存峰值。
即使我做了:
- 降分辨率
- 减少帧数
- 尝试进一步拆分
依然出现 OOM,且位置更接近主生成阶段。
这里的核心结论是:
LTX-2.3 22B 的权重(≈46GB)只是显存需求的一部分。
推理时还会叠加:
- 激活(diffusion 的迭代过程会放大峰值)
- 各类中间 buffer
- 可能的 KV cache / attention 临时张量
- 后处理/增强组件(如果启用)
最终,你会发现 24GB 这条线对它来说太窄了。
9. 最终结论:这是一次“边界验证”
我最终得到的最重要结论是:
- 在 4×3090(24GB)上,按当前实现与默认推理方式,LTX-2.3 22B 很难稳定跑通
- 这不是“参数没调好”,而是资源约束与实现方式共同决定的不可行
这类项目最怕的是:你投入很多时间,最后只留下一个模糊的“没跑通”。我希望这篇复盘留下的是一个可复用的方法论:
- 先把系统拆成 pipeline(谁在吃资源、谁是硬依赖)
- 对每一段做“可测量的资源预算”(显存、CPU、磁盘、带宽)
- 多卡要显式规划(组件级 device placement),不要期待自动分摊
- 当 OOM 多次落在主模型推理峰值时,要学会及时判断“物理不可行”,避免无效优化
10. 后续可行路线(现实版)
如果你也在类似硬件上想“出结果”,大致只有三条路:
- CPU/NVMe offload:能跑,但速度会非常慢
- 真正的模型并行:需要系统性改造(不是简单把
.to(cuda:1)) - 换模型/换规模:选择更适合 24GB 单卡推理的版本(或更激进的蒸馏/量化方案)
结语
这次复盘对我最有价值的点,不是“搞定了一个部署”,而是把一条大模型 pipeline 的依赖链、资源峰值、以及多卡拆分的工程边界走了一遍。
一句话总结:
从“我能不能跑这个模型”
到“这个模型在这套硬件上按当前实现物理不可行”
陕公网安备61011302002223号