Coverage for mlprodict/onnx_conv/scorers/cdist_score.py: 100%
37 statements
« prev ^ index » next coverage.py v7.1.0, created at 2023-02-04 02:28 +0100
« prev ^ index » next coverage.py v7.1.0, created at 2023-02-04 02:28 +0100
1"""
2@file
3@brief Implementation of a dummy score using
4:epkg:`cdist`.
5"""
6import numpy
7from onnx import onnx_pb as onnx_proto
8from scipy.spatial.distance import cdist
11def score_cdist_sum(expected_values, predictions,
12 metric='sqeuclidean', p=None):
13 """
14 Computes the sum of pairwise distances between
15 *expected_values* and *predictions*. It has no
16 particular purpose except the one of converting
17 a scorer into ONNX.
19 @param expected_values expected_values
20 @param predictions predictions
21 @param metric see function :epkg:`cdist`
22 @param p see function :epkg:`cdist`
23 @return some of the pairwise distances
24 """
25 if p is None:
26 dist = cdist(expected_values, predictions, metric=metric)
27 else:
28 dist = cdist(expected_values, predictions, metric=metric, p=p)
29 return numpy.sum(dist, axis=1)
32def convert_score_cdist_sum(scope, operator, container):
33 """
34 Converts function @see fn score_cdist_sum into :epkg:`ONNX`.
35 """
36 op = operator.raw_operator
37 if op._fct != score_cdist_sum: # pylint: disable=W0143
38 raise RuntimeError( # pragma: no cover
39 f"The wrong converter was called {op._fct} != {score_cdist_sum}.")
41 from skl2onnx.algebra.complex_functions import onnx_cdist
42 from skl2onnx.algebra.onnx_ops import OnnxReduceSumApi11 # pylint: disable=E0611
43 from skl2onnx.common.data_types import guess_numpy_type
45 X = operator.inputs[0]
46 Y = operator.inputs[1]
47 out = operator.outputs
48 opv = container.target_opset
49 dtype = guess_numpy_type(operator.inputs[0].type)
50 out = operator.outputs
52 options = container.get_options(score_cdist_sum, dict(cdist=None))
54 kwargs = op.kwargs
56 if options.get('cdist', None) == 'single-node':
57 attrs = kwargs
58 cdist_name = scope.get_unique_variable_name('cdist')
59 container.add_node('CDist', [X.full_name, Y.full_name], cdist_name,
60 op_domain='mlprodict', name=scope.get_unique_operator_name('CDist'),
61 **attrs)
62 if container.target_opset < 13:
63 container.add_node('ReduceSum', [cdist_name], out[0].full_name,
64 axes=[1], keepdims=0,
65 name=scope.get_unique_operator_name('ReduceSum'))
66 else:
67 axis_name = scope.get_unique_variable_name('axis')
68 container.add_initializer(
69 axis_name, onnx_proto.TensorProto.INT64, [1], [1]) # pylint: disable=E1101
70 container.add_node(
71 'ReduceSum', [cdist_name, axis_name],
72 out[0].full_name, keepdims=0,
73 name=scope.get_unique_operator_name('ReduceSum'))
74 else:
75 metric = kwargs['metric']
76 if metric == 'minkowski':
77 dists = onnx_cdist(X, Y, dtype=dtype, op_version=opv,
78 metric=metric, p=kwargs.get('p', 2))
79 else:
80 dists = onnx_cdist(X, Y, dtype=dtype, op_version=opv,
81 metric=kwargs['metric'])
83 res = OnnxReduceSumApi11(dists, axes=[1], keepdims=0,
84 output_names=[out[0].full_name],
85 op_version=opv)
86 res.add_to(scope, container)