我在使用JPMML(scala)处理包含大量输入字段的PMML模型时遇到了问题。请看下面的最小示例:加载一个300×150像素的图像,并将其用作PCA(python)的输入:
img = PIL.Image.open(filename)img = img.resize(STANDARD_SIZE) # 300x150img = np.array([int(np.mean(a)) for a in img])pca = PCA(svd_solver=pca_method,n_components = components)train = pca.fit_transform(train_x)pipeline = PMMLPipeline(([('pca', pca), ('knn', neigh)]))sklearn2pmml(pipeline, "/tmp/pca.pmml")
接下来,这模型应使用JPMML(scala)加载:
val evaluator = new LoadingModelEvaluatorBuilder() .setLocatable(false) .load(new File("/tmp/pca.pmml")) .build()evaluator.verify()
这将会导致明显的异常:
Exception in thread "main" org.jpmml.evaluator.InvalidElementException: Model has too many input fields at org.jpmml.evaluator.ModelEvaluatorBuilder.checkSchema(ModelEvaluatorBuilder.java:135) at org.jpmml.evaluator.ModelEvaluatorBuilder.build(ModelEvaluatorBuilder.java:115) ...
如果你查看源代码,会在ModelEvaluatorBuilder
中发现以下限制:
if((inputFields.size() + groupFields.size()) > 1000){ throw new InvalidElementException("Model has too many input fields", miningSchema); }
因此,我的45k个输入字段实在是太多了。如果我正确理解了PMML文档,输入字段只能使用原子数据类型(如int、char、double等)。
有什么办法可以绕过这个限制吗?
回答:
你可以用自己的检查逻辑(如“接受所有”)重写ModelEvaluatorBuilder#checkSchema(ModelEvaluator)
方法:
evaluator = new LoadingModelEvaluatorBuilder(){ @Override protected void checkSchema(ModelEvaluator<?> modelEvaluator){ // 什么都行 - 我愿意为自己的行为负责 }} .setLocatable(false) .load(new File("/tmp/pca.pmml")) .build();
这个健全性检查是有原因的。JPMML并不适合处理二进制大对象(如图像),而且将图像对象表示为45k个双精度字段是一个非常糟糕的主意。