跨说话人音频相似度检测异常:MFCC+DTW方法问题排查与优化
语音相似度检测问题
我有两段由不同说话人录制的、包含同一词汇的音频文件,需要验证它们是否相似,但不想采用语音转文本的方式(因为部分音频不含有效词汇)。
我对音频预处理后提取了MFCCs(梅尔频率倒谱系数)向量,并应用了DTW(动态时间规整)算法。对比同一音频时得到0相似度分数(符合预期),但对比不同说话人的同词汇音频时却得到高分(判定为不相似),这显然不符合需求。请问我的方法存在什么问题?能否提供解决思路?
现有实现代码
from pydub import AudioSegment, silence from scipy.signal import lfilter import librosa import numpy as np from sklearn.preprocessing import StandardScaler from dtw import dtw # 音频静音切割预处理 audio_file = AudioSegment.from_wav('C://Users//10Rs6//Desktop//testapb.wav') min_silence_len = 100 # 毫秒 silence_thresh = -25 # dBFS non_silent_segments = silence.split_on_silence(audio_file, min_silence_len=min_silence_len, silence_thresh=silence_thresh) trimmed_audio = AudioSegment.empty() for segment in non_silent_segments: trimmed_audio += segment trimmed_audio.export('C://Users//10Rs6//Desktop//trimmed_audio5.wav', format='wav') # 预加重函数 def preemphasis(signal, alpha=0.97): return lfilter([1, -alpha], [1], signal) # 假设resampled_audio_test和resampled_audio_ref是已重采样的音频数组 pre_emphasised_test = preemphasis(resampled_audio_test) pre_emphasised_ref = preemphasis(resampled_audio_ref) normalized_test = librosa.util.normalize(pre_emphasised_test) normalized_ref = librosa.util.normalize(pre_emphasised_ref) # 提取MFCC并错误地做了时间维度均值 mfccsT = librosa.feature.mfcc(y=pre_emphasised_test, sr=41100, n_mfcc=13) mfccsT = np.mean(mfccsT.T, axis=0) # 这里丢失了时间序列信息 mfccsR = librosa.feature.mfcc(y=pre_emphasised_ref, sr=41100, n_mfcc=13) mfccsR = np.mean(mfccsR.T, axis=0) # 同样丢失时间序列 # 分别标准化两个MFCC(错误) mfccsT_2d = np.reshape(mfccsT, (mfccsT.shape[0], -1)) scaler = StandardScaler() scaler.fit(mfccsT_2d) normalized_mfccsT_2d = scaler.transform(mfccsT_2d) normalized_mfccsT = np.reshape(normalized_mfccsT_2d, mfccsT.shape) mfccsR_2d = np.reshape(mfccsR, (mfccsR.shape[0], -1)) scaler = StandardScaler() scaler.fit(mfccsR_2d) normalized_mfccsR_2d = scaler.transform(mfccsR_2d) normalized_mfccsR = np.reshape(normalized_mfccsR_2d, mfccsR.shape) # DTW计算距离 normalized_mfccsT = normalized_mfccsT.reshape(-1, 1) normalized_mfccsR = normalized_mfccsR.reshape(-1, 1) l2_norm = lambda x, y: (x - y) ** 2 dist, cost_matrix, acc_cost_matrix, path = dtw(normalized_mfccsT, normalized_mfccsR, dist=l2_norm) print(dist)
问题分析
你的核心问题出在MFCC特征的处理和标准化流程上,完全浪费了DTW的时序对齐能力:
- 丢失语音时序信息:对MFCC的时间维度取均值,把原本的二维时序特征(13个MFCC系数×时间步)压缩成了一维静态向量。DTW的作用是对齐不同长度的时间序列,现在变成了两个固定向量的距离计算,完全忽略了同一词汇发音的时序变化(比如辅音到元音的过渡节奏),不同说话人的同词汇发音时序差异被抹平,自然无法正确判断相似度。
- 独立标准化导致特征分布不一致:分别对两个音频的MFCC做StandardScaler,相当于把两个特征拉到了不同的分布空间,此时计算的距离没有意义,无法反映真实的特征相似性。
- 额外隐患:代码中
resampled_audio_test和resampled_audio_ref的采样率是否统一到了41100?如果不一致,MFCC的频率分辨率会有差异,也会干扰结果判断。
解决方案
1. 保留MFCC的时序特征
去掉对MFCC时间维度的均值计算,保留原始的二维MFCC矩阵,让DTW能发挥时序对齐的作用:
# 正确提取MFCC:保留时间序列 mfccsT = librosa.feature.mfcc(y=pre_emphasised_test, sr=41100, n_mfcc=13) mfccsR = librosa.feature.mfcc(y=pre_emphasised_ref, sr=41100, n_mfcc=13) # 转置成 (时间步, n_mfcc),符合DTW的输入习惯 mfccsT = mfccsT.T mfccsR = mfccsR.T
2. 统一标准化流程
用同一个Scaler拟合所有数据(或其中一个作为基准),再对两个MFCC做转换,保证特征分布一致:
# 合并两个MFCC的时间步数据来拟合scaler combined_mfccs = np.vstack([mfccsT, mfccsR]) scaler = StandardScaler() scaler.fit(combined_mfccs) # 分别转换两个MFCC normalized_mfccsT = scaler.transform(mfccsT) normalized_mfccsR = scaler.transform(mfccsR)
3. 优化DTW计算
使用更适合语音特征的距离度量(比如余弦距离),或者添加窗口约束避免过度对齐:
# 使用余弦距离作为DTW的元素距离 from scipy.spatial.distance import cosine dist, cost_matrix, acc_cost_matrix, path = dtw(normalized_mfccsT, normalized_mfccsR, dist=cosine) # 可选:添加窗口约束(只允许在±50%时间步内对齐,避免无效匹配) # dist, cost_matrix, acc_cost_matrix, path = dtw(normalized_mfccsT, normalized_mfccsR, dist=cosine, window_type="sakoechiba", window_size=min(len(mfccsT), len(mfccsR))//2)
4. 增强特征维度(可选)
添加MFCC的一阶、二阶差分,捕捉语音的动态变化趋势,提升相似度判断的准确性:
def extract_mfcc_features(y, sr): mfcc = librosa.feature.mfcc(y=y, sr=sr, n_mfcc=13) mfcc_delta = librosa.feature.delta(mfcc) mfcc_delta2 = librosa.feature.delta(mfcc, order=2) # 合并特征并转置为(时间步, 特征数) combined = np.vstack([mfcc, mfcc_delta, mfcc_delta2]).T return combined mfccsT = extract_mfcc_features(pre_emphasised_test, 41100) mfccsR = extract_mfcc_features(pre_emphasised_ref, 41100)
5. 统一预处理流程
确保两个音频的采样率、静音切割参数完全一致,避免预处理环节引入不必要的差异。
内容的提问来源于stack exchange,提问作者jey
相关产品推荐
相关产品推荐

