Композитор с долгой кратковременной памятью

Original author: Jason Rampe
  • Translation

Автоматическое сочинение музыки



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

Я в течение нескольких лет предпринимал примитивные попытки автоматического сочинения музыки для Visions of Chaos. В основном при этом использовались простые математические формулы или генетические мутации случайных последовательностей нот. Добившись недавно скромного успеха в изучении и применении TensorFlow и нейронных сетей для поиска клеточных автоматов, я решил попробовать использовать нейронные сети для создания музыки.

Как это работает


Композитор обучает нейросеть с долгой кратковременной памятью (Long short-term memory, LSTM). LSTM-сети хорошо подходят для предсказания того, «что встретится дальше» в последовательностях данных. Подробнее о LSTM можно прочитать здесь.


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


Схемы внутреннего устройства LSTM могут казаться пугающими, но использование TensorFlow и/или Keras сильно упрощают создание LSTM и эксперименты с ними.

Исходная музыка для обучения моделей


Для таких простых LSTM-сетей нам достаточно, чтобы исходные композиции представляли собой один канал midi. Отлично для этого подходят файлы midi с соло на пианино. Я нашёл файлы midi с пианинными соло на Classical Piano Midi Page и mfiles, и использовал их для обучения своих моделей.

Музыку разных композиторов я поместил в отдельные папки. Благодаря этому пользователь может выбрать Баха, нажать на кнопку Compose и получить композицию, которая (надеюсь) будет походить на Баха.

Модель LSTM


Моделью, на основании которого я писал код, был выбран этот пример автора Sigurður Skúli Sigurgeirsson, о котором он подробнее пишет здесь.

Я запустил выполнение скрипта lstm.py и через 15 часов он завершил обучение. Когда я запустил predict.py для генерации файлов midi, то был разочарован, потому что они состояли из одной повторяющейся ноты. Дважды повторив обучение, я получил такие же результаты.

Исходная модель

model = Sequential()
model.add(CuDNNLSTM(512,input_shape=(network_input.shape[1], network_input.shape[2]),return_sequences=True))
model.add(Dropout(0.3))
model.add(CuDNNLSTM(512, return_sequences=True))
model.add(Dropout(0.3))
model.add(CuDNNLSTM(512))
model.add(Dense(256))
model.add(Dropout(0.3))
model.add(Dense(n_vocab))
model.add(Activation('softmax'))
model.compile(loss='categorical_crossentropy', optimizer='rmsprop',metrics=["accuracy"])

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


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

model = Sequential()
model.add(CuDNNLSTM(512, input_shape=(network_input.shape[1], network_input.shape[2]), return_sequences=True))
model.add(Dropout(0.2))
model.add(BatchNormalization())
model.add(CuDNNLSTM(256))
model.add(Dropout(0.2))
model.add(BatchNormalization())
model.add(Dense(128, activation="relu"))
model.add(Dropout(0.2))
model.add(BatchNormalization())
model.add(Dense(n_vocab))
model.add(Activation('softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adam',metrics=["accuracy"])

Она компактнее и в ней меньше слоёв LSTM. Также я добавил BatchNormalization, увидев его в видео sentdex. Скорее всего, существуют более качественные модели, но эта вполне неплохо работала во всех моих сеансах обучения.

Заметьте, что в обеих моделях я заменил LSTM на CuDNNLSTM. Так я добился гораздо более быстрого LSTM-обучения благодаря использованию Cuda. Если у вас нет GPU с поддержкой Cuda, то придётся пользоваться LSTM. Спасибо sendtex за этот совет. Обучение новых моделей и сочинение файлов midi при использовании CuDNNLSTM выполняется примерно в пять раз быстрее.

Как долго следует обучать модель


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

Но как узнать на каком количестве эпох остановиться?

Простое решение заключается в добавлении обратного вызова, который сохраняет модель и график точности/потерь через каждые 50 эпох на прогоне обучения в 500 эпох. Благодаря этому после завершения обучения у вас получатся модели и графики с инкрементом в 50 эпох, показывающие, как именно проходит обучение.

Вот результаты графиков одного прогона с сохранением каждых 50 эпохах, объединённые в один анимированный GIF.


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

Нужно использовать модель с количеством эпох, соответствующим моменту, когда графики впервые достигли своих пределов. Для показанного выше графика это будет 150 эпох. Если использовать более «старые» модели, то они будут переобучены и скорее всего приведут к простому копированию исходного материала.

Соответствующая этим графам модель обучалась на файлах midi категории «Гимны» (Anthems), взятых отсюда.



Выходные midi-данные в модели с 150 эпохами.



Выходные midi-данные в модели с 100 эпохами.

Даже модель с 100 эпохами может слишком точно копировать исходник. Это может происходить из-за относительно малой выборки файлов midi для обучения. При большем количестве нот обучение проходит лучше.

Когда обучение проходит плохо



На изображении выше показан пример того, что иногда может происходить и происходит во время обучения. Потери уменьшаются, а точность повышается, как и обычно, но внезапно они начинают сходить с ума. На этом этапе возможно тоже стоит остановиться. Модель больше не будет (по крайней мере, на моём опыте) снова обучаться правильно. В этом случае сохранённая модель с 100 эпохами ещё слишком случайна, а с 150 эпохами уже прошла момент сбоя модели. Теперь я сохраняюсь через каждые 25 эпох, чтобы точно найти идеальный момент модели с наилучшим обучением, ещё до того, как она переобучится и придёт к сбою.


Ещё один пример ошибки обучения. Эта модель обучалась на файлах midi, взятых отсюда. В этом случае она хорошо держалась чуть дольше, чем 200 эпох. При использовании модели с 200 эпохами получается следующий результат в Midi.



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

Другие примеры




Модель с 75 эпохами, созданная на основании композиций Шопена.



Модель с 50 эпохами, основанная на Midi-файлах рождественских композиций.



Модель с 100 эпохами, основанная на Midi-файлах рождественских композиций. Но очень ли они «рождественские»?



Модель с 300 эпохами, основанная на Midi-файлах Баха, взятых отсюда и отсюда.



Модель с 200 эпохами, основанная на единственном Midi-файле Балакирева, взятого здесь.



Модель с 200 эпохами, основанная на композициях Дебюсси.



Модель с 175 эпохами, основанная на композициях Моцарта.



Модель с 100 эпохами, основанная на композициях Шуберта.



Модель с 200 эпохами, основанная на композициях Шумана.



Модель с 200 эпохами, основанная на композициях Чайковского.



Модель с 175 эпохами, основанная на народных песнях.



Модель с 100 эпохами, основанная на колыбельных.



Модель с 100 эпохами, основанная на музыке для свадеб.



Модель с 200 эпохами, основанная на моих собственных файлах midi, взятых из моих саундтреков к видео на YouTube. Возможно, она немного переобучена, потому что в основном генерирует копии моих коротких одно- и двухтактных файлов midi.

Партитуры


Получив файлы midi, можно воспользоваться онлайн-инструментами наподобие SolMiRe, чтобы преобразовать их в партитуры. Ниже показана партитура представленного выше файла midi Softology с 200 эпохами.



Где можно протестировать композитора


LSTM Composer теперь включён в Visions of Chaos.


Выберите стиль из раскрывающегося списка и нажмите Compose. Если у вас установлены минимально необходимые Python и TensorFlow (инструкции см. здесь), то за несколько секунд (если у вас быстрый GPU) вы получите новый сочинённый машиной файл midi, который можно слушать и использовать для любой другой цели. Никаких авторских прав, никаких лицензионных отчислений. Если вам не понравятся результаты, то можете снова нажать на Compose и через несколько секунд будет готова новая композиция.

Результаты пока нельзя считать полноценными композициями, но в них есть интересные небольшие последовательности нот, которые я буду использовать для создания музыки в будущем. В этом отношении LSTM-композитор может быть хорошим источником вдохновения для написания новых композиций.

Исходники на Python


Ниже приведён использованный мной код скриптов на Python для обучения LSTM и прогнозирования. Чтобы эти скрипты работали, необязательно устанавливать Visions of Chaos, а обучение и генерирование midi будут работать из командной строки.

Вот скрипт обучения lstm_music_train.py

lstm_music_train.py
# based on code from https://github.com/Skuldur/Classical-Piano-Composer
# to use this script pass in;
# 1. the directory with midi files
# 2. the directory you want your models to be saved to
# 3. the model filename prefix
# 4. how many total epochs you want to train for
# eg python -W ignore "C:\\LSTM Composer\\lstm_music_train.py" "C:\\LSTM Composer\\Bach\\" "C:\\LSTM Composer\\" "Bach" 500

import os
import tensorflow as tf

# ignore all info and warning messages
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' 
tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.ERROR)

import glob
import pickle
import numpy
import sys
import keras
import matplotlib.pyplot as plt

from music21 import converter, instrument, note, chord
from datetime import datetime
from keras.models import Sequential
from keras.layers.normalization import BatchNormalization
from keras.layers import Dense
from keras.layers import Dropout
from keras.layers import CuDNNLSTM
from keras.layers import Activation
from keras.utils import np_utils
from keras.callbacks import TensorBoard
from shutil import copyfile

# name of midi file directory, model directory, model file prefix, and epochs
mididirectory = str(sys.argv[1])
modeldirectory = str(sys.argv[2])
modelfileprefix = str(sys.argv[3])
modelepochs = int(sys.argv[4])

notesfile = modeldirectory + modelfileprefix + '.notes'

# callback to save model and plot stats every 25 epochs
class CustomSaver(keras.callbacks.Callback):
	def __init__(self):
		self.epoch = 0	
	# This function is called when the training begins
	def on_train_begin(self, logs={}):
		# Initialize the lists for holding the logs, losses and accuracies
		self.losses = []
		self.acc = []
		self.logs = []
	def on_epoch_end(self, epoch, logs={}):
		# Append the logs, losses and accuracies to the lists
		self.logs.append(logs)
		self.losses.append(logs.get('loss'))
		self.acc.append(logs.get('acc')*100)
		# save model and plt every 50 epochs
		if (epoch+1) % 25 == 0:
			sys.stdout.write("\nAuto-saving model and plot after {} epochs to ".format(epoch+1)+"\n"+modeldirectory + modelfileprefix + "_" + str(epoch+1).zfill(3) + ".model\n"+modeldirectory + modelfileprefix + "_" + str(epoch+1).zfill(3) + ".png\n\n")
			sys.stdout.flush()
			self.model.save(modeldirectory + modelfileprefix + '_' + str(epoch+1).zfill(3) + '.model')
			copyfile(notesfile,modeldirectory + modelfileprefix + '_' + str(epoch+1).zfill(3) + '.notes');
			N = numpy.arange(0, len(self.losses))
			# Plot train loss, train acc, val loss and val acc against epochs passed
			plt.figure()
			plt.subplots_adjust(hspace=0.7)
			plt.subplot(2, 1, 1)
			# plot loss values
			plt.plot(N, self.losses, label = "train_loss")
			plt.title("Loss [Epoch {}]".format(epoch+1))
			plt.xlabel('Epoch')
			plt.ylabel('Loss')
			plt.subplot(2, 1, 2)
			# plot accuracy values
			plt.plot(N, self.acc, label = "train_acc")
			plt.title("Accuracy % [Epoch {}]".format(epoch+1))
			plt.xlabel("Epoch")
			plt.ylabel("Accuracy %")
			plt.savefig(modeldirectory + modelfileprefix + '_' + str(epoch+1).zfill(3) + '.png')
			plt.close()
			
# train the neural network
def train_network():

	sys.stdout.write("Reading midi files...\n\n")
	sys.stdout.flush()

	notes = get_notes()

	# get amount of pitch names
	n_vocab = len(set(notes))

	sys.stdout.write("\nPreparing note sequences...\n")
	sys.stdout.flush()

	network_input, network_output = prepare_sequences(notes, n_vocab)

	sys.stdout.write("\nCreating CuDNNLSTM neural network model...\n")
	sys.stdout.flush()

	model = create_network(network_input, n_vocab)

	sys.stdout.write("\nTraining CuDNNLSTM neural network model...\n\n")
	sys.stdout.flush()

	train(model, network_input, network_output)

# get all the notes and chords from the midi files
def get_notes():

	# remove existing data file if it exists
	if os.path.isfile(notesfile):
		os.remove(notesfile)
	
	notes = []

	for file in glob.glob("{}/*.mid".format(mididirectory)):
		midi = converter.parse(file)

		sys.stdout.write("Parsing %s ...\n" % file)
		sys.stdout.flush()

		notes_to_parse = None

		try: # file has instrument parts
			s2 = instrument.partitionByInstrument(midi)
			notes_to_parse = s2.parts[0].recurse() 
		except: # file has notes in a flat structure
			notes_to_parse = midi.flat.notes

		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))

	with open(notesfile,'wb') as filepath:
		pickle.dump(notes, filepath)

	return notes

# prepare the sequences used by the neural network
def prepare_sequences(notes, n_vocab):
	sequence_length = 100

	# get all pitch names
	pitchnames = sorted(set(item for item in notes))

	 # create a dictionary to map pitches to integers
	note_to_int = dict((note, number) for number, note in enumerate(pitchnames))

	network_input = []
	network_output = []

	# create input sequences and the corresponding outputs
	for i in range(0, len(notes) - sequence_length, 1):
		sequence_in = notes[i:i + sequence_length] # needs to take into account if notes in midi file are less than required 100 ( mod ? )
		sequence_out = notes[i + sequence_length]  # needs to take into account if notes in midi file are less than required 100 ( mod ? )
		network_input.append([note_to_int[char] for char in sequence_in])
		network_output.append(note_to_int[sequence_out])

	n_patterns = len(network_input)

	# reshape the input into a format compatible with CuDNNLSTM layers
	network_input = numpy.reshape(network_input, (n_patterns, sequence_length, 1))
	# normalize input
	network_input = network_input / float(n_vocab)

	network_output = np_utils.to_categorical(network_output)

	return (network_input, network_output)

# create the structure of the neural network
def create_network(network_input, n_vocab):

	'''
	""" create the structure of the neural network """
	model = Sequential()
	model.add(CuDNNLSTM(512, input_shape=(network_input.shape[1], network_input.shape[2]), return_sequences=True))
	model.add(Dropout(0.3))
	model.add(CuDNNLSTM(512, return_sequences=True))
	model.add(Dropout(0.3))
	model.add(CuDNNLSTM(512))
	model.add(Dense(256))
	model.add(Dropout(0.3))
	model.add(Dense(n_vocab))
	model.add(Activation('softmax'))
	model.compile(loss='categorical_crossentropy', optimizer='rmsprop',metrics=["accuracy"])
	'''
	
	model = Sequential()
	
	model.add(CuDNNLSTM(512, input_shape=(network_input.shape[1], network_input.shape[2]), return_sequences=True))
	model.add(Dropout(0.2))
	model.add(BatchNormalization())
	
	model.add(CuDNNLSTM(256))
	model.add(Dropout(0.2))
	model.add(BatchNormalization())
	
	model.add(Dense(128, activation="relu"))
	model.add(Dropout(0.2))
	model.add(BatchNormalization())
	
	model.add(Dense(n_vocab))
	model.add(Activation('softmax'))
	model.compile(loss='categorical_crossentropy', optimizer='adam',metrics=["accuracy"])
	
	return model

# train the neural network
def train(model, network_input, network_output):
	
	# saver = CustomSaver()
	# history = model.fit(network_input, network_output, epochs=modelepochs, batch_size=50, callbacks=[tensorboard])
	history = model.fit(network_input, network_output, epochs=modelepochs, batch_size=50, callbacks=[CustomSaver()])

	# evaluate the model
	print("\nModel evaluation at the end of training")
	train_acc = model.evaluate(network_input, network_output, verbose=0)
	print(model.metrics_names)
	print(train_acc)
	
	# save trained model
	model.save(modeldirectory + modelfileprefix + '_' + str(modelepochs) + '.model')

	# delete temp notes file
	os.remove(notesfile)
	
if __name__ == '__main__':
	train_network()

А вот скрипт генерации midi lstm_music_predict.py:

lstm_music_predict.py
# based on code from https://github.com/Skuldur/Classical-Piano-Composer
# to use this script pass in;
# 1. path to notes file
# 2. path to model
# 3. path to midi output
# eg python -W ignore "C:\\LSTM Composer\\lstm_music_predict.py" "C:\\LSTM Composer\\Bach.notes" "C:\\LSTM Composer\\Bach.model" "C:\\LSTM Composer\\Bach.mid"

# ignore all info and warning messages
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' 
import tensorflow as tf
tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.ERROR)

import pickle
import numpy
import sys
import keras.models

from music21 import instrument, note, stream, chord
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
from keras.layers import Activation

# name of weights filename
notesfile = str(sys.argv[1])
modelfile = str(sys.argv[2])
midifile = str(sys.argv[3])

# generates a piano midi file
def generate():
	sys.stdout.write("Loading notes data file...\n\n")
	sys.stdout.flush()

	#load the notes used to train the model
	with open(notesfile, 'rb') as filepath:
		notes = pickle.load(filepath)

	sys.stdout.write("Getting pitch names...\n\n")
	sys.stdout.flush()

	# Get all pitch names
	pitchnames = sorted(set(item for item in notes))
	# Get all pitch names
	n_vocab = len(set(notes))

	sys.stdout.write("Preparing sequences...\n\n")
	sys.stdout.flush()

	network_input, normalized_input = prepare_sequences(notes, pitchnames, n_vocab)

	sys.stdout.write("Loading LSTM neural network model...\n\n")
	sys.stdout.flush()

	model = create_network(normalized_input, n_vocab)

	sys.stdout.write("Generating note sequence...\n\n")
	sys.stdout.flush()

	prediction_output = generate_notes(model, network_input, pitchnames, n_vocab)

	sys.stdout.write("\nCreating MIDI file...\n\n")
	sys.stdout.flush()

	create_midi(prediction_output)

# prepare the sequences used by the neural network
def prepare_sequences(notes, pitchnames, n_vocab):
	# map between notes and integers and back
	note_to_int = dict((note, number) for number, note in enumerate(pitchnames))

	sequence_length = 100
	network_input = []
	output = []
	for i in range(0, len(notes) - sequence_length, 1):
		sequence_in = notes[i:i + sequence_length]
		sequence_out = notes[i + sequence_length]
		network_input.append([note_to_int[char] for char in sequence_in])
		output.append(note_to_int[sequence_out])

	n_patterns = len(network_input)

	# reshape the input into a format compatible with LSTM layers
	normalized_input = numpy.reshape(network_input, (n_patterns, sequence_length, 1))
	# normalize input
	normalized_input = normalized_input / float(n_vocab)

	return (network_input, normalized_input)

# create the structure of the neural network
def create_network(network_input, n_vocab):
	model = keras.models.load_model(modelfile)
	return model

# generate notes from the neural network based on a sequence of notes
def generate_notes(model, network_input, pitchnames, n_vocab):
	# pick a random sequence from the input as a starting point for the prediction
	start = numpy.random.randint(0, len(network_input)-1)

	int_to_note = dict((number, note) for number, note in enumerate(pitchnames))

	pattern = network_input[start]
	prediction_output = []

	# generate 500 notes
	for note_index in range(500):
		prediction_input = numpy.reshape(pattern, (1, len(pattern), 1))
		prediction_input = prediction_input / float(n_vocab)

		prediction = model.predict(prediction_input, verbose=0)

		index = numpy.argmax(prediction)
		result = int_to_note[index]
		prediction_output.append(result)

		pattern.append(index)
		pattern = pattern[1:len(pattern)]

		if (note_index + 1) % 50 == 0:
			sys.stdout.write("{} out of 500 notes generated\n".format(note_index+1))
			sys.stdout.flush()

	return prediction_output

# convert the output from the prediction to notes and create a midi file from the notes
def create_midi(prediction_output):
	offset = 0
	output_notes = []

	# create note and chord objects based on the values generated by the model
	for pattern in prediction_output:
		# pattern is a chord
		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)
		# pattern is a note
		else:
			new_note = note.Note(pattern)
			new_note.offset = offset
			new_note.storedInstrument = instrument.Piano()
			output_notes.append(new_note)

		# increase offset each iteration so that notes do not stack
		offset += 0.5

	midi_stream = stream.Stream(output_notes)

	midi_stream.write('midi', fp=midifile)

if __name__ == '__main__':
	generate()

Размеры файлов моделей


Недостаток включения нейросетей в Visions of Chaos заключается в размере файлов. Если бы генерация модели была быстрее, то я бы просто добавил кнопку, чтобы конечный пользователь мог сам обучать модели. Но поскольку некоторые из сеансов обучения множества моделей могут занимать по несколько дней, это не особо практично. Мне показалось, что лучше выполнить всё обучение и тестирование самому, и добавить только самые лучшие работающие модели. Это также означает, что конечному пользователю достаточно просто нажать на кнопку, и обученные модели создадут музыкальные композиции.

Каждая из моделей имеет размер 22 мегабайта. В условиях современного Интернета это не так уж много, но за годы разработки Visions of Chaos наращивал свой размер постепенно, и только недавно он внезапно увеличился с 70 до 91 МБ (из-за модели поиска клеточных автоматов). Поэтому я пока добавил в основной установщик Visions of Chaos только одну модель. Для пользователей, которым хочется большего, я выложил ссылку на ещё 1 ГБ моделей. Также они могут воспользоваться приведённым выше скриптом, чтобы создавать собственные модели, основанные на выбранных ими файлах midi.

Что дальше?


На данном этапе LSTM-композитор является простейшим примером использования нейронных сетей для сочинения музыки.

Я уже нашёл другие композиторы музыки на нейронных сетях, с которыми поэкспериментирую в будущем, поэтому можно ожидать, что в Visions of Chaos будут появляться новые возможности автоматического сочинения музыки.

Similar posts

Ads
AdBlock has stolen the banner, but banners are not teeth — they will be back

More

Comments 20

    0
    Без примеров — как-то неинтересно. Старый добрый Band In Box без нейросетей мог генерировать гармонию и мелодию по стандартам, тем более тут даже двоезвучий нет, не говоря об аккордах и смене тональностей.
      0
      В каком смысле «без примеров»? Ссылки на сгенерированные midi есть в посте.
      • UFO just landed and posted this here
          0
          Может у вас эти иконки не отображаются? Там каждая — это ссылка на файл midi
          Например = softology.com.au/gallery/midi/Softology_200.mid
            0
            Видимо, что-то поправили, или от провайдера зависит, на рабочем месте Yota и иконок не было совсем.
        0
        На иконки же можно нажимать — это ссылки на midi файлы с примерами.
          0
          Спасибо.
        0
        С керасом удобнее взять готовые keras.callbacks.ModelCheckpoint и TensorBoard (и часто LearningRateScheduler). Возможно стоит уменьшить Adam lr, часто значения около 10e-4… 10e-5 работают лучше. Ну и как следующий уровень — попробовать подходы с GAN, но там сложнее все обучить.

          0
          Стандартные GAN не работают с последовательностями. Есть методы использующие reinforcement learning (вроде SeqGAN), но это очень, очень медленно и неясно, насколько большие преимущества.

          Ну и еще по поводу статьи — GRU быстрее/точнее LSTM.
          0
          вот еще бы сведение и мастеринг
            0

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

              0
              Потому что сильно сложнее. Музыка-то что? 96 цифр и всё. И если ты Рохманинов, то иногда 12-нотные аккорды
                0
                Ну и процесс сочинения музыки интереснее, чем обработка. Более технические вещи бы автоматизировать. Например, вбиваешь «хочу звук как раммштайн 1997го» и выдает тебе схожий звук)
                  0

                  Так и я о том же, было бы круто :)
                  А в чём смысл делать автоматические клепалки псевдослучайных последовательностей нот, как в статье — в упор не понимаю.

                    0
                    конечно, тогда и сама профессия звукорежиссер вымрет полностью)
              0
              Если честно, то приведённые треки похожи друг на друга до степени смешения. Ритм вообще примитивен и описывается словами «бам-бам-бам-бам». Мне кажется, что-то в этом подходе не так, результат совсем слабенький. Сам факт, что так легко можно запустить генератор музыки, интересен. Но что-то меня не покидает ощущение, что где-то уже должны быть доступны генераторы с более высоким качеством.
                0
                Послушал. Как бы, генерация псевдослучайных секвенций, часто с перепутанными тональностями.
                Проигрыш дедушке Band In Box в сухую
                • UFO just landed and posted this here
                    0
                    Боюсь что это намного интереснее звучит. Недавно тоже была статья.
                      0

                      Вы какую версию TensorFlow использовали? Я только что убил два дня на проблему с резким падением точности на 1.10, пока не определил, что в 1.10-1.12 в BatchNormalization есть критический баг с переполнением. Используйте 1.13+

                      Only users with full accounts can post comments. Log in, please.