feat: 批量流水线按 GPU 资源调度(非 GPU 阶段并行、GPU 阶段互斥)
此前组内阶段是串行的(先全部提音、再全部转写、再全部翻译),LLM 走线上端点时 翻译阶段不占显存、GPU 全程空转——实测占整轮挂钟约 40%(19.6W / 272MiB)。 - `_run_job` 改为按组启动在途流水线:每个视频独立推进自己的阶段,最多 `WOV_BATCH_PIPELINE_WORKERS`(默认 4)个阶段在途。 - 派发只看资源:`stage_gpu_need_mb` 为 0 的阶段(提音、线上翻译、ASS)立刻派发, 可与其它视频的转写并行;需要 GPU 的阶段由 `GpuGate` 互斥准入,并按"阶段索引 最小者优先"派发,组内仍是先跑完全部转写再进翻译——本机 Ollama 模型每组只 加载一次,不需要按"是否云端"写分支。 - 同一阶段只在途一份(派发即标记 running),单视频异常不带走整组;暂停沿用 run 级 paused.flag,暂停后不再派发新阶段。 - 测试:远端翻译与其它视频转写重叠、本机端点下全部转写先于翻译且翻译互斥、 提音与转写重叠,以及既有分组/暂停/失败隔离用例。
This commit is contained in:
@@ -33,7 +33,12 @@ http://127.0.0.1:8000/docs API 文档
|
||||
| `WOV_CLEANUP_GRACE_SECONDS` | `3600` | 孤儿清理宽限期(秒) |
|
||||
| `WOV_BATCH_ENABLED` | `1` | 开启文件夹批量处理引擎(处理 source=batch 任务) |
|
||||
| `WOV_BATCH_INTERVAL_SECONDS` | `1.0` | 批量引擎轮询间隔 |
|
||||
| `WOV_BATCH_STAGE_GROUP_SIZE` | `8` | 批量「分块流水线」分组大小:每组视频按节点顺序跑完全部阶段(全部 extract → 全部 ASR → 全部翻译 → 全部 ASS)再进入下一组,本地模型每组只加载一次;设为 1 等价于每个视频各跑完整链路(产物逐视频落地最及时) |
|
||||
| `WOV_BATCH_STAGE_GROUP_SIZE` | `8` | 批量流水线分组大小:组内每个视频独立推进阶段(详见 [operations.md](./operations.md#文件夹批量处理)),GPU 阶段组内串行、非 GPU 阶段并行;本机模型每组只加载一次 |
|
||||
| `WOV_BATCH_PIPELINE_WORKERS` | `4` | 批量组内在途阶段上限:提音/线上翻译/ASS 等不吃 GPU 的阶段可并行,GPU 阶段仍互斥 |
|
||||
| `WOV_DB_BUSY_TIMEOUT_SECONDS` | `30` | SQLite 写锁等待时长(并发写产物/进度时排队而不是立刻报错);库自动开启 WAL |
|
||||
| `WOV_LOCAL_MODEL_HOSTS` | 空 | 视为「本机模型」的额外主机名/IP(逗号分隔):Ollama 跑在本机局域网地址上时必须声明,否则会被当成不占显存的远端端点 |
|
||||
| `WOV_LOCAL_LLM_RESERVE_MB` | `22528` | 本机 LLM 端点占用的显存预留(MB):常驻期间转写阶段会等待显存 |
|
||||
| `WOV_LOCAL_VLM_RESERVE_MB` | `8192` | 本机 VLM/OCR 端点占用的显存预留(MB) |
|
||||
| `WOV_AUTO_VAD` | `1` | 开启每视频自适应 VAD 调参(详见 [adaptive_vad.md](./adaptive_vad.md)) |
|
||||
| `WHISPER_MODEL_PATH` | 见 [模型权重解析](./node-protocol.md#模型权重解析本地优先) | 显式指定 whisper 模型路径 |
|
||||
| `WHISPER_DEVICE` | `auto` | 转写设备 |
|
||||
|
||||
@@ -85,6 +85,23 @@
|
||||
“COMPLETED 但仍有未结束明细”的脏数据。回归测试见 `test_batch.py` 的
|
||||
`test_job_hidden_from_engine_until_details_written`。
|
||||
|
||||
## 批量流水线按 GPU 资源调度(而不是按"是否云端"分支)
|
||||
|
||||
- **现象**:LLM 走线上端点时翻译阶段不占显存,但组内阶段仍是"先全部提音、再全部
|
||||
转写、再全部翻译"的串行推进,翻译期间 GPU 全程空闲(实测 19.6W / 272MiB,
|
||||
占整轮挂钟约 40%)。
|
||||
- **结论**:阶段能否启动只看资源。`wov_app.resources.stage_gpu_need_mb` 给出每个
|
||||
阶段的显存需求(whisper 按权重 ×1.45、本机 LLM 端点按预留、线上端点为 0),
|
||||
进程内 `GpuGate` 负责准入:不需要 GPU 的阶段立刻放行(转写与线上翻译并行);
|
||||
需要 GPU 的阶段互斥,并按"阶段索引最小者优先"派发,组内因此仍是先跑完全部转写
|
||||
再进翻译——本机 Ollama 模型每组只加载一次,行为与旧实现一致。
|
||||
- **为什么不是"配置分支"**:代码不判断端点是不是云端,只读"这个阶段要不要占
|
||||
GPU、现在够不够"。同一份代码在本机模型下自动退化为串行、在线上模型下自动并行。
|
||||
- **降级**:探测不到 `nvidia-smi` 时退化为 GPU 阶段互斥(与串行结果一致);
|
||||
局域网地址上的本机 Ollama 需用 `WOV_LOCAL_MODEL_HOSTS` 声明,否则会被当成远端。
|
||||
- **并发写**:流水线多线程写产物/进度,SQLite 开 WAL + busy timeout
|
||||
(`WOV_DB_BUSY_TIMEOUT_SECONDS`)。
|
||||
|
||||
## 相关文档
|
||||
|
||||
- 当前生效的参数与协议:[node-protocol.md](./node-protocol.md)
|
||||
|
||||
+14
-9
@@ -104,15 +104,20 @@
|
||||
run 的 `current_node_id` 在 DAG 拓扑序中的位置推导、节点类型映射中文标签。
|
||||
粒度限制:`progress` 只有**节点边界**粒度,句级进度(转写分块、翻译批次、OCR 帧)
|
||||
不落库、只在控制台日志里。
|
||||
- **分块流水线执行(本地模型只加载一次)**:批量引擎把待处理视频按
|
||||
`WOV_BATCH_STAGE_GROUP_SIZE`(默认 8)分组,**组内按节点顺序跑完全部视频**
|
||||
(先全部 extract、再全部 ASR、再全部 LLM 翻译、最后 ASS)再进入下一组。每个
|
||||
视频的 run 在阶段边界保持 RUNNING(`execute_run(stop_after=节点)`),下一阶段
|
||||
从产物表跳过已完成节点继续,因此本地模型每组只加载一次、卸载一次,而不是每个
|
||||
视频来回加载卸载;产物仍按组增量落地。LLM 阶段执行时引擎在 run 根目录写
|
||||
`keep_model.flag`,节点据此不在每次调用后卸载模型(`nodes/llm.py`),阶段
|
||||
结束由引擎调 `release_local_model()` 统一释放显存,让下一组的 ASR 拿到 GPU
|
||||
(否则本地模型常驻显存会让 whisper 直接 CUDA OOM)。设为 1 即回到「每个视频
|
||||
- **按资源调度的在途流水线(2026-09 起)**:批量引擎把待处理视频按
|
||||
`WOV_BATCH_STAGE_GROUP_SIZE`(默认 8)分组,组内**每个视频独立推进自己的
|
||||
阶段**,最多 `WOV_BATCH_PIPELINE_WORKERS`(默认 4)个阶段在途。判定只看资源:
|
||||
阶段是否需要 GPU 由 `wov_app.resources.stage_gpu_need_mb` 给出(提音、**线上
|
||||
端点**的翻译、ASS 都不需要),不需要 GPU 的阶段立刻派发,于是转写能与线上翻译
|
||||
并行、提音能与转写并行(此前组内阶段是串行的,翻译时 GPU 全程空转)。需要 GPU
|
||||
的阶段由进程内 `GpuGate` 串行准入并按"阶段索引最小者优先"派发,因此组内仍是
|
||||
先跑完全部转写再进翻译——**本机 Ollama 模型每组只加载一次**,不需要按"是否
|
||||
云端"写分支。每个视频的 run 在阶段边界保持 RUNNING(`execute_run(stop_after=节点)`),
|
||||
下一阶段从产物表跳过已完成节点继续。LLM 阶段执行时引擎在 run 根目录写
|
||||
`keep_model.flag`,节点据此不在每次调用后卸载模型(`nodes/llm.py`),组末由
|
||||
引擎调 `release_local_model()` 统一释放显存,让下一组的 ASR 拿到 GPU(否则
|
||||
本机模型常驻显存会让 whisper 直接 CUDA OOM)。显存探测不到(无 `nvidia-smi`)
|
||||
时退化为"GPU 阶段互斥",行为与串行一致。设为 1 即回到「每个视频
|
||||
跑完整链路」的旧行为。
|
||||
- **失败视频不跨阶段推进**:某阶段失败的视频只在**它失败节点的那个阶段**重试
|
||||
(下一次引擎循环从断点续跑),不会在后续阶段里重跑前序节点——避免本地 LLM 已
|
||||
|
||||
Reference in New Issue
Block a user