Пишете музыку, но внезапно настиг творческий кризис? Или вам хочется получить треки уровня royalty-free, потыкав несколько слайдеров в Colab ноутбуке? Вы не готовы получать PhD в нейронных сетях и разбираться с теорией музыки, а попробовать себя в роли нейросетевого музыканта очень уж хочется? Команда Sber AI спешит к вам с радостной новостью: совершенно безвозмездно мы выкатили NLP-модель синтеза музыки, обученную на тысячах часов музыки из открытых источников. Вам не придется платить за аренду GPU сервера с картой V100 для синтеза через Jukebox - наша модель порадует вас бесплатными треками в риалтайме даже в простом Google Colab. А ещё вы узнаете, как связаны трансформеры и шедевры классической музыки. Но обо всем по порядку. Ссылка на репозиторий - можно загрузить демку и сгенерировать музыку С чего начинается путь падавана нейросетевой музыки? Разумеется, пишем в google “neural network music generator” и видим следующее: OpenAI мы доверяем, ведь благодаря им мы имеем DALL-E, CLIP и GPT-3, превзошедшие многие другие модели и подходы. Начнем с MuseNet (ведь он выше в поиске, а значит годнее). Прослушаем несколько любезно предоставленных примеров для повышения мотивации: Но вот незадача - у MuseNet есть только заранее сгенерированные треки, нет доступа к коду и возможности поимпровизировать, заточив музыку под себя.  Пробуем вторую модель - Jukebox. Вот тут мы уже можем наложить свои руки на код и адаптировать музыку под свои нужды. С ней мы можем выбрать жанр, стиль исполнителя и даже добавить вокал, получив что-то наподобие: Ваша мотивация повысилась? Открываем демонстрационный ноутбук на Google Colab, запускаем все ячейки подряд и вожделенно ожидаем музыкального шедевра… Однако вместо него ноутбук перезагружается и ставит нас перед фактом: Но мы готовы немного потанцевать с бубном, взять урезанную модель и сократить длину трека. В таком случае спустя несколько часов мы получим наше творение (упс, сорри, очень скверный звук): Стоп, а почему так много шума? Всё потому, что надо произвести дополнительный шаг апсемплинга со слоёв меньшего разрешения. К нашему сожалению, генерация музыки на колабе с урезанной моделью заняла у нас больше времени, чем продолжительность бесплатных инстансов Colab: Неужели синтез музыки - удел счастливчиков со свободным сервером? Разберёмся в том, почему у нас не хватает памяти и времени. Всё дело в том, что Jukebox синтезирует музыку в волновом формате. А это ни много ни мало, а 44100 точек данных в одной секунде трека студийной записи. Выглядит это следующим образом: Односекундные треки мало кому интересны, для начала попробуем хотя бы получить 30-секундную студийную запись. Итого 1 323 000 значений амплитуд в одной записи с частотой семплирования 44100. Для сравнения: RGB-изображение разрешением 512x512 имеет всего 786 432 значений - почти в два раза меньше. И тут уже многие эксперты по Computer Vision скажут вам, что это перебор (кроме разве что тех, кто поднимает super resolution, высокоточную сегментацию или детекцию). И с такими проблемами мы сталкиваемся на инференсе. А представляете, какие ресурсы нужны для обучения такой модели?  В итоге имеем фундаментальную проблему - слишком много данных нужно сгенерировать. Самый простой способ обойти это ограничение - поменять сам формат данных. Музыку же можно представить в виде последовательности нот, и мы получим так называемый MIDI файл. После этого он загружается в секвенсор, выдающий нам музыкальный трек в волновом формате.  На первый взгляд может показаться, что от смены формата ничего радикально не поменялось. На самом же деле даже с самым базовым MIDI мы сильно сокращаем запись. Мы на практике получали треки продолжительностью до 2.5 минут используя всего 2048 нот. Разница в генерации 2048 и 1 323 000 значений очень ощутима, не правда ли? Плюс перед нами открылся огромный творческий простор для того, чтобы придумать оптимальный способ кодирования данных. Осторожнее! Мы ступили на земли NLP, как только решили кодировать свои данные. Но не стоит пугаться, ведь принцип тут простой - придумать такой алфавит из нот, чтобы трек на новом энкодинге занимал меньшее число значений. При этом делать всё слишком сжатым нежелательно - можем потерять важную информацию. По нашему опыту сложилось впечатление, что рецепт синтеза символьной музыки - это 60% энкодинга, 30% сбора и чистки данных и 10% обучения модели. Поэтому все, кто работает в этой области только и думают о том, как бы предложить что-нибудь свое. Мы, однако, для пилотной версии модели решили не запариваться и взяли самый простой, родной event-based MIDI энкодинг из статьи Music Transformer. В MIDI каждая нота имеет 3 основных характеристики: высота, длительность и громкость. По вертикальной оси задается высота ноты, по горизонтальной - длительность. Отдельно вынесены громкости для каждой ноты (на рисунке ниже - вертикальные столбцы под каждой нотой, чем выше столбец - тем громче нота). Для каждого инструмента создаётся своя дорожка с последовательностями нот. Из таких дорожек состоит midi файл.  Суть event-based MIDI энкодинга в том, что мы отслеживаем нажатия и отпускания клавиш, учитывая силу нажатия. Так, MIDI преобразуется в последовательность событий нажатия, отпускания клавиши (по 128 токенов), установки громкости (32 токена) и шага по времени (100 токенов). Углубляться в способы кодирования можно очень долго, и это выйдет за рамки вводной статьи, так что оставим это в качестве материала на будущее. Энкодинг есть, а что с ним делать? Правильно - с материнской заботой скармливаем его какой-нибудь NLP-модели. И учим-учим-учим. В нашем случае под руку подвернулась архитектура Music Transformer от Magenta. Поздравляем, теперь вам открылась тайна связи антропоморфных роботов-машин и игры на фортепиано.  Из интересных особенностей - тут вместо стандартного Self-Attention прикручен более прокачанный Relative Attention. По заверениям авторов, он сильно улучшает качество и позволяет модели воспроизводить и повторять музыкальные фразы. Мы в этом убедились, теперь ваш черёд. Что же такое Relative Positional Self-Attention, и с чем его едят? Тут в отличие от дефолтного Self-Attention, учитывается относительное положение каждой пары токенов, а не абсолютное. Это сильно помогает модели обрабатывать музыкальную информацию, так как в музыке часто встречаются повторения музыкальных фраз или повторения с небольшими изменениями. Механизм skew введён авторами оригинальной статьи как версия оптимизированного варианта Relative Attention, уменьшив, тем самым, затраты по памяти с O(L^2 D) до O(LD) (L - длина последовательности, D - hidden size). Подробнее можно почитать в оригинальной статье или на medium. На MIDI представлении мы уже видим повторяющиеся паттерны в виде повторяющихся гор и всяческих лесенок. Без него модели снизу пытаются получить что-то подобное, но даже если у них в начале получается, то под конец они предпочитают зажать клавиши и не отпускать до самого конца. Особенно это заметно на средней модели. Нижняя же вообще не склонна к повтору музыкальных фраз. Так что Relative attention - настоящая палочка-выручалочка в задаче синтеза символьной музыки. Использованная архитектура Music Transformer на самом деле в некотором смысле неконтролируема. Вы можете часами генерировать музыку, ожидая вам трек ожидаемого вами жанра. И он может оказаться неприемлемого качества.  Мы решили, что это бессмысленно и постарались сымитировать механизм генерации Jukebox. Для этого в начало генерируемой последовательности мы подаем специальный код, отвечающий за жанр. Через него модель понимает какое подмножество треков от неё хотят получить и генерирует в этом стиле. Сейчас мы смогли создать модель на четыре жанра: classic, pop, jazz, ambient. Но это не предел и в перспективе никто не мешает из метаинформации о треках достать исполнителей и большее число жанров, расширить их список, позволив генерировать в их стиле. А еще в отличие от Jukebox мы можем при желании контролировать каждый шаг генерации. Если этого не делать - существует риск того, что модель начнёт циклически повторять какую-то музыкальную фразу. В секвенсоре это, конечно, выглядит прикольно, но на слух приедается уже после второго повторения. Для этого мы добавляем штрафы за частую генерацию с повторами. Также у нас есть температурный скейлинг, позволяющий балансировать между моделью, зажатой в рамках и моделью-импровизатором. Ну и конечно же beam search, использующийся во многих NLP-задачах генерации текста.  Стандартный способ генерации основан на случайном сэмплировании по распределению вероятностей, полученному из модели. Генерация происходит авторегрессионно, то есть за один шаг генерируется один токен с учётом всех предыдущих. Каждый новый токен добавляется к последовательности уже сгенерированных токенов, и вся последовательность подаётся на вход для генерации следующего. Но такая случайная генерация - очень неконтролируемый процесс и может приводить к плохим случаям, т.к. всегда существует маленькая вероятность сгенерировать что-то неподходящее. К примеру, начать повторять две-три ноты по кругу, сродни тому как происходит в языковых моделях клавиатурных ассистентов. Поэтому мы используем методы, контролирующие процесс генерации: ●       top-k - ограничение набора по верхней границе. Сэмплирование происходит из набора k наиболее вероятных токенов. ●       at_least_k - ограничение набора по нижней границе. Сэмплирование будет гарантированно происходить как минимум из at_least_k наиболее вероятных токенов. ●       top-p - ограничение набора по кумулятивной сумме вероятностей. Упрощенно набор токенов для генерации создаётся так: итеративно добавляем наиболее вероятные токены в набор, и считаем их суммарную вероятность (всех токенов в наборе). Добавляем в набор до тех пор, пока суммарная вероятность не станет больше topp. (отметим, что сумма вероятностей по всему распределению = 1, поэтому значения topp, обычно выбираются в пределах 0.90-0.99). top-p хорошо комбинируется с at_least_k, т.к. из-за ограничения по top-p слишком уверенная модель может прийти к тому, что будет выбирать только из одного токена, тогда сэмплирования не будет. Это часто приводит к бесконечному зацикливанию композиции на одной музыкальной фразе. at_least_k помогает решить эту проблему. ●       temperature - влияет на само распределение вероятностей, делая его более либо менее равновероятным. Тем самым регулируется разнообразие генерации. При t=1.0 ничего не изменит (дефолтное значение). При t<1.0 - равновероятность уменьшается. Это аналогично увеличению уверенности модели, она будет склонна генерировать наиболее вероятные токены (при t→0 сэмплирование превратится в выбор по argmax - то есть в выбор одного самого вероятного токена). При t>1.0, наоборот, распределение будет приближаться к равновероятному, при t>>1.0 происходит абсолютно случайная генерация - шум. ●       Мы разработали метод Repetition Penalty (RP), который помогает избавиться от проблемы зацикливания на одной музыкальной фразе и в целом позволяет генерировать более разнообразные композиции. rp_penalty и rp_restore_speed - эти параметры отвечают за штрафование модели за частое повторение нот или фрагментов. Суть метода в том, что мы отслеживаем все нажатия нот, каждое нажатие уменьшает вероятность этой же ноты на следующем шаге генерации на число rp_penalty. Если нажатие всё равно происходит, то вероятность снова понижается, и т.д. Если нажатие не происходит, то вероятность этой ноты восстанавливается с каждым следующим шагом генерации За скорость восстановления отвечает параметр rp_restore_speed. Это число, обратное кол-ву секунд, за которое произойдет полное восстановление - с 0 до 1. Чем больше значение, тем менее заметно влияние RP. Сейчас мы предоставляем доступ к коду модели, обучения и генерации в нашем репозитории. Там же можно найти предобученные веса для экспериментов с подбором параметров генерации. Пытливые умы и знакомые с PyTorch смогут разобраться с кодом, подгрузить веса и сгенерировать всё, что душе угодно. Пока мы готовили демо-ноутбук на свет появилась картинка с «рыбов продаёте?» и теперь с его наличием она уже не актуальна. Но выбрасывать жалко, поэтому она занимает почетное место в заключении. Ну а напоследок можете оценить результаты генерации нашей модели: Один из самых длинных треков. В жанре ambient, т.к. в нём музыка спокойная и расход токенов на генерацию меньше. Благодаря этому удаётся растянуть 2048 токенов на 2 минуты. Еще один ambient. Звучит энергичнее чем предыдущий, оттого и длина меньше. Интересный спокойный душевный джазовый трек. Модель довольно смело раскидывается красивыми джазовыми аккордами в нужных местах и в нужное время, не скупясь, при этом, на импровизацию, и, сохраняя общую спокойную идею трека. Более динамичный современный джаз. Напоминает лёгкое джазовое музыкальное оформление в кафе. Интересная классическая композиция. Здесь модель хорошо подчеркнула динамику трека - на контрасте чередуются то громкие и смелые, то тихие фрагменты, что характерно для классической музыки. Жанр pop. Интересна тенденция модели к запоминанию основной ведущей партии в поп треках. Поп сам по себе склонен к частым повторениям простых мелодий и аккомпанемента, поэтому модель это успешно усвоила. Как видим лучше получаются жанры Jazz(в нем проще всего импровизировать) и Ambient(в нем треки простые) Максим Елисеев, Александр Маркелов, Иван Базанов SberAI