1. 程式人生 > >20行python程式碼實現雞湯智慧生成器

20行python程式碼實現雞湯智慧生成器

“Don’t think of the overwhelming majority of the impossible.”
“不要去想不可能之事”
“Grew up your bliss and the world.”
“努力贏得自己的幸福和世界”
“what we would end create, creates the ground and you are the one to warm it”
“我們想要結束的創造卻造就了大地,唯你抱以溫情”
“look and give up in miracles”
“仰望奇蹟,放棄幻想”

但其實上面這些雞湯句子全都是電腦生成的,而且其生成雞湯文所用的程式還不到 20 行 Python 程式碼。

一提到自然語言生成,人們通常會覺得這一定是很先進的 AI 系統,使用了很高階的數學知識。但是,事實並非如此。在本文我(作者 Ramtin Alami——譯者注)會用馬爾科夫鏈(Markov chains)和一個很小的雞湯文資料集生成新的雞湯文。

馬爾科夫鏈

馬爾科夫鏈是一種隨機模型,能根據先前的事件單獨預測一個事件。舉個簡單的例子,就用我家喵主子的生活狀態轉換解釋一下吧。我家喵主子總是要麼吃、要麼睡、要麼玩玩具。她大部分時間都是在睡覺,但是偶爾會睡醒起來用膳。通常,用膳過後她會倍兒精神,開始玩玩具,玩夠了就回去睡,然後再睡醒去吃。

用馬爾科夫鏈就能很容易地模擬出我家喵主人的生活狀態,因為她會根據之前的狀態決定下一步去幹嘛。她一般不會醒來後直接去玩玩具,但是吃完東西后,有很大概率去玩一會。這些生活狀態轉換也可以用圖表的形式表現出來:

每個迴圈是一個生活狀態,箭頭所指的是下一個生活狀態,箭頭旁邊的數字是指她從一種狀態轉到另一種狀態的可能性。我們可以看到,狀態轉換的可能性基本上只根據上一種生活狀態。

使用馬爾科夫鏈生成文字

使用馬爾科夫鏈生成文字也是採用了相同的理念,努力找到一個詞出現在另一個詞後面的概率。為了確認這些轉換的可能性,我們用一些例句訓練模型。

例如,我們使用下面這些句子訓練模型:

我喜歡吃蘋果(I like to eat apples)。 你吃橘子(You eat oranges)。

從上面這兩個訓練句子,我們可以總結出“I”(我),“like”(喜歡)和“eat”(吃)總是以相同的順序出現,而“you”(你)和“eat”(吃)一直連在一起。但是“orange”(橘子)和“apples”(蘋果)出現在詞彙“eat”(吃)後面的機率是相等的。下面這個轉換圖表能更好地顯示我上面講的這一堆:

這兩個訓練句子能夠生成兩個新的句子,但是情況不總是這樣。我用下面這四個句子訓練了另一個模型,結果大不相同:

我朋友做出的樹莓派在鎮上最好(my friend makes the best raspberry pies in town)。 我覺得蘋果派最好(i think apple pies are the best pies)。 史蒂夫覺得蘋果做出的電腦在世界上最好(steve thinks apple makes the best computers in the world)。 我有兩臺電腦,它們不是蘋果電腦,因為我既不是史蒂夫也不是大款(I own two computers and they’re not apple because I am not steve or rich)。

用這四個句子訓練的模型的轉換圖表會大得多。

雖然圖表和典型的馬爾科夫鏈轉換圖表看起來大不一樣,但兩者背後的主要理念是一樣的。

從起始節點開始的路徑會隨機選取接下來的詞,一直到終端節點。詞語之間相連路徑的寬度表示詞彙被選取的概率。

雖然只用四個句子訓練,上面的模型卻能夠生成幾百個不同的句子。

程式碼

上面這個文字生成器的程式碼非常簡單,除了Python的隨機模組,不需要任何額外的模組或程式庫。程式碼包含兩部分,一個用來訓練,另一個用來生成。

訓練

訓練程式碼構造了我們稍後會用來生成雞湯句的模型。我用了一個詞典作為模型,其包含一些詞彙作為關鍵點,還有一列可能跟隨詞作為對應值。例如,用上面“我喜歡吃蘋果”(‘I like to eat apples’)和“你吃橘子”(You eat oranges)這兩個句子訓練的模型的詞典會是這樣:

{'START': ['i', 'you'], 'i': ['like'], 'like': ['to'], 'to': ['eat'], 'you': ['eat'], 'eat': ['apples', 'oranges'], 'END': ['apples', 'oranges']}

我們不需要計算跟隨詞出現的概率,因為如果它們出現的概率較高,那麼它們會在可能跟隨詞列表中多次出現。例如,如果我們想另外新增訓練句子“我們吃蘋果”(‘we eat apples’),詞彙“蘋果”(‘apples’)已經在兩個句子中出現在詞彙“吃”(eat)後面,那麼它出現的概率就會很高。在該模型的詞典中,如果在“吃”(eat)列表中出現兩次就屬於出現概率較高。

{'START': ['i', 'we', 'you'], 'i': ['like'], 'like': ['to'], 'to': ['eat'], 'you': ['eat'], 'we': ['eat'], 'eat': ['apples', 'oranges', 'apples'], 'END': ['apples', 'oranges', 'apples']}

另外,在上面的模型詞典中還有兩個術語:“起始”(START)和“結束”(END),它們表示一個生成的句子的起始詞和結束詞。

for line in dataset_file:
   line = line.lower().split()
   for i, word in enumerate(line):
       if i
== len(line)-1:  
           model['END'] = model.get('END', []) + [word]
       else:    
           if i == 0:
               model['START'] = model.get('START', []) + [word]
           model[word] = model.get(word, []) + [line[i+1]]

生成雞湯句

生成器部分包含一個迴圈。它首先會選取一個隨機的起始詞並將其新增至一個列表,然後會在詞典中所搜包含潛在跟隨詞的列表,並隨機選取一個列表,將新的選取的詞新增至該列表。生成器會一直選擇隨機的潛在跟隨詞直到找到結束詞,然後會停止迴圈,輸出生成的句子或所謂的“名言”。

import random
generated = []
while True:
   if not generated:
       words = model['START']
   elif generated[-1] in model['END']:
       break
   else:
       words = model[generated[-1]]
   generated.append(random.choice(words))

我用馬爾科夫鏈生成了不少雞湯文,但是作為文字生成器,你可以輸入任何文字,讓它生成相似的句子。

用馬爾科夫鏈文字生成器還可以做別的很酷的事情,就是混合不同的文字型別。例如,在我最喜歡的電視劇《瑞克和莫蒂》中,有個角色叫做“亞拉道夫·林肯勒”(Abradolf Lincler)就是用“亞拉伯罕·林肯”和“阿道夫·希特勒”兩人的名字混合而成。

你也可以這麼操作,把一些名人的名字輸入馬爾科夫鏈中,讓它生成好玩的混合人物名,(比如…

郭達·斯坦森

尼古拉斯.趙四

甚至你還能更進一步,把一些名人的名言,比如上面說的林肯和希特勒的演講句子用馬爾科夫鏈混合後生成全新風格的演講。

馬爾科夫鏈幾乎可以應用在所有領域,雖然文字生成並非最有用處的應用,但我確實覺得這項應用很有意思,萬一你生產的雞湯文有朝一日吸引來的粉絲比咪蒙還多呢?

∞∞∞

IT派 - {技術青年圈}持續關注網際網路、區塊鏈、人工智慧領域

公眾號回覆“Python”

邀你加入{ IT派Python技術群 }