1
0
0

video-subtitle-remover 字幕抹除部署:预构建包、CUDA 库冲突与算法取舍

📝 笔记摘要:video-subtitle-remover 字幕抹除部署

VSR 是去除视频硬字幕的开源工具,Apache 2.0 协议,特点是只在字幕那一小块矩形里做修复,其余像素原样拷贝,所以叫「无损分辨率」。原笔记记的是一次实际的源码安装过程,卡在 CUDA 库加载上,留下了 unset LD_LIBRARY_PATH 这个动作。

动作本身能用,但原笔记漏了三件更要紧的事:发布包是 .7z 不是 zip、Paddle 版本 pin 的是 2.6.2 而当前是 3.0.0、README 明确说优先用预构建包,源码安装只是兜底。另外记进笔记的 conda install cudatoolkit 这条命令,conda-forge 已经在 CUDA 12 迁移时把 cudatoolkit 这个包整个移除了,新版上跑会直接 PackagesNotFound。

环境隔离和 screen 会话的部分在 conda 与 screen 运维速查。

1. 流水线:六段

核心思路决定了它的能力边界:不碰字幕区之外的任何像素。所以画面越干净、字幕越小,修复效果越好;反过来,字幕压在复杂纹理上时,任何算法都会露出痕迹。

六段纵向流水线图:解码用项目自带 FFmpeg 拆帧不转码,字幕检测用 PaddleOCR DB 模型,裁剪按 -c 指定区域,修复用 inpaint 算法,回贴做 BOX_BLUR 边缘模糊,收尾编码输出

解码不转码,这是「无损」的第一层
  backend/ffmpeg/ 里预置了各平台的 FFmpeg 二进制,不依赖系统装的版本
  拆帧直接出图片,跳过重采样,中间没有一次画质损失
字幕检测是最耗时的一段
  模型在 backend/models/V4/ch_det,逐帧找文字框
  整个流程的进度感基本等于检测的进度
场景切换会重算区域
  用 ContentDetector 判断镜头切换,切一次字幕区就重算一次
  这是防止镜头切换后新增字幕被漏掉的兜底
只想拿字幕文件就别用 VSR
  姊妹项目 video-subtitle-extractor(VSE)做同样的检测,导出 SRT 而不做修复
自带 FFmpeg 报错时
  预构建包解压失败或者 backend/ffmpeg/ 下的二进制在当前系统跑不起来,
  系统里得有一个能用的 FFmpeg,装法见 Linux 上装 ffmpeg

2. 先选路线

README 第一句就是优先用预构建包。源码安装要自己处理 Paddle 与 Torch 的 CUDA 版本对齐,是预构建包跑不起来时的兜底,不是首选。

部署路线图:上方绿色框说明路线一用预构建包;中间两行卡片列出五个包的适用范围,CPU 包无独显可用、DirectML 包给 AMD Intel 显卡、三个 CUDA 包按计算能力 3.5 到 9.0 区分;下方红框指出原笔记写 unzip 是错的,包是 7z 格式
# 判断自己的卡属于哪一档
nvidia-smi

看 nvidia-smi 的两个位置
  右上角 CUDA Version 是驱动支持的最高 CUDA 版本
  下面 GPU 0 那行里的 Compute Capability 决定选哪个包
  比如 8.6 是 RTX 30 系,三个 CUDA 包的区间都覆盖
没有 Nvidia 显卡会直接报错
  nvidia-smi: command not found 就是没装驱动或者压根不是 N 卡
  这时候选 directml 包(AMD / Intel 核显)或 cpu 包
Docker 镜像的标签别选错
  eritpchy/video-subtitle-remover:1.4.0-cuda11.8 这种形式
  标签就是 CUDA 运行时版本,选错等于换了一套 CUDA
  可用标签:cuda11.8、cuda12.6、cuda12.8、directml、cpu

3. 路线一:预构建包

原笔记这一步是错的
  写的「使用 unzip 进行解压」——发布包是 .7z,unzip 解不了
  README FAQ 里明确要求先升级到 7-Zip 24.x 及以上,老版本解压大文件会报数据错误
  Windows 资源管理器右键直接选 7-Zip → 解压到 xxx 目录就行,不用命令行
五个包的依赖版本
  vsr-windows-cpu.7z    Python 3.12 / Paddle 3.0.0 / Torch 2.7.0
  vsr-windows-directml.7z Python 3.12 / Paddle 3.0.0 CPU / torch_directml
  …-nvidia-cuda-11.8.7z  计算能力 3.5 – 8.9
  …-nvidia-cuda-12.6.7z  计算能力 5.0 – 8.9
  …-nvidia-cuda-12.8.7z  计算能力 5.0 – 9.0+
解压后不用碰 pip 和 conda
  包里的 Python 解释器和依赖都是现成的,FFmpeg 也在 backend/ffmpeg/
  这一步之所以值得优先,就是因为它把下面第 4 到 6 节的所有麻烦全跳过了

4. 路线二:源码 + conda

预构建包解决不了的场景才走这条:需要改代码、Linux 上部署、或者要在指定 CUDA 版本上复现。

# 系统依赖,Linux
apt install cmake ffmpeg libgl1 libglib2.0-0

# 建环境,Python 3.12 是硬要求
conda create -n VSR python=3.12 -y
conda activate VSR

# 按显卡选一组,下面四组选一组

# A. Nvidia + CUDA 11.8
pip install paddlepaddle-gpu==3.0.0 -i https://www.paddlepaddle.org.cn/packages/stable/cu118/
pip install torch==2.7.0 torchvision==0.22.0 --index-url https://download.pytorch.org/whl/cu118
# Linux 上还需要这一条
pip install onnxruntime-gpu==1.20.1 --index-url https://aiinfra.pkgs.visualstudio.com/PublicPackages/_packaging/onnxruntime-cuda-11/pypi/simple/

# B. AMD / Intel 核显,走 DirectML
pip install paddlepaddle==3.0.0 -i https://www.paddlepaddle.org.cn/packages/stable/cpu/
pip install torch_directml==0.2.5.dev240914

# C. 纯 CPU
pip install paddlepaddle==3.0.0 -i https://www.paddlepaddle.org.cn/packages/stable/cpu/
pip install torch==2.7.0 torchvision==0.22.0

# 依赖装齐
pip install -r requirements.txt

原笔记 pin 的版本过时了
  原文写 paddlepaddle-gpu==2.6.2.post118,那是上一代
  当前官方要求 3.0.0,预构建包里带的也是这个版本
  两代 wheel 的 API 有变化,按老版本写的启动脚本在新版上会报错
PyPI 上没有 GPU 版
  pip install paddlepaddle-gpu 不带 -i 会装成 CPU 版或者直接找不到包
  GPU 版的索引地址在 Paddle 官方站,不是 PyPI,必须显式带 -i
Linux 少一条会怎样
  不装 onnxruntime-gpu 那条,程序能启动,但在某些分支上回落到 CPU 推理
  表现是能跑、就是慢好几倍,不报错,很难定位
Python 3.12 是下限不是上限
  官方要求 3.12 或更高,但更高版本未必兼容,3.12 是最稳的
  建环境时就锁死 python=3.12,别用 python=3.13 这种模糊写法

5. 两份 cuDNN 打起来

原笔记里 unset LD_LIBRARY_PATH 那两行,就是这一步的解药。但只记了动作没记原理,换台机器就不灵了。

原理示意图:上方红色框写症状,中间并排两张卡片分别是 conda 装的 cuDNN 8.9.7 和 paddle wheel 自带的 cuDNN 8.6.0,中间加号表示两者同时存在;下方说明动态链接器按 LD_LIBRARY_PATH 顺序从前往后找、命中第一个就用不看版本;再下方左右两张卡片对比笔记里改顺序的做法和全程用 conda 的做法
# 笔记里的解法:把 conda 那份顶到最前
unset LD_LIBRARY_PATH
export LD_LIBRARY_PATH=$CONDA_PREFIX/lib:$LD_LIBRARY_PATH

为什么会撞
  conda install cudnn -c conda-forge 装一份进 $CONDA_PREFIX/lib/
  pip install paddlepaddle-gpu 的 wheel 自带一份在 site-packages/paddle/libs/
  两套管理体系在同一个环境里叠上了,这是根因
动态链接器不看版本
  进程要 libcudnn.so.8 时,按 LD_LIBRARY_PATH 顺序从前往后找
  命中第一个就用,不做版本兼容判断,另一份被完全无视
  所以报的是 version \`CUDNN_VERSION_8.6.0' not found 这种看着莫名其妙的错
原笔记的 cudnn 版本和 README 冲突
  笔记装 cudnn=8.9.7,VSR README 对 CUDA 11.8 推荐的是 8.6.0
  8.6.0 正是 paddle wheel 自带的那份,两边对齐之后其实根本不需要改 LD_LIBRARY_PATH
更干净的做法是别混装
  全程 conda 装 paddle,频道用 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/Paddle/(即 anaconda.org/paddle)
  或者全程 pip,不碰 -c conda-forge
  conda-forge 的 cudatoolkit 已经被移除
  CUDA 12 迁移时改成按组件拆分,conda install cudatoolkit=11.8 -c conda-forge 在新版上直接 PackagesNotFound
  这是原笔记里第三条命令现在跑不通的原因,跟 LD_LIBRARY_PATH 无关
怎么确认实际加载了哪一份
  python -c "import paddle; print(paddle.utils.run_check())" 看 GPU 是否可用
  LD_DEBUG=libs python -c "import paddle" 2>&1 | grep cudnn 能看到每个候选路径和最终选中的那个

6. 修复算法怎么选

算法配置在 backend/config.py 的 MODE 里,改完要重启进程。

对比表格:STTN 真人视频好速度快显存低可跳过检测,LAMA 图片和动画最好速度一般不可跳过检测,PROPAINTER 运动剧烈场景好但慢且吃显存,OpenCV 纯遮罩填充极快但效果差;下方两张卡片分别说明 STTN 三个参数的关系和 LAMA_SUPER_FAST 的取舍

默认 sttn-auto,多数情况不用改
  真人视频、录屏、采访类素材,STTN 又快又稳
LAMA 留给静态画面
  番剧截图、二次元素材这类,LAMA 明显占优
  代价是速度一般,而且不可跳过字幕检测
PROPAINTER 是显存杀手
  运动剧烈的片段效果最好,但速度和显存都是最差的一档
STTN 三个参数有硬约束
  STTN_NEIGHBOR_STRIDE 参考多少邻近帧
  STTN_REFERENCE_LENGTH 参考帧总数
  STTN_MAX_LOAD_NUM 一次进显存多少帧
  MAX_LOAD_NUM 必须大于前两者,不满足会直接抛异常,不会自动纠正
LAMA_SUPER_FAST 别开
  默认 False,改成 True 快一些但填充质量肉眼可见下降

7. 跑起来

# 命令行
python ./backend/main.py -i input.mp4 -o output.mp4

# 手工指定字幕区域:-c 接四个数,上下左右,-c 可以多次
python ./backend/main.py -i input.mp4 -o output.mp4 -c 800 950 100 1200

# 指定算法
python ./backend/main.py -i input.mp4 -o output.mp4 --inpaint-mode lama

# 图形界面
python gui.py

-c 的四个数是像素坐标
  顺序是 YMIN YMAX XMIN XMAX,Y 在前不是 X 在前
  给大了会拖慢速度并让周围变糊,给小了字幕去不干净
指定 -c 就等于放弃字幕检测
  这是最直接的提速手段,PaddleOCR 那段整个跳过
  但框歪了不会有任何报错,输出里残留半截字幕,而且要逐个视频试
  批量处理建议让它自己检
先拿十秒样本试参数
  拿完整片跑一遍再发现算法选错,机器得白忙几小时
  截一小段出来先把 -c 和 --inpaint-mode 定下来
输出目录要存在
  -o 指到不存在的目录会直接失败,不会自动创建

💡 补充几个原文没写的:

抹除不等于提取
  这两个方向是分开的项目,要 SRT 用 VSE,要无字幕视频用 VSR
无损的是分辨率,不是码率
  原片重编码之后码流必然变,但分辨率和字幕区之外的像素保持不变
  对画质敏感的场景,输出后再压制一遍比一次性上高码率更稳
硬字幕才能抹
  烧录进画面的才行;外挂的软字幕(.ass、.srt)换个播放器关掉就有,不需要这个工具
models 目录别跟着仓库同步
  backend/models/ 和 backend/ffmpeg/ 都是二进制,体积大
  备份代码时排除掉,同步到国内机器也会慢
显存不够先降 STTN_MAX_LOAD_NUM
  从 30 往下调,但必须仍然大于 NEIGHBOR_STRIDE 和 REFERENCE_LENGTH
  降到 0 报 CUDA 内存不足,说明该换 PROPAINTER 关掉改用小 batch 了
多核机器设一下线程
  CPU 模式下 OMP_NUM_THREADS 不设的话会占满全部核,SSH 会话容易变卡
版本号跟着 Release 走
  预构建包、Docker 标签、requirements 三处的版本要对得上
  跨版本混用时 config.py 的参数名可能已经改了

🔥 一句话总结:VSR 部署能走预构建包就别碰源码——.7z 解压、跑 python gui.py,Python、Paddle 3.0.0、Torch 2.7.0、FFmpeg 全都配好了;非走源码不可时,Paddle 必须从官方站带 -i 装 paddlepaddle-gpu==3.0.0,Torch 从 PyTorch 官方索引装同 CUDA 版本;conda 和 pip 不要混着装 CUDA 组件,两份 cuDNN 同时在盘上时动态链接器只认 LD_LIBRARY_PATH 里排在前面的那个;算法默认 sttn-auto,静态画面换 lama,运动剧烈换 propainter,调 STTN 时 MAX_LOAD_NUM 必须大于另外两个参数。

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或者给予支持!