语音转写的输入是一段连续音频,输出是可编辑的文本。但机器并不能直接从波形中得到汉字或单词,中间需要完成特征表示、发音建模和语言解码。讯飞听见这类产品在真实会议、采访、课程录音中表现稳定,依赖的是多年积累的声学数据与深度学习模型,而不是简单的模板匹配。传统语音识别系统通常拆成声学模型、发音词典和语言模型三条流水线,深度学习出现后,这些模块被重新整合,部分模型甚至可以直接建立语音到文本的映射。

理解这套机制,可以从一个关键问题入手:为什么一个听起来很自然的句子,在没有语义约束时会被识别成一堆发音相似但语义混乱的词?原因在于语音信号本身具有高度不确定性,同样的词在不同人、不同语速、不同噪声环境下差异巨大。深度学习之所以有效,是因为它能够从大规模数据中自动学习鲁棒的声学表示和语言规律,替代大量人工设计的规则。
从波形到特征:语音信号如何变成模型输入
原始音频是随时间变化的连续波形,采样率通常为16kHz或8kHz。直接逐点送入网络并不可行,因为采样点数量巨大,且单个采样点几乎没有稳定的语义信息。更合理的做法是先做分帧和加窗,将音频切成约25毫秒的小段,帧移一般设为10毫秒,保证相邻帧有一定重叠。每一帧再做快速傅里叶变换,得到频谱能量分布,再经过梅尔滤波器组转换成梅尔频谱或MFCC特征。
梅尔频率之所以比线性频率更适合语音任务,是因为它更贴近人耳对音高的感知。低频区域分辨更高,高频区域分辨略低,这种设计能够在保留发音信息的同时压缩维度。实际系统中常用Fbank特征配合深度网络,因为MFCC中的离散余弦变换会丢失部分相位和能量细节,而卷积和Transformer结构更擅长从频谱图中自动发现模式。下面这段代码展示了MFCC特征的简化提取过程。
import numpy as np
import librosa
y, sr = librosa.load("meeting.wav", sr=16000)
# 预加重,提升高频分量
y = np.append(y[0], y[1:] - 0.97 * y[:-1])
# 分帧:帧长25ms,帧移10ms
frame_len = int(0.025 * sr)
frame_shift = int(0.010 * sr)
frames = []
for start in range(0, len(y) - frame_len, frame_shift):
frame = y[start:start + frame_len] * np.hamming(frame_len)
frames.append(frame)
# 提取MFCC特征
mfcc = librosa.feature.mfcc(
y=y,
sr=sr,
n_mfcc=40,
hop_length=frame_shift,
n_fft=frame_len
)
print(mfcc.shape)
特征提取之后还不能直接输出文字。早期的语音识别系统会把这些特征送入GMM-HMM声学模型,由高斯混合模型估计每一帧属于某个音素状态的概率,再由隐马尔可夫模型处理状态转移。这条链路虽然可解释,但训练复杂,且GMM对高维特征的建模能力有限。深度学习改变了这一局面,让特征表示和序列建模可以在同一个网络里完成。
声学模型的演进:从DNN到Conformer
深度神经网络最早以DNN形式进入语音识别领域,用来替代GMM计算音素状态后验概率。输入不再是单帧特征,而是前后若干帧拼接起来,这样网络在预测当前帧时能够看到上下文信息。DNN的参数量远大于GMM,可以拟合更复杂的非线性映射,在相同训练数据规模下,识别错误率明显下降。但DNN本身没有时序建模能力,仍然依赖HMM完成动态对齐。
随后循环神经网络尤其是LSTM被引入声学模型。LSTM通过门控机制在时间轴上传递状态,天然适合处理变长语音序列,不再需要拼接大量上下文帧。缺点是序列计算是串行的,训练和推理速度受限。Transformer带来并行计算能力,通过自注意力机制建模任意距离的依赖关系,在离线转写中表现出色。但它对局部细节不够敏感,且全序列注意力在长音频上计算开销很高。Conformer则把卷积和自注意力结合起来,卷积负责捕捉局部声纹变化,注意力负责捕捉全局语义,成为目前主流的语音识别编码器结构之一。
import torch
import torch.nn as nn
class ConformerBlock(nn.Module):
def __init__(self, dim, heads, kernel_size=31, dropout=0.1):
super().__init__()
self.ff1 = nn.Sequential(
nn.LayerNorm(dim),
nn.Linear(dim, dim * 4),
nn.GELU(),
nn.Dropout(dropout),
nn.Linear(dim * 4, dim),
)
self.attn = nn.MultiheadAttention(dim, heads, batch_first=True)
self.conv = nn.Sequential(
nn.Conv1d(dim, dim, kernel_size, padding=kernel_size // 2, groups=dim),
nn.BatchNorm1d(dim),
nn.SiLU(),
nn.Conv1d(dim, dim, 1),
)
self.ff2 = nn.Sequential(
nn.LayerNorm(dim),
nn.Linear(dim, dim * 4),
nn.GELU(),
nn.Dropout(dropout),
nn.Linear(dim * 4, dim),
)
self.norm = nn.LayerNorm(dim)
def forward(self, x):
x = x + 0.5 * self.ff1(x)
x = x + self.attn(x, x, x)[0]
x = x.transpose(1, 2)
x = x + self.conv(x).transpose(1, 2)
x = x + 0.5 * self.ff2(x)
return self.norm(x)
讯飞听见在语音转写中会根据场景选择不同的声学模型结构。对于离线转写,深层Conformer或Transformer可以提供更高的准确率;对于实时会议字幕,则可能采用经过流式优化的Conformer变体,通过限制注意力范围来降低延迟。这种结构上的取舍,直接影响产品的响应速度和转写质量。
端到端模型与语言模型融合
传统语音识别由声学模型、发音词典和语言模型三个独立模块组成,训练时各自优化,容易出现错误传递。端到端模型则把语音直接映射为文字序列,主要代表有CTC、注意力序列到序列模型和RNN-T。其中RNN-T非常适合流式转写,因为它在时间步上逐步输出符号,允许遇到空白标记时继续等待后续声学信息。相比全局注意力模型,RNN-T可以做到边听边出字。
不过端到端模型并不排斥外部语言模型。实际产品中常采用浅融合或重打分的方式,把端到端模型输出的候选文本再交给一个独立的语言模型打分。语言模型擅长建模词与词之间的长距离搭配关系,对于纠正同音字、补充标点、识别专业术语很有帮助。讯飞听见在会议场景中通常还会加入热词列表,比如参会人姓名、公司名称、项目代号等,通过上下文偏置提升这些词的召回率。
import torch
import torch.nn.functional as F
def greedy_decode(encoder_out, predictor, joiner, blank_id=0, max_steps=200):
batch = encoder_out.size(0)
pred_state = None
pred_token = torch.full((batch, 1), blank_id, dtype=torch.long)
output_tokens = []
y = pred_token
t = 0
while t < max_steps:
pred_vec, pred_state = predictor(y, pred_state)
logits = joiner(encoder_out[:, t, :], pred_vec[:, -1, :])
prob = F.softmax(logits, dim=-1)
token = torch.argmax(prob, dim=-1)
token = token.item()
if token != blank_id:
output_tokens.append(token)
y = torch.full((batch, 1), token, dtype=torch.long)
t += 1
return output_tokens
贪心解码只是最简单的路径,实际系统会使用束搜索来保留多个候选序列,同时平衡语言模型得分和声学得分。解码完成后还需要做逆文本正则化,把数字、日期、金额等符号还原成自然书写形式。标点恢复也常常作为后处理模块,因为语音里听不到标点,但屏幕上必须有句读,否则大段文字难以阅读。
工程落地中的流式、延迟与领域适配
实时转写和离线转写对系统的要求很不一样。离线场景可以等待整段音频结束后统一解码,模型能够利用完整上下文,准确率更高。实时场景则要求低延迟,用户期望说完一句话后文字几乎同步出现。为了做到这一点,流式模型会设计分块注意力掩码,只允许当前块关注已经解码的历史块和少量未来帧。允许未来帧的多少称为lookahead,增加lookahead可以提高准确率,但会引入额外延迟。
import torch
def create_chunk_mask(seq_len, chunk_size, device="cpu"):
# 构造分块注意力掩码:当前帧只看到所在块及其历史块
mask = torch.zeros(seq_len, seq_len, dtype=torch.bool, device=device)
for i in range(seq_len):
block_end = ((i // chunk_size) + 1) * chunk_size
mask[i, block_end:] = True
return mask
除了延迟,领域适配同样关键。通用语音模型在新闻、日常对话上表现不错,但放到医疗、法律、能源等专业会议中,术语识别率会下降。常见的做法包括收集领域数据进行微调、在解码时注入行业热词、或者通过语言模型提示的方式让模型在特定上下文中工作。数据增强技术也被广泛使用,例如对原音频加入多种噪声、改变语速、模拟远场混响,让模型在真实环境中更鲁棒。
语音转写不是一个单点算法,而是一条融合信号处理、深度学习、自然语言处理和工程优化的完整链路。讯飞听见背后的技术思路,正是通过Conformer声学模型获得可靠的声学表示,通过端到端建模减少错误传播,再通过流式解码、语言模型融合和领域适配来满足真实产品对准确率与延迟的双重要求。随着模型结构和训练方法持续迭代,语音转写会越来越接近人类对语言的理解能力。