1. 程式人生 > >基於Text-CNN模型的中文文字分類實戰

基於Text-CNN模型的中文文字分類實戰

1 文字分類

文字分類是自然語言處理領域最活躍的研究方向之一,目前文字分類在工業界的應用場景非常普遍,從新聞的分類、商品評論資訊的情感分類到微博資訊打標籤輔助推薦系統,瞭解文字分類技術是NLP初學者比較好的切入點,較簡單且應用場景高頻。

  文字分類

2 資料準備

資料決定了模型最終的高度,不斷優化的模型只不過是為了不斷逼近這個高度而已。

文字分類作為一種有監督學習的任務,毫無疑問的需要一個可用於有監督學習的語料集(X,Y)。本文中使用以下標記,X為特徵,文字分類中即為文字序列,Y是標籤,即文字的分類名稱。

機器學習與傳統程式設計技術的明顯區別就是機器學習是以資料為驅動的,傳統的程式設計中,我們核心任務是人工設計分類規則(指令程式碼),然後實現輸入特徵X獲得分類標籤Y。而在機器學習的方式中,我們首要的是獲得一個高質量的、大資料量的有監督語料集(X,Y),然後機器學習的方式會自動的從已構建的資料集上歸納出(訓練出)一套分類規則(分類模型),最後我們利用獲得的分類規則來實現對未標記文字的分類。

  機器學習 VS 傳統程式設計

傳統的程式設計方式輸入的是指令程式碼,而機器學習輸入的是結構化資料

因此,在機器學習任務中,資料的質量與數量對最終模型的預測結果好壞具有決定性的作用。

在文字分類中,語料集(X,Y)的質量、數量決定了文字分類模型的分類效果。

語料集的質量:即資料集的特徵X對應的標籤Y是否標記的正確,一般在眾包平臺中會採用多人重複標記,然後基於投票的機制來控制語料集的標記質量。

語料集的數量:有監督語料集的標註複雜度,想要獲得海量的高質量語料集的成本是十分高昂的,這也限制的語料集的數量。

在實際的文字分類任務中,一般通過蒐集開源的資料集,或者利用爬蟲獲取結構化的網頁資訊來構建特定任務的語料集。不過,我還是更喜歡關注一些公開的競賽專案,能夠獲得企業準備的高質量、應對真實業務場景的資料集,例如:kaggle、知乎的看山杯、mrc2018-cipsc等,但大多數情況下企業只給脫敏之後的資料。

搜狗的新聞語料集:http://www.sogou.com/labs/resource/cs.php

3 文字的預處理

文字的預處理,主要針對剔除無意義的符號資訊,或其它的冗餘資訊。

例如,在使用爬蟲獲取的語料集上可能存在一些html標籤,這些符號對於文字分類任務來說應該是冗餘的無意義資訊,可以剔除掉。

針對中文、日語等無空格切分字詞的語言,還需要進行分詞處理,將一段文字序列劃分為合理的詞(字)序列。

英文中天生的就有空格把每個詞彙分割開來,所以不需要分詞操作,但由於英文存在時態、縮寫等問題,在預處理階段會有詞幹提取、詞性還原、大小寫轉換等。

去除停用詞

中文分詞的工具有非常多的方案,我一般習慣於使用Python版的JieBa分詞工具包來進行分詞的操作,使用非常的簡單,使用pip install jieba就可以很方便的安裝該工具包,jieba常用的API可以檢視GitHub主頁的例項。

分詞工具:

中科院計算所NLPIRhttp://ictclas.nlpir.org/nlpir/

ansj分詞器https://github.com/NLPchina/ansj_seg

哈工大的LTPhttps://github.com/HIT-SCIR/ltp

清華大學THULAChttps://github.com/thunlp/THULAC

斯坦福分詞器,Java實現的CRF演算法。https://nlp.stanford.edu/software/segmenter.shtml

Hanlp分詞器,求解的是最短路徑。https://github.com/hankcs/HanLP

結巴分詞,基於字首詞典,生成句子中所有可能成詞所構成的有向無環圖 (DAG),採用動態規劃查詢最大概率路徑, 找出基於詞頻的最大切分組合,對於未登入詞,採用了 HMM 模型,使用 Viterbi 演算法。https://github.com/yanyiwu/cppjieba

KCWS分詞器(字嵌入+Bi-LSTM+CRF),本質上是序列標註。https://github.com/koth/kcws

ZParhttps://github.com/frcchang/zpar/releases

IKAnalyzerhttps://github.com/wks/ik-analyzer

4 文字的數值化【詞向量技術】

文字的數值化,即使用數字代表特定的詞彙,因為計算機無法直接處理人類創造的詞彙。為了讓計算機能夠理解詞彙,我們需要將詞彙資訊對映到一個數值化的語義空間中,這個語義空間我們可以稱之為詞向量空間(詞向量模型)。

文字的數值化方式有很多種,例如:TF-IDF、BOW、One-Hot、分散式的表示方式(word2vec、Glove)等。

一般常用的就是最經典的word2vec工具,該工具在NLP領域具有非常重要的意義!

word2ve工具,它是一種無監督的學習模型,可以在一個語料集上(不需要標記,主要思想是“具有相似鄰近詞分佈的中心詞之之間具有一定的語義相似度”),實現詞彙資訊到語義空間的對映,最終獲得一個詞向量模型(每個詞彙對應一個指定維度的陣列)。

  兩種模型兩種優化方式

它的核心優勢就是實現了兩個詞彙資訊之間的語義相似度的可計算性,也可以理解為是一種遷移學習的思想,word2vec獲取的意義空間資訊作為後續文字分類模型的輸入。

python 中使用word2vec工具也是非常的便利,通過pip install gensim安裝gensim工具包,此包彙總包含了word2vec工具。

Gensim官網:https://radimrehurek.com/gensim/models/word2vec.html

深度學習中將單詞表示成向量是很普遍的情況,深度學習模型以詞向量序列的形式讀取序列化的單詞,而不是以文字的形式。

今天大多數用於自然語言處理的深度學習模型都依賴詞向量來代表單個單詞的含義。對於不太熟悉這領域的人而言,可以這樣簡單的理解:我們把每一種語言中的每一個單詞都與一串被叫做向量的數字聯絡起來了。

以上就是深度學習模型需要的資料格式的核心處理流程,在整個處理過程中樣本資料的處理流程如下圖所示:

  資料處理流程

5 文字分類模型

文字分類模型,可以大體上分為基於傳統機器學習的文字分類模型,基於深度學習的文字分類模型,目前基於深度學習模型的文字分類模型已經成為了主流,下面基於CNN的文字分類模型。

  深度學習的優劣

文字分類模型,從最經典的2013年Kim提出Text-CNN模型開始,深度學習模型在文字分類任務上具有廣泛的應用。2016年Kim跳槽FaceBook後提出了工業界的文字分類模型的“新寵”—FastText。

  文字分類模型

為了實現文字分類模型,需要藉助開源的深度學習框架,這樣在開發中就不需要自己從零實現整個深度學習模型的各個功能模組。如果你之前做過Java Web開發的話,肯定也使用過SSH或SSM等框架來簡化你的開發工作。

深度學習框架有很多優秀的框架,我一般使用比較流行的tensorflow計算框架,該框架的使用者比較多,可以查閱的學習資料非常多,Github上的開原始碼也比較多,非常有利於我們學習。

  tensorflow 框架   文字分類技術路線

目前深度學習在NLP的文字分類任務中已經具有比較廣泛的探究,其中經典的深度學習模型結構有以下三種:

  三種經典基於深度學習的文字分類模型

本文選擇使用2013年Kim提出的Text-CNN模型作為文字分類模型,通過驗證實驗以及業界的共識,在文字分類任務中,CNN模型已經能夠取到比較好的結果,雖然在某些資料集上效果可能會比RNN稍差一點,但是CNN模型訓練的效率更高。所以,一般認為CNN模型在文字分類任務中是兼具效率與質量的理想模型。

卷積神經網路(CNN)的特點:

CNN的三個優點:

sparse interaction(稀疏的互動)

parameter sharing(引數共享)

equivalent respresentation(等價表示)。

經典的簡化卷積公式表示如下:

  CNN中的卷積操作的計算公式

假設每個詞用三維向量表示,左邊是4個詞,右邊是卷積矩陣,那麼得到輸出為:

  卷積層的輸出

如果基於這個結果做1-MaxPool池化(最大值池化),那麼就取卷積層結果 o 中的最大值,即提取最顯著的特徵。

針對海量的文字多分類資料,也可以嘗試一下淺層的深度學習模型FastText模型,該模型的分類效率更高。

Kim提出的經典Text-CNN模型的整體網路架構如圖所示,如果你學習過CNN或者CNN在影象中的使用,應該很容易就理解,因為該模型就是一個最簡單、基礎的CNN網路結構。

整個模型由四部分構成:輸入層、卷積層、池化層、全連線層。

  Text-CNN

1.輸入層(詞嵌入層):

Text-CNN模型的輸入層需要輸入一個定長的文字序列,我們需要通過分析語料集樣本的長度指定一個輸入序列的長度L,比L短的樣本序列需要填充(自己定義填充符),比L長的序列需要擷取。最終輸入層輸入的是文字序列中各個詞彙對應的分散式表示,即詞向量。

對於輸入層輸入的詞向量的表達方式,Text-CNN模型的作者Kim在論文中也分析了幾個變種的方式:

1.static(靜態詞向量)

使用預訓練的詞向量,即利用word2vec、fastText或者Glove等詞向量工具,在開放領域資料上進行無監督的學習,獲得詞彙的具體詞向量表示方式,拿來直接作為輸入層的輸入,並且在TextCNN模型訓練過程中不再調整詞向量, 這屬於遷移學習在NLP領域的一種具體的應用。

2.non-static(非靜態詞向量)

預訓練的詞向量+ 動態調整 , 即拿word2vec訓練好的詞向量初始化, 訓練過程中再對詞向量進行微調。

3.multiple channel(多通道)

借鑑影象中的RGB三通道的思想, 這裡也可以用 static 與 non-static 兩種詞向量初始化方式來搭建兩個通道。

4.CNN-rand(隨機初始化)

指定詞向量的維度embedding_size後,文字分類模型對不同單詞的向量作隨機初始化, 後續有監督學習過程中,通過BP的方向更新輸入層的各個詞彙對應的詞向量。

2.卷積層:

在NLP領域一般卷積核只進行一維的滑動,即卷積核的寬度與詞向量的維度等寬,卷積核只進行一維的滑動。

在Text-CNN模型中一般使用多個不同尺寸的卷積核。卷積核的高度,即視窗值,可以理解為N-gram模型中的N,即利用的區域性詞序的長度,視窗值也是一個超引數,需要在任務中嘗試,一般選取2-8之間的值。

  卷積層

3.池化層:

在Text-CNN模型的池化層中使用了Max-pool(最大值池化),即減少模型的引數,又保證了在不定長的卷基層的輸出上獲得一個定長的全連線層的輸入

  池化層

池化層除了最大值池化之外,也有論文討論過 Top K最大值池化,即選取每一個卷積層輸出的Top k個最大值作為池化層的輸出。

卷積層與池化層在分類模型的核心作用就是提取特徵,從輸入的定長文字序列中,利用區域性詞序資訊,提取初級的特徵,並組合初級的特徵為高階特徵,通過卷積與池化操作,省去了傳統機器學習中的特徵工程的步驟。

但TextCNN的一個明顯缺點就是,卷積、池化操作丟失了文字序列中的詞彙的順序、位置資訊,比較難以捕獲文字序列中的否定、反義等語義資訊

4.全連線層:

全連線層的作用就是分類器,原始的Text-CNN模型使用了只有一層隱藏層的全連線網路,相當於把卷積與池化層提取的特徵輸入到一個LR分類器中進行分類。

至此,Text-CNN的模型結構就算大體瞭解了,有人把深度學習模型看作一個黑盒子,知道格式化的輸入,我們就可以利用別人搭建好的模型框架訓練在自己的資料集上實現一定的功能。但是在不同的資料集上,模型的最佳狀態也不唯一,這就需需要我們在新的資料集上需要進行調優(調參)。

6 模型的效果評估與調優

針對分類問題,一般可以使用準確率、召回率、F1值、混淆矩陣等指標,在文字多標籤分類中一般還會考慮標籤的位置加權等問題。

分類模型中的主要引數:詞向量的維度、卷積核的個數、卷積核的視窗值、L2的引數、DropOut的引數、學習率等。

這是在模型優化的過程中需要重點關注的引數。此外,一般資料集的類別不均衡問題對模型的影響也是比較顯著的,可以嘗試使用不同的方法,評估不同方案的模型效果。

7 文字分類中經常遇到的問題

1.資料集類別不均衡

即語料集中,各個類別下的樣本數量差異較大,會影響最終文字分類模型的效果。

主要存在兩類解決方案:

(1)調整資料:資料增強處理,NLP中一般隨分詞後的詞序列進行隨機的打亂順序丟棄某些詞彙然後分層的取樣的方式來構造新的樣本資料。

(2)使用代價敏感函式:例如影象識別中的Focal Loss等。

2.文字分類模型的泛化能力

首先,對於一個未知的樣本資料,分類模型只能給出分類標籤中的一個,無法解決不屬於分類標籤體系的樣本。

我們無法預知未來的資料會是什麼樣的,也不能保證未來的所有分類情況在訓練集中都已經出現過!

剩下影響分類模型泛化能力的就是模型過擬合的問題了。

如何防止過擬合?那就是老生常談的問題了:

(1)資料上:交叉驗證

(2)模型上:使用DropOut、BatchNorm、正則項、Early Stop。

3.關於模型的上線方案:

1、基於Java的:

請參考:https://www.ioiogoo.cn/2018/04/03/java%E8%B0%83%E7%94%A8keras%E3%80%81tensorflow%E6%A8%A1%E5%9E%8B/

2、基於Flask等python的web框架:

請參考:https://guillaumegenthial.github.io/serving.html

3、基於google官方的tensorflow Serving框架:

請參考:https://www.jianshu.com/p/c1cd2d127ae2

阿里的基於容器部署的方案:https://yq.aliyun.com/articles/60894?spm=a2c4e.11153959.blogcont60601.11.815eea72lw2ij

8 基於Text-CNN模型的中文文字分類Demo

我從搜狗的開源的的新聞資料集(small版)中,選擇了兩個類別的資料:計算機與交通兩個類別,構建了一箇中文文字二分類的資料集。

  搜狗資料集的語料

實現文字二分類的Demo程式碼以及指令碼執行的說明放在GitHub中:https://github.com/yongfengxuemei/NLP/tree/master/CNN_ChineseTextBinaryClassify

以上就是簡單的介紹了NLP中文字分類所涉及的主要流程,並給出了一箇中文文字二分類的Demo程式碼。下面推薦一些拓展的資料,感興趣的童鞋可以繼續深入研究。

補充資源:

各種文字分類模型的例項程式碼:https://github.com/brightmart/text_classification

中文文字分類對比:https://github.com/Edward1Chou/Textclassification

CNN-RNN中文文字分類,基於TensorFlow :https://github.com/gaussic/text-classification-cnn-rnn

9 Window上跑的效果

  訓練   訓練   測試   測試   prediction.csv

10 參考

中文分詞常用方法簡述:https://www.jianshu.com/p/6c085bf1086f

吾愛NLP(4)—基於Text-CNN模型的中文文字分類實戰:https://www.jianshu.com/p/f69e8a306862



作者:高永峰_GYF
連結:https://www.jianshu.com/p/e6d71a9b1554
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯絡作者獲得授權並註明出處。