1. 引子
一階邏輯:
???? 規則:如果A是人,那么A會死(人是會死的)
???? 已知事實:柏拉圖是人
???? 推理事實:柏拉圖會死
其思想就是 對于已知事實使用非常確定的規則進行推理,希望能發現未知的事實。
但是在現實世界中,很少有規則是沒有意外的,比如:
???? 好人有好報(才怪呢),郎才配女貌(也不一定),功到自然成(更是屁話),甚至連是人就會死都不一定(如果你相信電影《那個男人來自地球》所言其實的話)。
那末,我們如何對這類的知識進行建模呢?
馬爾可父邏輯網提供了一種表示該知識的模型。它通過對規則引入權重來表示規則的確定性 ,如果權重非常大非常大(正無窮),則表示該規則非常之肯定,比如人是會死的;如果權重不是非常大,則表示該規則不一定很確定,比如吸煙會減少壽命;權重為零,則表示該規則有等于沒有,比如讀書會讓人快樂(我亂扯的,嘿嘿);如果權重非常小非常小(負無窮),則表示該規則非常之肯定不成立,比如人是不會死的。 通過對已知事實結合規則構建一個馬爾可夫邏輯網,并進行概率推理,計算出未知事實成真的概率。
大概思想就是這樣。
?
2. 分類
這樣的模型非常之適合知識推理,但是用于分類問題好像不是很明顯。
這個時候我們需要對問題進行一些轉換:
分類問題<==>指定對象類別<==>確定該對象是否屬于該類別<==>是否能推導出該對象屬于該類別
也就是說:
???? 加入需要對文檔doc進行分類,他可能屬于C1,C2和C3,則我們需要通過已知的事實證據計算其能推導出C1(doc)、C2(doc)、C3(doc)的可能性分別有多大,最簡單的一種方式就是選擇概率最的類別為其分類類別。
?
3.實踐
該例子為一個3類文本分類問題,使用MLN目前唯一的Alchemy作為實驗平臺:
依照Alchemy用戶手冊給出的語法和規則,定義各個文件如下:
1) three.mln
//predicate declarations
HasToken(doc, token)
Class0(doc)
Class1(doc)
Class2(doc)
//formulas
HasToken(d, +t) => Class0(d)
HasToken(d, +t) => Class1(d)
HasToken(d, +t) => Class2(d)
2) three-train.db
Class0(Doc37261)
Class0(Doc37913)
...
HasToken(Doc37261, ASheep)
HasToken(Doc37261, AVisualization)
HasToken(Doc37261, AXref)
...
3) three-test.db
HasToken(Doc39063, ASystems)
HasToken(Doc39063, AWet)
HasToken(Doc39063, ATIF)
...
權重學習命令: ../../bin/learnwts -d -i three.mln -o three-out.mln -t three-train.db -ne HasToken,Class0,Class1,Class2
學習到的規則及其權重如下:
//predicate declarations
HasToken(doc,token)
Class0(doc)
Class1(doc)
Class2(doc)
// 1.80043? HasToken(d,ASheep) => Class0(d)
1.80043? !HasToken(a1,ASheep) v Class0(a1)
// 2.96212? HasToken(d,AVisualization) => Class0(d)
2.96212? !HasToken(a1,AVisualization) v Class0(a1)
...
推理事實命令: ../../bin/infer -i three-out.mln -e three-test.db -r three.results -q Class0,Class1,Class2
推理結果為:
注:該次試驗是失敗的,效果也N不好,因為沒有對特征進行任何處理,連詞干化都沒做
...
Class0(Doc61551) 4.9995e-05
Class0(Doc61552) 4.9995e-05
...
最后文件組織如下圖:
分別給定訓練集路徑和測試集路勁,轉換語料庫為Alchemy格式的數據,數據的組織如下圖:
轉換格式的python腳本如下:
#encoding:utf-8
import os
import re
tp = re.compile(r'\W')
mlnfile = "three.mln"
traindb = "three-train.db"
testdb? = "three-test.db"
validb? = "three-validate.db"
#對指定文件路徑生成token列表
def genetoken(filepath):
??? lines = open(filepath).readlines()
??? tokens = list()
??? line_tokens = [token for line in lines for token in tp.split(line) if len(token.strip())>0]
??? map(tokens.append, line_tokens)
??? tokens = map(upperToken, tokens)???
??? return ["A"+token for token in list(set(tokens))]
#把token首字符變大寫
def upperToken(token):
??? token = token[0].upper()+token[1:] if len(token) > 1 else token.upper()
??? return token
def getTitle(title):
??? return "Doc"+title
if __name__ == '__main__':
??? train_path = 'train'#train set path
??? test_path? = 'test' #test set path
??? classIndex = dict()#類別索引
??? for index, subfile in enumerate(os.listdir(train_path)):
??????? className = "Class" + str(index)
??????? classIndex[subfile] = "Class" + str(index)
??? #生成訓練集
??? for subdir in os.listdir(train_path):
??????? className = classIndex[subdir]#類別名
??????? subdir = os.path.join(train_path, subdir)#子目錄,即類別目錄
??????? titledb = [className + "(" + getTitle(title) + ")" for title in os.listdir(subdir)]
??????? #如Class1(Doc1111), Class2(Doc2222)
??????? open(traindb,'a').write('\n'.join(titledb) + '\n\n')
??? for subdir in os.listdir(train_path):
??????? className = classIndex[subdir]#類別名
??????? subdir = os.path.join(train_path, subdir)#子目錄,即類別目錄
??????? for docfile in os.listdir(subdir):
??????????? titleName = getTitle(docfile)
??????????? tokens = genetoken(os.path.join(subdir, docfile))
??????????? tokendb = ["HasToken(" + titleName + ", " + token + ")" for token in tokens]
??????????? open(traindb,'a').write('\n'.join(tokendb)+ '\n\n')???
??? #生成驗證集
??? for subdir in os.listdir(test_path):
??????? className = classIndex[subdir]#類別名
??????? subdir = os.path.join(test_path, subdir)
??????? titledb = [className + "(" + getTitle(title) + ")" for title in os.listdir(subdir)]#如Class1(Doc1111), Class2(Doc2222)
??????? open(validb,'a').write('\n'.join(titledb) + '\n\n')
??????? for docfile in os.listdir(subdir):
??????????? titleName = getTitle(docfile)
??????????? tokens = genetoken(os.path.join(subdir, docfile))
??????????? tokendb = ["HasToken(" + titleName + ", " + token + ")" for token in tokens]
??????????? open(testdb,'a').write('\n'.join(tokendb) + '\n\n')
?
4. 尾巴
我必須坦白,如果數據量大了該程序根本沒發工作,3*1000個文檔集更不跑不動,最后只有減少數據量實驗了,并且我現在開始考慮:
0) 該模型做文本分類是不適合滴,開始的大數據根本沒法跑,減少到mini型數據還是跑了N個小時:Done learning discriminative weights. Time Taken for learning = 3 hrs, 6.43783 mins Total time = 3 hrs, 10.7546 mins
1) 該模型對實際應用的可能性,特別是對網絡數據的知識抽取和知識發現;
2) 還有很多優化值得做,很可能該系統已經做了,只不過我不知道如何使用;
3) 還有很多工作可以做,開發很快更有效的推理學習算法,擴展模型;
對于該分類任務呢,還有不少工作沒有做,比如確定最后類別,評價分類效果等等。
沒辦法,老板又派新活了,這個MLN只有先放到一邊。那邊書都沒看完就亂扯一通確實非常不合適,但是什么都不寫吧,又怕這么久的東西事是白看了。
?
5. 參考
Pedro Domingos, etc. Markov Logic : An Interface Layer for Artificial Intelligence. 2009.
徐從富等. 馬爾可父邏輯網研究. 軟件學報. 2011.
Alchemy用戶手冊. http://alchemy.cs.washington.edu/user-manual/manual.html
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
