Рекурсивные нейронные сети — пример генерации музыки
- четверг, 25 июня 2020 г. в 00:28:36
Сегодня попробуем создать простую музыку при помощи сетей LSTM.
Целю статьи есть указание возможностей сетей на практике, будет интересно какой результат получится у читателя, сможете оставить ссылки на свой варианты в комментариях.
Минимальные навыки, нужные читателю, чтобы мочь сделать собственный вариант:
Не буду одобрять комментарии, в которых есть суть только:
Мы используем входные данные в формате 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
Результат 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]
Создаются обучающие последовательности
Нашей модели будет поручено научиться прогнозировать следующий знак на основе 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])
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
В статии не описывал всех математических/технических нюансов машинного обучения, для заитересованых оставляю источники, которыми я пользовался. Пишите в коментарях, если что-то будет непонятно, постараюсь адвекватно ответить. Как и уже сказал, жду ваших вариантов!
Ссылки: