Категория статьи: Нейронные сети
Проект: Shazam своими руками
Подготовка данных для обучения модели нейронной сети
Снова, всем привет!
В этой статье будет описан процесс подготовки данных, которые буду подавать на вход модели при обучении.
Все загруженные mp3 файлы нарежем на 300 частей, потом с помощью библиотеки librosa, сформируем mel-спектрограмму каждого кусочка и сохраним на диске. Иерархия папок будет соответствовать метке класса определенной композиции.
# Директория с mp3 файлами
mp3_dir = 'mp3'
# Директория с файлами для обучения модели
train_dir = 'train'
# Директория с файлами для проверки модели
val_dir = 'val'
# Создаем директории
create_dir_if_not_exists(mp3_dir, True)
create_dir_if_not_exists(train_dir, True)
create_dir_if_not_exists(val_dir, True)
Гиперпараметры
Выделим некоторые параметры, которые необходимы для формирования mel-спектрограммы в отдельный класс и создадим объект этого класса.
# Класс гиперпараметров для работы со звуком
class LibROSA_HP():
def __init__(self):
self.sr = 22050
self.n_fft = 2048
self.win_length = self.n_fft
self.hop_length = self.win_length // 4
self.n_mels = 128 * 4
self.n_iter = 3
self.n_timeframe = 80
self.n_sec = 2
self.part_count = 300
# Создаем объект гиперпараметров
lhp = LibROSA_HP()
Параметры класса LibROSA_HP
Нарезка mp3 файла на обучающую и проверочную выборки
import warnings
# отключаем вывод предупреждений
warnings.simplefilter("ignore")
i = 0
# Таймер для расчета общего времени выполнения формирования нарезок файлов
t1 = MeasuringRunTime.Timer()
# Таймер для расчета времени выполнения одной итерации
t2 = MeasuringRunTime.Timer()
print("СТАРТ")
# Получаем список файлов
mp3s = os.listdir(mp3_dir)
mp3s = sorted(mp3s)
# Фильтруем файлы от системных
mp3s = list(filter(lambda x: x[0] != '.', mp3s))
# Отбираем файлы только с расширение mp3
mp3s = list(filter(lambda x: x.split('.')[-1] == 'mp3', mp3s))
count = len(mp3s)
for mp3 in mp3s:
t2.Start()
label = int(mp3.split('.')[0])
# Создаем директории с именем метки класса для каждого mp3 файла
train_cl_full_path = create_labeled_dir(train_dir, label)
val_cl_full_path = create_labeled_dir(val_dir, label)
full_path = os.path.join(mp3_dir, mp3)
# Загружаем файл mp3
X, sr = librosa.load(full_path)
part = int(sr * lhp.n_sec)
n = len(X) - part + 1
step = n // lhp.part_count if n // lhp.part_count < sr else sr
# создаем файлы mel-спектрограмм нарезанных кусочков
create_mel_files(X, sr, 0, n, step, part, train_cl_full_path, label)
create_mel_files(X, sr, step // 2, n, step, part, val_cl_full_path, label)
i += 1
print(f"Шаг {i} / {count} - {t2.Stop()} сек.")
print(f"Общее время выполнения {t1.Stop()} сек. ( ~ {int(t1.Stop() // 60)} мин. )")
Скажу сразу, это не быстрый процесс, одна итерация, т.е. 1 mp3 файл нарезается примерно 25 секунд!!!
На рисунке ниже отображено как нарезается mp3 файл. step рассчитывается исходя из длины файла и количества частей на которые он нарезается. Для проверочной выборки первый кусочек начинается с позиции step / 2, таким образом кусочки пересекаются между собой, но только частично. А обучающая и проверочная выборки абсолютно отличаются между собой.
Осталось рассмотреть еще одну функцию create_mel_files, собственно сохранение нарезанных кусочков.
def create_mel_files(X, sr, start, n, step, part, parent_dir, label):
k = 0
for i in range(start, n, step):
# Формируем mel-спектрограмму
mel_spec = librosa.feature.melspectrogram(y=X[i:i + part],
sr=sr,
n_fft=lhp.n_fft,
hop_length=lhp.hop_length,
win_length=lhp.win_length,
n_mels=lhp.n_mels)
# Переводим энергию сигнала в децибелы
mel_log = librosa.power_to_db(mel_spec)
# Формируем имя файла
filename = str(k).zfill(max_len_filename) + ".pickle"
full_filename = os.path.join(parent_dir, filename)
# Сохраняем файл на диск
dumppickle(full_filename, {'X': mel_log[:, :lhp.n_timeframe], 'y': label})
k += 1
Функция dumppickle сохраняет любой объект в файл.
В нашем случае объектом будет справочник, где в значении 'X' будет храниться матрица размерностью (lhp.n_mels, lhp.n_timeframe), а в значении 'y' номер музыкальной композиции.