5.4. Имплементација
Системот за автоматско генерериње на македонска народна мелодија наречен MacedonMelody се состои од две python скрипти. Првата скрипта се користи за креирање и тренирање на моделот врз базата на податоци, додека во втората се генерира македонска народна мелодија врз база на тренираниот модел.
Скрипта 1 – macedon_melody_train.py
import glob # За да можеме да пристапиме локално во системот import pickle # За да ги зачуваме нотите во документ import numpy # За менување на формата на влезот на невронската мрежа from time import time from keras.models import Sequential from keras.layers import CuDNNLSTM from keras.layers import Dropout from keras.layers import Dense from keras.layers import Activation from keras.utils import np_utils from keras.callbacks import ModelCheckpoint from music21 import converter, instrument, note, chord, stream
def mac_notes(): # Функција за креирање вокабулар од ноти од сите муз. документи во базата на податоци за тренирање
macedonian_notes = [] # Листа за зачувување на сите ноти од МИДИ документите for file in glob.glob("mac_midi/*.mid"):
macedonian_midi = converter.parse(file) #Парсирање на нотен запис од фајл print("The song parsed is: %s " %file)
# macedonian_midi.show('text') # За прикажување на содржините на миди документите
mac_notes_to_be_parsed = None offsets = None try:
mac_notes_to_be_parsed = macedonian_midi.flat.notes
except:
mac_instruments = instrument.partitionByInstrument(macedonian_midi) mac_notes_to_be_parsed = mac_instruments.parts[0].recurse()
for element in mac_notes_to_be_parsed:
if isinstance(element, note.Note):
macedonian_notes.append(str(element.pitch))
elif isinstance(element, chord.Chord):
macedonian_notes.append('.'.join(str(m) for m in element.normalOrder))
with open('data/macedonian_notes','wb') as filepath:
pickle.dump(macedonian_notes, filepath)
return macedonian_notes # На излез дава листа со ноти
def io_neural_sequences(macedonian_notes,mac_notes_vocabulary): # Функција за дефинирање на влезната и излезната секвенца на моделот на невронската мрежа.
input_sequence = None output_sequence = None sequence_size = 150 n_patterns = 0 pitch_names = sorted(set(elem for elem in macedonian_notes)) mac_notes_to_int = dict((note, number) for number, note in enumerate(pitch_names)) i_neural_sequence = [] o_neural_sequence = [] for m in range(0, len(macedonian_notes)-sequence_size,1):
input_sequence = macedonian_notes[m:m + sequence_size] output_sequence = macedonian_notes[m + sequence_size] i_neural_sequence.append([mac_notes_to_int[char] for char in input_sequence]) o_neural_sequence.append(mac_notes_to_int[output_sequence])
n_patterns = len(i_neural_sequence) i_neural_sequence = numpy.reshape(i_neural_sequence, (n_patterns,sequence_size,1)) i_neural_sequence = i_neural_sequence / float(mac_notes_vocabulary) o_neural_sequence = np_utils.to_categorical(o_neural_sequence)
return (i_neural_sequence, o_neural_sequence) # На излез ни ги дава дефинираните внезна и излезна секвенца за невронската мрежа
def model_neural_netrowk(i_neural_sequence, mac_notes_vocabulary): # Функција за креирање на артитектура на секвенционен модел на невронска мрежа, кој се состои од 3 CuDNNLSTM слоја, 3 Dropout слоја, 2 Dense слоја и слој за активација.
model = Sequential() model.add(CuDNNLSTM(256,input_shape=(i_neural_sequence.shape[1], i_neural_sequence.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(256)) model.add(Dropout(0.3)) model.add(Dense(256)) model.add(Dense(mac_notes_vocabulary)) model.add(Activation('softmax')) model.compile(loss='categorical_crossentropy', optimizer='rmsprop') return model # На излез дава моделиран модел на LSTM невронска мрежа
def train_neural_network(model, i_neural_sequence, o_neural_sequence): # Функција за тренирање на невронската мрежа
filepath = "weights-{epoch:02d}-{loss:.4f}-bigger.hdf5" checkpoint = ModelCheckpoint(
filepath, monitor='loss', verbose=0, save_best_only=True, mode='min'
)
callbacks_list = [checkpoint] tensorboard = TensorBoard(log_dirr=”logs/{}”.format(time())) model.fit(i_neural_sequence, o_neural_sequence, epochs=50, batch_size=50, callbacks=callbacks_list)
if name == 'main':
macedonian_notes = mac_notes() # Ја повикуваме функцијата за креирање вокабулар од мак. ноти mac_notes_vocabulary = len(set(macedonian_notes)) mac_notes_vocabulary2 = len(macedonian_notes) print("Num vocab is: %s " % mac_notes_vocabulary) print("Size is: %s " % mac_notes_vocabulary2) i_neural_sequence, o_neural_sequence = io_neural_sequences(macedonian_notes,mac_notes_vocabulary) # Ја повикуваме функцијата која ни ги дава влезната и излезната секвенца за н. мрежа model = model_neural_netrowk(i_neural_sequence, mac_notes_vocabulary) # Ja повикуваме функцијата за креирање на моделот train_neural_network(model, i_neural_sequence, o_neural_sequence) # Ја повикуваме функцијата за тренирање на модел на невронска мрежа
Скрипта 2 – macedon_melody_predict.py
import pickle import numpy from music21 import instrument, note, stream, chord, meter from keras.models import Sequential from keras.layers import Dense from keras.layers import Dropout from keras.layers import CuDNNLSTM from keras.layers import Activation
def io_neural_sequences(macedonian_notes,mac_notes_vocabulary): # Функција за дефинирање на влезната и излезната секвенца на моделот на невронската мрежа.
input_sequence = None output_sequence = None n_i_neural_sequence = None sequence_size = 150 n_patterns = 0 pitch_names = sorted(set(elem for elem in macedonian_notes)) mac_notes_to_int = dict((note, number) for number, note in enumerate(pitch_names)) i_neural_sequence = [] o_neural_sequence = [] for m in range(0, len(macedonian_notes)-sequence_size,1):
input_sequence = macedonian_notes[m:m + sequence_size] output_sequence = macedonian_notes[m + sequence_size] i_neural_sequence.append([mac_notes_to_int[char] for char in input_sequence]) o_neural_sequence.append(mac_notes_to_int[output_sequence])
n_patterns = len(i_neural_sequence) n_i_neural_sequence = numpy.reshape(i_neural_sequence, (n_patterns,sequence_size,1)) n_i_neural_sequence = n_i_neural_sequence / float(mac_notes_vocabulary) return (i_neural_sequence, n_i_neural_sequence)
def model_neural_netrowk(i_neural_sequence, mac_notes_vocabulary): # Функција за креирање на артитектура на секвенционен модел на невронска мрежа (го има истиот модел на невронска мрежа за тренирање, но на излез не враќа модел туку ги вчитуваме тежините од веќе тренираниот модел
model = Sequential() model.add(CuDNNLSTM(256,input_shape=(i_neural_sequence.shape[1],neural_sequence.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(256)) model.add(Dropout(0.3)) model.add(Dense(256)) model.add(Dense(mac_notes_vocabulary)) model.add(Activation('softmax')) model.compile(loss='categorical_crossentropy', optimizer='rmsprop') model.load_weights('weights.hdf5') return model
def mac_notes_generation(model, i_neural_sequence, pitch_names,mac_notes_vocabulary): # Функција за декодирање на излезот од тренираниот модел на мрежа
start = numpy.random.randint(0, len(i_neural_sequence)-1) # Бираме случаен почеток за нота за секвенцата на новата мелодија int_to_mac_notes = dict((number, note) for number, note in enumerate(pitch_names)) # Мапирање на висината на нотите од цели броеви во речник од ноти pattern = i_neural_sequence[start] prediction_output = [] for note_index in range(400): # Генерирање на ноти за музичко дело со должина од приближно минута и 30 секунди
prediction_input = numpy.reshape(pattern, (1, len(pattern), 1)) n_prediction_input = prediction_input / float(mac_notes_vocabulary) prediction = model.predict(n_prediction_input, verbose=0) index = numpy.argmax(prediction) result = int_to_mac_notes[index] prediction_output.append(result) pattern.append(index) pattern = pattern[1:len(pattern)]
return prediction_output # На излез се добива низа со 400 генерирани ноти
def generate_macedon_melody(prediction_output): # Функција за декодирање на предвидените ноти во објекти Note и Chord, претставени во music21 за да можеме после да ја запишеме мелодијата во формат кој може да се слушне
offset = 0 mac_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 mac_output_notes.append(new_chord)
# Доколку запишаната вредност е нота else:
new_note = note.Note(pattern) new_note.offset = offset new_note.storedInstrument = instrument.Piano() mac_output_notes.append(new_note)
# Растојание на нотите, за да не се случи нивно повторување (Вредноста е добиена со истражување на растојанието помеѓу нотите во песните за тренирање со помош на функцијата .show() на потокот на податоци). offset += 0.5
mac_midi_stream = stream.Stream(mac_output_notes) mac_midi_stream.write('midi', fp='ai_mac_melody.mid') # Запишување на предвидената мелодија во .mid формат
if name == 'main':
#Вчитување на нотите врз кои беше трениран моделот with (open('data/macedonian_notes', 'rb')) as filepath:
macedonian_notes = pickle.load(filepath)
# Вокабулар на висина на ноти pitch_names = sorted(set(elem for elem in macedonian_notes)) # Бројот на различни висини на ноти во песните за тренирање mac_notes_vocabulary = len(set(macedonian_notes)) i_neural_sequence, n_i_neural_sequence = io_neural_sequences(macedonian_notes, mac_notes_vocabulary) model = model_neural_netrowk(n_i_neural_sequence, mac_notes_vocabulary) prediction_output = mac_notes_generation(model, i_neural_sequence, pitch_names,mac_notes_vocabulary) generate_macedon_melody(prediction_output) # Оваа функција генерира мак. народна мелодија и ја запишува во документ: ai_mac_melody.mid