CoderCastrov logo
CoderCastrov
Наука о данных

ChordSuggester: использование LSTM для предсказания музыкальных последовательностей аккордов

ChordSuggester: использование LSTM для предсказания музыкальных последовательностей аккордов
просмотров
15 мин чтение
#Наука о данных
Logo of the application

ChordSuggester - это система компьютерной помощи в музыкальном сочинении. Она не предназначена для профессионального использования, а является результатом магистерской диссертации, которая пытается охватить весь процесс для проекта DataScience:

  • Получение данных путем парсинга данных с ultimate-guitar.com с использованием Selenium и BeaufitulSoup. Эта часть сама по себе интересна, так как нет примеров чистых наборов данных, включающих песни с аккордами.
  • Очистка и подготовка данных, используя Pandas и music21.
  • Анализ данных, с использованием Pandas.
  • Моделирование, с использованием Keras для обучения нейронной сети LSTM.
  • Визуализация результатов на **React-приложении, которое использует модель с помощью TensorFlow.js и показывает результаты с использованием музыкальных JavaScript-библиотек Tone.js и Vexflow.

Некоторая музыкальная теория

Для полного понимания системы необходимо иметь базовые знания музыкальной теории. В этой статье будут объяснены некоторые важные музыкальные концепции.

Элементы музыки

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

  • Мелодия относится к тому, как ноты расположены горизонтально, во времени, одна за другой. Например, григорианский хорал сосредоточен только на мелодии, имея повторяющийся ритм и отсутствие гармонии.
Gregorian Chant score: all the notes have the same duration (no rhythm) and only one note sound at once.
  • Ритм относится к комбинированию длительностей нот. Даже используя только ритмические ресурсы, можно создать хорошие композиции. Один пример может быть африканская перкуссия, которая обычно богаче классической европейской музыки.

  • Гармония относится к тому, как ноты расположены вертикально, то есть как несколько нот звучат одновременно. ChordSuggester будет сосредоточен на этом аспекте. Например, прелюдия Шопена Op. 28 №4 не имеет особой мелодии или ритма, но ее гармония делает ее невероятно интересной:

Конечно, эти три элемента могут быть объединены для создания еще более интересных композиций. Хорошо известным примером является тема "Розовой пантеры" великого американского композитора Генри Манчини:


Что такое нота?

Нота - это просто звук с определенной частотой (на самом деле это совокупность нескольких частот, но мы можем упростить задачу, обратив внимание только на частоту с наибольшей амплитудой, называемую основной частотой). Этот звук можно математически представить:

A note with its several frequencies. In this case, the **fundamental frequency** is the **red** one.

В английской системе музыка обозначается буквами (A, B, C, D, E, F, G), соответствующими (Ля, Си, До, Ре, Ми, Фа, Соль) в латинской системе.

Origin of Latin naming system. UT was replaced by DO for simplicity when singing. SI comes from the initials of Sant Joannes

Обратив внимание только на основную частоту, мы можем однозначно идентифицировать ноту с определенной частотой:

Musical Harmonic Series

Что такое интервал?

Интервал - это расстояние между двумя нотами. Это расстояние измеряется в полутонов (или полутонах в США). Расстояние между соседними нотами на пианино составляет один полутон.

Расстояние между нотами

Например, расстояние между нотами D и G составляет 5 полутонов (PT), то есть 2 тона (T) и 1 PT.

Кроме того, мы можем использовать диезы и бемоли для изменения наших нот:

  • ‘#’, называемый диез, повышает ноту на один полутон.
  • ‘♭’, называемый бемоль, понижает ноту на один полутон.

Обратите внимание, что, например, G♭ = F#, A♭ = G# или даже E# = F (расстояние между E и F составляет всего один полутон).

В результате у нас есть хроматическая гамма, которая содержит все эти 12 нот:

Восходящая и нисходящая хроматическая гамма на нотном стане

Интервалы имеют музыкальное название. Например, расстояние в 3 полутона называется малой терцией. Ниже приведена таблица с названиями интервалов и частотными соотношениями:

Названия интервалов (0 полутонов = унисон, 1 полутон = малая секунда...) и их частотные соотношения

Давайте обратим внимание на частотные соотношения. Обратите внимание, что наиболее простые соотношения (за исключением унисона и октавы, которые тривиальны) соответствуют совершенной квинте (3/2) и большой терции (5/4).

И вот интересное! Эти интервалы считаются наиболее приятными (созвучными) для нашего уха по сравнению с другими более сложными (несозвучными), такими как малая секунда (16/15). Поэтому наша музыкальная система не выбрана произвольно, она имеет физический смысл и даже удовлетворяет принципу KISS!

Больше информации об этом (видео на испанском языке):

Что такое аккорд?

Аккорд - это набор нескольких звуков, звучащих одновременно. Теоретически, нет ограничений на количество звуков, которые могут быть включены в аккорд.

Тем не менее, обычно в аккорде содержится не более 6 звуков, а наиболее распространены аккорды из 3 или 4 звуков.

Существует несколько способов представления аккорда:

  • Указание звуков, которые он содержит (мы рассмотрим это в коде, где используется массив из 12 позиций).
  • Название аккорда. Это музыкальный способ.

Название аккорда состоит из:

  • Корня (также известного как основной звук): это основной звук аккорда. Например, это может быть 'B'.
  • Тип или качество: это название, которое указывает интервалы от корневого звука. Например, наиболее распространенный аккорд, то есть мажорный аккорд, содержит большую терцию (4 полутона) и чистую квинту (7 полутонов) от корневого звука. Опять же, наиболее расширенный = наиболее простой. Например, аккорд Cmaj или просто C состоит из звуков: C, E и G.
Major chords: 4 and 7 semitones Minor chords: 3 and 7 semitones 7th chords, 4, 7 and 10 semitones
  • Слэш: Слэш-аккорд - это аккорд (например, G/B), который указывает на акцент на басовом звуке, отличном от корня аккорда. Когда играется аккорд, обычно предполагается, что бас будет акцентировать корень аккорда. Иногда предпочитается другой звук, что приводит к аккорду с альтернативным басовым звуком. Включение слэш-звука (также известного как on) делает проблему более сложной, поэтому она была проигнорирована в текущем подходе.

Связь между аккордами: круг пятых

Гармония лежит не только в вертикальном расположении нот (создание аккорда), но и в горизонтальном расположении аккордов (один за другим).

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

Круг пятых

Предположим, что мы начинаем с аккорда C. Если мы движемся по часовой стрелке и выбираем аккорд (ближайший, наиболее обычный), мы создаем напряжение: G. Ухо будет просить нас вернуться против часовой стрелки и сыграть снова C. Это самая простая последовательность аккордов и, снова же, одна из самых распространенных. Еще одна интересная последовательность - C-F-G, которая изначально создает расслабление, чтобы затем создать большее напряжение при переходе к G. Поэтому в круге пятых много песен с амплитудой 3.

Дополнительная информация:

Получение данных

Сложно найти чистый набор данных, содержащий аккорды для множества песен. Хорошим примером является этот, который содержит аккорды джазовых прогрессий, извлеченных из Real Book. Однако, недостаточно наборов данных с широким спектром стилей.

Было несколько вариантов для создания таких данных:

  • Извлечение из файлов mp3 или аналогичных. У этого подхода было две проблемы: одна не очень сложная для управления - найти mp3. Вторая была более важной: скорость информации. Размер mp3 огромен по сравнению с фактической информацией для извлечения. Например, 3 МБ mp3 может содержать только последовательность из 50 аккордов (размер в МБ против размера в Кб). Это может сделать процесс извлечения данных трудоемким и медленным.
  • Извлечение из файлов midi. Этот подход был первоначально выбран, потому что легко найти страницы midi или даже гигабайты данных внутри zip-компиляций midi. Кроме того, скорость чистой информации гораздо выше (размер в Кб против размера в Кб). Тем не менее, я скоро обнаружил, что этот процесс легок для определенных типов музыки (гомофоническая музыка):
Баховская хоральная музыка: каждая тактовая доля - аккорд

...в то время как он очень сложен для других типов (полифоническая музыка):

Есть некоторые инструменты для анализа музыки, но это не тривиальная работа.

  • Парсинг с веб-страницы с аккордами: Существует множество страниц, предоставляющих аккорды для гитары, такие как UltimateGuitar, La Cuerda, ... В этом случае, не учитывая сам процесс парсинга, информация была почти полностью чистой: для каждой песни предоставлялся список названий аккордов.

Парсинг с UltimateGuitar

Наконец, был выбран третий подход, и для извлечения данных с одной из самых известных страниц аккордов для гитары - UltimateGuitar, потребовалась библиотека для парсинга - BeautifulSoup.

Процесс парсинга имел несколько сложностей:

  • UltimateGuitar защищен от веб-парсинга. Я рассматривал использование некоторых платных сервисов, таких как удобный в использовании ScraperApi, но в конечном итоге тактика перезагрузки роутера, которая используется уже тысячелетиями, оказалась достаточной. В качестве компенсации были необходимы некоторые специальные стратегии для сохранения уже спарсенных данных, возобновления работы с последней страницы ошибки или объединения новых спарсенных данных с уже существующими.
Number 429 is like 666 for Data Scientists
  • Не было индекса, чтобы получить список песен. Чтобы обойти это, я проанализировал шаблоны URL при поиске по разным критериям. Я выбрал десятилетие, жанр и поджанр. В последующих итерациях я убрал последний критерий, потому что использование только десятилетия и жанра было быстрее, и объем сгенерированных данных был достаточным.
[https://www.ultimate-guitar.com/explore?genres[]=14&&decade[]=2010&subgenres[]=343](https://www.ultimate-guitar.com/explore?genres%5B%5D=14&decade%5B%5D=2010&subgenres%5B%5D=343)

Были спарсены не только песни, но и словари жанра, поджанра (также известного как стиль) и десятилетия.

  • При открытии страницы появлялось уведомление о куки, которое мешало отображению нужного HTML. BeautifulSoup анализирует только HTML, поэтому он не может имитировать события, такие как клики. Решением было использование Selenium Driver, который может напрямую взаимодействовать с браузером и выполнять действия, подобные действиям человека.
Пример уведомления о куки
  • Некоторые песни имеют несколько стилей, поэтому у нас есть некоторые дубликаты, с которыми нам пришлось справиться.

Весь этот процесс можно найти в этих двух блокнотах:


Извлечение признаков

Результатом предыдущего процесса был набор данных, содержащий следующие столбцы:

  • url: Исходный URL песни. Строка.
  • name: Очищенное название песни. Строка. Уже очищено на предыдущем этапе.
  • **decade: **Исходное десятилетие песни. Строка в формате: 1990-е.
  • **genre: **Исходные данные о жанре. Строка с жанрами, разделенными %%. Может содержать повторяющиеся жанры (например, Фолк%%Кантри%%Кантри).
  • chords: список аккордов. Строка, содержащая аккорды. Может быть преобразована в список Python с помощью eval. Например, [‘C’, ‘F’, ‘C’, ‘D7’]
  • uuid: уникальный идентификатор, автоматически сгенерированный в процессе парсинга.
Пример исходного набора данных

Из этих исходных данных было извлечено несколько признаков, не только для исследования их полезности для обучения модели, но и для возможности анализа песен более эффективным способом.

Давайте объясним некоторые из этих признаков.

  • artist: извлечен из URL. С этого момента мы можем сравнить музыку, например, Дэвида Боуи и Джастина Бибера.
  • decade: преобразован в числовой формат.
  • genres: не дублируются, но все еще разделены %%.
Жанры по числу появлений
  • cardinality: количество аккордов в песнях. Считает повторяющиеся аккорды. Например, для [D,D,E], cardinality = 3.
Распределение cardinality. Среднее около 85.
  • unique cardinality: количество различных аккордов в песнях. Не считает повторяющиеся аккорды. Например, для [D,D,E], cardinality = 2. Этот признак гораздо интереснее, чем cardinality, потому что он указывает на горизонтальную (во времени) богатство песни.
Уникальная кардинальность

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

Джаз является, с большим отрывом, самой богатой музыкой в терминах уникальной кардинальности.
  • major cardinality, minor cardinality и **neutral cardinality. **Упрощая:

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

  • sadness. Создан из предыдущих признаков. Это соотношение минорных аккордов к общему числу аккордов.
В целом, музыка склонна быть счастливой Но она становится грустной во все большей прогрессии...
  • **гармоническое среднее: **среднее положение каждой песни внутри круга квинт (см. первый раздел этой статьи). Аккорд имеет положение в этом круге. Это положение кодируется с помощью X и Y. Гармоническое среднее песни - это среднее значение X и Y среди ее аккордов.
Гармоническое среднее. Тональности с # более распространены. Чем короче радиус, тем шире гармоническое отклонение песни
  • **отклонение субдоминанты: **разница между гармоническим средним и самым удаленным аккордом в направлении против часовой стрелки.
Распределение отклонения субдоминанты
  • **отклонение доминанты: **разница между гармоническим средним и самым удаленным аккордом по часовой стрелке.
Отклонение доминанты. Увеличение на 3-4 шага может указывать на основной аккорд, заимствованный у минорной тональности
  • гармоническая ширина: сумма отклонения доминанты и отклонения субдоминанты.
Джаз, снова, является самым богатым жанром в терминах гармонической ширины
  • **сложность: **аккорд является сложным, если отношение частот между его нотами сложное (см. первый раздел этой статьи). Этот признак указывает среднюю сложность каждой песни.
Мы становимся все проще и проще...
  • нормализованные аккорды: последовательность аккордов можно транспонировать в эквивалентную последовательность с более низким или более высоким тоном. Модель, или по крайней мере это была моя гипотеза, будет лучше обучаться, если мы транспонируем (~нормализуем) эти последовательности.

Сгенерированный набор данных имеет самостоятельную ценность, потому что его можно использовать в качестве отправной точки для любого другого проекта DataScience. Некоторые примеры:

  • Кластеризация песен, исполнителей или жанров по этим характеристикам.
  • Составление музыки определенного жанра или десятилетия.
  • Добавление новых признаков к характеристикам песни в Spotify API.

Весь процесс извлечения признаков можно найти в этой записной книжке.


Модель

Была обучена LSTM-сеть для предсказания следующей аккордовой последовательности на основе входных данных.

Эту проблему можно рассматривать как простую задачу предсказания слов. Однако, я обнаружил некоторые отличия:

Музыка = Математика

Circle of fifths

Аккорд можно математически представить без использования подходов к векторизации (например, word2vec). В данной работе была исследована возможность представления аккорда следующим образом:

При использовании этих подходов я столкнулся с проблемой, что появление одной ноты зависит от появления другой. Например, маловероятно, чтобы в аккорде были ноты C и C#, но очень часто можно встретить аккорд с нотами C и E. Поэтому эти признаки являются ковариантными/контравариантными и не подходят для обучения модели машинного обучения.

Си-мажор эквивалентно С или СМ. Другие подходы не учитывают эту ситуацию, но в нашей системе мы нормализовали данные, чтобы преобразовать все варианты в каноническую версию.

C, Cmaj и CM - одно и то же

Мы можем транспонировать данные

Транспонирование данных

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

Модель получает нормализованную последовательность, а затем предсказания "денормализуются" (т.е. транспонируются обратно в правильную тональность).

Гиперпараметры

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

Я использовал нейронную сеть с фиксированной топологией:

Топология сети

Наконец, мне пришлось использовать слой вложения, хотя я пытался его избежать...

Оптимизатором был выбран Adam, а функцией потерь - categorical_crossentropy, так как это задача классификации.

Выбранные переменные гиперпараметры:

  • Длина входной последовательности (называемая W в блокноте). Были протестированы значения 10 и 20. В итоге было выбрано значение 20.
  • Скорость обучения. Были протестированы значения 0.1 (застревание), 0.01 (ухудшение точности), 0.001 (лучше, но переобучение) и 0.0005 (лучшее).
График с точностью у 0.01, где точность начинает ухудшаться после 46 эпохи График с точностью у 0.001, где теряется точность на валидации после 22 эпохи (переобучение) Обучение с использованием скорости обучения 0.0005. График указывает на то, что, возможно, мы могли бы увеличить количество эпох
  • Размер пакета. Были протестированы значения 1024 (застревание), 128 (лучшее) и 32 (слишком медленно).
  • Эпохи. Изначально было выбрано значение 20, чтобы получить более быструю обратную связь, а затем 50, когда были выбраны гиперпараметры.
  • Нормализация или не нормализация данных. Я обнаружил, что нормализация данных приводит к лучшей производительности, но не такой высокой, как ожидалось.

Обучение LSTM можно найти в этом блокноте.

Конверсия

Для использования модели в продакшн-среде (веб-приложение на React без необходимости бэкенда) обученные модели были преобразованы в формат Tensorflow.js.

Инструкции по конвертации модели можно найти в файле readme.

Кроме того, некоторые словари на языке Python, используемые при извлечении признаков, были экспортированы в формате JSON для использования их во фронтенде. Преобразование выполняется в этом ноутбуке.


Фронтенд

Было создано приложение на React, чтобы интерактивно тестировать модель. Внешний вид приложения следующий:

Look and feel of the application
  1. Самый вероятный аккорд, предложенный моделью.

  2. Второй по вероятности аккорд, предложенный моделью.

  3. Вероятность, рассчитанная моделью для аккорда C.

  4. Нажмите, чтобы прослушать аккорд C.

  5. Нажмите, чтобы добавить аккорд C на лист (1).

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

  7. Транспонировать лист на полутон вниз.

  8. Транспонировать лист на полутон вверх.

  9. Удалить последний аккорд с листа.

  10. Очистить весь лист.

  11. Воспроизвести песню.

  12. Загрузить стандартную композицию (канон Пахельбеля).

  13. Переключение между двумя моделями (одна обучена на нормализованных данных, по умолчанию, и другая обучена на ненормализованных данных).

  • Для прослушивания песен использован Tone.js.
  • Для отображения нотного листа использован VexFlow.

Некоторые соображения о стоимости ошибок, тестировании и непрерывной интеграции

Ошибки в области Data Science, как и в любом другом программном обеспечении, имеют стоимость, которая может быть экономической или даже человеческой.

Чем позже найдена ошибка, тем выше ее стоимость. Хотя ошибки неизбежны, мы можем попытаться обнаружить их как можно раньше.

В моем личном случае ошибка может заставить меня потратить время на поиск проблемы, что также является важным фактором :).

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

Непрерывная интеграция и доставка должны быть обязательными в любом проекте Data Science. В качестве небольшого примера, в репозитории Python были настроены GitHub Actions, чтобы автоматически запускать тесты.



Выводы

Это был проект, в котором:

  • У меня была возможность пройти через все этапы проекта по науке о данных.
  • Я применил техники науки о данных в области, которую я люблю: музыка.
  • Мне удалось сделать несколько инновационных вещей по сравнению с существующими проектами.
  • Я представил данные в красивом виде, получив продукт, который мог бы иметь реальных пользователей.
  • Я применил принципы инженерии программного обеспечения для повышения качества и снижения вероятности ошибок, что очень важно в этой области.

Хорошо, но... покажите мне код!

ChordSuggester

Демонстрационный проект, созданный с использованием React

huanlui.github.io

  • Исходный код: Парсинг, очистка и обучение на Python (BeautifulSoup, Pandas, Keras, music21 и специальной версии Pychord):

github.com/huanlui/chord-suggester

  • Исходный код: Фронтенд (приложение на React и Tensorflow.js)

github.com/huanlui/chord-suggester-frontend