Генерация музыкальных треков с помощью нейросети

XXVI Международный конкурс научно-исследовательских и творческих работ учащихся
Старт в науке

Генерация музыкальных треков с помощью нейросети

Титов Т.И. 1
1Физтех-лицей им. П.Л. Капицы
Мерзляков А.В. 1
1Физтех-лицей им. П.Л. Капицы
Автор работы награжден дипломом победителя II степени
Текст работы размещён без изображений и формул.
Полная версия работы доступна во вкладке "Файлы работы" в формате PDF

Введение

Цель

Разработать собственную нейронную сеть, способную генерировать MIDI-треки, и обучить ее создавать музыкальные композиции.

Назначение

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

Постановка проблемы

Классические методы кодирования входных данных для нейронных сетей, применяемые при генерации музыкальных MIDI-треков, а также классические подходы с использованием популярных библиотек (таких как TensorFlow и др.) не достаточны для получения высокого качества результата. Например: генерация интересных, разнообразных, запоминающихся мелодий с плавным голосоведением.

Требуется разработать инновационный метод кодирования данных, а также предложить собственную реализацию различных архитектур нейросетей, чтобы эффективно их использовать в составе более сложных моделей генерации музыки, таких как seq2seq. Важной частью решения проблемы является условие: не прибегать к таким сложным архитектурам нейросетей, как Transformer, так как подобные архитектуры очень сложны в обучении и требуют больших вычислительных мощностей.

Актуальность

Актуальность данного проекта заключается в нескольких ключевых аспектах:

  1. Развитие музыкальных технологий: с каждым годом развивается индустрия музыкальных технологий, и автоматизация создания музыки становится важным направлением. Генерация MIDI-файлов с помощью алгоритмов открывает новые возможности как для профессиональных музыкантов, так и для любителей, позволяя создавать музыку быстрее и с минимальными усилиями.

  2. Использование машинного обучения: современные алгоритмы на основе машинного обучения и искусственного интеллекта могут эффективно генерировать музыкальные композиции, что приводит к новому уровню творчества и инноваций в музыке. Генерация MIDI-файлов с использованием этих технологий помогает создавать уникальные произведения, которые могут быть использованы в различных музыкальных жанрах.

  3. Спрос на музыкальный контент: в условиях роста популярности стриминговых платформ, видео и аудиопрограмм востребованность контента продолжает расти. Генерация MIDI-файлов дает возможность создавать музыку, которая может быть использована в различных проектах, таких как видеоигры, фильмы, рекламные ролики и другие виды медиа-продукции.

Новизна

Проект предлагает инновационный метод генерации музыкальных MIDI‑треков, обеспечивающий качество результата, превосходящее как классические методы кодирования входных данных (кодирование MIDI-событий), так и традиционные архитектуры нейросетей.

Анализ аналогов на рынке

Место

Компания

Связанная мелодия

Сложная интересная мелодия

Бесплатная утилита

Выбор тональности

Широкий выбор длины трека

Удобный интерфейс

Разнообразный ритм

Выбор музыкальных инструментов

Много-

голосие

Полифония

Создание нотной партитуры

1

MN3F

+-

+

+

-

+

+

+

+

+

+

+

2

MIDI GEN 1.0

-

-

+

+

+

+

+

+

-

-

-

3

dopeloop

+

-

-

+

-

+

+

+

-

-

-

4

MIDI Generation Studio

-

-

+

-

-

-

-

-

-

-

-

Хотелось бы отметить, что связанная мелодия получилась далеко не у всех. В частности, связанность присутствует только dopeloop. Но dopeloop специализируется на генерации мелодий, максимальная длина которых не превышает 64 нот.

Генератор MIDI Generation Studio вообще выдает MIDI-файл, в котором содержится только одна очень короткая нота.

У MIDI GEN 1.0 генератор работает не намного лучше, чем у MIDI Generation Studio. Он выдает абсолютно не связанный между собой набор нот разной длины.

Таким образом, услышать мелодию от генераторов конкурентов можем только с оговоркой, у dopeloop.

Также хотелось бы упомянуть успешный проект Midi Composer, но к сожалению он не подходит нам по критериям оценки, так как он работает на базе архитектуры нейросети Transformer.

Этапы проектирования

Создание MidiNeuro

Сбор датасета: скачивание 20’000 MIDI-файлов.

Обучение нейросети: решение проблемы с затуханием и взрывом градиента, с применением L1 и L2 регуляции.

Вывод: отдельно высоты нот не несут в себе никакого семантического смысла, следовательно началась разработка нового метода обучения нейросети.

Создание MN2F

Идея: группировать ноты по парам и представлять это как слова.

Реализация Word2Vec: разработка CBOW (Continuous Bag Of Words) нейросети.

Отказ от старого датасета: использование датастеа MAESTRO V3.0.0.

Разработка 8 скриптов на Python для преобразования MIDI-файлов в нужные форматы - для подачи на вход и на выход CBOW и основной MidiNeuro2 на базе архитектуры RNN.

Приобретение видеокарты NVIDIA GeForce GT 1030 с поддержкой CUDA (Compute Unified Device Architecture).

Переработка кодовой базы на PyTorch для того, чтобы использовать возможности видеокарты: возможность вычисления на CUDA ядрах дало ускорение в 80 раз.

Создание MN3F

Выяснилось, что из-за того, что в датасете MAESTRO V3.0.0 пианисты играют двумя руками верхний и нижний голос, нейросеть начинает в своих сочинениях резко переходить от нижнего голоса к верхнему. Так как, моя нейросеть способна обрабатывать только 1 голос, она слушала, как пианист играет двумя руками, в разложенном виде. То есть, нейросеть слушала по очереди то нижний голос, то верхний.

Для того, чтобы решить эту проблему, я создал специальный ритм, который каждый 2 соседние ноты воспроизводит одновременно. Это помогло, но все же нейросети было трудно уловить зависимости между нотами, которые расположены в таком порядке.

Из-за вышеописанных проблем пришлось отказаться от датасета MAESTRO V3.0.0. Было принято решение создать свой датасет. В этом мне помогла профессиональный композитор, член Союза композиторов России и Москвы, Суфиярова Диана Александровна. Вместе мы записали более 400 одноголосных MIDI-треков с плавным голосоведением. Далее я обучил нейросеть на собственном датасете. Теперь сочинения нейросети стали звучать гораздо лучше. График ошибки тоже стал лучше. В отличие от предыдущих графиков, теперь в общей тенденции прослеживается явное падения ошибки. В среднем функция ошибки MSE теперь составляет примерно 0.5, а функция точности RMSE примерно 0.4.

Концепция моей нейросети описана более подробно в теоретической и практической части.

Методы исследования

  1. Анализ - в данном проекте это математический анализ поведения функций при изменении входных параметров.

  2. Моделирование - строим математическую модель нейросети (задаем структуру, функцию потерь, метод оптимизации), наблюдаем, как нейросеть обрабатывает входные данные, изменяем глобальные параметры обучения и смотрим, как это влияет на качество предсказаний, корректируем параметры и изучаем поведение нейросети.

  3. Обобщение - обобщаем результаты тестирования на основе показателей точности (смотрим, насколько хорошо модель обобщает знания на тестовых данных).

  4. Формализация - используем для формулирования алгоритмов обучения и четкого определения метрик качества модели (формализация теоретических основ, архитектуры нейросети, процесса обучения, метрик и результатов), выводим с все формулы, необходимые для написания данной нейросети.

  5. Эксперимент - экспериментируем с архитектурой нейросети, с выбором функции потерь, с гиперпараметрами, с различными методами предобработки данных, с методами регуляризации, с метриками оценки модели, с алгоритмами оптимизации.

Средства разработки

В проекте использовались современные технологии и языки: язык программирования Python, CUDA1.

Библиотеки для Python: PyTorch, Midiutil, Mido, Pickle, Matplotlib, Keyboard.

Задачи

Для реализации поставленной цели необходимо было решить следующие задачи:

  1. Задача №1 - Разработка модели нейронной сети, которая подходит под данную задачу

  2. Задача №2 - Выбор языка программирования и библиотек

  3. Задача №3 - Реализация модели нейронной сети

  4. Задача №4 - Обучение нейронной сети создавать музыкальные MIDI-треки

Структура проекта

Вся система состоит из 2-х частей - frontend и backend:

  • Backend - это серверная часть, которая будет обрабатывать запросы от frontend части и отвечать на них.

  • Frontend - это Telegram бот, позволяющий взаимодействовать с нейросетью.

Описание функционала конечного продукта

Конечным продуктом является нейросеть, доступная через Telegram бот, которая может генерировать интересные, запоминающиеся мелодические темы.

Описание алгоритмов, структур данных и их сложности

MIDI-файл, который пользователь загрузил для генерации по нему остальной части трека, передается на сервер, где проходит 3 этапа конвертации. После этого запускается нейросеть, которая проходится по входным данным, полученным из MIDI-файла, после чего нейросеть начинает генерировать продолжение до тех пор, пока не будет достигнуто специальное “STOP” значение. Далее результат проходит 2 этапа обратного преобразования в выходной MIDI-файл, который отправляется пользователю на устройство.

  1. Этапы преобразования (MIDI-файл => формат входных данных в нейросеть):

    1. Преобразование элементарных событий MIDI в номера нот (от 0 до 127 включительно)

    2. Деление нот на слова

    3. Преобразование индексов слов в векторы слов

  2. Этапы преобразования (формат выходных данных нейросети => MIDI-файл):

    1. Преобразование индексов слов в ноты

    2. Сбор нот в итоговый MIDI-файл

Архитектура нейросети

Данная нейросеть написана мной вручную. Были использованы следующие библиотеки: Numpy, PyTorch, Pickle и другие. Стоит отметить, что PyTorch использовался исключительно для вычислений на GPU.

Архитектура нейросети создана на базе seq2seq. Seq2seq состоит из 2 частей: Encoder и Decoder.

Encoder

Задача: создать словарь эмбеддингов для каждого слова.

Формат входных данных: контекстный вектор.

Формат выходных данных: вектор центрального слова.

Decoder

Задача: сгенерировать продолжение временной зависимости, состоящей из эмбеддингов слов.

Формат входных данных: вектор текущего слова (эмбеддинг текущего слова).

Формат выходных данных: вектор следующего слова (эмбеддинг следующего слова).

Классы

В данном проекте имеется 3 класса: RNN, Hyper и EMA.

RNN - это основной класс, который использует классы Hyper и EMA для группировки переменных в логические блоки. Подсчитаем асимптотику обучения нейронной сети.

Обучающая выборка

Собран собственный dataset, состоящий из более чем 400 одноголосных MIDI-треков с плавным голосоведением.

Этапы разработки

Задача №1 - Разработка модели нейронной сети, которая подходит под данную задачу

Выбор архитектуры нейронной сети

Для задач анализа последовательностей во времени хорошо подходит seq2seq. Encoder представляет собой архитектуру CBOW, так как используется способ создания векторов слов Word2Vec (имеется 1 скрытый слой). Decoder представляет собой архитектуру RNN.

Выбор идеи генерации музыкальных файлов

Для генерации трека будем использовать MIDI-файлы. Каждый MIDI-файл состоит из элементарных событий. Среди них есть note_on и note_off. Каждое из этих двух событий состоит из множества параметров. Среди них выделим номер ноты, начало/конец звучания ноты на шкале времени MIDI, которая измеряется в tick, и громкость ноты.

Выбор количества входных нейронов

Для разложения MIDI-файла на ноты я буду использовать библиотеку Mido. Так как уже говорилось ранее, seq2seq состоит из 2 частей - Encoder и Decoder. Количество нейронов на вход и выход для Encoder соответствует количеству слов в словаре, так как контекстный вектор - это среднее значение one-hot векторов контекстных слов. Количество нейронов на вход и выход для Decoder соответствует выбранной длине вектора слова.

Выбор количества скрытых слоев и количества нейронов в них

Я долго экспериментировал и пришел к следующей архитектуре:

  1. Input Dim: 32 нейрона, Linear, Tanh

  2. Hidden Dim 1: 64 нейрона, RNN, Tanh

  3. Hidden Dim 2: 64 нейрона, Linear, Tanh

  4. Hidden Dim 3: 64 нейрона, Linear, Tanh

  5. Output Dim: 32 нейрона, Linear, None

Для вычисления ошибки используется функция MSE (среднеквадратичная ошибка). Для оценки точности модели используется функция RMSE (Root Mean Squared Error).

Выбор выходных данных нейронной сети

Так как я пишу нейросеть, которая генерирует продолжение входных данных, количество нейронов в выходном слове должно совпадать с количеством нейроном во входном слое.

Задача №2 - Выбор языка программирования и библиотек

Выбор языка программирования для написания нейронной сети

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

Выбор библиотек для написания нейронной сети

Я выбрал следующие библиотеки:

  • PyTorch — в качестве замены NumPy, так как NumPy не позволяет производить вычисления на CUDA

  • Midiutil — для создания MIDI-треков

  • Mido — для чтения MIDI-файлов

  • Pickle — для сериализации3 объектов Python

  • Matplotlib — для создания графиков

  • Keyboard — для считывания событий нажатия клавиш на клавиатуре

Задача №3 - Реализация модели нейронной сети

Разработка CBOW нейросети (Encoder)

Для реализации CBOW нейросети достаточно реализовать обычную NLP нейросеть.

Подробнее можно посмотреть в приложении. Там есть исходный код с подробными комментариями.

Разработка конвертера MIDI-треков в формат, подходящий для обучения CBOW нейросети

Для этого, напишем 2 скрипта: GetGroupMidiPKL и BuildDatasetForNeuroEmbedding.

Первый скрипт (GetGroupMidiPKL) будет преобразовывать MIDI-файлы в последовательность MIDI-нот.

Второй скрипт (BuildDatasetForNeuroEmbedding) будет создавать словарь индексов слов, а затем, используя результаты предыдущих двух преобразований, создавать dataset из one-hot векторов для обучения CBOW нейросети.

Подробнее можно посмотреть в приложении. Там есть исходный код с подробными комментариями.

Разработка RNN (Decoder)

Разрабатывать RNN я буду на базе обычной NLP. За основу возьму уже написанную CBOW нейросеть. В данном разделе хочется разобрать только места с кардинальными отличиями от NLP нейросети.

Подробнее можно посмотреть в приложении. Там есть исходный код с подробными комментариями.

Разработка конвертера выходных данных CBOW нейросети в формат, подходящий для обучения RNN

Напишем еще 2 скрипта: MidiPKLToEmbedding и BuildDatasetForNeuroMidi.

Первый скрипт отвечает за конвертацию последовательности MIDI-нот в последовательность векторов слов.

Второй скрипт отвечает за создание датасета для обучения основной нейросети (RNN).

Подробнее можно посмотреть в приложении. Там есть исходный код с подробными комментариями.

Разработка конвертера выходных данных RNN в MIDI-трек

Напишем еще один скрипт - RComposeGenMidi.

Для создания MIDI-файла будем использовать библиотеку MIDIUtil, так как, в отличие от Mido, она позволяет работать не с низкоуровневыми событиями MIDI-файла, а напрямую с нотами. Скрипт просто будет итерироваться по нотам и добавлять их в MIDI-файл в соответствии с ритмом.

Подробнее можно посмотреть в приложении. Там есть исходный код с подробными комментариями.

Преобразование MIDI-трека в MP3-аудиофайл

Данное преобразование также происходит в скрипте RComposeGenMidi. Для этого используются по очереди 2 библиотеки: midi2audio и pydub.

Сначала midi2audio преобразовывает MIDI-файл в WAV-файл с использованием SoundFont “HQ Orchestral Soundfont Collection v3.0”.

Затем используются pydub для преобразования WAV-файла в MP3-файл.

Преобразование MIDI-трека в нотное представление

Данное преобразование также происходит в скрипте RComposeGenMidi. Для этого используются снова 2 библиотеки по очереди: Music21 и lxml.

Music21 преобразовывает MIDI-файл в MusicXML-файл.

Затем используются lxml для парсинга MusicXML-файла и последующей установки названия музыкального трека, а также его автора.

Завершающим штрихом является применение программы MuseScore34 для преобразования итогового MusicXML-файла в PDF-файл с нотной партитурой.

Задача №4 - Обучение нейронной сети создавать музыкальные MIDI-треки

 

Обучение CBOW нейросети

Так как CBOW нейросеть отвечает за создание векторов слов, ее обучение происходит каждый раз при изменении датасета. На данный момент CBOW нейросеть обучалась уже 13 раз. Ниже представлен график с последнего обучения.

Обучение RNN

Основную нейросеть MN3F я обучал с уже 15 раз. За это время многое улучшилось. Ниже представлен график с последнего, 15 обучения.

Заключительная часть

Результат

Написана собственная нейросеть, взаимодействие с которой осуществляется через Telegram бот. Данный Telegram бот дает возможность загрузить собственный MIDI-файл, отправить данные на сервер (нейросети) и получить готовый MIDI-файл с продолжением заданной мелодии.

Выводы

Удалось обучить нейросеть, решить проблему с затухающим градиентом посредством использования техники машинного обучения TBPTT. Улучшена сходимость нейросети. Собран собственный специализированный датасет под данную задачу для обучения нейросети. Разработан Telegram бот, позволяющий пользоваться одной нейросетью сразу нескольким пользователям в порядке очереди.

Приложение

  1. Вывод всех формул: https://cyberneural.ru/fq4Gxkq9ww6Am4n8TczyAyOwRUFMVQhcp1eAObPgvBAnei2nEPMvIyeimOTWGw/16eie8lV04MfNmTABjK4AHulL4LSMTAPsFf3OvyyQAGX0BX2fygfkGo9UB7dOW.7z

  2. Исходный код проекта: https://cyberneural.ru/fq4Gxkq9ww6Am4n8TczyAyOwRUFMVQhcp1eAObPgvBAnei2nEPMvIyeimOTWGw/KTc903v3sqWHusoPCja5XqrZyQQv1ZypqbtrjXvvi0pUAUQhUOTFQNuNY8nPC.7z

(пароль от 7z-архива с выводом всех формул: ChDpDScB0EtLwBJ82VLyJo8WfSEzxFrjqn)

(пароль от 7z-архива с исходным кодом: tIrJyhvx0SllGopBDK5vZFEP1rAvboMLMr6s)

Список используемой литературы

  1. Интернет-ресурсы

  2. Официальная документация по Python — https://www.python.org/doc

  3. Платформа электронного обучения — https://www.geeksforgeeks.org

  4. Руководство по NumPy — https://numpy.org/doc/stable

  5. Руководство по PyTorch — https://github.com/pytorch/pytorch

  6. Таулли, Т. Нетехническое введение в искусственный интеллект / Т. Таулли. — Москва: Издательство, 2023. — 256 с.

  7. Gunawan, A. A. S., Iman, A. P., & Suhartono, D. (2020). Automatic music generator using recurrent neural network. International Journal of Computational Intelligence Systems, 13(1), 645–654.

1 Сериализация в программировании — это процесс преобразования объекта в последовательность байтов или формат, который можно сохранить в файл, передать по сети или сохранить в базе данных.

2 MuseScore3 — свободный редактор нотных партитур

3 Big Data — обозначение структурированных и неструктурированных данных огромных объёмов и значительного многообразия

4 CUDA — программно-аппаратная архитектура параллельных вычислений Compute Unified Device Architecture

Просмотров работы: 38