MF CC Python: совершенно другой результат: librosa vs python_speech_features vs tenorsflow.signal - PullRequest
3 голосов
/ 02 марта 2020

Я пытаюсь извлечь MF CC функции из аудио (WAV-файл), и я пробовал 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)

Ниже приведены графики:

librosa : enter image description here

python_speech_features : enter image description here

Я передал какие-либо параметры неправильно для этих двух методов? Почему здесь такая огромная разница?

Обновление: Я также попробовал реализацию tenorflow.signal, и вот результат:

enter image description here

Сам график совпадает с тем из librosa, но масштаб ближе к python_speech_features. (Обратите внимание, что здесь я вычислил 80 контейнеров с мелом и взял первые 13; если я выполню расчет только с 13 контейнерами, результат также будет выглядеть совершенно по-другому). Код ниже:

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

Я думаю, что мой вопрос: какой вывод ближе к тому, что MF CC на самом деле выглядит?

Ответы [ 2 ]

4 голосов
/ 02 марта 2020

Здесь есть как минимум два фактора, объясняющих, почему вы получаете разные результаты:

  1. Единого определения шкалы расплава не существует. Librosa реализовать двумя способами: Slaney и HTK . Другие пакеты могут и будут использовать другие определения, что приведет к другим результатам. При этом общая картина должна быть похожей. Это приводит нас ко второй проблеме ...
  2. python_speech_features по умолчанию устанавливает коэффициент энергии в качестве первого (индекс ноль) коэффициента (appendEnergy равен True по умолчанию), то есть, когда вы запрашиваете, например, 13 MF CC, вы фактически получаете 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)

spectrogram 1

Как видите, масштаб отличается, но в целом картина выглядит очень похожей. Обратите внимание, что мне нужно было убедиться, что количество параметров, передаваемых в модули, одинаково.

0 голосов
/ 31 марта 2020

Это такая вещь, которая не дает мне спать по ночам. Этот ответ является правильным (и чрезвычайно полезным!), Но не полным, потому что он не объясняет большую разницу между двумя подходами. Мой ответ добавляет существенные дополнительные детали, но все еще не дает точных совпадений.

То, что происходит, сложно, и лучше всего объяснить с помощью длинного блока кода, который сравнивает 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 также будет эмулировать, также имеет универсальную дельта-функцию, но все еще не имеет чистого, очевидного способа получения энергии.

enter image description here

...