LTX-2 视频生成 Conditioning 完全指南:图像/视频/EXR 条件注入与生成关键帧槽位机制
【免费下载链接】LTX-2Official Python inference and LoRA trainer package for the LTX-2 audio–video generative model.项目地址: https://gitcode.com/GitHub_Trending/lt/LTX-2
本指南以 LTX-2 官方推理仓库中 conditioning.md 为核心,系统讲解ltx-pipelines各管线支持的图像、视频与 HDR/EXR 条件输入方法,以及「生成关键帧槽位(Generated Keyframe Slots)」这一缓解时间压缩瓶颈的高级机制。读完本文,你将掌握替换式/引导式图像条件的取舍、IC-LoRA 参考视频条件的注入原理、--hdrEXR 条件输入的 CLI 用法,以及generated_keyframes的代价模型、适用管线与结果读取方式。
1. Conditioning 在 LTX-2 推理体系中的位置
在 LTX-2 中,「Conditioning(条件注入)」指在扩散去噪开始之前,把外部控制信号(图像、视频、HDR 静态帧等)写入LatentState的机制。ltx-pipelines是高层推理封装,负责模型加载、编码、解码与文件 I/O;而条件注入的具体数据结构和位置语义全部由底层包ltx-core实现(参见 ltx-core conditioning 文档)。
所有条件注入都收敛到ltx-core中定义的ConditioningItem.apply_to(latent_state, latent_tools)接口。ltx-pipelines侧通过 helpers.py 的state_with_conditionings按列表顺序逐个把条件项应用到潜状态上,最后交给noiser加噪进入去噪循环:
def state_with_conditionings( latent_state: LatentState, conditioning_items: list[ConditioningItem], latent_tools: LatentTools ) -> LatentState: for conditioning in conditioning_items: latent_state = conditioning.apply_to(latent_state=latent_state, latent_tools=latent_tools) return latent_state(helpers.py)
LatentState中最关键的两个字段决定了条件的语义(types.py):
clean_latent:去噪前的干净潜变量,条件内容写在这里;denoise_mask:每个 token 的去噪强度(1 = 完全去噪、0 = 不去噪)。条件 token 的掩码被设置为1.0 - strength,strength越接近 1.0 条件保持越干净,越接近 0.0 条件越被重新去噪。
2. 图像条件注入:替换潜变量 vs 引导潜变量
所有管线都支持图像条件注入,但方式不同,对应的构造函数都在 helpers.py 中。
2.1 替换式:image_conditionings_by_replacing_latent
def image_conditionings_by_replacing_latent( images: list[ImageConditioningInput], height: int, width: int, video_encoder: VideoEncoder, dtype: torch.dtype, device: torch.device, color_space: HDRColorSpace | None = None, ) -> list[ConditioningItem]: conditionings = [] for img in images: image = load_image_and_preprocess(...) encoded_image = video_encoder(image) conditionings.append( VideoConditionByLatentIndex( latent=encoded_image, strength=img.strength, latent_idx=img.frame_idx, ) ) return conditionings(helpers.py)
每个输入图像先用video_encoder编码为潜变量,然后构造VideoConditionByLatentIndex,把编码结果直接写入指定latent_idx(潜帧索引)对应的 clean_latent 位置。其核心实现(latent_cond.py):
tokens = latent_tools.patchifier.patchify(self.latent) start_token = latent_tools.patchifier.get_token_count( latent_tools.target_shape._replace(frames=self.latent_idx) ) stop_token = start_token + tokens.shape[1] latent_state.clean_latent[:, start_token:stop_token] = tokens latent_state.denoise_mask[:, start_token:stop_token] = 1.0 - self.strength注意它不新增任何 token,而是就地覆盖既有潜帧的 token 区间,因此在序列长度上零开销,属于「占位替换」式注入。
特点:
- 对指定帧有极强的控制力;
- 潜变量形状必须与目标一致,否则抛出
ConditioningError(源码中显式校验了 batch/channel/height/width); - 适合「首帧 + 若干指定帧」这种需要严格锚定的场景。
2.2 引导式:image_conditionings_by_adding_guiding_latent
conditionings.append( VideoConditionByKeyframeIndex(keyframes=encoded_image, frame_idx=img.frame_idx, strength=img.strength) )(helpers.py)
引导式改为构造VideoConditionByKeyframeIndex(keyframe_cond.py),它把条件当作追加的引导 token而非替换:
- 条件 token 被
patchify后追加到序列末尾(latent里放占位零、clean_latent里放条件内容); frame_idx作为位置编码偏移写入positions;- 当
num_pixel_frames == 1(单像素帧)时,时间跨度被收窄为[start, start+1); denoise_mask = 1.0 - strength,语义与替换式相同。
由于引导 token 有自己的 RoPE 位置、与目标帧在时间上相邻,模型可以在关键帧之间做平滑插值——这正是「引导」优于「替换」的典型场景:替换只锁死单帧,引导则让相邻帧的注意力自然过渡。
2.3 两者如何选择
| 维度 | 替换潜变量(replacing_latent) | 引导潜变量(adding_guiding_latent) |
|---|---|---|
| 底层类 | VideoConditionByLatentIndex | VideoConditionByKeyframeIndex |
| 注入方式 | 就地覆盖既有 token | 追加新 token |
| 序列开销 | 无 | 每个条件增加一帧 token |
| 控制力 | 对指定帧极强 | 强,且利于帧间平滑过渡 |
| 典型场景 | 首帧/精确锚定 | 关键帧插值、多图引导 |
另外值得注意:在helpers.py中还有一种混合形态(create_keyframe_conditionings附近的逻辑)——首帧用VideoConditionByLatentIndex替换,其余帧用VideoConditionByKeyframeIndex引导(helpers.py),兼顾首帧锁定与中间帧平滑,实际管线中常用此组合。
3. 视频条件注入:IC-LoRA 参考视频
视频条件注入目前仅由 ICLoraPipeline 系列提供,用于 video-to-video 变换。它基于ltx-core的VideoConditionByKeyframeIndex以及专门的参考视频类VideoConditionByReferenceLatent(reference_video_cond.py)。
其原理与 IC-LoRA 训练协议严格对齐:
- IC-LoRA 训练时:把「参考(control signal)token + 目标 token」拼接,让模型学会跨两者注意力;
- 推理时:
VideoConditionByReferenceLatent.apply_to复刻这一设置——参考视频潜变量作为 clean_latent 追加进序列,latent对应位置放占位零,denoise_mask由strength决定(1.0 = 参考保持干净,0.0 = 参考完全重新去噪)。
该实现还支持训练时使用的降采样参考(例如 384px 参考配 768px 目标输出),通过两个缩放因子把参考位置映射回目标坐标系:
downscale_factor:目标/参考空间分辨率比(如 2 = 半分辨率参考),作用于高度、宽度轴;temporal_scale_factor:目标/参考时间比 S(如 4 = 参考以 1/4 帧率采样),作用于时间轴,并在平移后 clamp 回[0, 1/target_fps)。
这两个因子必须与 LoRA 元数据中训练时的取值一致,否则位置关系错位会导致生成质量下降。
参考 token 永远不会被标记为关键帧(keyframes_mask置marked=False)——因为参考视频的首个潜帧虽然也覆盖单像素帧,但它是条件内容而非生成槽位,不能误用关键帧绝对位置嵌入。
4. HDR / EXR 条件注入
标准管线(非 IC-LoRA)接受 OpenEXR 静态帧(.exr)以及 EXR 帧序列文件夹作为图像/视频条件输入,前提是用--hdr {SRGB_LINEAR,ACESCG,ACESCCT}声明源色彩空间。HDR 运行会解码输出半精度浮点 EXR 帧,外加一条 BT.2020/HLG 母版视频。
核心要点:
- 色彩空间声明:
--hdr接受SRGB_LINEAR、ACESCG、ACESCCT三种源色彩空间,管线内部通过HDRColorSpace枚举传递到load_image_and_preprocess(见 helpers.py 的color_space参数); - 混合限制:CLI 上禁止 EXR 与 SDR 输入混用,retake 管线还有
--frame-rate约束; - 输出格式:半精度浮点 EXR 帧(保留 HDR 动态范围)+ BT.2020/HLG 母版,方便下游调色与交付。
完整的色彩空间语义、CLI 约束与示例请参阅 HDR Support 文档。
5. 生成关键帧槽位(Generated Keyframe Slots)
这是 LTX-2 conditioning 体系中最具特色的机制:让模型在常规帧网格之外,于你指定的内部位置额外生成像素帧。
5.1 原理:一个槽位 = 一个空白的完整去噪 token 槽
生成关键帧是模型在常规帧网格之外额外产生的帧,位于你选择的内部位置。每个槽位是一个空的、完全去噪的 token 槽,被追加到序列末尾。关键区别在于:
- 一个普通潜帧(latent frame)编码8 个像素帧;
- 一个关键帧槽位只承载1 个像素帧。
因此在槽位处,有效时间压缩比被放宽——原本该位置 8 帧才分配一个潜帧 token,现在 1 帧就分配一整套 token,模型得以在运动过快、基础时间分辨率跟不上的地方补充细节。
实现类为VideoGeneratedKeyframeSlots(keyframe_slots.py)。apply_to的核心动作:
- 每个槽位在 RoPE 空间中占据恰好
[t, t+1)的单像素帧时间跨度(_slot_positions显式把时间末边界设为start + 1); latent追加全零 token(或initial_keyframes提供的种子内容),clean_latent追加全零;denoise_mask置 1,让 noiser 从槽位 latent 向噪声插值、由去噪循环生成内容;keyframes_mask标记marked=True——槽位 token 会获得模型学到的关键帧绝对位置嵌入(use_keyframes_abs_pos_embedding);- 记录
GeneratedKeyframeLayout(pixel_frame_indices、tokens_per_keyframe、first_token),用于之后精确抽取槽位结果。
GeneratedKeyframeLayout(types.py)专门解决「槽位 token 不一定在序列末尾」的定位问题:条件项按列表顺序追加,若槽位之外还有其他追加型条件(如引导式图像),尾部布局就不固定,必须靠first_token+num_tokens精确切片。
槽位与普通图像引导(
VideoConditionByKeyframeIndex)是刻意分离的:后者追加给定内容、不标记关键帧;前者追加空槽位、必须标记。参考实现只对关键帧类条件设置标记,普通图像/首尾帧条件不得标记。
5.2 前置要求:必须有关键帧 checkpoint
VideoGeneratedKeyframeSlots的类注释明确要求:checkpoint 的 transformer 配置必须设置use_keyframes_abs_pos_embedding。原因在于:
- 若 checkpoint 未训练该能力,学到的「关键帧标记」不存在,槽位会被当作未标记 token去噪,额外算力被白白浪费;
- 因此管线在开头就校验(
assert_generated_keyframes_supported,见 ti2vid_one_stage.py),对旧 checkpoint直接抛错而非静默降级。
LTX-2.5 系列 checkpoint 支持该特性;旧 checkpoint 会得到显式错误提示。
5.3 代价模型:一个潜帧的 token 换一个像素帧
每个关键帧消耗一个潜帧量的 token,换来 1 个像素帧(而不是 8 个)。文档给出的量级参考:
| 配置 | 5 个关键帧的开销 |
|---|---|
| 512×768 / 241 帧 | 约 +16% token(注意力约 1.35 倍) |
| 1088×1920 / 121 帧 | 约 +31% token(注意力约 1.72 倍) |
--num-generated-keyframes的帮助文本也给出了经验公式:N 个关键帧使序列长度约增加N / num_latent_frames。提高关键帧数量前必须先为这部分算力做预算。
5.4 适用管线:仅第一阶段
生成关键帧槽位只适用于第一阶段,支持以下管线及其多 GPU runner:
TI2VidOneStagePipeline(ti2vid_one_stage.py)TI2VidTwoStagesPipeline(ti2vid_two_stages.py)TI2VidTwoStagesHQPipeline(ti2vid_two_stages_hq.py)DistilledPipeline(distilled.py)- 对应的
*_mgpu.py多 GPU runner
第二阶段不需要槽位——效果已经烘焙进第一阶段的潜变量里。唯一的例外是DFRPipeline(详见 pipelines.md):它在第二阶段重新挂接已播种的槽位,并在时间轮次中按 tile 发明新的槽位(见 dfr_pipeline.py 中对generated_keyframes的反复处理:阶段 1 抽出 → upsampler 放大 → 阶段 2 重新挂载)。
5.5 使用方式:API 与 CLI
API 调用:向__call__传generated_keyframes参数:
int:请求该数量的均匀间隔内部关键帧(两端点排除);- 序列(如
list[int]):给出显式帧索引。
位置归一化逻辑在 helpers.py 的resolve_generated_keyframes中实现。int走evenly_spaced_keyframe_positions,使用torch.linspace(0, num_frames-1, num_keyframes+2)后取中间段(helpers.py);序列则去重排序并校验边界[0, num_frames)。
CLI 调用:标志为--num-generated-keyframes N,默认0(关闭)。该参数按管线单独注册(add_generated_keyframes_arg,args.py),而不是共享参数——只有真正会把值转发给第一阶段扩散的 CLI 才注册该标志,否则会出现「解析了却被静默忽略」的陷阱。DFRPipeline自己推导槽位位置,因此不接受该参数。
示例:
python -m ltx_pipelines.ti2vid_two_stages \ --checkpoint-path path/to/checkpoint.safetensors \ --prompt "A fast-moving waterfall" \ --num-generated-keyframes 5 \ --output-path output.mp4注意代码中专门提供了has_generated_keyframes(helpers.py)来判断是否请求了槽位,并要求调用方不要直接对参数做真值测试——因为序列可能是 tensor 或 array,其真值判定有歧义甚至抛错。
5.6 读取关键帧结果
生成的关键帧会落在LatentState.generated_keyframes中,形状为(B, C, K, H, W)(K = 关键帧数量,见 types.py)。在clear_conditioning时依据GeneratedKeyframeLayout从去噪后的序列中抽取并 unpatchify 得到。
解码铁律:每个关键帧必须作为独立的单帧片段解码。若把 K 帧当作一个连续视频做因果解码,会把从未在时间上相邻的槽位混合在一起——槽位之间隔着常规潜帧,因果 VAE 的时序因果性会让结果错误。
在 DFR 场景下该规则同样成立且更复杂:DFRPipeline把阶段 1 的generated_keyframes经 upsampler 放大后作为阶段 2 的初始关键帧重新挂载,并在每个 tile 的时间轮次中各自检查tile_state.generated_keyframes(dfr_pipeline.py),最后拼回完整潜变量时显式把generated_keyframes置空。
6. 小结
| 条件类型 | 底层实现 | 关键参数 | 适用管线 |
|---|---|---|---|
| 图像替换式 | VideoConditionByLatentIndex | latent_idx、strength | 全部 |
| 图像引导式 | VideoConditionByKeyframeIndex | frame_idx、strength | 全部 |
| 参考视频 | VideoConditionByReferenceLatent | downscale_factor、temporal_scale_factor、strength | ICLoraPipeline 系列 |
| HDR/EXR | load_image_and_preprocess+--hdr | SRGB_LINEAR/ACESCG/ACESCCT | 标准管线 |
| 生成关键帧槽位 | VideoGeneratedKeyframeSlots | pixel_frame_indices、initial_keyframes | 一阶段管线 + DFR |
选择建议:需要强锚定用替换式,需要平滑插值用引导式;追求运动细节补足用生成关键帧槽位——但务必先确认 checkpoint 支持use_keyframes_abs_pos_embedding,并按 5.3 节的代价模型为 token 预算留出余量。更完整的管线选型对比可参考 Pipeline Selection Guide 与 Available Pipelines。
【免费下载链接】LTX-2Official Python inference and LoRA trainer package for the LTX-2 audio–video generative model.项目地址: https://gitcode.com/GitHub_Trending/lt/LTX-2
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考