1. 程式人生 > >用機器學習打造聊天機器人(三) 設計篇

用機器學習打造聊天機器人(三) 設計篇

本文是用機器學習打造聊天機器人系列的第三篇,通過閱讀本文你將對聊天機器人的實現有一個大致的思路。

我們的聊天機器人將具備什麼樣的特性?

  • 使用者可以使用人類自然語言的方式來表達自己的意圖。
  • 可以依據使用者的反饋進行線上增量學習,使用的越久,能回答得問題越多。
  • 採用非侵入式設計,通過幾個簡單的API就可以接入。
  • 語料資料使用簡單的txt格式,只要更換txt,就可以服務於不同的知識領域。
  • 提供做為Demo的UI系統,帶有簡單的登入認證。

開源聊天機器人框架ChatterBot簡介

本專案基於chatterbot0.8.7來開發,但不僅於此。讓我們先對chatterbot做一個簡單的瞭解。

什麼是ChatterBot?

ChatterBot是一個基於機器學習的口語式對話引擎,基於python編寫,可以基於已有的會話集合返回匹配問題的響應。ChatterBot的非侵入式語言設計,使得我們可以在其上訓練任何語言的對話模型。

怎麼使用chatterbot?

首先,安裝chatterbot0.8.7版本:

pip install ChatterBot==0.8.7

建立一個chat bot例項:

from chatterbot import ChatBot
chatbot = ChatBot("Ron Obvious")

訓練你的機器人:

from chatterbot.trainers import ListTrainer

# 對話語料對,一問一答
conversation = [
    "Hello",
    "Hi there!",
    "How are you doing?",
    "I'm doing great.",
    "That is good to hear",
    "Thank you.",
    "You're welcome."]
trainer = ListTrainer(chatbot)
trainer.train(conversation)

獲取響應,"Thanks!"在上面的語料對中是沒有的,但是其預設使用的Levenshtein distance演算法能讓引擎從問答對中選出一個相近的回答:

response = chatbot.get_response("Thanks!")
print(response) # 將輸出You're welcome.

ok,如果你也已經得到了上面的正確輸出,你可能想說,就這麼簡單?其實如果從簡單體驗一下的角度來說,就是這麼簡單。但是如果你想做一個像那麼回事的聊天機器人出來,那麼還有一段路要走,比如Levenshtein distance演算法其實過於簡單了,會導致一些答非所問的情況,除此之外,還有一些其他我們需要完善的地方,具體會在下一個話題中討論。

如此簡單就實現了一個聊天機器人,其中有沒有什麼不妥?

的確,這裡面是有一些問題的:

  • chatterbot的預設實現,可以正常處理1000左右的問答對,但是隨著資料量的繼續增加,就會十幾秒甚至幾十秒才能獲取到回答,以及更長的時間才能訓練完成(這裡有一點需要注意,就是chatterbot中提到的訓練,其實就是將問答語料寫入資料庫中),這顯然是不能接受的。
  • 預設採用的Levenshtein distance演算法在句子的相似度比較上過於簡單了,它只關心一句話變成另一句話需要的最小的修改步驟有多少,認為步驟越少,兩句話越相近,所以它並不會考慮句子中每個詞的具體含義,比如不知道西紅柿和番茄雖然每個字都不同,長度也不同,但是其實指的是同一個東西。

沒錯,我們要解決的主要問題就是上面列出的2個問題,概括來說就是2個方面,一個是效能,另一個是智慧。雖然問題只有2個,但是解決起來確是要花費一番功夫的。
首先,讓我們來分析一下效能的問題:
1、chatterbot預設採用sqlite資料庫,sqlite是一個關係型資料庫,非常輕量,無需配置和部署,但是當資料量比較大的時候,寫效能相對mongodb等nosql資料庫還是有差距的,對於我們的場景,由於不存在強事務要求,所以建議切換到mongodb資料庫,你會發現訓練速度會有較大的提升;
策略:chatterbot除了支援sqlite,還支援mongodb,所以可以通過修改配置的方式切換到mongodb資料庫,示例如下:

chat = ChatBot(
            bot_name,
            database=bot_name,
            database_uri=current_app.config['DATABASE_URI'],
            storage_adapter="chatterbot.storage.MongoDatabaseAdapter")

2、chatterbot將所有問答對儲存在一起,比如在mongodb中,是儲存在一個集合裡的,這樣匹配問題的時候,就要和所有的問答對資料比較一遍,如果資料量很大的話,效率肯定是很慢的;
策略:將問答對分類儲存,比如在mongodb中,不同型別的問答對儲存在不同的集合裡,這一步稱為意圖分類,所以我們需要通過另外的演算法來確定輸入句子的意圖類別,然後在指定類別下去判斷句子和哪些問題更為近似,然後返回對應的回答。這樣做的好處是方便維護,大體量的問答對被拆分到各個對應的類別下,分別匹配,體量自然會減少很多,並且某一型別的問答對的資料量增加,對其他型別問答對的響應速度沒有直接的影響。
3、chatterbot區分問題和答案是根據句子是否出現在in_response_to屬性下的text屬性中來判斷的,這導致需要先查詢出in_response_to下的所有text,然後根據text再查出所有屬於問題的句子,這樣的查詢效率是很低的;
策略:在準備問答對語料的時候,分別對問題和答案進行標識,比如用Q和A做字首,這樣儲存到資料庫中後,查詢的時候就可以用Q來直接匹配出問題,而不需要多次查詢資料庫。
4、chatterbot預設採用Levenshtein distance演算法將當前輸入的問題和資料庫裡每一個問答記錄進行比較,具體做法是先查出所有的問答句子,然後for迴圈進行一一比較,選擇出最相似的句子做為響應返回,效率自然不會高。
策略:改為使用詞向量進行比較,具體在下面的智慧度策略中有介紹。
ok,我們再來聊聊如何提升chatterbot的智慧度:
1、採用餘弦相似度演算法代替Levenshtein distance演算法
Levenshtein distance演算法只是單純的計算一個句子變成另一個句子需要經過的最小的編輯步驟,並沒有考慮句子中詞彙本身的含義,所以它並能識別出"蘋果"比起"香水"來說和"香蕉"在語義上靠的更近。而餘弦相似度是指比較兩個向量之間的餘弦相似度,向量當然分別是輸入句子的句向量和資料庫中所有問題句子的句向量,而句子轉為向量的方式是採用的word2vec,該方法在後續講原理的部分會具體介紹,這裡我們只需要知道詞向量模型可以將詞轉為對應的向量,這些向量在空間中呈現一種語義上的關係,比如用詞向量表示我們的詞的時候,會發現 King的向量-Man的向量+Woman的向量=Queen的向量。
那麼句子又是怎麼轉成向量的呢?這裡我們採用了平均向量的方法,就是先對句子分詞,然後將詞向量相加再除以向量的個數。至於為什麼餘弦值可以表示兩個向量的相似度,我們同樣也會在原理的部分進行介紹。
2、採用向量化平行計算策略代替for迴圈比對
有了句子的向量表示後,我們就可以採用一些平行計算的方式來代替for迴圈,具體的操作是將所有資料放到一個矩陣中一起計算,CPU雖然遠比不上GPU的平行計算速度,但是比起for迴圈的方式仍然可以帶來幾十到幾百倍計算速度的提升。在此也體現了chatterbot的優秀設計,使得我們可以在不更改原始碼的情況下就替換掉原有的匹配演算法,具體見程式碼篇的介紹。

一個問題從輸入到給出回覆將經歷什麼?

到此,我們解釋了為什麼需要基於chatterbot再做一些事情,以及如何做,現在我們來看看一個問題從輸入到給出回覆具體經歷了哪些步驟:

使用者提問後,由意圖推測元件接收問題,元件內部進行特徵提 取後,傳給意圖分類器去預測問題所屬的類別(比如:這是一個關於 “電影演員”的問題,或關於“電影上映時間”的問題),接著問題會傳遞到語義 理解模組,並自動觸發合適的語義理解例項去嘗試匹配問題對應的 答案,這裡說的語義理解就是在指定的意圖分類下,去匹配具體的問題,比如“你覺得功夫類電影誰演的好?”,或者“愛情片什麼時間段上映比較合適?”等。整個過程主要是採用詞向量模型構造問題句子的特徵向量,通過貝葉斯演算法進行意圖分類,以及 採用餘弦相似度演算法計算問題和答案的匹配分數。此時引擎會根據 匹配分數結合閾值進行分析,從而決定是直接返回答案,還是降級處理,所以有些場景下可能會返回多個候選答案,候選答案會根據分數降序排列。

如何讓機器人說我想聽的話?

前面說的都是如何根據輸入的問題給與合適的回覆,本篇主要討論如何調教機器人說你想聽的回覆,具體流程如下:

使用者提問後,如果系統沒能給出滿意的答案,使用者可以通過新增問答對、修訂答案 2 種方式來進行反饋,當系統給出多個候選答 案,但是正確答案沒有排在首位時,使用者可以通過標註最佳答案來 進行反饋。可以定期讓問答引擎自主學習使用者的反饋,重新訓練意 圖分類器並更新問答語料庫,當用戶自己或其他使用者再次問到相同 含義的問題時即可得到相應的答案。
由於我們可以自己調教機器人,所以你可以將其調教成僅屬於你自己的獨一無二的性格