jpmml / jpmml-sklearn

Java library and command-line application for converting Scikit-Learn pipelines to PMML
GNU Affero General Public License v3.0
531 stars 117 forks source link

Add support for TPOT estimator types #54

Closed vruusmann closed 6 years ago

vruusmann commented 6 years ago

See https://github.com/rhiever/tpot/issues/152#issuecomment-341694304

esanchezSavvyds commented 6 years ago

Not supported transformers and estimators:

Not supported Models:

Not supported preprocessors:

In general, all selectors are not supported:

java.lang.UnsupportedOperationException at sklearn.Selector.getOpType(Selector.java:42) at sklearn2pmml.PMMLPipeline.encodePMML(PMMLPipeline.java:125) at org.jpmml.sklearn.Main.run(Main.java:144) at org.jpmml.sklearn.Main.main(Main.java:93)

Exception in thread "main" java.lang.UnsupportedOperationException at sklearn.Selector.getOpType(Selector.java:42) at sklearn2pmml.PMMLPipeline.encodePMML(PMMLPipeline.java:125) at org.jpmml.sklearn.Main.run(Main.java:144) at org.jpmml.sklearn.Main.main(Main.java:93)

I will update it when I find more

vruusmann commented 6 years ago

In general, all selectors are not supported

SkLearn selectors don't have a persistent state starting from the 0.19 version. They are all supported, but they need to be wrapped into a sklearn2pmml.SelectorProxy object first - see slides 23 and 24 for more information: https://www.slideshare.net/VilluRuusmann/converting-scikitlearn-to-pmml

The easiest way to "escape" selectors is to filter the original TPOT pipeline using the sklearn2pmml.make_pmml_pipeline function. See the highlighted code example on slide 28.

esanchezSavvyds commented 6 years ago

Hi @vruusmann We have been testing the new version of the library and we have reached 2 problems: - We have encountered an error related to Stacking Estimator when trying to export this pipeline: Pipeline: PMMLPipeline(steps=[('stackingestimator', StackingEstimator(estimator=BaggingRegressor(base_estimator=None, bootstrap=True, bootstrap_features=False, max_features=0.9500000000000001, max_samples=5, n_estimators=100, n_jobs=1, oob_score=False, random_state=None, verbose=0, warm_start=False))), ('standardscaler', StandardScaler(copy=True, with_mean=True, with_std=True)), ('ridgecv', RidgeCV(alphas=(0.1, 1.0, 10.0), cv=None, fit_intercept=True, gcv_mode=None, normalize=False, scoring=None, store_cv_values=False))]) Error Failed to convert java.lang.IllegalArgumentException: Empty selection for names [stack(8)] at org.jpmml.model.FieldUtil.selectAll(FieldUtil.java:56) at org.jpmml.model.FieldUtil.selectAll(FieldUtil.java:45) at org.jpmml.model.visitors.FieldDependencyResolver.process(FieldDependencyResolver.java:189) at org.jpmml.model.visitors.FieldDependencyResolver.visit(FieldDependencyResolver.java:77) at org.dmg.pmml.DerivedField.accept(DerivedField.java:373) at org.dmg.pmml.PMMLObject.traverse(PMMLObject.java:86) at org.dmg.pmml.TransformationDictionary.accept(TransformationDictionary.java:181) at org.dmg.pmml.PMMLObject.traverse(PMMLObject.java:68) at org.dmg.pmml.PMML.accept(PMML.java:391) at org.jpmml.model.visitors.AbstractVisitor.applyTo(AbstractVisitor.java:272) at org.jpmml.model.visitors.FieldResolver.applyTo(FieldResolver.java:57) at org.jpmml.model.visitors.FieldDependencyResolver.applyTo(FieldDependencyResolver.java:52) at org.jpmml.model.visitors.DeepFieldResolver.applyTo(DeepFieldResolver.java:17) at org.jpmml.converter.ModelEncoder.encodePMML(ModelEncoder.java:54) at org.jpmml.sklearn.SkLearnEncoder.encodePMML(SkLearnEncoder.java:64) at sklearn2pmml.PMMLPipeline.encodePMML(PMMLPipeline.java:297) at org.jpmml.sklearn.Main.run(Main.java:145) at org.jpmml.sklearn.Main.main(Main.java:94)

Exception in thread "main" java.lang.IllegalArgumentException: Empty selection for names [stack(8)] at org.jpmml.model.FieldUtil.selectAll(FieldUtil.java:56) at org.jpmml.model.FieldUtil.selectAll(FieldUtil.java:45) at org.jpmml.model.visitors.FieldDependencyResolver.process(FieldDependencyResolver.java:189) at org.jpmml.model.visitors.FieldDependencyResolver.visit(FieldDependencyResolver.java:77) at org.dmg.pmml.DerivedField.accept(DerivedField.java:373) at org.dmg.pmml.PMMLObject.traverse(PMMLObject.java:86) at org.dmg.pmml.TransformationDictionary.accept(TransformationDictionary.java:181) at org.dmg.pmml.PMMLObject.traverse(PMMLObject.java:68) at org.dmg.pmml.PMML.accept(PMML.java:391) at org.jpmml.model.visitors.AbstractVisitor.applyTo(AbstractVisitor.java:272) at org.jpmml.model.visitors.FieldResolver.applyTo(FieldResolver.java:57) at org.jpmml.model.visitors.FieldDependencyResolver.applyTo(FieldDependencyResolver.java:52) at org.jpmml.model.visitors.DeepFieldResolver.applyTo(DeepFieldResolver.java:17) at org.jpmml.converter.ModelEncoder.encodePMML(ModelEncoder.java:54) at org.jpmml.sklearn.SkLearnEncoder.encodePMML(SkLearnEncoder.java:64) at sklearn2pmml.PMMLPipeline.encodePMML(PMMLPipeline.java:297) at org.jpmml.sklearn.Main.run(Main.java:145) at org.jpmml.sklearn.Main.main(Main.java:94) I think it's related to the number of stacking estimators that are used in that pipeline, as before converting it to a PMMLpipeline it had more than one. - We have encountered an error related to FeatureUnion when trying to export this pipeline: Pipeline: PMMLPipeline(steps=[('featureunion', FeatureUnion(n_jobs=1, transformer_list=[('functiontransformer', FunctionTransformer(accept_sparse=False, func=<function copy at 0x000002262FA977B8>, inv_kw_args=None, inverse_func=None, kw_args=None, pass_y='deprecated', validate=True)), ('stackingestimator', StackingEstimator(estimator=Pipe...ss='squared_epsilon_insensitive', max_iter=1000, random_state=None, tol=1e-05, verbose=0))])))], transformer_weights=None)), ('ridgecv', RidgeCV(alphas=(0.1, 1.0, 10.0), cv=None, fit_intercept=True, gcv_mode=None, normalize=False, scoring=None, store_cv_values=False))]) Error: Failed to convert java.lang.IllegalArgumentException: Attribute 'sklearn.preprocessing._function_transformer.FunctionTransformer.func' has an unsupported value (Java class net.razorvine.pickle.objects.ClassDictConstructor) at org.jpmml.sklearn.CastFunction.apply(CastFunction.java:43) at org.jpmml.sklearn.PyClassDict.get(PyClassDict.java:55) at sklearn.preprocessing.FunctionTransformer.getUFunc(FunctionTransformer.java:77) at sklearn.preprocessing.FunctionTransformer.encodeFeatures(FunctionTransformer.java:50) at sklearn.pipeline.FeatureUnion.encodeFeatures(FeatureUnion.java:58) at sklearn.pipeline.Pipeline.encodeFeatures(Pipeline.java:81) at sklearn2pmml.PMMLPipeline.encodePMML(PMMLPipeline.java:147) at org.jpmml.sklearn.Main.run(Main.java:145) at org.jpmml.sklearn.Main.main(Main.java:94) Caused by: java.lang.ClassCastException: Cannot cast net.razorvine.pickle.objects.ClassDictConstructor to numpy.core.UFunc at java.lang.Class.cast(Unknown Source) at org.jpmml.sklearn.CastFunction.apply(CastFunction.java:41) ... 8 more

Exception in thread "main" java.lang.IllegalArgumentException: Attribute 'sklearn.preprocessing._function_transformer.FunctionTransformer.func' has an unsupported value (Java class net.razorvine.pickle.objects.ClassDictConstructor) at org.jpmml.sklearn.CastFunction.apply(CastFunction.java:43) at org.jpmml.sklearn.PyClassDict.get(PyClassDict.java:55) at sklearn.preprocessing.FunctionTransformer.getUFunc(FunctionTransformer.java:77) at sklearn.preprocessing.FunctionTransformer.encodeFeatures(FunctionTransformer.java:50) at sklearn.pipeline.FeatureUnion.encodeFeatures(FeatureUnion.java:58) at sklearn.pipeline.Pipeline.encodeFeatures(Pipeline.java:81) at sklearn2pmml.PMMLPipeline.encodePMML(PMMLPipeline.java:147) at org.jpmml.sklearn.Main.run(Main.java:145) at org.jpmml.sklearn.Main.main(Main.java:94) Caused by: java.lang.ClassCastException: Cannot cast net.razorvine.pickle.objects.ClassDictConstructor to numpy.core.UFunc at java.lang.Class.cast(Unknown Source) at org.jpmml.sklearn.CastFunction.apply(CastFunction.java:41) ... 8 more

Do you know what can it be? Thank you very much.

vruusmann commented 6 years ago

The first pipeline contains sequence: [BaggingRegressor, StandardScaler, RidgeCV]. The exception is related to the scoping of fields - the predicted outputs of BaggingRegressor (ie. field stack(8)) are not visible globally, so StandradScaler transformation which is to be encoded as a DerivedField element in the top-level TransformationDictionary element cannot see them.

The second pipeline contains FunctionTransformer, which wraps some anonymous machine-generated Numpy UFunc. The JPMML-SkLearn library is unable to determine its identity (because it doesn't have a name), so it's not supported.