我們用 RNN 分析了最流行的音樂,只想為你寫首歌

文/Daniil Pakhomov

RNN(Recurrent Neural Networks,循環神經網路)不僅會學習當前時刻的信息,也會依賴之前的序列,這種獨特的優勢非常適合用於處理時間序列和語言文本序列問題。本文數據俠就利用RNN的生成模型對最受歡迎的音樂家作品進行了訓練。當藝術遇到神經網路,會擦出怎樣的火花呢?一起來漲姿勢吧~

本文轉自AI研習社(ID:okweiwu)

介紹

我們將在歌詞數據集上訓練RNN字元級語言模型,數據集來自最受歡迎以及最新發布的藝術家的作品。模型訓練好之後,我們會選出幾首歌曲,這些歌曲將會是不同風格、不同藝術家的有趣混合。之後,我們將更新模型使之成為一個條件字元級RNN,使我們能夠從藝術家的歌曲中採樣。最後,我們通過對鋼琴曲的midi數據集的訓練來總結。

在解決這些任務的同時,我們將簡要地探討一些有關RNN訓練和推斷的有趣概念,如字元級RNN,條件字元級RNN,從RNN採樣,經過時間截斷的反向傳播和梯度檢查點。

所有的代碼和訓練模型都已在github(

t.cn/RE0QF8J)上開源(DT君註:文中所有短鏈接,感興趣的網友都可以複製到瀏覽器中打開),並通過PyTorch (

pytorch.org/ ) 實現。如果你已經熟悉字元級語言模型和循環神經網路,可以隨意跳過各個部分或直接進入結果部分。

字元級語言模型

在選擇模型前,讓我們仔細看看我們的任務。基於現有的字母和所有之前的字母,我們將預測下一個字元。在訓練過程中,我們只使用一個序列,除了最後一個字元外,序列中的其他字元將作為輸入,並從第二個字元開始,作為groundtruth(見上圖,t.cn/REO4fe3

)。我們將從最簡單的模型開始,在進行預測時忽略所有前面的字元,然後改善這個模型使其只考慮一定數量的前面的字元,最後得到一個考慮所有前面的字元的模型。

我們的語言模型定義在字元級別。我們將創建一個包含所有英文字元和一些特殊符號(如句號,逗號和行尾符號)的字典。每個字元將被表示為一個獨熱編碼的張量。有關字元級模型和示例的更多信息,推薦此資源(t.cn/Rxwgzqw )。

有了字元後,我們可以生成字元序列。即使是現在,也可以通過隨機抽樣字元和固定概率p(any

letter)=1 和字典大小 p(any letter)=1dictionary size

來生成句子。這是最簡單的字元級語言模型。可以做得更好嗎?當然可以,我們可以從訓練語料庫中計算每個字母的出現概率(一個字母出現的次數除以我們的數據集的大小),並且用這些概率隨機抽樣。這個模型更好但是它完全忽略了每個字母的相對位置。

舉個例子,注意你是如何閱讀單詞的:你從第一個字母開始,這通常很難預測,但是當你到達一個單詞的末尾時,你有時會猜到下一個字母。當你閱讀任何單詞時,你都隱含地使用了一些規則,通過閱讀其他文本學習:例如,你從單詞中讀到的每一個額外的字母,空格字元的概率就會增加(真正很長的單詞是罕見的),或者在字母"r"之後的出現輔音的概率就會變低,因為它通常跟隨母音。有很多類似的規則,我們希望我們的模型能夠從數據中學習。為了讓我們的模型有機會學習這些規則,我們需要擴展它。

讓我們對模型做一個小的逐步改進,讓每個字母的概率只取決於以前出現的字母(馬爾科夫假設,t.cn/REO4Ydj

)。所以,基本上我們會有 p(current letter|previous

letter)。這是一個馬爾科夫鏈模型(如果你不熟悉,也可以嘗試這些互動式可視化,t.cn/RZBE1ME

)。我們還可以從訓練數據集中估計概率分布p(current letter|previous

letter)。但這個模型是有限的,因為在大多數情況下,當前字母的概率不僅取決於前一個字母。

我們想要建模的其實是p(current

letter|all previous

letters)。起初,這個任務看起來很棘手,因為前面的字母數量是可變的,在長序列的情況下它可能變得非常大。結果表明,在一定程度上,利用共享權重和固定大小的隱藏狀態,循環神經網路可以解決這個問題,因此引出下一個討論RNNs的部分。

循環神經網路

循環神經網路是一族用於處理序列數據的神經網路,與前饋神經網路不同,RNNs可以使用其內部存儲器來處理任意輸入序列。

由於任意大小的輸入序列,它們被簡潔地描述為一個具有循環周期的圖(見上圖:源,t.cn/RyIAoWq

)。但是如果已知輸入序列的大小,則可以"展開"。定義一個非線性映射,從當前輸入xt 和先前隱藏狀態st?1 到輸出

ot和隱藏狀態st。隱藏狀態大小具有預定義的大小,存儲在每一步更新的特徵,並影響映射的結果。

現在,將字元級語言模型的前一張圖片與已摺疊的RNN圖片對齊,以了解我們如何使用RNN模型來學習字元級語言模型。

雖然圖片描繪了Vanilla RNN,但是我們在工作中使用LSTM,因為它更容易訓練,通常可以獲得更好的結果。

為了更詳細地介紹RNNs,推薦以下資源(t.cn/RyIAoWq )。

歌詞數據集

在實驗中,我們選擇了55000+ Song Lyrics Kaggle dataset ,其中包含了很多近期的藝術家和更多經典的好作品。它存儲為pandas文件,並用python包裝,以便用於培訓。為了使用我們的代碼,你需要自行下載。

為了能夠更好地解釋結果,我選擇了一些我稍微熟悉的藝術家:

artists = [

ABBA,

Ace Of Base,

Aerosmith,

Avril Lavigne,

Backstreet Boys,

Bob Marley,

Bon Jovi,

Britney Spears,

Bruno Mars,

Coldplay,

Def Leppard,

Depeche Mode,

Ed Sheeran,

Elton John,

Elvis Presley,

Eminem,

Enrique Iglesias,

Evanescence,

Fall Out Boy,

Foo Fighters,

Green Day,

HIM,

Imagine Dragons,

Incubus,

Jimi Hendrix,

Justin Bieber,

Justin Timberlake,

Kanye West,

Katy Perry,

The Killers,

Kiss,

Lady Gaga,

Lana Del Rey,

Linkin Park,

Madonna,

Marilyn Manson,

Maroon 5,

Metallica,

Michael Bolton,

Michael Jackson,

Miley Cyrus,

Nickelback,

Nightwish,

Nirvana,

Oasis,

Offspring,

One Direction,

Ozzy Osbourne,

P!nk,

Queen,

Radiohead,

Red Hot Chili Peppers,

Rihanna,

Robbie Williams,

Rolling Stones,

Roxette,

Scorpions,

Snoop Dogg,

Sting,

The Script,

U2,

Weezer,

Yellowcard,

ZZ Top]

訓練無條件的字元級語言模型

第一個實驗是在整個語料庫上訓練我們的字元級語言模型RNN,在訓練時沒有考慮藝術家的信息。

從 RNN 採樣

在訓練完模型之後,我們試著抽出幾首歌。基本上,RNN每一步都會輸出 logits,我們可以利用softmax函數從分布中取樣(t.cn/REOGbtS )。或者可以直接使用Gumble-Max技巧採樣,這和直接使用logits是等價的。

抽樣的一個有趣之處是,我們可以對輸入序列進行部分定義,並在初始條件下開始採樣。舉個例子,我們採樣以"Why"開頭的歌曲:

Why do you have to leave me?

I think I know Im not the only one

I dont know if Im gonna stay awake

I dont know why I go along

I dont know why I cant go on

I dont know why I dont know

I dont know why I dont know

I dont know why I keep on dreaming of you

那麼,這聽起來像是一首歌。

讓我們來看一下以 「Well」 開頭的歌曲:

Well, I was a real good time

I was a rolling stone

I was a rock and roller

Well, I never had a rock and roll

There were times I had to do it

I had a feeling that I was found

I was the one who had to go

採樣過程中使用的"temperature"參數控制採樣過程的隨機性。當這個參數接近零時,採樣等於argmax,當它接近無窮時,採樣等同於均勻分布的採樣。可以看一下相關論文中的圖(Jang et al):

當τ=1 時,分布不受影響。如果我們減少 τ,分布變得更加明顯,意味著有更大概率質量的值會增加。當τ 接近零時,採樣將相當於argmax,因為該值的概率接近於 1。當我們開始增加τ 時,分布變得越來越均勻。

之前的樣本是在"temperature"參數等於 0.5 的情況下生成的,讓我們看看

當我們增加到 1.0 時會發生什麼:

Why cant we drop out of time?

We were born for words to see.

Wont you love this. Youre still so amazing.

This could be that down on Sunday Time.

Oh, Caroline, a lady floor.

I thought of love, oh baby.

讓我們進一步增加:

Why - wont we grow up naked?

We went quietly what we wouldve still give

That girl you walked before our bedroom room

I see your mind is so small to a freak

Stretching for a cold white-heart of crashing

Truth in the universal daughter

I lose more and more hard

I love you anytime at all

Ah come let your help remind me

Now Ive wanted waste and never noticed

I swear I saw you today

You needed to get by

But you sold a hurricane

Well out whispered in store

我們為什麼不直接一次性增加呢?

那麼,你可以看到這樣的趨勢:當我們增加"temperature"時,採樣的句子變得越來越隨機。

訓練有條件的字元級語言模型

想像一下,如果我們能夠以某種特定藝術家的風格生成歌詞。讓我們改變我們的模型,以便在訓練期間使用這些信息。

我們將通過為我們的RNN增加一個額外的輸入來做到這一點。到目前為止,我們的RNN模型只接受每步包含one-hot編碼字元的張量。

對我們的模型的擴展將是非常簡單的:我們將擁有和額外的一個熱點編碼張量來代表藝術家。所以每一步RNN都會接受一個張量,這個張量由代表人物和藝術家的連續張量組成。

從有條件語言模型 RNN 中抽樣

訓練結束後,我們抽取了一些藝術家的歌曲,部分結果如下所示:

Him:

My fears

And the moment dont make me sing

So free from you

The pain you love me yeah

Whatever caused the warmth

You smile youre happy

You sit away

You say its all in vain

似乎真的有可能,尤其是使用了痛苦這個詞,這在藝術家的歌詞中是很常見的事實。

ABBA:

Oh, my love it makes me close a thing

Youve been heard, I must have waited

I hear you

So I say

Thank you for the music, that makes me cry

And you moving my bad as me, ah-hang wind in the hell

I was meant to be with you, Ill never be playing up

Bob Marley:

Mercy on judgment, we got so much

Alcohol, cry, cry, cry

Why dont try to find our own

I want to know, Lord, I wanna give you

Just saving it, learned

Is there any more?

All that damage done

Thats all reason, dont worry

Need a hammer

I need you more and more

Coldplay:

Look at the stars

Into life matter where you lay

Saying no doubt

I dont want to fly

In my dreams and fight today

I will fall for you

All I know

And I want you to stay

Into the night

I want to live waiting

With my love and always

Have I wouldnt wasted

Would it hurt you

Kanye West:

Im everywhere for you

The way that it couldnt stop

I mean it too late and love I made in the world

I told you so I took the studs full cold-stop

The hardest stressed growin

The hustler raisin on my tears

I know Im true, one of your love

看起來很酷,但請記住,我們沒有跟蹤驗證的準確性,所以一些樣本行可能已經被RNN模型記住了。一個更好的方法是選擇一個模型,在訓練期間給出最好的驗證分數。

我們也注意到了一件有趣的事情:當你想用一個指定的起始字元串進行採樣時,無條件模型通常更好地表現出來。我們的直覺是,當從一個具有特定起始字元串的條件模型中抽樣時,我們實際上把兩個條件放在我們的模型開始字元串和一個藝術家之間。而且我們沒有足夠的數據來模擬這個條件分布(每個歌手的歌曲數量相對有限)。

我們正在使代碼和模型可用,並且即使沒有gpu,也可以從我們訓練好的模型中採樣歌曲,因為它計算量並不大。

Midi 數據集

接下來,我們將使用由大約700 首鋼琴歌曲組成的小型midi數據集(t.cn/RadrUlf )。我們使用了諾丁漢鋼琴數據集(僅限於訓練分割)。

任何

MIDI

文件都可以轉換為鋼琴鍵軸(t.cn/REO5Avk),這只是一個時頻矩陣,其中每一行是不同的MIDI音高,每一列是不同的時間片。因此,我們數據集中的每首鋼琴曲都會被表示成一個大小的矩陣

88×song_length,88 是鋼琴音調的個數。下圖是一個鋼琴鍵軸矩陣的例子:

即使對於一個不熟悉音樂理論的人來說,這種表現方式也很直觀,容易理解。每行代表一個音高:高處的行代表低頻部分,低處的行代表高頻部分。另外,我們有一個代表時間的橫軸。所以如果我們在一定時間內播放一定音調的聲音,我們會看到一條水平線。總而言之,這與

YouTube 上的鋼琴教程非常相似(t.cn/REO5tIu )。

現在,我們來看看字元級模型和新任務之間的相似之處。在目前的情況下,給定以前播放過的所有音調,

我們將預測下一個時間步將要播放的音調。所以,如果你看一下鋼琴鍵軸的圖,每一列代表某種音樂字元,給定所有以前的音樂字元,預測下一個音樂字元。我們注意依一下文字字元與音樂字元的區別。回憶一下,語言模型中的每個字元都是由one-hot向量表示的(意思是我向量中只有一個值是

1,其他都是 0)。對於音樂字元,可以一次按下多個鍵(因為我們正在處理複音數據集)。在這種情況下,每個時間步將由一個可以包含多個 1

的向量表示。

培養音高水平的鋼琴音樂模型

在開始訓練之前,根據在前面討論過的不同的輸入,需要調整我們用於語言模型的損失函數。在語言模型中,我們在每個時間步上都有one-hot的編碼張量(字元級)作為輸入,用一個one-hot的編碼張量作為輸出(預測的下一個字元)。由於預測的下一個字元時使用獨佔,我們使用交叉熵損失(t.cn/RqQJif4

)。

但是現在我們的模型輸出一個不再是one-hot編碼的矢量(可以按多個鍵)。當然,我們可以將所有可能的按鍵組合作為一個單獨的類來處理,但是這是比較難做的。相反,我們將輸出向量的每個元素作為一個二元變數(1

表示正在按鍵,0

表示沒有按鍵)。我們將為輸出向量的每個元素定義一個單獨的損失為二叉交叉熵。而我們的最終損失將是求這些二元交叉熵的平均和。可以閱讀代碼以獲得更好的理解。

按照上述的修改後,訓練模型。在下一節中,我們將執行採樣並檢查結果。

從音調水平的RNN採樣

在優化的早期階段,我們採樣了鋼琴鍵軸:

可以看到,模型正在開始學習數據集中歌曲常見的一種常見模式:1

首歌曲由 2 個不同的部分組成。第一部分包含一系列獨立播放的節奏(t.cn/REO58VI

),非常易辨,通常是可唱(也稱為旋律)。如果看著採樣的鋼琴鍵軸圖,這部分在底部。如果觀察鋼琴捲軸的頂部,可以看到一組通常一起演奏的音高 -

這是伴隨著旋律的和聲或和音(在整個歌曲中一起播放的部分)的進行。

訓練結束後,從模型中抽取樣本如下圖所示:

如圖所示,他們和前面章節中的所看到的真實情況相似。

訓練結束後,抽取歌曲進行分析。這裡有一個有趣的介紹樣本(dwz.cn/7y4sJ1

)。而另一個樣本,是具有很好的風格轉換(suo.im/37xGMo

)。同時,我們生成了一些低速參數的例子,它們導致歌曲的速度慢了:這裡是第一個(suo.im/1HXnWq

)和第二個(suo.im/4AMlAy )。可以在這裡(suo.im/u0Bo5 )找到整個播放列表。

序列長度和相關問題

現在讓我們從GPU內存消耗和速度的角度來看待我們的問題。

我們通過批量處理我們的序列大大加快了計算速度。同時,隨著序列變長(取決於數據集),我們的最大批量開始減少。為什麼是這種情況?當我們使用反向傳播來計算梯度時,我們需要存儲所有對內存消耗貢獻最大的中間激活量。隨著我們的序列變長,我們需要存儲更多的激活量,因此,我們可以用更少的樣本在批中。

有時候,我們需要用很長的序列來工作,或者增加批的大小,而你只有 1 個有少量內存的GPU。在這種情況下,有多種可能的解決方案來減少內存消耗,這裡,我們只提到兩種解決方案,它們之間需要取捨。

首先是一個截斷的後向傳播(suo.im/3OinMH

)。這個想法是將整個序列拆分成子序列,並把它們分成不同的批,除了我們按照拆分的順序處理這些批,每一個下一批都使用前一批的隱藏狀態作為初始隱藏狀態。我們提供了這種方法的實現,以便能更好地理解。這種方法顯然不是處理整個序列的精確等價,但它使更新更加頻繁,同時消耗更少的內存。另一方面,我們有可能無法捕捉超過一個子序列的長期依賴關係。

第二個是梯度檢查點(suo.im/2fDdzL)。這種方法使我們有可能在使用更少內存的同時,在整個序列上訓練我們的模型,以執行更多的計算。回憶,之前我們提到過訓練中的大部分內存資源是被激活量使用。梯度檢查點的思想包括僅存儲每個第n個激活量,並在稍後重新計算未保存的激活。這個方法已經在Tensorflow(t.cn/RQJ51iO

)和Pytorch(t.cn/REOc5g0 ) 中實現。

結論和未來的工作

在我們的工作中,我們訓練了簡單的文本生成模型,擴展了模型以處理復調音樂,簡要介紹了採樣如何工作以及溫度參數如何影響我們的文本和音樂樣本 - 低溫提供了更穩定的結果,而高溫增加了更多的隨機性,這有時會產生非常有趣的樣本。

未來的工作可以包括兩個方向

- 用訓練好的模型在更多的應用或更深入的分析上。例如,可以將相同的模型應用於 Spotify

收聽歷史記錄。在訓練完收聽歷史數據後,可以給它一段前一小時左右收聽的歌曲序列,並在當天餘下時間為您播放一個播放列表。那麼,也可以為你的瀏覽歷史做同樣的事情,這將是一個很酷的工具來分析你的瀏覽行為模式。在進行不同的活動(在健身房鍛煉,在辦公室工作、睡覺)時,從手機中獲取加速度計和陀螺儀數據(suo.im/r1PDm

),並學習分類這些活動階段。之後,您可以根據自己的活動自動更改音樂播放列表(睡眠 - 冷靜的音樂,在健身房鍛煉 -

高強度的音樂)。在醫學應用方面,模型可以應用於基於脈搏和其他數據檢測心臟問題,類似於這項工作。

分析在為音樂生成而訓練的 RNN 中的神經元激勵是非常有趣的。看模型是否隱含地學習了一些簡單的音樂概念(就像我們對和聲和旋律的討論)。RNN的隱藏表示可以用來聚集我們的音樂數據集以找到相似的歌曲。

讓我們從無條件的模型中抽取最後一首歌詞來結束這篇文章:D:

The story ends

The sound of the blue

The tears were shining

The story of my life

I still believe

The story of my life

註:本文翻譯自博文《Machine Learning and Computer Vision artisan》,內容僅為作者觀點,不代表DT財經立場。

編譯 | 余若男 李振 吳章勇

題圖 | 站酷海洛

▍數據俠門派

本文數據俠Daniil Pakhomov,約翰斯·霍普金斯大學博士生。主要研究領域為計算機視覺、深度學習及機器學習。關注醫學影像方面的圖像識別與目標分割。

▍加入數據俠

「數據俠計劃」是由第一財經旗下DT財經發起的數據社群,包含數據俠專欄、數據俠實驗室系列活動和數據俠聯盟,旨在聚集大數據領域精英,共同挖掘數據價值。了解數據俠計劃詳情請回復「數據俠計劃」,投稿、合作請聯繫datahero@dtcj.com。


推薦閱讀:

R語言從入門到精通之二數據集創建
不要盲目相信大數據結論, 有時候小數據更靠譜!
kylin 同步原理及加入重試邏輯
精準營銷的兩階段預測模型-客戶響應模型+代碼
大數據分析挖掘培訓課程,數據分析挖掘應該從哪裡開始學習

TAG:RNN | 作曲 | 大數據分析 |