MFCC Python:结果与librosa、python_speech_features和tensorflow.signal完全不同

myss37ts  于 2022-12-19  发布在  Python
关注(0)|答案(3)|浏览(205)

我试图从音频(.wav文件)中提取MFCC功能,我已经尝试了python_speech_featureslibrosa,但他们给出了完全不同的结果:

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语音功能

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

**更新:**我也尝试过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的实际外观?

bnl4lu3b

bnl4lu3b1#

这里至少有两个因素在起作用,可以解释为什么你会得到不同的结果:
1.熔点刻度没有单一的定义。Librosa有两种实现方式:SlaneyHTK。其他软件包可能也将使用不同的定义,导致不同的结果。话虽如此,总体情况应该是相似的。这就引出了第二个问题...

  1. python_speech_features默认将能量作为第一(索引零)系数(appendEnergy默认为True),这意味着当您请求例如13MFCC时,您实际上得到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)

正如你所看到的规模是不同的,但整体图片看起来真的很相似。注意,我必须确保传递给模块的一些参数是相同的。

ao218c7q

ao218c7q2#

This answer是正确的(而且非常有用!),但并不完整,因为它没有解释两种方法之间的巨大差异。我的答案增加了一个重要的额外细节,但仍然没有实现精确匹配。
发生的事情很复杂,最好用下面一段冗长的代码来解释,它将librosapython_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谱图,获取它的nautral log,并使用它而不是原始样本作为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函数,但仍然没有干净,明显的方式来获得能量。

mo49yndu

mo49yndu3#

关于与tf.signal的区别,对于任何仍在寻找这个的人:前段时间我也遇到过类似的问题:将librosa的 *mel滤波器组/mel谱图 * 匹配到tensorflow 实现。解决方案是对谱图使用不同的窗口方法,并将librosa的 mel 矩阵作为常量Tensor。请参见此处和此处。

相关问题