1. 程式人生 > >NLP+詞法系列(二)︱中文分詞技術簡述、深度學習分詞實踐(CIPS2016、超多案例)

NLP+詞法系列(二)︱中文分詞技術簡述、深度學習分詞實踐(CIPS2016、超多案例)

這裡寫圖片描述

這裡寫圖片描述

詞法分析是將輸入句子從字序列轉化為詞和詞性序列, 句法分析將輸入句子從詞序列形式轉化為樹狀結構,從而刻畫句子的詞法和句法結構。

一、詞法分析的難題

1、詞的定義和生詞問題、未登入詞(新詞)

特別是在網際網路時代,外來語、新詞、熱詞不斷出現,事實上,也不存在一個絕對統一的構詞標準和分詞規範。
未登入詞(新詞)識別錯誤對分詞效果有著很大的影響。一般的專有名詞還有一定的構詞規律,如字首字尾有跡可循。而新詞則五花八門,如新術語、新縮略語、新商品名、綽號、筆名等。
尤其是在領域移植的情境下,當測試文字與訓練資料的領域存在較大差異的時候,未登入詞的數量增多,導致分詞效果變差。
解決辦法:

互動建模:如上所述,未登入詞識別,尤其是新詞識別,對分詞效果的影響很大。如果一個句子中出現了一個新詞時,人在理解句子時會嘗試多種分詞結果,甚至會綜合句法結構、語義結構是否合理,從而判斷出這個新詞是否應該是一個詞

2、錯別字、諧音字規範化、非規範詞

不規範文字(如網路文字和語音轉錄文字) 時,輸入的句子中不可避免會存在一些錯別字或者刻意的諧音詞(如“香菇” ->“想哭”;“藍瘦” ->“難受”;“藍菇” ->“難過”等等)。這些錯別字或諧音字對於分詞系統造成了很大的困擾。
當不規範文字時,分析準確率急劇下降。

3、分詞歧義消解

4、詞性定義和詞性兼類問題

詞性類別遠比詞的個數要小,但詞性的定義也不完全存在一個統一的資訊處理用的國內和國際標準。詞性兼類問題是詞性標註面臨的主要問題,需要更高層次的上下文資訊來解決。

5、分詞粒度問題

受到個人的知識結構和所處環境的很大影響(黃昌寧、趙海, 2007)。這樣就導致多人標註的語料存在大量不一致現象,即表達相同意思的同一字串,在語料中存在不同的切分方式,如“我”和“我/國”。

  • 細粒度

可以緩解資料稀疏問題,解決粗粒度詞語在訓練資料中沒有出現的問題。存在兩個問題:

1、標註人員對於分詞規範的理解存在差異,因此會影響人工標註資料的質量
2、不同的上層應用對於分詞粒度的需求不同,有些應用甚至需要不同粒度的分詞結果

  • 多粒度

資料標註時,便可以弱化分詞規範,可以讓標註者根據自己對詞語定義的理解進行標註,模稜兩可的地方允許提供多個標註結果。多粒度分詞規範下,如何進行詞性標註、句法分析,也是一個很有意思的問題
.
.

二、分詞實踐

1、基於詞典的特徵

分詞過程中,可以把“當前字開始的三個字構成的字串是否在詞典中出現”這樣的資訊作為特徵,加入到統計模型中,這種資訊稱為基於詞典的特徵。

2、基於無標註資料的半指導特徵

很多有效的基於無標註資料的半指導特徵,如兩個字串之間的互資訊( mutual information),一個字串左右鄰接字的多樣性( accessor variety) ,一個字串左右鄰接標點符號的頻率,字串在篇章中出現頻率,漢字的左右邊界熵,兩個漢字的卡方統計量等 (Weiwei Sun and Jia Xu, 2011; 韓東煦、常寶寶, 2015)。
研究表明,這些半指導特徵可以顯著提高分詞準確率,尤其在領域移植的場景中處理有別於訓練資料的文字時。
相關詞-詞之間的距離標註可見:
NLP︱句子級、詞語級以及句子-詞語之間相似性(相關名稱:文件特徵、詞特徵、詞權重)

3、基於自然標註資料的學習方法

網頁源文字中包含了大量的 html 標記,指定了文字在網頁中的角色、超連結、顯示位置或顯示格式,而這些標記無形中也隱含了分詞邊界資訊。研究者們將這種隱含的分詞邊界資訊稱為自然標註,將包含自然標註資訊的文字轉化為區域性標註資料,加入到模型訓練資料中,顯著提高了分詞效果 (Wenbin Jiang et al., 2013;Yijia Liu et al., 2014)

4、基於深度學習的分詞方法

近幾年,深度學習方法為分詞技術帶來了新的思路,直接以最基本的向量化原子特徵作為輸入,經過多層非線性變換,輸出層就可以很好的預測當前字的標記或下一個動作。在深度學習的框架下,仍然可以採用基於子序列標註的方式,或基於轉移的方式,以及半馬爾科夫條件隨機場。深度學習主要有兩點優勢:
1) 深度學習可以通過優化最終目標,有效學習原子特徵和上下文的表示;
2)基於深層網路如 CNN、 NN、 LSTM等,深度學習可以更有效的刻畫長距離句子資訊。

5、詞法句法一體化建模

隨著計算資源的飛速發展和對機器學習模型的理解更加深入,研究者們提出了很有效的統計模型,直接從字開始對句子進行分析,輸出分詞、詞性、句法的結果。
多年前也有研究者提出詞法句法一體化分析,如最有代表性的 NLPWin**,但是均採用基於規則的方法。**基於統計模型的一體化建模可以讓詞法句法分析互相影響,互相提高,顯著提高了詞法和句法的分析效果。尤其值得提出的是,研究者們提出進一步分析詞語內部結構,有效緩解了資料稀疏問題。

6、分詞開源軟體開放

影響較大、使用人數較多的幾個分詞系統包括中科院計算所的 ICTLAS 分詞系統、哈工大語言技術平臺 LTP、清華大學自然語言處理工具包、海量雲分詞等。
常用的中文分詞工具包括jieba分詞、哈工大分詞、Stanford分詞等。
關於中文分詞的測評,可見上一篇部落格:NLP+詞法系列(一)︱中文分詞技術小結、幾大分詞引擎的介紹與比較

.
.

三、詞性標註

給定一個切好詞的句子,詞性標註的目的是為每一個詞賦予一個類別,這個類別稱為詞性標記( part-of-speech tag),比如,名詞(> noun)、動詞( verb)、形容詞( adjective)等。

這裡寫圖片描述

詞性標註人工標註資料目前也存在一些問題,可能會影響面向不規範文字的詞性標註研究:

  • 資料中往往會包含存在一些標註不一致。現象,如 CTB 中“新華社”被大量標為兩種詞性“ NR”(專有名詞)和“ NN”(普通
    名詞)

  • 詞性標註標籤集合如何設計?這個問題取決於詞性標註服務於什麼任務。

  • 網際網路文字分析和領域自適應問題:句法分析面臨的一個重要問題是面對和訓練資料很接近的新聞領域規範文字時效能較好,但用於其它領域或型別的文字(比如口語化文字)時,準確率則急劇下降。

1、異構資料融合

漢語資料目前存在多個人工標註資料,然而不同資料遵守不同的標註規範,因此稱為多源異構資料。近年來,學者們就如何利用多源異構資料提高模型準確率,提出了很多有效的方法,如基於指導特徵的方法、基於雙序列標註的方法、以及基於神經網路
共享表示的方法。

2、基於深度學習的方法

轉化為字標註的方式,進行分析。傳統詞性標註方法的特徵抽取過程主要是將固定上下文視窗的詞進行人工組合,而深度學習方法能夠自動利用非線性啟用函式完成這一目標。進一步,如果結合迴圈神經網路如雙向 LSTM,則抽取到的資訊不再受到固定視窗的約束,而是考慮整個句子。除此之外,深度學習的另一個優勢是初始詞向量輸入本身已經刻畫了詞語之間的相似度資訊,這對詞性標註非常重要。

.
.

公眾號“素質雲筆記”定期更新部落格內容:

這裡寫圖片描述

四、深度學習分詞實踐案例

1、動態規劃的方法——轉移概率

本文來源於蘇劍林,泰迪大資料探勘,原創作品名稱《【OCR技術淺探】6. 語言模型》

轉移概率:從概率的角度來看,就是對於第一個字的區域的識別結果s1,我們前面的卷積神經網路給出了“電”、“宙”兩個候選字(僅僅選了前兩個,後面的概率太小),每個候選字的概率W(s1)分別為0.99996、0.00004;第二個字的區域的識別結果s2,我們前面的卷積神經網路給出了“柳”、“視”、“規”(僅僅選了前三個,後面的概率太小),每個候選字的概率W(s2)分別為0.87838、0.12148、0.00012,因此,它們事實上有六種組合:“電柳”、“電視”、“電規”、“宙柳”、“宙視”、“宙規”。
下面考慮它們的遷移概率。所謂遷移概率,其實就是條件概率P(s1|s2),即當s1出現時後面接s2的概率。通過10萬微信文字,我們統計出,“電”字出現的次數為145001,而“電柳”、“電視“、”電規“出現的次數為0、12426、7;“宙”字出現的次數為1980次,而“宙柳”、“宙視”、“宙規”出現的次數為0、0、18,因此,可以算出
這裡寫圖片描述
結果如下圖:
這裡寫圖片描述
從統計的角度來看,最優的s1,s2組合,應該使得式(14)取最大值:
這裡寫圖片描述
因此,可以算得s1,s2的最佳組合應該是“電視”而不是“電柳”。這時我們成功地通過統計的方法得到了正確結果,從而提高了正確率。

對於第一個問題,只需要從大的語料庫中統計si的出現次數#si,以及si,si+1相接地出現的次數#(si,si+1),然後認為
這裡寫圖片描述
即可,本質上沒有什麼困難。本文的識別物件有3062個,理論上來說,應該生成一個3062×3062的矩陣,這是非常龐大的。當然,這個矩陣是非常稀疏的,我們可以只儲存那些有價值的元素。

現在要著重考慮當#(si,si+1)=0的情況。在前一節我們就直接當P(si|si+1)=0,但事實上是不合理的。沒有出現不能說明不會出現,只能說明概率很小,因此,即便是對於#(si,si+1)=0,也應該賦予一個小概率而不是0。這在統計上稱為資料的平滑問題。

一個簡單的平滑方法是在所有項的頻數(包括頻數為0的項)後面都加上一個正的小常數α(比如1),然後重新統計總數並計算頻率,這樣每個專案都得到了一個正的概率。這種思路有可能降低高頻數的項的概率,但由於這裡的概率只具有相對意義,因此這個影響是不明顯的(一個更合理的思路是當頻數小於某個閾值T時才加上常數,其他不加。)。按照這種思路,從數十萬微信文章中,我們計算得到了160萬的鄰接漢字的轉移概率矩陣。
.

2、動態規劃的方法——Viterbi演算法

本文來源於泰迪大資料探勘,原創作品名稱《【OCR技術淺探】6. 語言模型》

求解最優組合是屬於動態規劃中求最優路徑的問題,其中最有效的方法是Viterbi演算法。

Viterbi演算法是一個簡單高效的演算法,用Python實現也就十來行的程式碼。它的核心思想是:如果最終的最優路徑經過某個si−1,那麼從初始節點到si−1點的路徑必然也是一個最優路徑——因為每一個節點si只會影響前後兩個P(si−1|si)和P(si|si+1)。

根據這個思想,可以通過遞推的方法,在考慮每個si時只需要求出所有經過各si−1的候選點的最優路徑,然後再與當前的si結合比較。這樣每步只需要算不超過 次,就可以逐步找出最優路徑。Viterbi演算法的效率是θ,l 是候選數目最多的節點si的候選數目,它正比於n,這是非常高效率的。
由於Viterbi演算法的簡單高效,這是一個性價比很高的步驟。

3、無監督分詞——基於切分的新詞發現

我們說片段的凝固度大於一定程度時,片段可能成詞(接下來要去考慮它的邊界熵)。那這不就是說,如果片段的凝固度低於一定程度時,這個片段就不可能成詞了嗎?那麼我們就可以在原來的語料中把它斷開了。

我們可以做適當的簡化,如果a,ba,b是語料中相鄰兩字,那麼可以統計(a,b)(a,b)成對出現的次數#(a,b)#(a,b),繼而估計它的頻率P(a,b)P(a,b),然後我們分別統計a,ba,b出現的次數#a,#b#a,#b,然後估計它們的頻率P(a),P(b)P(a),P(b),如果

P(a,b) / P(a)P(b) < α(α是給定的大於1的閾值)

那麼就應該在原來的語料中把這兩個字斷開。這個操作本質上就是——我們根據這個指標,對原始語料進行初步的分詞!在完成初步分詞後,我們就可以統計詞頻了,然後根據詞頻來篩選。

我們現在只用了兩個指標:頻數和凝固度,去掉了計算量最大的邊界熵,而且,在計算凝固度時,我們只需要計算二字片段的凝固度,省掉了更多字片段的凝固度計算,但是,由於我們是基於切分的方式做的,因此我們少了很多計算量,但理論上卻能夠得任意長度的詞語!
下面給出實現程式碼,很短,純Python,並且不用第三方庫的支援,而且記憶體非常友好,這裡的texts可以是一個列表,也可以是一個迭代器(每次返回一篇文章),配合tqdm庫,可以方便地顯示進度。最後,在統計時,用到了加γ平滑法,以緩解出現不合理的詞。以前做這些統計計算的時候,不用想就用Pandas了,最近嘗試了一下Python原生的一些庫,發現也相當好用呢~

from collections import defaultdict
from itertools import tee
import re

def count_words(texts, min_count=10, min_proba=1, gamma=0.5):
    segments = [defaultdict(int), defaultdict(int)]
    for text in texts:
        for i in range(2):
            for j in range(len(text)-i):
                segments[i][text[j: j+i+1]] += 1
    segments[0] = {i:j+gamma for i,j in segments[0].iteritems()}
    segments[1] = {i:j+gamma for i,j in segments[1].iteritems()}
    nb_words = sum(segments[0].values())**2/sum(segments[1].values())
    strong_segments = {i: nb_words*j/(segments[0][i[0]]*segments[0][i[1]]) for i,j in segments[1].iteritems() if j >= min_count}
    strong_segments = {i:j for i,j in strong_segments.iteritems() if j >= min_proba}
    return strong_segments

def filter_words(texts):
    for text in texts:
        for t in re.split(u'[^\u4e00-\u9fa50-9a-zA-Z]+', text):
            yield t

def find_words(texts, min_count=10, min_proba=1):
    texts_for_count, texts_for_cut = tee(filter_words(texts))
    strong_segments = count_words(texts_for_count, min_count, min_proba)
    words = defaultdict(int)
    for text in texts_for_cut:
        if text:
            s = text[0]
            for i in range(len(text)-1):
                if text[i:i+2] in strong_segments:
                    s += text[i+1]
                else:
                    words[s] += 1
                    s = text[i+1]
    return {i:j for i,j in words.iteritems() if j >= min_count}

一般情況下,為了得到更細粒度的詞語(避免分出太多無效的長詞),我們可以選擇較大的α,比如α=10,但是這帶來一個問題:一個詞語中相鄰兩個字的凝固度不一定很大。

一個典型的例子是“共和國”,“和”跟“國”都是很頻繁的字,“和國”兩個字的凝固度並不高(在微信文字中大概為3左右),如果α太大就會導致切錯了這個詞語(事實上,是“共和”跟“國”的凝固度高),這些例子還有很多,比如“林心如”的“心如”凝固度就不大(當然,如果語料來源於娛樂圈,那又另當別論)。而如果設定α=1,則需要更大的語料庫才能使得詞庫完備起來。這是在使用本演算法時需要仔細考慮的。

4、基於HMM的字標註

通過字標註法來進行分詞的模型有隱馬爾科夫模型(HMM)、最大熵模型(ME)、條件隨機場模型(CRF),它們在精度上都是遞增的,據說目前公開評測中分詞效果最好的是4標註的CRF。然而,在本文中,我們要講解的是最不精確的HMM。因為在筆者看來,它並非一個特定的模型,而是解決一大類問題的通用思想,一種簡化問題的學問。
HMM模型一般都是用來解決“在查詞典方法的過程中不能解決的部分”(就好比結巴分詞所做的)。當然,你可以把馬爾可夫假設加強——比如假設每個狀態跟前面兩個狀態有關,那樣肯定會得到更精確的模型,但是模型的引數就更難估計了。
文中也有的python實現
.

5、★無監督分詞典範——基於凝聚度和自由度的非監督詞庫生成

本節來自於張巨集倫工作室,同時開源了程式碼在自己網站上,可以計算頻率、凝聚度、自由度的corpus.py

主流的分詞模型比較固定,而好的語料詞庫往往很難獲得,並且大多需要人工標註。這裡介紹一種基於詞頻、凝聚度和自由度的非監督詞庫生成方法

  • 第一步:獲取所有的備選詞語
    例如《西遊記》的全文,使用的是utf-8版本,我關注的最大詞語長度為5,因此可以使用正則匹配出全部的單個漢字、雙漢字、三漢字、四漢字、五漢字,作為可能的備選詞語。
    所以我用的是python的regex模組,可以進行多漢字的重疊匹配。
  • 第二步:統計詞頻
    真正的詞語應該至少出現一定次數,而那些區域性切割出來的碎片出現次數則較少,因此可以統計一下以上全部可能備選詞語的詞頻
    對於《西遊記》而言,一共出現了4459個漢字,而長度不超過5個漢字的全部可能備選詞語共824567個。為了得到這些詞語的詞頻,我寫了一個迴圈,挨個在《西遊記》中查詢每一個詞的詞頻。但是事實證明這樣相當浪費時間,因為這個迴圈需要進行824567次!所以更好的方法是,同樣還是使用regex匹配單漢字、雙漢字、三漢字、四漢字和五漢字詞語,只不過不進行set、list的去重操作,這樣返回的匹配結果中便包含了全部備選詞語的詞頻,而且一共只需執行五次正則匹配,所需時間會少很多。
  • 第三步:計算聚合度
    聚合度的概念很好理解,例如“齊天”會和“大聖”出現在一起,因為“齊天大聖”這個詞的聚合度很高。
    假設該詞語為S,首先計算該詞語出現的概率P(S),然後嘗試S的所有可能的二切分,即分為左半部分sl和右半部分sr並計算P(sl)和P(sr),例如雙漢字詞語存在一種二切分、三漢字詞語存在兩種二切分。接下來計算所有二切分方案中,P(S)/(P(sl)×P(sr))的最小值,取對數之後即可作為聚合度的衡量。
    以雙漢字詞語為例,可以想象到,如果該詞語的聚合度很低,說明其第一個字和第二個字的相關性很弱,甚至是不相關的,那麼P(S)和P(sl)×P(sr)將處於同一個數量級。相反,如果該詞語的聚合度很高,“齊天”、“大聖”和“齊天大聖”三者的概率都很接近,因此P(S)/(P(sl)×P(sr))將是一個遠大於1的數值。
    有意思的是,《西遊記》的824567個備選詞中,對應的聚合度範圍為-6至20。為什麼會出現負數呢?說明P(S)比P(sl)×P(sr)更小,即sl和sr同時出現的可能性更低,因此別提聚合,可能還存在某些排斥。

  • 第四步:計算自由度
    有了聚合度的概念,我們可以自動識別出類似“齊天大聖”這樣的詞語。那麼問題來了,“天大聖”是一個有效詞語嗎?“齊天大”呢?可以推測到,這兩個詞語的聚合度也很高,但是它們卻不應該成為有效的詞語。
    一個有效的詞語,應該能夠被靈活地運用到各種語句中,其上下文搭配應當是豐富的,這便是自由度的概念。“天大聖”的左邊絕大多數都是“齊”,“齊天大”的右邊絕大多數都是“聖”,因此它們的自由度很低。可以用熵來衡量一個詞語的自由度。假設一個詞語一共出現了N次,其左邊共出現過n個漢字,每個漢字依次出現N1,N2,……,Nn次,則滿足N = N1 + N2 + …… + Nn,因此可以計算該詞語左邊各個漢字出現的概率,並根據熵公式計算左鄰熵。熵越小則自由度越低,例如“天大聖”的左鄰熵接近於0,因為“齊”字的概率幾乎為1;熵越大則自由度越高,表示用詞搭配越混亂、越自由、越多樣。因為“天大聖”的左鄰熵很小,而右鄰熵則相對較大,因此我們將一個詞語左鄰熵和右鄰熵中較小者作為最終的自由度。

.

標準一:通常我們認為兩個片段可以成詞的一個條件就是這個詞語會在很多的語境中被提到。熵就是一個用來衡量這個維度的指標。
標準二:內部聚合程度 - 互資訊 (mutual information) & 點間互資訊 (pointwise mutual information)
.

7、semi-CRF演算法與神經網路的中文分詞方法

作者: 哈工大SCIR博士生 劉一佳,文章為《賽爾原創 | 基於詞的神經網路中文分詞方法》 在ICLR2016上,Kong等人發表了一篇名為Segmental Recurrent Neural Networks (SRNN)的工作[Kong et al.2015]。這篇工作的核心思想是將semi-CRF演算法與神經網路進行結合。

CRF基於馬爾科夫過程建模,演算法在隨機過程的每步對輸入序列的一個元素進行標註。而semi-CRF則是基於半-馬爾科夫過程建模,演算法在每步給序列中的連續元素標註成相同的標籤。semi-CRF演算法的這一性質使得它可以直接應用於中文分詞任務。標註連續元素的行為可以看做從字序列中識別出詞來。形式化地講,semi-CRF建模的是整句分割的概率。其函式形式如下:
這裡寫圖片描述
其中,x對應輸入字序列,s對應分詞序列。G(x,s)將x和s表示為特徵向量。G是一種泛化的函式,它的輸出可以是稀疏的0-1向量,也可以是稠密的詞表示。
他們使用一個雙向RNN作為G函式。這個雙向RNN將成詞的若干個字的向量組合為這個詞的向量。他們的模型如圖1所示。由於這種網路具有將字向量組合成詞向量的功能,本文稱其為組合網路。
這裡寫圖片描述
在IJCAI2016發表的工作 Exploring Segment Representations for Neural Segmentation Models 中嘗試了兩種雙向RNN的替代網路:CNN以及直接拼接。實驗結果如表1所示。結果顯示,使用CNN (SCNN)或拼接 (SCONCATE)都無法取得與基線結果類似的效能,準確率甚至低於SRNN。

我們首先使用一個不依賴詞向量的模型(SRNN或SCONCATE)對大規模文字進行切分,然後從自動切分結果中使用word2vec學習詞向量。這種方法解決了詞向量的獲取問題。
這裡寫圖片描述
引入詞向量能夠帶來分詞準確率的顯著提升。

.

8、中文分詞:字嵌入+Bi-LSTM+CRF

本文來源於公眾號待字閨中,原創作品名稱《97.5%準確率的深度學習中文分詞(字嵌入+Bi-LSTM+CRF)》

基於傳統機器學習的方法 ,以CRF為主,也有用svm,nn的實現,這類都是基於模型的,跟本文一樣,都有個缺陷,不方便增加使用者詞典(但可以結合,比如解碼的時候force-decode)。 速度上會有損耗。 另外都需要提取特徵。傳統CRF一般是定義特徵模板,方便性上有所提高。另外傳統CRF訓練演算法(LBFGS)較慢,也有使用sgd的,但多執行緒都支援的不好。代表有crf++, crfsuite, crfsgd, wapiti等。

  • 本文實現的第一步也是對語料進行處理,使用word2vec對語料的字進行嵌入,每個字特徵為50維。
  • 得到字嵌入後,用字嵌入特徵餵給雙向LSTM, 對輸出的隱層加一個線性層,然後加一個CRF就得到本文實現的模型。

這裡寫圖片描述

我們首先使用word2vec對字進行嵌入,具體就是把每一句按字元切割,空格隔開,餵給word2vec,指定維度50

然後我們把每一句處理成 :

字索引1 字索引2 … 字索引N 標註1 標註2 … 標註N

對於標註,我們按字分詞的典型套路:

  • 對於單獨字元,不跟前後構成詞的,我們標註為S (0)
  • 跟後面字元構成詞且自身是第一個字元的,我們標註為B (1)
  • 在成詞的中間的字元,標註為M (2)
  • 在詞尾的字元,標註為E (3)

這樣處理後使用前面描述模型訓練。
.

9、基於雙向LSTM的seq2seq字標註

關於標註,還有一個值得討論的內容,就是標註的數目。常用的是4tag,事實上還有6tag和2tag,而標記分詞結果最簡單的方法應該是2tag。
用4tag標註,我們能總結出哪些字單字成詞、哪些字經常用作開頭、哪些字用作末尾,但僅僅用2tag,就只能總結出哪些字經常用作開頭,從歸納的角度來看,是不夠全面的。
RNN的意思是,為了預測最後的結果,我先用第一個詞預測,當然,只用第一個預測的預測結果肯定不精確,我把這個結果作為特徵,跟第二詞一起,來預測結果;接著,我用這個新的預測結果結合第三詞,來作新的預測;然後重複這個過程;直到最後一個詞。這樣,如果輸入有n個詞,那麼我們事實上對結果作了n次預測,給出了n個預測序列。整個過程中,模型共享一組引數。因此,RNN降低了模型的引數數目,防止了過擬合,同時,它生來就是為處理序列問題而設計的,因此,特別適合處理序列問題。

LSTM對RNN做了改進,使得能夠捕捉更長距離的資訊。但是不管是LSTM還是RNN,都有一個問題,它是從左往右推進的,因此後面的詞會比前面的詞更重要,但是對於分詞這個任務來說是不妥的,因為句子各個字應該是平權的。因此出現了雙向LSTM,它從左到右做一次LSTM,然後從右到左做一次LSTM,然後把兩次結果組合起來。
LSTM可以根據輸入序列輸出一個序列,這個序列考慮了上下文的聯絡,因此,可以給每個輸出序列接一個softmax分類器,來預測每個標籤的概率。基於這個序列到序列的思路,我們就可以直接預測句子的標籤。
Keras實現程式碼可見其部落格。同類文章有:
深度學習將會變革NLP中的中文分詞,陳圳,keras實現
基於深度學習的中文分詞嘗試,gensim庫和keras庫
Deep Learning 在中文分詞和詞性標註任務中的應用

簡單解釋seq2seq:
從一個Sequence做某些工作對映到(to)另外一個Sequence的任務 。具體結合實際應用來說,如下的連個任務都可以看做是Seq2Seq的任務:

  • 1、SMT翻譯任務(源語言的語句 -> 目標語言的語句)
  • 2、對話任務(上下文語句->應答語句)

RNN Encoder-Decoder 框架:

  • Encoder,是將輸入的Sequence編碼成為一個固定長度的向量

  • Decoder,是根據背景Vector(即Encoder最後輸出的向量)生成一個Token序列,作為輸出的Sequence
    這兩部分Sequence的長度可以不一致。

這裡寫圖片描述
最經典的Encoder-Decoder框架,用的就是RNN,即Encoder是一個RNN,而Decoder也是一個RNN。

10、基於全卷積網路的中文分詞

放到語言任務中看,(一維)卷積其實就是ngram模型,從這個角度來看其實CNN遠比RNN來得自然,RNN好像就是為序列任務精心設計的,而CNN則是傳統ngram模型的一個延伸。另外不管CNN和RNN都有權值共享,看上去只是為了降低運算量的一個折中選擇,但事實上裡邊大有道理。CNN中的權值共享是平移不變性的必然結果,而不是僅僅是降低運算量的一個選擇,試想一下,將一幅影象平移一點點,或者在一個句子前插入一個無意義的空格(導致後面所有字都向後平移了一位),這樣應該給出一個相似甚至相同的結果,而這要求卷積必然是權值共享的,即權值不能跟位置有關係。
RNN類模型,尤其是LSTM,一直語言任務的霸主,但最近引入門機制的卷積GCNN據說在語言模型上已經超過了LSTM(一點點),這說明哪怕在語言任務中CNN還是很有潛力的。

LSTM的優勢就是能夠捕捉長距離的資訊,但事實上語言任務中真正長距離的任務不多,哪怕是語言模型,事實上後一個字的概率只取決於前面幾個字罷了,不用取決於前面的全文,而CNN只要層數多一點,卷積核大一點,其實也能達到這個效果了。但CNN還有一個特別的優勢:CNN比RNN快多了。用顯示卡加速的話,顯示卡最擅長的就是作卷積了,因為顯示卡本身就是用來處理影象的,GPU對CNN的加速要比對RNN的加速明顯多了…
解碼階段加入硬解碼(人工干預解碼)用viterbi演算法得到最優路徑,但是在viterbi之前,可以利用詞表對各個標籤的概率進行調整。這裡的做法是:新增一個add_dict.txt檔案,每一行是一個詞,包括詞語和倍數,這個倍數就是要將相應的標籤概率擴大的倍數,比如詞表中指定詞語“科學空間,10”,而對“科學空間挺好”進行分詞時,先用模型得到這六個字的標籤概率,然後查詢發現“科學空間”這個詞在這個句子裡邊,所以將第一個字為s的概率乘以10,將第二、三個字為m的概率乘以10,將第4個字為e的概率乘以10(不用歸一化,因為只看相對值就行了),同樣地,如果某些地方切漏了(該切的沒有切),也可以加入到詞表中,然後設定小於1的倍數就行了。
.

11、詞典+LSTM的深度學習的結合(keras)

參考部落格:【中文分詞系列】 7. 深度學習分詞?只需一個詞典!
僅用一個詞典,就完成了一個深度學習分詞器的訓練,居然效果還不錯!這種方案可以稱得上是半監督的,甚至是無監督的。
做法很簡單,既然深度學習需要語料,那我就自己生成一批語料。怎麼生成?我把詞典中的詞隨機組合就行了。不對不對,隨機組合生成的不是自然語言呀?我開始也懷疑這一點,但實驗之後發現,這樣做出來的效果特別好,甚至有勝於標註語料的結果的現象。

事不宜遲,我們來動手。首先得準備一個帶詞頻的詞表,詞頻是必須的,如果沒有詞頻,則效果會大打折扣。然後寫一個函式,以正比於詞頻的概率,隨機挑選詞表中的詞語,組合成“句子”。
首先得準備一個帶詞頻的詞表,詞頻是必須的,如果沒有詞頻,則效果會大打折扣。然後寫一個函式,以正
比於詞頻的概率,隨機挑選詞表中的詞語,組合成“句子”。
.

12、【中文分詞系列】 8. 更好的新詞發現演算法

蘇劍林:http://spaces.ac.cn/archives/4256/
注意到,當特徵之間明顯不獨立的時候,可以考慮將特徵組合之後,使得特徵之間的相關性減弱,再用樸素貝葉斯。比如,對於文字,如果以字為特徵,則樸素假設顯然不成立,如“我喜歡數學”中的“喜”和“歡”、“數”和“學”都明顯相關,這時候我們可以考慮將特徵進行組合,得到“我/喜歡/數學”,這樣三個片段之間的相關性就沒有那麼強了,因此可以考慮用上述結果。可以發現,這個過程很像分詞,或者反過來說,分詞的主要目的之一,就是將句子分為若干個相關性比較弱的部分,便於進一步處理。從這個角度來看,分的可能不一定是“詞”,也可能是短語、常用搭配等。

說白了,分詞就是為了削弱相關性,降低對詞序的依賴,這一點,哪怕在深度學習模型中,都是相當重要的。有些模型,不分詞但是用CNN,也就是把若干個字組合作為特徵來看,這也是通過字的組合來減弱特徵間的相關性的體現。

既然分詞是為了削弱相關性,那麼我們分詞,就是在相關性弱的地方切斷了。文章《【中文分詞系列】 2. 基於切分的新詞發現》其實就是這個意思,只是那裡認為,文字的相關性僅由相鄰兩字(2grams)來決定,這在很多時候都是不合理的,比如“林心如”中的“心如”、“共和國”中的“和國”,凝固度(相關性)都不是很強,容易錯切。因此,本文就是在前文的基礎上改進,那裡只考慮了相鄰字的凝固度,這裡同時考慮多字的內部的凝固度(ngrams),比如,定義三字的字串內部凝固度為:
這裡寫圖片描述

這個定義其實也就是說,要列舉所有可能的切法,因為一個詞應該是處處都很“結實”的,4字或以上的字串凝固度類似定義。一般地,我們只需要考慮到4字(4grams)就好(但是注意,我們依舊是可以切出4字以上的詞來的)。

考慮了多字後,我們可以設定比較高的凝固度閾值,同時防止諸如“共和國”之類的詞不會被切錯,因為考慮三字凝固度,“共和國”就顯得相當結實了,所以,這一步就是“寧放過,勿切錯”的原則。

但是,“各項”和“專案”這兩個詞,它們的內部凝固度都很大,因為前面一步是“寧放過,勿切錯”,因此這樣會導致“各專案”也成詞,類似的例子還有“支撐著”、“球隊員”、“珠海港”等很多例子。但這些案例在3grams中來看,凝固度是很低的,所以,我們要有一個“回溯”的過程,在前述步驟得到詞表後,再過濾一遍詞表,過濾的規則就是,如果裡邊的n字詞,不在原來的高凝固度的ngrams中,那麼就得“出局”。

所以,考慮ngrams的好處就是,可以較大的互資訊閾值情況下,不錯切詞,同時又排除模凌兩可的詞。就比如“共和國”,三字互資訊很強,兩字就很弱了(主要還是因為“和國”不夠結實),但是又能保證像“的情況”這種不會被切出來,因為閾值大一點,“的情”和“的情況”都不結實了。