tiny-audio 开源语音转文字系统:冻结编码器接 LLM,训练成本约 25 美元
tiny-audio, nanoGPT for speech-to-text
tiny-audio 是一个开源语音转文字系统,将冻结的预训练语音编码器通过小型可训练投影层接入预训练 LLM,整体训练成本约 25 美元,只需训练约 8000 万参数。
原文给出了冻结语音编码器加可训练投影层再加冻结 LLM 的解耦架构与完整训练流程,可作为低成本端到端语音转文字方案的参考实现。
一个 25 美元即可训练的语音转文字系统。
Tiny Audio 将一个冻结的预训练语音编码器连接到一个预训练大语言模型,中间用一个小型可训练投影层。从本仓库发布的模型在 LibriSpeech test-clean 上达到 1.8% 的词错误率,在 12 个基准上平均 7.4%(共汇总 11,822 个样本),同时仅训练约 8000 万参数。整个代码库小到可以在一个下午读完,而且你可以在笔记本电脑上用大约五分钟跑起一个训练循环。
30 秒试用
无需安装:打开 在线演示,自己录音或上传文件,即可获得转写文本。
在 Python 中:
pip install "transformers>=5.0" peft torch torchaudio librosafrom transformers import pipeline pipe = pipeline( "automatic-speech-recognition", model="mazesmazes/tiny-audio", trust_remote_code=True ) print(pipe("audio.wav")["text"]) # The quarterly revenue grew by 12% according to Dr. Smith.
输出带有标点、大写规范和数字格式,无需任何后处理步骤。输入可以是文件路径、URL 或 16 kHz 的 numpy 数组。权重为 bf16,因此你需要大约 6 GB 的 GPU 或 Apple Silicon 显存。
不止于纯文本
# Word-level timestamps (forced alignment) pipe("audio.wav", return_timestamps=True) # {"text": "hello world", "words": [{"word": "hello", "start": 0.0, "end": 0.5}, ...]} # Who spoke when (speaker diarization) pipe("meeting.wav", return_speakers=True, num_speakers=2)
Nemotron-3-Diarization 找到的每位说话者都会被单独转写:在一份将其他人都静音后的音频副本上进行转写,每个词归属于它原本所在的流。这是一个对 NeMo 的 masked_asr 配方的零样本移植;若一个词被两个流同时听到,则只保留一次。每位说话者大致按其自身发言时长消耗 ASR 算力,单说话者音频则不经掩蔽地转写。重叠部分只得到部分处理:某位说话者回合中出现的他人语音会保留在该说话者的流中。
在下一个版本发布之前,说话者 diarization 需要从 main(pip install git+https://github.com/huggingface/transformers)安装 transformers。如需逐 token 的流式输出,请参阅 ASRModel.generate_streaming。模型卡介绍了批处理和 GPU 设置。
作为 RunPod 上的 HTTP API
ta serve 将模型部署在批量化 HTTP 服务器之后:同时到达的请求会共享 GPU 批次,因此吞吐量随负载增长(在 RTX 4090 上、128 个并发请求时约为实时的 460 倍)。要在 RunPod GPU 上运行它:
poetry run ta runpod up --serve # create an inference pod; prints <POD_ID> poetry run ta runpod wait <POD_ID> # prints <HOST> <PORT> poetry run ta runpod deploy <HOST> <PORT> # sync the project, install the fast kernels TINY_AUDIO_API_KEY=my-secret poetry run ta runpod serve <HOST> <PORT> --no-attach # Ready when https://<POD_ID>-8000.proxy.runpod.net/health answers (a few minutes: it compiles first)
在缺少 TINY_AUDIO_API_KEY 的情况下,服务器对持有该 URL 的任何人都开放。ta serve 也可以在本地运行,支持 CUDA、Apple Silicon 或 CPU。
将音频作为请求体发送,选项放在查询字符串中:
curl -X POST "https://<POD_ID>-8000.proxy.runpod.net/?return_timestamps=true" \ -H "Authorization: Bearer my-secret" \ -H "Content-Type: application/octet-stream" \ --data-binary @audio.wav
import httpx response = httpx.post( "https://<POD_ID>-8000.proxy.runpod.net/", params={"return_speakers": "true", "num_speakers": "2"}, content=open("meeting.wav", "rb").read(), headers={"Authorization": "Bearer my-secret"}, timeout=600, ) print(response.json()["text"])
- 选项:
return_timestamps、return_speakers、num_speakers和max_speakers,与 pipeline 中相同。响应与 pipeline 返回的字典一致。 - JSON 请求体:若要发送 JSON,请使用
{"inputs": "<base64 audio>", "parameters": {...}}。 - 音频格式:FFmpeg 能读取的任何格式均可。
- 错误:音频或选项错误时返回
400并附带{"error": ...};密钥错误时返回401。 - 其他端点:
GET /health和GET /stats(批大小与 GPU 时间)。
RunPod 的 HTTP 代理会拒绝超过 500 MiB 的请求体,并丢弃任何耗时超过 100 秒的请求。对于较长的录音,请发送 16 kHz 单声道 FLAC:
ffmpeg -i recording.wav -ac 1 -ar 16000 recording.flac
这大约是每分钟音频 1 MB,且不会损失精度,因为服务器无论如何都会把所有内容转换为 16 kHz 单声道。在 RTX 4090 上,45 分钟音频大约需要 10 秒,带说话者标签时则需 21 秒。演示 Space正是以这种方式调用服务器。
效果如何?
在 11,822 个样本(每个数据集最多 1,000 个)上的词错误率(%,越低越好),使用本仓库的 ta eval 对接 ta serve HTTP API,在 RTX 4090 上测得:
| 数据集 | WER |
|---|---|
| LibriSpeech test-clean | 1.84 |
| SPGISpeech | 2.29 |
| TED-LIUM | 3.71 |
| LoquaciousSet † | 6.20 |
| LibriSpeech test-other | 6.38 |
| VoxPopuli | 7.11 |
| Common Voice | 7.18 |
| AMI (IHM) | 8.99 |
| GigaSpeech | 9.06 |
| Earnings22 † | 10.58 |
| People's Speech | 17.59 |
| AMI (SDM) | 23.53 |
| 平均(12 个数据集) | 8.71 |
| 汇总(11,822 个样本) | 7.42 |
† 留出集:训练中未使用该来源的任何数据。
你可以自行核验这些数字,并在相同样本上与商业 API 进行对比:
poetry run ta eval -m mazesmazes/tiny-audio -d loquacious -n 100 # Same samples through a commercial API (also: deepgram, elevenlabs, apple-speech) ASSEMBLYAI_API_KEY=... poetry run ta eval -m assemblyai -d loquacious -n 100
工作原理
Audio (16 kHz) → speech encoder (frozen) → MLP projector (trained) → LLM decoder → Text
- 一个预训练的语音编码器将音频转换为一系列帧嵌入。
- 一个小型MLP 投影器把相邻的帧堆叠起来,并将它们映射到 LLM 的嵌入空间。它是唯一从零开始训练的部分。
- LLM 把这些投影后的帧当作 token 一样读取,并输出转录文本。
编码器、投影器和解码器都可通过配置进行互换。仓库附带两个配方:
| 配方 | 编码器 | 解码器 | 训练对象 |
|---|---|---|---|
已发布模型 (granite_qwen_frozen) |
Granite Speech 470M | Qwen3.5,冻结 + LoRA | 投影器 + LoRA(约 80M) |
默认 / 课程配方 (stage_1) |
GLM-ASR-Nano (635M) | Qwen3-0.6B,微调 | 投影器 + 解码器 |
训练你自己的模型
先在笔记本上免费起步,等你确认流水线能跑通后再去租用 GPU。
| 级别 | 数据 | 硬件 | 费用 |
|---|---|---|---|
| 冒烟测试 | 73 段 LibriSpeech 片段 | 你的笔记本(CPU、MPS、CUDA) | 免费,约 5 分钟 |
| 课程运行 | LoquaciousSet small(约 250 小时) |
一块租用 GPU,数小时 | 数个 GPU 小时 |
| 生产配方 | 横跨十个语料库的约 300 万片段(>1 TB) | 一块 80 GB GPU,约一天或更久 | 数百美元 |
git clone https://github.com/alexkroman/tiny-audio.git && cd tiny-audio poetry install # 1. Smoke test: a real training loop on your laptop poetry run python scripts/train.py +experiments=mps_smoke # 2. Before renting hardware, estimate the VRAM and disk a config needs poetry run ta runpod plan -e stage_1 # 3. Full run poetry run python scripts/train.py +experiments=stage_1
每一项设置都是一个 Hydra 覆写,例如
model.projector_hidden_dim=2048 或 training.use_lora=true。当你对模型满意时,
ta push 会把它发布到 Hugging Face Hub,而 ta deploy 会把类似上方那样的演示放到
Space 上。
在 RunPod 上训练
poetry run ta runpod up -e stage_1 # create a pod with enough GPU for the config poetry run ta runpod wait <POD_ID> # prints <HOST> <PORT> poetry run ta runpod deploy <HOST> <PORT> # sync the project and install dependencies HF_TOKEN=hf_... poetry run ta runpod train <HOST> <PORT> -e stage_1 poetry run ta runpod attach <HOST> <PORT> # watch the run in tmux
通过动手构建来学习
这门免费的 3.5 小时课程会带你走完完整闭环:
编码器、投影器和解码器是如何配合工作的(包含真实的张量形状)、如何训练模型、
如何与商业 API 评估对比,以及如何发布一个带现场演示的版本。你需要会 Python、
命令行和 git。课程训练的是较小的 stage_1 配方,而不是已发布的模型,所以
你的 WER 会比上表中的更高。
想试试新的投影器架构、加入数据集,或改动代码库?请参阅 CONTRIBUTING.md 中的 CLI 参考、配置布局和质量门禁。
致谢
- Granite Speech 和 GLM-ASR 提供音频编码
- Qwen3.5 和 Qwen3 提供语言建模
- LoquaciousSet 提供默认 评估集
许可证
MIT
来源:Hacker News · github.com
