基于keras的人工作曲代碼積累

utils.py

包含的函數(shù)有

  • def convert_midi_to_mp3():: 將神經(jīng)網(wǎng)絡(luò)生成的MIDI文件轉(zhuǎn)換為MP3文件
  • def get_notes():: 從 music_midi 目錄中的所有 MIDI 文件里提取 note(音符)和 chord(和弦) return notes
  • def create_music(prediction):: 用神經(jīng)網(wǎng)絡(luò)'預(yù)測'的音樂數(shù)據(jù)來生成 MIDI 文件,再轉(zhuǎn)成 MP3 文件,最后一句調(diào)用了convert_midi_to_mp3()
  1. 使用方式: from utils import * ,然后直接調(diào)用函數(shù)即可,比如notes = get_notes()
    2.文件操作一般要引用import os, 文件操作建議寫法,同時(shí)積累形式字符串的寫法,如果用多個(gè),寫成format(xxx,xxx)
input_file = 'output.mid'
output_file = 'output.mp3'

if not os.path.exists(input_file):
        raise Exception("MIDI 文件 {} 不在此目錄下,請確保此文件被正確生成".format(input_file))

print('將 {} 轉(zhuǎn)換為 MP3'.format(input_file))
  1. 在代碼中想執(zhí)行命令行命令的寫法,建議每一個(gè)比較大的操作都打一個(gè)log,需要引用import subprocess.發(fā)現(xiàn)如果使用的時(shí)候用的是import,那么在使用時(shí)需要寫庫名
command = 'timidity {} -Ow -o - | ffmpeg -i - -acodec libmp3lame -ab 64k {}'.format(input_file, output_file)
    return_code = subprocess.call(command, shell=True)

    if return_code != 0:
        print('轉(zhuǎn)換時(shí)出錯(cuò),請查看出錯(cuò)信息')
    else:
        print('轉(zhuǎn)換完畢. 生成的文件是 {}'.format(output_file))
  1. glob.glob匹配所有符合條件的文件,并以 List 的形式返回,提前引用庫import glob
    for midi_file in glob.glob("music_midi/*.mid"):
        stream = converter.parse(midi_file)
  1. music21的操作見原代碼
  2. 判斷類型,用isinstance( , ),append()用于在list后面添加元素。string有 .join()。并且由于之前的note=[],所以相當(dāng)于是把list的符號轉(zhuǎn)成str輸出,奇妙的轉(zhuǎn)換 4.15.7
 for element in notes_to_parse:
            # 如果是 Note 類型,那么取它的音調(diào)
            if isinstance(element, note.Note):
                # 格式例如: E6
                notes.append(str(element.pitch))
            # 如果是 Chord 類型,那么取它各個(gè)音調(diào)的序號
            elif isinstance(element, chord.Chord):
                # 轉(zhuǎn)換后格式例如: 4.15.7
                notes.append('.'.join(str(n) for n in element.normalOrder))
  1. 如果目錄不存在,創(chuàng)建目錄
if not os.path.exists("data"):
     os.mkdir("data")
  1. 寫入文件,使用了 import pickle store the serialized object data into the file
with open('data/notes', 'wb') as filepath:
    pickle.dump(notes, filepath)

network.py

使用keras框架搭建網(wǎng)絡(luò)
1.def network_model(inputs, num_pitch, weights_file=None): 輸入,最后輸出的個(gè)數(shù),以及是否有權(quán)重文件。默認(rèn)沒有,如果有的話,就載入

 if weights_file is not None:  # 如果是 生成 音樂時(shí)
     # 從 HDF5 文件中加載所有神經(jīng)網(wǎng)絡(luò)層的參數(shù)(Weights)
     model.load_weights(weights_file)

2.步驟

  • 創(chuàng)建Sequential()類。model = tf.keras.models.Sequential()
  • 添加每一層網(wǎng)絡(luò),比如
LSTM層
model.add(tf.keras.layers.LSTM(
        512,  # LSTM 層神經(jīng)元的數(shù)目是 512,也是 LSTM 層輸出的維度
        input_shape=(inputs.shape[1], inputs.shape[2]),  # 輸入的形狀,對第一個(gè) LSTM 層必須設(shè)置
        return_sequences=True  # 返回所有的輸出序列(Sequences)
    ))
Dropout層

model.add(tf.keras.layers.Dropout(0.3)) # 丟棄 30% 神經(jīng)元,防止過擬合

全連接層

model.add(tf.keras.layers.Dense(num_pitch))

  • softmax激活函數(shù)算概率
    model.add(tf.keras.layers.Activation('softmax'))
  • 交叉熵計(jì)算誤差,使用對 循環(huán)神經(jīng)網(wǎng)絡(luò)來說比較優(yōu)秀的 RMSProp 優(yōu)化器 compile: configure the model for training
    model.compile(loss='categorical_crossentropy', optimizer='rmsprop')

train.py

1.會(huì)from utils import *以及from network import *
2.步驟

  • 用utils.py中的函數(shù)得到數(shù)據(jù)及數(shù)據(jù)長度
  • 為神經(jīng)網(wǎng)絡(luò)準(zhǔn)備好訓(xùn)練的序列prepare_sequence
    • 字符串與整數(shù)的映射
    • 序列長度,生成新的輸入序列
    • 將輸入的形狀轉(zhuǎn)為神經(jīng)網(wǎng)絡(luò)接受的
    • 歸一化(注意不是除以輸入的長度,而是輸入的最大值)
    • 將期望輸出轉(zhuǎn)換成 {0, 1} 組成的布爾矩陣,為了配合 categorical_crossentropy 誤差算法使用
      network_output = tf.keras.utils.to_categorical(network_output)
  • 生成checkpoint文件
  • 用fit方法生成模型

3.得到不重復(fù)的元素個(gè)數(shù)。set是不會(huì)有重復(fù)的數(shù)的
num_pitch = len(set(notes))

  1. notes中為字符串,要無重復(fù)并且按序
    pitch_names = sorted(set(item for item in notes))
  2. enumerate()同時(shí)得到索引和元素,創(chuàng)建字典用dict( , )。把set轉(zhuǎn)換為dict,如下,建立字符串與整數(shù)的映射關(guān)系
    pitch_to_int = dict((pitch, num) for num, pitch in enumerate(pitch_names))
  3. range的用法
    range(start, stop, step) stop is not include
  4. 生成checkpoint文件
filepath = "weights-{epoch:02d}-{loss:.4f}.hdf5"

    # 用 Checkpoint(檢查點(diǎn))文件在每一個(gè) Epoch 結(jié)束時(shí)保存模型的參數(shù)(Weights)
    # 不怕訓(xùn)練過程中丟失模型參數(shù)??梢栽谖覀儗?Loss(損失)滿意了的時(shí)候隨時(shí)停止訓(xùn)練
    checkpoint = tf.keras.callbacks.ModelCheckpoint(
        filepath,  # 保存的文件路徑
        monitor='loss',  # 監(jiān)控的對象是 損失(loss)
        verbose=0,
        save_best_only=True,  # 不替換最近的數(shù)值最佳的監(jiān)控對象的文件
        mode='min'      # 取損失最小的
    )
    callbacks_list = [checkpoint] #后面的fit方法會(huì)調(diào)用
  1. 用 fit 方法來訓(xùn)練模型
    model.fit(network_input, network_output, epochs=100, batch_size=64, callbacks=callbacks_list)

generate.py

用訓(xùn)練好的神經(jīng)網(wǎng)絡(luò)模型參數(shù)來作曲

1.用pickle加載之前保存的文件

    with open('data/notes', 'rb') as filepath:
        notes = pickle.load(filepath)

2.載入之前訓(xùn)練時(shí)最好的參數(shù)文件,來生成曲子
model = network_model(normalized_input, num_pitch, "best-weights.hdf5")
其中network_model就是寫的model,normalized_input是經(jīng)過prepare_sequential的

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容