未來(lái)人工智能應(yīng)用程序的主要是構(gòu)建能夠從一些數(shù)據(jù)集學(xué)習(xí)并生成原始內(nèi)容的網(wǎng)絡(luò)。這個(gè)想法已被應(yīng)用于自然語(yǔ)言處理(NLP),這就是AI社區(qū)如何開(kāi)發(fā)一種稱為語(yǔ)言模型的東西。
語(yǔ)言模型的前提是要學(xué)習(xí)如何在某些文本中構(gòu)建句子并生成原始內(nèi)容的網(wǎng)絡(luò)。
在本文中,想嘗試使用饒舌作為一個(gè)有趣的項(xiàng)目,看看是否可以重新制作流行的加拿大說(shuō)唱歌手Drake的歌詞。
同時(shí),也想分享一個(gè)通用的機(jī)器學(xué)習(xí)項(xiàng)目管道,因?yàn)槿绻悴恢缽哪睦镩_(kāi)始,那么構(gòu)建你自己的東西往往是非常困難的。
這一切都始于尋找所有Drake歌曲的數(shù)據(jù)集,基于時(shí)間的問(wèn)題,所以這里構(gòu)建了一個(gè)快速腳本,把名為metrolyrics.com的流行網(wǎng)站的網(wǎng)頁(yè)挖出來(lái)。
這兒用了一個(gè)眾所周知的Python包抓取出頁(yè)面,這是在大約5分鐘內(nèi)從Justin Yek的精彩教程中摘錄的。作為一個(gè)說(shuō)明,實(shí)際上預(yù)先定義了想要獲得的歌曲,實(shí)際上是預(yù)先定義了想要獲取的歌曲,這就是為什么您可能會(huì)注意到在上面的代碼中遍歷歌曲dataframe。
DataFrame存儲(chǔ)所有歌曲的歌詞
在運(yùn)行scraper之后,將所有歌詞都格式化為.csv文件,并準(zhǔn)備開(kāi)始預(yù)處理數(shù)據(jù)并構(gòu)建模型。
關(guān)于模型
現(xiàn)在,我們將談?wù)撐谋旧傻哪P?,這是真正的原料部分。我將首先討論模型設(shè)計(jì)和一些使抒情生成成為可能的重要元素,然后我們將著手實(shí)施它。
建立語(yǔ)言模型主要有兩種方法:(1)字符級(jí)模型和(2)字級(jí)模型。
每個(gè)模型的主要區(qū)別來(lái)自您的輸入和輸出,我將詳細(xì)討論它們各自如何在這里工作。
字符級(jí)模型
在字符級(jí)模型的情況下,您的輸入是一系列字符seed,您的模型負(fù)責(zé)預(yù)測(cè)下一個(gè)字符new_char。然后把seed + new_char一起使用來(lái)產(chǎn)生下一個(gè)字符等等。請(qǐng)注意,由于您的網(wǎng)絡(luò)輸入必須始終具有相同的形狀,因此我們實(shí)際上將在此過(guò)程的每次迭代中丟失一個(gè)字符。這是一個(gè)簡(jiǎn)單的可視化圖片:
圖2用字符級(jí)語(yǔ)言模型生成字的迭代過(guò)程
在每一次迭代中,模型基本上都是預(yù)測(cè)給定字符的下一個(gè)最可能的字符是什么,或者使用條件概率,這可以描述為找到最大值P(new_char|seed),new_char字母表中的任何字符在哪里。在我們的例子中,字母表是一組所有英文字母和一個(gè)空格字符(注意,您的字母表可以非常不同,并且可以包含您想要的任何字符,這取決于您正在構(gòu)建的模型。
字級(jí)模型
字級(jí)模型幾乎與字符一樣,但它會(huì)生成下一個(gè)字,而不是下一個(gè)字符。這里有一個(gè)簡(jiǎn)單的例子:
圖3用字符級(jí)語(yǔ)言模型生成詞的迭代過(guò)程
現(xiàn)在,在這個(gè)模型中,我們正在向前看一個(gè)單位,但這次我們的單位是一個(gè)單詞,而不是一個(gè)字符。所以,我們正在尋找P(new_word|seed),其中,new_word詞匯中的詞語(yǔ)。
請(qǐng)注意,現(xiàn)在我們正在搜索比以前更大的集合。使用字母表時(shí),我們搜索了大約30個(gè)項(xiàng)目,現(xiàn)在我們?cè)诿看蔚卸妓阉鞲囗?xiàng)目,因此單詞級(jí)別算法在每次迭代中都比較慢,但由于我們生成的是整個(gè)單詞而不是單個(gè)字符,因此它其實(shí)并沒(méi)有那么糟糕。作為我們的字符級(jí)模型的最后一個(gè)注記,我們可以有一個(gè)非常多樣化的詞匯表,我們通常通過(guò)從數(shù)據(jù)集中找到獨(dú)特的單詞(通常在數(shù)據(jù)預(yù)處理階段完成)來(lái)開(kāi)發(fā)它。由于詞匯表可以變得無(wú)限大,因此有許多技術(shù)可以提高算法的效率,例如詞嵌入,這是為了以后的文章。
出于本文的目的,將重點(diǎn)介紹字符級(jí)模型,因?yàn)樗膶?shí)現(xiàn)更簡(jiǎn)單,并且對(duì)字符級(jí)模型的理解可以稍后輕松轉(zhuǎn)移到更復(fù)雜的字級(jí)模型。
對(duì)于字符級(jí)模型,我們將不得不按照以下方式預(yù)處理數(shù)據(jù):
標(biāo)記數(shù)據(jù)集 ?- 當(dāng)我們將輸入饋送到模型中時(shí),我們不想只用字符串進(jìn)行輸入,我們想要用字符來(lái)代替,因?yàn)檫@是一個(gè)字符級(jí)模型。所以我們將把所有歌詞分成一個(gè)字符列表。
定義字母表 - 現(xiàn)在,我們知道可能出現(xiàn)在歌詞中的每一種字符(來(lái)自之前的標(biāo)記化步驟),我們希望找到所有的獨(dú)特字符。為了簡(jiǎn)單起見(jiàn),整個(gè)數(shù)據(jù)集并沒(méi)有那么大(只使用了140首歌曲),這里將堅(jiān)持使用英文字母和一些特殊字符(比如空格),并且會(huì)忽略所有數(shù)字和其他東西(由于數(shù)據(jù)集很小,寧愿讓模型預(yù)測(cè)更少的字符)。
創(chuàng)建訓(xùn)練序列 ?- 我們將使用滑動(dòng)窗口的概念,并通過(guò)在句子上滑動(dòng)固定大小的窗口來(lái)創(chuàng)建一組訓(xùn)練示例。這是一個(gè)很好的可視化方式:
圖4輸入/輸出生成的數(shù)據(jù)集上的滑動(dòng)窗口
通過(guò)一次移動(dòng)一個(gè)字符,我們可以生成長(zhǎng)度為20個(gè)字符的輸入和一個(gè)輸出字符。此外,作為獎(jiǎng)勵(lì),由于我們一次只移動(dòng)一個(gè)角色,實(shí)際上我們正在顯著擴(kuò)大數(shù)據(jù)集的大小。
4. 標(biāo)簽編碼訓(xùn)練序列-最后,因?yàn)槲覀儾幌MP褪褂迷甲址ūM管理論上可能是這樣,因?yàn)樽址诩夹g(shù)上只是一個(gè)數(shù)字,所以你幾乎可以說(shuō)ASCII編碼了所有字符為了我們)。我們將把一個(gè)唯一的整數(shù)與我們字母表中的每個(gè)字符關(guān)聯(lián)起來(lái),這可能是您聽(tīng)說(shuō)過(guò)的標(biāo)簽編碼。這也是時(shí)候我們創(chuàng)建了兩個(gè)非常重要的映射character-to-index和index-to-character。通過(guò)這兩種映射,我們可以將任何字符編碼為唯一的整數(shù),并將模型的輸出從索引解碼為其原始字符。
5. 單熱編碼數(shù)據(jù)集 ?- 由于我們正在處理分類數(shù)據(jù),所有字符都屬于某種類別,所以我們將不得不編碼輸入列。下面是關(guān)于單熱編碼實(shí)際上由Rakshith Vasudev寫的一個(gè)很好的描述。
一旦我們完成了這五個(gè)步驟,我們已經(jīng)完成了很多工作,現(xiàn)在我們所要做的就是構(gòu)建模型并進(jìn)行訓(xùn)練。如果您想深入了解細(xì)節(jié),以下是前五個(gè)步驟的代碼。
為了使用一組以前的字符來(lái)預(yù)測(cè)下一個(gè)字符,我們將要使用遞歸神經(jīng)網(wǎng)絡(luò)(RNN)或?qū)iT的長(zhǎng)期短期記憶網(wǎng)絡(luò)(LSTM)。如果你對(duì)這兩個(gè)概念都不熟悉,我建議你閱讀它們。RNNs通過(guò)Pranoy拉達(dá)克里希和LSMTs通過(guò)Eugine康。如果你只是需要一個(gè)復(fù)習(xí)或感覺(jué)勇敢,這里是快速破?。?/p>
RNN
通常情況下,您會(huì)看到網(wǎng)絡(luò)看起來(lái)像網(wǎng)絡(luò),并從多個(gè)節(jié)點(diǎn)匯聚到單個(gè)輸出。像這樣的東西:
圖5神經(jīng)網(wǎng)絡(luò)的圖像
這里我們有一個(gè)輸入點(diǎn)和一個(gè)輸出點(diǎn)。這對(duì)于輸入不連續(xù)的輸入非常有用,輸入順序不會(huì)影響輸出。但在我們的例子中,字符順序?qū)嶋H上非常重要,因?yàn)樽址木唧w順序是創(chuàng)建獨(dú)特單詞的順序。
RNN通過(guò)創(chuàng)建一個(gè)接受連續(xù)輸入的網(wǎng)絡(luò)來(lái)解決這個(gè)問(wèn)題,并且使用前一個(gè)節(jié)點(diǎn)的激活作為下一個(gè)節(jié)點(diǎn)的參數(shù)。
圖6簡(jiǎn)單RNN的概述
記住我們的一個(gè)序列的情況,Tryna_keep_it_simple我們提取后面的下一個(gè)字符應(yīng)該是_。這正是我們希望我們的網(wǎng)絡(luò)所做的。我們要輸入每個(gè)字符進(jìn)入的字符序列,T?—?> s<1>, r -> x<2>, n -> x<3>... e-> x LSTM 簡(jiǎn)單的RNN對(duì)他們來(lái)說(shuō)有一個(gè)問(wèn)題,他們不擅長(zhǎng)將信息從非常早的細(xì)胞傳遞到后面的細(xì)胞。例如,如果您正在查看Tryna keep it simple is a struggle for me預(yù)測(cè)最后一個(gè)單詞me(可能是字面上任何人或任何類似于:貓,土豆)的句子,如果您無(wú)法回顧并查看之前出現(xiàn)的其他單詞,則非常困難。 LSTM通過(guò)給每個(gè)單元添加一點(diǎn)內(nèi)存來(lái)解決這個(gè)問(wèn)題,該單元存儲(chǔ)了一些關(guān)于之前發(fā)生的事情的信息(以前出現(xiàn)過(guò)的單詞),這就是為什么LSTM看起來(lái)像這樣:
圖7 LSTM可視化,取自Andrew Ng的深度學(xué)習(xí)專門化
除了傳遞a 實(shí)際建設(shè) 這里用Keras作為構(gòu)建網(wǎng)絡(luò)的框架,但事實(shí)上,這可以通過(guò)手工完成,唯一的區(qū)別是它需要更長(zhǎng)的時(shí)間。
正如您所看到的,我們正在使用LSTM模型,并且我們也在使用批處理,這意味著我們一次性對(duì)數(shù)據(jù)子集進(jìn)行訓(xùn)練,而不是一次性加快訓(xùn)練過(guò)程。
在我們的網(wǎng)絡(luò)訓(xùn)練完成之后,我們將如何尋找下一個(gè)角色。我們將得到一些隨機(jī)種子,這將是一個(gè)由用戶輸入的簡(jiǎn)單字符串。然后我們將使用種子作為網(wǎng)絡(luò)的輸入來(lái)預(yù)測(cè)下一個(gè)字符,我們將重復(fù)這個(gè)過(guò)程,直到我們產(chǎn)生了一串新的行,類似于上面顯示的圖2。
以下是生成的歌詞的一些例子
注意:歌詞沒(méi)有被審查,所以請(qǐng)自行判斷
您可能已經(jīng)注意到,單詞有時(shí)是沒(méi)有意義的,這是字符級(jí)模型的一個(gè)非常常見(jiàn)的問(wèn)題,這是由于輸入數(shù)據(jù)通常在單詞中間切片,這會(huì)使網(wǎng)絡(luò)學(xué)習(xí)并生成奇怪的新單詞。
這是用字級(jí)模型解決的問(wèn)題,但對(duì)于少于200行的代碼,字符級(jí)模型仍然非常令人印象深刻。
其他應(yīng)用
在這個(gè)字符級(jí)網(wǎng)絡(luò)中描述的想法可以擴(kuò)展到比歌詞生成更有用的許多其他應(yīng)用程序。
例如,這與iPhone鍵盤上的下一個(gè)!單詞建議的工作方式是相同的。
鍵盤下一個(gè)單詞預(yù)測(cè)
想象一下,如果您構(gòu)建了足夠準(zhǔn)確的Python語(yǔ)言模型,則不僅可以自動(dòng)完成關(guān)鍵字或變量名稱,還可以自動(dòng)完成大量代碼,從而為程序員節(jié)省大量時(shí)間。
您可能已經(jīng)注意到代碼有缺失的部分,這是github的地址:
https://github.com/keras-team/keras/blob/master/examples/lstm_text_generation.py
3>2>1>聯(lián)系客服