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

  • 2019 年 12 月 12 日
  • 筆記

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

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

  • 用戶可以使用人類自然語言的方式來表達自己的意圖。
  • 可以依據用戶的回饋進行在線增量學習,使用的越久,能回答得問題越多。
  • 採用非侵入式設計,通過幾個簡單的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 種方式來進行回饋,當系統給出多個候選答 案,但是正確答案沒有排在首位時,用戶可以通過標註最佳答案來 進行回饋。可以定期讓問答引擎自主學慣用戶的回饋,重新訓練意 圖分類器並更新問答語料庫,當用戶自己或其他用戶再次問到相同 含義的問題時即可得到相應的答案。 由於我們可以自己調教機器人,所以你可以將其調教成僅屬於你自己的獨一無二的性格。