Repository: onnx/sklearn-onnx

Issue:
SVMClassifier trained with GridSearchCV is not correctly converted
Hi,
I trained a SVMClassifier model with GridSearchCV and then converted it into a ONNX, but the resulting model is not valid (nodes of the models' graph are not topologically sorted).
I guess it is an issue related to the conversion of GridSearchCV and so it would be probably independent from the type of classifier chosen.
A possible workaround is to pass to `to_onnx()` method the best classifier found by GridSearchCV insead of the object returned by GridSearchCV.

The script added in the follow can be used to reproduce the issue and the workaround described above.

Best regards,
Biagio.
```
import numpy as np
import onnx
from sklearn import svm
from sklearn.model_selection import GridSearchCV
from sklearn import datasets
from sklearn.model_selection import train_test_split
from skl2onnx.helpers.onnx_helper import load_onnx_model
from skl2onnx import to_onnx

rand_seed = 0
np.random.seed(rand_seed)

def convert_to_onnx(sklearn_model, X, model_savename):
    onnx_model_filename = model_savename + '.onnx'

    onnx_model = to_onnx(sklearn_model, X[:1].astype(np.float32))

    # Check the model
    try:
        onnx.checker.check_model(onnx_model)
    except onnx.checker.ValidationError as e:
        print('The model is NOT valid:\n%s' % e)
    else:
        print('The model is valid!')

        with open(onnx_model_filename, "wb") as f:
            f.write(onnx_model.SerializeToString())


def load_train_test():
    iris = datasets.load_iris()
    X = iris.data
    y = iris.target
    X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.8, random_state=rand_seed)
    return X_train, X_test, y_train, y_test


def train_svc_gs(X_train, y_train, apply_fix=False):
    param_grid = {
        'C': [0.1, 1, 1e1],
        'gamma': [1e-3, 1e-2, 1e-1]
    }

    clf_est = svm.SVC(kernel='rbf', coef0=0.0, degree=3,
                      decision_function_shape='ovr',
                      probability=True)
    
    if apply_fix:
        gs_clf = GridSearchCV(clf_est, param_grid)
        gs_clf.fit(X_train, y_train)
        clf = gs_clf.best_estimator_
    else:
        clf = GridSearchCV(clf_est, param_grid)
        clf.fit(X_train, y_train)

    return clf

def train_svc(X_train, y_train):
    clf = svm.SVC(kernel='rbf', coef0=0.0, C=10,
                  gamma=3e-2, degree=3,
                  decision_function_shape='ovr',
                  probability=True)
    
    clf.fit(X_train, y_train)

    return clf


def run(test_gs=True, apply_fix=False):
    # Load train and test dataset
    X_train, X_test, y_train, y_test = load_train_test()

    assert apply_fix in [True, False], "Invalid value for apply_fix"
    assert test_gs in [True, False], "Invalid value for test_gs"

    if test_gs:
        clf = train_svc_gs(X_train, y_train, apply_fix)
    else:
        clf = train_svc(X_train, y_train)

    if test_gs:
        if apply_fix:
            onnx_model_name = "svc_gs_valid"
        else:
            onnx_model_name = "svc_gs_not_valid"
    else:
        onnx_model_name = "svc"
    
    convert_to_onnx(clf, X_test, onnx_model_name)


if __name__ == "__main__":
    print("SVC model trained with GridSearchCV (without workaround):")
    run(test_gs=True, apply_fix=False)
    print("\nSVC model trained with GridSearchCV (with workaround):")
    run(test_gs=True, apply_fix=True)
    print("\nSVC model trained without GridSearchCV:")
    run(test_gs=False)
```


Discussion:

Resolving patch:
diff --git a/docs/tutorial/plot_cbegin_opset.py b/docs/tutorial/plot_cbegin_opset.py
--- a/docs/tutorial/plot_cbegin_opset.py
+++ b/docs/tutorial/plot_cbegin_opset.py
@@ -45,7 +45,7 @@
 
 X, y = make_blobs(n_samples=100, n_features=2)
 
-model = IsolationForest(3)
+model = IsolationForest(n_estimators=3)
 model.fit(X)
 labels = model.predict(X)
 
diff --git a/skl2onnx/common/_container.py b/skl2onnx/common/_container.py
--- a/skl2onnx/common/_container.py
+++ b/skl2onnx/common/_container.py
@@ -684,3 +684,74 @@ def has_options(self, model, option_name):
         """
         opts = self._get_allowed_options(model)
         return option_name in opts
+
+    def ensure_topological_order(self):
+        """
+        Ensures and modifies the order of nodes to have
+        a topological order (every node in the list
+        can only be an input for a node later in this list).
+        The function raises an exception if a cycle is detected.
+        """
+        order = {}
+        for inp in self.inputs:
+            name = inp.name
+            order[name] = 0
+        for inp in self.initializers:
+            name = inp.name
+            order[name] = 0
+        n_iter = 0
+        while n_iter < len(self.nodes) * 2:
+            n_iter += 1
+            missing_names = set()
+            missing_ops = []
+            for node in self.nodes:
+                maxi = 0
+                for name in node.input:
+                    if name in order:
+                        maxi = max(maxi, order[name])
+                    else:
+                        maxi = None
+                        missing_names.add(name)
+                        break
+                if maxi is None:
+                    missing_ops.append(node)
+                    continue
+                key = id(node)
+                if key in order:
+                    continue
+                maxi += 1
+                order[key] = maxi
+                maxi += 1
+                for name in node.output:
+                    if name in order:
+                        raise RuntimeError(
+                            "Unable to sort a node (cycle). An output was "
+                            "already ordered %r (iteration=%r)." % (
+                                name, n_iter))
+                    order[name] = maxi
+            if len(missing_names) == 0:
+                continue
+
+        if len(missing_ops) > 0:
+            def nstr(name):
+                if name in order:
+                    return "%s(%d)" % (name, order[name])
+                return name
+            rows = ["%s (%s) -> (%s)" % (
+                        n.name or n.op_type,
+                        ', '.join(map(nstr, n.input)),
+                        ', '.join(n.output))
+                    for n in missing_ops]
+            rows.insert(0, "")
+            raise RuntimeError(
+                "After %d iterations for %d nodes, still unable "
+                "to sort names %r. The graph may be disconnected. "
+                "List of operators: %s" % (
+                    n_iter, len(self.nodes), missing_names,
+                    "\n".join(rows)))
+
+        # Update order
+        topo = [(order[id(node)], str(id(node))) for node in self.nodes]
+        topo.sort()
+        map_nodes = {str(id(node)): node for node in self.nodes}
+        self.nodes = [map_nodes[_[1]] for _ in topo]
diff --git a/skl2onnx/common/_topology.py b/skl2onnx/common/_topology.py
--- a/skl2onnx/common/_topology.py
+++ b/skl2onnx/common/_topology.py
@@ -74,6 +74,17 @@ def __init__(self, raw_name, onnx_name, scope, type=None):
         if not isinstance(onnx_name, str) or '(' in onnx_name:
             raise TypeError(
                 "raw_name must be a string not %r." % type(onnx_name))
+
+        if type is not None:
+            shape = type.shape
+            if shape is not None:
+                not_none = [v for v in shape if v is not None]
+                if len(not_none) and min(not_none) == 0:
+                    raise RuntimeError(
+                        "A variable cannot be empty, raw_name=%r, "
+                        "onnx_name=%r, type=%r." % (
+                            raw_name, onnx_name, type))
+
         self.raw_name = raw_name  #
         self.onnx_name = onnx_name  #
         self.scope = scope
@@ -128,8 +139,15 @@ def from_pb(obj):
         """
         Creates a data type from a protobuf object.
         """
+        def get_dim(d):
+            r = d.dim_value
+            if r == 0:
+                # dim_value is 0 when it is 0 or undefined
+                return 0 if "0" in str(d) else None
+            return r
+
         def get_shape(tt):
-            return [tt.shape.dim[i].dim_value
+            return [get_dim(tt.shape.dim[i])
                     for i in range(len(tt.shape.dim))]
 
         if hasattr(obj, 'extend'):
@@ -1161,6 +1179,8 @@ def convert_topology(topology, model_name, doc_string, target_opset,
         container.validate_options(operator)
         conv(scope, operator, container)
 
+    container.ensure_topological_order()
+
     # Create a graph from its main components
     if container.target_opset_onnx < 9:
         # When calling ModelComponentContainer's add_initializer(...),


Test patch:
diff --git a/tests/test_sklearn_grid_search_cv_converter.py b/tests/test_sklearn_grid_search_cv_converter.py
--- a/tests/test_sklearn_grid_search_cv_converter.py
+++ b/tests/test_sklearn_grid_search_cv_converter.py
@@ -4,21 +4,21 @@
 from distutils.version import StrictVersion
 import unittest
 import numpy as np
+import onnx
 from onnxruntime import __version__ as ort_version
 from sklearn.gaussian_process import GaussianProcessRegressor
 from sklearn.linear_model import Lasso, LassoLars, LogisticRegression
 from sklearn.model_selection import GridSearchCV
 from sklearn.svm import SVC
-from skl2onnx import convert_sklearn
-from skl2onnx.common.data_types import DoubleTensorType
-from skl2onnx.common.data_types import FloatTensorType, Int64TensorType
+from sklearn.model_selection import train_test_split
+from sklearn.datasets import load_iris
+from skl2onnx import convert_sklearn, to_onnx
+from skl2onnx.common.data_types import (
+    DoubleTensorType, FloatTensorType, Int64TensorType)
 from skl2onnx.common.data_types import onnx_built_with_ml
 from test_utils import (
-    dump_data_and_model,
-    fit_classification_model,
-    fit_regression_model,
-    TARGET_OPSET
-)
+    dump_data_and_model, fit_classification_model,
+    fit_regression_model, TARGET_OPSET)
 
 
 class TestSklearnGridSearchCVModels(unittest.TestCase):
@@ -34,18 +34,11 @@ def test_grid_search_binary_float(self):
         model_onnx = convert_sklearn(
             model, "GridSearchCV",
             [("input", FloatTensorType([None, X.shape[1]]))],
-            target_opset=TARGET_OPSET
-        )
+            target_opset=TARGET_OPSET)
         self.assertIsNotNone(model_onnx)
         dump_data_and_model(
-            X,
-            model,
-            model_onnx,
-            basename="SklearnGridSearchBinaryFloat-Dec4",
-            allow_failure="StrictVersion("
-            "onnxruntime.__version__)"
-            "<= StrictVersion('0.2.1')",
-        )
+            X, model, model_onnx,
+            basename="SklearnGridSearchBinaryFloat-Dec4")
 
     @unittest.skipIf(not onnx_built_with_ml(),
                      reason="Requires ONNX-ML extension.")
@@ -58,18 +51,11 @@ def test_grid_search_multiclass_float(self):
         model_onnx = convert_sklearn(
             model, "GridSearchCV",
             [("input", FloatTensorType([None, X.shape[1]]))],
-            target_opset=TARGET_OPSET
-        )
+            target_opset=TARGET_OPSET)
         self.assertIsNotNone(model_onnx)
         dump_data_and_model(
-            X,
-            model,
-            model_onnx,
-            basename="SklearnGridSearchMulticlassFloat",
-            allow_failure="StrictVersion("
-            "onnxruntime.__version__)"
-            "<= StrictVersion('0.2.1')",
-        )
+            X, model, model_onnx,
+            basename="SklearnGridSearchMulticlassFloat")
 
     @unittest.skipIf(not onnx_built_with_ml(),
                      reason="Requires ONNX-ML extension.")
@@ -83,18 +69,11 @@ def test_grid_search_binary_int(self):
         model_onnx = convert_sklearn(
             model, "GridSearchCV",
             [("input", Int64TensorType([None, X.shape[1]]))],
-            target_opset=TARGET_OPSET
-        )
+            target_opset=TARGET_OPSET)
         self.assertIsNotNone(model_onnx)
         dump_data_and_model(
-            X,
-            model,
-            model_onnx,
-            basename="SklearnGridSearchBinaryInt-Dec4",
-            allow_failure="StrictVersion("
-            "onnxruntime.__version__)"
-            "<= StrictVersion('0.2.1')",
-        )
+            X, model, model_onnx,
+            basename="SklearnGridSearchBinaryInt-Dec4")
 
     @unittest.skipIf(not onnx_built_with_ml(),
                      reason="Requires ONNX-ML extension.")
@@ -108,18 +87,11 @@ def test_grid_search_multiclass_int(self):
         model_onnx = convert_sklearn(
             model, "GridSearchCV",
             [("input", Int64TensorType([None, X.shape[1]]))],
-            target_opset=TARGET_OPSET
-        )
+            target_opset=TARGET_OPSET)
         self.assertIsNotNone(model_onnx)
         dump_data_and_model(
-            X,
-            model,
-            model_onnx,
-            basename="SklearnGridSearchMulticlassInt-Dec4",
-            allow_failure="StrictVersion("
-            "onnxruntime.__version__)"
-            "<= StrictVersion('0.2.1')",
-        )
+            X, model, model_onnx,
+            basename="SklearnGridSearchMulticlassInt-Dec4")
 
     def test_grid_search_regression_int(self):
         tuned_parameters = [{'alpha': np.logspace(-4, -0.5, 4)}]
@@ -132,16 +104,8 @@ def test_grid_search_regression_int(self):
             target_opset=TARGET_OPSET)
         self.assertIsNotNone(model_onnx)
         dump_data_and_model(
-            X,
-            model,
-            model_onnx,
-            basename="SklearnGridSerachRegressionInt-OneOffArray-Dec4",
-            allow_failure="StrictVersion("
-            "onnxruntime.__version__) "
-            "<= StrictVersion('0.2.1') or "
-            "StrictVersion(onnx.__version__) "
-            "== StrictVersion('1.4.1')",
-        )
+            X, model, model_onnx,
+            basename="SklearnGridSerachRegressionInt-OneOffArray-Dec4")
 
     def test_grid_search_regressor_float(self):
         tuned_parameters = [{'alpha': np.logspace(-4, -0.5, 4)}]
@@ -154,16 +118,8 @@ def test_grid_search_regressor_float(self):
             target_opset=TARGET_OPSET)
         self.assertIsNotNone(model_onnx)
         dump_data_and_model(
-            X,
-            model,
-            model_onnx,
-            basename="SklearnGridSearchRegressionFloat-OneOffArray-Dec4",
-            allow_failure="StrictVersion("
-            "onnxruntime.__version__) "
-            "<= StrictVersion('0.2.1') or "
-            "StrictVersion(onnx.__version__) "
-            "== StrictVersion('1.4.1')",
-        )
+            X, model, model_onnx,
+            basename="SklearnGridSearchRegressionFloat-OneOffArray-Dec4")
 
     @unittest.skipIf(
         StrictVersion(ort_version) <= StrictVersion('0.4.0'),
@@ -179,17 +135,9 @@ def test_grid_search_gaussian_regressor_float(self):
             target_opset=TARGET_OPSET)
         self.assertIsNotNone(model_onnx)
         dump_data_and_model(
-            X,
-            model,
-            model_onnx,
+            X, model, model_onnx,
             basename="SklearnGridSearchGaussianRegressionFloat"
-                     "-OneOffArray-Dec4",
-            allow_failure="StrictVersion("
-            "onnxruntime.__version__) "
-            "<= StrictVersion('0.4.0') or "
-            "StrictVersion(onnx.__version__) "
-            "== StrictVersion('1.4.1')",
-        )
+                     "-OneOffArray-Dec4")
 
     @unittest.skipIf(
         StrictVersion(ort_version) <= StrictVersion('0.4.0'),
@@ -205,17 +153,9 @@ def test_grid_search_gaussian_regressor_double(self):
             target_opset=TARGET_OPSET)
         self.assertIsNotNone(model_onnx)
         dump_data_and_model(
-            X.astype(np.float64),
-            model,
-            model_onnx,
+            X.astype(np.float64), model, model_onnx,
             basename="SklearnGridSearchGaussianRegressionDouble"
-                     "-OneOffArray-Dec4",
-            allow_failure="StrictVersion("
-            "onnxruntime.__version__) "
-            "<= StrictVersion('0.4.0') or "
-            "StrictVersion(onnx.__version__) "
-            "== StrictVersion('1.4.1')",
-        )
+                     "-OneOffArray-Dec4")
 
     @unittest.skipIf(not onnx_built_with_ml(),
                      reason="Requires ONNX-ML extension.")
@@ -230,21 +170,55 @@ def test_grid_search_binary_float_nozipmap(self):
             model, "GridSearchCV",
             [("input", FloatTensorType([None, X.shape[1]]))],
             options={id(clf): {'zipmap': False, 'raw_scores': True}},
-            target_opset=TARGET_OPSET
-        )
+            target_opset=TARGET_OPSET)
         self.assertIsNotNone(model_onnx)
         assert "zipmap" not in str(model_onnx).lower()
         assert '"LOGISTIC"' not in str(model_onnx).lower()
         dump_data_and_model(
-            X,
-            model,
-            model_onnx,
+            X, model, model_onnx,
             basename="SklearnGridSearchBinaryFloat-Out0",
-            allow_failure="StrictVersion("
-            "onnxruntime.__version__)"
-            "<= StrictVersion('0.2.1')",
-            methods=['predict', 'decision_function']
-        )
+            methods=['predict', 'decision_function'])
+
+    @unittest.skipIf(not onnx_built_with_ml(),
+                     reason="Requires ONNX-ML extension.")
+    def test_grid_search_svm(self):
+        rand_seed = 0
+        np.random.seed(rand_seed)
+
+        def convert_to_onnx(sklearn_model, X, model_savename):
+            onnx_model = to_onnx(sklearn_model, X[:1].astype(np.float32),
+                                 target_opset=TARGET_OPSET)
+            onnx.checker.check_model(onnx_model)
+            return onnx_model
+
+        def load_train_test():
+            iris = load_iris()
+            X = iris.data
+            y = iris.target
+            X_train, X_test, y_train, y_test = train_test_split(
+                X, y, train_size=0.8, random_state=rand_seed)
+            return X_train, X_test, y_train, y_test
+
+        def train_svc_gs(X_train, y_train, apply_fix=False):
+            param_grid = {'C': [0.1, 1, 1e1], 'gamma': [1e-3, 1e-2, 1e-1]}
+            clf_est = SVC(kernel='rbf', coef0=0.0, degree=3,
+                          decision_function_shape='ovr',
+                          probability=True)
+            clf = GridSearchCV(clf_est, param_grid)
+            clf.fit(X_train, y_train)
+            return clf
+
+        def run():
+            # Load train and test dataset
+            X_train, X_test, y_train, y_test = load_train_test()
+            clf = train_svc_gs(X_train, y_train)
+            onnx_model_name = "svc_gs_not_valid"
+            return X_test, clf, convert_to_onnx(clf, X_test, onnx_model_name)
+
+        x_test, model, model_onnx = run()
+        dump_data_and_model(
+            x_test.astype(np.float32), model, model_onnx,
+            basename="SklearnGridSearchSVC-Out0")
 
 
 if __name__ == "__main__":
diff --git a/tests/test_sklearn_nearest_neighbour_converter.py b/tests/test_sklearn_nearest_neighbour_converter.py
--- a/tests/test_sklearn_nearest_neighbour_converter.py
+++ b/tests/test_sklearn_nearest_neighbour_converter.py
@@ -14,19 +14,22 @@
 import onnxruntime
 from onnxruntime import InferenceSession
 from pandas import DataFrame
+try:
+    from sklearn.utils._testing import ignore_warnings
+except ImportError:
+    # older versions of scikit-learn
+    from sklearn.utils.testing import ignore_warnings
 from sklearn import datasets
 from sklearn.model_selection import train_test_split
 from sklearn.neighbors import (
     KNeighborsRegressor, RadiusNeighborsRegressor,
     KNeighborsClassifier, RadiusNeighborsClassifier,
-    NearestNeighbors,
-)
+    NearestNeighbors)
 try:
     from sklearn.impute import KNNImputer
     from sklearn.neighbors import (
         KNeighborsTransformer,
-        NeighborhoodComponentsAnalysis,
-    )
+        NeighborhoodComponentsAnalysis)
 except ImportError:
     # New in 0.22
     KNNImputer = None
@@ -110,6 +113,7 @@ def _fit_model_simple(self, model, n_targets=1, label_int=False,
     @unittest.skipIf(
         StrictVersion(onnxruntime.__version__) < StrictVersion("0.5.0"),
         reason="not available")
+    @ignore_warnings(category=DeprecationWarning)
     def test_model_knn_regressor(self):
         model, X = self._fit_model(KNeighborsRegressor(n_neighbors=2))
         model_onnx = convert_sklearn(model, "KNN regressor",
@@ -126,6 +130,10 @@ def test_model_knn_regressor(self):
             basename="SklearnKNeighborsRegressor-Dec4")
 
     @unittest.skipIf(dont_test_radius(), reason="not available")
+    @unittest.skipIf(
+        StrictVersion(onnxruntime.__version__) < StrictVersion("1.8.0"),
+        reason="produces nan values")
+    @ignore_warnings(category=DeprecationWarning)
     def test_model_knn_regressor_radius(self):
         model, X = self._fit_model(RadiusNeighborsRegressor())
         model_onnx = convert_sklearn(model, "KNN regressor",
@@ -133,6 +141,7 @@ def test_model_knn_regressor_radius(self):
                                      target_opset=TARGET_OPSET,
                                      options={id(model): {'optim': 'cdist'}})
         sess = InferenceSession(model_onnx.SerializeToString())
+        X = X[:5]
         got = sess.run(None, {'input': X.astype(numpy.float32)})[0]
         exp = model.predict(X.astype(numpy.float32))
         if any(numpy.isnan(got.ravel())):
@@ -160,6 +169,7 @@ def test_model_knn_regressor_radius(self):
     @unittest.skipIf(
         StrictVersion(onnx.__version__) < StrictVersion("1.6.0"),
         reason="not available")
+    @ignore_warnings(category=DeprecationWarning)
     def test_model_knn_regressor_double(self):
         model, X = self._fit_model(KNeighborsRegressor(n_neighbors=2))
         model_onnx = convert_sklearn(
@@ -182,6 +192,7 @@ def test_model_knn_regressor_double(self):
             basename="SklearnKNeighborsRegressor64")
 
     @unittest.skipIf(dont_test_radius(), reason="not available")
+    @ignore_warnings(category=DeprecationWarning)
     def test_model_knn_regressor_double_radius(self):
         model, X = self._fit_model(RadiusNeighborsRegressor())
         model_onnx = convert_sklearn(
@@ -202,6 +213,7 @@ def test_model_knn_regressor_double_radius(self):
     @unittest.skipIf(
         StrictVersion(onnxruntime.__version__) < StrictVersion("0.5.0"),
         reason="not available")
+    @ignore_warnings(category=DeprecationWarning)
     def test_model_knn_regressor_yint(self):
         model, X = self._fit_model(
             KNeighborsRegressor(n_neighbors=2), label_int=True)
@@ -215,6 +227,7 @@ def test_model_knn_regressor_yint(self):
             basename="SklearnKNeighborsRegressorYInt")
 
     @unittest.skipIf(dont_test_radius(), reason="not available")
+    @ignore_warnings(category=DeprecationWarning)
     def test_model_knn_regressor_yint_radius(self):
         model, X = self._fit_model(
             RadiusNeighborsRegressor(), label_int=True)
@@ -230,6 +243,7 @@ def test_model_knn_regressor_yint_radius(self):
     @unittest.skipIf(
         StrictVersion(onnxruntime.__version__) < StrictVersion("0.5.0"),
         reason="not available")
+    @ignore_warnings(category=DeprecationWarning)
     def test_model_knn_regressor2_1(self):
         model, X = self._fit_model(KNeighborsRegressor(n_neighbors=1),
                                    n_targets=2)
@@ -243,6 +257,7 @@ def test_model_knn_regressor2_1(self):
             basename="SklearnKNeighborsRegressor2")
 
     @unittest.skipIf(dont_test_radius(), reason="not available")
+    @ignore_warnings(category=DeprecationWarning)
     def test_model_knn_regressor2_1_radius(self):
         model, X = self._fit_model_simple(
             RadiusNeighborsRegressor(algorithm="brute"),
@@ -297,6 +312,7 @@ def test_model_knn_regressor2_1_radius(self):
     @unittest.skipIf(
         StrictVersion(onnx.__version__) < StrictVersion("1.4.0"),
         reason="not available")
+    @ignore_warnings(category=DeprecationWarning)
     def test_model_knn_regressor2_1_opset(self):
         model, X = self._fit_model(KNeighborsRegressor(n_neighbors=1),
                                    n_targets=2)
@@ -317,6 +333,7 @@ def test_model_knn_regressor2_1_opset(self):
     @unittest.skipIf(
         StrictVersion(onnxruntime.__version__) < StrictVersion("0.5.0"),
         reason="not available")
+    @ignore_warnings(category=DeprecationWarning)
     def test_model_knn_regressor2_2(self):
         model, X = self._fit_model(KNeighborsRegressor(n_neighbors=2),
                                    n_targets=2)
@@ -334,6 +351,7 @@ def test_model_knn_regressor2_2(self):
         reason="not available")
     @unittest.skipIf(TARGET_OPSET < 9,
                      reason="needs higher target_opset")
+    @ignore_warnings(category=DeprecationWarning)
     def test_model_knn_regressor_weights_distance_11(self):
         model, X = self._fit_model(
             KNeighborsRegressor(
@@ -365,6 +383,7 @@ def test_model_knn_regressor_weights_distance_11(self):
                     basename="SklearnKNeighborsRegressorWDist%d-Dec3" % op)
 
     @unittest.skipIf(dont_test_radius(), reason="not available")
+    @ignore_warnings(category=DeprecationWarning)
     def test_model_knn_regressor_weights_distance_11_radius(self):
         model, X = self._fit_model_simple(
             RadiusNeighborsRegressor(
@@ -386,6 +405,7 @@ def test_model_knn_regressor_weights_distance_11_radius(self):
     @unittest.skipIf(
         StrictVersion(onnxruntime.__version__) < StrictVersion("0.5.0"),
         reason="not available")
+    @ignore_warnings(category=DeprecationWarning)
     def test_model_knn_regressor_metric_cityblock(self):
         model, X = self._fit_model(KNeighborsRegressor(metric="cityblock"))
         model_onnx = convert_sklearn(model, "KNN regressor",
@@ -404,6 +424,7 @@ def test_model_knn_regressor_metric_cityblock(self):
         reason="not available")
     @unittest.skipIf(TARGET_OPSET < TARGET_OPSET,
                      reason="needs higher target_opset")
+    @ignore_warnings(category=DeprecationWarning)
     def test_model_knn_classifier_binary_class(self):
         model, X = self._fit_model_binary_classification(
             KNeighborsClassifier())
@@ -422,6 +443,7 @@ def test_model_knn_classifier_binary_class(self):
     @unittest.skipIf(dont_test_radius(), reason="not available")
     @unittest.skipIf(TARGET_OPSET < 12,
                      reason="needs higher target_opset")
+    @ignore_warnings(category=DeprecationWarning)
     def test_model_knn_classifier_binary_class_radius(self):
         model, X = self._fit_model_binary_classification(
             RadiusNeighborsClassifier())
@@ -440,6 +462,7 @@ def test_model_knn_classifier_binary_class_radius(self):
     @unittest.skipIf(
         StrictVersion(onnxruntime.__version__) < StrictVersion("0.5.0"),
         reason="not available")
+    @ignore_warnings(category=DeprecationWarning)
     def test_model_knn_classifier_multi_class(self):
         model, X = self._fit_model_multiclass_classification(
             KNeighborsClassifier())
@@ -458,6 +481,7 @@ def test_model_knn_classifier_multi_class(self):
     @unittest.skipIf(dont_test_radius(), reason="not available")
     @unittest.skipIf(TARGET_OPSET < 12,
                      reason="needs higher target_opset")
+    @ignore_warnings(category=DeprecationWarning)
     def test_model_knn_classifier_multi_class_radius(self):
         model, X = self._fit_model_multiclass_classification(
             RadiusNeighborsClassifier())
@@ -477,6 +501,7 @@ def test_model_knn_classifier_multi_class_radius(self):
     @unittest.skipIf(
         StrictVersion(onnxruntime.__version__) < StrictVersion("0.5.0"),
         reason="not available")
+    @ignore_warnings(category=DeprecationWarning)
     def test_model_knn_classifier_multi_class_string(self):
         model, X = self._fit_model_multiclass_classification(
             KNeighborsClassifier(), use_string=True)
@@ -495,6 +520,7 @@ def test_model_knn_classifier_multi_class_string(self):
     @unittest.skipIf(
         StrictVersion(onnxruntime.__version__) < StrictVersion("0.5.0"),
         reason="not available")
+    @ignore_warnings(category=DeprecationWarning)
     def test_model_knn_classifier_weights_distance(self):
         model, X = self._fit_model_multiclass_classification(
             KNeighborsClassifier(weights='distance'))
@@ -509,6 +535,7 @@ def test_model_knn_classifier_weights_distance(self):
     @unittest.skipIf(
         StrictVersion(onnxruntime.__version__) < StrictVersion("0.5.0"),
         reason="not available")
+    @ignore_warnings(category=DeprecationWarning)
     def test_model_knn_classifier_metric_cityblock(self):
         model, X = self._fit_model_multiclass_classification(
             KNeighborsClassifier(metric='cityblock'))
@@ -523,6 +550,7 @@ def test_model_knn_classifier_metric_cityblock(self):
     @unittest.skipIf(
         StrictVersion(onnxruntime.__version__) < StrictVersion("0.5.0"),
         reason="not available")
+    @ignore_warnings(category=DeprecationWarning)
     def test_model_knn_classifier_multilabel(self):
         model, X_test = fit_multilabel_classification_model(
             KNeighborsClassifier(), n_classes=7, n_labels=3,
@@ -549,6 +577,7 @@ def test_model_knn_classifier_multilabel(self):
     @unittest.skipIf(
         StrictVersion(onnxruntime.__version__) < StrictVersion("0.5.0"),
         reason="not available")
+    @ignore_warnings(category=DeprecationWarning)
     def test_model_knn_regressor_int(self):
         model, X = self._fit_model(KNeighborsRegressor())
         X = X.astype(numpy.int64)
@@ -568,6 +597,7 @@ def test_model_knn_regressor_int(self):
     @unittest.skipIf(
         StrictVersion(onnxruntime.__version__) < StrictVersion("0.5.0"),
         reason="not available")
+    @ignore_warnings(category=DeprecationWarning)
     def test_model_knn_regressor_equal(self):
         X, y = datasets.make_regression(
             n_samples=1000, n_features=100, random_state=42)
@@ -601,6 +631,7 @@ def test_model_knn_regressor_equal(self):
     @unittest.skipIf(
         StrictVersion(onnxruntime.__version__) < StrictVersion("0.5.0"),
         reason="not available")
+    @ignore_warnings(category=DeprecationWarning)
     def test_model_knn_multi_class_nocl(self):
         model, X = fit_classification_model(
             KNeighborsClassifier(),
@@ -625,6 +656,7 @@ def test_model_knn_multi_class_nocl(self):
     @unittest.skipIf(
         StrictVersion(onnxruntime.__version__) < StrictVersion("0.5.0"),
         reason="not available")
+    @ignore_warnings(category=DeprecationWarning)
     def test_model_knn_regressor2_2_pipee(self):
         pipe = make_pipeline(StandardScaler(),
                              KNeighborsClassifier())
@@ -642,6 +674,7 @@ def test_model_knn_regressor2_2_pipee(self):
     @unittest.skipIf(
         StrictVersion(onnxruntime.__version__) < StrictVersion("0.5.0"),
         reason="not available")
+    @ignore_warnings(category=DeprecationWarning)
     def test_onnx_test_knn_transform(self):
         iris = datasets.load_iris()
         X, _ = iris.data, iris.target
@@ -666,6 +699,7 @@ def test_onnx_test_knn_transform(self):
 
     @unittest.skipIf(NeighborhoodComponentsAnalysis is None,
                      reason="new in 0.22")
+    @ignore_warnings(category=DeprecationWarning)
     def test_sklearn_nca_default(self):
         model, X_test = fit_classification_model(
             NeighborhoodComponentsAnalysis(random_state=42), 3)
@@ -684,6 +718,7 @@ def test_sklearn_nca_default(self):
 
     @unittest.skipIf(NeighborhoodComponentsAnalysis is None,
                      reason="new in 0.22")
+    @ignore_warnings(category=DeprecationWarning)
     def test_sklearn_nca_identity(self):
         model, X_test = fit_classification_model(
             NeighborhoodComponentsAnalysis(
@@ -703,6 +738,7 @@ def test_sklearn_nca_identity(self):
 
     @unittest.skipIf(NeighborhoodComponentsAnalysis is None,
                      reason="new in 0.22")
+    @ignore_warnings(category=DeprecationWarning)
     def test_sklearn_nca_double(self):
         model, X_test = fit_classification_model(
             NeighborhoodComponentsAnalysis(
@@ -723,6 +759,7 @@ def test_sklearn_nca_double(self):
 
     @unittest.skipIf(NeighborhoodComponentsAnalysis is None,
                      reason="new in 0.22")
+    @ignore_warnings(category=DeprecationWarning)
     def test_sklearn_nca_int(self):
         model, X_test = fit_classification_model(
             NeighborhoodComponentsAnalysis(
@@ -742,6 +779,7 @@ def test_sklearn_nca_int(self):
 
     @unittest.skipIf(KNeighborsTransformer is None,
                      reason="new in 0.22")
+    @ignore_warnings(category=DeprecationWarning)
     def test_sklearn_k_neighbours_transformer_distance(self):
         model, X_test = fit_classification_model(
             KNeighborsTransformer(
@@ -761,6 +799,7 @@ def test_sklearn_k_neighbours_transformer_distance(self):
 
     @unittest.skipIf(KNeighborsTransformer is None,
                      reason="new in 0.22")
+    @ignore_warnings(category=DeprecationWarning)
     def test_sklearn_k_neighbours_transformer_connectivity(self):
         model, X_test = fit_classification_model(
             KNeighborsTransformer(
@@ -783,6 +822,7 @@ def test_sklearn_k_neighbours_transformer_connectivity(self):
     @unittest.skipIf((StrictVersion(onnx.__version__) <
                       StrictVersion("1.4.1")),
                      reason="ConstantOfShape op not available")
+    @ignore_warnings(category=DeprecationWarning)
     def test_sklearn_knn_imputer(self):
         x_train = numpy.array(
             [[1, 2, numpy.nan, 12], [3, numpy.nan, 3, 13],
@@ -808,6 +848,7 @@ def test_sklearn_knn_imputer(self):
     @unittest.skipIf((StrictVersion(onnx.__version__) <
                       StrictVersion("1.4.1")),
                      reason="ConstantOfShape op not available")
+    @ignore_warnings(category=DeprecationWarning)
     def test_sklearn_knn_imputer_cdist(self):
         x_train = numpy.array(
             [[1, 2, numpy.nan, 12], [3, numpy.nan, 3, 13],
@@ -846,6 +887,7 @@ def test_sklearn_knn_imputer_cdist(self):
         reason="not available")
     @unittest.skipIf(TARGET_OPSET < 11,
                      reason="needs higher target_opset")
+    @ignore_warnings(category=DeprecationWarning)
     def test_model_knn_iris_regressor_multi_reg(self):
         iris = datasets.load_iris()
         X = iris.data.astype(numpy.float32)
@@ -863,6 +905,7 @@ def test_model_knn_iris_regressor_multi_reg(self):
             basename="SklearnKNeighborsRegressorMReg")
 
     @unittest.skipIf(dont_test_radius(), reason="not available")
+    @ignore_warnings(category=DeprecationWarning)
     def test_model_knn_iris_regressor_multi_reg_radius(self):
         iris = datasets.load_iris()
         X = iris.data.astype(numpy.float32)
@@ -890,6 +933,7 @@ def test_model_knn_iris_regressor_multi_reg_radius(self):
         reason="not available")
     @unittest.skipIf(TARGET_OPSET < 11,
                      reason="needs higher target_opset")
+    @ignore_warnings(category=DeprecationWarning)
     def test_model_knn_iris_classifier_multi_reg2_weight(self):
         iris = datasets.load_iris()
         X = iris.data.astype(numpy.float32)
@@ -908,6 +952,7 @@ def test_model_knn_iris_classifier_multi_reg2_weight(self):
             basename="SklearnKNeighborsClassifierMReg2-Out0")
 
     @unittest.skipIf(dont_test_radius(), reason="not available")
+    @ignore_warnings(category=DeprecationWarning)
     def test_model_knn_iris_classifier_multi_reg2_weight_radius(self):
         iris = datasets.load_iris()
         X = iris.data.astype(numpy.float32)
@@ -932,6 +977,7 @@ def test_model_knn_iris_classifier_multi_reg2_weight_radius(self):
         reason="not available")
     @unittest.skipIf(TARGET_OPSET < 11,
                      reason="needs higher target_opset")
+    @ignore_warnings(category=DeprecationWarning)
     def test_model_knn_iris_classifier_multi_reg3_weight(self):
         iris = datasets.load_iris()
         X = iris.data.astype(numpy.float32)
diff --git a/tests/test_topology_prune.py b/tests/test_topology_prune.py
--- a/tests/test_topology_prune.py
+++ b/tests/test_topology_prune.py
@@ -34,7 +34,7 @@ def __init__(self):
 
 def dummy_shape_calculator(operator):
     op_input = operator.inputs[0]
-    operator.outputs[0].type = FloatTensorType(op_input.type.shape)
+    operator.outputs[0].type.shape = op_input.type.shape
 
 
 def dummy_converter(scope, operator, container):
@@ -42,7 +42,7 @@ def dummy_converter(scope, operator, container):
     out = operator.outputs
 
     id1 = OnnxIdentity(X, op_version=TARGET_OPSET)
-    id2 = OnnxIdentity(id1, output_names=out[1:],
+    id2 = OnnxIdentity(id1, output_names=out[:1],
                        op_version=TARGET_OPSET)
     id2.add_to(scope, container)
 
@@ -71,7 +71,7 @@ def test_dummy_identity(self):
 
         idnode = [node for node in model_onnx.graph.node
                   if node.op_type == "Identity"]
-        assert len(idnode) == 0
+        self.assertEqual(len(idnode), 1)
 
 
 if __name__ == "__main__":