天然語言處理(NLP,Natural Language Processing)是一個信息時代最重要的技術之一,簡單來說,就是讓計算機可以理解人類語言的一種技術。在其中,分詞技術是一種比較基礎的模塊。對於英文等拉丁語系的語言而言,因爲詞之間有空格做爲詞邊際表示,詞語通常狀況下都能簡單且準確地提取出來。而中文日文等文字,除了標點符號以外,字之間緊密相連,沒有明顯的詞邊界,所以很難將詞提取出來。分詞的意義很是大,在中文中,單字做爲最基本的語義單位,雖然也有本身的意義,但表意能力較差,意義較分散,而詞的表意能力更強,能更加準確地描述一個事物,所以在天然語言處理中,一般狀況下詞(包括單字成詞)是最基本的處理單位。html
在具體的應用上,好比在經常使用的搜索引擎中,term若是是詞粒度的話,不只可以減小每一個term的倒排列表長度,提高系統性能,而且召回的結果相關性高更準確。好比搜索query「的確」,若是是單字切分的話,則有可能召回「你講的確實在理」這樣的doc。分詞方法大體分爲兩種:基於詞典的機械切分,基於統計模型的序列標註切分兩種方式。node
基於詞典的方法本質上就是字符串匹配的方法,將一串文本中的文字片斷和已有的詞典進行匹配,若是匹配到,則此文字片斷就做爲一個分詞結果。可是基於詞典的機械切分會遇到多種問題,最爲常見的包括歧義切分問題和未登陸詞問題python
歧義切分指的是經過詞典匹配給出的切詞結果和原來語句所要表達的意思不相符或差異較大,在機械切分中比較常見,好比下面的例子:「結婚的和還沒有結婚的人」,經過機械切分的方式,會有兩種切分結果:1,「結婚/的/和/還沒有/結婚/的/人」;2,「結婚/的/和尚/未/結婚/的/人」。能夠明顯看出,第二種切分是有歧義的,單純的機械切分很難避免這樣的問題。算法
未登陸詞識別也稱做新詞發現,指的是詞沒有在詞典中出現,好比一些新的網絡詞彙,如「網紅」,「走你」;一些未登陸的人名,地名;一些外語音譯過來的詞等等。基於詞典的方式較難解決未登陸詞的問題,簡單的case能夠經過加詞典解決,可是隨着字典的增大,可能會引入新的bad case,而且系統的運算複雜度也會增長。編程
爲了解決歧義切分的問題,在中文分詞上有不少優化的方法,常見的包括正向最大匹配,逆向最大匹配,最少分詞結果,全切分後選擇路徑等多種算法。後端
正向最大匹配指的是從左到右對一個字符串進行匹配,所匹配的詞越長越好,好比「中國科學院計算研究所」,按照詞典中最長匹配原則的切分結果是:「中國科學院/計算研究所」,而不是「中國/科學院/計算/研究所」。可是正向最大匹配也會存在一些bad case,常見的例子如:「他從東通過我家」,使用正向最大匹配會獲得錯誤的結果:「他/從/東經/過/我/家」。 api
逆向最大匹配的順序是從右向左倒着匹配,若是能匹配到更長的詞,則優先選擇,上面的例子「他從東通過我家」逆向最大匹配可以獲得正確的結果「他/從/東/通過/我/家」。可是逆向最大匹配一樣存在bad case:「他們昨日本應該回來」,逆向匹配會獲得錯誤的結果「他們/昨/日本/應該/回來」。 微信
針對正向逆向匹配的問題,將雙向切分的結果進行比較,選擇切分詞語數量最少的結果。可是最少切分結果一樣有bad case,好比「他未來上海」,正確的切分結果是「他/將/來/上海」,有4個詞,而最少切分結果「他/未來/中國」只有3個詞。網絡
全切分方法就是將全部可能的切分組合所有列出來,並從中選擇最佳的一條切分路徑。關於路徑的選擇方式,通常有n最短路徑方法,基於詞的n元語法模型方法等。 架構
n最短路徑方法的基本思想就是將全部的切分結果組成有向無環圖,每一個切詞結果做爲一個節點,詞之間的邊賦予一個權重,最終找到權重和最小的一條路徑做爲分詞結果。
基於詞的n元語法模型能夠看做是n最短路徑方法的一種優化,不一樣的是,根據n元語法模型,路徑構成時會考慮詞的上下文關係,根據語料庫的統計結果,找出構成句子最大模型機率。通常狀況下,使用unigram和bigram的n元語法模型的狀況較多。
針對基於詞典的機械切分所面對的問題,尤爲是未登陸詞識別,使用基於統計模型的分詞方式可以取得更好的效果。基於統計模型的分詞方法,簡單來說就是一個序列標註問題。
在一段文字中,咱們能夠將每一個字按照他們在詞中的位置進行標註,經常使用的標記有如下四個label:B,Begin,表示這個字是一個詞的首字;M,Middle,表示這是一個詞中間的字;E,End,表示這是一個詞的尾字;S,Single,表示這是單字成詞。分詞的過程就是將一段字符輸入模型,而後獲得相應的標記序列,再根據標記序列進行分詞。舉例來講:「達觀數據是企業大數據服務商」,通過模型後獲得的理想標註序列是:「BMMESBEBMEBME」,最終還原的分詞結果是「達觀數據/是/企業/大數據/服務商」。
在NLP領域中,解決序列標註問題的常見模型主要有HMM和CRF。
HMM(Hidden Markov Model)隱馬爾科夫模型應用很是普遍,基本的思想就是根據觀測值序列找到真正的隱藏狀態值序列。在中文分詞中,一段文字的每一個字符能夠看做是一個觀測值,而這個字符的詞位置label(BEMS)能夠看做是隱藏的狀態。使用HMM的分詞,經過對切分語料庫進行統計,能夠獲得模型中5大要要素:起始機率矩陣,轉移機率矩陣,發射機率矩陣,觀察值集合,狀態值集合。在機率矩陣中,起始機率矩陣表示序列第一個狀態值的機率,在中文分詞中,理論上M和E的機率爲0。轉移機率表示狀態間的機率,好比B->M的機率,E->S的機率等。而發射機率是一個條件機率,表示當前這個狀態下,出現某個字的機率,好比p(人|B)表示在狀態爲B的狀況下人字的機率。
有了三個矩陣和兩個集合後,HMM問題最終轉化成求解隱藏狀態序列最大值的問題,求解這個問題最長使用的是Viterbi算法,這是一種動態規劃算法,具體的算法能夠參考維基百科詞條,在此不詳細展開。
圖1.1 HMM模型示意圖
CRF(Conditional random field,條件隨機場)是用來標註和劃分結構數據的機率化結構模型,一般使用在模式識別和機器學習中,在天然語言處理和圖像處理等領域中獲得普遍應用。和HMM相似,當對於給定的輸入觀測序列X和輸出序列Y,CRF經過定義條件機率P(Y|X),而不是聯合機率分佈P(X,Y)來描述模型。CRF算法的具體算法能夠參考維基百科詞條。
圖1.2 不一樣機率模型之間的關係及演化圖
在實際應用中有不少工具包可使用,好比CRF++,CRFsuite,SGD,Wapiti 等,其中CRF++的準確度較高。在分詞中使用CRF++時,主要的工做是特徵模板的配置。CRF++支持unigram,bigram兩種特徵,分別以U和B開頭。舉例來說U00:%x[-2,0] 表示第一個特徵,特徵取值是當前字的前方第二個字,U01:%x[-1,0] 表示第二個特徵,特徵取值當前字前一個字,U02:%x[0,0] 表示第三個特徵,取當前字,以此類推。特徵模板能夠支持多種特徵,CRF++會根據特徵模板提取特徵函數,用於模型的創建和使用。特徵模板的設計對分詞效果及訓練時間影響較大,須要分析嘗試找到適用的特徵模板。
隨着AlphaGo的大顯神威,Deep Learning(深度學習)的熱度進一步提升。深度學習來源於傳統的神經網絡模型。傳統的神經網絡通常由輸入層,隱藏層,輸出層組成,其中隱藏層的數目按需肯定。深度學習能夠簡單的理解爲多層神經網絡,可是深度學習的卻不只僅是神經網絡。深度模型將每一層的輸出做爲下一層的輸入特徵,經過將底層的簡單特徵組合成爲高層的更抽象的特徵來進行學習。在訓練過程當中,一般採用貪婪算法,一層一層地訓練,好比在訓練第k層時,固定訓練好的前k-1層的參數進行訓練,訓練好第k層以後的以此類推動行一層層訓練。
圖2.1 AlphaGo的神經網絡模型的訓練過程及架構
圖2.2 Google Tensorflow官網的神經網絡演示示意圖
深度學習在不少領域都有所應用,在圖像和語音識別領域中已經取得巨大的成功。從2012年開始,LSVRC(Large Scale Visual Recognition Challenge)比賽中,基於Deep Learningd 計算框架一直處於領先。2015年LSVRC(http://www.image-net.org/challenges/LSVRC/2015/results)的比賽中,微軟亞洲研究院(MSRA)在圖像檢測(Object detection),圖像分類定位(Object Classification+localization)上奪冠,他們使用的神經網絡深達152層。
在天然語言處理上,深度學習在機器翻譯、自動問答、文本分類、情感分析、信息抽取、序列標註、語法解析等領域都有普遍的應用。2013年底google發佈的word2vec工具,能夠看作是深度學習在NLP領域的一個重要應用,雖然word2vec只有三層神經網絡,可是已經取得很是好的效果。經過word2vec,能夠將一個詞表示爲詞向量,將文字數字化,更好的讓計算機理解。使word2vec模型,咱們能夠方便地找到同義詞或聯繫緊密的詞,或者意義相反的詞等。
圖2.3 基於微信數據製做的word2vec模型測試:編程
圖2.4 基於微信數據製做的word2vec模型測試:韋德
詞向量的意思就是經過一個數字組成的向量來表示一個詞,這個向量的構成能夠有不少種。最簡單的方式就是所謂的one-hot向量。假設在一個語料集合中,一共有n個不一樣的詞,則可使用一個長度爲n的向量,對於第i個詞(i=0…n-1),向量index=i處值爲1外,向量其餘位置的值都爲0,這樣就能夠惟一的經過一個[0,0,1,…,0,0]形式的向量表示一個詞。one-hot向量比較簡單也容易理解,可是有不少問題,好比當加入新詞時,整個向量的長度會改變,而且存在維數太高難以計算的問題,以及向量的表示方法很難體現兩個詞之間的關係,所以通常狀況下one-hot向量較少的使用。
若是考慮到詞和詞之間的聯繫,就要考慮詞的共現問題。最簡單的是使用基於文檔的向量表示方法來給出詞向量。基本思想也很簡單,假設有n篇文檔,若是某些詞常常成對出如今多篇相同的文檔中,咱們則認爲這兩個詞聯繫很是緊密。對於文檔集合,能夠將文檔按順編號(i=0…n-1),將文檔編導做爲向量索引,這樣就有一個n維的向量。當一個詞出如今某個文檔i中時,向量i處值爲1,這樣就能夠經過一個相似[0,1,0,…,1,0]形式的向量表示一個詞。基於文檔的詞向量可以很好地表示詞之間的關係,可是向量的長度和語料庫的大小相關,一樣會存在維度變化問題。
考慮用一個固定窗口大小的文本片斷來解決維度變化問題,若是在這樣的片斷中,兩個詞出現了,就認爲這兩個詞有關。舉例來說,有如下三句話: 「我\喜歡\你」,「我\愛\運動」,「我\愛\攝影」,若是考慮窗口的大小爲1,也就是認爲一個詞只和它前面和後面的詞有關,經過統計共現次數,咱們可以獲得下面的矩陣。
能夠看到這是一個n*n的對稱矩陣X,這個矩陣的維數會隨着詞典數量的增長而增大,經過SVD(Singular Value Decomposition,奇異值分解),咱們能夠將矩陣維度下降,但仍存在一些問題: 矩陣X維度常常改變,而且因爲大部分詞並非共現而致使的稀疏性,矩陣維度太高計算複雜度高等問題。
Word2vec是一個多層的神經網絡,一樣能夠將詞向量化。在Word2vec中最重要的兩個模型是CBOW(Continuous Bag-of-Word)模型和Skip-gram(Continuous Skip-gram)模型,兩個模型都包含三層: 輸入層,投影層,輸出層。CBOW模型的做用是已知當前詞Wt的上下文環境(Wt-2,Wt-1,Wt+1,Wt+2)來預測當前詞,Skip-gram模型的做用是根據當前詞Wt來預測上下文(Wt-2,Wt-1,Wt+1,Wt+2)。在模型求解中,和通常的機器學習方法相似,也是定義不一樣的損失函數,使用梯度降低法尋找最優值。Word2vec模型求解中,使用了Hierarchical Softmax方法和Negative Sampling兩種方法。經過使用Word2vec,咱們能夠方便的將詞轉化成向量表示,讓計算機和理解圖像中的每一個點同樣,數字化詞的表現。
深度學習有不少種不一樣類型的網絡,在圖像識別領域,CNN(Convolutional Neural Network,卷積神經網絡)使用的較多,而在NLP領域,考慮到上下文的RNN(Recurrent Neural Networks,循環神經網絡)取得了巨大的成功。在傳統的神經網絡中,從輸入層到隱藏層到輸出層,層之間是全鏈接的,可是每層內部的節點之間是無鏈接的。由於這樣的緣由,傳統的神經網絡不能利用上下文關係, 而在天然語言處理中,上下文關係很是重要,一個句子中先後詞並不獨立,不一樣的組合會有不一樣的意義,好比」優秀」這個詞,若是前面是」不」字,則意義徹底相反。RNN則考慮到網絡前一時刻的輸出對當前輸出的影響,將隱藏層內部的節點也鏈接起來,即當前時刻一個節點的輸入除了上一層的輸出外,還包括上一時刻隱藏層的輸出。RNN在理論上能夠儲存任意長度的轉態序列,可是在不一樣的場景中這個長度可能不一樣。好比在詞的預測例子中: 1,「他是億萬富翁,他很?」; 2,「他的房子每平米物業費40元,而且像這樣的房子他有十幾套,他很?」。從這兩個句子中咱們已經能猜到?表明「有錢」或其餘相似的詞彙,可是明顯,第一句話預測最後一個詞時的上線文序列很短,而第二段話較長。若是預測一個詞彙須要較長的上下文,隨着這個距離的增加,RNN將很難學到這些長距離的信息依賴,雖然這對咱們人類相對容易。在實踐中,已被證實使用最普遍的模型是LSTM(Long Short-Term Memory,長短時記憶)很好的解決了這個問題。
LSTM最先由Hochreiter 及 Schmidhuber在1997年的論文中提出。首先LSTM也是一種RNN,不一樣的是LSTM可以學會遠距離的上下文依賴,可以存儲較遠距離上下文對當前時間節點的影響。
全部的RNN都有一串重複的神經網絡模塊。對於標準的RNN,這個模塊都比較簡單,好比使用單獨的tanh層。LSTM擁有相似的結構,可是不一樣的是,LSTM的每一個模塊擁有更復雜的神經網絡結構: 4層相互影響的神經網絡。在LSTM每一個單元中,由於門結構的存在,對於每一個單元的轉態,使得LSTM擁有增長或減小信息的能力。
圖2.6 標準RNN模型中的重複模塊包括1層結構
圖2.7 LSTM模型中的重複模塊包括4層結構
Keras(http://keras.io)是一個很是易用的深度學習框架,使用python語言編寫,是一個高度模塊化的神經網絡庫,後端同時支持Theano和TensorFlow,而Theano和TensorFlow支持GPU,所以使用keras可使用GPU加速模型訓練。Keras中包括了構建模型經常使用的模塊,如Optimizers優化方法模塊,Activations激活函數模塊,Initializations初始化模塊,Layers多種網絡層模塊等,能夠很是方便快速的搭建一個網絡模型,使得開發人員能夠快速上手,並將精力放在模型設計而不是具體實現上。常見的神經網絡模型如CNN,RNN等,使用keras均可以很快搭建出來,開發人員只須要將數據準備成keras須要的格式丟進網絡訓練便可。若是對keras中自帶的layer有更多的需求,keras還能夠本身定製所需的layer。
Keras項目中的example自帶了多個示例,包括經典的mnist手寫識別測試等,其中和NLP相關的示例有不少,好比基於imdb數據的情感分析、文本分類、序列標註等。其中lstm_text_generation.py示例能夠用來參考設計序列標註問題,這個示例試圖經過LSTM學習尼采的做品,經過序列標註的思想來訓練一個文本生成器模型。下面着重看一下兩個關鍵點:模型數據格式及模型設計。
這段代碼是數據準備的狀況。將尼采全文進行數據切割,每40個字符爲一個片斷,將緊接這個片斷的字符做爲預測值,來進行訓練。字符片斷的間隔爲3。
在模型設計上,主要是使用了兩層LSTM,每層的輸出維度爲512,並在每層LSTM後面加入了Dropout層,來防止過擬合。整個模型的輸入維度是字符類別的個數,輸入字符串長度是40,模型的輸出維度也是字符類別長度。整個模型表達的意思是每輸入40個字符,就會從模型中輸出一個預測的字符。由於LSTM的對長依賴term的記憶性,所以在上下文很長(40個字符)的狀況下也能夠表現的很好。
基於上面的知識,能夠考慮使用深度學習的方法進行中文分詞。分詞的基礎思想仍是使用序列標註問題,將一個句子中的每一個字標記成BEMS四種label。模型整的輸入是字符序列,輸出是一個標註序列,所以這是一個標準的sequence to sequence問題。由於一個句子中每一個字的上下文對這個字的label類型影響很大,所以考慮使用RNN模型來解決。
測試硬件是Macbook Pro 2014 Mid高配版,帶Nvidia GT 750M GPU,雖然GPU性能有限,但經過測試性能仍是強過mac自帶的i7 CPU。使用GPU進行模型運算,須要安裝Nvidia的cuda相關程序及cuDNN庫,會有較大的性能提高。軟件方面使用python2.7,安裝好了keras,theano及相關庫。關於keras使用GPU訓練的環境搭建問題,能夠參考這篇文章(Run Keras on Mac OS with GPU,http://blog.wenhaolee.com/run-keras-on-mac-os-with-gpu/)。
模型訓練使用的是經典的bakeoff2005中的微軟研究院的切分語料,將其中的train部分拿過來作訓練,將test做爲最終的測試。
首先,將訓練樣本中出現的全部字符所有映射成對應的數字,將文本數字化,造成一個字符到數據的映射。在分詞中,一個詞的label受上下文影響很大,所以參考以前提到的lstm_text_generation.py示例,咱們將一個長度爲n個字符的輸入文本處理成n個長度爲k的向量,k爲奇數。舉例來講,當k=7時,表示考慮了一個字前3個字和後三個字的上下文,將這個七個字做爲一個輸入,輸出就是這個字的label類型(BEMS)。
參考lstm_text_generation.py 中的模型搭建方式,咱們採用一層的LSTM構建網絡,代碼以下:
其中,輸入的維度input_dim 是字符類別總數,hidden_node 是隱藏層的結點個數。在上面的模型中,第一層輸入層Embedding的做用是將輸入的整數向量化。在如今這個模型中,輸入是一個一維向量,裏面每一個值是字符對應的整數,Embedding層就能夠將這些整數向量化,簡單來說就是生成了每一個字的字向量。接下來緊跟着一層是LSTM,它輸出維度也是隱藏層的結點個數。Dropout層的做用是讓一些神經節點隨機不工做,來防止過擬合現象。Dense層是最後的輸出,這裏nb_classes的數目是4,表明一個字符的label。模型創建好後開始訓練,重複20次,訓練的結果以下:
圖4.1 基礎模型(1層LSTM優化器RMSprop)訓練20次
訓練好後,咱們使用msr_test的測試數據進行分詞,並將最終的分詞結果使用icwb2自帶的腳本進行測試,結果以下:
圖4.2 基礎模型F Score: 0.845
能夠看到基礎模型的F值通常,比傳統的CRF效果差的較多,所以考慮優化模型。
1) 模型參數調整
首先想到的是模型參數的調整。Keras官方文檔中提到,RMSprop優化方法在RNN網絡中一般是一個好的選擇,可是在嘗試了其餘的優化器後,好比Adam,發現能夠取得更好的效果。
圖4.3 1層LSTM優化器Adam訓練20次
能夠看到,Adam在訓練過程當中的精度就已經高於RMSprop,使用icwb2的測試結果爲:
圖4.4 修改優化器Adam後的模型F Score:0.889
2) 模型結構改變
如今網絡結構較簡單,只有一層LSTM,參考文檔示例中的模型設計,考慮使用兩層的LSTM來進行測試,修改後的代碼以下:
注意,第一層LSTM有個return_sequences =True能夠將最後一個結果出入到輸出序列,保證輸出的tensor是3D的,由於LSTM的輸入要求是3D的tensor。
兩層LSTM模型訓練過程以下:
圖4.5 2層LSTM優化器Adam訓練20次的模型
能夠看到,兩層LSTM使得模型更加複雜,訓練時常也增長很多。模型訓練後,使用icwb2的測試結果爲:
圖4.6 兩層LSTM的模型F Score:0.889
能夠看到,隨着模型的複雜,雖然F Score無提高,可是其餘的指標有必定的提高。通常來講,神經網絡在大量訓練數據下也會有更好的效果,後續會繼續嘗試更大數據集更復雜模型的效果。
深度學習技術給NLP技術中的中文分詞技術帶來了新鮮血液,改變了傳統的思路。深度神經網絡的優勢是能夠自動發現特徵,大大減小了特徵工程的工做量。隨着技術的進一步發展,深度學習在NLP領域將會發揮更大的做用。達觀數據將在已有成熟的NLP算法及模型基礎上,逐漸融合基於深度神經網絡的NLP模型,在文本分類、序列標註、情感分析、語義分析等功能上進一步優化提高效果,來更好爲客戶服務。