mlsubgen — 在你自己的机器上为视频生成 45 种语言的字幕
摘要
mlsubgen 是一款开源命令行工具,完全在本地机器上为视频生成 45 种语言的字幕,采用基于 CUDA 的语音识别(Qwen3-ASR、Whisper large-v3)以及由 Ollama 托管的 LLM 翻译,并提供硬件配置方案,最低只需 8 GB 显存的 GPU。
查看缓存全文
缓存时间: 2026/10/03 04:57
dodgypast/mlsubgen
来源:https://github.com/dodgypast/mlsubgen
mlsubgen — 为你的视频生成 45 种语言的字幕,全部在你自己的机器上完成
cd /some/folder/of/videos
mlsubgen
该文件夹及其子目录下的每个视频,都会生成一个 .srt 字幕文件,对应你要求的每种字幕语言(.en.srt、.th.srt …)。数据不会离开机器:语音由本地模型转写,翻译由本地 LLM 完成,唯一写入的文件就是视频旁边的那些 .srt。
mlsubgen = multi-language(多语言)+ machine-learning(机器学习)字幕生成器。
它最初是一个日文→英文的工具,用于个人视频库,后来发展为通用工具:它会检测每一段语音的语言,强制用该语言对每段进行转写,并为 45 种目标语言各自生成独立文件。
硬件要求
| 需求 | 说明 | |
|---|---|---|
| GPU | 显存至少 8 GB 的 NVIDIA 显卡;完整质量配置需要 24 GB | 仅支持 CUDA——没有 AMD、Apple 或 Windows 路径,因为 ASR 引擎都是 CUDA 构建。显卡从不同时持有语音引擎和翻译器(一次运行会先转写一批文件,释放显卡,再进行翻译),所以它只需要能容纳较大的那个阶段。在 RTX A5000(24 GB)上开发并测量;较小的配置以更少的常驻显存运行同一套代码,仅经过轻度测试 |
| RAM | 最低 16 GB,推荐 32 GB | 模型在进入显卡之前会经过内存;OCR 期间同时运行四个 tesseract 进程;在小显存显卡上,Ollama 放不下翻译器时会将一部分溢出到内存 |
| CPU | 4 核或以上 | 说话人分离、位图解码和 tesseract OCR 在 CPU 上运行,而非 GPU |
| 磁盘 | 根据配置 30–65 GB | Docker 镜像约 14 GB(或宿主机上 venv 约 6 GB)· ASR 模型约 8 GB(Qwen3-ASR 及其对齐器、whisper large-v3)· Ollama 中的翻译器:full ≈ 37 GB(两个模型),12gb 7 GB,8gb 6 GB · 说话人模型 33 MB · tesseract 语言包约 0.5 GB · 每个视频的工作文件和 OCR 缓存几 MB;临时 wav 每小时视频约 120 MB,用完即删 |
| 操作系统 / 工具 | Linux;ffmpeg/ffprobe;同一宿主机上的 Ollama(https://ollama.com);带 NVIDIA Container Toolkit 的 Docker,或 Python 3.12 + uv(https://docs.astral.sh/uv/)用于宿主机安装 | 在 Arch 系(CachyOS)和 Debian 系系统上测试 |
启动时会根据显存自动选择硬件配置(mlsubgen models 或 mlsubgen config 会显示;MLSUBGEN_PROFILE=12gb 或 --profile 12gb 可强制指定;mlsubgen pull 会下载当前配置所需的模型)。24 GB 以下的配置共用一个技巧,于 2026-10-03 测得:翻译器是 Gemma 4 的 26B 混合专家模型(gemma4:26b,磁盘占用 18 GB),其 30 层中只有能装下的部分放在显卡上,其余由 Ollama 从系统内存运行。由于它每个 token 只有约 4B 参数是激活的,大部分层不在显卡上也能保持快速——24 层常驻时生成速度为 84 tok/s,16 层时为 51,8 层时为 40(短提示,在一张 24 GB 显卡上限制为这些拆分方式测得)——而且翻译质量几乎与 31B 相当(同一段片段和参考文本的 chrF++ 为 30.2,而 31B 为 31.0;稠密的 12B 为 29.0),读取泰文、中文和日文位图的能力也完全相同(76% / 93.8,而 31B 为 77% / 93.7)。端到端计算,包含提示词,十分钟测试片段用 16gb 拆分(22 层)翻译成泰文只需 68 秒,26B 完全装在 24 GB 显卡上时需 31 秒,用 31B 则需 103 秒。代价是不放在显卡上的那部分需要系统内存:没有足够内存的机器会改用稠密的小模型(-dense 配置,内存不足时自动选择)。
full — 20 GB 及以上 | 16gb — 15 到 20 GB | 12gb — 11 到 15 GB | 8gb — 11 GB 以下 | |
|---|---|---|---|---|
| 显卡,例如 | RTX 3090 / 4090 / 5090,RTX A5000 / A6000,L4(24 GB) | RTX 4080,4070 Ti Super,4060 Ti 16 GB,5070 Ti,RTX A4000,V100 | RTX 3060 12 GB,4070,3080 12 GB,5070 | RTX 3050 / 3070 / 4060(8 GB),2070 / 2080 |
| 该配置所需的系统内存 | 16 GB | 16 GB | 24 GB(否则用 12gb-dense) | 32 GB(否则用 8gb-dense) |
| 语音识别 | 两个引擎常驻,whisper 用 float16(≈ 10 GB) | 两个引擎常驻,whisper 用 float16(≈ 10 GB) | 两个引擎常驻,whisper 用 int8(≈ 8 GB) | 显卡上一次只放一个引擎(≈ 5 GB,然后 ≈ 2.5 GB);同样的两个引擎,每个文件更慢 |
| 翻译 | 日文→英文用 qwen3.8:27b,其余语言对用 gemma4:31b-it-qat,全部装在显卡上(测试片段:103 秒) | gemma4:26b,30 层中 22 层装在显卡上(≈ 13 GB):测试片段 68 秒,实测 | gemma4:26b,14 层装在显卡上(≈ 9 GB):生成速度约 50 tok/s,片段约 100 秒 | gemma4:26b,6 层装在显卡上(≈ 5 GB):生成速度约 40 tok/s,片段约 2 分钟 |
翻译,-dense 备选 | — | — | gemma4:12b-it-qat(7.2 GB):chrF++ 29.0 | gemma4:e4b-it-qat(6.1 GB):更弱 |
| 逐段语言检测 | 是 | 是 | 是 | 是 |
| 内嵌文本字幕(优先于音频使用) | 是 | 是 | 是 | 是 |
| 位图字幕,拉丁 / 希腊 / 西里尔文(tesseract,CPU) | 是 | 是 | 是 | 是 |
| 位图字幕,泰文 / 中文 / 日文 / 韩文 / 叠加标记文字(视觉模型) | 是——31B | 是——26B,效果与 31B 相当 | 是——26B(12gb-dense 用 12B,可用但较弱) | 是——26B,速度较慢(8gb-dense:否,E4B 读不了;这些音轨会被跳过,转而转写音频) |
| 说话人分离(CPU) | 是 | 是 | 是 | 是 |
| 术语统一处理(人名全片只翻译一次) | 是 | 是 | 是 | 是 |
| bench / lidbench / ocrbench | 是 | 是 | 是 | 是 |
这些层拆分方式为上下文窗口和视觉编码器留出了空间;速度数据来自一张限制为这些拆分方式的 24 GB 显卡,所以真实 16 GB 显卡在相同拆分下表现应该相近,CPU 和内存较慢/较小时则会更低。只有 full 配置在自己的硬件上连续运行过数周;其他配置运行的是同一套代码,只是显卡上的内容更少。mlsubgen bench 会在长时间运行之前显示每种选择在你自己的素材上的实际代价。
它的功能
- 逐段检测语音语言,而非整个文件:一个包含英文采访片段的日语节目会被当作两种语言处理。只有当 Whisper 的语言概率、Qwen3-ASR 自身的解码以及词语的文字系统三方一致时,才会认定为某种语言。
- 每个音频块都用两个语音识别引擎——Qwen3-ASR-1.7B(及其强制对齐器,用于词级时间戳)和 faster-whisper large-v3——在两者不一致时,由翻译 LLM 进行协调。音频块覆盖整个时间轴(只有处于噪声底限的片段会被跳过),因此压在音乐上的对白不会被 VAD 丢失。
- 由 LLM 完成翻译(Ollama,或任何 OpenAI 兼容的服务器),以 20 条字幕为窗口、带滚动上下文、人名术语表、按语言的语域规则(泰文语气词、du/Sie、简体 vs 繁体中文……),以及对模型遗漏内容的逐行降级处理。
- 45 种字幕语言,在 Web UI 中勾选或用
--target en,th,de按任务选择;已经是目标语言的字幕会直接复制,不进行翻译。 - 按语言的字幕排版:行宽随文字系统调整、阅读速度上限(CJK 语言更宽松)、最小持续时间和间隔,以及为泰文、老挝文、高棉文、缅甸文和天城文提供的聚类安全换行。
- 可选的说话人分离——sherpa-onnx 在 CPU 上本地识别说话人切换。说话人变化能让语言检测和字幕边界更精确,并为翻译器提供匿名的说话人连续性;不确定的说话人信息会被标为未知,而非强行归类。
--speakers auto,或已知人数时用--speakers N。详见下文说话人部分。 - 内嵌字幕优先于音频:已经带有目标语言完整字幕的视频在该目标语言上会被直接跳过;45 种语言中任何其他完整文本音轨(非强制字幕、非仅对白和歌曲)都会被当作转写文本来源进行翻译,优先使用所讲语言的音轨。无需花时间做 ASR,也不会在原文已存在的情况下翻译翻译稿。
- 带 Web UI 的任务队列:任务在 GPU 上逐个运行,能扛过重启(每个完成的阶段和每个解码的 ASR 音频块都有检查点),并且可以暂停和恢复。暂停的任务在重启后会一直保持在队列之外,直到你恢复它。
安装 — Docker
git clone https://github.com/dodgypast/mlsubgen.git && cd mlsubgen
cp .env.example .env
# MEDIA_DIR = 你的视频所在文件夹;默认语言;你的 uid/gid
mkdir -p data models
# 状态和模型缓存,由你创建,以便容器可以写入
docker compose up -d --build
# 镜像约 14 GB(CUDA torch 和 ASR 组件),首次 10–20 分钟
docker compose run --rm worker pull
# ASR 模型(约 8 GB)和两个默认翻译器(约 37 GB,装入 Ollama)
或者打开 http://:8790,使用 Models 面板:它会显示哪些模型已就绪,缺失的可以一键下载并显示进度。模型就绪后 worker 会立即使用。容器使用宿主机网络(Ollama 在 127.0.0.1:11434);Web UI 没有登录,所以请将它放在局域网或 VPN 地址上。你的视频被挂载到 /media,MLSUBGEN_MEDIA_ROOTS=/media 将文件夹选择器和 worker 限制在该目录内。停止 worker 容器会干净地中断正在运行的任务;下次启动时会从检查点继续。
安装 — 宿主机
git clone https://github.com/dodgypast/mlsubgen.git ~/mlsubgen && cd ~/mlsubgen
bash setup.sh
# venv、CUDA torch、固定版本的依赖、自检、`mlsubgen` 命令、两个用户级 unit
setup.sh 结束时会列出剩余步骤:编辑两个 unit 文件(MLSUBGEN_MEDIA_ROOTS、MLSUBGEN_TARGETS),用 mlsubgen pull 下载模型,然后 systemctl --user enable --now mlsubgen-worker mlsubgen-web。
使用方法
mlsubgen
# 该目录及以下的所有视频 → 默认语言;排队交给 worker
mlsubgen --target en,th,de .
# 每个视频生成三个字幕文件
mlsubgen --source ja FOLDER
# 跳过语言检测:音频是日语
mlsubgen --overwrite FILE
# 从头重新处理一个文件
mlsubgen --speakers auto FOLDER
# 带说话人分离(需要先 mlsubgen pull speakers);已知人数时用 --speakers 3
mlsubgen languages
# 45 种语言代码、它们的原生名称、每种由哪个引擎解码
mlsubgen config targets th,de
# 保存默认语言(Web 表单中有"设为默认"选项);config 会显示所有设置
mlsubgen models
# 显示就绪状态:Ollama 中的翻译器、缓存中的 ASR 模型
mlsubgen pull
# 下载默认运行所需的模型;pull gemma4 · pull some/tag:latest · pull --all
mlsubgen jobs
# 队列;mlsubgen log ID · pause ID · resume ID · cancel ID · retry ID
mlsubgen help
# 单屏指南;mlsubgen help run 查看所有选项
worker 服务运行期间,在文件夹中执行 mlsubgen 会将任务加入队列并返回;worker 会运行它,Web UI 会显示每个文件的处理结果和实时日志。mlsubgen --now ... 则改为在前台运行。
Web UI
新建任务表单(文件夹选择器被限制在你的媒体根目录内,字幕语言勾选框,如需覆盖检测器可指定所讲语言、翻译器、ASR 模式、说话人分离、内嵌字幕策略、上下文、术语表),一个 Preview(试运行) 会列出该任务将涉及的确切文件,任务队列支持暂停 / 恢复 / 取消 / 重试,任务页面显示每个文件的结果和实时日志,以及一个已跳过文件的页面,可强制指定语言后重新排队。
处理流程
| 阶段 | 内容 |
|---|---|
| 内嵌字幕 | 目标语言中的文本音轨 → 该目标语言即已完成;其他任何完整文本音轨(45 种语言;所讲语言的优先;清理掉 ASS 中的标签、卡拉 OK 和注释)→ 作为转写文本,无需 ASR。无标签的文本音轨会从其自身文字内容推断语言。位图(PGS)音轨通过 OCR 读取(0.4.8):若为目标语言则直接生成该语言的 .srt,若为所讲语言则作为转写文本——参见位图字幕部分 |
| 探测 | ffprobe 选择音频音轨(先标签,再标题,最后默认)——mlsubgen tracks FILE 会显示各音轨,--audio-track N 可覆盖 |
| 音频 | ffmpeg → 16 kHz 单声道 wav;该文件的分离和 ASR 完成后即删除 |
| 说话人 | 可选,--speakers:sherpa-onnx 在 CPU 上识别说话人切换,在任何内容听取文字之前完成;参见说话人部分 |
| 语言识别 | 每约 10 秒语音一段——若说话人切换已知,则按说话人切换分段:Whisper 概率 + Qwen 解码 + 文字系统和虚词;切换点会被精确到具体范围;另一种语言的短暂片段需要强证据才会认定 |
| 音频块 | ≤ 30 秒,每块一种语言(语言变化必然切分),覆盖整个时间轴;只有处于噪声底限的片段会被跳过 |
| ASR | 两个引擎各自解码每个音频块,强制指定语言;每个音频块后生成检查点 |
| 合并 | 翻译 LLM 协调两份转写文本的不一致之处(一致的音频块无需 LLM) |
| 词 ↔ 说话人 | 使用 --speakers 时:每个对齐的词取其明确覆盖的说话人段次,否则保持未标注 |
| 字幕切分 | 句末、停顿、说话人切换、长度限制、幻觉过滤(证据门控) |
| 翻译 | 按目标语言分别处理:已是目标语言的字幕直接复制;其余以 20 条为窗口,带上下文、术语表、语域规则、说话人连续性、重试和逐行降级 |
| 排版 | ≤ 2 行,按语言调整行宽和阅读速度,最小持续时间和间隔 → ..srt |
不使用 --speakers 时,两个说话人相关行不会运行,其余部分不变。
位图字幕
蓝光重封装文件以 PGS 位图形式携带字幕,常常包含十几种语言,完全没有文本音轨;在 0.4.8 之前,mlsubgen 无法利用其中任何一个——一部带有英文字幕的影片仍会被重新转写。现在位图音轨可以通过 OCR 读取(--ocr auto,默认值;--ocr off 恢复旧行为):
- 位于目标语言中的位图音轨会直接 OCR 生成该目标语言的
.srt——真实字幕,无需翻译(该语言中的文本音轨仍然优先,只有在没有文本音轨时位图目标音轨才被采用); - 位于所讲语言中的位图音轨(或在找不到时按常见来源顺序选取)会成为其他目标语言的翻译依据——带 OCR 噪声的人工字幕仍然优于机器转写。
mlsubgen 自行解码 PGS 流(合成、调色板、行程编码对象),并将每张字幕图像交给针对该文字系统实测效果最好的引擎:
| 文字系统 | 引擎 | 实测结果(字幕行精确匹配 / chrF) |
|---|---|---|
| 拉丁、希腊、西里尔 | tesseract 及对应语言包(Arch 上为 tesseract-data-,Debian 上为 tesseract-ocr-;Docker 镜像自带 19 种)——CPU,一次处理四张图 | 英文蓝光,1,800 条字幕:95% / 99.4 |
| 泰文、中文、日文、韩文,以及带叠加标记的文字(老挝文、高棉文、缅甸文、印度系文字、阿拉伯文、希伯来文) | 该硬件配置的视觉模型通过 Ollama 调用(full 用 gemma4:31b,12gb 用 12b)——GPU 上每秒一张图;在 ASR 引擎加载前卸载 | 泰文:31B 77% / 93.7,12B 65% / 89.3;简体中文:31B 79% / 90.0;日文(用某蓝光 SDH 音轨与另一发行商的 SDH 转写文本对比,去除描述和标签后):31B 51% 字幕行完全相同 / chrF 78——差距在于蓝光盘在加入下一行的同时保留了前一行在屏幕上的时间、另一份转写缺少的插入语,以及模型正确省略的假名;配对的行在字符级别上能够吻合。相同情况下 tesseract 的结果为:泰文 50 / 71,中文 41 / 78 |
8gb 配置下的上述文字系统 | 没有可用引擎——E4B 读取泰文的准确率为 18% / 66.5,不足以作为翻译依据;该音轨会被跳过,转而转写音频,与 0.4.8 之前的行为一致 | |
| 结果会缓存在工作文件旁边,因此一个音轨 |
相似文章
SubtitleGenerator
SubtitleGenerator是一款基于浏览器的工具,可利用人工智能从视频中生成可直接发布的字幕。
构建了一个开源、完全本地的字幕本地化代理
SubAgent 是一个完全本地运行的开源字幕本地化系统,支持 SRT/RTF 文件的翻译与编辑,并具备人工审核和视频同步功能。
我构建了一个开源的实时日语动漫字幕与翻译引擎,由 Whisper-Large-v3 + Groq / DeepSeek 驱动。
NihonSub 是一个开源的实时日语动漫字幕与翻译引擎,它将运行在 Groq 上的 Whisper-Large-v3 与 DeepSeek/LLaMA-3 相结合,用于生成上下文感知的双语字幕,并具备基于 VAD 的音频分段、保留敬语的 LLM 翻译,以及同步双字幕影院播放器等特性。
使用llama.cpp在GStreamer中进行本地LLM文本翻译或转换
一个新的GStreamer元素集成了llama.cpp,使得在多媒体管道中能够基于本地LLM进行文本翻译和转换,从而实现实时字幕生成和改写。
**破除巴别塔:面向长文本字幕翻译的自进化多智能体系统**
该论文提出了 SMART,一个用于长篇字幕翻译的自演化多智能体系统。该系统采用测试时训练机制,结合动态路由器、Mixture-of-Agents 层以及 judge-refiner 循环,在不重新训练底层 LLM 的前提下构建剧集级记忆并自适应地调整智能体提示词。论文还推出了 SubtitleArena 基准测试(涵盖 14 个类型、15 个目标语言区域)以及 SubMQM 评估框架,相比同类智能体系统实现了平均 6.9% 的 MQM 惩罚分数降低,并在 MuSC 基准测试上取得了最佳结果。