Классификация аудио / звуков с помощью python

В данном посте приведу относительно простой способ классифицировать звукозаписи с помощью python. Как и для любой задачи классификации, в первую очередь понадобится из аудиозаписи извлечь фичи, для этого воспользуемся библиотекой librosa. Звук — весьма сложная структура, не спроста задача распознавания голоса решена по сути только гигантами вроде гугла, яндекса, да и то не идеально. Хоти они явно не ограничены в вычислительных ресурсах.
В общем примерная суть всех фич заключается в том, что звук — это спектрограммы, т.е. если все данные закидывать как фичи, то классификатору будет очень тяжело. Поэтому мы из различных спектрограмм будем брать только некоторые характеристики в виде среднего, дисперсии, минимальных, максимальных значений итд.

Подробнее о каждом спектре можно прочитать здесь: github.com/subho406/Audio-Feature-Extraction-using-Librosa/blob/master/Song%20Analysis.ipynb
Здесь же представлю упрощённую версию:

import librosa
import numpy as np
import librosa.display
import scipy
from scipy import stats

# функция вернет 72 фичи для аудиозаписи по пути wav_path
def get_base_features(wav_path):
    ff_list = []

    y, sr = librosa.load(wav_path, sr=None)

    y_harmonic, y_percussive = librosa.effects.hpss(y)

    tempo, beat_frames = librosa.beat.beat_track(y=y_harmonic, sr=sr)
    chroma = librosa.feature.chroma_cens(y=y_harmonic, sr=sr)
    mfccs = librosa.feature.mfcc(y=y_harmonic, sr=sr, n_mfcc=13)
    cent = librosa.feature.spectral_centroid(y=y, sr=sr)
    contrast = librosa.feature.spectral_contrast(y=y_harmonic, sr=sr)
    rolloff = librosa.feature.spectral_rolloff(y=y, sr=sr)
    zrate = librosa.feature.zero_crossing_rate(y_harmonic)

    chroma_mean = np.mean(chroma, axis=1)
    chroma_std = np.std(chroma, axis=1)

    for i in range(0, 12):
        ff_list.append(chroma_mean[i])
    for i in range(0, 12):
        ff_list.append(chroma_std[i])

    mfccs_mean = np.mean(mfccs, axis=1)
    mfccs_std = np.std(mfccs, axis=1)

    for i in range(0, 13):
        ff_list.append(mfccs_mean[i])
    for i in range(0, 13):
        ff_list.append(mfccs_std[i])

    cent_mean = np.mean(cent)
    cent_std = np.std(cent)
    cent_skew = scipy.stats.skew(cent, axis=1)[0]

    contrast_mean = np.mean(contrast,axis=1)
    contrast_std = np.std(contrast,axis=1)

    rolloff_mean=np.mean(rolloff)
    rolloff_std=np.std(rolloff)

    data = np.concatenate(([cent_mean, cent_std, cent_skew], 
                           contrast_mean, contrast_std, 
                           [rolloff_mean, rolloff_std, rolloff_std]), axis=0)
    ff_list += list(data)

    zrate_mean = np.mean(zrate)
    zrate_std = np.std(zrate)
    zrate_skew = scipy.stats.skew(zrate,axis=1)[0]

    ff_list += [zrate_mean, zrate_std, zrate_skew]

    ff_list.append(tempo)

    return ff_list

Далее для классификации можно использовать любой алгоритм градиентного бустинга, буть то lightgbm, xgboost или catboost.
Предположим, что в одной папке лежат все аудиозаписи из одного класса, а в другой папке аудиозаписи из второго класса. Прочитаем их, вычислим фичи и запустим обучение.

import glob
from catboost import CatBoostClassifier
from sklearn.model_selection import train_test_split

h_features = []
s_features = []
ii, jj = 0, 0

for f_path in glob.glob('../Training_Data/human/*.wav'):
    h_features.append(get_base_features(f_path))
    ii += 1
    if ii > 50:
        break
for f_path in glob.glob('../Training_Data/spoof/*.wav'):
    s_features.append(get_base_features(f_path))
    jj += 1
    if jj > 50:
        break


X_train, X_test, y_train, y_test = train_test_split(
                                        h_features+s_features,
                                        [1]*len(h_features) + [0]*len(s_features),
                                        test_size=0.25,
                                        random_state=42,
                                    )

clf = CatBoostClassifier(iterations=200)
clf.fit(X_train, y_train, eval_set=(X_test, y_test))

Стоит отметить, что почему-то библиотека librosa медленно читает файл. Поэтому предложу альтернативный метод из библиотеки scipy:

import scipy.io.wavfile
sr, y = wavfile.read("audio/some_file.wav")

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>