В данном посте приведу относительно простой способ классифицировать звукозаписи с помощью 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")
Thanks!!