Создавайте свою собственную музыку с помощью глубокого обучения

глубокое обучение

Обзор

  • Узнайте, как разработать комплексную модель, автоматически генерирующую музыку.
  • Понять архитектуру WaveNet и внедрить ее с нуля с помощью Keras
  • Сравнение производительности WaveNet и LSTM для построения моделей автоматической генерации музыки

вводить

«Если бы я не был физиком, я мог бы стать музыкантом. Я часто думаю о музыке. Я воплощаю свои мечты в жизнь в музыке. Я смотрю на свою жизнь с точки зрения музыки». — Альберт Эйнштейн

Я не такой физик, как мистер Эйнштейн, но я полностью с ним согласен насчет музыки!Не могу вспомнить ни дня, когда бы я не включал свой плеер. Мои поездки сопровождаются музыкой, которая, честно говоря, помогает мне сосредоточиться на работе.

Я всегда мечтал сочинять, но не очень хорошо разбирался в инструментах. Пока я не наткнулся на глубокое обучение. Используя определенные методы и рамки, я могу создавать свою собственную оригинальную музыку, не зная никакой теории музыки!

Это один из моих любимых профессиональных проектов. Я объединил два своих увлечения — музыку и глубокое обучение — чтобы создать модель, автоматически генерирующую музыку. Мечты сбываются!

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

содержание

  1. Что такое автоматическая генерация музыки?
  2. Каковы компоненты музыки?
  3. Различные методы генерации музыки
    • Использование архитектуры WaveNet
    • Использование долговременной кратковременной памяти (LSTM)
  4. Реализация — автоматическая композиция с Python

Что такое автоматическая генерация музыки?

Музыка – это искусство, универсальный язык.

Я определяю музыку как набор тонов разных частот. Следовательно, автоматическое создание музыки — это процесс создания небольшого музыкального произведения с минимальным вмешательством человека в этот процесс.

Какая самая простая форма создания музыки?

Все начинается со случайного выбора звуков и объединения их в музыкальное произведение. В 1787 году Моцарт предложил игру в кости, в которой выбирались эти случайные звуки. Он создал около 272 тонов вручную, а затем выбрал тон на основе суммы двух кубиков.

Еще одна интересная идея — использовать музыкальную грамматику для создания музыки.

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

В начале 1950-х Яннис Ксенакис использовал концепции статистики и вероятности для создания музыки, которую часто называют случайной музыкой. Он определяет музыку как ряд элементов (или звуков), возникающих случайно. Поэтому он формулирует это в терминах стохастической теории. Его случайный выбор элементов полностью основан на математических концепциях.

В последнее время архитектуры глубокого обучения стали современным средством автоматического создания музыки. В этой статье я расскажу о двух разных подходах к автоматизации композиции песен с использованием архитектур WaveNet и LSTM (Long Short Term Memory).

Каковы компоненты музыки?

Музыка в основном состоит из нот и аккордов. Позвольте мне объяснить эти термины с точки зрения фортепианного инструмента:

  • ПРИМЕЧАНИЕ. Звук, воспроизводимый одной клавишей, называется нотой.
  • Аккорд: Звук, воспроизводимый двумя или более клавишами одновременно, называется аккордом. Как правило, большинство аккордов содержат как минимум 3 тональности.
  • Октава: повторяющийся узор называется октавой. Каждая октава содержит 7 белых клавиш и 5 черных клавиш.

Различные способы автоматической генерации музыки

Я подробно расскажу о двух основанных на глубоком обучении архитектурах для автоматического создания музыки — WaveNet и LSTM. Но почему только архитектуры глубокого обучения?

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

Таким образом, модели глубокого обучения являются самыми современными в области обработки естественного языка (NLP), компьютерного зрения, синтеза речи и т. д. Давайте посмотрим, как построить эти модели для музыкальной композиции.

Способ 1: Использование WaveNet

WaveNet — это примитивная модель генерации звука, основанная на глубоком обучении, разработанная Google DeepMind.

Основная цель WaveNet — генерировать новые выборки из исходного распределения данных. Следовательно, она называется генеративной моделью.

Wavenet похож на языковые модели в НЛП.

В языковой модели по последовательности слов модель пытается предсказать следующее слово:

Подобно языковой модели в WaveNet, данная последовательность выборок пытается предсказать следующую выборку.

Метод 2: использование моделей с долговременной кратковременной памятью (LSTM)

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

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

Способ 1: Использование WaveNet

Вейвнет: этап обучения

Это задача «многие к одному», где вход представляет собой последовательность значений амплитуды, а выход — последующее значение.

Давайте посмотрим, как подготовить входные и выходные последовательности.

Вход WaveNet:

WaveNet принимает необработанный звук в качестве входных данных. Необработанные звуковые волны относятся к представлению волн в области временных рядов.

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

Выход WaveNet:

Учитывая последовательность значений амплитуды, WaveNet пытается предсказать последовательные значения амплитуды.

Давайте разберемся в этом на примере. Рассмотрим 5-секундную звуковую волну с частотой дискретизации 16 000 (то есть 16 000 выборок в секунду). Теперь у нас есть 80000 сэмплов, записываемых каждые 5 секунд. Давайте разделим звук на куски одинакового размера, скажем, 1024 (это гиперпараметр).

На следующем рисунке показана входная и выходная последовательность модели:

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

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

этап вывода

На этапе вывода мы попытаемся создать новые выборки. Давайте посмотрим, как:

  1. Выберите случайный массив выборочных значений в качестве отправной точки для моделирования
  2. Теперь модель выводит распределение вероятностей всех выборок.
  3. Выберите значение с наибольшей вероятностью и добавьте его в массив образцов.
  4. удалить первый элемент и передать его в качестве входных данных для следующей итерации
  5. Повторите шаги 2 и 4 для определенного количества итераций.
Понимание архитектуры WaveNet

Строительные блоки WaveNet представляют собой причинно расширенные одномерные сверточные слои. Давайте сначала поймем важность связанных понятий.

Почему?Что такое свертка?

Одной из основных причин использования свертки является извлечение признаков из входных данных.

Например, в случае обработки изображений карту признаков можно получить путем свертки изображения с фильтром.

Свертка — это математическая операция, объединяющая две функции. В обработке изображений свертка представляет собой линейную комбинацию некоторой части изображения и ядра.

Что такое одномерная свертка?

Цель одномерной свертки аналогична модели долговременной памяти. Он используется для решения тех же задач, что и LSTM. В одномерной свертке ядро ​​или фильтр перемещаются только в одном направлении:

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

Когда мы устанавливаем допустимые значения заполнения, длина входных и выходных последовательностей изменяется. Длина вывода меньше длины ввода:

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

Преимущества одномерной свертки:
  • Захват информации о порядке, которая встречается во входной последовательности
  • По сравнению с GRU или LSTM обучение происходит намного быстрее, потому что они не связаны конкатенацией, как рекуррентные нейронные сети.
Недостатки одномерной свертки:
  • Когда для заполнения установлено то же самое, выходные данные на временном шаге t свернуты с предыдущим t-1 и будущим временным шагом t+1. Следовательно, это нарушает принцип авторегрессии.
  • Когда заполнение установлено как допустимое, длина входных и выходных последовательностей изменяется, что требуется для вычисления остаточных соединений (подробнее об этом позже).

Это расчищает путь для причинно-следственной свертки.

Примечание. Плюсы и минусы, которые я упоминаю здесь, относятся к этому вопросу.

Что такое одномерная причинная свертка?

Это определяется как свертка, где выходные данные во время t свернуты только с элементами из предыдущего слоя во время t и ранее.

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

Преимущества каузальной 1D свертки:
  • Причинно-следственная свертка не учитывает будущие временные шаги, которые являются критерием построения генеративных моделей.
Недостатки каузальной одномерной свертки:
  • Причинная свертка не может вернуться в прошлое или к временным шагам, которые произошли ранее в последовательности. Поэтому рецептивное поле каузальной свертки очень низкое. Рецептивное поле сети относится к количеству входов, которые влияют на выход:

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

Это подводит нас к концепции причинно-расширенной одномерной свертки.

Что такое причинно-следственная расширенная одномерная свертка?

Причинный 1D-сверточный слой с дырами или промежутками между значениями ядра называется расширенной 1D-сверткой.

Количество добавляемых пробелов определяется коэффициентом расширения. Он определяет принимающий домен сети. Ядро размера k и скорости расширения d имеет d-1 дырку между каждым значением k.

Как вы можете видеть здесь, свертывание ядра 3*3 с входом 7*7 с коэффициентом расширения 2 дает рецептивное поле 5*5.

Преимущества расширенной одномерной причинной свертки:
  • Расширение одномерных сверточных сетей увеличивает рецептивное поле за счет экспоненциального увеличения скорости расширения каждого скрытого слоя:

Как вы можете видеть здесь, на вывод влияют все входы. Следовательно, принятый домен сети — 16.

Остаточный блок WaveNet:

Блок содержит остаточные и пропускные соединения, которые просто добавляются для ускорения сходимости модели:

Рабочий процесс WaveNet:
  • Входные данные подаются в каузальную одномерную свертку
  • Затем выходные данные подаются на два разных расширенных одномерных сверточных слоя с сигмовидной и тангенциальной активациями.
  • Умножение двух элементов с разными значениями активации с последующим пропуском соединений
  • Добавление соединения с пропуском и каузального вывода 1D на элементах приводит к остаточным значениям.
  • Пропускайте соединения и причинно-следственные одномерные выходные данные для вычисления остатков

Метод 2: метод долговременной кратковременной памяти (LSTM)

Другой способ автоматического создания музыки основан на моделях долговременной кратковременной памяти (LSTM). Подготовка входных и выходных последовательностей аналогична WaveNet. На каждом временном шаге значение амплитуды заносится в блок долговременной кратковременной памяти — затем вычисляется скрытый вектор и передается на следующий временной шаг.

в $чТекущий скрытый вектор в момент времени t$ основан на $hтекущий вход $a в момент времени t$t$ и предыдущий скрытый вектор $h{t-1}$ вычислено. Вот как можно получить информацию о последовательности в любой рекуррентной нейронной сети:

Преимущества LSTM:
  • Захват информации о порядке, которая встречается во входной последовательности
Недостатки LSTM:
  • Поскольку он обрабатывает ввод последовательно, он требует много времени на обучение.

Реализация - Автоматически генерировать музыку с помощью Python

Ожидание закончилось! Давайте разработаем сквозную модель, которая автоматически генерирует музыку. Откройте Jupyter Notebook или Colab (или любую другую IDE, которая вам нравится).

Загрузите набор данных:Я скачал и объединил несколько файлов классической музыки для цифрового пианино из множества источников. Вы можете скачать окончательный набор данных отсюда.

https://drive.google.com/file/d/1qnQVK17DNVkU19MgVA4Vg88zRDvwCRXw/view?usp=sharing

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

from numpy.random import seed
seed(1)
from tensorflow import set_random_seed
set_random_seed(2)

библиотека импорта:

Music 21 — это библиотека Python, разработанная MIT для понимания музыкальных данных. MIDI — это стандартный формат для хранения музыкальных файлов (расшифровывается как Musical Instrument Digital Interface). MIDI-файлы содержат инструкции, а не фактический звук. Поэтому занимает очень мало места. Вот почему обычно предпочитают передавать файлы.

#处理MIDI文件
from music21 import * 

#数组处理
import numpy as np     
import os

#随机数生成
import random         

#keras构建深度学习模型
from keras.layers import * 
from keras.models import *
import keras.backend as K

читать данные:

Определите функцию для чтения MIDI-файла. Он возвращает набор нот и аккордов в музыкальном файле.


def read_midi(file):
  notes=[]
  notes_to_parse = None

  #解析MIDI文件
  midi = converter.parse(file)
  #基于乐器分组
  s2 = instrument.partitionByInstrument(midi)

  #遍历所有的乐器
  for part in s2.parts:
    #只选择钢琴
    if 'Piano' in str(part): 
      notes_to_parse = part.recurse() 
      #查找特定元素是音符还是和弦
      for element in notes_to_parse:
        if isinstance(element, note.Note):
          notes.append(str(element.pitch))
        elif isinstance(element, chord.Chord):
          notes.append('.'.join(str(n) for n in element.normalOrder))
      
  return notes

Прочитать MIDI-файл из каталога:

#读取所有文件名
files=[i for i in os.listdir() if i.endswith(".mid")]

#读取每个midi文件
all_notes=[]
for i in files:
  all_notes.append(read_midi(i))

#所有midi文件的音符和和弦
notes = [element for notes in all_notes for element in notes]

Подготовьте входные и выходные последовательности, упомянутые в статье:

#输入序列的长度
no_of_timesteps = 128      

n_vocab = len(set(notes))  
pitch = sorted(set(item for item in notes))  

#为每个note分配唯一的值
note_to_int = dict((note, number) for number, note in enumerate(pitch))  
#准备输入和输出序列
X = []
y = []
for notes in all_notes:
  for i in range(0, len(notes) - no_of_timesteps, 1):
    input_ = notes[i:i + no_of_timesteps]
    output = notes[i + no_of_timesteps]
    X.append([note_to_int[note] for note in input_])
    y.append(note_to_int[output])

Входные данные для сверточных 1D или LSTM должны быть в форме (выборки, временные шаги, функции). Итак, давайте изменим входной массив до желаемой формы. Обратите внимание, что количество признаков на каждом временном шаге равно 1:

X = np.reshape(X, (len(X), no_of_timesteps, 1))
#标准化输入
X = X / float(n_vocab)   

Здесь я определил две архитектуры — WaveNet и LSTM. Пожалуйста, попробуйте эти две архитектуры, чтобы понять важность архитектуры WaveNet.

def lstm():
  model = Sequential()
  model.add(LSTM(128,return_sequences=True))
  model.add(LSTM(128))
  model.add(Dense(256))
  model.add(Activation('relu'))
  model.add(Dense(n_vocab))
  model.add(Activation('softmax'))
  model.compile(loss='sparse_categorical_crossentropy', optimizer='adam')
  return model   

Я упростил структуру WaveNet, не добавляя остаточных и пропущенных соединений, потому что эффект этих слоев заключается в улучшении более быстрой конвергенции (в то время как WaveNet принимает необработанный звук в качестве входных данных). Но в нашем случае входными данными будет набор узлов и аккордов, так как мы генерируем музыку:

K.clear_session()
def simple_wavenet():
  no_of_kernels=64
  num_of_blocks= int(np.sqrt(no_of_timesteps)) - 1 

  model = Sequential()
  for i in range(num_of_blocks):
    model.add(Conv1D(no_of_kernels,3,dilation_rate=(2**i),padding='causal',activation='relu'))
  model.add(Conv1D(1, 1, activation='relu', padding='causal'))
  model.add(Flatten())
  model.add(Dense(128, activation='relu'))
  model.add(Dense(n_vocab, activation='softmax'))
  model.compile(loss='sparse_categorical_crossentropy', optimizer='adam')
  return model

Определите обратный вызов для сохранения модели через каждые 50 эпох:

import keras
mc = keras.callbacks.ModelCheckpoint('model{epoch:03d}.h5', save_weights_only=False, period=50)

Создайте и обучите модель с размером пакета 128:

model = simple_wavenet()
model.fit(X,np.array(y), epochs=300, batch_size=128,callbacks=[mc])

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

def generate_music(model, pitch, no_of_timesteps, pattern):
    
    int_to_note = dict((number, note) for number, note in enumerate(pitch))
    prediction_output = []
    
    # 生成50个
    for note_index in range(50):
        #输入数据
        input_ = np.reshape(pattern, (1, len(pattern), 1))
        #预测并选出最大可能的元素
        proba = model.predict(input_, verbose=0)
        index = np.argmax(proba)
        
        pred = int_to_note[index]
        prediction_output.append(pred)
        pattern = list(pattern)
        pattern.append(index/float(n_vocab))
        #将第一个值保留在索引0处
        pattern = pattern[1:len(pattern)]

    return prediction_output

Вот функция, которая конвертирует музыку, состоящую из MIDI-файла:

def convert_to_midi(prediction_output):
    offset = 0
    output_notes = []

    # 根据模型生成的值创建音符和和弦对象
    for pattern in prediction_output:
        # 模式是和弦
        if ('.' in pattern) or pattern.isdigit():
            notes_in_chord = pattern.split('.')
            notes = []
            for current_note in notes_in_chord:
                new_note = note.Note(int(current_note))
                new_note.storedInstrument = instrument.Piano()
                notes.append(new_note)
            new_chord = chord.Chord(notes)
            new_chord.offset = offset
            output_notes.append(new_chord)
        # 模式是音符
        else:
            new_note = note.Note(pattern)
            new_note.offset = offset
            new_note.storedInstrument = instrument.Piano()
            output_notes.append(new_note)

        # 指定两个音符之间的持续时间
        offset+  = 0.5
       # offset += random.uniform(0.5,0.9)

    midi_stream = stream.Stream(output_notes)
    midi_stream.write('midi', fp='music.mid')

Теперь давайте сочиним нашу собственную музыку!

#为第一次迭代选择随机块
start = np.random.randint(0, len(X)-1)
pattern = X[start]
#载入最好的模型
model=load_model('model300.h5')
#生成和保存音乐
music = generate_music(model,pitch,no_of_timesteps,pattern)
convert_to_midi(music)

Ниже представлены несколько мелодий, созданных нашими моделями. Время наслаждаться музыкой!

https://cdn.analyticsvidhya.com/wp-content/uploads/2019/12/music1fast.mp3

https://cdn.analyticsvidhya.com/wp-content/uploads/2019/12/music2fast.mp3

https://cdn.analyticsvidhya.com/wp-content/uploads/2019/12/music3fast.mp3

Круто, правда? Но ваше обучение на этом не заканчивается. Вот несколько способов дальнейшего улучшения производительности модели:

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

конец

Глубокое обучение имеет широкий спектр применений в нашей повседневной жизни. Ключевым шагом в решении любой проблемы является понимание постановки задачи, ее формулировка и определение архитектуры решения проблемы.

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

Сводная станция блога о технологиях искусственного интеллекта Panchuang: http://docs.panchuang.net/PyTorch, официальная учебная станция на китайском языке: http://pytorch.panchuang.net/OpenCV, официальный китайский документ: http://woshicver.com/