如何使⽤Java调取Python、R的训练模型?
在⼯业界,我们经常会使⽤ Python 或 R 来训练离线模型, 使⽤ Java 来做在线 Web 开发应⽤——这就涉及到了使⽤ Java 跨语⾔来调⽤Python 或 R 训练的模型。
PMML
PMML 是 Predictive Model Markup Language 的缩写,翻译为中⽂就是“预测模型标记语⾔”。它是⼀种基于XML的标准语⾔,⽤于表达数据挖掘模型,可以⽤来在不同的应⽤程序中交换模型。
PMML 能做什么
介绍完了 PMML 的概念后,⼤家可能还是很懵,不清楚它有什么⽤。先来相对正式地说下它的⽤处:对于 PMML,使⽤⼀个应⽤程序很容易在⼀个系统上开发模型,并且只需通过发送XML配置⽂件就可以在另⼀个系统上使⽤另⼀个应⽤程序部署模型。也就是说我们可以通过 Python 或 R 训练模型,将模型转为 PMML ⽂件,再使⽤ Java 根据 PMML ⽂件来构建 Java 程序。
来看⼀张关于 PMML ⽤途的图⽚:
这张图的信息来⼀⼀说明下:
整个流程分为两部分:离线和在线。
离线部分流程是将样本进⾏特征⼯程,然后进⾏训练、⽣成模型。⼀般离线部分常⽤ Python 中的 sklearn、R 或者 Spark ML 来训练模型。
在线部分是根据请求得到样本数据,对这些数据采⽤与离线特征⼯程⼀样的⽅式来处理,然后使⽤模型进⾏评估。⼀般在线部分常⽤Java、C++ 来开发。
离线部分与在线部分是通过 PMML 连接的,也就是说离线训练好了模型之后,将模型导出为 PMML ⽂件,在线部分加载该 PMML ⽂件⽣成对应的评估模型。
实战环节
训练并导出 PMML
我们这⾥仍然是通过 sklearn 训练⼀个随机森林模型,我们需要借助 sklearn2pmml 将 sklearn 训练的模型导出为 PMML ⽂件。如果没有 sklearn2pmml,请输⼊以下命令来安装:
pip install --user git+github/jpmml/sklearn2pmml.git
我们来看下如何使⽤ sklearn2pmml 。
from sklearn.datasets import load_iris
semble import RandomForestClassifier
from sklearn2pmml import PMMLPipeline, sklearn2pmml
iris = load_iris()
# 创建带有特征名称的 DataFrame
iris_df = pd.DataFrame(iris.data, columns=iris.feature_names)
# 创建模型管道
iris_pipeline = PMMLPipeline([
("classifier", RandomForestClassifier())
])
# 训练模型
iris_pipeline.fit(iris_df, iris.target)
# 导出模型到 RandomForestClassifier_Iris.pmml ⽂件
sklearn2pmml(iris_pipeline, "RandomForestClassifier_Iris.pmml")
导出成功后,我们将在当前路径看到⼀个 PMML ⽂件:RandomForestClassifier_Iris.pmml。
导⼊ PMML 并进⾏评估
⽣成了 PMML ⽂件后,接下来我们要做的就是使⽤ Java 导⼊(加载)PMML⽂件。这⾥借助了 Java 的第三⽅依赖:pmml-evaluator。我们需要在 l ⽂件中加⼊以下依赖:
<dependency>
<groupId>org.jpmml</groupId>
<artifactId>pmml-evaluator</artifactId>
<version>1.4.1</version>
</dependency>
<dependency>
<groupId>org.jpmml</groupId>
<artifactId>pmml-evaluator-extension</artifactId>
<version>1.4.1</version>
</dependency>
引⼊ PMML ⽂件并进⾏评估的代码如下:
import org.dmg.pmml.FieldName;
import org.dmg.pmml.PMML;
import org.jpmml.evaluator.*;
import del.PMMLUtil;
l.sax.SAXException;
l.bind.JAXBException;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ClassificationModel {
private Evaluator modelEvaluator;
/**
* 通过传⼊ PMML ⽂件路径来⽣成机器学习模型
*
* @param pmmlFileName pmml ⽂件路径
*/
public ClassificationModel(String pmmlFileName) {
PMML pmml = null;
try {
if (pmmlFileName != null) {
InputStream is = new FileInputStream(pmmlFileName);
pmml = PMMLUtil.unmarshal(is);
try {
is.close();
} catch (IOException e) {
System.out.println("InputStream close error!");
}
ModelEvaluatorFactory modelEvaluatorFactory = wInstance();
System.out.println("加载模型成功!");
}
} catch (SAXException e) {
e.printStackTrace();
} catch (JAXBException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
// 获取模型需要的特征名称
public List<String> getFeatureNames() {
List<String> featureNames = new ArrayList<String>();
List<InputField> inputFields = InputFields();
for (InputField inputField : inputFields) {
python转java代码featureNames.Name().toString());
}
return featureNames;
}
// 获取⽬标字段名称
public String getTargetName() {
TargetFields().get(0).getName().toString();
}
// 使⽤模型⽣成概率分布
private ProbabilityDistribution getProbabilityDistribution(Map<FieldName, ?> arguments) {
Map<FieldName, ?> evaluateResult = modelEvaluator.evaluate(arguments);
FieldName fieldName = new FieldName(getTargetName());
return (ProbabilityDistribution) (fieldName);
}
// 预测不同分类的概率
public ValueMap<String, Number> predictProba(Map<FieldName, Number> arguments) {
ProbabilityDistribution probabilityDistribution = getProbabilityDistribution(arguments);
Values();
}
// 预测结果分类
public Object predict(Map<FieldName, ?> arguments) {
ProbabilityDistribution probabilityDistribution = getProbabilityDistribution(arguments);
Prediction();
}
public static void main(String[] args) {
ClassificationModel clf = new ClassificationModel("RandomForestClassifier_Iris.pmml");
List<String> featureNames = FeatureNames();
System.out.println("feature: " + featureNames);
/
/ 构建待预测数据
Map<FieldName, Number> waitPreSample = new HashMap<>();
waitPreSample.put(new FieldName("sepal length (cm)"), 10);
waitPreSample.put(new FieldName("sepal width (cm)"), 1);
waitPreSample.put(new FieldName("petal length (cm)"), 3);
waitPreSample.put(new FieldName("petal width (cm)"), 2);
System.out.println("waitPreSample predict result: " + clf.predict(waitPreSample).toString());
System.out.println("waitPreSample predictProba result: " + clf.predictProba(waitPreSample).toString());
}
}
输出结果:
加载模型成功!
feature: [sepal length (cm), petal width (cm), sepal width (cm), petal length (cm)]
waitPreSample predict result: 1
waitPreSample predictProba result: {0=0.0, 1=0.5, 2=0.5}
可以看到,模型需要的特征为:[sepal length (cm), petal width (cm), sepal width (cm), petal length (cm)],预测该样本最终属于⽬标编号为 1 的类型,预测该样本属于不同⽬标编号的概率分布,{0=0.0, 1=0.5, 2=0.5}。
⼩结
为了实现 Java 跨语⾔调⽤ Python/R 训练好的模型,我们借助 PMML 的规范,将模型固化为 PMML ⽂件,再使⽤该⽂件⽣成模型来评估
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论