Files
nvlabs--longlive/utils/DATASET_PROMPT_LOGIC.md
2026-07-13 12:31:40 +08:00

7.8 KiB
Raw Permalink Blame History

Dataset Prompt 分配逻辑说明

本文档说明 MultiTextConcatDataset(纯文本)和 MultiVideoConcatDataset(视频训练)在不同配置下产生 prompts 的行为。


架构总览

使用场景 Dataset 类 输出
diffusion.py 训练 MultiVideoConcatDataset frames + prompts
diffusion.py 推理 MultiTextConcatDataset prompts
distillation.py 训练(backward_sim MultiTextConcatDataset prompts
distillation.py 可视化 MultiTextConcatDataset prompts
inference.py MultiTextConcatDataset prompts

一、MultiTextConcatDataset(纯文本)

关键参数

参数 含义
num_blocks 输出 prompt 列表的固定长度
chunks_per_shot 每个 shot 重复的 block 数(0=使用 even_durations 均分)
scene_cut_prefix 切镜标记前缀,默认 "The scene transitions. "

简写约定:0, 1, 2 表示不同 captionp+X 表示 scene_cut_prefix + X

1. txt 模式(data_path 指向 .txt 文件)

每行一个 caption,每个 sample 取 idx 行的 caption,重复 num_blocks 次。 不加 scene_cut_prefix(单 shot 语义)。

data_path="prompts.txt", line[3]="A dog runs", num_blocks=12
→ [A, A, A, A, A, A, A, A, A, A, A, A]

无论 chunks_per_shot 设为多少,txt 模式始终单 shot 重复。

2. 目录模式(data_path 指向目录)

读取 caption/<subfolder>/*.json(不需要 video/ 目录)。 每个 JSON 的 caption 字段作为一个 shot 的文本。

Shot duration 三级 fallback

按优先级决定每个 shot 占多少个 block:

  1. shot_durations.txtper-folder 文件)— 每行或逗号分隔的整数
  2. chunks_per_shot(全局 config)— 所有 shot 统一重复固定次数
  3. _even_durations(均分)— 将 num_blocks 均匀分给所有 caption

长度处理

输出始终恰好 num_blocks 个 prompt

  • 超过 → 截断尾部
  • 不足 → 用最后一个 caption 直接 padding不加 scene_cut_prefix

示例

3 caption, num_blocks=12, chunks_per_shot=4

captions: [0, 1, 2]
shot_durations: [4, 4, 4]
→ [0, 0, 0, 0, p+1, 1, 1, 1, p+2, 2, 2, 2]

3 caption, num_blocks=12, chunks_per_shot=0even_durations

captions: [0, 1, 2]
even_durations: base=4, extra=0 → [4, 4, 4]
→ [0, 0, 0, 0, p+1, 1, 1, 1, p+2, 2, 2, 2]

2 caption, num_blocks=12, chunks_per_shot=4

captions: [0, 1]
shot_durations: [4, 4], sum=8 < 12 → 最后一个 shot 扩展到 8
→ [0, 0, 0, 0, p+1, 1, 1, 1, 1, 1, 1, 1]
                                  ↑ padding 不加 prefix

5 caption, num_blocks=12, chunks_per_shot=4

captions: [0, 1, 2, 3, 4]
shot_durations: [4, 4, 4, 4, 4], 但 num_blocks=12 → clamped 到 [4, 4, 4]
→ [0, 0, 0, 0, p+1, 1, 1, 1, p+2, 2, 2, 2]
   caption 3 和 4 被截断

2 caption, num_blocks=12, chunks_per_shot=0even_durations

captions: [0, 1]
even_durations: base=6, extra=0 → [6, 6]
→ [0, 0, 0, 0, 0, 0, p+1, 1, 1, 1, 1, 1]

1 caption, num_blocks=12

captions: [0]
→ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
   单 shot,不加 prefix

shot_durations.txt 覆盖

captions: [0, 1, 2], shot_durations.txt 内容: "2, 6, 4", num_blocks=12
→ [0, 0, p+1, 1, 1, 1, 1, 1, p+2, 2, 2, 2]

二、MultiVideoConcatDataset(视频训练)

关键参数

参数 含义
total_segments 总 segment 数量(= 1 + num_subsequent_segments
single_video_only config 中的 uniform_promptTrue 时只从一个视频采样
max_chunks_per_shot 单镜头最大连续 chunk 数,超过则跳 1 秒做虚拟切镜(0=不限制)
scene_cut_prefix 切镜标记前缀
allow_padding 视频不够时是否允许 padding(否则跳过该 folder

Prompt 由实际视频采样决定,逐 segment 从视频文件加载对应的 per-video caption。

1. 多视频自然拼接(max_chunks_per_shot=0,默认)

按视频文件顺序采样,切换视频文件时加 scene_cut_prefix

video A 够采 3 chunks, video B 够采 4 chunks, total_segments=7
→ [A, A, A, p+B, B, B, B]

2. single_video_only=True

强制只从一个视频文件采样。视频不够长则整个 folder 被跳过:

video A 够采 7 chunks, total_segments=7
→ [A, A, A, A, A, A, A]

video A 只够采 5 chunks, total_segments=7
→ (失败,跳到下一个 folder)

3. max_chunks_per_shot=3(限制单镜头时长)

从同一视频连续采超过 3 chunks 后,跳 1 秒做虚拟切镜,加 scene_cut_prefix

video A 很长, video B, total_segments=7, max_chunks_per_shot=3
→ [A, A, A, p+A, A, A, p+B]
             ↑跳1秒虚拟切镜   ↑换视频

如果跳 1 秒后 A 不够了,直接跳到 B:

video A 够 4 chunks(跳1秒后不够), video B, total_segments=7, max_chunks_per_shot=3
→ [A, A, A, p+B, B, B, B]
             ↑A跳1秒后不够,换B

4. single_video_only=True + max_chunks_per_shot=3

单视频内也可以做虚拟切镜:

video A 很长, total_segments=7, single_video_only=True, max_chunks_per_shot=3
→ [A, A, A, p+A, A, A, p+A]

5. 训练 paddingallow_padding=True

视频不够时用最后一个 caption 直接 padding(不加 prefix):

video A 够采 3 chunks, video B 够采 2 chunks, total_segments=7, allow_padding=True
→ [A, A, A, p+B, B, B, B]
                      ↑后 2 个用最后一个 caption padding

三、Multi-Shot Sink

通过 config 的 multi_shot_sink: true 开启。 开启后,当检测到某个 block 处于新场景的起始位置时,会在该 block 去噪完成并更新 cache 后, 将 KV cache 的 attention sink 从旧场景的第一帧迁移到新场景的第一帧。 同时会自动把全局 sink 长度设为 sink_size,不需要单独配置 global sink。

配置方式yaml config 中添加):

sink_size: 8
multi_shot_sink: true    # 默认 false,不迁移 sink

此选项在以下所有场景均生效:

场景 Pipeline 检测方式
Diffusion trainer evaluation CausalDiffusionInferencePipeline 检查 prompt 是否以 scene_cut_prefix 开头
Distillation trainer evaluation CausalDiffusionInferencePipeline 同上
离线推理 inference.py CausalDiffusionInferencePipeline 同上
Distillation backward simulation SelfForcingTrainingPipeline trainer 预计算 scene_cut_mask 传入 conditional_dict
Streaming long tuning SelfForcingTrainingPipeline 同上(mask 随 chunk 自动 slice

实现机制

Inference pipelineCausalDiffusionInferencePipeline): 直接检查每个 chunk 的 raw prompt 是否以 scene_cut_prefix 开头。

Training pipelineSelfForcingTrainingPipeline): 由于 prompts 在进入 pipeline 前已编码为 embedding,无法从 embedding 反推文本。 因此 trainer 在编码前从原始 prompts 计算布尔列表 scene_cut_mask 放入 conditional_dict["scene_cut_mask"] 一路透传到 pipeline。 对于 streaming trainingscene_cut_mask_slice_cond_dict_for_chunk 中随 prompt 一起 slice。

block:  [0]  [1]  [2]  [p+3]  [4]  [5]  [p+6]  [7]
mask:    F    F    F    T      F    F    T       F
sink:    0    0    0   →3      3    3   →6       6
                       ↑更新sink          ↑更新sink

multi_shot_sink: false(默认)时,sink 始终锚定在视频的第一帧,不做任何迁移。

scene_cut_prefixDEFAULT_SCENE_CUT_PREFIX 常量定义(dataset.py), inference pipeline 引用同一常量,确保训练和推理的切镜检测一致。 可通过 config 中的 scene_cut_prefix 字段统一覆盖。