Repository: onnx/sklearn-onnx

Issue:
Fix discrepencies introduced by sciki-learn 0.23



Discussion:

Resolving patch:
diff --git a/skl2onnx/operator_converters/gaussian_process.py b/skl2onnx/operator_converters/gaussian_process.py
--- a/skl2onnx/operator_converters/gaussian_process.py
+++ b/skl2onnx/operator_converters/gaussian_process.py
@@ -90,9 +90,22 @@ def convert_gaussian_process_regressor(scope, operator, container):
         mean_y = op._y_train_mean.astype(dtype)
         if len(mean_y.shape) == 1:
             mean_y = mean_y.reshape(mean_y.shape + (1,))
-        y_mean = OnnxAdd(y_mean_b, mean_y,
-                         output_names=out[:1],
-                         op_version=opv)
+
+        if not hasattr(op, '_y_train_std') or op._y_train_std == 1:
+            y_mean = OnnxAdd(y_mean_b, mean_y, output_names=out[:1],
+                             op_version=opv)
+        else:
+            # A bug was fixed in 0.23 and it changed
+            # the predictions when return_std is True.
+            # See https://github.com/scikit-learn/scikit-learn/pull/15782.
+            # y_mean = self._y_train_std * y_mean + self._y_train_mean
+            var_y = op._y_train_std.astype(dtype)
+            if len(var_y.shape) == 1:
+                var_y = var_y.reshape(var_y.shape + (1,))
+            y_mean = OnnxAdd(
+                OnnxMul(y_mean_b, var_y, op_version=opv),
+                mean_y, output_names=out[:1], op_version=opv)
+
         y_mean.set_onnx_name_prefix('gpr')
         outputs = [y_mean]
 
@@ -128,6 +141,10 @@ def convert_gaussian_process_regressor(scope, operator, container):
             ys0_var = OnnxMax(ys_var, np.array([0], dtype=dtype),
                               op_version=opv)
 
+            if hasattr(op, '_y_train_std') and op._y_train_std != 1:
+                # y_var = y_var * self._y_train_std**2
+                ys0_var = OnnxMul(ys0_var, var_y ** 2, op_version=opv)
+
             # var = np.sqrt(ys0_var)
             var = OnnxSqrt(ys0_var, output_names=out[1:], op_version=opv)
             var.set_onnx_name_prefix('gprv')


Test patch:
diff --git a/tests/test_sklearn_gaussian_process.py b/tests/test_sklearn_gaussian_process.py
--- a/tests/test_sklearn_gaussian_process.py
+++ b/tests/test_sklearn_gaussian_process.py
@@ -497,7 +497,8 @@ def test_gpr_rbf_fitted_return_std(self):
         self.assertTrue(model_onnx is not None)
         self.check_outputs(gp, model_onnx, Xtest_.astype(np.float32),
                            predict_attributes=options[
-                             GaussianProcessRegressor])
+                             GaussianProcessRegressor],
+                           decimal=4)
         dump_data_and_model(Xtest_.astype(np.float32), gp, model_onnx,
                             verbose=False,
                             basename="SklearnGaussianProcessRBFStd-Out0")
diff --git a/tests/test_sklearn_svm_converters.py b/tests/test_sklearn_svm_converters.py
--- a/tests/test_sklearn_svm_converters.py
+++ b/tests/test_sklearn_svm_converters.py
@@ -341,7 +341,7 @@ def test_convert_svc_multi_pfalse_4_break_ties(self):
             X.astype(numpy.float32),
             model,
             model_onnx,
-            basename="SklearnMcSVCPFBTF",
+            basename="SklearnMcSVCPFBTF-Dec4",
             allow_failure="StrictVersion(onnxruntime.__version__)"
                           " < StrictVersion('0.5.0')"
         )
diff --git a/tests/test_utils/tests_helper.py b/tests/test_utils/tests_helper.py
--- a/tests/test_utils/tests_helper.py
+++ b/tests/test_utils/tests_helper.py
@@ -269,8 +269,18 @@ def _raw_score_binary_classification(model, X):
                     lambda: model.decision_function(dataone))  # noqa
             elif _has_transform_model(model):
                 # clustering
-                prediction = [model.predict(data), model.transform(data)]
-                lambda_original = lambda: model.transform(dataone)  # noqa
+                try:
+                    prediction = [model.predict(data), model.transform(data)]
+                    lambda_original = lambda: model.transform(dataone)  # noqa
+                except ValueError as e:
+                    if 'Buffer dtype mismatch' in str(e):
+                        d64 = data.astype(numpy.float64)
+                        prediction = [model.predict(d64),
+                                      model.transform(d64)]
+                        dataone64 = dataone.astype(numpy.float64)
+                        lambda_original = lambda: model.transform(dataone64)  # noqa
+                    else:
+                        raise e
             else:
                 # Regressor or VotingClassifier
                 prediction = [model.predict(data)]