尋夢新聞LINE@每日推播熱門推薦文章,趣聞不漏接❤️
大家好,在這篇文章中,我會分享給大家一些關於人工智能的實驗,教大家如何使用深度學習生成音符,與我之前關於生成歌詞的文章不同,這次我們將生成音樂筆記並生成文件(MIDI格式)。
音樂的主角是鋼琴。本文將在自我注意的幫助下,使用遞歸神經網路(RNN),門控遞歸單元(GRU)的變體生成鋼琴音符。本文不僅將介紹如何生成筆記,還將介紹如何將其生成為正確的MIDI文件,可以在計算機中播放。
本文針對的是對AI感興趣的人,尤其是那些想要練習深度學習的人。我希望通過發表這篇文章來增加我的寫作技巧,並也對你的文章內容產生幫助。
如果您想了解完整的源代碼,那麼本文末尾有一個Github鏈接。現在,我將在存儲庫中提供python筆記本和Colaboratory鏈接。
這是開場音樂
音樂.m4a
01:41.028999999999996
來自AI中國聲音1:打開鋼琴
(該音樂是由我們將在本文中創建的模型生成的)
大綱
- 介紹
- 技術與數據
- 管道
- 預處理MIDI文件
- 訓練模型
- 推理和生成MIDI文件
- 結果
- 結論
- 後記
介紹
人工智能當前的熱門話題之一是如何僅使用數據(無監督)來生成某些東西。在計算機視覺領域,有許多研究人員正在研究使用生成Advesarial網路(GAN)生成圖像的一些先進技術。例如,NVIDIA使用GAN創建逼真的臉部生成器。還有一些關於使用GAN生成音樂的研究。
如果我們談論音樂發生器的價值,它可以用來幫助音樂家創作他們的音樂。它可以增強人們的創造力。我想在未來,如果在這個領域有很多高度關注,大多數音樂家都會創作出由AI輔助的產生音樂。
本文將重點介紹如何通過在音樂中生成連續的音符來生成音樂。我們將知道如何預處理數據並將其轉換為神經網路的輸入以生成音樂。
該實驗還將使用Tensorflow v2.0(仍處於alpha階段)作為深度學習框架。我想要展示的是通過遵循他們的一些最佳實踐來測試和使用Tensorflow v2.0。我在Tensorflow v2.0中喜歡的一個功能是它通過使用AutoGraph來加速模型的訓練。它可以通過使用@tf.function定義我們的函數來使用。而且,再也沒有「tf.session」,也沒有全局初始化。這些特徵是我從Tensorflow轉移到PyTorch的原因之一。 Tensorflow可用性可能對於我來說不太好。盡管如此,在我看來,Tensorflow v2.0改變了這一切並增加了它們的可用性,使得做一些實驗變得舒適。
該實驗還使用自我注意層。自我注意層將告訴我們,給定一個順序實例(例如在音樂筆記「C D E F G」中),每個標記將了解對該標記的其他標記的影響程度。這是一些例子(對於NLP任務):
圖1:注意力的可視化
有關自我注意的更多信息,特別是有關transformer的信息,您可以閱讀這篇很棒的文章。
沒有任何進一步的問題,讓我們繼續生成音樂
技術與數據
這個實驗將使用:
- Tensorflow v2.0:深度學習框架、Tensorflow的新版本,仍處於alpha階段的開發階段。
- Python 3.7
- Colaboratory:免費的Jupyter筆記本環境,無需設置即可完全在雲中運行。擁有GPU Tesla K80甚至TPU!可悲的是,Tensorflow v2.0 alpha在撰寫本文時仍然不支持TPU。
- Python庫pretty_midi:一個用於操作和創建MIDI文件的庫
對於數據,我們使用來自Magenta的MAESTRO(MIDI和音頻編輯用於同步TRacks和組織)作為數據集。此數據集僅包含鋼琴樂器。我們將從大約1000個音樂中隨機抽取100個音樂,以加快我們的訓練時間。
管道
以下是關於我們的音樂生成器如何工作的管道:
圖2:管道
我們將看到每個過程。為簡化起見,我們將每個流程劃分如下:
- 預處理MIDI文件作為神經網路的輸入
- 訓練過程
- 生成MIDI文件
預處理MIDI文件
在討論如何預處理midi文件之前,我們需要知道midi格式文件是什麼。
從pcmag中,MIDI的定義為:
(樂器數字接口)樂器、合成器和計算機之間音樂信息交換的標準協議。MIDI的開發使一台合成器的鍵盤可以播放另一台合成器產生的音符。它為音符以及按鈕、撥盤和踏板的調整定義了代碼,MIDI控制消息可以編排一系列合成器,每個合成器都扮演樂譜的一部分。MIDI 1.0版於1983年引入。
總之,MIDI文件包含了一系列包含註釋的工具。例如鋼琴和吉他的組合,每種樂器通常有不同的音符。
對於預處理MIDI文件,有一些庫可以在Python中使用。其中一個是pretty_midi。它可以操作MIDI文件,還可以創建一個新文件。在本文中,我們將使用這個庫。
pretty_midi文件格式如下:
圖3:PrettyMidi格式
開始是第二個音符的開始。結束是一秒鐘內演奏的音符的結束。一次可以有多個音符重疊。音高是演奏音符的MIDI數字。速度是發出音符的力。
MIDI數字與註名的關係參考如下圖:
圖4:Midi數字和註釋名稱
閱讀Midi文件
我們將批量讀取midi文件,這是我們使用pretty_midi讀取它的方式:
midi_pretty_format = pretty_midi.PrettyMIDI (「song.mid」)
我們將得到PrettyMidi對象。
對鋼琴卷軸陣列進行預處理
圖5:從pretty tymidi到Piano Roll Array
在本文中,我們需要從樂器中提取所有的音符。許多MIDI文件的音樂中有多種樂器。在我們的數據集中,MIDI文件只包含一種樂器,那就是鋼琴。我們將從鋼琴樂器中提取音符。為了更簡單,我們將提取所需幀每秒的音符。pretty_midi有一個方便的函數get_piano_roll來獲取二進制2D numpy中的音符。數組在(註釋、時間)維度數組中,音符長度為128,時間按照音樂的時長除以FPS。
我們怎麼做的源代碼:
預處理到字典的時間和筆記
圖6:鋼琴卷軸數組到字典
在得到鋼琴卷軸的數組之後,我們將它們轉換成字典。字典將從音符播放的時間開始。例如,在上面的圖中,我們從28開始(如果我們轉換到秒,假設我們轉換到piano_roll的速度是5 fps,音樂開始播放的速度是5.6 s,我們可以用28除以5)。
創建字典之後,我們將把字典的值轉換為字符串。例如:
array([49,68]) => '49,68'
要做到這一點,我們應該循環字典的所有鍵並改變它的值:
for key in dict_note:
dict_note[key] = ','.join(dict_note[key])
預處理要輸入的音符列表和神經網路的目標
圖7:字典來列出序列
當我們得到字典後,將它轉換成連續的筆記,這些筆記將被用來作為神經網路的輸入。然後我們得到下一個時間步長作為神經網路輸入的目標。
圖8:滑動窗口
在本文中,序列列表的長度為50。這意味著如果我們的fps是5,將得到一個包含10秒(50 / 5)遊戲時間的序列。
列表中的「e」表示在這段時間內沒有演奏音符。因為有時候每個音符之間會有一個跳躍或者沒有音符。在圖7中的示例中,我們可以看到從43跳到46。如果我們轉換這個序列,序列的列表將是:
[…'61,77', '61,77', 'e', 'e', '73',…]
我們怎麼做呢?我們將用一批音樂來處理這個音符。
我們使用一個50長度的滑動窗口。對於音樂中的第一個音符,我們將在列表中添加「e」49次。然後將開始時間設置為字典中的第一個timestep。在圖7中的例子中,它是28。然後我們在音樂中添加第一個音符(在示例‘77’中)。
然後對於下一個實例,我們將窗口滑動1次,並向列表中添加48次「e」,並將timestep 28中播放的音符添加到列表中,將timestep 29中播放的音符添加到列表中,並重復操作,直到音樂結束。
在下一段音樂中,我們重復上面的過程。
這是源代碼:
創建注意分詞器
在我們深入研究神經網路之前,我們必須創建標記器以將順序音符更改為音符的順序索引。首先,我們應該將音符映射到表示音符id的索引。
例如:
{
'61,77' : 1, # 61,77 will be identified as 1
'e' : 2,
'73' : 3,
.
.
}
如果我們之前的輸入如下:
[...,'61,77','61,77','e','e','73',......]
我們將其轉換為:
[... 1,1,2,2,3 ......]
這是我們的做法。
總結我們的預處理功能,以下是我們將使用的功能:
訓練模型
在我們了解如何使用Tensorflow v2.0的新功能進行訓練之前,我們將看到如下架構:
神經網路架構
圖9:我們的神經網路架構
因此,深度學習架構將使用3層門控循環單元(GRU,一種回歸神經網路的變體)和一些自注意層。使用丟失使得神經網路不會過快地過度擬合。
對於Self Attention Layers,我們將使用此存儲庫並對其進行一些編輯,以便我們可以在Tensorflow v2.0上使用它。
因此,深度學習架構將使用3層門控遞歸單元(GRU,遞歸神經網路的一種變體)和一些自我注意層。該方法採用了跳脫法,使神經網路不會快速過擬合。
對於Self – Attention層,我們將使用這個存儲庫並稍微編輯一下,以便在Tensorflow v2.0上使用它。
代碼:
訓練
我們將通過迭代數據集中的多個音樂來更新模型的權重,並如上所述預處理數據。然後,以一批待輸入的實例和神經網路的目標為例。
我們將使用GradientTape來更新神經網路的權重。首先,我們使用apply_gradients計算損失並應用反向傳播。如果您熟悉使用PyTorch,這就是Pytorch在訓練其神經網路模型方面的工作方式。
務必在函數上使用@ tf.function。這會將功能轉換為簽名並使我們的訓練更快。 tf.function的一個缺點是不能使用不同大小的批量作為神經網路的輸入。例如,我們的批量大小為64。如果數據集的大小為70,則最後一批將包含6個實例。這將使程序拋出異常,因為圖形將具有與初始圖形不同大小的輸入。也許它的工作原理是通過在使用函數時查看第一個輸入來創建占位符。
在本文中,我們將使用16 BATCH_SONG和96 BATCH_NNET_SIZE。這意味著我們將從所有音樂列表中獲取16個音樂,然後提取其序列。然後,對於神經網路中的每一步,我們從提取的序列實例中獲取96個序列作為神經網路的輸入和目標。
代碼如下:
推理和生成MIDI文件
圖10:推理和生成MIDI文件
使用我們訓練的神經網路模型生成MIDI文件有兩種方法:
我們需要在開始時選擇:
- 我們生成隨機50個音符作為音樂的開頭。
- 我們使用49個空音符(’e’),然後是我們選擇的開始音符(例如’72’,確保音符在NoteTokenizer中)。
圖11:關於生成器如何工作的可視化
在我們選擇音樂生成器的種子之後,使用我們訓練的模型基於50個隨機音符預測下一個音符。我們使用預測值作為如何隨機選擇音符的概率分布,這樣做直到我們想要的指定的最大序列長度。然後我們放下前50個音符。
在我們生成音符列表序列之後,將其再次轉換為鋼琴卷軸陣列。然後將其轉換為PrettyMidi對象。
之後,我們調整音樂的速度和節奏,最後我們生成MIDI文件。
代碼 :
這是如何從生成的註釋中編寫midi文件:
結果
當我這樣做時,訓練耗時1小時,持續1個 epoch。當我這樣做時,我決定進行4個 epoch(4個小時)的訓練。
已經訓練了4個 epoch的模型,結果如下:
由於頭條號限制,只能發送一條音頻,故詳細資料請私信小編,回復「音樂」即可免費獲取。
(請注意,這些是從MIDI文件轉換而來的mp3文件。我使用在線轉換器來執行此操作,這些註釋似乎有點遺漏。如果您想聽到,我會將原始MIDI上傳到存儲庫中。)
這些生成的筆記之間存在明顯差異。如果我們用一個音符生成它,它將在播放音符時節奏緩慢。它與我們從50個隨機音符生成它時不同。它沒有緩慢的開始。
這是在選擇以隨機50個音符開始的音樂的最後序列上的自我注意塊的可視化:
首先注意
圖12:第一次自我注意
第二個注意
圖13:第二次自我注意
正如您所看到的,第一個自我注意塊會學習在序列實例中為每個音符聚焦的音符。然而,在第二個關注區塊中沒有關注什麼結果。我們還可以判斷,如果其他音符的位置離當前音符很遠,則它不會聚焦於它(圖像12和圖像13中的黑色)。
結論
我們使用包含鋼琴音樂的MAESTRO數據集構建了一個生成音樂的工具。我們預處理它,訓練我們的神經網路模型,然後用它生成音樂。音樂是MIDI格式。我們使用Tensorflow v2.0來完成它。我認為Tensorflow v2.0用戶體驗(UX)比以前的版本更好。
我們的模型產生的音樂也很連貫,很好聽。它可以調整播放音符的方式。例如:當發生器從音符(意味著它是音樂的開頭)時,它以慢節奏開始。
我們可以嘗試一些音樂生成器。在本文中,我們已經嘗試生成單個儀器。如果音樂有多種樂器怎麼辦?需要有一個更好的架構來做到這一點。我們可以嘗試多種方法來試驗音樂數據。
後記
這就是關於生成鋼琴音樂筆記的文章。實際上,通過查看我的第一篇關於深度學習的文章,我得到了啟發,這就是生成音樂的抒情效果。 「如何生成音符?」我做了一個試驗它很有效。
對我來說,試驗這個有一些困難。首先,我需要搜尋易於預處理和輸入神經網路的文件格式。我發現MIDI很簡單,文件很小。然後,我需要知道是否有任何庫可以在Python中預處理文件。我找到了兩個,有music21和pretty_midi,他們的存儲庫沒有過時,我選擇pretty_midi。最後,我需要考慮如何預處理筆記。值得慶幸的是,pretty_midi有一個方便的函數get_piano_roll來使它更容易。
我還沒有讀過很多關於音樂的研究論文。也許有一些研究論文可以在Colaboratory中復制和顯示。
自我注意層缺乏可視化效果。
存儲庫:https://github.com/haryoa/note_music_generator