echo / code /data_pipeline_audit.md
amonshano's picture
Add Echo-Memory codebase used for this run (CC BY 4.0, JD Echo Team)
00c7b31 verified
|
Raw
History Blame Contribute Delete
5.07 kB
# 数据管线审计(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 表述。