几率软逻辑(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();
• 推理完成,请关闭模型。