機率軟邏輯(PSL,Probabilistic soft logic)是用於開發機率模型的機器學習框架,由加州大學聖克魯茲分校和馬里蘭大學的統計關係學習小組LINQS開發。目前其複雜的環境構建方式和Groovy語言表達給像做者同樣的初學者帶來了不小的困難,並且諸多的依賴項常常使本來已經構建好的模型小錯誤頻繁。java
通過努力,做者將其構建成單個jar包,而且加入編碼機制使其能夠支持各類語言的數據。主要貢獻有三:sql
1.將PSL本來複雜的依賴打包爲單個jar包,加入依賴便可開始使用。數據庫
2. 將不夠熟悉的Groovy語言模型構建方式所有轉化爲.java支持,只需一個.java文件即可進行模型構建。框架
3.加入編碼機制,使PSL能夠輕鬆處理除英文之外語言的數據。機器學習
連接:https://pan.baidu.com/s/1PybpNoPpvk4jmSMw7Rm_7A 密碼:g1cx
連接文件夾裏有三個文件:
PSL_swust1.0.jar 修改過的PSL模型
SimpleAcquaintances.zip PSL官方例子的改編版本(不包含權重學習和函數)
Entity_resolution.zip PSL官方例子的改編版本(包含權重學習和函數)函數
使用時請將PSL_swust1.0.jar加入java項目依賴便可,導入示例項目也須要將項目lib文件夾下PSL_swust.jar加入依賴。工具
以SimpleAcquaintances內SimpleAcquaintances.java爲例進行闡述。post
/* * ======【配置項】====== */ Tool tool = new Tool(); DataStore datastore; HashMap<String, Partition> partitions = new HashMap<String, Partition>(); String path = tool.getPath(new SimpleAcquaintances().getClass()) + "/../data/";// SimpleAcquaintances改成當前類名 String[] paths = tool.getFiles(path); PSLMODEL psl = new PSLMODEL(paths, "H2");// 在安裝了postgresql數據庫時可H2改成postgresql datastore = psl.getDatastore(); psl.transcoding = false;//是否給數據編碼(此值只決定數據是否編碼,謂詞默認都要編碼)
• 使用時SimpleAcquaintances須要改成當前類名(目的是爲了經過Tool類 getPath() 函數獲取獲取當前項目文件夾)。
• 當安裝配置了postgreSQL時可將 「H2」 改成 「postgresql」 來使用postgreSQL數據庫(H2爲模型自帶數據庫,運行於內存)。
• transcoding 項設置爲 true 時候模型會給數據編碼,此時模型能夠支持處理各類語言的數據(另外,設置true編碼後設置謂詞屬性爲UniqueIntID,可提高模型計算效率)。
• 此修改後的版本依然保留了PSL自帶的類似度計算函數和自定義函數功能,可是編碼後的數據沒法經過PSL自帶類似度計算函數計算類似度 (由於,編碼後的數據再也不是原來的字符串)。學習
// 權重學習分區 // partitions.put("learn_obs", datastore.getPartition("learn_obs")); // partitions.put("learn_target", // datastore.getPartition("learn_target")); // partitions.put("learn_truth", datastore.getPartition("learn_truth")); // 實驗分區 datastore = psl.getDatastore(); partitions.put("obs", datastore.getPartition("obs")); partitions.put("target", datastore.getPartition("target")); partitions.put("truth", datastore.getPartition("truth")); psl.setPartitions(partitions);
• 當須要權重學習時(有訓練數據時),須要定義權重學習分區。
• 「obs」 表明已知數據分區;
• 「target」 表明要推理的目標數據儲存分區(當要使用LazyInference推理時能夠不往裏面加載數據),
• 「truth」 爲真實數據分區。優化
HashMap<String, ConstantType[]> p = new HashMap<String, ConstantType[]>(); HashMap<String, ExternalFunction> f = new HashMap<String, ExternalFunction>(); // 添加謂詞 p.put("Lived", new ConstantType[] { ConstantType.UniqueStringID,ConstantType.UniqueStringID }); p.put("Likes", new ConstantType[] { ConstantType.UniqueStringID,ConstantType.UniqueStringID }); p.put("Knows", new ConstantType[] { ConstantType.UniqueStringID,ConstantType.UniqueStringID }); // 添加函數 // f.put("SameInitials", new SameInitials()); // f.put("SameNumTokens", new SameNumTokens()); psl.definePredicates(p, f);// 謂詞、函數輸入模型
• 謂詞定義只需替換修改便可,可隨意增減。
• 謂詞經常使用屬性有UniqueStringID、UniqueIntID、String等。
• 函數能夠定義PSL自帶類似度函數(transcoding 爲false時),也可定義繼承自ExternalFunction的自定義函數。
String[] rules = { "20.0: ( LIVED(P1, L) & (P1 != P2) & LIVED(P2, L) ) >> KNOWS(P1, P2) ^2", "5.0: ( (L1 != L2) & (P1 != P2) & LIVED(P2, L2) & LIVED(P1, L1) ) >> ~( KNOWS(P1, P2) ) ^2", "10.0: ( LIKES(P2, L) & (P1 != P2) & LIKES(P1, L) ) >> KNOWS(P1, P2) ^2", "5.0: ( KNOWS(P1, P2) & KNOWS(P2, P3) & (P1 != P3) ) >> KNOWS(P1, P3) ^2", "1.0 * KNOWS(P1, P2) + -1.0 * KNOWS(P2, P1) = 0.0 .", "5.0: ~( KNOWS(P1, P2) ) ^2" }; psl.defineRules(rules);// 規則輸入模型
• 規則格式: 權重: 規則體 >> 規則頭
• ^2表明平方優化,
• 定義本身項目的規則只需按照例子裏的規則格式增減規則便可。
• 提示:算術規則的定義只能寫成 "apredicateX(A,B)+bpredicte(A,B)= 0.0 ." 的形式,如PSL可接受的規則:「Knows(P1, P2) = Knows(P2, P1) .」 在做者修改版本中請寫成 "1.0 * KNOWS(P1, P2) + -1.0 * KNOWS(P2, P1) = 0.0 ." ,不然會報錯,後期會進行優化。
/* * ======【導入數據】====== * 其中"1-2"表示對數據的一二列進行轉碼 * 只有在transcoding = true時做用,表示只對1,2兩列進行轉碼 */ psl.loadData("Lived", path + "Lived_obs.txt", "obs", "1-2"); psl.loadDataTruth("Likes", path + "likes_obs.txt", "obs", "1-2"); psl.loadData("Knows", path + "knows_obs.txt", "obs", "1-2"); psl.loadData("Knows", path + "knows_targets.txt", "target","1-2"); psl.loadDataTruth("Knows", path + "knows_truth.txt", "truth","1-2"); // ArrayList<String[]> likepe = tool.fileToArrayList(path + "likes_obs.txt", "1-2-3"); // psl.insertDataTruth("Likes", likepe, "obs"); // psl.insertData("Likes", likepe, "obs");
• 此版本提供了loadData,loadDataTruth,insertData,insertDataTruth四種方法載入數據,格式爲:loadData("謂詞",謂詞對應數據文件路徑, "要導入的分區", "要取的列(不包含機率值那一列)")
• loadData,loadDataTruth中的"1-2"表示對數據的一二列進行轉碼, 只有在transcoding = true時做用,表示對數據文件裏的1,2兩列進行轉碼,多列增長便可,以「-」分開。
• loadData,loadDataTruth區別在於:用loadDataTruth加載數據,默認最後一列爲機率值;
• insertData,insertDataTruth適用於一個數據文件存儲了多個謂詞對應數據的狀況,使用前須要先將文件轉化爲List數據,此文版本里包含的工具類Tool提供了 fileToArrayList("文件路徑","要提取的列數")函數輔助完成轉化工做。
• ""1-2-3""表示要取出一、二、3做爲謂詞的數據,insertDataTruth取出的每一個數據 "1-2-...-n"的第n項默認是機率值。
// psl.learnWeights("learn_target", "Lived-Likes", "learn_obs", "learn_truth","MaxLikelihoodMPE");
• 格式:learnWeights("訓練數據目標分區", "封閉謂詞,即:做爲已知數據,推理過程不會再新產生的原子", "訓練數據已知數據分區", "真實數據存放分區","權重學習方法")
• 當有訓練數據時候可進行權重學習優化規則權重。
• 此版本保留了五種PSL權重優化方法:
"LazyMaxLikelihoodMPE",
"MaxLikelihoodMPE",
"MaxPiecewisePseudoLikelihood",
"MaxPseudoLikelihood",
"SimplexSampler"
替換便可使用。
psl.printModel();
• 可用於查看已經定義的模型及編碼後的模型(規則)。
// psl.runLazyInference("已知數據分區", "目標分區(存放結果)"); // psl.runLazyInference("obs", "target"); // psl.runInference(""已知數據分區"","封閉謂詞1-封閉謂詞2" , "目標分區(包含定義的目標原子)"); psl.runInference("obs","Lived-Likes" , "target");
• 此版本有兩種推理方式:LazyMPEInference,MPEInference。
• LazympeInference格式:runLazyInference("已知數據分區", "目標分區 用於存放結果")
• MPEInference格式:runInference(""已知數據分區"","封閉謂詞1-封閉謂詞2" , "目標分區 包含了輸入的目標原子")
psl.writeOutput("target", "Knows", path + "/result/knows_inffer.txt");
• 輸出函數使用格式:writeOutput("目標分區", "要輸出的數據對應謂詞1-要輸出的數據對應謂詞2", 輸出路徑)
psl.evalResults("target", "truth", "Knows", path + "/result/evalResults.txt");
• 評估函數使用格式:evalResults("目標分區", "真實數據分區", "目標謂詞1-目標謂詞2", 評估結果輸出路徑)
• 值得一提的是,"目標謂詞1-目標謂詞2" 項須要填寫全部真實數據分區所包含數據對應的謂詞。
psl.closeModel();
• 推理完成,請關閉模型。