每天逛一趟GitHub,向大神们学习。
1.拿出所有的音符
import glob
import pickle
from music21 import converter,instrument,note,chord,stream
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense,Dropout,LSTM,Activation,BatchNormalization
#from tensorflow.keras.utils import np_utils
from tensorflow.keras.callbacks import ModelCheckpoint
from keras.utils import np_utils
import numpy as np
#1.从midi文件中获取音符和和弦
def get_notes():
notes=[]
for file in glob.glob('./midi_songs/*.mid'):
midi=converter.parse(file)
print('Parsing %s'%file)
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('data/notes','wb') as f:
pickle.dump(notes,f)
return notes
2.准备用于循环神经网络训练的数据,整合序列数据
def prepare_sequences(notes,n_vocab):#vocab#有多少种音符
sequence_length=100#以100个notes为一个输入
pitchnames=sorted(set(item for item in notes))#将所有note整合成集合并按出现次数排序
note_to_int=dict((note,number) for number,note in enumerate(pitchnames))#将notes的内容和顺序排成字典,字符到数字的映射
network_input=[]
normalized_input=[]
network_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])
network_output.append([note_to_int[sequence_out]])
n_patterns=len(network_input)#一共有多少个以100个数字为输入的网络可以用的数据
normalized_input=np.reshape(network_input,(n_patterns,sequence_length,1))#一所有数据作为一个batch,数据变成rnn的输入格式
normalized_input=normalized_input/float(n_vocab)#输入数据标准化
network_output=np_utils.to_categorical(network_output)#输出的一维数字转换成独热编码格式
return (network_input,network_output,normalized_input,pitchnames)
3.创建循环训练网络
def creat_network(network_input,n_vocab):
model=Sequential()
model.add(LSTM(512,input_shape=(network_input.shape[1],network_input.shape[2]),recurrent_dropout=0.3,return_sequences=True))
model.add(LSTM(512,recurrent_dropout=0.3,return_sequences=True))
model.add(LSTM(512))
model.add(BatchNormalization())
model.add(Dropout(0.3))
model.add(Dense(256))
model.add(Activation('relu'))
model.add(BatchNormalization())
model.add(Dropout(0.3))
model.add(Dense(n_vocab))
model.add(Activation('softmax'))
model.compile(loss='categorical_crossentropy',optimizer='rmsprop')
return model
def train(model,network_input,network_output):
filepath="weights-improvement-{epoch:02d}-{loss:.4f}-bigger.hdf5"
checkpoint=ModelCheckpoint(filepath,monitor='loss',verbose=0,save_best_only=True,mode='min')
callbacks_list=[checkpoint]
model.fit(network_input, network_output, epochs=5, batch_size=128, callbacks=callbacks_list)
4.训练
def train_network():
notes=get_notes()
n_vocab=len(set(notes))
network_input,network_output,normalized_input,pitchnames=prepare_sequences(notes, n_vocab)
model=creat_network(normalized_input,n_vocab)
train(model,normalized_input,network_output)
return (notes,n_vocab,network_input,normalized_input,pitchnames)
if __name__=="__main__":
notes,n_vocab,network_input,normalized_input,pitchnames=train_network()
5.实际生成音乐
def generate_notes(model,network_input,pitchnames,n_vocab):
start=np.random.randint(0,len(network_input)-1)#随机生成一个序列的数字
print(start)
int_to_note={number:note for number,note in enumerate(pitchnames)}
pattern=network_input[start]
prediction_output=[]
for note_index in range(20):#生成500个notes
prediction_input=np.reshape(pattern, (1,len(pattern),1))
prediction_input=prediction_input/float(n_vocab)#归一化
prediction=model.predict(prediction_input,verbose=0)
index=np.argmax(prediction)#预测出来概率最大的哪一项
print(index)
result=int_to_note[index]
print(result)
prediction_output.append(result)
pattern.append(index)
pattern=pattern[1:len(pattern)]
return prediction_output
def create_midi(prediction_output):
""" convert the output from the prediction to notes and create a midi file
from the notes """
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='test_output.mid')
#开始生成
from tensorflow.keras.models import load_model
def generate(notes,n_vocab,network_input,normalized_input,pitchnames):
model=load_model('weights-improvement-05-4.4652-bigger.hdf5')
prediction_output= generate_notes(model,network_input,pitchnames,n_vocab)
create_midi(prediction_output)
generate(notes,n_vocab,network_input,normalized_input,pitchnames)
参考:https://github.com/Xunzhuo/LSTM-Music
资源:https://download.csdn.net/download/weixin_38226321/12619361