1
votes

I've trained a linear model in R and exported a POJO which I've embedded in a (Java) SpringBoot webapp. Wrapping the POJO using the EasyPredictModelWrapper and instantiating an object is well described in the tutorials:

hex.genmodel.GenModel rawModel = (hex.genmodel.GenModel) Class.forName(modelClassName).newInstance();
model = new EasyPredictModelWrapper(rawModel);

I can assemble a RowData object:

RowData row = new RowData();
row.put("feature1", this.feature1);

and obtain a prediction for that row:

BinomialModelPrediction p = model.predictBinomial(row);

I've also exported the same model as a MOJO - the deployment procedure is almost identical.

My use case is that I receive a variable-length list of objects which need scoring, so I iterate the list and construct a row for each object, pass that to the wrapper and receive the prediction. So far so good.

Now I want to use a more sophisticated model that considers all the rows simultaneously. In R it's a case of passing a dataframe to the model, rather than a row (and receiving a dataframe back).

My question is: how can I pass a dataframe to a generated model object? I've gone over the source in the h2o-3 repo, read the title of every SO post in the h2o tag and scrolled through the JIRA board until I got RSI, and the closest thing I've found is a DriverlessAI class called MojoFrame, though the example given is a transform rather than a prediction.

I'm fairly sure that the EasyPredictModelWrapper doesn't support multirow input - the source is all about the RowData class. It would be great if it does but it's not necessarily a showstopper.

I'm less sure about the underlying model implementation: the MojoFrame and FrameBuilder classes tend to imply that it's supported within DriverlessAI, which may or may not use the same MOJO. Also the H2OFrame class crops up now and then in the context of scoring from Spark/R/Python, so although that's for a native model rather than the generated Java object it gives me hope that the model format can support it, and that a possible route might be to extend the support classes.

Options I've considered but haven't tested yet:

  • modify EasyPredictModelWrapper to accept Frames (lots of effort to understand the MOJO format)
  • renormalise the input list into a single row (breaks the frame-based paradigm for training the model, which probably breaks the whole process)

Has anyone done multi-row / frame-based input with the generated POJO or MOJO artifacts?

1

1 Answers

1
votes

H2O-3 MOJO/POJOs are row-based. The EasyPredictModelWrapper is a convenient wrapper for making row-based predictions.

If you want to make more than one prediction, then using a for-loop is a fine answer.

Even if sometime in the future the API expands to accept some kind of frame, it won't do anything different than the for-loop would.

(Note that this should not be confused with Driverless AI MOJOs, which are not interchangeable and do have some different properties.)


I'm less sure about the underlying model implementation: the MojoFrame and FrameBuilder classes tend to imply that it's supported within DriverlessAI, which may or may not use the same MOJO.

Despite sharing a common name of MOJO, H2O-3 MOJOs and Driverless AI MOJOs are different implementations and not interchangeable.

MOJO-ness qualities that they share are:

  • the resulting artifact doesn't need to be compiled (unlike the H2O-3 POJO, which is Java code)
  • a java runtime is supported
  • low latency, so suited for real-time applications
  • works efficiently on one row at a time, so suited for streaming applications

Driverless AI MOJOs include feature engineering transformations as well as a predictive model.


My question is: how can I pass a dataframe to a generated model object? I've gone over the source in the h2o-3 repo

You can't with the current H2O-3 MOJO API. The H2O-3 MOJO API is a row-based API. One could, of course, extend the API to do some kind of for-loop approach.


Now I want to use a more sophisticated model that considers all the rows simultaneously

I don't know what "considers all the rows simultaneously" means. This isn't what the H2O-3 MOJO API or EasyPredictModelWrapper do. The underlying math is row-by-row. Even if you put a convenience function around the math to take a frame of values, it would still calculate the results row-by-row, with the individual rows calculated one-by-one in isolation in a theoretically embarrassingly parallel way using a simple for loop, or some other fancy way if you needed parallelism for speed.

In the H2O-3 MOJO API, the result calculated for row N has no impact on the result calculated for rows N-1 or N+1 (or, more generally, the result for any row other than N).

(Note that for Driverless AI MOJOs, since feature engineering is incorporated, it is possible the above row-by-row discussion may be different. A good example is time-series windowing calculations. Such a discussion is beyond the scope of this question and answer, but worth pointing out in this context.)