PaddleSpeech S2T 前端特征提取器(Featurizer)完全解析:AudioFeaturizer / SpeechFeaturizer / TextFeaturizer 源码级指南
2026/9/23 19:33:18 网站建设 项目流程
  • 人工智能
  • 语音
  • 音频
  • NLP
  • 媒体生成

【免费下载链接】PaddleSpeech

Easy-to-use Speech Toolkit including Self-Supervised Learning model, SOTA/Streaming ASR with punctuation, Streaming TTS with text frontend, Speaker Verification System, End-to-End Speech Translation and Keyword Spotting. Won NAACL2022 Best Demo Award.

项目地址:https://gitcode.com/paddlepaddle/PaddleSpeech
点击查看免费下载

导读

paddlespeech.s2t.frontend.featurizer是飞桨 PaddleSpeech 语音识别(S2T)训练与推理流水线的"入口关卡":它负责把原始音频波形与文本转写统一转换为模型可消费的特征张量,涵盖线性频谱图(linear spectrogram)、MFCC、FBank 三类音频特征,以及 char/word/sentencepiece 三种粒度的文本 token 化。本文以该包的 API 文档与源码为主体,深入讲解三大特征提取器类的构造参数、调用链与底层实现,并给出真实配置文件中的接入方式,帮助你理解 PaddleSpeech 数据管线从"wav + 文本"到"特征 + token id"的完整过程。


1. 包结构与职责划分

featurizer包位于 paddlespeech/s2t/frontend/featurizer,由三个子模块构成,并在init.py 中统一导出:

模块导出类职责
audio_featurizerAudioFeaturizer从音频片段(AudioSegment/SpeechSegment)中提取线性频谱、MFCC、FBank 特征
speech_featurizerSpeechFeaturizer组合音频特征与文本特征,是训练数据管线的主入口
text_featurizerTextFeaturizer将文本转写转换为 token 索引序列,或反向还原为文本

三者关系清晰:SpeechFeaturizer内部持有AudioFeaturizerTextFeaturizer各一个实例,对外提供统一的featurize()接口。从源码结构看,AudioFeaturizer只关心信号处理,TextFeaturizer只关心词表与 token 化,而SpeechFeaturizer负责调度与组合,这种分层设计使得音频特征与文本特征可以独立替换和演进。


2. AudioFeaturizer:音频特征提取核心

2.1 构造参数与默认值

AudioFeaturizer 的构造函数完整签名如下(含源码默认值):

AudioFeaturizer( spectrum_type: str = 'linear', # 特征类型:'linear' | 'mfcc' | 'fbank' feat_dim: int = None, # MFCC/FBank 使用,如 13、40、80 delta_delta: bool = False, # 是否拼接 delta 与 delta-delta(维度 ×3) stride_ms = 10.0, # 帧移(毫秒) window_ms = 20.0, # 窗长(毫秒) n_fft = None, # 自定义 FFT 点数,None 时由窗长推导 max_freq = None, # 最大频率;linear 截断 FFT bin,mfcc/fbank 为 mel 滤波器最高边 target_sample_rate = 16000, # 目标采样率,输入音频会先重采样到此值 use_dB_normalization = True, # 是否做分贝归一化 target_dB = -20, # 归一化目标分贝 dither = 1.0) # 加性噪声抖动,用于 mfcc/fbank

各参数对特征结果的影响:

  • spectrum_type'linear'输出 log 幅度线性频谱,'mfcc'输出梅尔倒谱系数,'fbank'输出 log 梅尔滤波器组能量。三者对feat_dimn_fftdither的依赖不同,见下文实现细节。
  • delta_delta:开启后,MFCC/FBank 会拼接[原特征, delta, delta-delta],特征维度变为原来的 3 倍,为模型提供动态信息。
  • stride_ms/window_ms:控制分帧的步长与窗长,直接决定时间帧数与频谱分辨率;源码在_compute_linear_specgram_compute_mfcc_compute_fbank中均校验stride_ms <= window_ms,违反会抛出ValueError
  • max_freqNone时默认取sample_rate / 2(奈奎斯特频率);若显式设置超过采样率一半,源码会抛ValueError
  • target_sample_ratefeaturize()中若输入片段采样率与目标不一致,会调用audio_segment.resample()重采样(受allow_downsampling/allow_upsampling开关控制),重采样后仍不匹配则抛异常,提示打开对应开关。
  • use_dB_normalization/target_dB:归一化通过audio_segment.normalize(target_db=target_dB)实现,将音频幅度对齐到固定分贝,降低录音响度差异带来的特征漂移。

2.2 featurize() 主流程

featurize(audio_segment, allow_downsampling=True, allow_upsampling=True)是核心入口(audio_featurizer.py#L77-L108),执行三步:

  1. 重采样:采样率高于目标且允许降采样、或低于目标且允许升采样时,调用resample(target_sample_rate)
  2. 分贝归一化:开启时执行normalize(target_db=target_dB)
  3. 特征计算:按spectrum_type分发到_compute_linear_specgram/_compute_mfcc/_compute_fbank,返回形状为(时间帧 T, 特征维度 D)的 2D ndarray。

2.3 feature_size:特征维度的推导规则

feature_size属性(audio_featurizer.py#L114-L133)是模型输入维度的重要依据,其计算规则:

  • linearfeat_dim = int(fft_point * (target_sample_rate / 1000) / 2 + 1),其中fft_pointn_fftNone时取window_ms。以 16kHz、20ms 窗长为例,FFT 点数为 320,特征维度为320 * 16 / 2 + 1 = 2561(rfft 仅保留非负频率 bin,故约半)。
  • mfcc / fbankfeat_dim = feat_dim * 3(开启delta_delta)或feat_dim(未开启)。
  • 其他类型:抛ValueError,提示仅支持linear

这也解释了为何 Aishell 等中文 ASR 配置中feat_dim: 80配合fbank:80 维 FBank 加上 10ms 帧移、25ms 窗长,是当前仓库中 Conformer/U2 等模型的默认前端配置。

2.4 三种特征的底层实现

线性频谱(linear)_compute_linear_specgram(audio_featurizer.py#L196-L238)通过_specgram_real完成核心计算:

  • np.lib.stride_tricks.as_strided对采样点构造滑窗视图,不做数据拷贝;
  • 使用np.hanning汉宁窗加权后执行np.fft.rfft,取幅度平方得到功率谱;
  • 按窗能量sum(weighting^2) * sample_rate缩放,频点能量归一化;
  • 根据max_freq截取频率 bin,取log(spec + eps)eps=1e-14防止对数下溢),最终转置为(T, D)输出。

MFCC_compute_mfcc(audio_featurizer.py#L257-L312)依赖python_speech_features.mfcc,关键参数固定为:

mfcc(signal=samples, samplerate=sample_rate, winlen=0.001 * window_ms, winstep=0.001 * stride_ms, numcep=feat_dim, nfilt=23, nfft=512, lowfreq=20, highfreq=max_freq, dither=dither, remove_dc_offset=True, preemph=0.97, ceplifter=22, useEnergy=True, winfunc='povey')

注意其中useEnergy=True会用 log 帧能量替换第一个倒谱系数;输入音频先被转为int16。开启delta_delta时调用_concat_delta_delta拼接一阶、二阶差分(audio_featurizer.py#L240-L255)。

FBank_compute_fbank(audio_featurizer.py#L314-L363)走的是 Kaldi 兼容路径——调用paddlespeech.audio.compliance.kaldi.fbank,将波形转为 Paddle Tensor 后计算:

mat = kaldi.fbank(waveform, n_mels=feat_dim, frame_length=window_ms, frame_shift=stride_ms, dither=dither, energy_floor=0.0, sr=sample_rate)

这一实现与 Kaldi 的 fbank 计算约定对齐,使 PaddleSpeech 提取的特征可与 Kaldi 工具链的 CMVN 统计(compute-cmvn-stats.pyapply-cmvn.py)互通,是仓库中fbank类型被 ASR 配方广泛采用的技术基础。


3. TextFeaturizer:文本 token 化与词表管理

3.1 构造与词表加载

TextFeaturizer 的构造参数为:

TextFeaturizer(unit_type, vocab, spm_model_prefix=None, maskctc=False)
  • unit_type:必须是'char''spm''word'三者之一(源码assert强制校验);
  • vocab:词表文件路径或词表 list;为空时仅能 tokenize,无法转换为 token id(源码会打印 warning);
  • spm_model_prefixunit_type == 'spm'时必填,实际加载prefix + '.model'作为 sentencepiece 模型;
  • maskctc:用于 Mask CTC 训练,影响词表加载时是否注入<mask>特殊 token。

词表加载走 utility.py 的load_dict:词表文件每行一个 token(支持token id双列格式,取第一列),并保证<blank><eos>等特殊 token 存在(缺失时自动插入到词表头部)。加载后同时生成token2idid2token两个映射,并解析出blank_idunk_ideos_id等供训练与解码使用。

3.2 特殊 token 约定

特殊 token 常量定义在 paddlespeech/s2t/frontend/utility.py#L37-L44:

常量取值含义
IGNORE_ID-1忽略位 id
SOS/EOS"<eos>"起始与结束共用同一 token
UNK"<unk>"未登录词
BLANK"<blank>"CTC 的 blank 符号
MASKCTC"<mask>"Mask CTC 掩码符号
SPACE"<space>"空格占位符(字符级分词用)

这些约定与 CTC 解码、注意力解码器的序列建模直接相关,例如defeaturize()在遇到eos_id时即停止还原,与解码器的终止条件一致。

3.3 核心方法:tokenize / detokenize / featurize / defeaturize

  • tokenize(text)/detokenize(tokens):按unit_type分发到char/word/spm三种实现。
  • featurize(text) -> List[int]:tokenize 后逐 token 查词表;未登录 token 替换为UNK(debug 日志记录),最终返回 token id 列表。
  • defeaturize(idxs) -> str:id 列表还原为文本,自动兼容[[1,2,3]]形式的嵌套输入,遇eos_id截断。

三种 tokenizer 的实现要点:

  • charchar_tokenize将文本 strip 后逐字符拆分,空格替换为<space>replace_space=True时);char_detokenize反向把<space>还原为空格后拼接。replace_space=False仅用于build_vocab.py建词表场景。
  • word:按空格split()/join(),适用于英文等以空格分隔的语言。
  • spmspm_tokenize通过 sentencepiece 的EncodeAsPieces得到子词序列,spm_detokenize支持'piece''id'两种输入格式,用DecodePieces/DecodeIds还原文本。

4. SpeechFeaturizer:音频 + 文本的统一入口

SpeechFeaturizer 聚合了两大子特征器,构造参数是AudioFeaturizerTextFeaturizer参数的并集(unit_typevocab_filepathspm_model_prefixspectrum_typefeat_dimdelta_deltastride_mswindow_msn_fftmax_freqtarget_sample_rateuse_dB_normalizationtarget_dBdithermaskctc),并在初始化时暴露两个关键属性:

  • feature_size:转发自audio_feature.feature_size,即模型音频输入维度;
  • vocab_size:转发自text_feature.vocab_size,即模型输出类别数。

它对外提供两个方法:

def featurize(self, speech_segment, keep_transcription_text): # 1) 音频特征:spec_feature = audio_feature.featurize(speech_segment) # 2) 文本部分: # keep_transcription_text=True -> 直接返回原文 transcript # False 且 segment 已有 token_ids -> 返回 token_ids # 否则 -> text_feature.featurize(transcript) 得到 token id 列表 # 返回 (spec_feature, text_ids_or_text) def text_featurize(self, text, keep_transcription_text): # 仅处理文本:返回原文或 token id 列表

keep_transcription_text开关决定了流水线输出的是"训练用的 token id"还是"推理/评估用的原始文本",训练与解码阶段因此可以复用同一套特征器。


5. 在数据管线与配置文件中的实际接入

5.1 Collator 中的调用链

SpeechFeaturizer的实际消费方是 paddlespeech/s2t/io/collator.py 中的CollateFN(collator.py#L111-L131 构造、collator.py#L133-L172 使用):

  1. 从 manifest 读取音频文件构建SpeechSegment
  2. AugmentationPipeline.transform_audio做音频增强;
  3. 调用speech_featurizer.featurize(speech_segment, keep_transcription_text)得到(spectrum, transcript_part)
  4. 若有 CMVN 统计文件,对频谱执行FeatureNormalizer.apply归一化;
  5. 再经transform_feature做频谱域增强,最终产出模型输入 batch。

此外,模型端(如 u2/model.py、hubert/model.py、wav2vec2/model.py、deepspeech2/model.py 等)也会直接引用TextFeaturizer完成推理时的文本编码,足见该包在训练与推理两侧的复用程度。

5.2 真实配置示例

以 examples/aishell/asr1/conf/conformer.yaml 为例,Dataloader 一节完整展示了特征器相关配置:

vocab_filepath: data/lang_char/vocab.txt # 词表文件,TextFeaturizer 加载 spm_model_prefix: '' # 空表示不使用 spm,unit_type 为 char unit_type: 'char' # 字符级分词 preprocess_config: conf/preprocess.yaml # 数据增强/预处理配置 feat_dim: 80 # FBank 维度(fbank 特征) stride_ms: 10.0 # 帧移 10ms window_ms: 25.0 # 窗长 25ms

对应地,examples/aishell/asr0/local/data.sh 在生成数据时使用--spectrum_type="fbank"--unit_type="char",两者保持一致才能保证AudioFeaturizer.feature_size(此处为 80)与模型输入、TextFeaturizer.vocab_size与模型输出类别数严格对齐。

5.3 训练管线中的整体流程

结合上述代码,一次 utterance 的特征化可概括为:

wav + transcript │ ├─ SpeechSegment.from_file ├─ transform_audio (增强) ├─ AudioFeaturizer.featurize │ ├─ resample(16k) ── dB normalize(-20dB) ── 分帧加窗 ── FFT │ └─ 输出 (T, feat_dim) 频谱 ├─ TextFeaturizer.featurize │ └─ char/spm/word tokenize ── 查词表 ── 输出 List[int] └─ 输出 (spectrum, token_ids) → CMVN → 特征增强 → 模型

6. 小结与扩展阅读

paddlespeech.s2t.frontend.featurizer是 PaddleSpeech S2T 体系中音频前端与文本前端的统一抽象:

  • AudioFeaturizer提供 linear/MFCC/FBank 三种频谱计算,内置重采样、分贝归一化、delta-delta 拼接等预处理,其feature_size是模型输入维度的权威来源;
  • TextFeaturizer覆盖 char/word/spm 三种分词粒度,负责词表加载、特殊 token 约定与 id 双向转换;
  • SpeechFeaturizer将两者组装为单一入口,通过keep_transcription_text兼顾训练与解码两种模式。

想要继续深入,可以从以下仓库路径展开:

  • 特征器源码:featurizer 目录,重点关注audio_featurizer.py_specgram_real_compute_mfcc_compute_fbank
  • 特殊 token 与词表工具:frontend/utility.py;
  • 数据管线消费方:s2t/io/collator.py;
  • 模型端引用:u2/model.py、hubert/model.py;
  • 真实配置:examples/aishell/asr1/conf/conformer.yaml、examples/aishell/asr0/conf/deepspeech2.yaml。

理解了这一层"前端",你就掌握了 PaddleSpeech 从原始音频到模型输入之间最关键的转换环节,无论是替换特征类型、切换分词粒度,还是接入新数据集,都能从配置与源码两个层面精准下手。

  • 人工智能
  • 语音
  • 音频
  • NLP
  • 媒体生成

【免费下载链接】PaddleSpeech

Easy-to-use Speech Toolkit including Self-Supervised Learning model, SOTA/Streaming ASR with punctuation, Streaming TTS with text frontend, Speaker Verification System, End-to-End Speech Translation and Keyword Spotting. Won NAACL2022 Best Demo Award.

项目地址:https://gitcode.com/paddlepaddle/PaddleSpeech
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询