引言
语音是最高效的人机交互通道,也是机器学习里最「不像图像也不像文本」的模态——它是一维时序信号,采样率高、冗余大、变长且对齐模糊。把「一段波形」变成「一串文字」或「一个说话人身份」,背后是一整套从信号处理到序列建模的技术栈。
本文从最基础的音频表示讲起:采样率、频谱、梅尔谱、MFCC 这些特征决定了模型能「看到」什么;然后对比 ASR 的三大建模范式 CTC、RNN-T、注意力编码解码,并给出 Whisper 的实战用法;接着讲 TTS 与声码器如何把文字变回声音、说话人识别如何用一个向量表征音色;最后覆盖音频增强、WER/MOS 评测与工程落地。全文代码基于 HuggingFace 与 torchaudio 生态。
前置:序列建模与注意力机制见 https://plumephp.com/ml-deep-learning-advanced/;文本侧的语言模型与分词见 https://plumephp.com/ml-nlp-basics/;预训练与迁移复用见 https://plumephp.com/ml-transfer-learning/;语音服务上线见 https://plumephp.com/ml-model-deployment/。
目录
- 1. 语音任务全景
- 2. 音频特征:从波形到梅尔谱
- 3. ASR 架构:CTC、RNN-T 与注意力
- 4. Whisper 与端到端 ASR
- 5. TTS 与声码器
- 6. 说话人识别与音频嵌入
- 7. 音频数据增强
- 8. 评测指标与工程落地
- 9. 总结
- 延伸阅读
1. 语音任务全景
1.1 常见任务分类
| 任务 | 输入 | 输出 | 典型应用 |
|---|---|---|---|
| ASR 语音识别 | 波形 | 文本 | 语音转写、字幕 |
| TTS 语音合成 | 文本 | 波形 | 语音助手、有声书 |
| 说话人识别 | 波形 | 身份/向量 | 声纹解锁、客服质检 |
| 语音增强 | 带噪波形 | 干净波形 | 降噪、助听器 |
| 关键词唤醒 | 波形 | 命中/未命中 | 「小爱同学」 |
| 情感识别 | 波形 | 情感类别 | 客服情绪分析 |
1.2 三个技术转折
语音技术的演进有三个关键节点:GMM-HMM(传统,靠特征工程 + 隐马尔可夫)→ DNN-HMM / CTC(深度学习接管声学模型)→ 端到端(Whisper 直接把波形映射成文本)。端到端把复杂的多模块流水线压成一个模型,大幅简化了工程。
1.3 语音数据的特殊性
- 时序变长:一段话可以是 1 秒也可以是 1 分钟;
- 对齐模糊:文字和音频的时间边界不明确(一个音素对应多少帧?);
- 冗余高:16kHz 采样,1 秒就是 16000 个点,但信息量远低于此;
- 噪声敏感:环境噪声、口音、语速都影响识别。
一句话:语音是「高采样率、变长、对齐模糊」的时序信号,所有语音模型的第一课都是「怎么把冗余的波形压缩成有意义的特征」。
2. 音频特征:从波形到梅尔谱
2.1 采样、分帧与加窗
音频是连续的声压变化,数字化要经过采样(通常 16kHz)、分帧(每帧 25ms、步长 10ms)、加窗(汉明窗减少频谱泄漏)。分帧后每帧做短时傅里叶变换(STFT)得到频谱。
波形 (16000 点/秒)
→ 分帧:25ms 一帧、10ms 一帧移 → 每帧 400 点
→ 加窗:汉明窗
→ STFT:每帧 → 频谱
→ 梅尔滤波 → 梅尔谱(80 或 128 维)
2.2 梅尔谱与 MFCC
人耳对频率的感知是非线性的(低频敏感、高频迟钝),梅尔刻度模拟了这种非线性。梅尔谱就是把频谱过一组梅尔滤波器组,得到 80/128 维的表示,是深度学习 ASR 的标准输入。
MFCC 是在梅尔谱基础上再做 DCT(离散余弦变换)取前 13 维,进一步压缩。MFCC 曾是传统 ASR 的标配,如今深度学习更常用原始梅尔谱(保留更多信息)。
| 特征 | 维度 | 特点 | 用途 |
|---|---|---|---|
| 原始波形 | 16000/s | 信息全、冗余大 | 端到端模型 |
| 梅尔谱 | 80-128 | 保留感知相关信息 | 主流 ASR 输入 |
| MFCC | 13-40 | 高度压缩、去相关 | 传统 ASR、说话人 |
2.3 用 torchaudio 提取特征
import torch
import torchaudio
import torchaudio.transforms as T
waveform, sr = torchaudio.load("speech.wav") # (channels, samples)
if sr != 16000:
waveform = torchaudio.functional.resample(waveform, sr, 16000)
mel_transform = T.MelSpectrogram(
sample_rate=16000, n_fft=400, hop_length=160, n_mels=80, f_min=0, f_max=8000,
)
mfcc_transform = T.MFCC(
sample_rate=16000, n_mfcc=13,
melkwargs={"n_fft": 400, "hop_length": 160, "n_mels": 80},
)
mel = mel_transform(waveform) # (1, 80, T)
mfcc = mfcc_transform(waveform) # (1, 13, T)
log_mel = torch.log(mel + 1e-6) # 取对数,动态范围更友好
print(mel.shape, mfcc.shape)
一句话:梅尔谱模拟人耳的非线性频率感知,是深度学习 ASR 的标准输入;MFCC 是它的压缩版,适合传统模型和说话人任务。
3. ASR 架构:CTC、RNN-T 与注意力
3.1 核心难题:变长对齐
ASR 的根本困难是输入帧数和输出字符数不对齐:1 秒语音有 100 帧梅尔特征,但只对应几个字。三大架构就是三种解决对齐的思路。
3.2 CTC:引入空白符
CTC(Connectionist Temporal Classification)在词表里加一个空白符(blank),允许模型在任意帧输出 blank 或字符,最后合并重复、删掉 blank 得到文本。它假设输出帧之间条件独立,因此训练快、可并行,但无法建模字符间依赖(需外接语言模型)。
帧输出: _ _ h h _ e e _ l l l _ l l _ o o _ _
合并后: h e l l o
import torch
import torch.nn as nn
# CTC 损失:log_probs 形状 (T, N, C),targets 是文本 id
ctc_loss = nn.CTCLoss(blank=0, zero_infinity=True)
log_probs = model(mel) # (T, N, C)
loss = ctc_loss(log_probs, targets, input_lengths, target_lengths)
3.3 RNN-T:流式识别的王者
RNN-T(RNN Transducer)把网络拆成三部分:Encoder(处理音频)、Predictor(处理已输出文本)、Joiner(合并两者预测下一个 token)。它不假设独立性,且天然支持流式(来一帧解一帧),是实时字幕、语音输入法的首选。
| 架构 | 独立性假设 | 流式 | 训练难度 | 代表 |
|---|---|---|---|---|
| CTC | 有 | 支持 | 低 | DeepSpeech |
| RNN-T | 无 | 原生支持 | 中 | Google、Conformer |
| Attention Enc-Dec | 无 | 需改造 | 高 | Whisper |
3.4 注意力编码解码
Attention Encoder-Decoder 用编码器压缩音频、解码器自回归生成文本,建模能力最强(能利用全部上下文和语言知识),但不天然流式。Whisper、大部分高质量离线 ASR 都用这个范式。
一句话:CTC 用 blank 解决对齐、训练简单但假设独立;RNN-T 用 Joiner 建模依赖、天生流式;注意力编码解码能力最强但需离线——选架构就是选「流式 vs 精度」的权衡。
4. Whisper 与端到端 ASR
4.1 Whisper 的设计
Whisper 是 OpenAI 的大规模弱监督 ASR:用 68 万小时多语言、多任务的网络音频训练,输入是 30 秒的 log-Mel 谱,输出是文本 token 序列(含任务标记如 <|transcribe|>、<|translate|>、语言标记)。它的核心贡献不是架构创新,而是数据规模 + 多任务统一。
音频 → 30s 窗口 → log-Mel (80维) → Encoder(Transformer) → Decoder → 文本 token
Decoder 前缀:[<|startoftranscript|><|zh|><|transcribe|><|notimestamps|>]
4.2 用 transformers 跑 Whisper
import torch
from transformers import WhisperProcessor, WhisperForConditionalGeneration
processor = WhisperProcessor.from_pretrained("openai/whisper-large-v3")
model = WhisperForConditionalGeneration.from_pretrained(
"openai/whisper-large-v3", torch_dtype=torch.float16
).to("cuda")
import librosa
audio, sr = librosa.load("speech.wav", sr=16000)
inputs = processor(audio, sampling_rate=16000, return_tensors="pt").to("cuda")
forced_ids = processor.get_decoder_prompt_ids(language="zh", task="transcribe")
ids = model.generate(inputs.input_features, forced_decoder_ids=forced_ids, max_new_tokens=256)
print(processor.batch_decode(ids, skip_special_tokens=True)[0])
4.3 长音频与时间戳
Whisper 原生只吃 30 秒,长音频要滑窗切分 + 拼接。生产环境用 whisperx 或 faster-whisper:前者加 VAD 切分和对齐(给词级时间戳),后者用 CTranslate2 推理,速度提升 4 倍、显存减半。
# faster-whisper:CTranslate2 加速 + int8 量化
pip install faster-whisper
from faster_whisper import WhisperModel
model = WhisperModel("large-v3", device="cuda", compute_type="float16")
segments, info = model.transcribe("long_audio.wav", language="zh", vad_filter=True)
for seg in segments:
print(f"[{seg.start:.2f}-{seg.end:.2f}] {seg.text}")
一句话:Whisper 靠海量弱监督数据 + 多任务统一标记做到了强大的零样本识别;生产落地要配 VAD 切分、faster-whisper 加速和词级对齐。
5. TTS 与声码器
5.1 两阶段:文本 → 声学特征 → 波形
经典 TTS 是两段式:声学模型把文本转成中间声学特征(梅尔谱),**声码器(Vocoder)**再把梅尔谱还原成波形。声码器质量直接决定音质。
文本 "你好" → [文本前端/音素] → [声学模型 Tacotron/FastSpeech] → 梅尔谱
→ [声码器 HiFi-GAN] → 波形
5.2 声码器:从 Griffin-Lim 到 HiFi-GAN
| 声码器 | 类型 | 音质 | 速度 |
|---|---|---|---|
| Griffin-Lim | 信号处理 | 差(机械音) | 慢 |
| WaveNet | 自回归神经 | 极好 | 极慢 |
| WaveGlow | 流模型 | 好 | 中 |
| HiFi-GAN | GAN | 好 | 快(实时) |
HiFi-GAN 是当前主流:用生成器把梅尔谱逐层上采样成波形,配合多周期判别器训练,音质接近真人且可实时。
5.3 现代端到端 TTS
VITS、Tortoise、Bark、以及基于 LLM 的 TTS 把两阶段合并,直接从文本生成波形,并支持零样本音色克隆(给几秒参考音频就能模仿音色)。
from TTS.api import TTS # Coqui TTS
tts = TTS("tts_models/zh-CN/baker/tacotron2-DDC-GST").to("cuda")
tts.tts_to_file(text="你好,欢迎使用语音合成。", file_path="out.wav")
# 零样本音色克隆
tts_clone = TTS("tts_models/multilingual/multi-dataset/xtts_v2").to("cuda")
tts_clone.tts_to_file(
text="这是用参考音色说的话。",
speaker_wav="reference.wav",
language="zh",
file_path="clone.wav",
)
5.4 TTS 的评测
TTS 没有唯一正确答案,评测靠主观 MOS(人打分)+ 客观指标(MCD 梅尔倒谱失真、PESQ)。MOS 是黄金标准但昂贵,常做小规模人工评估。
一句话:TTS = 声学模型 + 声码器两段式(或端到端),HiFi-GAN 是声码器的性价比之王;评测依赖主观 MOS,工程上还要关注实时率(RTF)。
6. 说话人识别与音频嵌入
6.1 任务定义
说话人识别分两种:验证(Verification)——判断两段语音是不是同一个人;辨认(Identification)——从注册库里找出是谁。核心是把变长语音压成定长说话人嵌入向量(如 192 维),再算余弦相似度。
6.2 经典模型:ECAPA-TDNN 与 x-vector
| 模型 | 结构 | 特点 |
|---|---|---|
| i-vector | GMM + 因子分析 | 传统、已过时 |
| x-vector | TDNN + 池化 | 深度学习的里程碑 |
| ECAPA-TDNN | 多尺度 TDNN + 注意力 | 当前 SOTA 之一 |
| WavLM/ECAPA | 自监督前端 | 抗噪强 |
6.3 用 SpeechBrain 提取嵌入
from speechbrain.inference.speaker import EncoderClassifier
import torch
import torchaudio
classifier = EncoderClassifier.from_hparams(
source="speechbrain/spkrec-ecapa-voxceleb", run_opts={"device": "cuda"}
)
def embed(path):
signal, sr = torchaudio.load(path)
if sr != 16000:
signal = torchaudio.functional.resample(signal, sr, 16000)
return classifier.encode_batch(signal).squeeze() # (192,)
e1, e2 = embed("a.wav"), embed("b.wav")
score = torch.nn.functional.cosine_similarity(e1, e2, dim=0)
print(f"相似度: {score:.3f}") # 阈值通常 0.25-0.35
6.4 关键指标
- EER(等错误率):误拒率 = 误受率时的错误率,越低越好;
- minDCF:给定代价下的最小检测代价;
- 阈值选择:取决于业务——安全场景宁可误拒(阈值高),便捷场景容忍误受。
一句话:说话人识别的本质是「把音色压成一个向量」,ECAPA-TDNN 是当前主力;评测看 EER,落地要按业务风险选阈值。
7. 音频数据增强
7.1 为什么要增强
语音数据标注昂贵、场景多样(安静/嘈杂/远场/电话),增强能显著提升鲁棒性。音频增强分波形级和特征级两类。
| 增强手段 | 层级 | 模拟场景 |
|---|---|---|
| 加噪(Noise) | 波形 | 嘈杂环境 |
| 变速(Speed) | 波形 | 语速差异 |
| 变调(Pitch) | 波形 | 音高差异 |
| 混响(Reverb) | 波形 | 房间声学 |
| SpecAugment | 特征 | 遮挡时频 |
| 音量扰动 | 波形 | 远近距离 |
7.2 SpecAugment:语音里的 Cutout
SpecAugment 直接作用在梅尔谱上:时间掩蔽(遮一段连续帧)+ 频率掩蔽(遮几个梅尔通道)。它简单有效,是 ASR 训练的标配,几乎零成本。
import torch
import torchaudio.transforms as T
spec_aug = T.FrequencyMasking(freq_mask_param=27)
time_aug = T.TimeMasking(time_mask_param=100)
def augment(mel):
# mel: (C, n_mels, T)
for _ in range(2):
mel = spec_aug(mel) # 频率掩蔽
mel = time_aug(mel) # 时间掩蔽
return mel
7.3 加噪与混响实现
import torch
import torchaudio
def add_noise(waveform, noise, snr_db=10):
"""按指定信噪比混合噪声"""
signal_power = waveform.norm(p=2) ** 2
noise_power = noise.norm(p=2) ** 2
snr = 10 ** (snr_db / 10)
scale = (signal_power / (snr * noise_power + 1e-8)).sqrt()
return waveform + scale * noise[:, :waveform.size(-1)]
一句话:SpecAugment 是语音训练的「免费午餐」,直接遮挡时频块;波形级的加噪、变速、混响则模拟真实场景,是鲁棒性的关键。
8. 评测指标与工程落地
8.1 ASR 指标:WER 与 CER
WER(词错误率) = (替换 + 删除 + 插入) / 总词数。中文按字算则用 CER(字错误率)。
import jiwer
reference = "今天天气很好"
hypothesis = "今天天气好"
print("CER:", jiwer.cer(reference, hypothesis)) # 0.2
| 指标 | 计算单位 | 适用 |
|---|---|---|
| WER | 词 | 英文等分词语言 |
| CER | 字 | 中文、日文 |
| RTF | 处理时长/音频时长 | 速度(<1 为实时) |
| MOS | 人工打分 1-5 | TTS 音质 |
8.2 影响 WER 的因素
| 因素 | 影响 | 缓解 |
|---|---|---|
| 噪声 | WER 大幅上升 | 增强训练、降噪前端 |
| 口音 | 领域偏移 | 口音数据微调 |
| 专业术语 | 未登录词 | 热词/上下文偏置 |
| 长音频 | 累积错误 | VAD 切分、分段解码 |
| 数字/实体 | 格式不一致 | 文本归一化 |
8.3 工程落地要点
1. 前端:VAD 切分 + 降噪 + 重采样统一到 16kHz
2. 模型:faster-whisper / onnx 导出 + int8 量化
3. 后处理:标点恢复 + 数字归一化 + 热词替换
4. 部署:流式用 RNN-T/流式 Whisper,离线用大模型
5. 监控:记录 WER 抽样、RTF、失败率
热词偏置是中文 ASR 的刚需——人名、品牌名、专业术语模型常识别错,用 initial_prompt 或专门的热词机制注入:
# Whisper 用 initial_prompt 做热词偏置
ids = model.generate(
inputs.input_features,
initial_prompt="以下是关于 Plumephp 框架和 Kubernetes 的技术讨论。",
language="zh",
)
一句话:ASR 评测看 WER/CER、TTS 看 MOS;工程落地一半的功夫在前后处理(VAD、标点、热词),模型只占另一半。
9. 总结
9.1 技术栈全景
特征层:波形 → 分帧 → 梅尔谱(MFCC)
识别层:CTC / RNN-T(流式)/ 注意力编码解码(精度)
合成层:声学模型 + 声码器(HiFi-GAN)/ 端到端 TTS
表征层:说话人嵌入(ECAPA-TDNN)+ 余弦相似度
工程层:VAD + 增强(SpecAugment)+ 后处理 + 量化
9.2 关键决策点
| 问题 | 选择 |
|---|---|
| 实时字幕/语音输入 | RNN-T 或流式 Whisper |
| 离线高精度转写 | Whisper large-v3 |
| 快速落地 | faster-whisper + VAD |
| 定制音色 TTS | XTTS / VITS 零样本克隆 |
| 声纹验证 | ECAPA-TDNN + EER 调阈值 |
| 噪声环境 | SpecAugment + 加噪增强 + 降噪前端 |
9.3 一句话心法
语音建模的核心是「对齐」与「表征」——ASR 解决音频帧与文本的变长对齐,说话人识别解决音色的定长表征,TTS 解决文本到声学的映射;三者共享同一套梅尔谱特征与序列建模工具。
延伸阅读
- https://plumephp.com/ml-deep-learning-advanced/ — 序列建模、注意力与 Transformer
- https://plumephp.com/ml-nlp-basics/ — 分词、语言模型与文本处理
- https://plumephp.com/ml-transfer-learning/ — 预训练模型复用与领域微调
- https://plumephp.com/ml-model-deployment/ — 模型量化、导出与服务化
- AI/ML 专题 — 语音与序列建模深度文章
- Whisper 官方仓库
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。