基於深度學習生成音樂

   以前在看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的.html

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 函數修改成:python

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)格式的文件.那麼這二者有什麼區別呢?這裏引用百度百科的定義簡單說明一下:git

與波形文件不一樣,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格式的文件體積很是小,這是它的一個很大的優勢,其缺點就是對於真實的聲音還原較差(由於它只能經過有限種指定的樂器來模擬聲音).github

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應該就能夠正常播放啦!ubuntu

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的音頻處理庫介紹過,有興趣能夠自行查看.windows

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

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

如何訓練本身的midi文件?

   以前咱們是拿做者給的一個original_metheny.mid文件進行訓練而後生成mid文件的.那麼咱們能夠拿本身的mid文件進行訓練嗎?這裏有一個網址能夠打包下載不少的midi文件,或者訪問這個網址能夠下載本身喜歡的流行音樂的midi格式.咱們發現咱們下載的midi文件的format,tracks,divisions都和deepjazz做者提供的original_metheny.mid格式不一樣,因此若是隻是把mid文件換成咱們本身的是沒有辦法順利train的,老是會報錯.我大概看了一下代碼,主要是使用music21處理midi格式轉換的代碼部分有問題.我嘗試了半天,由於本身對於music21以及midi格式不是很熟悉,因此這個問題暫時沒有解決.若是我後面有時間了會好好再分析一下deepjazz的源碼,解決這個問題.api

---------------------------------------------------------------------------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詳細瞭解.

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

相關文章
相關標籤/搜索