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

от автора

Сегодня попробуем создать простую музыку при помощи сетей LSTM.

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

  • Python3
  • BASH
  • jupyter-notebook.

Не буду одобрять комментарии, в которых есть суть только:

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

Входные данные

Мы используем входные данные в формате ABC
Примерные строки:

[V: S] (BA) !p!G2 |z AGA|(FG) A2| w: ple -na, Do-mi-nus te -cum, [V: A] F2       E2|z FEC|(DE) F2 | w: ple-na, Do-mi-nus te -cum, [V: T] (dc)     c2|z ccA|(Ac) c2 | w: ple -na, Do-mi-nus te -cum, [V: B] (B,,F,) C,2|z F,C,F,|(D,C,) F,2 | w: ple -na, Do-mi-nus te -cum,

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

Чтение файла

Для вашего удобства, используйте jupyter notebook .

import numpy as np import matplotlib.pyplot as plt import tensorflow as tf 

with open('my_song.abc', 'r') as f:     text = f.read()

Прослушивание песни

Чтобы прослушать песню, мы должны установить в нашу среду несколько дополнительных инструментов

!apt-get install -y -qq abcmidi timidity

Сохраняем выбранную песню в файл:

#этот шаг зависит от входных данных, тут нужен гибкий подход song = text.split('\n\n') with open('my_song.abc', "w") as f:     f.write(song)

Мы конвертируем в файл mid, а затем wav.

!abc2midi "my_song.abc" -o "my_song.mid" && timidity "my_song.mid" -Ow "my_song.wav"

Результат

from IPython.display import Audio Audio('my_song.wav') #ссылка #https://github.com/fuwiak/Habr/blob/master/my_song.wav

Время на LSTM

Результат my_song.wav оказывается неплохим, сейчас попробуем сделать свой вариант при помощи LSTM.

Создание обучающей выборки

#уникальные символы, найденные в песнях. vocab = set(text)  # словарь: ключ=символ, значение=индекс, указав символ, мы получаем его индекс char_to_index = {char_ :ind for ind, char_  in enumerate (vocab)} ind_to_char = np.array(vocab) text_as_int = np.array([char_to_index[c] for c in text])  #'X:1\nT:dfkjds ' ----- > [49 22 13  0 45 22 26 67 60 79 56 69 59] 

Генерация последовательности

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

  • input: строка из 100 символов
  • target: строка из 100 символов, но сдвинутая на 1.

Нашей модели будет поручено научиться прогнозировать следующий знак на основе 100 предыдущих. Это будет модель RNN версии "many to many", которая на самом деле будет прогнозировать один следующий символ, но в процессе обучения ошибка будет учитываться по всей последовательности (100 предсказаний).

 seq_length = 100 step = 10  sequences = np.array([text_as_int[i:i+seq_length+1] for i in range(0, len(text_as_int)-seq_length-1,step)]) input_text = np.array([seq[:-1] for seq in sequences])  target_text = np.array([seq[1:] for seq in sequences]) 

LSTM

from tensorflow.keras.models import Model from tensorflow.keras.layers import Input, LSTM, Dense, Embedding  vocab_size = len(vocab)  #new value embedding_dim = 256*2 rnn_units = 1024*2  x = Input(shape=(seq_length,)) e = Embedding(vocab_size, embedding_dim)(x) l = LSTM(rnn_units, return_sequences=True)(e) d = Dense(vocab_size, activation='softmax')(l) model = Model(inputs=x, outputs=d) model.summary()

Обучение сети

from tensorflow.keras.optimizers import Adam model.compile(optimizer=Adam(), loss='sparse_categorical_crossentropy')  EP=5 BS = 128  hist = model.fit(input_text, target_text, batch_size=BS, epochs=EP)

Создание музыки из модели

def generate_text(model, start_string, generation_length=100):    input_eval = np.array([char_to_index[s] for s in start_string])   x = np.zeros((1, seq_length))   x[0,-len(input_eval):] = input_eval[:]   text_generated = []    model.reset_states()   for i in range(generation_length):       predictions = model.predict(x)[0,-1]        predictions = predictions.astype(np.float64)       predictions = predictions/np.sum(predictions)           predicted_id = np.argmax(np.random.multinomial(1, predictions))       x[0,:-1] = x[0,1:]       x[0,-1] = predicted_id       text_generated.append([predicted_id])     return (start_string + ''.join(text_generated))

new_song = generate_text(model, "X:", generation_length=500) 

Наш результат

with open('new_song.abc', "w") as f:     f.write(new_song)

!abc2midi "new_song.abc" -o "new_song.mid" && timidity "new_song.mid" -Ow "new_song.wav"

 Audio('new_song.wav') #https://github.com/fuwiak/Habr/blob/master/new_song.wav

Итоги

В статии не описывал всех математических/технических нюансов машинного обучения, для заитересованых оставляю источники, которыми я пользовался. Пишите в коментарях, если что-то будет непонятно, постараюсь адвекватно ответить. Как и уже сказал, жду ваших вариантов!

Ссылки:

ссылка на оригинал статьи https://habr.com/ru/post/501550/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *