【中文分詞系列】 5. 基於語言模型的無監督分詞

轉載:https://spaces.ac.cn/archives/3956/

迄今爲止,前四篇文章已經介紹了分詞的若干思路,其中有基於最大概率的查詞典方法、基於HMM或LSTM的字標註方法等。這些都是已有的研究方法了,筆者所做的就只是總結工作而已。查詞典方法和字標註各有各的好處,我一直在想,能不能給出一種只需要大規模語料來訓練的無監督分詞模型呢?也就是說,怎麼切分,應該是由語料來決定的,跟語言本身沒關係。說白了,只要足夠多語料,就可以告訴我們怎麼分詞。

看上去很完美,可是怎麼做到呢?《2.基於切分的新詞發現》中提供了一種思路,但是不夠徹底。那裏居於切分的新詞發現方法確實可以看成一種無監督分詞思路,它就是用一個簡單的凝固度來判斷某處該不該切分。但從分詞的角度來看,這樣的分詞系統未免太過粗糙了。因此,我一直想着怎麼提高這個精度,前期得到了一些有意義的結果,但都沒有得到一個完整的理論。而最近正好把這個思路補全了。因爲沒有查找到類似的工作,所以這算是筆者在分詞方面的一點原創工作了。

語言模型

首先簡單談一下語言模型。

很多數據挖掘的讀者都已經聽說過Word2Vec,知道它是一個能夠生成詞向量的工具,很多人也知道將詞向量作爲模型的特徵來進行輸入。但相信不少讀者不知道爲什麼會有詞向量,爲什麼Word2Vec能生成詞向量。Word2Vec本身的光芒(Google出品、速度快、效果也不錯、在Python中有很好實現等)已經把同類產品以及背後的原理都給掩蓋下去了。事實上,詞向量的初衷,是爲了更好地生成語言模型,最經典的文章應該是深度學習的鼻祖之一——Bengio——的《A Neural Probabilistic Language Model》。這一段的重點是談語言模型,不是詞向量。關於詞向量,有興趣的讀者可以參考下面的文章:

Deep Learning in NLP (一)詞向量和語言模型:
http://licstar.net/archives/328

火光搖曳的《我們是這樣理解語言的》系列:
http://www.flickering.cn/?s=我們是這樣理解語言的

語言模型是計算條件概率

p(wn|w1,w2,…,wn−1)

的模型,其中w1,w2,…,wn−1是句子中的前n−1個詞(或字),wn是第n個詞(或字)。語言模型在很多方面都有應用,比如說分詞、語音識別、機器翻譯等。爲了得到語言模型,有很多方法,比如說最簡單的是“統計+平滑”的方法,還有最大熵語言模型、CRF語言模型等,而當前深度學習框架下研究得很多的是“神經網絡語言模型”,它的大概思路是:p(wn|w1,w2,…,wn−1)是關於w1,w2,…,wn的一個函數,這個函數的具體形式我不知道,所以利用神經網絡去擬合它,爲了更好地擬合,並且減少模型參數,還把詞語“嵌入”到實數空間中,用短向量來表示詞語,跟語言模型一起訓練。從這個角度看,詞向量只是語言模型的副產品。

語言模型生成的詞向量能夠較好地表示語義,這是很有趣的,卻也是在情理之中。什麼是語義?對人類來說,語義是一種推理和理解的過程,而我們的語言模型,就是從前n−1個字推測下一個字,這也是一個推理的過程。既然包含了推理成分在裏邊,就有可能捕捉到語義了。

無監督分詞

說語言模型似乎說得有點多了,不過,本文要介紹的分詞方法,就是以“基於字的語言模型”爲基礎的。

我們從最大概率法出發,如果一個長度爲l的字符串s1,s2,…,sl,最優分詞結果爲w1,w2,…,wm,那麼它應該是所有切分中,概率乘積

p(w1)p(w2)…p(wm)

最大的一個。

假如沒有詞表,自然也就不存在w1,w2,…,wm這些詞了。但是,我們可以用貝葉斯公式,將詞的概率轉化爲字的組合概率:

p(w)=p(c1)p(c2|c1)p(c3|c1c2)…p(ck|c1c2…ck−1)

其中w是一個k字詞,c1,c2,…,ck分別是w的第1,2,…,k個字。可以發現,p(ck|c1c2…ck−1)就是我們前面提到過的字的語言模型。

當然,對於很大的kp(ck|c1c2…ck−1)還是不容易估算的,不過幸好按照我們的經驗,詞的平均長度不會很大,因此,我們只需要用n-gram語言模型就夠了,其中n爲4時效果就挺不錯了。

那分詞具體又是怎麼操作呢?假如字符串s1,s2,s3…,sl,如果不進行切分,那麼它的路徑概率應該是

p(s1)p(s2)p(s3)…p(sl)

如果s1,s2應該合併爲一個詞,那麼它的路徑概率是
p(s1s2)p(s3)…p(sl)=p(s1)p(s2|s1)p(s3)…p(sl)

如果s2,s3應該合併爲一個詞,那麼它的路徑概率是
p(s1)p(s2s3)…p(sl)=p(s1)p(s2)p(s3|s2)…p(sl)

如果s1,s2,s3應該合併爲一個詞,那麼它的路徑概率是
p(s1s2s3)…p(sl)=p(s1)p(s2|s1)p(s3|s1s2)…p(sl)

看到特點了嗎?每一種切分方式,事實上都對應着l個條件概率的相乘,我們就是從這些條件概率的相乘模式中,找出結果最大的那個。而同樣的,如果我們知道了最優的相乘模式,就可以對應地寫出分詞結果來。

更系統地看,其實就是將分詞轉化爲了標註問題,如果字語言模型取到4-gram,那麼它相當於做了如下的字標註:

b:單字詞或者多字詞的首字
c:多字詞的第二字
d:多字詞的第三字
e:多字詞的其餘部分

對於句子中的一個字sk來說,就有

p(b)=p(sk)p(c)=p(sk|sk−1)p(d)=p(sk|sk−2sk−1)p(e)=p(sk|sk−3sk−2sk−1)

這就是將分詞問題變成了一種字標註問題,而每個標籤的概率由語言模型給出。而且,顯然b後面只能接b或者c,類似地,就得到非零的轉移概率只有:

p(b|b),p(c|b),p(b|c),p(d|c),p(b|d),p(e|d),p(b|e),p(e|e)

這些轉移概率的值,決定了劃分出來的是長詞還是短詞。最後找最優路徑,依舊由viterbi算法完成。

到這裏,問題就變成了語言模型的訓練了,這是無監督的。我們只需要花心思優化語言模型,而這方面不論是理論還是實戰都已經很成熟了,有不少現成的工具可以用。簡單地可以只用傳統的“統計+平滑”模型,如果要從語義來做,那麼就可以用最新的神經語言模型。總而言之,分詞的效果,取決於語言模型的質量。

實踐:訓練

首先來訓練語言模型。這裏文本數據是50萬微信公衆號的文章,約2GB大小,訓練語言模型用的是傳統的“統計+平滑”的方法,使用kenlm這個工具來訓練。

kenlm是一個C++編寫的語言模型工具,具有速度快、佔用內存小的特點,也提供了Python接口。首先下載編譯它:

1
2
3
4
wget -O - http://kheafield.com/code/kenlm.tar.gz |tar xz 
cd kenlm
./bjam -j4
python setup.py install

接着訓練語言模型。kenlm的輸入很靈活,不用預先生成語料文本,而可以通過管道的方式傳遞。比如先編寫一個p.py

1
2
3
4
5
import pymongo
db = pymongo.MongoClient().weixin.text_articles
 
for text in db.find(no_cursor_timeout=True).limit(500000):
    print ' '.join(text['text']).encode('utf-8')

我的文章放在MongoDB中,所以是上面的格式,如果你的數據放在其他地方,請做相應修改,其實很簡單,就是把你要訓練的文本分好詞(用空格隔開),然後逐一print出來。

然後就可以訓練語言模型了,這裏訓練一個4-gram的語言模型:

1
2
python p.py|./kenlm/bin/lmplz -o 4 > weixin.arpa
./kenlm/bin/build_binary weixin.arpa weixin.klm

arpa是通用的語言模型格式,klm是kenlm定義的二進制格式,klm格式佔用空間更少。最後我們就可以在Python中載入了

1
2
3
4
5
6
7
import kenlm
model = kenlm.Model('weixin.klm')
model.score('微 信', bos=False, eos=False)
'''
score函數輸出的是對數概率,即log10(p('微 信')),其中字符串可以是gbk,也可以是utf-8
bos=False, eos=False意思是不自動添加句首和句末標記符
'''

實踐:分詞

有了上述基礎,就可以來做一個分詞系統了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import kenlm
model = kenlm.Model('weixin.klm')
 
from math import log10
 
#這裏的轉移概率是人工總結的,總的來說,就是要降低長詞的可能性。
trans = {'bb':1, 'bc':0.15, 'cb':1, 'cd':0.01, 'db':1, 'de':0.01, 'eb':1, 'ee':0.001}
trans = {i:log10(j) for i,j in trans.iteritems()}
 
def viterbi(nodes):
    paths = nodes[0]
    for l in range(1, len(nodes)):
        paths_ = paths
        paths = {}
        for i in nodes[l]:
            nows = {}
            for j in paths_:
                if j[-1]+i in trans:
                    nows[j+i]= paths_[j]+nodes[l][i]+trans[j[-1]+i]
            k = nows.values().index(max(nows.values()))
            paths[nows.keys()[k]] = nows.values()[k]
    return paths.keys()[paths.values().index(max(paths.values()))]
 
def cp(s):
    return (model.score(' '.join(s), bos=False, eos=False) - model.score(' '.join(s[:-1]), bos=False, eos=False)) or -100.0
 
def mycut(s):
    nodes = [{'b':cp(s[i]), 'c':cp(s[i-1:i+1]), 'd':cp(s[i-2:i+1]), 'e':cp(s[i-3:i+1])} for i in range(len(s))]
    tags = viterbi(nodes)
    words = [s[0]]
    for i in range(1, len(s)):
        if tags[i] == 'b':
            words.append(s[i])
        else:
            words[-1] += s[i]
    return words

實踐:效果

語言模型的大小有近3G,因此就不放出來了,有需要的讀者可以聯繫我。下面看一下一些例子。

水 是 生命 的 源泉 , 是 人類 賴以生存 且無 可 替代 的 營養 物質 。 爲 使 隊員們 更加 瞭解 水 對 生命 的 至關重要 性 , 提高 隊員們 對 水 更 科學 的 認識 與 理解 , 倡導 節水 愛 水 的 環保 意識 , 青少年 環境 知識 科普 課堂 走進 大 金 小學 , 爲 五、 六年級 近 300 餘 名 隊員 開展 了 一場 《 水 與 生命 》爲主題 的 科普 知識 講座 。 此次 活動 共分爲三 場 進行 , 宣講 人 祝 老師 結合 PPT , 圖文並茂 、 生動 地 從 水 的 特性 、 水 與 生命 、 水 與 生活 以及 節水 技巧 四個 方面 與 隊員們 進行 了 交流 。 祝 老師 告訴 隊員們 水 對人體 的 重要 性 , 詳細 說明 了 水 的 營養 組成 , 同 時 提醒 隊員們 要 學會 健康 科學 的 飲水 方法 , 並 分享 了 節水 小竅門, 希望 隊員們 都能 以 自己 爲 榜樣 , 努力 承擔 “ 小 小 節水 宣傳 員 ”的 職責 , 積極 帶動 身邊的人 一起 參與 節約用水 。 PH 試紙 檢測 水 的 酸鹼度 ,隊員們 都 表現 了 濃厚的興趣 , 紛紛 取了 試紙 回家 測試 水質 。 講座 結束後, 隊員們 都 領到 了 “ 小 小 節水 宣傳 員 ” 培訓 課 程 的 結業證書 。 從 隊員們 興奮 的 表情 中 能夠 感受 到 隊員們 節水 愛 水 的 決心 。 保護 水 環境 , 珍惜 水 資源 , 從點滴做起 , 從 自己 做起 , 只要 每個人都 做到 了 保護 生態 、 愛護 環境 , 那麼 碧水藍天 就會 離我們 越來越 近 ! 打賞小編 的 最好 方式 就是 —— 點贊 ↓↓ 長按二維碼 , 關注 我們 吧! ↓↓

可以看到,效果還是不錯的,對長詞的識別效果都挺好。但是,有些情況可能不符合我們的習慣認識,比如“隊員們”作爲一個詞了,還有“且無可替代”錯誤地分爲了“且無 可 替代”,因爲“且無”太頻繁了。

區 志願者 協會 在 前幾日 得知 蘆林街道 三官殿居 有 一 居民 家庭 特別 困難 的 情況 , 12月 12 日 下午 , 招募 了 7 名 志願者 來到 蘆林三官 殿周全祿 老人 家 , 送去 了 一袋大米 和 一牀棉被 。   此次 助 養 慰問 品 是 由 廣豐區 志願者 協會 公益 基金 提供 , “ 暖冬行動 ” 作爲 志願者 協會 幫困 項目 的 其中 重要 一 項 , 由 參與 暖冬行動 的 志願者們 負責 執行 發 放到 走訪 覈實 的 困境 家庭 手中 。 志願者 現場 和 周 全 祿 老人 交談 , 從 他 本人 和 周邊 羣衆 瞭解 到 他的 基本 家庭 狀況 , 他 本人 今年 62 歲 , 娶了一個 患有 精神 疾病 的 妻子 , 生 了 2個 兒子 , 小孩 大 的 14 歲 , 小 的 12 歲 , 妻子 在 十年 前 也 離家出走 , 至今 未 回 , 留下 他 和 2個 兒子 共同 生活 , 由於 兒子 遺傳 了 母 親 的 精神 疾病 , 大 兒子 的 種種 不 正常 表現 , 不能 在 學校 正常 上 學 , 只能 整天 跟着 小 兒子 兩個 人 無所事事 , 遊手好閒 , 什麼 事 也 做 不 了。 周 老 本身就是 一個 老實巴交 的 農民 , 今年 不慎 幹農活 時 摔了一跤 , 醫藥費 2萬多 元 , 都是 村裏 和 親戚 鄰居 幫忙 籌集 的 。 他 住的 房子 也是 親戚 籌集 蓋的 一層 瓦房 。 凌亂的 客廳 , 衣服 基本 上 就是 沒有 什麼 換洗 , 溼了 就 隨意 搭着 晾乾 , 然後 接着 穿 我們 在 他 家 看到 做的 飯菜 , 這 就是 一 家人 賴以 生存 的 廚房 。 這 就是 臥室 , 牀鋪被褥 都是 破舊不堪 , 我們 帶去 的 一 牀 新 棉被 他的 外甥女 偶爾 幫他 整理 下 衛生 , 做些家務 贈人玫瑰 , 手有餘香 ; 扶困助弱 , 千古 美德 ; 能力 不 分 大 小 , 善舉 不 分 先後 , 真情 重 在 付出 。 衆人 拾柴火焰高 , 我們 將 把所有 愛心 力量 彙集 在 一起 , 傳遞 社會 大 家庭 的 溫暖 , 傳遞 社會 正能量 , 放 飛 困境兒童 的 未來 夢想 ! 伸出 您的 雙手 , 奉獻 您的 愛心 , 讓我們 行動 起來 , 共同 關愛 困境 家庭 , 讓 所 他們 同 在 藍天 下 健康 快樂 成長 ! 如果 您 或 您身邊的 人 有 12 - 15 歲 男 孩子 的 衣物 , 棉被 等 暖冬 物質 可以 捐贈 , 請伸出您 充滿 愛心 的 雙手 , 給 這個 特殊 家庭 一個 暖暖的 冬日 ! !! 暖冬 物質 接收 地址: 廣豐區 志願者 協會 暖冬 物質 接收 聯繫人: 18 6 07 03 48 18 ( 段 先生 ) 13 8 70 32 70 03 ( 陳女士 ) 供稿: 段 建 波 圖片 : 段 建 波 編輯: 周 小 飛

可以看到,即使對“拾柴火焰高”這樣的長詞也有不錯的識別效果。當然,錯誤的例子也不少,比如“把所有”、“讓我們”、“請伸出您”成爲了一個詞。

根據 業務 發展 需要 , 現 將 我 公司 20 16 年 招聘 應屆高校 畢業 生 公告 如下 : 一 、 招聘 崗位 20 16 年 我 公司 擬招聘 應屆高校 畢業 生 20 名 。 招聘 崗位 和 學歷 、 專業 要求 見下表 。 二、 報名 條件 1. 列入國家 招生 計劃 、 具備 派遣 資格 、 處於 畢業 學 年 的 全日制 普通 高等院校 在 校 生 , 以及 經 教育 部 留學 服務 中心 認證 並 具備 派遣 資 格 的 歸國留學 生 ; 2. 遵守 國家 法律法規 和 學校 規章制度 , 具有 良好 的 思想 品質 和 道德 素質 , 無 刑事 犯罪 和 嚴重 違反 校紀校規 記錄 ; 3. 專業 對 口 , 符合 工作 崗位要求 , 熱愛 鐵路 集裝箱 事業 ; 4. 學習 成績 優良 , 取得 相應 的 大學 本科 及以上學歷 和 學位證書 ; 應聘 在 京 單位 崗位 畢業 生 需 取得 國家 大學 外語 四級考試 合格 證書 ( 主 修其他語 種 除外 ); 5. 身心 健康 , 近期 醫院 健康 體檢合格 , 能夠 適應 應聘 崗位 工作 要求 。 三、 報名 方法 應 聘者 需 登錄 " 中國 鐵路 人才 招聘 網 — 個人 中心 " 欄目 按照 流程 進行 報名 應聘 ( 首次 登錄 須 進行 網上 註冊 )。 報名 截止日期 爲 20 16 年 1月 10 日 。 每人 限報一個 崗位 。 四、 招聘 流程 1. 資格 確認 。 根據 資格審查 和 初步 篩選 情況 , 於201 6年 2月 28 日前 , 擇優 以 郵件 、 短信 或 電話 方式 通知 畢業 生 參加 招聘 考試 。 2. 招聘 考試 。 參加 招聘 考試 的 畢業 生 應 攜帶 在 中國 鐵路 人才 招聘 網 打印 的 畢業 生 應聘 登記 表 , 本人 身份證 、 學生 證、 所在 學校 蓋章 的 就業 推薦 表 、 成績 單 、 外語 證書 等 材料 的 原件及複印件 。 招聘 考試 在 20 16 年 4月 15 日前 完成 , 具體 時間 、 地點 另行通知 。 3. 人員 公示 。 擬錄用人 選 將 統一 在 中國 鐵路 人才 招聘 網 和 公司 官網 進行 公示 。 招聘 過程中, 對 未 進入 下一 環節 的 畢業 生 不再 另行通知 。 五、 其他 事項 1. 公司 不 委託 第三 方 招聘 , 也不 在 招聘 過程中 向 應聘者 收 任何 費用 。 2. 應聘者 的 報名 材料 概不退回 , 在 招聘 過程中 公司 對 應聘者 的 相關 信息 予以 保密 。 畢業 生 應對 招聘 各環節 所提供的 材料 的 真實 性 負責 , 凡 弄虛作假 的 , 一 經 發現 , 取消 聘用 資格 。 3. 單位 地址: 北京 市 西城區 鴨子 橋路 24 號 中 鐵 商務大廈 郵政編碼 : 10 00 55 聯繫 電話:0 10 - 51 89 27 23

總的來說

總的來說,這種無監督的分詞方式,事實上是對我們的用字習慣做了總結,把我們常見的用字模式提取了出來。因此,它對於不少長詞,尤其是固定搭配的成語,有着很好的識別效果。同時,我們也有一些頻繁的用字組合,比如前面說的“讓我們”之類的,也被視爲單個詞語了。可能我們會覺得這是一個不合理的情況,但反過來想想,既然我們經常說“讓我們”,那麼爲什麼不把“讓我們”就作爲一個“詞”呢?

換句話說,我們做分詞,事實上就是事先提取出固定的用語模式罷了,這個固定的用語模式,不一定是我們認識中的“詞”,也有可能是習慣用語等。當然,這裏邊有個相互矛盾的地方,就是分詞的粒度太細,則詞表的詞數不會過多,但單個句子的長度則會變長;分詞的粒度太粗,則詞表的詞數可能暴增,但好處是單個句子的長度會減少。而本文所提供的分詞方式,可以通過轉移概率的調整,來實現對分詞粒度的調整,以適應不同的任務。

同時,前面已經說了,分詞的效果取決於語言模型的質量,這使得我們只需要優化語言模型,而且語言模型可以無監督地訓練,這是一個明顯的好處。比如,如果我們希望能夠實現具有語義理解能力的分詞模型,那麼用神經網絡之類的方法訓練語言模型即可,如果我們考慮速度,那麼傳統的統計方法就不錯了(用kenlm從50萬文本中得到語言模型,只用了10分鐘不到)。總而言之,提供了最大的自由度。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章