将H2O生成的POJO部署到Jetty:/ predict返回404

时间:2017-09-13 19:02:08

标签: amazon-ec2 jetty pojo h2o jetty-9

我已经从H2O模型中生成了一个POJO。

在单独的EC2实例上,我想将此模型部署到Jetty服务器以用作API评分端点。我怎么能这样做?

1。示例POJO

这是一个最小的例子,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";
    }
  }
}

2。我到目前为止所做的尝试

在单独的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&s‌​ex=female

我明白了:

  

HTTP错误404

     

访问/预测问题。原因是:

  Not Found 

1 个答案:

答案 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>