Если музыка — это место, то джаз — это город, фолк — это пустыня, рок — это дорога, классика — это храм.

— Вера Назарян

Музыка является неотъемлемой частью нашей жизни, и компании, занимающиеся потоковой передачей музыки, такие как Spotify, в настоящее время используют машинное обучение для создания рекомендаций для нас. Музыкальные жанры играют большую роль в создании этих рекомендаций. В этой истории мы построим модель классификации музыкальных треков по соответствующим жанрам. В этом руководстве мы будем использовать librosa, библиотеку для анализа музыки и звука. Мы также будем использовать GTZAN Dataset от Kaggle для обучения нашего классификатора.

Импорт библиотек

import os
import pandas as pd
import numpy as np
import IPython
import librosa
import librosa.display
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn import preprocessing
from sklearn.preprocessing import minmax_scale
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score

Разные жанры

Давайте посмотрим весь список жанров, присутствующих в наборе данных.

general_path = './Data'
print(list(os.listdir('Data/genres_original/')))

Запись одного аудио

Мы возьмем один аудиофайл для исследования.

file = './Data/genres_original/classical/classical.00050.wav'
signal , sr = librosa.load(file , sr = 22050)

Визуализация сигналов

Давайте используем волновой график для визуализации аудиофайла или сигнала.

plt.figure(figsize=(15,5))
librosa.display.waveplot(signal , sr = sr)
plt.xlabel('Time')
plt.ylabel('Amplitude')
plt.title("Classical music signal")
plt.show()

Воспроизведение аудио

Чтобы воспроизвести звук в Jupyter Notebook, мы будем использовать следующий код.

IPython.display.Audio(signal, rate=sr)

Преобразование Фурье

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

n_fft = 2048
hop_length = 512
D = np.abs(librosa.stft(signal, n_fft = n_fft, hop_length = hop_length))
plt.figure(figsize = (15, 5))
plt.plot(D)
plt.title('Fourier Transform')
plt.show()

Спектрограмма

Спектрограмма представляет собой представление громкости сигнала во времени на различных частотах, присутствующих в определенной волновой форме. Давайте построим спектрограмму для нашего аудиофайла.

DB = librosa.amplitude_to_db(D, ref = np.max)
plt.figure(figsize = (15, 5))
librosa.display.specshow(DB, sr = sr, hop_length = hop_length, x_axis = 'time', y_axis = 'log', cmap = 'cool')
plt.colorbar()
plt.title('Spectrogram')
plt.show()

Гармоники и восприятие

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

a,b = librosa.effects.hpss(signal)
plt.figure(figsize = (15, 5))
plt.plot(a, color = '#FF5E33');
plt.plot(b, color = '#FFD433');
plt.title('Harmonics and Perceptrual')
plt.show()

Спектральный центроид

Спектральный центроид указывает, где расположен центр масс спектра.

spectral_centroids = librosa.feature.spectral_centroid(signal, sr=sr)[0]
plt.figure(figsize=(15, 5))
frames = range(len(spectral_centroids))
t = librosa.frames_to_time(frames)
librosa.display.waveplot(signal, sr=sr, alpha=0.4)
plt.plot(t, minmax_scale(spectral_centroids,axis=0), color='r')
plt.title('Spectral Centroid')
plt.show()

Хромограмма

Мы создадим хромограмму, в которой весь спектр будет спроецирован на 12 бинов, представляющих 12 различных полутонов музыкальной октавы.

hop_length = 5000
chromagram = librosa.feature.chroma_stft(signal, sr=sr, hop_length=hop_length)
plt.figure(figsize=(15, 5))
librosa.display.specshow(chromagram, x_axis='time', y_axis='chroma', hop_length=hop_length, cmap='YlGnBu')
plt.title('Chromogram')
plt.show()

30-секундные функции

Файл features_30_sec.csv содержит звуковые характеристики продолжительностью 30 секунд. Мы будем использовать его для изучения ударов в минуту.

data = pd.read_csv('./Data/features_30_sec.csv')
data.head()

Ударов в минуту

Давайте посмотрим количество ударов в минуту для разных жанров.

x = data[["label", "tempo"]]
f, ax = plt.subplots(figsize=(15, 5));
sns.boxplot(x = "label", y = "tempo", data = x, palette = 'husl');
plt.title('BPM for Genres', fontsize = 20)
plt.xticks(fontsize = 14)
plt.yticks(fontsize = 10);
plt.xlabel("Genre", fontsize = 15)
plt.ylabel("BPM", fontsize = 15)
plt.show()

Загрузка данных

Файл features_3_sec.csvсодержит звуковые характеристики продолжительностью 3 секунды. Мы будем использовать его для обучения нашей модели.

data = pd.read_csv('./Data/features_3_sec.csv')
data = data.iloc[0:, 1:]

Предварительная обработка данных

Мы предварительно обработаем данные, чтобы сделать их подходящими для нашей модели. Для этой цели мы будем использовать MinMaxScaler.

y = data['label']
X = data.loc[:, data.columns != 'label']
cols = X.columns
min_max_scaler = preprocessing.MinMaxScaler()
np_scaled = min_max_scaler.fit_transform(X)
X = pd.DataFrame(np_scaled, columns = cols)

Разделение данных

Давайте разделим данные для обучения и тестирования.

X_train, X_test, y_train, y_test = train_test_split(X, y)

Создание модели и прогнозирование

Пришло время создать нашу модель. Мы будем использовать классификатор случайного леса для построения модели. Мы подгоним модель, используя данные обучения, и предскажем данные тестирования. Точность нашей модели оказалась 81,38 %, и это здорово!

model = RandomForestClassifier(n_estimators=1000, max_depth=10, random_state=0)
model.fit(X_train, y_train)
preds = model.predict(X_test)
print('Accuracy:', round(accuracy_score(y_test, preds)))

Мы успешно построили модель классификации музыкальных жанров. Если вы нашли это руководство полезным, нажмите «Подписаться», чтобы присоединиться к сообществу.