1. 程式人生 > >基於深度學習生成音樂

基於深度學習生成音樂

cto ont -name 編碼 mp3文件 script 取值 style bsp

之前在看Andrew Ng 的deep learning 視頻教程,在RNN 這一節的課後作業裏,實現了一個基於deepjazz的music generator,實驗之後發現產生的結果還有模有樣的,這激發了我的興趣,於是我就查閱了一些資料,看看音樂的自動生成方面最近有哪些進展,特別是深度學習在這一塊的應用.在這裏稍微總結一下,並且寫一寫一些有趣的應用.

---------------------------------------------------- Part I : deep jazz 的簡單介紹-------------------------------------------------------------

1.What is deepjazz?

以下內容搬運自deepjazz的官網:

deepjazz 是一個使用theano 和keras的基於深度學習的jazz music 生成器.我在編程馬拉松(hackathon)使用36個小時創建了deepjazz.它使用了theano和keras這兩個庫來生成jazz music.具體地說,它構建了兩層的LSTM,從midi files 中學習.它使用了深度學習技術,以及AI技術,這個技術創造了著名的google AlphaGo和IBM的Watson,來產生音樂.而音樂被認為是非常human的.

2.怎樣使用deepjazz?

2.1 訓練模型並產生midi文件

我們首先去deepjazz的github首頁看一下.github上面說的比較簡單,我們首先git clone https://github.com/jisungk/deepjazz,然後 cd deepjazz,再運行python generator.py 應該就可以產生 學習出來的.mid 文件了.但是在測試的過程裏,首先會報錯(python3):‘‘‘ from itertools import groupby, izip_longest ImportError: cannot import name ‘izip_longest‘ ‘‘‘.這是由於原來的腳本是用python2寫的,我們需要將原來所有的"from itertools import izip_longest" 替換為"from itertools import zip_longest".

繼續運行,還是由於兼容性的問題,仍然會報錯:

"melody_voice.insert(0, key.KeySignature(sharps=1,mode=‘major‘))TypeError: init() got an unexpected keyword argument ‘mode‘
這裏我們只需要將mode = ‘major‘移除就可以了,後面還需要將generator.py中的 _sample 函數修改為:

def __sample(a, temperature=1.0):
    a = np.log(a) / temperature
    # a = np.exp(a) / np.sum(np.exp(a))
    # return np.argmax(np.random.multinomial(1, a, 1))
    dist = np.exp(a)/np.sum(np.exp(a))
    choices = range(len(a)) 
    return np.random.choice(choices, p=dist)

做了如上的修改之後,再運行python generator.py 應該就可以正常run起來了,運行結束之後,在midi 文件夾下,會多出一個deepjazz_on_metheny...128_epochs.midi 文件,這個就是我們通過 original_metheny.mid 訓練學習得到的生成文件了.需要註意的是,無論我們訓練還是生成的都不是常見的.mp3,.wav格式的音頻文件,而是.mid(或者.midi)格式的文件.那麽這兩者有什麽區別呢?這裏引用百度百科的定義簡單說明一下:

與波形文件不同,MIDI文件不對音樂進行抽樣,而是對音樂的每個音符記錄為一個數字,所以與波形文件相比文件要小得多,可以滿足長時間音樂的需要。MIDI標準規定了各種音調的混合及發音,通過輸出裝置可以將這些數字重新合成為音樂。
MIDI音樂的主要限制是它缺乏重現真實自然聲音的能力,因此不能用在需要語音的場合。此外,MIDI只能記錄標準所規定的有限種樂器的組合,而且回放質量受到聲音卡的合成芯片的限制。近年來,國外流行的聲音卡普遍采用波表法進行音樂合成,使MIDI的音樂質量大大提高。
MIDI文件有幾個變通格式,如RMI和CIF等。其中CMF文件(creative music format)是隨聲霸卡一起使用的音樂文件。RMI文件是Windows使用的RIFF(resource interchange file format)文件的一種子格式,稱為RMID,即包含MIDI文件的格式。
簡單來說就是:常見的.mp3,.wav格式的文件記錄的都是真實的音頻內容,因此一般體積會比較大(幾兆到幾十兆不等),而midi格式的文件沒有記錄真實的音頻信息,它只是記錄了一種代表格式的數字,計算機可以按照一定的標準識別出這種數字,然後把它轉化為對應的音頻播放出來.因此一般.midi格式的文件體積非常小,這是它的一個很大的優點,其缺點就是對於真實的聲音還原較差(因為它只能通過有限種指定的樂器來模擬聲音).

2.2 如何播放midi文件?

言歸正傳,在得到生成的midi文件之後,我們當然需要播放它好好欣賞一番啦.在windows下有不少軟件可以播放midi格式的文件,但是我使用的系統是ubuntu16.04,默認的播放器不支持midi格式,在查閱了資料以後發現需要安裝timidity,在ubuntu 下
直接sudo apt-get install timidity 即可.我找了一個python腳本play_midi.py(基於pygame),可以播放midi 文件,代碼如下:

import pygame
import pygame as pg
def play_music(music_file):
    ‘‘‘
    stream music with mixer.music module in blocking manner
    this will stream the sound from disk while playing
    ‘‘‘
    clock = pg.time.Clock()
    try:
      pg.mixer.music.load(music_file)
      print("Music file {} loaded!".format(music_file))
    except pygame.error:
        print("File {} not found! {}".format(music_file, pg.get_error()))
        return
    pg.mixer.music.play()
    # check if playback has finished
    while pg.mixer.music.get_busy():
        clock.tick(30)
# pick a midi or MP3 music file you have in the working folder
# or give full pathname
music_file = input("Please input the midi file path:")
#music_file = "Drumtrack.mp3"
freq = 44100  # audio CD quality
bitsize = -16  # unsigned 16 bit
channels = 2  # 1 is mono, 2 is stereo
buffer = 2048  # number of samples (experiment to get right sound)
pg.mixer.init(freq, bitsize, channels, buffer)
# optional volume 0 to 1.0
pg.mixer.music.set_volume(0.8)
try:
    play_music(music_file)
except KeyboardInterrupt:
    # if user hits Ctrl/C then exit
    # (works only in console mode)
    pg.mixer.music.fadeout(1000)
    pg.mixer.music.stop()
    raise SystemExit

運行python play_midi.py ,然後輸入midi文件的路徑,就可以播放啦.試著播放我們生成的midi文件,你會發現聽起來是相當不錯的!
當然其實安裝了timidity之後,我們就可以直接播放midi文件了,直接運行 timidity xxx.midi 就可以了.但是有可能會出問題,因為我們還需要一些額外的配置文件,運行命令‘sudo apt-get install fluid-soundfont-gm fluid-soundfont-gs‘ 安裝好soundfont(聲音字體,用於解析midi,並且播放),然後打開/etc/timidity/timidity.cfg 文件,將最後一行‘source freepats.cfg‘ 註釋掉,如果是ubuntu系統的話改為:
dir /usr/share/sounds/sf2/
soundfont FluidR3_GM.sf2
如果是centos系統的話改為:
dir /usr/share/soundfonts/
soundfont FluidR3_GM.sf2
然後重啟timidity,執行命令:sudo /etc/init.d/timidity restart
這樣我們再執行timidity xxx.midi應該就可以正常播放啦!

2.3 如何將midi文件轉化為一般的音頻文件(mp3,wav等格式)

現在我們可以正常播放midi文件了.但是還有一個問題,一般我們使用的音頻格式是wav,mp3這種格式的,因為它們更易於被一般的播放器識別並且播放.那麽有沒有上面辦法可以將midi文件轉化為這樣的格式呢?當然是有辦法的,最簡單的辦法就是使用timidity(之前我們已經安裝過啦),運行下面的命令:
timidity --output-24bit --output-mono -A120 source.mid -Ow -o source.wav
就可以把source.mid 轉化為source.wav 了.其中 --output指定輸出的格式,-A指定音量(volume),-Ow 表示轉化為RIFF WAVE file輸出格式,-o指定輸出音頻文件的名字,具體可以timidity --help 查看各個參數的含義.
如果沒有問題的話,我們就得到一個.wav文件啦,這樣你使用任何一個音樂播放器都可以播放它啦!
順便提一個小問題.wav文件一般體積比較大(質量較好),而在網絡上更常見的是mp3文件,那麽這兩者該如何轉化呢?這裏我提供兩種解決辦法:
1.使用ffmpeg 這個音視頻庫來進行轉化.運行命令
ffmpeg -i source.wav -acodec libmp3lame source.mp3
就可以將source.wav 轉化為source.mp3了.這裏 -i 表示輸入音頻,-acodec 表示設置 audio codec(音頻編碼)格式,是"-codec:a"的別名,更多的信息可以輸入 ffmpeg --help 或者 man ffmpeg查看
2.也可以安裝python的音頻庫pydub進行轉化,這個我在之前的博客介紹幾個python的音頻處理庫介紹過,有興趣可以自行查看.

如何將wav,mp3文件轉化為midi文件?

這個問題我一開始以為是挺容易實現的一個任務,哪知道查了資料以後才發現是一個很hard的問題,目前仍然有很多人研究music transcription(音樂轉換)的問題.我沒有找到一個很好地解決這個問題的api,具體可以參看stackoverflow的這個討論,目前也有很多的plugin可以做這個事情,比如Sonic Annotator等,但是就涉及到很專業的知識了,我想了一個還是放棄了...總之如果要做批量的從wav,mp3到midi的轉化還是很困難的,特別是要求比較高的質量的話,如果有興趣,大家可以自行研究了.但是如果不要求大規模的自動轉換,還是有不少軟件可以完成wav(mp3)到midi的轉化的,比如這個網址可以在線將mp3轉換為midi格式.

如何訓練自己的midi文件?

之前我們是拿作者給的一個original_metheny.mid文件進行訓練然後生成mid文件的.那麽我們可以拿自己的mid文件進行訓練嗎?這裏有一個網址可以打包下載很多的midi文件,或者訪問這個網址可以下載自己喜歡的流行音樂的midi格式.我們發現我們下載的midi文件的format,tracks,divisions都和deepjazz作者提供的original_metheny.mid格式不同,所以如果只是把mid文件換成我們自己的是沒有辦法順利train的,總是會報錯.我大概看了一下代碼,主要是使用music21處理midi格式轉換的代碼部分有問題.我嘗試了半天,因為自己對於music21以及midi格式不是很熟悉,所以這個問題暫時沒有解決.如果我後面有時間了會好好再分析一下deepjazz的源碼,解決這個問題.

---------------------------------------------------------------------------Part II magenta ---------------------------------------------------------------

1.What is magenta?

下面是magenta官方github的介紹.

magenta是一個旨在探索使用機器學習來創造藝術和音樂的研究項目.目前它主要使用新興的深度學習技術以及強化學習技術來產生歌曲,繪畫,圖片等等.同時它也旨在探索構建智能化的工具和接口,這樣藝術家可以使用這些模型來擴展(而不是取代)他們的部分工作.
magenta最初是由Google Brain 的一些研究員發起的,但是其他的很多研究人員也為這個項目做出了巨大的貢獻.我們使用tensorflow在github上發布我們的模型和代碼.如果你想要了解更多關於magenta的事情,你可以查看我們的博客,我們在那裏介紹了很多技術上的細節.你也可以加入討論組.

2.How to install magenta and use it?

安裝magenta非常簡單,可以直接使用pip install magenta 安裝,但是要註意在此之前你需要安裝好了tensorflow.
magenta支持gpu加速(你只需要安裝gpu版本的tensorflow),使用pip install magenta-gpu 安裝即可.magenta其實提供了非常多的models,包含了語音,圖片等.這裏我們主要關註音樂生成方面的模型.

2.1 drums_rnn model

這是一個訓練得到drums 風格音樂的模型.這個模型使用了LSTM將語言模型應用在drum track 生成上.和melodies不一樣,drum tracks是多音的,多個drums可能會同時存在.盡管這樣,我們還是通過以下手段將drum track 作為一個single sequence 來處理:
a)將所有不同的midi drums 映射到一個更小的drum classes上去
b)將每一個event表達為一個單一值,該值代表了該次struck(敲擊)所屬的drums classes 類別
這裏model 提供了兩個configurations:one drum 和drum kit.具體可以參考原網址的說明
下面來說明如何訓練drums_rnn model.magenta其實已經提供了pre trained model,我們可以首先快速來inference一下.首先下載drum_kit文件,然後將下載的drum_kit_rnn.mag文件放入某一個文件夾下(比如model/下).然後我們寫一個腳本generate_drums_rnn.sh:

#!/bin/bash
drums_rnn_generate         --config=‘drum_kit‘         --bundle_file=../data/drum_kit_rnn.mag         --output_dir=../output         --num_outputs=5         --num_steps=256         --primer_drums="[(36,)]"

這裏 --config 是配置 configuration,有‘drum_kit‘和‘one_drum‘兩個選項
--bundle_file 指定我們bundle file的地址(就是剛才下載的drum_kit_rnn.mag文件)
--output_dir 指定輸出midi文件的地址
--num_outputs 指定輸出midi文件的個數(默認是10個)
--num_steps 指定訓練的epochs(訓練輪數)
--primer_drums 指定開始的一些音節(必填)
上面的腳本會以一個bass drum hit(低音)開始,如果你願意的話,你也可以使用其他的字符串形式的python list,但是list中的元素必須是一個tuple,而且必須要是代表drum 的midi 音節的整數.比如說:--primer_drums="[(36, 42), (), (42,)]"表示的意思就是一個bass 和一個hit-hat,然後是一個silence,最後是一個hit-hat.如果你不使用--primer_drums參數,你也可以使用--primer_midi參數,來使用一個drum midi 文件來作為primer(開頭).
如果按照上面的方式來進行嘗試的話,你會得到一些midi文件.然後播放它吧,有些還是相當不錯的!
上面我們使用了pre trained model,然後可以直接得到生成的midi文件,那麽該如何來訓練自己的model呢?訓練自己的model有些復雜,我們可以按照如下的steps 進行操作:

step1:build your dataset

參考網址首先我們需要準備自己的midi datasets,可以在這個網址打包下載,或者在這個midiworld自己手動下載,然後我們需要將這些midi files 轉化為NoteSequences.使用如下的腳本convert_midi.sh進行轉換:

#!/bin/bash
convert_dir_to_note_sequences   --input_dir=$INPUT_DIRECTORY   --output_file=$SEQUENCES_TFRECORD   --recursive

上面的參數:
--input_dir表示輸入midi files 的文件夾地址(可以包含子文件夾)
--output_file 表示輸出.tfrecord文件的地址
--recursive 表示遞歸遍歷midi files
註意如果你使用的是前一個midi datasets的話,由於這個數據集非常大(有1.6G左右),包含了非常多的midi文件,所以訓練起來可能會非常耗時,我大概訓練了兩個小時還沒訓練完最後提前終止了,當然如果你的計算機性能非常好,你也可以嘗試訓練完.
訓練完之後,我們會得到一個lmd_matched_notesequences.tfrecord文件.接下來進入step2

step2:create sequenceExamples

註意我們輸入模型進行訓練和評估的是SequenceExamples.每一個SequenceExample都會包含一個序列輸入和一個序列標簽,代表了一個drum track.可以運行下面的命令將之前得到的NoteSequences 轉化為SequenceExamples.這樣將會產生兩個部分的SequenceExamples,一個用於training,一個用於evaluation.具體可以使用--eval_ratio來指定兩者的比例.比如指定eval_ratio = 0.1(或者10%),會將提取出的drums tracks 的10%用於evaluation,剩下的90%用於training.

drums_rnn_create_dataset --config=<one of ‘one_drum‘ or ‘drum_kit‘> --input=/tmp/notesequences.tfrecord --output_dir=/tmp/drums_rnn/sequence_examples --eval_ratio=0.10

上面的參數中:
--config 只能取值為‘one_drum‘或者‘drum_kit‘
--input 為step1得到的tfrecord文件地址
--output_dir 為輸出SequenceExamples的文件夾地址
--eval_ratio 指定evaluation 和training的比例

step3:train and evaluate the model

運行下面的代碼(train.sh)就可以進行train了.

#!/bin/bash
drums_rnn_train --config=drum_kit --run_dir=/tmp/drums_rnn/logdir/run1 --sequence_example_file=/tmp/drums_rnn/sequence_examples/training_drum_tracks.tfrecord --hparams="batch_size=64,rnn_layer_sizes=[64,64]}" --num_training_steps=20000

各個參數的含義如下:
--config:‘one_drum‘ or ‘drum_kit‘
--run_dir 是運行tensorflow訓練模型checkpoints存放的文件夾地址
--sequence_example_file是用於訓練模型的SequenceExamples tfrecord文件地址
--num_training_steps 指定訓練的steps(輪數),如果不指定的話,會一直運行直到手動終止(CTRL-C或者CTRL-Z)
--hparams 用於指定其他的超參數,比如這裏我們指定了batch_size = 64,而不是默認的128.使用更小的batch size 有助於降低OOM(內存溢出)的風險,當然,如果你的內存夠大,也可以設置較大的batch_size.這裏還設定使用2 layers的RNN,每一個layer 的hidden units都是64,而不是默認的3 layers,每個layer有256個hidden units.這樣可以加速訓練(當然損失了一定的精度),如果你的計算機性能很高,你可以嘗試更大的hidden units以獲得更好的結果.我們還可以設定--attn_length 參數來指定多少個steps進行一次attention machanism.這裏我們使用的是默認值32.
運行下面的代碼(eval.sh)就可以進行evaluation.

!/bin/bash
drums_rnn_train --config=drum_kit --run_dir=/tmp/drums_rnn/logdir/run1 --sequence_example_file=/tmp/drums_rnn/sequence_examples/eval_drum_tracks.tfrecord --hparams="batch_size=64,rnn_layer_sizes=[64,64]" --num_training_steps=20000 --eval

和train.sh差不多,唯一區別是--sequence_example_file需要指定eval的tfrecord file 了,還有就是多了一個--eval 用於指定這是一個eval過程,而不是train.註意eval過程不會改變任何一個參數,它只是用於評估模型的性能.
當然我們也可以運行:tensorboard --logdir=/tmp/drums_rnn/logdir 來使用tensorboard來查看train 和eavl的結果,只要在瀏覽器打開:
http://localhost:6006 就可以了.

step4:generate drum tracks

完成了step1~step3之後我們就可以來產生自己的midi 文件了.運行的腳本為:

#!/bin/bash
drums_rnn_generate --config=drum_kit --run_dir=/tmp/drums_rnn/logdir/run1 --hparams="batch_size=64,rnn_layer_sizes=[64,64]" --output_dir=/tmp/drums_rnn/generated --num_outputs=10 --num_steps=128 --primer_drums="[(36,)]"

大部分參數上面都已經解釋了,這裏不再贅述.

2.2 melody_rnn model

melody_rnn model 和上面的 drums_rnn 非常類似,只不過這裏產生的是melody,而上面產生的是drums.這裏不再贅述,具體可以參見melody_rnn

2.3 其他的模型

除了上面說的drums_rnn 和melody_rnn之外,magenta還有很多其他有趣的模型,比如neural style transfer(神經風格遷移,可以產生指定風格的圖片)等,有興趣的可以去magenta詳細了解.

------------------------本文完,感謝閱讀!-----------------------------------------------------------------------

基於深度學習生成音樂