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 - путь нужно указывать к ней.

Результат

Наблюдаем за процессом. А потом смотрим на результат в папке out. Там будут находиться папки для каждой картинки, для которой было проведено распознавание. В каждой папке файл word.txt где первая строка - предсказанный результат, вторая - ground-truth Также в папке находится гифка, показывающая процесс работы нейросети.

Для перевода результата в читаемый формат (переименование папок и файлов), кидаем питоновский скрипт в папку out и запускаем.

Проигрывание MIDI

Для проигрывания MIDI, кидаем в ту же папку этот скрипт и запускаем (важно, перед этим нужно запустить скрипт для перевода файлов в читаемый формат). В каждой папке для всех распознанных изображений скрипт создаст .py файл, запустив который проиграется MIDI. Этот .py файл также создаст .mid файл. Ограничения: не учитывается тональность, из-за чего некоторые ноты могут в итоге звучать неправильно (тут нужно более развёрнутое пояснение, которое я как-нибудь напишу).

pip install mido
pip install python-rtmidi

Быстрая установка и запуск на Линуксе

sudo pip install aocr
pip install tensorflow
pip install mido

git clone https://github.com/Dene33/notes-recognition
cd notes-recognition
unzip checkpoints.zip -d checkpoints

aocr test --visualize notesTest.tfrecords --max-width 1000 --max-height 61 --max-prediction 36 --full-ascii --model-dir ./checkpoints/checkpointsDL

По поводу перевода результата в читаемый формат и проигрывания MIDI смотрим выше.

Тест на своём датасете

Чтобы протестировать на своих картинках, создаём папку с картинками. Максимальная высота картинок - 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