Это такая вещь, которая не дает мне спать по ночам. Этот ответ является правильным (и чрезвычайно полезным!), Но не полным, потому что он не объясняет большую разницу между двумя подходами. Мой ответ добавляет существенные дополнительные детали, но все еще не дает точных совпадений.
То, что происходит, сложно, и лучше всего объяснить с помощью длинного блока кода, который сравнивает librosa
и python_speech_features
с еще одним пакетом torchaudio
.
Во-первых, обратите внимание, что реализация torchaudio имеет аргумент log_mels
, значение по умолчанию (False) которого имитирует реализацию librosa, но если установлено значение True, то будет mimi c 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)
В-третьих, вы будете удивляться вполне разумно если вы можете заставить либросу действовать правильно. Ответ - да (или, по крайней мере, «Похоже, что это так»), взяв непосредственно спектрограмму mel, взяв ее логарифмический журнал и используя ее, а не необработанные образцы, в качестве входных данных для librosa mf cc функция. Смотрите код ниже для деталей.
Наконец, будьте осторожны, и , если вы используете этот код, изучите, что происходит, когда вы смотрите на различные функции . 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-й элемент энергией, а не увеличивая его, и не имеет обычно используемой дельта-реализации
Librosa является нестандартной по умолчанию, без предупреждений и не содержит очевидный способ дополнить энергией, но имеет высоко компетентную дельта-функцию в других местах библиотеки.
Torchaudio также будет эмулировать, также имеет универсальную дельта-функцию, но все еще не имеет чистого, очевидного способа получения энергии.