简介这份资源面向语音信号处理与人工智能方向的初学者及进阶学习者提供一套基于Python与Jupyter Notebook的语音特征提取实践材料可用于语音识别、情感分析等场景的入门与练手。压缩包共222个文件约29.87MB以png图表、py脚本、md说明、html文档、ipynb笔记本为主另含wav语音样本、pt模型文件、praat脚本及Sphinx文档构建相关配置覆盖代码、数据与文档多个层面。已有198人学习下载。内容围绕音频加载与预处理、时域波形与短时能量分析、短时傅立叶变换与频谱图、MFCC提取及其他谱熵、过零率等特征展开并借助Jupyter Notebook逐步记录运行结果便于读者边调试边理解每一步输出。通过动手复现这些流程读者可掌握librosa等工具的使用方法积累从原始语音到特征向量的完整处理经验为后续训练SVM、DNN等模型打下基础。1. 从语音信号中提取特征为什么你下的这个 Notebook 跑不出论文里的那条曲线你下载了一个名为「从语音信号中提取特征_Jupyter Notebook_Python_下载.zip」的压缩包解压后大概率会看到一个.ipynb文件、一两个.wav样例可能还有一份requirements.txt。打开 Jupyter Notebook 一路 ShiftEnter最后画出来的 MFCC 热力图看着挺像那么回事但把它喂给分类器准确率就是上不去。问题往往不在模型而在特征提取这一段——预加重系数、帧长、帧移、窗函数、梅尔滤波器个数、是否做倒谱均值归一化任何一个参数没对齐特征分布就变了。这篇笔记面向两类人一是刚用 Python 做语音方向、想搞懂「特征提取到底在提什么」的新手二是已经能跑通代码、但想弄明白每个参数边界和踩坑点的熟手。我会按「信号怎么变成向量 → 每个参数怎么定 → 哪里最容易翻车 → 怎么验证提得对不对」的顺序讲所有代码都能直接粘进 Jupyter Notebook 里跑。语音特征提取不是什么黑匣子它是一串有明确物理含义的数学操作理解了每一步你才知道该改哪个数。2. 语音特征提取的底层链路从波形到梅尔倒谱系数2.1 为什么原始采样点不能直接当特征一段 16kHz、2 秒的语音就是 32000 个浮点数。直接把这 32000 维向量丢给分类器会碰到三个硬问题维度太高导致样本需求爆炸、时域波形对时间偏移极度敏感、人耳感知的频率分辨率并非线性。所以特征提取的本质是「降维 去冗余 贴合听觉特性」。常见做法是分帧。语音在 10~30ms 尺度上可以近似看成平稳信号于是把长信号切成短帧每帧做频谱分析。这一步的产物是帧矩阵行是时间帧列是频率 bin。后面所有操作——加窗、FFT、梅尔滤波、取对数、DCT——都是在这个矩阵上做变换。理解这条链路比记住librosa.feature.mfcc的参数重要得多因为一旦结果不对你能顺着链路往回查是哪一步歪了。2.2 预加重、分帧、加窗三个最容易被忽略的预处理预加重是一阶高通滤波目的是补偿语音从声门到嘴唇辐射时高频被衰减的部分。系数一般取 0.97公式是y[n] x[n] - 0.97 * x[n-1]。很多人直接跳过这步结果高频共振峰信息偏弱在清音和摩擦音上区分度下降。分帧要定两个参数帧长和帧移。帧长通常 20~25ms帧移通常 10ms也就是 50% 重叠。16kHz 下25ms 是 400 个采样点10ms 是 160 个采样点。重叠是为了避免帧边界处的信息丢失。加窗一般用汉明窗把帧两端削到接近零减少 FFT 的频谱泄漏。import numpy as np def pre_emphasis(signal, coeff0.97): # 一阶高通补偿高频衰减 return np.append(signal[0], signal[1:] - coeff * signal[:-1]) def frame_signal(signal, frame_len, frame_shift): # 按帧长和帧移切分返回二维矩阵 (帧数, 帧长) num_frames 1 (len(signal) - frame_len) // frame_shift indices np.arange(frame_len)[None, :] frame_shift * np.arange(num_frames)[:, None] return signal[indices] def apply_window(frames, window_typehamming): # 加窗抑制频谱泄漏 if window_type hamming: win np.hamming(frames.shape[1]) else: win np.ones(frames.shape[1]) return frames * win逻辑说明pre_emphasis用np.append保留第一个采样点避免长度少一。frame_signal用广播生成索引矩阵比 Python 循环快一个量级。apply_window里窗函数长度必须等于帧长否则广播会报错。参数说明coeff取 0.95~0.97噪声大时取小一点frame_len在 16kHz 下取 40025ms8kHz 下取 200frame_shift一般取frame_len // 2或固定 10ms 对应点数。帧移大于帧长会丢信息小于帧长一半则计算量翻倍但收益很小。2.3 从功率谱到梅尔滤波器组人耳尺度怎么落地FFT 之后取模平方得到功率谱。人耳对频率的感知不是线性的1kHz 以下近似线性1kHz 以上近似对数。梅尔刻度就是模拟这个特性mel 2595 * log10(1 f/700)。梅尔滤波器组是一组三角形滤波器在梅尔刻度上等间距分布转回赫兹后低频密、高频疏。滤波器个数常见 26 或 40。个数太少频率分辨率不够太多相邻滤波器相关性高后面 DCT 去相关效果打折。每个滤波器对功率谱加权求和得到该频带的能量再取对数得到对数梅尔谱。这一步已经可以作为特征用了比如在语音增强和声学场景分类里对数梅尔谱有时比 MFCC 更稳。2.4 DCT 与动态特征把 40 维压到 13 维并补上时间信息对对数梅尔谱做离散余弦变换DCT取前 13 个系数就是 MFCC。DCT 的作用是去相关把能量集中到低阶系数。第 0 阶代表帧能量通常丢弃或单独处理。取 13 是因为更高阶系数对应滤波器组的快速变化多为噪声。静态 MFCC 只描述单帧缺少时间动态。常见做法是拼接一阶差分delta和二阶差分delta-delta得到 39 维。差分用numpy.diff或scipy.signal.savgol_filter都行窗口一般取 2前后各两帧。这一步对连续语音识别提升明显但对孤立词或短命令词增益有限反而增加维度。import librosa y, sr librosa.load(sample.wav, sr16000) mfcc librosa.feature.mfcc( yy, srsr, n_mfcc13, # 倒谱系数个数 n_fft512, # FFT 点数需 帧长 hop_length160, # 帧移10ms win_length400, # 帧长25ms n_mels26, # 梅尔滤波器个数 fmin0, fmax8000 # 频率范围通常到 Nyquist ) delta librosa.feature.delta(mfcc) delta2 librosa.feature.delta(mfcc, order2) features np.vstack([mfcc, delta, delta2]) # (39, 帧数)逻辑说明librosa.load默认会重采样到 22050这里显式指定 16000避免和后续参数不匹配。n_fft必须大于等于win_length否则报错。librosa.feature.delta默认窗口为 9对短语音可能边界效应明显。参数说明n_mfcc取 13 是通用起点做声纹任务可加到 20n_mels取 26 或 40和n_mfcc不必相等fmax一般设到sr/2但如果采样设备在 7kHz 以上噪声大可以降到 7000 减少干扰。hop_length决定时间分辨率做关键词检测时常用 10ms做长语音情感识别可以放宽到 20ms。3. 在 Jupyter Notebook 里把特征提取跑通环境、数据与可视化3.1 Python 环境与 Jupyter Notebook 安装的最小闭环如果你还没装 Python去官网下 3.9~3.11 的版本安装时勾选「Add Python to PATH」。然后开终端python -m pip install --upgrade pip pip install jupyter notebook numpy scipy librosa matplotlib soundfile jupyter notebook浏览器会自动打开http://localhost:8888。如果你用 VS Code装 Python 扩展后直接在.ipynb里选解释器也行这就是常说的 vscode python 环境配置。Jupyter Notebook 网页版和本地版操作一致区别只是文件存哪。注意librosa依赖numba首次导入会编译等十几秒正常。提示如果pip install librosa卡在llvmlite编译先升级 pip 和 setuptools或者用 conda 装。Windows 上缺 C 编译工具也会导致失败。3.2 读音频、看波形、听差异三行代码建立直觉拿到.wav后别急着提特征先看波形和频谱。很多翻车是因为音频本身有问题采样率不对、双声道没转单声道、静音段太长、幅度削顶。import librosa import librosa.display import matplotlib.pyplot as plt y, sr librosa.load(sample.wav, sr16000, monoTrue) print(f采样率 {sr}, 时长 {len(y)/sr:.2f}s, 幅度范围 [{y.min():.3f}, {y.max():.3f}]) plt.figure(figsize(12, 3)) librosa.display.waveshow(y, srsr) plt.title(Waveform) plt.tight_layout() plt.show()逻辑说明monoTrue强制单声道避免后续维度混乱。打印幅度范围能快速判断是否削顶接近 ±1.0 且大量样本贴边。waveshow比直接plot(y)在处理长音频时更清晰。参数说明sr16000是语音任务常用值电话语音用 8000音乐或宽频语音用 22050 或 44100。如果原始文件是 44.1kHz重采样到 16kHz 会丢高频但对语音识别影响不大反而减少计算量。3.3 用 librosa 提取 MFCC 并画出热力图把第 2 章的链路用librosa走一遍然后画出来。热力图横轴时间、纵轴系数序号颜色代表数值。正常语音的低阶系数0~12会有明显的水平条纹条纹随发音变化。mfcc librosa.feature.mfcc(yy, srsr, n_mfcc13, n_fft512, hop_length160, win_length400, n_mels26) plt.figure(figsize(12, 4)) librosa.display.specshow(mfcc, x_axistime, srsr, hop_length160) plt.colorbar(format%2.0f) plt.title(MFCC) plt.tight_layout() plt.show()逻辑说明specshow的hop_length必须和提取时一致否则时间轴错位。x_axistime会自动按帧移换算秒数。参数说明如果热力图整体偏暗或偏亮检查是否做了倒谱均值归一化CMN。CMN 是减去每维的均值能消除信道影响在跨设备场景下常用。librosa没有直接开关手动mfcc - mfcc.mean(axis1, keepdimsTrue)即可。3.4 特征维度对齐与保存成 npy提取完的特征要存下来给模型用。注意维度方向librosa返回(n_mfcc, 帧数)而多数分类器期望(帧数, 特征维)。转置别忘。feat mfcc.T # (帧数, 13) np.save(feat.npy, feat) print(feat.shape, feat.dtype)逻辑说明.npy比 CSV 快且保留浮点精度。如果要做变长序列可以存列表再np.save成 object 数组但更推荐统一帧数或使用 padding。参数说明dtype默认 float32 或 float64模型训练时统一转 float32 省显存。如果特征值范围差异大可以按维做标准化但要注意训练集和测试集用同一组均值方差。4. 特征提取的避坑与排查那些让准确率掉 10 个点的细节4.1 采样率不匹配导致梅尔滤波器错位现象同一段音频用 16kHz 和 22.05kHz 提取的 MFCC 热力图形态相似但数值对不上模型在测试集上准确率波动大。原因librosa.load默认sr22050如果你没显式指定而训练数据是按 16kHz 提的梅尔滤波器的频率边界就变了。fmax默认是sr/2采样率一变整个滤波器组跟着平移。解决在load和mfcc两处都写死sr16000并在项目里统一用一个常量。如果数据来源杂先批量重采样再提特征。4.2 帧长大于 FFT 点数直接报错现象n_fft256配win_length400运行时报ValueError: n_fft must be greater than or equal to win_length。原因FFT 点数必须能覆盖一帧的长度。帧长 400 点FFT 至少 400通常取 512 方便计算。解决n_fft取大于等于win_length的 2 的幂比如 512 或 1024。如果非要小 FFT就减小帧长但 25ms 以下频率分辨率会变差。4.3 静音段拉低特征均值现象一段前后有长静音的音频提取的 MFCC 第 0 阶均值明显偏低分类器把静音当成一个类别。原因静音段能量低对数梅尔谱接近负无穷MFCC 第 0 阶被拉低。如果没做端点检测静音帧会混进特征序列。解决用短时能量或librosa.effects.trim去掉首尾静音再做特征提取。或者在训练时对非静音帧加权。y_trim, _ librosa.effects.trim(y, top_db25)top_db25表示低于峰值 25dB 的部分视为静音数值越小裁剪越激进。4.4 差分特征在短音频上边界失真现象2 秒以内的短命令词加了 delta 和 delta-delta 后首尾几帧数值异常大模型在验证集上过拟合。原因librosa.feature.delta默认用 9 帧窗口做回归短音频首尾没有足够上下文用边缘填充导致差分值被放大。解决短音频要么不加动态特征要么把width调小到 3 或 5要么在计算前做边界反射填充。我一般对小于 1.5 秒的音频只用静态 MFCC。4.5 忘记转置导致维度对不上现象X.shape是(13, 200)喂给 sklearn 的fit报Found input variables with inconsistent numbers of samples。原因librosa输出是(特征维, 帧数)sklearn 期望(样本数, 特征维)。这里样本是帧特征是 13 维。解决统一在提取后.T转置并在函数返回值注释里写清维度顺序。团队协作时最好封装成一个extract_features函数输入音频路径输出(帧数, 维数)。5. 验证特征提得对不对三个可复现的检查手段5.1 重建波形听差异预加重和加窗到底改了什么把预加重后的信号和原信号分别保存成 wav用耳朵听。预加重后高频更亮齿音更明显。如果听不出区别说明你的音频高频本来就弱或者预加重系数设得太小。这一步能帮你建立参数和听感的对应关系。import soundfile as sf y_pre pre_emphasis(y, 0.97) sf.write(orig.wav, y, sr) sf.write(pre.wav, y_pre, sr)注意保存前做归一化避免削顶。soundfile写 float32 默认不削顶但播放器可能按 int16 处理。5.2 用 MFCC 做一次最近邻检索特征有没有区分度拿 10 段不同数字的语音提取 MFCC 后取每段均值向量算两两余弦相似度。如果同数字的相似度明显高于不同数字说明特征有区分度。如果全都差不多检查是不是没做 CMN 或者滤波器个数太少。from sklearn.metrics.pairwise import cosine_similarity feats np.array([extract(path).mean(axis0) for path in paths]) sim cosine_similarity(feats) print(sim)这个检查不需要训练模型几分钟就能跑完适合在调参前做基线。5.3 对比不同参数下的分类准确率用网格搜索定边界固定分类器比如 SVM 或逻辑回归只变特征参数看准确率怎么动。重点观察n_mfcc、n_mels、hop_length三个。如果准确率对某个参数不敏感说明你的任务对该维度不依赖可以取小值省算力。参数候选值观察点n_mfcc13, 20, 26超过 20 后准确率是否还涨n_mels26, 40, 64和 n_mfcc 的比值影响 DCT 效果hop_length80, 160, 320时间分辨率与数据量权衡动态特征无, delta, deltadelta2短音频是否反而下降我一般先用 13/26/160 跑基线再单独调一个参数每次只动一个记录准确率和训练时间。别一次改三个否则出了问题不知道是谁的锅。5.4 一个容易忽略的验证特征随时间是否平稳把 MFCC 每一维沿时间轴画出来看有没有突跳。正常语音是平滑变化的如果某几帧突然全维跳变多半是音频里有爆音或裁剪边界。这种帧在训练时会变成噪声标签建议用中值滤波或直接剔除。plt.figure(figsize(12, 6)) for i in range(13): plt.plot(mfcc[i], labelfc{i}) plt.legend(ncol2, fontsize8) plt.title(MFCC coefficients over time) plt.show()如果某条曲线在开头或结尾剧烈震荡就是边界效应考虑加反射填充或裁掉前几帧。6. 把特征提取封装成可复用模块从 Notebook 到脚本的最后一公里Notebook 适合探索但每次改参数都要重跑所有单元格效率低。我习惯在验证完参数后把提取逻辑抽成一个features.pyNotebook 里只调函数。这样换数据集时不用改代码只改配置。# features.py import numpy as np import librosa SR 16000 N_MFCC 13 N_MELS 26 N_FFT 512 HOP 160 WIN 400 def extract(path, use_deltaTrue): y, _ librosa.load(path, srSR, monoTrue) y, _ librosa.effects.trim(y, top_db25) mfcc librosa.feature.mfcc(yy, srSR, n_mfccN_MFCC, n_fftN_FFT, hop_lengthHOP, win_lengthWIN, n_melsN_MELS) mfcc mfcc - mfcc.mean(axis1, keepdimsTrue) # CMN if use_delta: d1 librosa.feature.delta(mfcc, width5) d2 librosa.feature.delta(mfcc, order2, width5) mfcc np.vstack([mfcc, d1, d2]) return mfcc.T.astype(np.float32)逻辑说明把采样率、帧长等写成模块级常量换任务时只改这里。trim去掉静音CMN消除信道均值width5比默认 9 更适合短音频。返回前转置并转 float32直接对接 PyTorch 或 sklearn。参数说明如果做声纹识别N_MFCC可以提到 20use_delta设为 False因为声纹更依赖静态频谱包络。如果做关键词检测HOP可以降到 80 提高时间分辨率但特征矩阵会大一倍训练时注意显存。封装完之后Notebook 里只留可视化和调参代码可维护性提升明显。我踩过最大的坑就是在一个 Notebook 里改了 20 版参数最后忘了哪版对应哪个结果只能全部重跑。现在习惯每改一组参数就存一个feat_v3.npy并在文件名里带参数比如feat_mfcc13_mel26_hop160.npy后悔药提前备好。最后说个习惯每次提完特征先打印shape、dtype、min/max/mean再画一张热力图。这三个数加一张图能拦住八成以上的低级错误。特征提取没有玄学只有没对齐的参数和没检查的边界。希望帮到你。本文还有配套的精品资源点击获取