更多幹貨內容請關注微信公眾號“AI 前線”,(ID:ai-front)
不論是已經成熟的企業或是正要上線新業務,你都可以利用文字資料來驗證、提升以及擴充套件產品的功能。這種從文字資料中提取含義並進行學習的科學叫做自然語言處理(Natural Language Processing, NLP),是當前非常熱門的研究課題。
NLP 是一個非常大的研究領域且每天都在產生一些新的激動人心的成果。經過和上百家企業的合作,我們 Insight 團隊從中發現了幾個關鍵的實際應用,這些應用會有更高的出現頻率:
識別使用者 / 客戶不同的使用者群(例如預測使用者流失、生命週期價值、產品偏好等)
精準檢測和提取反饋分類(例如正面和負面的評論 / 觀點,對諸如衣服尺寸、舒適度等一些特別屬性的提及)
根據意圖進行文字分類(例如請求普通幫助,緊急問題處理)
鑑於 NLP 的文章和指南很多都存在於網路上,我們發現很難找到對處理這些問題徹底有效的指導或建議。
我們在這一年裡做了數百個專案,並吸取了全美頂尖團隊的建議,整理出這篇文章來說明如何使用機器學習解決上述問題。我們將從最簡單可行的方法說起,然後進階到更細緻的解決方案,例如特徵工程、詞向量以及深度學習等。
讀完這篇文章,你將會知道如何去:
收集、準備和檢測資料
從建立簡單模型開始,必要時使用深度學習來過渡
解釋和理解模型,來確保你實際捕獲的是有效資訊而不是噪聲
這篇文章是一份循序漸進的操作指南,也是一份對高效標準化過程的高度概括。
文章還附帶了一份互動筆記,裡面對所有涉及到的技術都進行了論證和應用。你可以嘗試邊執行程式碼邊看下文。
每一個機器學習問題都始於資料,比如一組郵件、帖子或是推文。文字資訊的常見來源包括:
商品評價(來自 Amazon、Yelp 以及其他 App 商城)
使用者產出的內容(推文、Facebook 的帖子、StackOverflow 的提問等)
問題解決(客戶請求、技術支援、聊天記錄)
在這篇文章中,我們將使用 CrowdFlower 提供的一個資料集,名為“社交媒體中的災難(Disasters on Social Media)”。
貢獻者們檢視了超過 10000 條具有類似“著火”、“隔離”、“混亂”等搜尋關鍵詞的推文,然後標記這個推文是否和災難事件有關(與之相反的是一些玩笑、電影點評或是一些非災難性的事件)。
我們的任務是分辨出哪些推文是真正和災難事件相關的,而不是一些類似電影描述的不相關話題。為什麼呢?一個潛在的應用是針對突發事件對執法人員進行專門的提醒,而不會被其他無關資訊,比如 Adam Sandler 新上映的電影所干擾。這項任務中一個特別的挑戰是這兩種情況在搜尋推文的時候都用到了相同的檢索詞,所以我們只能通過細微的差別去區分他們。
在下面的文章中,我們將把與災難事件相關的推文稱為“災難”,將其他推文稱為“不相關的”。
我們已經標註過資料,所以知道推文是如何分類的。如 Richard Socher 所說,比起優化一個複雜的無監督學習方法,尋找和標記足夠多的資料來訓練模型會更加快捷、簡單和廉價。
Richard Socher 的高階技巧
我們要遵循的首要原則是:“你的模型必須和你的資料一樣好。”
資料科學家的一個必備技能是知道自己的下一步操作是處理模型還是資料。有一個好的經驗法則是先觀察資料然後進行資料清洗。一個乾淨的資料集能使模型學習到有意義的特徵而不會被一些不相關的噪聲影響。
可以借鑑下方的列表來進行資料清洗:(檢視程式碼獲取更多資訊)
去除一切不相關的字元,比如任何非字母數字的字元
標記你的文字,將他們拆分為獨立的單詞
去除不相關的詞語,比如 @這類提醒或是 url 連結
將所有字母轉換成小寫,這樣“hello”,“Hello”,“HELLO”就會被當做同樣的單詞處理
將拼錯的單詞或是多種拼法的單詞與某個特定的表達繫結(比如:“cool”/“kewl”/“cooool”)
考慮詞形還原(比如將“am”,“are”,“is”都看做“be”)
完成這些步驟並檢查完其他錯誤後,我們就可以使用這些乾淨的、標記過的資料進行模型訓練了!
機器學習模型會使用數值作為輸入。例如處理影象的模型會用矩陣來表示每個顏色通道畫素的亮度。
用數字矩陣表現的笑臉
我們的資料集是一系列的句子,為了使我們的演算法能從資料中提取特徵,首先需要找到一種演算法能夠理解的表達方式,比如一串數字。
通常為計算機解釋文字的方法是將每一個字元都編為一個獨立的數字(例如 ASCII 碼)。如果使用這種簡單的表達來做分類器,需要我們的資料從頭開始學習詞語的結構,這對大多數資料集來說是很難實現的。所以我們需要一種更上層的方法。
例如,我們可以為資料集中的所有單詞製作一張詞表,然後將每個單詞和一個唯一的索引關聯。每個句子都是由一串數字組成,這串數字是詞表中的獨立單詞對應的個數。通過列表中的索引,我們可以統計出句子中某個單詞出現的次數。這種方法叫做 詞袋模型,它完全忽略了句子中單詞的順序。如下圖所示:
用詞袋模型表示句子。句子在左邊,模型表達在右邊。向量中的每一個索引代表了一個特定的單詞。
在“社交媒體中的災難”樣本詞表中大概會有 20000 個單詞,這意味著每句句子都會用一個長度為 20000 的向量來表示。向量的 大部分會被 0 填充,因為每句話只包含了詞表中很小的一個子集。
為了看出嵌入的工作是否真正抓住了和問題相關的資訊(比如推文是否與災難相關),有一個好方法是將它們視覺化,然後觀察結果是否有很好的分佈。考慮到詞表通常很大,而且用 20000 維的資料做視覺化是基本不可能的,所以我們使用了 PCA 這種技術將資料降到二維。繪製如下:
詞袋模型嵌入的視覺化
兩個分類看起來沒有很好的分離,這可能是我們選擇的嵌入方法的特徵或是單純因為維度的減少引起的。為了瞭解詞袋模型的特徵是否會起一些作用,我們可以試著基於它訓練一個分類器。
當初次接觸一個問題,通常來說最好的方法是先挑選一個能解決問題的最簡單的工具。當提到資料分類時,一般最受歡迎的是通用性和可解釋性兼具的邏輯迴歸演算法。這種演算法很容易訓練而且結果也是可解釋的,你可以很輕鬆地從模型中提取出最重要的一些係數。
我們將資料分為兩個集合,訓練集用於匹配模型,測試集用於觀察應用在未知資料上的效果。訓練後我們得到了 75.4% 的精確度。結果還不錯!推測出現最多的類(“不相關”)只能達到 57%。但是,即使是 75% 的精確度也已經足夠好了,我們決不能在還沒有理解模型的情況下就開始應用它。
第一步是理解我們的模型會產生哪些錯誤型別,哪些錯誤是我們最不希望出現的。在例子中,誤報(false positive)是指將不相關的推文歸為災難,漏報(false negative)是指將真實災難歸為不相關的。如果需要優先響應所有潛在事件,我們需要降低漏報率。如果是資源有限,我們就需要優先降低誤報率來減少錯誤告警。我們可以使用混淆矩陣來視覺化這些資訊,它能將模型的預測與真實的標籤進行比較。理想狀態下,矩陣將形成一條貫穿左上角至右下角的對角線(此時預測值和真實值完美匹配)。
混淆矩陣(綠色是高比例,藍色是低比例)
我們的分類器生成的漏報要比誤報多(按比例)。換句話說,我們模型最常見的錯誤是將災難事件錯誤地劃分到了不相關的分類。如果誤報會造成法律實施上的高昂成本,這對我們的分類器來說可能是個好事。
為了驗證我們的模型並解釋它的預測,就需要觀察它是用哪些詞來做決策的。如果我們的資料本身有偏差,分類器能基於樣例資料做出準確的預測,但是將模型應用在真實世界中的結果就不會很理想。我們繪製出了災難類和不相關類中最重要的一些詞。用詞袋模型和邏輯迴歸來繪製單詞重要性非常簡單,我們只需要將模型預測時使用的係數進行提取和排序。
詞袋模型:單詞重要性
我們的分類器正確地找出了一些特徵(hiroshima, massacre),但很顯然在一些無意義的詞上出現了過擬合(heyoo, x1392)。現在,我們的詞袋模型處理著大量的詞彙,且每個單詞都是被平等對待的。但是,有些詞出現的頻率非常高,卻只會對預測提供噪聲。接下來,我們會嘗試一種能解釋詞頻的方法來表達句子,來看是否能從資料中獲取更多資訊。
為了使我們的模型能更多地關注有意義的單詞,我們可以在詞袋模型上進行 TF-IDF(Term Frequency, Inverse Document Frequency)評分。TF-IDF 根據單詞在資料集中的稀有程度打分,會對一些出現太過頻繁且只會增加噪聲的詞進行削減。下圖是我們新嵌入的 PCA 投影圖:
TF-IDF 嵌入的視覺化
上圖中我們可以看到,兩種顏色有了更清晰的區分。這能使我們的分類器能更容易地區分兩個組。讓我們看看這樣是否會形成更好的結果。用我們新的嵌入訓練的另一個邏輯迴歸模型得到了 76.2% 的精確度。
這是一個非常微小的提升。我們的模型開始注意到更重要的單詞了嗎?如果我們在保證模型沒有“欺騙”行為的情況下得到了更好的結果,那麼可以認為這個模型有了提升。
TF-IDF: 單詞重要性
被選出的單詞看起來更相關了!雖然我們測試集的矩陣只有略微的增長,但是我們對模型選用的詞彙有了更多的信心,因此能更放心地將它部署到一些需要和客戶互動的系統中。
我們最新的模型設法注意到了高層的訊號詞。但是如果我們部署了這個模型,很有可能會遇到在訓練集中沒有出現過的單詞。那麼之前的模型可能就無法準確地為這些推文分類,即使在訓練時已經遇到過類似的詞語。
為了解決這個問題,我們需要獲取到詞語的語義,也就是說我們需要理解“good”和“positive”比“apricot”和“continent”更接近。我們會使用一個叫做 Word2Vec 的工具來幫助我們獲取含義。
Word2Vec 是一種用來為單詞尋找連續嵌入的技術。它通過讀取大量文字並記憶出現在相似上下文中的單詞來進行學習。在經過足夠的資料訓練後,它會為詞表中的每個單詞生成一個 300 維的向量,具有相似含義的單詞會靠的更近。
這篇文章的作者開源了一個在很大的語料庫上預先訓練過的模型,我們可以利用它來為我們的模型引入一些語義的知識。預先訓練的向量可以在這篇文章的資源庫中找到。
一種讓句子快速嵌入我們分類器的方法是對句子中所有單詞取 Word2Vec 分數的平均值。用的是和之前一樣的詞袋方法,但是這次我們在保留一些語義資訊的時候,僅丟失了句子的語法。
Word2Vec 句子嵌入
下面是使用之前所說的技術形成的新嵌入的視覺化:
Word2Vec 嵌入視覺化
兩組顏色區分的更明顯了,這次新的嵌入會幫助我們的分類器找到兩類之間的分隔。在對同一個模型訓練了三次之後(邏輯迴歸),我們得到了 77.7% 的準確率,這是至今最棒的結果了!是時候檢驗模型了。
鑑於在之前的模型中,我們的嵌入不是表達成每個單詞對應一個一維向量,這就更難判斷出哪些單詞和我們的分類是最相關的。但是我們仍然可以使用邏輯迴歸的係數,因為它和我們嵌入的 300 個維度相關而不和單詞的索引相關。
對於準確性上如此微弱的提升,丟失所有可解釋性似乎是一種很苛刻的權衡。但是在使用更復雜的模型時,我們可以利用 LIME這類黑盒直譯器 來檢視我們的分類器是怎麼工作的。
LIME 可以在 Github 的開源包裡獲取到。黑盒直譯器允許使用者利用一個典型的案例來解釋任何一個分類器的決定,可以通過擾動輸入(在我們的案例中,是從句子中移除單詞)來觀察預測的變化。
來看一下我們資料集中句子的一組解釋。
正確的災難詞彙被分類為“相關的”
這裡,單詞對分類的影響似乎不明顯
但我們沒有時間去探索資料集中成千上萬的案例。取而代之的是我們會用 LIME 跑在具有代表性的測試樣本上來看哪些單詞會一直有很強的貢獻。使用這種方法,我們就能像之前的模型一樣得到單詞重要性得分,並驗證模型的預測。
Word2Vec: 單詞重要性
似乎能找出高度相關詞語的模型就意味著能夠做出可理解的決策。這些應該是使用之前模型產出的最相關的單詞,因此我們能更安心地應用到生產中了。
之前文章的內容涵蓋了用於生成緊湊句子嵌入的快速有效的方法。但是,由於忽略了單詞的順序,我們失去了句子中所有語法資訊。如果這些方法無法提供足夠有效的結果,你可以用一些更復雜的模型,它們會把整句句子作為輸入,並在不需要構建中間表達的情況下預測標籤。通常的做法是用 Word2Vec 或是一些更新的方法,比如 GloVe 或 CoVe,把句子當做一系列獨立的單詞向量。我們下面便會這麼做。
一個高效的端到端架構(源)
用於句子分類的卷積神經網路(Convolutional Neural Networks,CNN)訓練起來非常快,是非常好用的入門級深度學習架構。CNN 廣為人知的是它在影象資料上的表現,但是它在處理文字相關的任務時也能提供極好的效果,而且通常會比大多數複雜的 NLP 演算法訓練的更快(例如 LSTMs 和 Encoder/Decoder 架構)。這個模型保留了單詞的順序,並且從我們可預測單詞順序的目標類中學習有價值的資訊。與之前的模型相反,他可以區分出“Alex eats plants”和“Plants eat Alex”。
訓練這個模型並不會比之前的方法花費更多功夫(更詳細的內容可以參考程式碼),但效果會比之前的都好,精確度能達到 79.5%!用著上述的模型,我們下一步的操作將是探索和解釋用我們描述的方法做出的預測,來證實這的確是能夠交付給使用者的最好的模型。現在,你可以放心地嘗試親自操作了。
讓我們把之前提到過的成功方法快速的過一下:
從一個快速簡單的模型開始
解釋它的預測
理解它產生的錯誤
用這些資訊來判斷你的下一步操作,是否對你的資料起作用,或是需要一個更復雜的模型
這些方法應用到了特殊的案例上,用的是理解和處理像推文一樣小段文字的模型,但是這種思考模式可以廣泛地應用到其他問題上。希望這篇文章可以對你有所幫助,也希望可以從你那裡聽到一些建議或是諮詢!請在下方盡情地留言,也可以在這裡或是 Twitter 上聯絡 EmmanuelAmeisen。
更多幹貨內容,可關注AI前線,ID:ai-front,後臺回覆「AI」、「TF」、「大資料」可獲得《AI前線》系列PDF迷你書和技能圖譜。