数据管线审计(data_pipeline_audit.md,2026-07-23)
对象:diffsynth/trainers/utils.py 的 CamVideoDataset(第 613 行起),即 two-chunk 训练实际使用的数据集类。对照 doc/dataset_preprocessing.md、scripts/README.md、env/loop_utils.py。
总结论:metadata_full.csv 是不可省的硬依赖(三重坐实);captions.txt 是"强制但内容无用";另有 4 处静默失效和 2 处尖锐耦合。
1. 硬依赖 / 必崩
| # | 位置 | 问题 |
|---|---|---|
| 1 | utils.py:695-697 |
metadata_path=None 时调用 self.generate_metadata(base_path),但 CamVideoDataset 直接继承 torch.utils.data.Dataset(:613),没有这个方法——它属于 VideoDataset(:244)→ AttributeError。即便把方法搬过来也没用:generate_metadata 扫的是".mp4 + 同名 .txt"布局并只产出 video/prompt 两列,而 _try_get_sample(:1025-1032)要读 video_name/start_frame/end_frame → 紧接着 KeyError。**"无 metadata 自动生成"是彻底的死路。** |
| 2 | utils.py:722-724 |
open(base_path/captions.txt) 无 try/except → 文件缺失即 FileNotFoundError。但 doc/dataset_preprocessing.md 第 2 节把它标为 "optional for some workflows",文档与代码矛盾。 |
对下载路线的影响:doc/dataset_preprocessing.md 的 Option B(上游 KlingTeam/KwaiVGI 源,即 ModelScope 那份)不含 metadata_full.csv,scripts/README.md:9-13 专门交代要另外补。走 Option B 必须单独从 HF 拉这个 767 MiB 的文件,否则训练起不来。
2. 静默失效(跑得起来但不对)
| # | 位置 | 问题 |
|---|---|---|
| 3 | utils.py:679 |
self.repeat = repeat 之后全类再无引用,__len__(:1199)直接返回 len(self.data) 不乘 repeat → --dataset_repeat 完全空转,设了等于没设。 |
| 4 | utils.py:1136-1147 |
__getitem__ 的坏样本容错整段被注释掉,return self._try_get_sample(...) 无条件在 attempt 0 执行 → for attempt in range(max_attempts) 只跑一轮、self.invalid_scenes/invalid_metadata_indices 成死状态、末尾 raise RuntimeError(...last_error...) 不可达(last_error 恒为 None)。数据集是 100 场景 × 7601 张 PNG ≈ 76 万文件,任何一个损坏/缺失都会崩掉整个训练,而原设计是跳过。 |
| 5 | utils.py:1075 |
_try_get_metadata_sample 从未被调用(__getitem__ 只走 _try_get_sample)。它是 _find_nearest_caption(:810)的唯一活调用点,而 _try_get_sample 里取 caption 的那行被注释了(:1041,改为 prompt = data_item["prompt"])→ captions.txt 的内容实际只用于 :755-756 的日志计数,不参与任何采样。命名也反了:叫 metadata 的那个是死的,不叫 metadata 的那个才在吃 metadata 行。 |
| 6 | utils.py:741-746 |
self.metadata_rows 把 767 MiB / ~24 万行的 CSV 第二次 pd.read_csv + 逐行 to_dict() 进内存(self.data 在 :719-720 已经存了一份同样的东西),而它只被 :757 的一行日志和 :758 的 effective_len 使用——**effective_len 算完之后从未被用过**。每个 DataLoader worker fork 后都白扛这一份冗余副本。 |
3. 尖锐耦合(改参数会炸)
| # | 位置 | 问题 |
|---|---|---|
| 7 | utils.py:1032 |
assert end_frame == data_item["end_frame"],而 end_frame = start_frame + self.num_frames - 1。这把 --num_frames 与 metadata 生成时的段长(81)死绑:改成别的值会让每一个样本都 AssertionError,而不是给出可读的报错。 |
| 8 | utils.py:1057-1058 |
pose_indices = range(0, num_frames, 4) → 81 帧取 21 个位姿,对齐 21 个 latent 帧。改 num_frames 必须同步改这个 stride,否则位姿数与 latent 帧数错位。与 #7 是同一处耦合的两面。 |
4. 数据契约(实测确认)
metadata_full.csv 必需列(_try_get_sample 直接索引,缺一即 KeyError):
video_name(= frames/ 下的场景目录名)、start_frame、end_frame、prompt。
captions.txt 格式(:725-735 解析):制表符分隔的 场景名/起始帧_结束帧.mp4 \t caption;场景名取最后一个 / 之前,clip_start 取文件名 _ 之前的整数。内容不参与采样,但文件必须存在。
jsons/<scene>.json 必须是 dict 且含 CineCameraActor 键(_load_scene_poses,:790 起),每帧含 position/rotation;位置乘 cam_position_scale(默认 0.01)。
5. 修复建议(按性价比)
- P0:#4 恢复
__getitem__的容错(取消注释即可)——76 万文件的数据集不做坏样本跳过,长训练几乎必然中途崩。 - P1:#1 把
metadata_path=None分支改成明确报错("CamVideoDataset requires a metadata CSV; see scripts/README.md"),而不是 AttributeError;#7 把 assert 换成带上下文的 ValueError。 - P2:#6 删掉
metadata_rows冗余副本(省每 worker 数 GB 内存);#3 要么实现 repeat 要么删掉该参数;#5 删死代码或把captions.txt改成软依赖;#2 同步修正doc/dataset_preprocessing.md的 optional 表述。