我已经从H2O模型中生成了一个POJO。
在单独的EC2实例上,我想将此模型部署到Jetty服务器以用作API评分端点。我怎么能这样做?
这是一个最小的例子,demo_glm
,预测泰坦尼克号的乘客生存是对年龄,票价等级和性别的逻辑回归:
/*
Licensed under the Apache License, Version 2.0
http://www.apache.org/licenses/LICENSE-2.0.html
AUTOGENERATED BY H2O at 2017-09-13T17:30:17.931Z
3.13.0.3908
Standalone prediction code with sample test data for GLMModel named demo_glm
How to download, compile and execute:
mkdir tmpdir
cd tmpdir
curl http://XXX.XX.XX.XXX:54321/3/h2o-genmodel.jar > h2o-genmodel.jar
curl http://XXX.XX.XX.XXX:54321/3/Models.java/demo_glm > demo_glm.java
javac -cp h2o-genmodel.jar -J-Xmx2g -J-XX:MaxPermSize=128m demo_glm.java
(Note: Try java argument -XX:+PrintCompilation to show runtime JIT compiler behavior.)
*/
import java.util.Map;
import hex.genmodel.GenModel;
import hex.genmodel.annotations.ModelPojo;
@ModelPojo(name="demo_glm", algorithm="glm")
public class demo_glm extends GenModel {
public hex.ModelCategory getModelCategory() { return hex.ModelCategory.Binomial; }
public boolean isSupervised() { return true; }
public int nfeatures() { return 3; }
public int nclasses() { return 2; }
// Names of columns used by model.
public static final String[] NAMES = NamesHolder_demo_glm.VALUES;
// Number of output classes included in training data response column.
public static final int NCLASSES = 2;
// Column domains. The last array contains domain of response column.
public static final String[][] DOMAINS = new String[][] {
/* pclass */ demo_glm_ColInfo_0.VALUES,
/* sex */ demo_glm_ColInfo_1.VALUES,
/* age */ null,
/* survived */ demo_glm_ColInfo_3.VALUES
};
// Prior class distribution
public static final double[] PRIOR_CLASS_DISTRIB = null;
// Class distribution used for model building
public static final double[] MODEL_CLASS_DISTRIB = null;
public demo_glm() { super(NAMES,DOMAINS); }
public String getUUID() { return Long.toString(-1806915013443955212L); }
// Pass in data in a double[], pre-aligned to the Model's requirements.
// Jam predictions into the preds[] array; preds[0] is reserved for the
// main prediction (class for classifiers or value for regression),
// and remaining columns hold a probability distribution for classifiers.
public final double[] score0( double[] data, double[] preds ) {
final double [] b = BETA.VALUES;
for(int i = 0; i < 2; ++i) if(Double.isNaN(data[i])) data[i] = CAT_MODES.VALUES[i];
for(int i = 0; i < 1; ++i) if(Double.isNaN(data[i + 2])) data[i+2] = NUM_MEANS.VALUES[i];
double eta = 0.0;
for(int i = 0; i < CATOFFS.length-1; ++i) if(data[i] != 0) {
int ival = (int)data[i] - 1;
if(ival != data[i] - 1) throw new IllegalArgumentException("categorical value out of range");
ival += CATOFFS[i];
if(ival < CATOFFS[i + 1])
eta += b[ival];
}
for(int i = 2; i < b.length-1-1; ++i)
eta += b[1+i]*data[i];
eta += b[b.length-1]; // reduce intercept
double mu = hex.genmodel.GenModel.GLM_logitInv(eta);
preds[0] = (mu >= 0.3701702514726391) ? 1 : 0; // threshold given by ROC
preds[1] = 1.0 - mu; // class 0
preds[2] = mu; // class 1
return preds;
}
public static class BETA implements java.io.Serializable {
public static final double[] VALUES = new double[5];
static {
BETA_0.fill(VALUES);
}
static final class BETA_0 implements java.io.Serializable {
static final void fill(double[] sa) {
sa[0] = -1.280567936795408;
sa[1] = -2.2896567020762353;
sa[2] = -2.4978421167555616;
sa[3] = -0.034393168117166584;
sa[4] = 3.5220688949789816;
}
}
}
// Imputed numeric values
static class NUM_MEANS implements java.io.Serializable {
public static final double[] VALUES = new double[1];
static {
NUM_MEANS_0.fill(VALUES);
}
static final class NUM_MEANS_0 implements java.io.Serializable {
static final void fill(double[] sa) {
sa[0] = 29.881134512434045;
}
}
}
// Imputed categorical values.
static class CAT_MODES implements java.io.Serializable {
public static final int[] VALUES = new int[2];
static {
CAT_MODES_0.fill(VALUES);
}
static final class CAT_MODES_0 implements java.io.Serializable {
static final void fill(int[] sa) {
sa[0] = 2;
sa[1] = 1;
}
}
}
// Categorical Offsets
public static final int[] CATOFFS = {0,2,3};
}
// The class representing training column names
class NamesHolder_demo_glm implements java.io.Serializable {
public static final String[] VALUES = new String[3];
static {
NamesHolder_demo_glm_0.fill(VALUES);
}
static final class NamesHolder_demo_glm_0 implements java.io.Serializable {
static final void fill(String[] sa) {
sa[0] = "pclass";
sa[1] = "sex";
sa[2] = "age";
}
}
}
// The class representing column pclass
class demo_glm_ColInfo_0 implements java.io.Serializable {
public static final String[] VALUES = new String[3];
static {
demo_glm_ColInfo_0_0.fill(VALUES);
}
static final class demo_glm_ColInfo_0_0 implements java.io.Serializable {
static final void fill(String[] sa) {
sa[0] = "1st";
sa[1] = "2nd";
sa[2] = "3rd";
}
}
}
// The class representing column sex
class demo_glm_ColInfo_1 implements java.io.Serializable {
public static final String[] VALUES = new String[2];
static {
demo_glm_ColInfo_1_0.fill(VALUES);
}
static final class demo_glm_ColInfo_1_0 implements java.io.Serializable {
static final void fill(String[] sa) {
sa[0] = "female";
sa[1] = "male";
}
}
}
// The class representing column survived
class demo_glm_ColInfo_3 implements java.io.Serializable {
public static final String[] VALUES = new String[2];
static {
demo_glm_ColInfo_3_0.fill(VALUES);
}
static final class demo_glm_ColInfo_3_0 implements java.io.Serializable {
static final void fill(String[] sa) {
sa[0] = "0";
sa[1] = "1";
}
}
}
在单独的EC2实例上安装Jetty后,我按照上面评论中的说明进行操作:
cd $JETTY_HOME/demo-base/webapps
mkdir model_demo
cd model_demo
curl http://XXX.XX.XX.XXX:54321/3/h2o-genmodel.jar > h2o-genmodel.jar
curl http://XXX.XX.XX.XXX:54321/3/Models.java/demo_glm > demo_glm.java
javac -cp h2o-genmodel.jar -J-Xmx2g -J-XX:MaxPermSize=128m
我可以在http://XXX.XX.XX.YY:8080/
访问服务器,并查看&#34;欢迎使用Jetty-9&#34;浏览器或通过卷曲屏幕。
我的问题是,当我尝试:
curl http://XXX.XX.XX.YY:8080/predict?pclass=1st&age=29&sex=female
或:
curl http://XXX.XX.XX.YY:8080/model_demo/predict?pclass=1st&age=29&sex=female
我明白了:
HTTP错误404
访问/预测问题。原因是:
Not Found
答案 0 :(得分:3)
这里有两个回购你可以看一下在码头部署的POJO的工作示例:
一个部署在码头的MOJO:
关于上面的具体问题,您可能需要在.war文件中添加web.xml文件。这是来自app-mojo-servlet repo的web.xml:
$ cat src/main/webapp/WEB-INF/web.xml
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
<servlet>
<servlet-name>Predict</servlet-name>
<servlet-class>ai.h2o.PredictServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Predict</servlet-name>
<url-pattern>/predict</url-pattern>
</servlet-mapping>
</web-app>