项目笔记(一):实验——用神经网络实现midi音乐旋律音轨的确定
零、寫(xiě)在前面
計(jì)劃要用seq2seq模型做一個(gè)交響樂(lè)編曲程序,encoder network的輸入是一個(gè)樂(lè)句旋律,decoder network的目標(biāo)target是這個(gè)樂(lè)句完整的管弦配樂(lè)版本。本文記錄的實(shí)驗(yàn)的目的是自動(dòng)提取出midi樂(lè)句的旋律音軌。
一、原理
參考這篇文獻(xiàn)中的方法:提取出這個(gè)樂(lè)句中各個(gè)音軌(樂(lè)器)的以下特征:
每個(gè)音軌的五個(gè)特征疊在一起,作為一個(gè)樂(lè)句的神經(jīng)網(wǎng)絡(luò)輸入。
對(duì)應(yīng)于主旋律的音軌的one-hot向量作為神經(jīng)網(wǎng)絡(luò)的目標(biāo)輸出。
之前文獻(xiàn)中,使用了其他的特征作為輸入,但那些特征并不十分合理。
二、技術(shù)細(xì)節(jié)
1.midi_to_features.py
這個(gè)文件用于提取出一個(gè)樂(lè)句各個(gè)音軌的5個(gè)特征值,用了python的pretty_midi包作為處理midi文件的工具。
import pretty_mididef get_avg_velocity(instrument):# 平均力度velocity = 0for note in instrument.notes:velocity += note.velocityvelocity /= len(instrument.notes)return velocitydef get_sum_duration(instrument):# 所有音符累加總時(shí)值duration = 0for note in instrument.notes:duration += note.end - note.startreturn durationdef get_types_of_duration(instrument):# 時(shí)值類(lèi)型duration = []for note in instrument.notes:duration.append(note.end - note.start)types = len(set(duration))return typesdef get_pitch_range(instrument):# 最高音與最低音之間的音程pitch = []for note in instrument.notes:pitch.append( note.pitch )sorted_pitch = sorted( set(pitch) )range = sorted_pitch[-1] - sorted_pitch[0]return rangedef get_second_pitch_range(instrument):# 第二高音與第二低音之間的音程pitch = []for note in instrument.notes:pitch.append( note.pitch )sorted_pitch = sorted( set(pitch) )range = sorted_pitch[-2] - sorted_pitch[1]return range上面的代碼中五個(gè)函數(shù)對(duì)應(yīng)于提取一個(gè)樂(lè)句中某一音軌(樂(lè)器)的五個(gè)特征值。
我們接下來(lái)將每一個(gè)音軌(樂(lè)器)的這五個(gè)值,壓縮到到一個(gè)向量中。
接下來(lái)還要寫(xiě)函數(shù)來(lái)遍歷數(shù)據(jù)集,提取出各個(gè)midi樂(lè)句的(一個(gè)樂(lè)句一個(gè)midi文件)特征值。將他們疊在一起,作為訓(xùn)練集的輸入。
def get_X_train():X_train = [[]]for i in range(13): # 一共切取了14個(gè)midi片段,其中13個(gè)作為訓(xùn)練樣本midi_file = 'data/x'+str(i+1)+'.mid'train_example = get_train_example(midi_file)if i==0:X_train[0]=train_exampleelse:X_train.append(train_example)return X_train類(lèi)似地,再寫(xiě)測(cè)試集:
def get_X_test():X_test = [[]]midi_file = 'data/x14.mid'train_example = get_train_example(midi_file)X_test[0]=train_examplereturn X_test2. features_to_melody.py
這個(gè)文件里用tensorflow構(gòu)建一個(gè)二層神經(jīng)網(wǎng)絡(luò),用matplotlib繪圖。我們使用鋼琴曲作為數(shù)據(jù)集,左右手各一個(gè)音軌,每個(gè)音軌5個(gè)特征值,所以一個(gè)樂(lè)句共有10個(gè)特征值。對(duì)應(yīng)的y值顯然也只有兩種可能。
from midi_to_features import * import tensorflow as tf import matplotlib.pyplot as plt import numpy as npn_x, n_y = 10, 2接下來(lái)我們制作訓(xùn)練集和測(cè)試集的輸入和輸出,我使用的數(shù)據(jù)中都是旋律再右手的,所以所有的輸出都相同。
# get training data X_train = get_X_train() Y_example = [1, 0] Y_train = [[]] for i in range (13):if i == 0:Y_train[0] = Y_exampleelse:Y_train.append( Y_example )#行列互換,使其符合tensorflow的輸入格式 X_train = list(map(list, zip(*X_train))) Y_train = list(map(list, zip(*Y_train))) print("X_train:", X_train) print("Y_train:", Y_train)# get testing data X_test = get_X_test() X_test = list(map(list, zip(*X_test))) Y_test = [[1],[0]] print("X_test:", X_test) print("Y_test:", Y_test)接下來(lái)是構(gòu)建神經(jīng)網(wǎng)絡(luò)的準(zhǔn)備工作:創(chuàng)建placeholder和初始化參數(shù)(用xavier來(lái)初始化所有w,用全零初始化b)。
# Create placeholders def create_placeholders(n_x, n_y):X = tf.placeholder(tf.float32, shape=[n_x, None])Y = tf.placeholder(tf.float32, shape=[n_y, None])return X, Y# Initialize the parameters def initialize_parameters():W1 = tf.get_variable("W1", [25, n_x], initializer=tf.contrib.layers.xavier_initializer())b1 = tf.get_variable("b1", [25, 1], initializer=tf.zeros_initializer())W2 = tf.get_variable("W2", [12, 25], initializer=tf.contrib.layers.xavier_initializer())b2 = tf.get_variable("b2", [12, 1], initializer=tf.zeros_initializer())W3 = tf.get_variable("W3", [n_y, 12], initializer=tf.contrib.layers.xavier_initializer())b3 = tf.get_variable("b3", [n_y, 1], initializer=tf.zeros_initializer())parameters = {"W1": W1,"b1": b1,"W2": W2,"b2": b2,"W3": W3,"b3": b3}return parameters神經(jīng)網(wǎng)絡(luò)的正向傳播,激活函數(shù)使用relu。
# Forward propagation def forward_propagation(X, parameters):W1 = parameters['W1']b1 = parameters['b1']W2 = parameters['W2']b2 = parameters['b2']W3 = parameters['W3']b3 = parameters['b3']Z1 = tf.add(tf.matmul(W1, X), b1)A1 = tf.nn.relu(Z1)Z2 = tf.add(tf.matmul(W2, A1), b2)A2 = tf.nn.relu(Z2)Z3 = tf.add(tf.matmul(W3, A2), b3)return Z3使用softmax作為輸出層,定義交叉熵?fù)p失。
# Compute Cost def compute_cost(Z3, Y):logits = tf.transpose(Z3)labels = tf.transpose(Y)cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits = logits, labels = labels))return cost現(xiàn)在我們可以開(kāi)始構(gòu)建整個(gè)模型了。
# the model def model(X_train, Y_train, X_test, Y_test,learning_rate = 0.0001, num_epochs = 1000,print_cost = True):n_x, n_y, = 10, 2, 13costs = []# 創(chuàng)建placeholderX, Y = create_placeholders(n_x, n_y)# 初始化參數(shù)parameters = initialize_parameters()# 神經(jīng)網(wǎng)絡(luò)前向傳播Z3 = forward_propagation(X, parameters)# 計(jì)算損失函數(shù)cost = compute_cost(Z3, Y)#用adam算法最小化損失函數(shù)optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)init = tf.global_variables_initializer()# 創(chuàng)建tensorflow的sessionwith tf.Session() as sess:sess.run(init)for epoch in range(num_epochs):_, Cost = sess.run([optimizer, cost], feed_dict={X: X_train, Y: Y_train})# 打印出cost的變化if print_cost == True and epoch % 100 == 0:print ("Cost after epoch %i: %f" % (epoch, Cost))costs.append(Cost)# 用matplotlib繪制 時(shí)間-損失圖像plt.plot(np.squeeze(costs))plt.ylabel('cost')plt.xlabel('iterations (per tens)')plt.title("Learning rate =" + str(learning_rate))plt.show()parameters = sess.run(parameters)print ("Parameters have been trained!")correct_prediction = tf.equal(tf.argmax(Z3), tf.argmax(Y))# 計(jì)算準(zhǔn)確率accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))print("Train Accuracy:", accuracy.eval({X: X_train, Y: Y_train}))print("Test Accuracy:", accuracy.eval({X: X_test, Y: Y_test}))return parametersparameters = model(X_train, Y_train, X_test, Y_test)3.數(shù)據(jù)集
這個(gè)實(shí)驗(yàn)只是為了驗(yàn)證可行性,用了很小很小的數(shù)據(jù)集(對(duì)應(yīng)無(wú)比強(qiáng)烈的過(guò)擬合)。我手工提取了莫扎特土耳其進(jìn)行曲(這是我寫(xiě)過(guò)的這首曲子的樂(lè)理分析)的一共14旋律材料(14個(gè)樂(lè)句)。13個(gè)作為訓(xùn)練集,最后一個(gè)作為測(cè)試集。他們可以在這里下載。
我使用的是降b小調(diào)的版本,但樂(lè)句整體的移調(diào)不會(huì)影響輸出,所以,never mind。
三、結(jié)論
Cost after epoch 0: 9.850606 Cost after epoch 100: 0.593675 Cost after epoch 200: 0.267264 Cost after epoch 300: 0.170038 Cost after epoch 400: 0.108876 Parameters have been trained! Train Accuracy: 1.0 Test Accuracy: 1.0我們看到,神經(jīng)網(wǎng)絡(luò)對(duì)于訓(xùn)練集擬合地很好,正確率100%(其實(shí)是過(guò)擬合),測(cè)試樣本Test Accuracy: 1.0,即算法正確地分類(lèi)了測(cè)試樣本。
這說(shuō)明,用神經(jīng)網(wǎng)絡(luò)實(shí)現(xiàn)midi音樂(lè)旋律音軌的確定,這一方法是可行的。
總結(jié)
以上是生活随笔為你收集整理的项目笔记(一):实验——用神经网络实现midi音乐旋律音轨的确定的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 研究GigE Vision(未完待续)
- 下一篇: F28M35调用IQmath库出错