使用 Java 客户端评估已部署的计算机学习模型
此示例展示如何编写一个客户端应用程序,使用 MATLAB® Production Server™ Java® 客户端库来评估部署到 MATLAB Production Server 的计算机学习模型。本示例中使用分类学习器应用程序来训练和导出模型。通常,MATLAB 开发人员会训练模型,并使用分类学习器应用程序或回归学习器应用程序将训练后的模型导出为可部署存档(CTF 文件)。有关详细信息,请参阅Deploy Model Trained in Classification Learner to MATLAB Production Server (Statistics and Machine Learning Toolbox)和Deploy Model Trained in Regression Learner to MATLAB Production Server (Statistics and Machine Learning Toolbox)。使用分类学习器和回归学习器需要 Statistics and Machine Learning Toolbox™。服务器管理员将存档部署到 MATLAB Production Server 实例。
该示例提供并解释了如何使用示例 Java 客户端 PredictFunctionPatientData.java 将 patients.csv 中的患者数据发送到部署在服务器上的 MATLAB 函数 predictFunction。predictFunction 的结果将患者数据分类为吸烟者或非吸烟者。该示例还使用了辅助类 PatientData.java、PatientDataBeanInfo.java 和 Utils.java。
示例中的文件可在 MATLAB Production Server Client Libraries 在线获取。在本地 MATLAB Production Server 安装中,示例文件位于 ,其中 $MPS_INSTALL/client/java/examples/ClassificationModelPatientData$MPS_INSTALL 是 MATLAB Production Server 安装位置。examples 目录还包含一个示例 Java 客户端,用于评估使用回归学习器应用程序创建的已部署的计算机学习模型。有关如何使用 Java 客户端库编写客户端的概述,请参阅 MATLAB Production Server Java 客户端基础知识。
确定部署函数的输入参量类型
在此示例的场景中,MATLAB 开发人员确定部署的 MATLAB 模型是否需要以矩阵或表格的形式输入数据。
如果模型需要表,Java 客户端程序必须发送对象数组,因为 MATLAB Production Server Java 客户端库不支持 table (MATLAB) 数据类型。当用作 MATLAB 函数的输入时,Java 对象会被编组到 MATLAB struct (MATLAB) 中,因为 Java 本身不支持 MATLAB 结构体。
在此示例中,部署的 predictFunction MATLAB 函数需要以对象数组的形式输入,这些对象被编组为 structs。
将输入数据表示为对象数组
文件 patients.csv 包含输入的患者数据。patients.csv 中的每一行对应一名患者,每行中逗号分隔的值对应一个诊断变量。Smoker 变量是响应变量,其余变量(Age、Diastolic、Gender、Height、SelfAssessedHealthStatus、Systolic、Weight)是预测变量。
以下部分说明如何将 CSV 文件中的患者数据转换为对象数组。部署的 MATLAB 函数 predictFunction 要求患者数据输入是一个对象数组。
创建 Java 类来表示输入数据
创建一个 Java 类 PatientData 来表示来自 patients.csv 文件的数据。PatientData 类的每个对象代表 patients.csv 中的一行。PatientData 中的实例变量名称必须与 patients.csv 中的预测变量名称相同。预测变量名称以大写字母开头。但是,实例变量名称默认以小写字母开头。稍后,您将看到如何覆盖此默认行为以匹配预测变量名称和实例变量名称的大小写。
PatientData.java 的类定义如下。
package com.mathworks;
public class PatientData {
double age;
double diastolic;
String gender;
double height;
String selfAssessedHealthStatus;
double systolic;
double weight;
public PatientData(double age, double diastolic, String gender, double height,
String selfAssessedHealthStatus, double systolic, double weight) {
this.age = age;
this.diastolic = diastolic;
this.gender = gender;
this.height = height;
this.selfAssessedHealthStatus = selfAssessedHealthStatus;
this.systolic = systolic;
this.weight = weight;
}
public double getAge() {
return age;
}
public void setAge(double age) {
this.age = age;
}
public double getDiastolic() {
return diastolic;
}
public void setDiastolic(double diastolic) {
this.diastolic = diastolic;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public String getSelfAssessedHealthStatus() {
return selfAssessedHealthStatus;
}
public void setSelfAssessedHealthStatus(String selfAssessedHealthStatus) {
this.selfAssessedHealthStatus = selfAssessedHealthStatus;
}
public double getSystolic() {
return systolic;
}
public void setSystolic(double systolic) {
this.systolic = systolic;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
@Override
public String toString() {
return "PatientData{" +
"age=" + age +
", diastolic=" + diastolic +
", gender='" + gender + '\'' +
", height=" + height +
", selfAssessedHealthStatus='" + selfAssessedHealthStatus + '\'' +
", systolic=" + systolic +
", weight=" + weight +
'}';
}
}
将 Java 实例变量映射到 MATLAB 结构成员
表示 Java 结构体的 MATLAB 类使用 Java Beans Introspector 类将实例变量映射到结构体的字段。有关 Introspector 类的更多信息,请参阅 Oracle Class Introspector 文档。这些类也使用 Introspector 类的默认命名约定。默认约定使用 decapitalize 方法,将 Java 变量名的首字母映射为小写字母。因此,使用默认值,您无法定义映射到以大写字母开头的 Java 结构体成员的 MATLAB 实例变量。您可以通过使用自定义 SimpleBeanInfo 方法实现 getPropertyDescriptors() 类来覆盖此行为。
示例使用实现 PatientDataBeanInfo 接口的 SimpleBeanInfo 类,并将 PatientDataBeanInfo 的实例变量的首字母设置为大写。PatientDataBeanInfo 类的代码如下。
package com.mathworks;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.beans.SimpleBeanInfo;
public class PatientDataBeanInfo extends SimpleBeanInfo
{
@Override
public PropertyDescriptor[] getPropertyDescriptors()
{
PropertyDescriptor[] props = new PropertyDescriptor[7];
try
{
props[0] = new PropertyDescriptor("Age",PatientData.class,
"getAge","setAge");
props[1] = new PropertyDescriptor("Diastolic",PatientData.class,
"getDiastolic","setDiastolic");
props[2] = new PropertyDescriptor("Gender",PatientData.class,
"getGender","setGender");
props[3] = new PropertyDescriptor("Height",PatientData.class,
"getHeight","setHeight");
props[4] = new PropertyDescriptor("SelfAssessedHealthStatus",PatientData.class,
"getSelfAssessedHealthStatus","setSelfAssessedHealthStatus");
props[5] = new PropertyDescriptor("Systolic",PatientData.class,
"getSystolic","setSystolic");
props[6] = new PropertyDescriptor("Weight",PatientData.class,
"getWeight","setWeight");
return props;
}
catch (IntrospectionException e)
{
e.printStackTrace();
}
return null;
}
}准备要输入到部署函数的数据
该示例提供了一个类 Utils.java,其中包含实用函数,可将 patients.csv 文件中的数据转换为已部署的 predictFunction MATLAB 函数所期望的对象数组。Utils.java 包含一个函数,可从 CSV 文件读取数据并将其转换为 ArrayList 类。Utils.java 包含另一个函数,可将 ArrayList 类转换为 PatientData 对象数组。
Utils.java 的代码如下。
package com.mathworks;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.StringTokenizer;
public class Utils {
String fileName;
Utils(String fileName) {
this.fileName = fileName;
}
public static ArrayList<String[]> readFromCsv() {
Scanner sc = null;
ArrayList<String[]> inputs = new ArrayList<String[]>();
try {
sc = new Scanner(new File("patients.csv"));
sc.useDelimiter("\n");
sc.next();
String line;
while (sc.hasNext())
{
line = sc.next();
StringTokenizer tokenizer = new StringTokenizer(line, ",");
String[] tmp = new String[tokenizer.countTokens() - 1];
for (int i = 0; i < tmp.length; i++) {
String s = tokenizer.nextToken();
if (s.compareTo("Inf") == 0) {
tmp[i] = String.valueOf(Double.POSITIVE_INFINITY);
} else if (s.compareTo("-Inf") == 0) {
tmp[i] = String.valueOf(Double.NEGATIVE_INFINITY);
} else {
tmp[i] = s;
}
}
inputs.add(tmp);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally{
sc.close();
}
return inputs;
}
public static PatientData[] prepareDataForTableInput() {
ArrayList<String[]> inputs = readFromCsv();
int i = 0;
PatientData[] datas = new PatientData[inputs.size()];
for (String[] mat : inputs) {
datas[i] = new PatientData(Double.valueOf(mat[0]), Double.valueOf(mat[1]), mat[2],
Double.valueOf(mat[3]), mat[4] ,Double.valueOf(mat[5]), Double.valueOf(mat[6]));
i++;
}
return datas;
}
}编写客户端应用程序
在客户端应用程序中,定义一个代表已部署的 Java 函数的 MATLAB 接口。然后,实例化一个代理对象来与服务器通信并调用部署的函数。
由于部署的函数需要 MATLAB 结构体作为输入,因此您必须使用 MWStructureList 注解来使接口包含您之前创建的 PatientData 类。有关如何在 MATLAB 中编组 Java 结构体的更多示例,请参阅 在 MATLAB 中编组 Java 结构 (Structs)。有关实例化代理对象和调用部署函数的示例,请参阅 使用 MWHttpClient 类创建 MATLABProduction ServerJava 客户端。
客户端应用程序 PredictFunctionPatientData.java 的代码如下。
package com.mathworks;
import com.mathworks.mps.client.MATLABException;
import com.mathworks.mps.client.MWClient;
import com.mathworks.mps.client.MWHttpClient;
import com.mathworks.mps.client.annotations.MWStructureList;
import java.io.IOException;
import java.net.URL;
interface CallMethod {
@MWStructureList({PatientData.class})
boolean[] predictFunction(PatientData[] dataSet) throws IOException, MATLABException;
}
public class PredictFunctionPatientData {
public static void main(String[] args) {
PatientData[] datas = Utils.prepareDataForTableInput();
MWClient client = new MWHttpClient();
try {
CallMethod s = client.createProxy(new URL("http://localhost:9910/DeployedClassificationModel"),
CallMethod.class);
boolean[] results = s.predictFunction(datas);
for (int j = 0; j < results.length; j++) {
System.out.println(results[j]);
}
} catch (MATLABException ex) {
System.out.println(ex);
} catch (IOException ex) {
System.out.println(ex);
} finally {
client.close();
}
}
}
另请参阅
主题
- Deploy Model Trained in Classification Learner to MATLAB Production Server (Statistics and Machine Learning Toolbox)
- Deploy Model Trained in Regression Learner to MATLAB Production Server (Statistics and Machine Learning Toolbox)
- 在 MATLAB 中编组 Java 结构 (Structs)
- 使用 MWHttpClient 类创建 MATLABProduction ServerJava 客户端
- MATLAB Production Server Java 客户端基础知识