Описание проекта
Recognition of music sheet and transcribing it into MIDI
Подход к распознаванию нот
После определённого количества безуспешных попыток написания проекта с нуля и проверки разных подходов, наткнулся на следующую статью: В ней описан подход к распознаванию нот с помощью связки Convolutional и Recurrent сетей. Этот подход используется, в частности, для распознавания текста. Поэтому я решил взять одну из реализаций Optical Character Recognition и обучить сеть на базе нот.
Была выбрана эта tensorflow модель. Научная статья, объясняющая принцип её работы.
Датасет
Наиболее полная информация касательно датасетов по распознаванию нот находится здесь. Однако, датасетов с размеченной высотой нот, подходящих для моих задач не нашлось. Единственный доступный датасет со звуковысотным маппингом был взят отсюда, у ребят написавших оригинальную статью, ссылка на которую представлена выше. Он представляет из себя сгенерированные в Lilypond изображения с соответствующими лейблами для каждой ноты и знака.
Характеристики датасета
94,984 случайных монофонических последовательностей, состоящих из 52 символов: музыкальных нот от С4 до Е5, 4 длительности (половина, четверь, восьмая, шестнадцатая), 4 паузы тех же длительностей, символы размеров (3/4, 4/4, 6/8), знаки альтерации (диез, бемоль, бекар), скрипичный ключ, тактовая черта.
Поскольку датасет составлен из сгенерированных изображений, распознавание не будет адекватно работать с фотографиями. Также, с нотами, чья структура отличается от характеристик датасета.
Датасет был обработан, чтобы соответстовать требованиям сети для обучения (созданы лейблы, изображения уменьшены и т.д.). 95% - обучающая выборка 5% - тестовая.
Обучение
Сеть обучалась в течение около 8 часов на NVIDIA Tesla K80. 16 эпох.
Сложности
1. Сейчас модель может распознавать небольшие последовательности. Ей нельзя скормить весь лист с нотами. Однако, эта проблема решаема. Я пытался сделать сегментацию листа (вычленение тактов) силами OpenCV и добился определённых результатов. Но код очень по-разному работает для изображений разного качества. Поэтому, в долгосрочной перспективе, тут нужно тренировать отдельный слой сети. Для этого нужны данные с разметкой тактов, систем и прочих высокоуровневых элементов системы нотного листа.
2. Не успел сделать конвертацию в MIDI. К сожалению, вопрос в лоб не решить. Думал просто конвертировать обратно в Lilypond но сделать это оказалось не так легко из-за того, что программа сама проставляет знаки альтерации в зависимости от тональности и ещё пары тонкостей. Возможно, тут лучше подойдёт OpenXML, на изучение формата которого, однако, у меня не хватило времени. Если успею и всё получится, реализую в ближайшие дни. Следите за гитхабом.
3. Также не хватило времени на "выкат в продакшен" версии для удобного тестирования без каких-либо установок. Поэтому, чтобы поиграться с распознаванием, нужно поставить https://github.com/emedvedev/attention-ocr и запустить функцию тестирования, это опишу ниже.
4. Также не успел, как следует протестить и собрать статистику. Единичный прогон по тестовой выборке показал результат в 99,5%.
Как запустить
Устанавливаем https://www.tensorflow.org/install/
Устанавливаем https://github.com/emedvedev/attention-ocr
Качаем тестовую выборку: https://github.com/Dene33/notes-recognition/blob/master/notesTest.tfrecords?raw=true
Качаем чекпоинты (это и есть обученная модель) и распаковываем: https://github.com/Dene33/notes-recognition/blob/master/checkpoints.zip?raw=true
Запускаем:
aocr test --visualize ПУТЬ/К/notesTest.tfrecords --log-path ./log/log.log --max-width 1000 --max-height 61 --max-prediction 36 --full-ascii --model-dir ПУТЬ/К/checkpoints
Небольшое примечание. Распакованные checkpoints.zip содержат папку checkpointsDL - путь нужно указывать к ней.
Наблюдаем за процессом. А потом смотрим на результат в папке log. Там будут находиться папки для каждой картинки, для которой было проведено распознавание. В каждой папке файл word.txt где первая строка - предсказанный результат, вторая - ground-truth Также в папке находится гифка, показывающая процесс работы нейросети.
Для перевода результата в читаемый формат (переименование папок и файлов), кидаем питоновский скрипт в папку out и запускаем.
Быстрая установка и запуск на Линуксе
sudo pip install aocr
pip install tensorflowgit clone https://github.com/Dene33/notes-recognition
cd notes-recognition
unzip checkpoints.zip -d checkpointsaocr test --visualize notesTest.tfrecords --max-width 1000 --max-height 61 --max-prediction 36 --full-ascii --model-dir ./checkpoints/checkpointsDL
Тест на своём датасете
Чтобы протестировать на своих картинках, создаём папку с картинками. Максимальная высота картинок - 60, ширина - 1000. Создаём текстовый файл (например labels.txt) с лейблами такого формата:
./datasets/images/hello.jpg hello ./datasets/images/world.jpg world
где ./datasets/images/hello.jpg - путь до картинки, hello - её лейбл. Какому символу какая нота соответствует можно посмотреть тут, где 1 столбец - лейблы, 2 - соответствующая нота или знак.
Затем, чтобы создать tfrecord из картинок выполняем:
aocr dataset ПУТЬ/К/labels.txt ПУТЬ/К/МОДЕЛИ/testing.tfrecords
Запускаем:
aocr test --visualize ПУТЬ/К/testing.tfrecords --log-path ./log/log.log --max-width 1000 --max-height 61 --max-prediction 36 --full-ascii --model-dir ПУТЬ/К/checkpoints
Примеры картинок из обучаемой выборки и соответствующих лейблов:
MRRRROT:3+)R*
MRRN;RK+3R"QR<L+6
MSSO6S4'
Ссылка на .tfrecord который использовался для обучения модели: https://drive.google.com/file/d/1wd716Lg6Uz5Vxr6x-vEeoLKMb09YapPL/view?usp=sharing
TODO
1. Экспорт SaveModel для Tensorflow
2. Конвертация в MIDI. Этим я занимаюсь в настоящий момент, можно ожидать в ближайшие дни.
3. Сегментация листа на такты и обратная сборка всей структуры после прохода распознаванием по каждому сегменту
4. Поднять Tensorflow Serving
5. Разметка датасета под распознавание фотографий и более широкого спектра символов
ETH-wallet: 0x136f0a3d6f3Db9db3b742153a396B8b47721Bb24
Состав команды:
- Denis Cera, code
Комментарии
А не сравнивали качество с традиционными программами распознавания нот без нейросетей? https://en.wikipedia.org/wiki/Optical_music_recognition
Традиционные подходы работают более-менее, но 1. требовательны к качеству входного изображения - нужны отсканированные листы. 2. Не работают/работают плохо с рукописными нотами. Ну и конечно же, 3. большая часть подобного софта - проприетарные продукты. Нейронные же сети можно обучить распознавать ноты и на обычных фотографиях с телефона (был бы датасет подходящий).
В обратную сторону музыку в ноты переводить тоже можно? Не в рамках этого проекта, а вообще в принципе. Импровизируешь, потом читаешь.
Насколько я знаю, распознавание звука - более тривиальная задача, решаемая без использования нейронных сетей. Особенно, если говорить о монофонических мелодиях. С полифоническими уже сложнее, но тоже реально, особенно если играет один инструмент. Что касается записей с большим количеством инструментов - тут нейронные сети уже могли бы найти применение, да. Не уверен, что есть какие-то прям хорошие реализации для подобного, но могу ошибаться.
По поводу символов - было бы круто, если бы проект в будущем научился распознавать ноты для барабанщиков. Прикол в том, что если есть слух, то прослушать и повторить проще, чем разбирать ноты и считать длительности)
А на будущее, можно было бы еще подумать насчет интеграции с каким-нибудь существующим музыкальным ПО, тот же guitar pro, например...
Или вообще уйти в другую сторону и по нотам генерировать какую-нибудь игру, типа tap-tap:)
Распознавание нот для барабанщиков во многом даже легче реализовать (за счёт меньшего количества нотационных символов). Всё дело сводится лишь к размеченному дата сету, сама сеть работает отлично.
То, что слушать и повторять легче, чем копаться в нотах - это прям то, из-за чего я решил взяться за этот проект. Я пою в хоре и иногда хочется просто прослушать, как звучит партия. :) Надеюсь, со временем получится довести проект до уровня "сфотографировал партию, прослушал".
Гитар про умеет импортировать MIDI файлы. Тут главное найти наиболее удобный способ для работы с выходными данными, да. Сейчас они генерируются в MIDI посредством питоновской библиотеки mido.
Буквально нескольких часов не хватило, чтобы закончить конвертацию в MIDI. На гитхабе добавлено пояснение того, как работает. В папку out кидаем этот скрипт: https://github.com/Dene33/notes-recognition/blob/master/python-util-scripts/toMidiRenamer.py и запускаем. Он создаст .py файл для каждого распознанного изображения. Запустив файл, проиграется MIDI и создастся .mid файл для соответствующего распознанного изображения.