Saltar al contenido

MFCC Python: resultado completamente diferente de librosa vs python_speech_features vs tensorflow.signal

Solución:

Hay al menos dos factores en juego aquí que explican por qué obtiene resultados diferentes:

  1. No existe una definición única de la escala mel. Librosa implementar de dos formas: Slaney y HTK. Otros paquetes pueden y voluntad utilizar definiciones diferentes, lo que lleva a resultados diferentes. Dicho esto, el panorama general debería ser similar. Eso nos lleva al segundo tema …
  2. python_speech_features por defecto pone la energía como primer coeficiente (índice cero) (appendEnergy es True por defecto), lo que significa que cuando pides, por ejemplo, 13 MFCC, efectivamente obtienes 12 + 1.

En otras palabras, no estabas comparando 13 librosa frente a 13 python_speech_features coeficientes, sino 13 frente a 12. La energía puede ser de diferente magnitud y, por lo tanto, producir una imagen bastante diferente debido a la diferente escala de colores.

Ahora demostraré cómo ambos módulos pueden producir resultados similares:

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)

espectrograma 1

Como puede ver, la escala es diferente, pero la imagen general se ve muy similar. Tenga en cuenta que tenía que asegurarme de que varios parámetros pasados ​​a los módulos sean los mismos.

Este es el tipo de cosas que me mantienen despierto por la noche. Esta respuesta es correcta (¡y extremadamente útil!) Pero no completa, porque no explica la amplia variación entre los dos enfoques. Mi respuesta agrega un detalle adicional significativo, pero aún no logra coincidencias exactas.

Lo que está sucediendo es complicado y se explica mejor con un largo bloque de código a continuación que compara librosa y python_speech_features a otro paquete más, torchaudio.

  • Primero, tenga en cuenta que la implementación de torchaudio tiene un argumento, log_mels cuyo valor predeterminado (False) imita la implementación de librosa, pero si se establece True imitará python_speech_features. En ambos casos, los resultados aún no son exactos, pero las similitudes son obvias.

  • En segundo lugar, si se sumerge en el código de la implementación de torchaudio, verá la nota de que el valor predeterminado NO es una “implementación de libro de texto” (las palabras de torchaudio, pero confío en ellas), sino que se proporciona para compatibilidad con Librosa; la operación clave en torchaudio que cambia de una a otra es:

    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)
  • En tercer lugar, se estará preguntando razonablemente si puede obligar a los librosa a actuar correctamente. La respuesta es sí (o al menos, “lo parece”) tomando el espectrograma mel directamente, tomando el registro natural del mismo y usándolo, en lugar de las muestras sin procesar, como entrada para la función librosa mfcc. Consulte el código a continuación para obtener más detalles.

  • Por último, tenga algo de precaución y si usa este código, examine lo que sucede cuando observa diferentes características. La característica 0 todavía tiene graves compensaciones inexplicables, y las características más altas tienden a alejarse unas de otras. Esto puede ser algo tan simple como diferentes implementaciones bajo el capó o constantes de estabilidad numérica ligeramente diferentes, o puede ser algo que se puede arreglar con un ajuste fino, como una elección de relleno o quizás una referencia en una conversión de decibelios en algún lugar. Realmente no lo se.

Aquí hay un código de muestra:

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()

Honestamente, ninguna de estas implementaciones es satisfactoria:

  • Python_speech_features adopta el enfoque inexplicablemente extraño de reemplazar la característica 0 con energía en lugar de aumentar con ella, y no tiene una implementación delta de uso común

  • Librosa no es estándar de forma predeterminada sin advertencia, y carece de una forma obvia de aumentar con energía, pero tiene una función delta altamente competente en otras partes de la biblioteca.

  • Torchaudio emulará cualquiera de los dos, también tiene una función delta versátil, pero aún no tiene una forma clara y obvia de obtener energía.

ingrese la descripción de la imagen aquí

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *