【问题标题】:MFCC Python: completely different result from librosa vs python_speech_features vs tensorflow.signalMFCC Python:与 librosa vs python_speech_features vs tensorflow.signal 完全不同的结果
【发布时间】:2020-06-14 23:06:04
【问题描述】:

我正在尝试从音频(.wav 文件)中提取 MFCC 特征,我尝试过 python_speech_features 和 librosa,但它们给出的结果完全不同:

audio, sr = librosa.load(file, sr=None)

# librosa
hop_length = int(sr/100)
n_fft = int(sr/40)
features_librosa = librosa.feature.mfcc(audio, sr, n_mfcc=13, hop_length=hop_length, n_fft=n_fft)

# psf
features_psf = mfcc(audio, sr, numcep=13, winlen=0.025, winstep=0.01)

以下是地块:

图书馆:

python_speech_features:

我是否为这两种方法传递了错误的参数?为什么这里有这么大的差异?

更新:我也尝试过 tensorflow.signal 实现,结果如下:

情节本身更接近 librosa 的情节,但比例更接近 python_speech_features。 (请注意,这里我计算了 80 个 mel bin 并取了前 13 个;如果我只用 13 个 bin 进行计算,结果看起来也完全不同)。代码如下:

stfts = tf.signal.stft(audio, frame_length=n_fft, frame_step=hop_length, fft_length=512)
spectrograms = tf.abs(stfts)

num_spectrogram_bins = stfts.shape[-1]
lower_edge_hertz, upper_edge_hertz, num_mel_bins = 80.0, 7600.0, 80
linear_to_mel_weight_matrix = tf.signal.linear_to_mel_weight_matrix(
    num_mel_bins, num_spectrogram_bins, sr, lower_edge_hertz, upper_edge_hertz)
mel_spectrograms = tf.tensordot(spectrograms, linear_to_mel_weight_matrix, 1)
mel_spectrograms.set_shape(spectrograms.shape[:-1].concatenate(linear_to_mel_weight_matrix.shape[-1:]))

log_mel_spectrograms = tf.math.log(mel_spectrograms + 1e-6)
features_tf = tf.signal.mfccs_from_log_mel_spectrograms(log_mel_spectrograms)[..., :13]
features_tf = np.array(features_tf).T

我想我的问题是:哪个输出更接近 MFCC 的实际样子?

【问题讨论】:

  • 有趣。将采样率作为 kwarg 传递给 psf 版本,即samplerate=sr,有什么不同吗?或者更改 librosa 版本中的dct_type?
  • @Hendrik psf 版本已经有 sr 作为输入。就dct_type 而言,当我设置为 3 时会有一些变化,但与 psf 输出仍然相差甚远(1 和 2 几乎相同)。
  • @Hendrik 也尝试过 tensorflow,它更接近 librosa 但规模如此不同。
  • "将采样率作为 kwarg 传递给 psf 版本,即samplerate=sr,有什么不同吗?" -> 我的意思是,你将它作为位置参数传递,但它是一个关键字参数。不确定,如果将它作为 kwarg 参数传递在这里会有所不同,但我会坚持(显式)API。
  • @Hendrik 不,没有区别。

标签: python tensorflow audio librosa mfcc


【解决方案1】:

这里至少有两个因素可以解释为什么你会得到不同的结果:

  1. mel 标度没有单一的定义。 Librosa 实现两种方式:Slaney 和 HTK。其他软件包可能也将使用不同的定义,从而导致不同的结果。话虽如此,整体情况应该是相似的。这就引出了第二个问题……
  2. python_speech_features 默认将能量作为第一个(索引零)系数(appendEnergy 默认为 True),这意味着当您要求例如13 MFCC,你实际上得到了 12 + 1。

换句话说,您不是在比较 13 个librosa 与 13 个python_speech_features 系数,而是比较 13 与 12。能量的大小可能不同,因此由于色阶不同,会产生完全不同的图像。

我现在将演示这两个模块如何产生相似的结果:

import librosa
import python_speech_features
import matplotlib.pyplot as plt
from scipy.signal.windows import hann
import seaborn as sns

n_mfcc = 13
n_mels = 40
n_fft = 512 
hop_length = 160
fmin = 0
fmax = None
sr = 16000
y, sr = librosa.load(librosa.util.example_audio_file(), sr=sr, duration=5,offset=30)

mfcc_librosa = librosa.feature.mfcc(y=y, sr=sr, n_fft=n_fft,
                                    n_mfcc=n_mfcc, n_mels=n_mels,
                                    hop_length=hop_length,
                                    fmin=fmin, fmax=fmax, htk=False)

mfcc_speech = python_speech_features.mfcc(signal=y, samplerate=sr, winlen=n_fft / sr, winstep=hop_length / sr,
                                          numcep=n_mfcc, nfilt=n_mels, nfft=n_fft, lowfreq=fmin, highfreq=fmax,
                                          preemph=0.0, ceplifter=0, appendEnergy=False, winfunc=hann)

如您所见,比例不同,但整体画面看起来非常相似。请注意,我必须确保传递给模块的参数数量是相同的。

【讨论】:

  • 感谢您对此进行调查!我尝试将所有参数一一添加,以查看导致差异的原因,发现是appendEnergy,添加后,情节看起来非常相似。就规模而言,我想如果我们在那之后再做一个缩放,那也没什么大不了的。
  • @TYZ 是的。话虽如此,考虑到你们正在做的事情,我会考虑远远超出 MFCC。
  • 您对其他选项有什么建议吗?我目前正在阅读 fairseq 的 wav2vec,但肯定会接受更多建议。
  • @TYZ 因为和原来的问题不相干,我会直接联系你。
【解决方案2】:

这是让我夜不能寐的事情。 This answer 是正确的(并且非常有用!)但并不完整,因为它不能解释两种方法之间的巨大差异。我的回答增加了重要的额外细节,但仍然没有达到完全匹配。

发生的事情很复杂,最好用下面的长代码块来解释,它将librosa 和python_speech_features 与另一个包torchaudio 进行比较。

  • 首先,请注意 torchaudio 的实现有一个参数 log_mels,其默认值 (False) 模仿 librosa 实现,但如果设置为 True 将模仿 python_speech_features。在这两种情况下,结果仍然不准确,但相似之处是显而易见的。

  • 其次,如果您深入研究torchaudio 的实现代码,您会看到默认不是“教科书实现”(torchaudio 的话,但我相信它们),而是为 Librosa 兼容性而提供的; torchaudio 中从一个切换到另一个的关键操作是:

    mel_specgram = self.MelSpectrogram(waveform)
    if self.log_mels:
        log_offset = 1e-6
        mel_specgram = torch.log(mel_specgram + log_offset)
    else:
        mel_specgram = self.amplitude_to_DB(mel_specgram)
  • 第三,如果你能强制 librosa 正确行动,你会很合理地想知道。答案是肯定的(或者至少是“看起来像”),方法是直接获取 mel 频谱图,获取它的自然对数,然后使用它而不是原始样本作为 librosa mfcc 函数的输入。有关详细信息,请参阅下面的代码。

  • 最后,请注意,如果您使用此代码,请检查查看不同功能时会发生什么。第 0 个特征仍然有严重的无法解释的偏移,并且更高的特征往往会相互偏离。这可能是一些简单的东西,比如引擎盖下的不同实现或稍微不同的数值稳定性常数,或者它可能是可以通过微调来修复的东西,比如填充的选择或某处分贝转换中的参考。我真的不知道。

这里是一些示例代码:

import librosa
import python_speech_features
import matplotlib.pyplot as plt
from scipy.signal.windows import hann
import torchaudio.transforms
import torch

n_mfcc = 13
n_mels = 40
n_fft = 512 
hop_length = 160
fmin = 0
fmax = None
sr = 16000

melkwargs={"n_fft" : n_fft, "n_mels" : n_mels, "hop_length":hop_length, "f_min" : fmin, "f_max" : fmax}

y, sr = librosa.load(librosa.util.example_audio_file(), sr=sr, duration=5,offset=30)

# Default librosa with db mel scale 
mfcc_lib_db = librosa.feature.mfcc(y=y, sr=sr, n_fft=n_fft,
                                    n_mfcc=n_mfcc, n_mels=n_mels,
                                    hop_length=hop_length,
                                    fmin=fmin, fmax=fmax, htk=False)

# Nearly identical to above
# mfcc_lib_db = librosa.feature.mfcc(S=librosa.power_to_db(S), n_mfcc=n_mfcc, htk=False)

# Modified librosa with log mel scale (helper)
S = librosa.feature.melspectrogram(y=y, sr=sr, n_mels=n_mels, fmin=fmin, 
                                    fmax=fmax, hop_length=hop_length)

# Modified librosa with log mel scale
mfcc_lib_log = librosa.feature.mfcc(S=np.log(S+1e-6), n_mfcc=n_mfcc, htk=False)

# Python_speech_features 
mfcc_speech = python_speech_features.mfcc(signal=y, samplerate=sr, winlen=n_fft / sr, winstep=hop_length / sr,
                                          numcep=n_mfcc, nfilt=n_mels, nfft=n_fft, lowfreq=fmin, highfreq=fmax,
                                          preemph=0.0, ceplifter=0, appendEnergy=False, winfunc=hann)

# Torchaudio 'textbook' log mel scale 
mfcc_torch_log = torchaudio.transforms.MFCC(sample_rate=sr, n_mfcc=n_mfcc, 
                                            dct_type=2, norm='ortho', log_mels=True, 
                                            melkwargs=melkwargs)(torch.from_numpy(y))

# Torchaudio 'librosa compatible' default dB mel scale 
mfcc_torch_db = torchaudio.transforms.MFCC(sample_rate=sr, n_mfcc=n_mfcc, 
                                           dct_type=2, norm='ortho', log_mels=False, 
                                           melkwargs=melkwargs)(torch.from_numpy(y))

feature = 1 # <-------- Play with this!!
plt.subplot(2, 1, 1)

plt.plot(mfcc_lib_log.T[:,feature], 'k')
plt.plot(mfcc_lib_db.T[:,feature], 'b')
plt.plot(mfcc_speech[:,feature], 'r')
plt.plot(mfcc_torch_log.T[:,feature], 'c')
plt.plot(mfcc_torch_db.T[:,feature], 'g')
plt.grid()

plt.subplot(2, 2, 3)
plt.plot(mfcc_lib_log.T[:,feature], 'k')
plt.plot(mfcc_torch_log.T[:,feature], 'c')
plt.plot(mfcc_speech[:,feature], 'r')
plt.grid()

plt.subplot(2, 2, 4)
plt.plot(mfcc_lib_db.T[:,feature], 'b')
plt.plot(mfcc_torch_db.T[:,feature], 'g')
plt.grid()

老实说,这些实现都不令人满意:

  • Python_speech_features 采用了一种莫名其妙的奇怪方法,即用能量代替第 0 个特征而不是用它进行增强,并且没有常用的 delta 实现

  • Librosa 在默认情况下是非标准的,没有任何警告,并且缺乏一种明显的方式来增加能量,但在库的其他地方具有高度称职的 delta 函数。

  • Torchaudio 也可以效仿,也有一个通用的 delta 函数,但仍然没有干净、明显的方式来获取能量。

【讨论】:

  • 感谢您的付出! +1
猜你喜欢
  • 2018-04-13
  • 2020-06-08
  • 2021-07-25
  • 1970-01-01
  • 1970-01-01
  • 2016-12-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多