我们的公司代码是Java,但是做算法部分用的是python的sklearn库,因此考虑用sklearn2pmml出一个pmml文件,文件里保存的是模型文件的详情,再交给Java用,实现跨平台使用,下面是使用跑通的方法:
1.在网站下载文件
https://pypi.org/project/sklearn2pmml/#files
我这里下载的是最新版的。(20180921)
2.下载的是一个压缩包,任意指定一个文件夹将文件解压缩。
image.png解压后文件内容(360解压就可以了)
3.安装sklearn2pmml
1.在cmd里,切换到之前解压缩的目录里(setup.py文件所在的位置)
2.在命令行输入
python setup.py build
python setup.py install
image.png
多了一个build文件夹
4.查看是否安装成功
image.png如上图,引入sklearn2pmml库不提示错误了,运行一下看看
image.png
上面是训练模型的代码,这里使用了最简单的参数,仅指定了pmml文件的路径。
image.png
运行报错,缺少sklearn_pandas 库。
5.安装sklearn_pandas库
https://pypi.org/project/sklearn-pandas/
安装这个.whl文件,其实安装在哪里都可以,但是为了方便找,一般都安装在Scripts文件夹下
image.png
我使用的是anaconda,如果没有使用anaconda就安装在python的script文件夹下。
在cmd里,cd到该文件夹下,输入命令:pip install sklearn_pandas-1.7.0-py2.py3-none-any.whl
这个比较简单,出现successed证明成功安装。
6.python输入测试代码
image.png运行报错
image.png
下载java端的jar包,jpmml-sklearn-executable
https://github.com/jpmml/jpmml-sklearn/releases
image.png
7.先保存成sklearn模型的自带格式
image.png修改程序加两句话
image.png
生成了自带格式的模型
在将自带格式的模型文件转换成pmml文件
8.将pkl文件转换成pmml文件
在CMD中输入下面的命令
image.png
出现下面的场景证明转换成功。
image.png
9.这个pmml文件只支持java8,不支持java7,因此要先在电脑上安装java8
https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html
上图显示出了依赖包,以及java8版本,下面是java代码
package javaTopython;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.dmg.pmml.FieldName;
import org.dmg.pmml.PMML;
import org.jpmml.evaluator.Evaluator;
import org.jpmml.evaluator.FieldValue;
import org.jpmml.evaluator.InputField;
import org.jpmml.evaluator.ModelEvaluator;
import org.jpmml.evaluator.ModelEvaluatorFactory;
import org.jpmml.evaluator.TargetField;
public class PmmlFile {
public static void main(String[] args) throws Exception {
String pathxml="D:\\pmml-model\\demo.pmml";
Map<String, Double> map=new HashMap<String, Double>();
map.put("sepal_length", 5.1);
map.put("sepal_width", 3.5);
map.put("petal_length", 1.4);
map.put("petal_width", 0.2);
predictLrHeart(map, pathxml);
}
public static void predictLrHeart(Map<String, Double> irismap,String pathxml)throws Exception {
PMML pmml;
// 模型导入
File file = new File(pathxml);
InputStream inputStream = new FileInputStream(file);
try (InputStream is = inputStream) {
pmml = org.jpmml.model.PMMLUtil.unmarshal(is);
ModelEvaluatorFactory modelEvaluatorFactory = ModelEvaluatorFactory
.newInstance();
ModelEvaluator<?> modelEvaluator = modelEvaluatorFactory
.newModelEvaluator(pmml);
Evaluator evaluator = (Evaluator) modelEvaluator;
List<InputField> inputFields = evaluator.getInputFields();
// 过模型的原始特征,从画像中获取数据,作为模型输入
Map<FieldName, FieldValue> arguments = new LinkedHashMap<>();
for (InputField inputField : inputFields) {
FieldName inputFieldName = inputField.getName();
Object rawValue = irismap
.get(inputFieldName.getValue());
FieldValue inputFieldValue = inputField.prepare(rawValue);
arguments.put(inputFieldName, inputFieldValue);
}
Map<FieldName, ?> results = evaluator.evaluate(arguments);
List<TargetField> targetFields = evaluator.getTargetFields();
//对于分类问题等有多个输出。
for (TargetField targetField : targetFields) {
FieldName targetFieldName = targetField.getName();
Object targetFieldValue = results.get(targetFieldName);
System.err.println("target: " + targetFieldName.getValue()
+ " value: " + targetFieldValue);
}
}
}
}
给出一组feature值
image.png
可以看出他的label值,应该是0,但是我的运行结果
image.png
不知道问题出现在哪里,回头我再检查一下是否是模型的问题。
10.首先从源头开始检查
所谓的源头就是python代码和生成的模型文件。
1,首先在网上百度了python端的代码,越简单出错的可能性越小
发现其实python端的代码都比较简单,主要有两种形式,上面已经展示了一种,就是含有feature_name的,下面我用的这种更加简单,是不含有feature_name的,但其实本质上并没有差别,是一样的,随便挑一种都可以。
from sklearn2pmml import PMMLPipeline
from sklearn.datasets import load_iris
from sklearn import tree
from sklearn.externals import joblib
from sklearn.linear_model import LogisticRegression
iris = load_iris()
clf = LogisticRegression()
pipeline = PMMLPipeline([("classifier", clf)])
pipeline.fit(iris.data, iris.target)
joblib.dump(pipeline, "pipeline.pkl", compress=9)
因为是跑通代码的demo,所以算法为默认参数,没有进行调参等处理。可以看到上面引用了tree,是因为一开始我在网上搜到的代码,别人用的是决策树。
这里提到是因为我踩了一个坑,对于零基础第一次做的人来说,可能并不容易察觉。
当我检查转换成的pmml文件的时候,发现
image.png
下图中的
DataField name,只有x1,x3,x4,并没有x2,也就是说生成的模型文件其实是不正确的。
因为python端的代码选择了最简单的代码,不可能出错,本着算法工作者的直觉,考虑换成了较为“安全”的逻辑回归。
再次生成模型文件,转换文件格式,发现模型文件正确了。
2,注意算法和参数的选择对模型正确性的影响
更正:这里出现了错误
其实出现特征缺失是因为这项特征前面的系数为0,所以模型文件做了简化处理,并不影响结果。我后来又用手写数字识别的数据做了实现,发现不论如何更换算法,x1,x40,x41这几个特征总是缺失,于是意识到了,这与算法无关,只不过是特征前面的系数为0。模型文件可以处理这样的缺失,类似于libsvm类型的数据一样,缺失值当做0处理,因此在java端赋值的时候可以正常赋值,并不影响正确结果
赋值结果
以上是我在理解上的错误,更正一下,至于上次出错的原因,猜测是因为决策树算法有一些不可或缺的参数,我没有赋值导致的结果总是null,跟算法的选择无关。
特此更正
11.java端的代码
网上java端的代码也有两种版本,经过尝试,上面给出的版本是可以跑通的,另一种在我这里不能用,不知道什么原因,因为在python代码中没有调用feature_name,所以在仅需在上面的java代码中将主函数的map.put()传参数的部分的key值做一下修改就可以了。
image.png
运行结果
target: y value: ProbabilityDistribution{result=2, probability_entries=[0=1.6171914035182245E-4, 1=0.427941843129312, 2=0.5718964377303362]}
image.png
运行结果中,target:y因为没有给target也就是label命名,因此默认y。后面value给出的是概率分布,result给出的是可能性最大的分类。后面是每一个类别的概率。
因为水平不行,所以就这么一个简单的东西折腾了好久。不知道这么做的人是不是比较少,网上的资料搜来搜去就那么几个,而且都是python部分和Java部分分开的。我这里算是一个小总结,省的自己将来再踩坑。
网友评论