keras-nightly 3.12.0.dev2025083103__py3-none-any.whl → 3.14.0.dev2026011604__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- keras/__init__.py +1 -0
- keras/_tf_keras/keras/__init__.py +1 -0
- keras/_tf_keras/keras/callbacks/__init__.py +3 -0
- keras/_tf_keras/keras/distillation/__init__.py +16 -0
- keras/_tf_keras/keras/distribution/__init__.py +3 -0
- keras/_tf_keras/keras/dtype_policies/__init__.py +6 -0
- keras/_tf_keras/keras/layers/__init__.py +21 -0
- keras/_tf_keras/keras/ops/__init__.py +16 -0
- keras/_tf_keras/keras/ops/image/__init__.py +1 -0
- keras/_tf_keras/keras/ops/linalg/__init__.py +1 -0
- keras/_tf_keras/keras/ops/nn/__init__.py +3 -0
- keras/_tf_keras/keras/ops/numpy/__init__.py +12 -0
- keras/_tf_keras/keras/quantizers/__init__.py +13 -0
- keras/callbacks/__init__.py +3 -0
- keras/distillation/__init__.py +16 -0
- keras/distribution/__init__.py +3 -0
- keras/dtype_policies/__init__.py +6 -0
- keras/layers/__init__.py +21 -0
- keras/ops/__init__.py +16 -0
- keras/ops/image/__init__.py +1 -0
- keras/ops/linalg/__init__.py +1 -0
- keras/ops/nn/__init__.py +3 -0
- keras/ops/numpy/__init__.py +12 -0
- keras/quantizers/__init__.py +13 -0
- keras/src/applications/imagenet_utils.py +4 -1
- keras/src/backend/common/backend_utils.py +30 -6
- keras/src/backend/common/dtypes.py +6 -12
- keras/src/backend/common/name_scope.py +2 -1
- keras/src/backend/common/variables.py +38 -20
- keras/src/backend/jax/core.py +126 -78
- keras/src/backend/jax/distribution_lib.py +16 -2
- keras/src/backend/jax/layer.py +3 -1
- keras/src/backend/jax/linalg.py +4 -0
- keras/src/backend/jax/nn.py +511 -29
- keras/src/backend/jax/numpy.py +109 -23
- keras/src/backend/jax/optimizer.py +3 -2
- keras/src/backend/jax/trainer.py +18 -3
- keras/src/backend/numpy/linalg.py +4 -0
- keras/src/backend/numpy/nn.py +313 -2
- keras/src/backend/numpy/numpy.py +97 -8
- keras/src/backend/openvino/__init__.py +1 -0
- keras/src/backend/openvino/core.py +6 -23
- keras/src/backend/openvino/linalg.py +4 -0
- keras/src/backend/openvino/nn.py +271 -20
- keras/src/backend/openvino/numpy.py +1369 -195
- keras/src/backend/openvino/random.py +7 -14
- keras/src/backend/tensorflow/layer.py +43 -9
- keras/src/backend/tensorflow/linalg.py +24 -0
- keras/src/backend/tensorflow/nn.py +545 -1
- keras/src/backend/tensorflow/numpy.py +351 -56
- keras/src/backend/tensorflow/trainer.py +6 -2
- keras/src/backend/torch/core.py +3 -1
- keras/src/backend/torch/linalg.py +4 -0
- keras/src/backend/torch/nn.py +125 -0
- keras/src/backend/torch/numpy.py +109 -9
- keras/src/backend/torch/trainer.py +8 -2
- keras/src/callbacks/__init__.py +1 -0
- keras/src/callbacks/callback_list.py +45 -11
- keras/src/callbacks/model_checkpoint.py +5 -0
- keras/src/callbacks/orbax_checkpoint.py +332 -0
- keras/src/callbacks/terminate_on_nan.py +54 -5
- keras/src/datasets/cifar10.py +5 -0
- keras/src/distillation/__init__.py +1 -0
- keras/src/distillation/distillation_loss.py +390 -0
- keras/src/distillation/distiller.py +598 -0
- keras/src/distribution/distribution_lib.py +14 -0
- keras/src/dtype_policies/__init__.py +4 -0
- keras/src/dtype_policies/dtype_policy.py +180 -1
- keras/src/export/__init__.py +2 -0
- keras/src/export/export_utils.py +39 -2
- keras/src/export/litert.py +248 -0
- keras/src/export/onnx.py +6 -0
- keras/src/export/openvino.py +1 -1
- keras/src/export/tf2onnx_lib.py +3 -0
- keras/src/layers/__init__.py +13 -0
- keras/src/layers/activations/softmax.py +9 -4
- keras/src/layers/attention/attention.py +1 -1
- keras/src/layers/attention/multi_head_attention.py +4 -1
- keras/src/layers/core/dense.py +406 -102
- keras/src/layers/core/einsum_dense.py +521 -116
- keras/src/layers/core/embedding.py +257 -99
- keras/src/layers/core/input_layer.py +1 -0
- keras/src/layers/core/reversible_embedding.py +399 -0
- keras/src/layers/input_spec.py +17 -17
- keras/src/layers/layer.py +50 -15
- keras/src/layers/merging/concatenate.py +6 -5
- keras/src/layers/merging/dot.py +4 -1
- keras/src/layers/pooling/adaptive_average_pooling1d.py +65 -0
- keras/src/layers/pooling/adaptive_average_pooling2d.py +62 -0
- keras/src/layers/pooling/adaptive_average_pooling3d.py +63 -0
- keras/src/layers/pooling/adaptive_max_pooling1d.py +65 -0
- keras/src/layers/pooling/adaptive_max_pooling2d.py +62 -0
- keras/src/layers/pooling/adaptive_max_pooling3d.py +63 -0
- keras/src/layers/pooling/base_adaptive_pooling.py +63 -0
- keras/src/layers/preprocessing/discretization.py +6 -5
- keras/src/layers/preprocessing/feature_space.py +8 -4
- keras/src/layers/preprocessing/image_preprocessing/aug_mix.py +2 -2
- keras/src/layers/preprocessing/image_preprocessing/bounding_boxes/validation.py +5 -5
- keras/src/layers/preprocessing/image_preprocessing/random_contrast.py +3 -3
- keras/src/layers/preprocessing/image_preprocessing/resizing.py +10 -0
- keras/src/layers/preprocessing/index_lookup.py +19 -1
- keras/src/layers/preprocessing/normalization.py +16 -1
- keras/src/layers/preprocessing/string_lookup.py +26 -28
- keras/src/layers/regularization/dropout.py +43 -1
- keras/src/layers/rnn/gru.py +1 -1
- keras/src/layers/rnn/lstm.py +2 -2
- keras/src/layers/rnn/rnn.py +19 -0
- keras/src/layers/rnn/simple_rnn.py +1 -1
- keras/src/legacy/preprocessing/image.py +4 -1
- keras/src/legacy/preprocessing/sequence.py +20 -12
- keras/src/losses/loss.py +1 -1
- keras/src/losses/losses.py +24 -0
- keras/src/metrics/confusion_metrics.py +7 -6
- keras/src/models/cloning.py +4 -0
- keras/src/models/functional.py +11 -3
- keras/src/models/model.py +195 -44
- keras/src/ops/image.py +257 -20
- keras/src/ops/linalg.py +93 -0
- keras/src/ops/nn.py +268 -2
- keras/src/ops/numpy.py +701 -44
- keras/src/ops/operation.py +90 -29
- keras/src/ops/operation_utils.py +2 -0
- keras/src/optimizers/adafactor.py +29 -10
- keras/src/optimizers/base_optimizer.py +22 -3
- keras/src/optimizers/loss_scale_optimizer.py +51 -18
- keras/src/optimizers/muon.py +65 -31
- keras/src/optimizers/schedules/learning_rate_schedule.py +4 -3
- keras/src/quantizers/__init__.py +14 -1
- keras/src/quantizers/awq.py +361 -0
- keras/src/quantizers/awq_config.py +140 -0
- keras/src/quantizers/awq_core.py +217 -0
- keras/src/quantizers/gptq.py +346 -207
- keras/src/quantizers/gptq_config.py +63 -13
- keras/src/quantizers/gptq_core.py +328 -215
- keras/src/quantizers/quantization_config.py +246 -0
- keras/src/quantizers/quantizers.py +407 -38
- keras/src/quantizers/utils.py +23 -0
- keras/src/random/seed_generator.py +6 -4
- keras/src/saving/file_editor.py +81 -6
- keras/src/saving/orbax_util.py +26 -0
- keras/src/saving/saving_api.py +37 -14
- keras/src/saving/saving_lib.py +1 -1
- keras/src/testing/__init__.py +1 -0
- keras/src/testing/test_case.py +45 -5
- keras/src/trainers/compile_utils.py +38 -17
- keras/src/trainers/data_adapters/grain_dataset_adapter.py +1 -5
- keras/src/tree/torchtree_impl.py +215 -0
- keras/src/tree/tree_api.py +6 -1
- keras/src/utils/backend_utils.py +31 -4
- keras/src/utils/dataset_utils.py +234 -35
- keras/src/utils/file_utils.py +49 -11
- keras/src/utils/image_utils.py +14 -2
- keras/src/utils/jax_layer.py +244 -55
- keras/src/utils/module_utils.py +29 -0
- keras/src/utils/progbar.py +10 -12
- keras/src/utils/python_utils.py +5 -0
- keras/src/utils/rng_utils.py +9 -1
- keras/src/utils/tracking.py +70 -5
- keras/src/version.py +1 -1
- {keras_nightly-3.12.0.dev2025083103.dist-info → keras_nightly-3.14.0.dev2026011604.dist-info}/METADATA +16 -6
- {keras_nightly-3.12.0.dev2025083103.dist-info → keras_nightly-3.14.0.dev2026011604.dist-info}/RECORD +163 -142
- keras/src/quantizers/gptq_quant.py +0 -133
- {keras_nightly-3.12.0.dev2025083103.dist-info → keras_nightly-3.14.0.dev2026011604.dist-info}/WHEEL +0 -0
- {keras_nightly-3.12.0.dev2025083103.dist-info → keras_nightly-3.14.0.dev2026011604.dist-info}/top_level.txt +0 -0
|
@@ -4,6 +4,7 @@ from openvino import Type
|
|
|
4
4
|
|
|
5
5
|
from keras.src.backend import config
|
|
6
6
|
from keras.src.backend.common import dtypes
|
|
7
|
+
from keras.src.backend.common.backend_utils import canonicalize_axis
|
|
7
8
|
from keras.src.backend.common.variables import standardize_dtype
|
|
8
9
|
from keras.src.backend.openvino.core import DTYPES_MAX
|
|
9
10
|
from keras.src.backend.openvino.core import DTYPES_MIN
|
|
@@ -46,6 +47,8 @@ def subtract(x1, x2):
|
|
|
46
47
|
x1 = get_ov_output(x1, element_type)
|
|
47
48
|
x2 = get_ov_output(x2, element_type)
|
|
48
49
|
x1, x2 = _align_operand_types(x1, x2, "subtract()")
|
|
50
|
+
if x1.get_element_type() == Type.boolean:
|
|
51
|
+
return OpenVINOKerasTensor(ov_opset.logical_xor(x1, x2).output(0))
|
|
49
52
|
return OpenVINOKerasTensor(ov_opset.subtract(x1, x2).output(0))
|
|
50
53
|
|
|
51
54
|
|
|
@@ -74,25 +77,81 @@ def multiply(x1, x2):
|
|
|
74
77
|
|
|
75
78
|
|
|
76
79
|
def mean(x, axis=None, keepdims=False):
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
80
|
+
x_ov = get_ov_output(x)
|
|
81
|
+
x_type = x_ov.get_element_type()
|
|
82
|
+
|
|
83
|
+
was_axis_none = axis is None
|
|
84
|
+
x_resolved, axis_resolved = _resolve_axis(x_ov, axis)
|
|
85
|
+
|
|
86
|
+
if axis_resolved is None:
|
|
87
|
+
return OpenVINOKerasTensor(x_ov)
|
|
88
|
+
|
|
89
|
+
if x_type.is_integral():
|
|
90
|
+
ov_type = OPENVINO_DTYPES[config.floatx()]
|
|
91
|
+
x_resolved = ov_opset.convert(x_resolved, ov_type).output(0)
|
|
92
|
+
|
|
93
|
+
result = ov_opset.reduce_mean(x_resolved, axis_resolved, keepdims).output(0)
|
|
94
|
+
|
|
95
|
+
if keepdims and was_axis_none:
|
|
96
|
+
rank = x.get_partial_shape().rank.get_length()
|
|
97
|
+
result_shape = [1] * rank
|
|
98
|
+
result = ov_opset.reshape(
|
|
99
|
+
result,
|
|
100
|
+
ov_opset.constant(result_shape, Type.i32).output(0),
|
|
101
|
+
False,
|
|
102
|
+
).output(0)
|
|
103
|
+
|
|
104
|
+
return OpenVINOKerasTensor(result)
|
|
85
105
|
|
|
86
106
|
|
|
87
107
|
def max(x, axis=None, keepdims=False, initial=None):
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
108
|
+
return _compute_extrema(x, "max", axis, keepdims, initial)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def _compute_extrema(x, operation, axis=None, keepdims=False, initial=None):
|
|
112
|
+
if operation == "min":
|
|
113
|
+
reduction_op = ov_opset.reduce_min
|
|
114
|
+
elementwise_op = ov_opset.minimum
|
|
115
|
+
elif operation == "max":
|
|
116
|
+
reduction_op = ov_opset.reduce_max
|
|
117
|
+
elementwise_op = ov_opset.maximum
|
|
118
|
+
else:
|
|
119
|
+
raise ValueError(
|
|
120
|
+
f"Operation must be 'min' or 'max', received {operation}"
|
|
121
|
+
)
|
|
122
|
+
|
|
91
123
|
x = get_ov_output(x)
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
124
|
+
x_type = x.get_element_type()
|
|
125
|
+
x_for_rank = x
|
|
126
|
+
|
|
127
|
+
is_bool = x_type == Type.boolean
|
|
128
|
+
if is_bool:
|
|
129
|
+
x = ov_opset.convert(x, Type.i32).output(0)
|
|
130
|
+
x_type = Type.i32
|
|
131
|
+
|
|
132
|
+
if isinstance(axis, tuple) and len(axis) == 0:
|
|
133
|
+
return OpenVINOKerasTensor(x)
|
|
134
|
+
|
|
135
|
+
was_axis_none = axis is None
|
|
136
|
+
x, axis = _resolve_axis(x, axis)
|
|
137
|
+
|
|
138
|
+
result = reduction_op(x, axis, keepdims).output(0)
|
|
139
|
+
|
|
140
|
+
if initial is not None:
|
|
141
|
+
initial_tensor = ov_opset.constant(initial, x_type).output(0)
|
|
142
|
+
result = elementwise_op(result, initial_tensor).output(0)
|
|
143
|
+
|
|
144
|
+
if keepdims and was_axis_none:
|
|
145
|
+
orig_shape = ov_opset.shape_of(x_for_rank, Type.i32).output(0)
|
|
146
|
+
orig_rank_shape = ov_opset.shape_of(orig_shape, Type.i32).output(0)
|
|
147
|
+
one = ov_opset.constant(1, Type.i32).output(0)
|
|
148
|
+
result_shape = ov_opset.broadcast(one, orig_rank_shape).output(0)
|
|
149
|
+
result = ov_opset.reshape(result, result_shape, False).output(0)
|
|
150
|
+
|
|
151
|
+
if is_bool:
|
|
152
|
+
result = ov_opset.convert(result, Type.boolean).output(0)
|
|
153
|
+
|
|
154
|
+
return OpenVINOKerasTensor(result)
|
|
96
155
|
|
|
97
156
|
|
|
98
157
|
def ones(shape, dtype=None):
|
|
@@ -123,6 +182,9 @@ def zeros(shape, dtype=None):
|
|
|
123
182
|
|
|
124
183
|
def absolute(x):
|
|
125
184
|
x = get_ov_output(x)
|
|
185
|
+
x_type = x.get_element_type()
|
|
186
|
+
if x_type == Type.boolean:
|
|
187
|
+
return OpenVINOKerasTensor(x)
|
|
126
188
|
return OpenVINOKerasTensor(ov_opset.absolute(x).output(0))
|
|
127
189
|
|
|
128
190
|
|
|
@@ -133,11 +195,10 @@ def abs(x):
|
|
|
133
195
|
|
|
134
196
|
def all(x, axis=None, keepdims=False):
|
|
135
197
|
x = get_ov_output(x)
|
|
198
|
+
x, axis = _resolve_axis(x, axis)
|
|
136
199
|
if axis is None:
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
axis = 0
|
|
140
|
-
axis = ov_opset.constant(axis, Type.i32).output(0)
|
|
200
|
+
return OpenVINOKerasTensor(x)
|
|
201
|
+
x = ov_opset.convert(x, Type.boolean).output(0)
|
|
141
202
|
return OpenVINOKerasTensor(
|
|
142
203
|
ov_opset.reduce_logical_and(x, axis, keepdims).output(0)
|
|
143
204
|
)
|
|
@@ -149,28 +210,21 @@ def angle(x):
|
|
|
149
210
|
|
|
150
211
|
def any(x, axis=None, keepdims=False):
|
|
151
212
|
x = get_ov_output(x)
|
|
213
|
+
x, axis = _resolve_axis(x, axis)
|
|
152
214
|
if axis is None:
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
axis = 0
|
|
156
|
-
axis = ov_opset.constant(axis, Type.i32).output(0)
|
|
215
|
+
return OpenVINOKerasTensor(x)
|
|
216
|
+
x = ov_opset.convert(x, Type.boolean).output(0)
|
|
157
217
|
return OpenVINOKerasTensor(
|
|
158
218
|
ov_opset.reduce_logical_or(x, axis, keepdims).output(0)
|
|
159
219
|
)
|
|
160
220
|
|
|
161
221
|
|
|
162
222
|
def amax(x, axis=None, keepdims=False):
|
|
163
|
-
if axis == () or axis == []:
|
|
164
|
-
return x
|
|
165
223
|
x = get_ov_output(x)
|
|
166
224
|
x_type = x.get_element_type()
|
|
225
|
+
x, axis = _resolve_axis(x, axis)
|
|
167
226
|
if axis is None:
|
|
168
|
-
|
|
169
|
-
x = ov_opset.reshape(x, flatten_shape, False).output(0)
|
|
170
|
-
axis = 0
|
|
171
|
-
if isinstance(axis, tuple):
|
|
172
|
-
axis = list(axis)
|
|
173
|
-
axis = ov_opset.constant(axis, Type.i32).output(0)
|
|
227
|
+
return OpenVINOKerasTensor(x)
|
|
174
228
|
if x_type == Type.boolean:
|
|
175
229
|
return OpenVINOKerasTensor(
|
|
176
230
|
ov_opset.reduce_logical_or(x, axis, keepdims).output(0)
|
|
@@ -179,10 +233,21 @@ def amax(x, axis=None, keepdims=False):
|
|
|
179
233
|
|
|
180
234
|
|
|
181
235
|
def amin(x, axis=None, keepdims=False):
|
|
182
|
-
if axis == () or axis == []:
|
|
183
|
-
return x
|
|
184
236
|
x = get_ov_output(x)
|
|
185
237
|
x_type = x.get_element_type()
|
|
238
|
+
x, axis = _resolve_axis(x, axis)
|
|
239
|
+
if axis is None:
|
|
240
|
+
return OpenVINOKerasTensor(x)
|
|
241
|
+
if x_type == Type.boolean:
|
|
242
|
+
return OpenVINOKerasTensor(
|
|
243
|
+
ov_opset.reduce_logical_and(x, axis, keepdims).output(0)
|
|
244
|
+
)
|
|
245
|
+
return OpenVINOKerasTensor(ov_opset.reduce_min(x, axis, keepdims).output(0))
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def _resolve_axis(x, axis):
|
|
249
|
+
if axis == () or axis == []:
|
|
250
|
+
return x, None
|
|
186
251
|
if axis is None:
|
|
187
252
|
flatten_shape = ov_opset.constant([-1], Type.i32).output(0)
|
|
188
253
|
x = ov_opset.reshape(x, flatten_shape, False).output(0)
|
|
@@ -190,11 +255,18 @@ def amin(x, axis=None, keepdims=False):
|
|
|
190
255
|
if isinstance(axis, tuple):
|
|
191
256
|
axis = list(axis)
|
|
192
257
|
axis = ov_opset.constant(axis, Type.i32).output(0)
|
|
258
|
+
return x, axis
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def _upcast_type_if_needed(x):
|
|
262
|
+
x_type = x.get_element_type()
|
|
193
263
|
if x_type == Type.boolean:
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
)
|
|
197
|
-
|
|
264
|
+
x = ov_opset.convert(x, Type.i32).output(0)
|
|
265
|
+
elif x_type in (Type.i8, Type.i16):
|
|
266
|
+
x = ov_opset.convert(x, Type.i32).output(0)
|
|
267
|
+
elif x_type in (Type.u8, Type.u16):
|
|
268
|
+
x = ov_opset.convert(x, Type.u32).output(0)
|
|
269
|
+
return x
|
|
198
270
|
|
|
199
271
|
|
|
200
272
|
def append(x1, x2, axis=None):
|
|
@@ -208,7 +280,7 @@ def append(x1, x2, axis=None):
|
|
|
208
280
|
return OpenVINOKerasTensor(ov_opset.concat([x1, x2], axis).output(0))
|
|
209
281
|
|
|
210
282
|
|
|
211
|
-
def arange(start, stop=None, step=
|
|
283
|
+
def arange(start, stop=None, step=None, dtype=None):
|
|
212
284
|
if stop is None:
|
|
213
285
|
start, stop = get_ov_output(0), get_ov_output(start)
|
|
214
286
|
else:
|
|
@@ -437,6 +509,10 @@ def array(x, dtype=None):
|
|
|
437
509
|
return np.array(x)
|
|
438
510
|
|
|
439
511
|
|
|
512
|
+
def view(x, dtype=None):
|
|
513
|
+
raise NotImplementedError("`view` is not supported with openvino backend")
|
|
514
|
+
|
|
515
|
+
|
|
440
516
|
def average(x, axis=None, weights=None):
|
|
441
517
|
x = get_ov_output(x)
|
|
442
518
|
if weights is not None:
|
|
@@ -470,22 +546,79 @@ def average(x, axis=None, weights=None):
|
|
|
470
546
|
|
|
471
547
|
|
|
472
548
|
def bartlett(x):
|
|
473
|
-
|
|
474
|
-
|
|
549
|
+
x = get_ov_output(x)
|
|
550
|
+
zero_const = ov_opset.constant(0, Type.i64)
|
|
551
|
+
one_const = ov_opset.constant(1, Type.i64)
|
|
552
|
+
two_const = ov_opset.constant(2, Type.i64)
|
|
553
|
+
two_const_f64 = ov_opset.constant(2.0, Type.f64)
|
|
554
|
+
if x.get_element_type() != Type.i64:
|
|
555
|
+
x = ov_opset.convert(x, Type.i64)
|
|
556
|
+
half = ov_opset.convert(
|
|
557
|
+
ov_opset.divide(ov_opset.subtract(x, one_const), two_const), Type.f64
|
|
558
|
+
)
|
|
559
|
+
n = ov_opset.range(zero_const, x, one_const, Type.f64)
|
|
560
|
+
condition = ov_opset.less_equal(n, half)
|
|
561
|
+
first_half = ov_opset.divide(
|
|
562
|
+
ov_opset.multiply(two_const_f64, n),
|
|
563
|
+
ov_opset.convert(ov_opset.subtract(x, one_const), Type.f64),
|
|
475
564
|
)
|
|
565
|
+
second_half = ov_opset.subtract(two_const_f64, first_half)
|
|
566
|
+
window = ov_opset.select(condition, first_half, second_half)
|
|
567
|
+
window = ov_opset.convert(window, OPENVINO_DTYPES[config.floatx()]).output(
|
|
568
|
+
0
|
|
569
|
+
)
|
|
570
|
+
return OpenVINOKerasTensor(window)
|
|
476
571
|
|
|
477
572
|
|
|
478
573
|
def hamming(x):
|
|
479
|
-
|
|
480
|
-
|
|
574
|
+
m = get_ov_output(x)
|
|
575
|
+
|
|
576
|
+
m_i64 = (
|
|
577
|
+
m if m.get_element_type() == Type.i64 else ov_opset.convert(m, Type.i64)
|
|
481
578
|
)
|
|
482
579
|
|
|
580
|
+
start = ov_opset.constant(0, Type.i64)
|
|
581
|
+
step = ov_opset.constant(1, Type.i64)
|
|
582
|
+
n = ov_opset.range(start, m_i64, step, Type.f64)
|
|
483
583
|
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
584
|
+
one_i64 = ov_opset.constant(1, Type.i64)
|
|
585
|
+
denom_i64 = ov_opset.subtract(m_i64, one_i64)
|
|
586
|
+
denom = ov_opset.convert(denom_i64, Type.f64)
|
|
587
|
+
|
|
588
|
+
two_pi = ov_opset.constant(2.0 * np.pi, Type.f64)
|
|
589
|
+
two_pi_over_m_minus_1 = ov_opset.divide(two_pi, denom)
|
|
590
|
+
|
|
591
|
+
x = ov_opset.multiply(two_pi_over_m_minus_1, n)
|
|
592
|
+
c = ov_opset.cos(x)
|
|
593
|
+
|
|
594
|
+
# 0.54 - 0.46 * cos(...)
|
|
595
|
+
a = ov_opset.constant(0.54, Type.f64)
|
|
596
|
+
b = ov_opset.constant(0.46, Type.f64)
|
|
597
|
+
hamming_window = ov_opset.subtract(a, ov_opset.multiply(b, c))
|
|
598
|
+
hamming_window = ov_opset.convert(
|
|
599
|
+
hamming_window, OPENVINO_DTYPES[config.floatx()]
|
|
487
600
|
)
|
|
488
601
|
|
|
602
|
+
return OpenVINOKerasTensor(hamming_window.output(0))
|
|
603
|
+
|
|
604
|
+
|
|
605
|
+
def heaviside(x1, x2):
|
|
606
|
+
x1 = get_ov_output(x1)
|
|
607
|
+
x_type = x1.get_element_type()
|
|
608
|
+
x2 = get_ov_output(x2, x_type)
|
|
609
|
+
|
|
610
|
+
zero_scalar = ov_opset.constant(0, x_type).output(0)
|
|
611
|
+
one_scalar = ov_opset.constant(1, x_type).output(0)
|
|
612
|
+
|
|
613
|
+
neg = ov_opset.less(x1, zero_scalar).output(0)
|
|
614
|
+
pos = ov_opset.greater(x1, zero_scalar).output(0)
|
|
615
|
+
eq = ov_opset.equal(x1, zero_scalar).output(0)
|
|
616
|
+
|
|
617
|
+
x = ov_opset.select(neg, zero_scalar, x1).output(0)
|
|
618
|
+
x = ov_opset.select(pos, one_scalar, x).output(0)
|
|
619
|
+
x = ov_opset.select(eq, x2, x).output(0)
|
|
620
|
+
return OpenVINOKerasTensor(x)
|
|
621
|
+
|
|
489
622
|
|
|
490
623
|
def kaiser(x, beta):
|
|
491
624
|
raise NotImplementedError("`kaiser` is not supported with openvino backend")
|
|
@@ -537,9 +670,30 @@ def bincount(x, weights=None, minlength=0, sparse=False):
|
|
|
537
670
|
|
|
538
671
|
|
|
539
672
|
def blackman(x):
|
|
540
|
-
|
|
541
|
-
|
|
673
|
+
x = get_ov_output(x)
|
|
674
|
+
zero_const = ov_opset.constant(0, Type.i64)
|
|
675
|
+
one_const = ov_opset.constant(1, Type.i64)
|
|
676
|
+
two_pi = ov_opset.constant(2.0 * np.pi, Type.f64)
|
|
677
|
+
term_1 = ov_opset.constant(0.42, Type.f64)
|
|
678
|
+
term_2 = ov_opset.constant(0.5, Type.f64)
|
|
679
|
+
term_3 = ov_opset.constant(0.08, Type.f64)
|
|
680
|
+
if x.get_element_type() != Type.i64:
|
|
681
|
+
x = ov_opset.convert(x, Type.i64)
|
|
682
|
+
n = ov_opset.range(zero_const, x, one_const, Type.f64)
|
|
683
|
+
n_minus_1 = ov_opset.subtract(
|
|
684
|
+
ov_opset.convert(x, Type.f64), ov_opset.constant(1.0, Type.f64)
|
|
685
|
+
).output(0)
|
|
686
|
+
angle_2pi = ov_opset.divide(ov_opset.multiply(two_pi, n), n_minus_1)
|
|
687
|
+
angle_4pi = ov_opset.multiply(angle_2pi, ov_opset.constant(2.0, Type.f64))
|
|
688
|
+
cos_2pi = ov_opset.cos(angle_2pi)
|
|
689
|
+
cos_4pi = ov_opset.cos(angle_4pi)
|
|
690
|
+
term_2_final = ov_opset.multiply(term_2, cos_2pi)
|
|
691
|
+
term_3_final = ov_opset.multiply(term_3, cos_4pi)
|
|
692
|
+
window = ov_opset.add(ov_opset.subtract(term_1, term_2_final), term_3_final)
|
|
693
|
+
window = ov_opset.convert(window, OPENVINO_DTYPES[config.floatx()]).output(
|
|
694
|
+
0
|
|
542
695
|
)
|
|
696
|
+
return OpenVINOKerasTensor(window)
|
|
543
697
|
|
|
544
698
|
|
|
545
699
|
def broadcast_to(x, shape):
|
|
@@ -552,16 +706,32 @@ def broadcast_to(x, shape):
|
|
|
552
706
|
|
|
553
707
|
|
|
554
708
|
def cbrt(x):
|
|
555
|
-
|
|
709
|
+
x = get_ov_output(x)
|
|
710
|
+
x_type = x.get_element_type()
|
|
711
|
+
if x_type.is_integral() or x_type == Type.boolean:
|
|
712
|
+
x = ov_opset.convert(x, OPENVINO_DTYPES[config.floatx()]).output(0)
|
|
713
|
+
sign_x = ov_opset.sign(x)
|
|
714
|
+
abs_x = ov_opset.absolute(x)
|
|
715
|
+
one_third = ov_opset.constant(1.0 / 3.0, x.get_element_type())
|
|
716
|
+
root_abs = ov_opset.power(abs_x, one_third)
|
|
717
|
+
res = ov_opset.multiply(sign_x, root_abs)
|
|
718
|
+
return OpenVINOKerasTensor(res.output(0))
|
|
556
719
|
|
|
557
720
|
|
|
558
721
|
def ceil(x):
|
|
559
722
|
x = get_ov_output(x)
|
|
560
|
-
|
|
723
|
+
x_type = x.get_element_type()
|
|
724
|
+
if x_type.is_integral():
|
|
725
|
+
x = ov_opset.convert(x, OPENVINO_DTYPES[config.floatx()]).output(0)
|
|
726
|
+
ceiling = ov_opset.ceil(x).output(0)
|
|
727
|
+
return OpenVINOKerasTensor(ceiling)
|
|
561
728
|
|
|
562
729
|
|
|
563
730
|
def clip(x, x_min, x_max):
|
|
564
731
|
x = get_ov_output(x)
|
|
732
|
+
x_type = x.get_element_type()
|
|
733
|
+
if x_type == Type.boolean:
|
|
734
|
+
x = ov_opset.convert(x, Type.i32).output(0)
|
|
565
735
|
x_min = get_ov_output(x_min, x.get_element_type())
|
|
566
736
|
x_max = get_ov_output(x_max, x.get_element_type())
|
|
567
737
|
clip_by_min = ov_opset.maximum(x, x_min).output(0)
|
|
@@ -617,15 +787,9 @@ def count_nonzero(x, axis=None):
|
|
|
617
787
|
zero_constant = ov_opset.convert_like(zero_constant, x)
|
|
618
788
|
x = ov_opset.not_equal(x, zero_constant).output(0)
|
|
619
789
|
x = ov_opset.convert(x, Type.i32).output(0)
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
x = ov_opset.reshape(x, flatten_shape, False).output(0)
|
|
623
|
-
axis = 0
|
|
624
|
-
if isinstance(axis, tuple):
|
|
625
|
-
axis = list(axis)
|
|
626
|
-
if axis == []:
|
|
790
|
+
x, axis = _resolve_axis(x, axis)
|
|
791
|
+
if not axis:
|
|
627
792
|
return OpenVINOKerasTensor(x)
|
|
628
|
-
axis = ov_opset.constant(axis, Type.i32).output(0)
|
|
629
793
|
return OpenVINOKerasTensor(ov_opset.reduce_sum(x, axis, False).output(0))
|
|
630
794
|
|
|
631
795
|
|
|
@@ -644,11 +808,9 @@ def cumsum(x, axis=None, dtype=None):
|
|
|
644
808
|
if dtype is not None:
|
|
645
809
|
ov_type = OPENVINO_DTYPES[standardize_dtype(dtype)]
|
|
646
810
|
x = ov_opset.convert(x, ov_type).output(0)
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
x = ov_opset.
|
|
650
|
-
axis = 0
|
|
651
|
-
axis = ov_opset.constant(axis, Type.i32).output(0)
|
|
811
|
+
x, axis = _resolve_axis(x, axis)
|
|
812
|
+
if x.get_element_type() == Type.boolean:
|
|
813
|
+
x = ov_opset.convert(x, Type.i32).output(0)
|
|
652
814
|
return OpenVINOKerasTensor(ov_opset.cumsum(x, axis).output(0))
|
|
653
815
|
|
|
654
816
|
|
|
@@ -674,13 +836,120 @@ def deg2rad(x):
|
|
|
674
836
|
|
|
675
837
|
|
|
676
838
|
def diag(x, k=0):
|
|
677
|
-
|
|
839
|
+
x = get_ov_output(x)
|
|
840
|
+
x_shape = x.get_partial_shape()
|
|
841
|
+
rank = x_shape.rank.get_length()
|
|
842
|
+
|
|
843
|
+
if rank == 1:
|
|
844
|
+
N_dim = x_shape[0]
|
|
845
|
+
if not N_dim.is_static:
|
|
846
|
+
raise ValueError(
|
|
847
|
+
"diag requires input with static shape for 1D input."
|
|
848
|
+
)
|
|
849
|
+
N = N_dim.get_length()
|
|
850
|
+
output_size = N + np.abs(k)
|
|
851
|
+
out_shape = ov_opset.constant(
|
|
852
|
+
[output_size, output_size], dtype=Type.i32
|
|
853
|
+
).output(0)
|
|
854
|
+
zeros_const = ov_opset.constant(0, x.get_element_type()).output(0)
|
|
855
|
+
diag_matrix = ov_opset.broadcast(zeros_const, out_shape)
|
|
856
|
+
|
|
857
|
+
indices = []
|
|
858
|
+
if k >= 0:
|
|
859
|
+
for i in range(N):
|
|
860
|
+
indices.append([i, i + k])
|
|
861
|
+
else:
|
|
862
|
+
for i in range(N):
|
|
863
|
+
indices.append([i - k, i])
|
|
864
|
+
|
|
865
|
+
indices = np.array(indices, dtype=np.int32)
|
|
866
|
+
indices_const = ov_opset.constant(indices, dtype=Type.i32).output(0)
|
|
867
|
+
updated = ov_opset.scatter_nd_update(diag_matrix, indices_const, x)
|
|
868
|
+
return OpenVINOKerasTensor(updated.output(0))
|
|
869
|
+
|
|
870
|
+
elif rank == 2:
|
|
871
|
+
M_dim = x_shape[0]
|
|
872
|
+
N_dim = x_shape[1]
|
|
873
|
+
if not M_dim.is_static or not N_dim.is_static:
|
|
874
|
+
raise ValueError(
|
|
875
|
+
"diag requires input with static shape for 2D input."
|
|
876
|
+
)
|
|
877
|
+
M = M_dim.get_length()
|
|
878
|
+
N = N_dim.get_length()
|
|
879
|
+
|
|
880
|
+
if k >= 0:
|
|
881
|
+
L = np.minimum(M, N - k) if (N - k) > 0 else 0
|
|
882
|
+
indices = [[i, i + k] for i in range(L)]
|
|
883
|
+
else:
|
|
884
|
+
L = np.minimum(M + k, N) if (M + k) > 0 else 0
|
|
885
|
+
indices = [[i - k, i] for i in range(L)]
|
|
886
|
+
|
|
887
|
+
if L <= 0:
|
|
888
|
+
keras_dtype = ov_to_keras_type(x.get_element_type())
|
|
889
|
+
np_dtype = np.dtype(keras_dtype)
|
|
890
|
+
empty_np = np.empty((0,), dtype=np_dtype)
|
|
891
|
+
empty_const = ov_opset.constant(
|
|
892
|
+
empty_np, x.get_element_type()
|
|
893
|
+
).output(0)
|
|
894
|
+
return OpenVINOKerasTensor(empty_const)
|
|
895
|
+
|
|
896
|
+
indices = np.array(indices, dtype=np.int32)
|
|
897
|
+
indices_const = ov_opset.constant(indices, dtype=Type.i32).output(0)
|
|
898
|
+
diag_vec = ov_opset.gather_nd(x, indices_const)
|
|
899
|
+
return OpenVINOKerasTensor(diag_vec.output(0))
|
|
900
|
+
|
|
901
|
+
else:
|
|
902
|
+
raise ValueError("diag supports only 1D or 2D tensors")
|
|
678
903
|
|
|
679
904
|
|
|
680
905
|
def diagonal(x, offset=0, axis1=0, axis2=1):
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
)
|
|
906
|
+
x = get_ov_output(x)
|
|
907
|
+
shape = x.get_partial_shape()
|
|
908
|
+
rank = x.get_partial_shape().rank.get_length()
|
|
909
|
+
if rank is None:
|
|
910
|
+
raise ValueError("`diagonal` requires input tensor with static rank.")
|
|
911
|
+
if rank < 2:
|
|
912
|
+
raise ValueError(
|
|
913
|
+
f"diagonal requires input tensor with rank >= 2.Given rank: {rank}"
|
|
914
|
+
)
|
|
915
|
+
axis1 = canonicalize_axis(axis1, rank)
|
|
916
|
+
axis2 = canonicalize_axis(axis2, rank)
|
|
917
|
+
if axis1 == axis2:
|
|
918
|
+
raise ValueError("`axis1` and `axis2` cannot be the same.")
|
|
919
|
+
|
|
920
|
+
perm_order = [axis1, axis2] + [
|
|
921
|
+
i for i in range(rank) if i != axis1 and i != axis2
|
|
922
|
+
]
|
|
923
|
+
perm_const = ov_opset.constant(perm_order, dtype=Type.i32).output(0)
|
|
924
|
+
x_transposed = ov_opset.transpose(x, perm_const)
|
|
925
|
+
|
|
926
|
+
N_dim = shape[axis1]
|
|
927
|
+
M_dim = shape[axis2]
|
|
928
|
+
if not N_dim.is_static or not M_dim.is_static:
|
|
929
|
+
raise ValueError(
|
|
930
|
+
"`diagonal` requires input tensor with static shape for axes "
|
|
931
|
+
f"`axis1` ({axis1}) and `axis2` ({axis2})."
|
|
932
|
+
)
|
|
933
|
+
N = N_dim.get_length()
|
|
934
|
+
M = M_dim.get_length()
|
|
935
|
+
if offset >= 0:
|
|
936
|
+
L = np.minimum(N, M - offset) if (M - offset) > 0 else 0
|
|
937
|
+
indices = [[i, i + offset] for i in range(L)]
|
|
938
|
+
else:
|
|
939
|
+
L = np.minimum(N + offset, M) if (N + offset) > 0 else 0
|
|
940
|
+
indices = [[i - offset, i] for i in range(L)]
|
|
941
|
+
|
|
942
|
+
indices = np.array(indices, dtype=np.int32).reshape(L, 2)
|
|
943
|
+
indices_const = ov_opset.constant(indices, dtype=Type.i32).output(0)
|
|
944
|
+
|
|
945
|
+
diag_gathered = ov_opset.gather_nd(x_transposed, indices_const)
|
|
946
|
+
|
|
947
|
+
out_rank = rank - 1
|
|
948
|
+
out_perm_order = list(range(1, out_rank)) + [0]
|
|
949
|
+
out_perm_const = ov_opset.constant(out_perm_order, dtype=Type.i32).output(0)
|
|
950
|
+
|
|
951
|
+
final_output = ov_opset.transpose(diag_gathered, out_perm_const)
|
|
952
|
+
return OpenVINOKerasTensor(final_output.output(0))
|
|
684
953
|
|
|
685
954
|
|
|
686
955
|
def diff(a, n=1, axis=-1):
|
|
@@ -757,9 +1026,30 @@ def diff(a, n=1, axis=-1):
|
|
|
757
1026
|
|
|
758
1027
|
|
|
759
1028
|
def digitize(x, bins):
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
)
|
|
1029
|
+
x_node = get_ov_output(x)
|
|
1030
|
+
|
|
1031
|
+
if isinstance(bins, OpenVINOKerasTensor):
|
|
1032
|
+
bins_node = get_ov_output(bins)
|
|
1033
|
+
else:
|
|
1034
|
+
bins_np = np.asarray(bins)
|
|
1035
|
+
if bins_np.ndim != 1:
|
|
1036
|
+
raise ValueError("`bins` must be 1-D array-like")
|
|
1037
|
+
bins_node = ov_opset.constant(bins_np).output(0)
|
|
1038
|
+
|
|
1039
|
+
x_node, bins_node = _align_operand_types(x_node, bins_node, "digitize()")
|
|
1040
|
+
|
|
1041
|
+
if x_node.get_element_type() == Type.boolean:
|
|
1042
|
+
x_node = ov_opset.convert(x_node, Type.f32).output(0)
|
|
1043
|
+
bins_node = ov_opset.convert(bins_node, Type.f32).output(0)
|
|
1044
|
+
|
|
1045
|
+
result = ov_opset.bucketize(
|
|
1046
|
+
x_node,
|
|
1047
|
+
bins_node,
|
|
1048
|
+
output_type=Type.i32,
|
|
1049
|
+
with_right_bound=False,
|
|
1050
|
+
).output(0)
|
|
1051
|
+
|
|
1052
|
+
return OpenVINOKerasTensor(result)
|
|
763
1053
|
|
|
764
1054
|
|
|
765
1055
|
def dot(x1, x2):
|
|
@@ -789,6 +1079,10 @@ def empty(shape, dtype=None):
|
|
|
789
1079
|
return OpenVINOKerasTensor(empty_tensor)
|
|
790
1080
|
|
|
791
1081
|
|
|
1082
|
+
def empty_like(x, dtype=None):
|
|
1083
|
+
return zeros_like(x, dtype=dtype)
|
|
1084
|
+
|
|
1085
|
+
|
|
792
1086
|
def equal(x1, x2):
|
|
793
1087
|
element_type = None
|
|
794
1088
|
if isinstance(x1, OpenVINOKerasTensor):
|
|
@@ -831,11 +1125,101 @@ def expm1(x):
|
|
|
831
1125
|
|
|
832
1126
|
|
|
833
1127
|
def flip(x, axis=None):
|
|
834
|
-
|
|
1128
|
+
x_node = get_ov_output(x)
|
|
1129
|
+
|
|
1130
|
+
# Using OpenVINO tensor shape
|
|
1131
|
+
ndim = len(x_node.get_partial_shape())
|
|
1132
|
+
if ndim is None:
|
|
1133
|
+
raise ValueError(
|
|
1134
|
+
"The `flip` operation does not support tensors with dynamic rank "
|
|
1135
|
+
"for the OpenVINO backend."
|
|
1136
|
+
)
|
|
1137
|
+
|
|
1138
|
+
if axis is None:
|
|
1139
|
+
axis = list(range(ndim))
|
|
1140
|
+
elif isinstance(axis, int):
|
|
1141
|
+
axis = [axis]
|
|
1142
|
+
|
|
1143
|
+
axis = [a + ndim if a < 0 else a for a in axis]
|
|
1144
|
+
|
|
1145
|
+
begin = [0] * ndim
|
|
1146
|
+
end = [0] * ndim
|
|
1147
|
+
strides = [1] * ndim
|
|
1148
|
+
for a in axis:
|
|
1149
|
+
strides[a] = -1
|
|
1150
|
+
|
|
1151
|
+
all_ones_mask = [1] * ndim
|
|
1152
|
+
result = ov_opset.strided_slice(
|
|
1153
|
+
data=x_node,
|
|
1154
|
+
begin=begin,
|
|
1155
|
+
end=end,
|
|
1156
|
+
strides=strides,
|
|
1157
|
+
begin_mask=all_ones_mask,
|
|
1158
|
+
end_mask=all_ones_mask,
|
|
1159
|
+
)
|
|
1160
|
+
return OpenVINOKerasTensor(result.output(0))
|
|
1161
|
+
|
|
1162
|
+
|
|
1163
|
+
def rot90(array, k=1, axes=(0, 1)):
|
|
1164
|
+
"""Rotate an array by 90 degrees in the plane specified by axes."""
|
|
1165
|
+
array = get_ov_output(array)
|
|
1166
|
+
|
|
1167
|
+
if not isinstance(axes, (tuple, list)) or len(axes) != 2:
|
|
1168
|
+
raise ValueError("axes must be a tuple of length 2")
|
|
1169
|
+
|
|
1170
|
+
shape = array.get_partial_shape()
|
|
1171
|
+
ndim = shape.rank.get_length()
|
|
1172
|
+
if ndim is None:
|
|
1173
|
+
raise ValueError(
|
|
1174
|
+
"`rot90` does not support tensors with dynamic rank "
|
|
1175
|
+
"for the OpenVINO backend."
|
|
1176
|
+
)
|
|
1177
|
+
|
|
1178
|
+
axis1 = canonicalize_axis(axes[0], ndim)
|
|
1179
|
+
axis2 = canonicalize_axis(axes[1], ndim)
|
|
1180
|
+
|
|
1181
|
+
if axis1 == axis2:
|
|
1182
|
+
raise ValueError("axes must be different")
|
|
1183
|
+
|
|
1184
|
+
k = k % 4
|
|
1185
|
+
if k == 0:
|
|
1186
|
+
return OpenVINOKerasTensor(array)
|
|
1187
|
+
|
|
1188
|
+
result = array
|
|
1189
|
+
|
|
1190
|
+
for _ in range(k):
|
|
1191
|
+
# 1️ Transpose axis1 <-> axis2
|
|
1192
|
+
perm = list(range(ndim))
|
|
1193
|
+
perm[axis1], perm[axis2] = perm[axis2], perm[axis1]
|
|
1194
|
+
perm_const = ov_opset.constant(perm, Type.i32).output(0)
|
|
1195
|
+
result = ov_opset.transpose(result, perm_const).output(0)
|
|
1196
|
+
|
|
1197
|
+
# 2️ Reverse along axis1 using StridedSlice
|
|
1198
|
+
begin = [0] * ndim
|
|
1199
|
+
end = [0] * ndim
|
|
1200
|
+
strides = [1] * ndim
|
|
1201
|
+
strides[axis1] = -1
|
|
1202
|
+
|
|
1203
|
+
begin_mask = [1] * ndim
|
|
1204
|
+
end_mask = [1] * ndim
|
|
1205
|
+
|
|
1206
|
+
result = ov_opset.strided_slice(
|
|
1207
|
+
data=result,
|
|
1208
|
+
begin=begin,
|
|
1209
|
+
end=end,
|
|
1210
|
+
strides=strides,
|
|
1211
|
+
begin_mask=begin_mask,
|
|
1212
|
+
end_mask=end_mask,
|
|
1213
|
+
).output(0)
|
|
1214
|
+
|
|
1215
|
+
return OpenVINOKerasTensor(result)
|
|
835
1216
|
|
|
836
1217
|
|
|
837
1218
|
def floor(x):
|
|
838
1219
|
x = get_ov_output(x)
|
|
1220
|
+
x_type = x.get_element_type()
|
|
1221
|
+
if x_type.is_integral():
|
|
1222
|
+
x = ov_opset.convert(x, OPENVINO_DTYPES[config.floatx()])
|
|
839
1223
|
return OpenVINOKerasTensor(ov_opset.floor(x).output(0))
|
|
840
1224
|
|
|
841
1225
|
|
|
@@ -907,7 +1291,34 @@ def hstack(xs):
|
|
|
907
1291
|
|
|
908
1292
|
|
|
909
1293
|
def hypot(x1, x2):
|
|
910
|
-
|
|
1294
|
+
element_type = None
|
|
1295
|
+
if isinstance(x1, OpenVINOKerasTensor):
|
|
1296
|
+
element_type = x1.output.get_element_type()
|
|
1297
|
+
if isinstance(x2, OpenVINOKerasTensor):
|
|
1298
|
+
element_type = x2.output.get_element_type()
|
|
1299
|
+
x1 = get_ov_output(x1, element_type)
|
|
1300
|
+
x2 = get_ov_output(x2, element_type)
|
|
1301
|
+
x1, x2 = _align_operand_types(x1, x2, "hypot()")
|
|
1302
|
+
x_type = x1.get_element_type()
|
|
1303
|
+
if x_type.is_integral() or x_type == Type.boolean:
|
|
1304
|
+
ov_type = OPENVINO_DTYPES[config.floatx()]
|
|
1305
|
+
x1 = ov_opset.convert(x1, ov_type)
|
|
1306
|
+
x2 = ov_opset.convert(x2, ov_type)
|
|
1307
|
+
x1_abs = ov_opset.absolute(x1)
|
|
1308
|
+
x2_abs = ov_opset.absolute(x2)
|
|
1309
|
+
max_val = ov_opset.maximum(x1_abs, x2_abs)
|
|
1310
|
+
min_val = ov_opset.minimum(x1_abs, x2_abs)
|
|
1311
|
+
one = ov_opset.constant(1, max_val.get_element_type())
|
|
1312
|
+
is_zero_mask = ov_opset.equal(
|
|
1313
|
+
max_val, ov_opset.constant(0, max_val.get_element_type())
|
|
1314
|
+
)
|
|
1315
|
+
safe_divisor = ov_opset.select(is_zero_mask, one, max_val)
|
|
1316
|
+
ratio = ov_opset.divide(min_val, safe_divisor)
|
|
1317
|
+
result = ov_opset.multiply(
|
|
1318
|
+
max_val,
|
|
1319
|
+
ov_opset.sqrt(ov_opset.add(one, ov_opset.multiply(ratio, ratio))),
|
|
1320
|
+
)
|
|
1321
|
+
return OpenVINOKerasTensor(result.output(0))
|
|
911
1322
|
|
|
912
1323
|
|
|
913
1324
|
def identity(n, dtype=None):
|
|
@@ -948,66 +1359,324 @@ def isclose(x1, x2, rtol=1e-5, atol=1e-8, equal_nan=False):
|
|
|
948
1359
|
|
|
949
1360
|
|
|
950
1361
|
def isfinite(x):
|
|
951
|
-
|
|
952
|
-
|
|
1362
|
+
# NOTE: openvino has an is_finite operation but it does not properly
|
|
1363
|
+
# catch np.inf and -np.inf as not finite values. Hence we bootstrap here. If
|
|
1364
|
+
# that ever changes, we could simplify this to just call that operation.
|
|
1365
|
+
inf_values = get_ov_output(isinf(x))
|
|
1366
|
+
nan_values = get_ov_output(isnan(x))
|
|
1367
|
+
all_non_finite_values = ov_opset.logical_or(inf_values, nan_values).output(
|
|
1368
|
+
0
|
|
1369
|
+
)
|
|
1370
|
+
is_finite = ov_opset.logical_not(all_non_finite_values).output(0)
|
|
1371
|
+
return OpenVINOKerasTensor(is_finite)
|
|
953
1372
|
|
|
954
1373
|
|
|
955
1374
|
def isin(x1, x2, assume_unique=False, invert=False):
|
|
956
|
-
|
|
1375
|
+
x1 = get_ov_output(x1)
|
|
1376
|
+
x2 = get_ov_output(x2)
|
|
1377
|
+
output_shape = ov_opset.shape_of(x1).output(0)
|
|
1378
|
+
x1, x2 = _align_operand_types(x1, x2, "isin()")
|
|
1379
|
+
|
|
1380
|
+
minus_one = ov_opset.constant([-1], dtype=Type.i64)
|
|
1381
|
+
x1 = ov_opset.reshape(x1, minus_one, special_zero=False).output(0)
|
|
1382
|
+
x2 = ov_opset.reshape(x2, minus_one, special_zero=False).output(0)
|
|
1383
|
+
if not assume_unique:
|
|
1384
|
+
x2 = ov_opset.unique(x2).output(0)
|
|
1385
|
+
x1 = ov_opset.unsqueeze(x1, 1).output(0)
|
|
1386
|
+
x2 = ov_opset.unsqueeze(x2, 0).output(0)
|
|
1387
|
+
cmp = ov_opset.equal(x1, x2).output(0)
|
|
1388
|
+
result_flat = ov_opset.reduce_logical_or(cmp, 1).output(0)
|
|
1389
|
+
|
|
1390
|
+
if invert:
|
|
1391
|
+
result_flat = ov_opset.logical_not(result_flat).output(0)
|
|
1392
|
+
result = ov_opset.reshape(result_flat, output_shape, False).output(0)
|
|
1393
|
+
return OpenVINOKerasTensor(result)
|
|
957
1394
|
|
|
958
1395
|
|
|
959
1396
|
def isinf(x):
|
|
960
|
-
|
|
961
|
-
|
|
1397
|
+
pos_inf = get_ov_output(isposinf(x))
|
|
1398
|
+
neg_inf = get_ov_output(isneginf(x))
|
|
1399
|
+
inf = ov_opset.logical_or(pos_inf, neg_inf).output(0)
|
|
1400
|
+
return OpenVINOKerasTensor(inf)
|
|
962
1401
|
|
|
963
1402
|
|
|
964
1403
|
def isnan(x):
|
|
965
1404
|
x = get_ov_output(x)
|
|
1405
|
+
x_type = x.get_element_type()
|
|
1406
|
+
if x_type.is_integral():
|
|
1407
|
+
x = ov_opset.convert(x, OPENVINO_DTYPES[config.floatx()])
|
|
966
1408
|
return OpenVINOKerasTensor(ov_opset.is_nan(x).output(0))
|
|
967
1409
|
|
|
968
1410
|
|
|
969
1411
|
def isneginf(x):
|
|
970
|
-
|
|
971
|
-
"`isneginf` is not supported with openvino backend"
|
|
972
|
-
)
|
|
1412
|
+
return _is_inf(x, pos=False)
|
|
973
1413
|
|
|
974
1414
|
|
|
975
1415
|
def isposinf(x):
|
|
976
|
-
|
|
977
|
-
"`isposinf` is not supported with openvino backend"
|
|
978
|
-
)
|
|
979
|
-
|
|
1416
|
+
return _is_inf(x)
|
|
980
1417
|
|
|
981
|
-
def less(x1, x2):
|
|
982
|
-
element_type = None
|
|
983
|
-
if isinstance(x1, OpenVINOKerasTensor):
|
|
984
|
-
element_type = x1.output.get_element_type()
|
|
985
|
-
if isinstance(x2, OpenVINOKerasTensor):
|
|
986
|
-
element_type = x2.output.get_element_type()
|
|
987
|
-
x1 = get_ov_output(x1, element_type)
|
|
988
|
-
x2 = get_ov_output(x2, element_type)
|
|
989
|
-
x1, x2 = _align_operand_types(x1, x2, "less()")
|
|
990
|
-
return OpenVINOKerasTensor(ov_opset.less(x1, x2).output(0))
|
|
991
1418
|
|
|
1419
|
+
def _is_inf(x, pos=True):
|
|
1420
|
+
# NOTE: there is an ov_opset.is_inf but it does not catch
|
|
1421
|
+
# numpy infinite values like np.inf and -np.inf, hence why we have this
|
|
1422
|
+
# if this ever changes in OpenVINO, we can do this instead:
|
|
1423
|
+
# ov_opset.is_inf(x, {"detect_positive": pos, "detect_negative": not pos})
|
|
1424
|
+
# for each infinite sign
|
|
1425
|
+
inf_value = np.inf if pos else -np.inf
|
|
1426
|
+
x = get_ov_output(x)
|
|
1427
|
+
x_type = x.get_element_type()
|
|
992
1428
|
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1429
|
+
if x_type.is_integral() or x_type == Type.boolean:
|
|
1430
|
+
shape = ov_opset.shape_of(x, "i32").output(0)
|
|
1431
|
+
false_const = ov_opset.constant(False, Type.boolean).output(0)
|
|
1432
|
+
return OpenVINOKerasTensor(
|
|
1433
|
+
ov_opset.broadcast(false_const, shape).output(0)
|
|
1434
|
+
)
|
|
1435
|
+
|
|
1436
|
+
if x_type == Type.bf16:
|
|
1437
|
+
x_f32 = ov_opset.convert(x, Type.f32).output(0)
|
|
1438
|
+
inf = ov_opset.constant(inf_value, Type.f32).output(0)
|
|
1439
|
+
is_inf = ov_opset.equal(x_f32, inf).output(0)
|
|
1440
|
+
else:
|
|
1441
|
+
if x_type == Type.f16:
|
|
1442
|
+
inf = ov_opset.constant(inf_value, Type.f16).output(0)
|
|
1443
|
+
elif x_type == Type.f32:
|
|
1444
|
+
inf = ov_opset.constant(inf_value, Type.f32).output(0)
|
|
1445
|
+
elif x_type == Type.f64:
|
|
1446
|
+
inf = ov_opset.constant(inf_value, Type.f64).output(0)
|
|
1447
|
+
else:
|
|
1448
|
+
inf = ov_opset.constant(inf_value, Type.f32).output(0)
|
|
1449
|
+
is_inf = ov_opset.equal(x, inf).output(0)
|
|
1450
|
+
return OpenVINOKerasTensor(is_inf)
|
|
1451
|
+
|
|
1452
|
+
|
|
1453
|
+
def isreal(x):
|
|
1454
|
+
raise NotImplementedError("`isreal` is not supported with openvino backend")
|
|
1455
|
+
|
|
1456
|
+
|
|
1457
|
+
def kron(x1, x2):
|
|
1458
|
+
x1 = get_ov_output(x1)
|
|
1459
|
+
x2 = get_ov_output(x2)
|
|
1460
|
+
x1, x2 = _align_operand_types(x1, x2, "kron()")
|
|
1461
|
+
x1_shape = x1.get_partial_shape()
|
|
1462
|
+
x2_shape = x2.get_partial_shape()
|
|
1463
|
+
if x1_shape.rank.is_dynamic or x2_shape.rank.is_dynamic:
|
|
1464
|
+
raise ValueError(
|
|
1465
|
+
"`kron` does not support tensors with dynamic rank for "
|
|
1466
|
+
"the OpenVINO backend."
|
|
1467
|
+
)
|
|
1468
|
+
ndim1 = x1_shape.rank.get_length()
|
|
1469
|
+
ndim2 = x2_shape.rank.get_length()
|
|
1470
|
+
if ndim1 < ndim2:
|
|
1471
|
+
axes = ov_opset.range(
|
|
1472
|
+
ov_opset.constant(0, Type.i32),
|
|
1473
|
+
ov_opset.constant(ndim2 - ndim1, Type.i32),
|
|
1474
|
+
ov_opset.constant(1, Type.i32),
|
|
1475
|
+
)
|
|
1476
|
+
x1 = ov_opset.unsqueeze(x1, axes)
|
|
1477
|
+
ndim1 = ndim2
|
|
1478
|
+
elif ndim2 < ndim1:
|
|
1479
|
+
axes = ov_opset.range(
|
|
1480
|
+
ov_opset.constant(0, Type.i32),
|
|
1481
|
+
ov_opset.constant(ndim1 - ndim2, Type.i32),
|
|
1482
|
+
ov_opset.constant(1, Type.i32),
|
|
1483
|
+
)
|
|
1484
|
+
x2 = ov_opset.unsqueeze(x2, axes)
|
|
1485
|
+
ndim2 = ndim1
|
|
1486
|
+
shape1 = ov_opset.shape_of(x1, Type.i32)
|
|
1487
|
+
shape2 = ov_opset.shape_of(x2, Type.i32)
|
|
1488
|
+
ones = ov_opset.broadcast(
|
|
1489
|
+
ov_opset.constant(1, Type.i32), ov_opset.constant([ndim1], Type.i32)
|
|
1490
|
+
)
|
|
1491
|
+
axis = ov_opset.constant(1, Type.i32)
|
|
1492
|
+
flatten = ov_opset.constant([-1], Type.i32)
|
|
1493
|
+
unsqueezed_ones = ov_opset.unsqueeze(ones, axis)
|
|
1494
|
+
x1_new_shape = ov_opset.reshape(
|
|
1495
|
+
ov_opset.concat(
|
|
1496
|
+
[ov_opset.unsqueeze(shape1, axis), unsqueezed_ones],
|
|
1497
|
+
axis=1,
|
|
1498
|
+
),
|
|
1499
|
+
flatten,
|
|
1500
|
+
False,
|
|
1501
|
+
)
|
|
1502
|
+
x2_new_shape = ov_opset.reshape(
|
|
1503
|
+
ov_opset.concat(
|
|
1504
|
+
[unsqueezed_ones, ov_opset.unsqueeze(shape2, axis)],
|
|
1505
|
+
axis=1,
|
|
1506
|
+
),
|
|
1507
|
+
flatten,
|
|
1508
|
+
False,
|
|
1509
|
+
)
|
|
1510
|
+
result = ov_opset.multiply(
|
|
1511
|
+
ov_opset.reshape(x1, x1_new_shape, False),
|
|
1512
|
+
ov_opset.reshape(x2, x2_new_shape, False),
|
|
1513
|
+
)
|
|
1514
|
+
result = ov_opset.reshape(
|
|
1515
|
+
result, ov_opset.multiply(shape1, shape2), False
|
|
1516
|
+
).output(0)
|
|
1517
|
+
return OpenVINOKerasTensor(result)
|
|
1518
|
+
|
|
1519
|
+
|
|
1520
|
+
def lcm(x1, x2):
|
|
1521
|
+
raise NotImplementedError("`lcm` is not supported with openvino backend")
|
|
1522
|
+
|
|
1523
|
+
|
|
1524
|
+
def ldexp(x1, x2):
|
|
1525
|
+
raise NotImplementedError("`ldexp` is not supported with openvino backend")
|
|
1526
|
+
|
|
1527
|
+
|
|
1528
|
+
def less(x1, x2):
|
|
1529
|
+
element_type = None
|
|
1530
|
+
if isinstance(x1, OpenVINOKerasTensor):
|
|
1531
|
+
element_type = x1.output.get_element_type()
|
|
1532
|
+
if isinstance(x2, OpenVINOKerasTensor):
|
|
1533
|
+
element_type = x2.output.get_element_type()
|
|
1534
|
+
x1 = get_ov_output(x1, element_type)
|
|
1535
|
+
x2 = get_ov_output(x2, element_type)
|
|
1536
|
+
x1, x2 = _align_operand_types(x1, x2, "less()")
|
|
1537
|
+
return OpenVINOKerasTensor(ov_opset.less(x1, x2).output(0))
|
|
1538
|
+
|
|
1539
|
+
|
|
1540
|
+
def less_equal(x1, x2):
|
|
1541
|
+
element_type = None
|
|
1542
|
+
if isinstance(x1, OpenVINOKerasTensor):
|
|
1543
|
+
element_type = x1.output.get_element_type()
|
|
1544
|
+
if isinstance(x2, OpenVINOKerasTensor):
|
|
1545
|
+
element_type = x2.output.get_element_type()
|
|
1546
|
+
x1 = get_ov_output(x1, element_type)
|
|
1547
|
+
x2 = get_ov_output(x2, element_type)
|
|
1548
|
+
x1, x2 = _align_operand_types(x1, x2, "less_equal()")
|
|
1549
|
+
return OpenVINOKerasTensor(ov_opset.less_equal(x1, x2).output(0))
|
|
1003
1550
|
|
|
1004
1551
|
|
|
1005
1552
|
def linspace(
|
|
1006
1553
|
start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis=0
|
|
1007
1554
|
):
|
|
1008
|
-
|
|
1009
|
-
|
|
1555
|
+
"""Return evenly spaced numbers over a specified interval.
|
|
1556
|
+
|
|
1557
|
+
Supports axis=0 (prepend) and axis=-1 (append). Intermediate axis values are
|
|
1558
|
+
treated as axis=-1.
|
|
1559
|
+
|
|
1560
|
+
If `retstep` is True, also returns the step size between values.
|
|
1561
|
+
|
|
1562
|
+
"""
|
|
1563
|
+
|
|
1564
|
+
start = get_ov_output(start)
|
|
1565
|
+
stop = get_ov_output(stop)
|
|
1566
|
+
|
|
1567
|
+
if hasattr(num, "output") or isinstance(num, OpenVINOKerasTensor):
|
|
1568
|
+
num_tensor = get_ov_output(num)
|
|
1569
|
+
try:
|
|
1570
|
+
if num_tensor.get_node().get_type_name() == "Constant":
|
|
1571
|
+
num_value = num_tensor.get_node().get_vector()[0]
|
|
1572
|
+
num = int(num_value)
|
|
1573
|
+
else:
|
|
1574
|
+
raise NotImplementedError(
|
|
1575
|
+
"Dynamic num values not fully supported"
|
|
1576
|
+
)
|
|
1577
|
+
except Exception as e:
|
|
1578
|
+
raise NotImplementedError(
|
|
1579
|
+
"Could not extract num value from tensor"
|
|
1580
|
+
) from e
|
|
1581
|
+
else:
|
|
1582
|
+
num = int(num)
|
|
1583
|
+
|
|
1584
|
+
if dtype is None:
|
|
1585
|
+
output_type = OPENVINO_DTYPES[config.floatx()]
|
|
1586
|
+
else:
|
|
1587
|
+
output_type = OPENVINO_DTYPES[dtype]
|
|
1588
|
+
|
|
1589
|
+
start = ov_opset.convert(start, output_type).output(0)
|
|
1590
|
+
stop = ov_opset.convert(stop, output_type).output(0)
|
|
1591
|
+
|
|
1592
|
+
if num < 0:
|
|
1593
|
+
raise ValueError("Number of samples, `num`, must be non-negative.")
|
|
1594
|
+
|
|
1595
|
+
if num == 0:
|
|
1596
|
+
empty_shape = ov_opset.constant([0], Type.i32).output(0)
|
|
1597
|
+
result = ov_opset.broadcast(
|
|
1598
|
+
ov_opset.constant(0.0, output_type).output(0), empty_shape
|
|
1599
|
+
).output(0)
|
|
1600
|
+
if retstep:
|
|
1601
|
+
nan_step = ov_opset.constant(np.nan, output_type).output(0)
|
|
1602
|
+
return OpenVINOKerasTensor(result), OpenVINOKerasTensor(nan_step)
|
|
1603
|
+
return OpenVINOKerasTensor(result)
|
|
1604
|
+
|
|
1605
|
+
if num == 1:
|
|
1606
|
+
result_val = start
|
|
1607
|
+
axis_const = ov_opset.constant([axis], Type.i32).output(0)
|
|
1608
|
+
result = ov_opset.unsqueeze(result_val, axis_const).output(0)
|
|
1609
|
+
if retstep:
|
|
1610
|
+
if endpoint:
|
|
1611
|
+
step = ov_opset.constant(np.nan, output_type).output(0)
|
|
1612
|
+
else:
|
|
1613
|
+
step = ov_opset.subtract(stop, start).output(0)
|
|
1614
|
+
return OpenVINOKerasTensor(result), OpenVINOKerasTensor(step)
|
|
1615
|
+
zero_i32 = ov_opset.constant(0, Type.i32).output(0)
|
|
1616
|
+
one_i32 = ov_opset.constant(1, Type.i32).output(0)
|
|
1617
|
+
one_i32_array = ov_opset.constant([1], Type.i32).output(0)
|
|
1618
|
+
|
|
1619
|
+
num_const = ov_opset.constant(num, output_type).output(0)
|
|
1620
|
+
|
|
1621
|
+
if endpoint:
|
|
1622
|
+
divisor = ov_opset.subtract(
|
|
1623
|
+
num_const, ov_opset.constant(1, output_type).output(0)
|
|
1624
|
+
).output(0)
|
|
1625
|
+
else:
|
|
1626
|
+
divisor = num_const
|
|
1627
|
+
|
|
1628
|
+
step = ov_opset.divide(
|
|
1629
|
+
ov_opset.subtract(stop, start).output(0), divisor
|
|
1630
|
+
).output(0)
|
|
1631
|
+
|
|
1632
|
+
indices = ov_opset.range(
|
|
1633
|
+
zero_i32,
|
|
1634
|
+
ov_opset.constant(num, Type.i32).output(0),
|
|
1635
|
+
one_i32,
|
|
1636
|
+
output_type,
|
|
1637
|
+
).output(0)
|
|
1638
|
+
|
|
1639
|
+
start_shape = ov_opset.convert(
|
|
1640
|
+
ov_opset.shape_of(start).output(0), Type.i32
|
|
1641
|
+
).output(0)
|
|
1642
|
+
indices_shape = ov_opset.convert(
|
|
1643
|
+
ov_opset.shape_of(indices).output(0), Type.i32
|
|
1644
|
+
).output(0)
|
|
1645
|
+
|
|
1646
|
+
start_rank = ov_opset.shape_of(start_shape).output(0)
|
|
1647
|
+
ones_for_start = ov_opset.broadcast(one_i32, start_rank).output(0)
|
|
1648
|
+
|
|
1649
|
+
if axis == 0:
|
|
1650
|
+
indices_target_shape = ov_opset.concat(
|
|
1651
|
+
[indices_shape, ones_for_start], 0
|
|
1652
|
+
).output(0)
|
|
1653
|
+
start_target_shape = ov_opset.concat(
|
|
1654
|
+
[one_i32_array, start_shape], 0
|
|
1655
|
+
).output(0)
|
|
1656
|
+
else:
|
|
1657
|
+
indices_target_shape = ov_opset.concat(
|
|
1658
|
+
[ones_for_start, indices_shape], 0
|
|
1659
|
+
).output(0)
|
|
1660
|
+
start_target_shape = ov_opset.concat(
|
|
1661
|
+
[start_shape, one_i32_array], 0
|
|
1662
|
+
).output(0)
|
|
1663
|
+
|
|
1664
|
+
indices_reshaped = ov_opset.reshape(
|
|
1665
|
+
indices, indices_target_shape, False
|
|
1666
|
+
).output(0)
|
|
1667
|
+
start_reshaped = ov_opset.reshape(start, start_target_shape, False).output(
|
|
1668
|
+
0
|
|
1010
1669
|
)
|
|
1670
|
+
step_reshaped = ov_opset.reshape(step, start_target_shape, False).output(0)
|
|
1671
|
+
|
|
1672
|
+
scaled_indices = ov_opset.multiply(indices_reshaped, step_reshaped).output(
|
|
1673
|
+
0
|
|
1674
|
+
)
|
|
1675
|
+
result = ov_opset.add(start_reshaped, scaled_indices).output(0)
|
|
1676
|
+
|
|
1677
|
+
if retstep:
|
|
1678
|
+
return OpenVINOKerasTensor(result), OpenVINOKerasTensor(step)
|
|
1679
|
+
return OpenVINOKerasTensor(result)
|
|
1011
1680
|
|
|
1012
1681
|
|
|
1013
1682
|
def log(x):
|
|
@@ -1060,8 +1729,58 @@ def log2(x):
|
|
|
1060
1729
|
|
|
1061
1730
|
|
|
1062
1731
|
def logaddexp(x1, x2):
|
|
1732
|
+
element_type = None
|
|
1733
|
+
if isinstance(x1, OpenVINOKerasTensor):
|
|
1734
|
+
element_type = x1.output.get_element_type()
|
|
1735
|
+
if isinstance(x2, OpenVINOKerasTensor):
|
|
1736
|
+
element_type = x2.output.get_element_type()
|
|
1737
|
+
x1 = get_ov_output(x1, element_type)
|
|
1738
|
+
x2 = get_ov_output(x2, element_type)
|
|
1739
|
+
x1, x2 = _align_operand_types(x1, x2, "logaddexp()")
|
|
1740
|
+
|
|
1741
|
+
if x1.element_type.is_integral() or x2.element_type.is_integral():
|
|
1742
|
+
float_dtype = OPENVINO_DTYPES[config.floatx()]
|
|
1743
|
+
if x1.element_type.is_integral():
|
|
1744
|
+
x1 = ov_opset.convert(x1, float_dtype)
|
|
1745
|
+
if x2.element_type.is_integral():
|
|
1746
|
+
x2 = ov_opset.convert(x2, float_dtype)
|
|
1747
|
+
|
|
1748
|
+
# Get the output nodes properly
|
|
1749
|
+
max_val_node = ov_opset.maximum(x1, x2)
|
|
1750
|
+
max_val = max_val_node.output(0)
|
|
1751
|
+
|
|
1752
|
+
# Compute absolute difference
|
|
1753
|
+
sub_node = ov_opset.subtract(x1, x2)
|
|
1754
|
+
abs_diff_node = ov_opset.abs(sub_node.output(0))
|
|
1755
|
+
abs_diff = abs_diff_node.output(0)
|
|
1756
|
+
|
|
1757
|
+
# Compute negative absolute difference and its exponential
|
|
1758
|
+
neg_abs_diff_node = ov_opset.negative(abs_diff)
|
|
1759
|
+
neg_abs_diff = neg_abs_diff_node.output(0)
|
|
1760
|
+
exp_neg_abs_node = ov_opset.exp(neg_abs_diff)
|
|
1761
|
+
exp_neg_abs = exp_neg_abs_node.output(0)
|
|
1762
|
+
|
|
1763
|
+
# Get the element type from the node, not the output
|
|
1764
|
+
element_type = exp_neg_abs_node.get_element_type()
|
|
1765
|
+
one_node = ov_opset.constant(1, element_type)
|
|
1766
|
+
one = one_node.output(0)
|
|
1767
|
+
|
|
1768
|
+
# Compute log term
|
|
1769
|
+
one_plus_exp_node = ov_opset.add(one, exp_neg_abs)
|
|
1770
|
+
one_plus_exp = one_plus_exp_node.output(0)
|
|
1771
|
+
log_term_node = ov_opset.log(one_plus_exp)
|
|
1772
|
+
log_term = log_term_node.output(0)
|
|
1773
|
+
|
|
1774
|
+
# Final result
|
|
1775
|
+
result_node = ov_opset.add(max_val, log_term)
|
|
1776
|
+
result = result_node.output(0)
|
|
1777
|
+
|
|
1778
|
+
return OpenVINOKerasTensor(result)
|
|
1779
|
+
|
|
1780
|
+
|
|
1781
|
+
def logaddexp2(x1, x2):
|
|
1063
1782
|
raise NotImplementedError(
|
|
1064
|
-
"`
|
|
1783
|
+
"`logaddexp2` is not supported with openvino backend"
|
|
1065
1784
|
)
|
|
1066
1785
|
|
|
1067
1786
|
|
|
@@ -1088,10 +1807,30 @@ def logical_or(x1, x2):
|
|
|
1088
1807
|
|
|
1089
1808
|
|
|
1090
1809
|
def logspace(start, stop, num=50, endpoint=True, base=10, dtype=None, axis=0):
|
|
1091
|
-
|
|
1092
|
-
|
|
1810
|
+
linear_samples = linspace(
|
|
1811
|
+
start=start,
|
|
1812
|
+
stop=stop,
|
|
1813
|
+
num=num,
|
|
1814
|
+
endpoint=endpoint,
|
|
1815
|
+
retstep=False,
|
|
1816
|
+
dtype=dtype,
|
|
1817
|
+
axis=axis,
|
|
1093
1818
|
)
|
|
1094
1819
|
|
|
1820
|
+
if dtype is None:
|
|
1821
|
+
output_type = OPENVINO_DTYPES[config.floatx()]
|
|
1822
|
+
else:
|
|
1823
|
+
output_type = OPENVINO_DTYPES[dtype]
|
|
1824
|
+
|
|
1825
|
+
linear_output = get_ov_output(linear_samples)
|
|
1826
|
+
base_tensor = get_ov_output(base)
|
|
1827
|
+
|
|
1828
|
+
base_tensor = ov_opset.convert(base_tensor, output_type).output(0)
|
|
1829
|
+
|
|
1830
|
+
result = ov_opset.power(base_tensor, linear_output).output(0)
|
|
1831
|
+
|
|
1832
|
+
return OpenVINOKerasTensor(result)
|
|
1833
|
+
|
|
1095
1834
|
|
|
1096
1835
|
def maximum(x1, x2):
|
|
1097
1836
|
x1 = get_ov_output(x1)
|
|
@@ -1101,7 +1840,138 @@ def maximum(x1, x2):
|
|
|
1101
1840
|
|
|
1102
1841
|
|
|
1103
1842
|
def median(x, axis=None, keepdims=False):
|
|
1104
|
-
|
|
1843
|
+
x = get_ov_output(x)
|
|
1844
|
+
x_shape = x.get_partial_shape()
|
|
1845
|
+
rank = x_shape.rank.get_length()
|
|
1846
|
+
|
|
1847
|
+
if rank == 0:
|
|
1848
|
+
return OpenVINOKerasTensor(x)
|
|
1849
|
+
|
|
1850
|
+
# Handle axis=None by flattening the input
|
|
1851
|
+
flattened_all = False
|
|
1852
|
+
if axis is None:
|
|
1853
|
+
x = ov_opset.reshape(x, [-1], False).output(0)
|
|
1854
|
+
axis = 0
|
|
1855
|
+
original_rank = rank
|
|
1856
|
+
rank = 1
|
|
1857
|
+
flattened_all = True
|
|
1858
|
+
else:
|
|
1859
|
+
# Handle tuple axis - for median, we only support single axis
|
|
1860
|
+
if isinstance(axis, (tuple, list)):
|
|
1861
|
+
if len(axis) != 1:
|
|
1862
|
+
raise ValueError("median only supports single axis reduction")
|
|
1863
|
+
axis = axis[0]
|
|
1864
|
+
|
|
1865
|
+
# Handle negative axis
|
|
1866
|
+
if axis < 0:
|
|
1867
|
+
axis = rank + axis
|
|
1868
|
+
original_rank = rank
|
|
1869
|
+
|
|
1870
|
+
# Get the size of the dimension to sort
|
|
1871
|
+
shape_tensor = ov_opset.shape_of(x, output_type=Type.i32).output(0)
|
|
1872
|
+
k = ov_opset.gather(
|
|
1873
|
+
shape_tensor,
|
|
1874
|
+
ov_opset.constant([axis], Type.i32).output(0),
|
|
1875
|
+
ov_opset.constant(0, Type.i32).output(0),
|
|
1876
|
+
).output(0)
|
|
1877
|
+
|
|
1878
|
+
# Convert k to a scalar value
|
|
1879
|
+
k_scalar = ov_opset.squeeze(k, [0]).output(0)
|
|
1880
|
+
|
|
1881
|
+
# Use topk with k=size_of_axis to get all elements sorted
|
|
1882
|
+
topk_outputs = ov_opset.topk(
|
|
1883
|
+
x, k=k_scalar, axis=axis, mode="min", sort="value", stable=True
|
|
1884
|
+
)
|
|
1885
|
+
|
|
1886
|
+
# Get the sorted values
|
|
1887
|
+
sorted_values = topk_outputs.output(0)
|
|
1888
|
+
|
|
1889
|
+
# Convert to float for median calculation
|
|
1890
|
+
x1_type = ov_to_keras_type(sorted_values.get_element_type())
|
|
1891
|
+
result_type = dtypes.result_type(x1_type, float)
|
|
1892
|
+
result_type = OPENVINO_DTYPES[result_type]
|
|
1893
|
+
sorted_values = ov_opset.convert(sorted_values, result_type).output(0)
|
|
1894
|
+
|
|
1895
|
+
# Calculate median indices
|
|
1896
|
+
# For odd length: median_idx = (k-1) // 2
|
|
1897
|
+
# For even length: we need indices (k//2 - 1) and k//2, then average
|
|
1898
|
+
|
|
1899
|
+
k_minus_1 = ov_opset.subtract(
|
|
1900
|
+
k_scalar, ov_opset.constant(1, Type.i32).output(0)
|
|
1901
|
+
).output(0)
|
|
1902
|
+
k_div_2 = ov_opset.divide(
|
|
1903
|
+
k_scalar, ov_opset.constant(2, Type.i32).output(0)
|
|
1904
|
+
).output(0)
|
|
1905
|
+
k_minus_1_div_2 = ov_opset.divide(
|
|
1906
|
+
k_minus_1, ov_opset.constant(2, Type.i32).output(0)
|
|
1907
|
+
).output(0)
|
|
1908
|
+
|
|
1909
|
+
# Check if k is odd
|
|
1910
|
+
k_mod_2 = ov_opset.mod(
|
|
1911
|
+
k_scalar, ov_opset.constant(2, Type.i32).output(0)
|
|
1912
|
+
).output(0)
|
|
1913
|
+
is_odd = ov_opset.equal(
|
|
1914
|
+
k_mod_2, ov_opset.constant(1, Type.i32).output(0)
|
|
1915
|
+
).output(0)
|
|
1916
|
+
|
|
1917
|
+
# For odd case: take the middle element
|
|
1918
|
+
odd_idx = k_minus_1_div_2
|
|
1919
|
+
|
|
1920
|
+
# For even case: take average of two middle elements
|
|
1921
|
+
even_idx1 = ov_opset.subtract(
|
|
1922
|
+
k_div_2, ov_opset.constant(1, Type.i32).output(0)
|
|
1923
|
+
).output(0)
|
|
1924
|
+
even_idx2 = k_div_2
|
|
1925
|
+
|
|
1926
|
+
# Gather elements for both cases
|
|
1927
|
+
# Create gather indices tensor for the axis
|
|
1928
|
+
gather_indices_odd = ov_opset.unsqueeze(odd_idx, [0]).output(0)
|
|
1929
|
+
gather_indices_even1 = ov_opset.unsqueeze(even_idx1, [0]).output(0)
|
|
1930
|
+
gather_indices_even2 = ov_opset.unsqueeze(even_idx2, [0]).output(0)
|
|
1931
|
+
|
|
1932
|
+
# Gather the median elements
|
|
1933
|
+
odd_result = ov_opset.gather(
|
|
1934
|
+
sorted_values,
|
|
1935
|
+
gather_indices_odd,
|
|
1936
|
+
ov_opset.constant(axis, Type.i32).output(0),
|
|
1937
|
+
).output(0)
|
|
1938
|
+
even_result1 = ov_opset.gather(
|
|
1939
|
+
sorted_values,
|
|
1940
|
+
gather_indices_even1,
|
|
1941
|
+
ov_opset.constant(axis, Type.i32).output(0),
|
|
1942
|
+
).output(0)
|
|
1943
|
+
even_result2 = ov_opset.gather(
|
|
1944
|
+
sorted_values,
|
|
1945
|
+
gather_indices_even2,
|
|
1946
|
+
ov_opset.constant(axis, Type.i32).output(0),
|
|
1947
|
+
).output(0)
|
|
1948
|
+
|
|
1949
|
+
# Average the two middle elements for even case
|
|
1950
|
+
even_sum = ov_opset.add(even_result1, even_result2).output(0)
|
|
1951
|
+
even_result = ov_opset.divide(
|
|
1952
|
+
even_sum, ov_opset.constant(2.0, result_type).output(0)
|
|
1953
|
+
).output(0)
|
|
1954
|
+
|
|
1955
|
+
# Select between odd and even results
|
|
1956
|
+
median_result = ov_opset.select(is_odd, odd_result, even_result).output(0)
|
|
1957
|
+
|
|
1958
|
+
# Remove the gathered dimension (squeeze)
|
|
1959
|
+
median_result = ov_opset.squeeze(median_result, [axis]).output(0)
|
|
1960
|
+
|
|
1961
|
+
# Handle keepdims
|
|
1962
|
+
if keepdims:
|
|
1963
|
+
if flattened_all:
|
|
1964
|
+
# When axis=None, keepdims should restore all dimensions as 1
|
|
1965
|
+
ones_shape = ov_opset.constant(
|
|
1966
|
+
[1] * original_rank, Type.i32
|
|
1967
|
+
).output(0)
|
|
1968
|
+
median_result = ov_opset.reshape(
|
|
1969
|
+
median_result, ones_shape, False
|
|
1970
|
+
).output(0)
|
|
1971
|
+
else:
|
|
1972
|
+
median_result = ov_opset.unsqueeze(median_result, [axis]).output(0)
|
|
1973
|
+
|
|
1974
|
+
return OpenVINOKerasTensor(median_result)
|
|
1105
1975
|
|
|
1106
1976
|
|
|
1107
1977
|
def meshgrid(*x, indexing="xy"):
|
|
@@ -1149,46 +2019,7 @@ def meshgrid(*x, indexing="xy"):
|
|
|
1149
2019
|
|
|
1150
2020
|
|
|
1151
2021
|
def min(x, axis=None, keepdims=False, initial=None):
|
|
1152
|
-
x
|
|
1153
|
-
original_type = x.get_element_type()
|
|
1154
|
-
x_type = original_type
|
|
1155
|
-
x_shape = x.get_partial_shape().to_shape()
|
|
1156
|
-
|
|
1157
|
-
is_bool = x_type == Type.boolean
|
|
1158
|
-
if is_bool:
|
|
1159
|
-
x = ov_opset.convert(x, Type.i32).output(0)
|
|
1160
|
-
x_type = Type.i32
|
|
1161
|
-
|
|
1162
|
-
if isinstance(axis, tuple) and len(axis) == 0:
|
|
1163
|
-
return OpenVINOKerasTensor(x)
|
|
1164
|
-
|
|
1165
|
-
if axis is None:
|
|
1166
|
-
flatten_shape = ov_opset.constant([-1], Type.i32).output(0)
|
|
1167
|
-
x = ov_opset.reshape(x, flatten_shape, False).output(0)
|
|
1168
|
-
axis = 0
|
|
1169
|
-
|
|
1170
|
-
if isinstance(axis, tuple):
|
|
1171
|
-
axis = list(axis)
|
|
1172
|
-
|
|
1173
|
-
axis_const = ov_opset.constant(axis, Type.i32).output(0)
|
|
1174
|
-
min_result = ov_opset.reduce_min(x, axis_const, keepdims).output(0)
|
|
1175
|
-
|
|
1176
|
-
if initial is not None:
|
|
1177
|
-
initial_tensor = ov_opset.constant(initial, x_type).output(0)
|
|
1178
|
-
min_result = ov_opset.minimum(min_result, initial_tensor).output(0)
|
|
1179
|
-
|
|
1180
|
-
if keepdims:
|
|
1181
|
-
result_shape = [1] * len(x_shape)
|
|
1182
|
-
min_result = ov_opset.reshape(
|
|
1183
|
-
min_result,
|
|
1184
|
-
ov_opset.constant(result_shape, Type.i32).output(0),
|
|
1185
|
-
False,
|
|
1186
|
-
).output(0)
|
|
1187
|
-
|
|
1188
|
-
if is_bool:
|
|
1189
|
-
min_result = ov_opset.convert(min_result, Type.boolean).output(0)
|
|
1190
|
-
|
|
1191
|
-
return OpenVINOKerasTensor(min_result)
|
|
2022
|
+
return _compute_extrema(x, "min", axis, keepdims, initial)
|
|
1192
2023
|
|
|
1193
2024
|
|
|
1194
2025
|
def minimum(x1, x2):
|
|
@@ -1339,7 +2170,9 @@ def pad(x, pad_width, mode="constant", constant_values=None):
|
|
|
1339
2170
|
"`pad` operation supports only scalar pad value "
|
|
1340
2171
|
"in constant mode by openvino backend"
|
|
1341
2172
|
)
|
|
1342
|
-
pad_value =
|
|
2173
|
+
pad_value = ov_opset.constant(
|
|
2174
|
+
constant_values, x.get_element_type()
|
|
2175
|
+
).output(0)
|
|
1343
2176
|
|
|
1344
2177
|
# split pad_width into two tensors pads_begin and pads_end
|
|
1345
2178
|
pads_begin = []
|
|
@@ -1355,7 +2188,26 @@ def pad(x, pad_width, mode="constant", constant_values=None):
|
|
|
1355
2188
|
|
|
1356
2189
|
|
|
1357
2190
|
def prod(x, axis=None, keepdims=False, dtype=None):
|
|
1358
|
-
|
|
2191
|
+
x = get_ov_output(x)
|
|
2192
|
+
|
|
2193
|
+
# If a specific dtype is requested, cast the input to that dtype.
|
|
2194
|
+
if dtype is not None:
|
|
2195
|
+
ov_dtype = OPENVINO_DTYPES[standardize_dtype(dtype)]
|
|
2196
|
+
x = ov_opset.convert(x, ov_dtype).output(0)
|
|
2197
|
+
# Otherwise, apply dtype promotion rules before reduction.
|
|
2198
|
+
else:
|
|
2199
|
+
x = _upcast_type_if_needed(x)
|
|
2200
|
+
x, axis = _resolve_axis(x, axis)
|
|
2201
|
+
if axis is None:
|
|
2202
|
+
return OpenVINOKerasTensor(x)
|
|
2203
|
+
# Compute the product
|
|
2204
|
+
result = ov_opset.reduce_prod(x, axis, keepdims).output(0)
|
|
2205
|
+
|
|
2206
|
+
return OpenVINOKerasTensor(result)
|
|
2207
|
+
|
|
2208
|
+
|
|
2209
|
+
def ptp(x, axis=None, keepdims=False):
|
|
2210
|
+
raise NotImplementedError("`ptp` is not supported with openvino backend")
|
|
1359
2211
|
|
|
1360
2212
|
|
|
1361
2213
|
def quantile(x, q, axis=None, method="linear", keepdims=False):
|
|
@@ -1451,7 +2303,17 @@ def reshape(x, newshape):
|
|
|
1451
2303
|
|
|
1452
2304
|
|
|
1453
2305
|
def roll(x, shift, axis=None):
|
|
1454
|
-
|
|
2306
|
+
x = get_ov_output(x)
|
|
2307
|
+
if axis is not None:
|
|
2308
|
+
result = ov_opset.roll(x, shift, axis).output(0)
|
|
2309
|
+
else:
|
|
2310
|
+
output_shape = ov_opset.shape_of(x).output(0)
|
|
2311
|
+
flattened = ov_opset.reshape(
|
|
2312
|
+
x, ov_opset.constant([-1], Type.i32), False
|
|
2313
|
+
).output(0)
|
|
2314
|
+
result = ov_opset.roll(flattened, shift, 0).output(0)
|
|
2315
|
+
result = ov_opset.reshape(result, output_shape, False).output(0)
|
|
2316
|
+
return OpenVINOKerasTensor(result)
|
|
1455
2317
|
|
|
1456
2318
|
|
|
1457
2319
|
def sign(x):
|
|
@@ -1484,11 +2346,54 @@ def sinh(x):
|
|
|
1484
2346
|
|
|
1485
2347
|
|
|
1486
2348
|
def size(x):
|
|
1487
|
-
|
|
2349
|
+
x = get_ov_output(x)
|
|
2350
|
+
shape_tensor = ov_opset.shape_of(x, output_type=Type.i64)
|
|
2351
|
+
final_size = ov_opset.reduce_prod(
|
|
2352
|
+
shape_tensor,
|
|
2353
|
+
ov_opset.constant([0], Type.i64),
|
|
2354
|
+
keep_dims=False,
|
|
2355
|
+
)
|
|
2356
|
+
return OpenVINOKerasTensor(final_size.output(0))
|
|
1488
2357
|
|
|
1489
2358
|
|
|
1490
2359
|
def sort(x, axis=-1):
|
|
1491
|
-
|
|
2360
|
+
x = get_ov_output(x)
|
|
2361
|
+
x_shape = x.get_partial_shape()
|
|
2362
|
+
rank = x_shape.rank.get_length()
|
|
2363
|
+
|
|
2364
|
+
if rank == 0:
|
|
2365
|
+
return OpenVINOKerasTensor(x)
|
|
2366
|
+
|
|
2367
|
+
# Handle axis=None by flattening the input
|
|
2368
|
+
if axis is None:
|
|
2369
|
+
x = ov_opset.reshape(
|
|
2370
|
+
x, ov_opset.constant([-1], Type.i32), False
|
|
2371
|
+
).output(0)
|
|
2372
|
+
axis = 0
|
|
2373
|
+
# Handle negative axis
|
|
2374
|
+
elif axis < 0:
|
|
2375
|
+
axis = rank + axis
|
|
2376
|
+
|
|
2377
|
+
# Get the size of the dimension to sort
|
|
2378
|
+
shape_tensor = ov_opset.shape_of(x, output_type=Type.i32).output(0)
|
|
2379
|
+
k = ov_opset.gather(
|
|
2380
|
+
shape_tensor,
|
|
2381
|
+
ov_opset.constant([axis], Type.i32).output(0),
|
|
2382
|
+
ov_opset.constant(0, Type.i32).output(0),
|
|
2383
|
+
).output(0)
|
|
2384
|
+
|
|
2385
|
+
# Convert k to a scalar value
|
|
2386
|
+
k_scalar = ov_opset.squeeze(k, ov_opset.constant([0], Type.i32)).output(0)
|
|
2387
|
+
|
|
2388
|
+
# Use topk with k=size_of_axis to get all elements sorted
|
|
2389
|
+
topk_outputs = ov_opset.topk(
|
|
2390
|
+
x, k=k_scalar, axis=axis, mode="min", sort="value", stable=True
|
|
2391
|
+
)
|
|
2392
|
+
|
|
2393
|
+
# Get the sorted values
|
|
2394
|
+
sorted_values = topk_outputs.output(0)
|
|
2395
|
+
|
|
2396
|
+
return OpenVINOKerasTensor(sorted_values)
|
|
1492
2397
|
|
|
1493
2398
|
|
|
1494
2399
|
def split(x, indices_or_sections, axis=0):
|
|
@@ -1537,6 +2442,37 @@ def split(x, indices_or_sections, axis=0):
|
|
|
1537
2442
|
)
|
|
1538
2443
|
|
|
1539
2444
|
|
|
2445
|
+
def array_split(x, indices_or_sections, axis=0):
|
|
2446
|
+
original_shape = x.shape
|
|
2447
|
+
x = get_ov_output(x)
|
|
2448
|
+
|
|
2449
|
+
num_splits_val = indices_or_sections
|
|
2450
|
+
total_size = original_shape[axis]
|
|
2451
|
+
if total_size is None:
|
|
2452
|
+
raise ValueError(
|
|
2453
|
+
f"Cannot use array_split with static Python logic on dynamic axis. "
|
|
2454
|
+
f"Axis {axis} has unknown dimension for shape {original_shape}."
|
|
2455
|
+
)
|
|
2456
|
+
|
|
2457
|
+
base_size = total_size // num_splits_val
|
|
2458
|
+
remainder = total_size % num_splits_val
|
|
2459
|
+
|
|
2460
|
+
split_lengths = [base_size + 1] * remainder + [base_size] * (
|
|
2461
|
+
num_splits_val - remainder
|
|
2462
|
+
)
|
|
2463
|
+
split_lengths_tensor = ov_opset.constant(
|
|
2464
|
+
split_lengths, dtype=Type.i64
|
|
2465
|
+
).output(0)
|
|
2466
|
+
|
|
2467
|
+
axis_tensor = ov_opset.constant(axis, dtype=Type.i32).output(0)
|
|
2468
|
+
splits = ov_opset.variadic_split(x, axis_tensor, split_lengths_tensor)
|
|
2469
|
+
|
|
2470
|
+
result = []
|
|
2471
|
+
for i in range(num_splits_val):
|
|
2472
|
+
result.append(OpenVINOKerasTensor(splits.output(i)))
|
|
2473
|
+
return result
|
|
2474
|
+
|
|
2475
|
+
|
|
1540
2476
|
def stack(x, axis=0):
|
|
1541
2477
|
if isinstance(x, tuple):
|
|
1542
2478
|
x = list(x)
|
|
@@ -1553,28 +2489,26 @@ def stack(x, axis=0):
|
|
|
1553
2489
|
|
|
1554
2490
|
|
|
1555
2491
|
def std(x, axis=None, keepdims=False):
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
x = ov_opset.reshape(x, flatten_shape, False).output(0)
|
|
1560
|
-
axis = 0
|
|
1561
|
-
axis = ov_opset.constant(axis, Type.i32).output(0)
|
|
1562
|
-
# The variance is computed using $Var = E[|x|^2] - |E[x]|^2$, It is faster
|
|
1563
|
-
# but less numerically stable.
|
|
1564
|
-
mean = ov_opset.reduce_mean(x, axis, keepdims).output(0)
|
|
1565
|
-
const_two = ov_opset.constant(2, x.get_element_type()).output(0)
|
|
1566
|
-
squared_x = ov_opset.power(x, const_two).output(0)
|
|
1567
|
-
squared_mean = ov_opset.power(mean, const_two).output(0)
|
|
1568
|
-
squared_x_mean = ov_opset.reduce_mean(squared_x, axis, keepdims)
|
|
1569
|
-
variance = ov_opset.subtract(squared_x_mean, squared_mean).output(0)
|
|
1570
|
-
std_var = OpenVINOKerasTensor(ov_opset.sqrt(variance).output(0))
|
|
1571
|
-
return std_var
|
|
2492
|
+
var_x = var(x, axis, keepdims)
|
|
2493
|
+
std_dev = ov_opset.sqrt(var_x).output(0)
|
|
2494
|
+
return OpenVINOKerasTensor(std_dev)
|
|
1572
2495
|
|
|
1573
2496
|
|
|
1574
2497
|
def swapaxes(x, axis1, axis2):
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
2498
|
+
x = get_ov_output(x)
|
|
2499
|
+
x_shape = x.get_partial_shape()
|
|
2500
|
+
if x_shape.rank.is_dynamic:
|
|
2501
|
+
raise ValueError(
|
|
2502
|
+
"`swapaxes` does not support tensors with dynamic rank for the "
|
|
2503
|
+
"OpenVINO backend."
|
|
2504
|
+
)
|
|
2505
|
+
rank = x_shape.rank.get_length()
|
|
2506
|
+
axis1 = canonicalize_axis(axis1, rank)
|
|
2507
|
+
axis2 = canonicalize_axis(axis2, rank)
|
|
2508
|
+
axes = list(range(rank))
|
|
2509
|
+
axes[axis1], axes[axis2] = axes[axis2], axes[axis1]
|
|
2510
|
+
result = ov_opset.transpose(x, ov_opset.constant(axes, Type.i32))
|
|
2511
|
+
return OpenVINOKerasTensor(result.output(0))
|
|
1578
2512
|
|
|
1579
2513
|
|
|
1580
2514
|
def take(x, indices, axis=None):
|
|
@@ -1693,7 +2627,8 @@ def tile(x, repeats):
|
|
|
1693
2627
|
|
|
1694
2628
|
|
|
1695
2629
|
def trace(x, offset=0, axis1=0, axis2=1):
|
|
1696
|
-
|
|
2630
|
+
x = diagonal(x, offset=offset, axis1=axis1, axis2=axis2)
|
|
2631
|
+
return sum(x, axis=-1)
|
|
1697
2632
|
|
|
1698
2633
|
|
|
1699
2634
|
def tri(N, M=None, k=0, dtype=None):
|
|
@@ -1788,7 +2723,20 @@ def triu(x, k=0):
|
|
|
1788
2723
|
|
|
1789
2724
|
|
|
1790
2725
|
def vdot(x1, x2):
|
|
1791
|
-
|
|
2726
|
+
element_type = None
|
|
2727
|
+
if isinstance(x1, OpenVINOKerasTensor):
|
|
2728
|
+
element_type = x1.output.get_element_type()
|
|
2729
|
+
if isinstance(x2, OpenVINOKerasTensor):
|
|
2730
|
+
element_type = x2.output.get_element_type()
|
|
2731
|
+
x1 = get_ov_output(x1, element_type)
|
|
2732
|
+
x2 = get_ov_output(x2, element_type)
|
|
2733
|
+
x1, x2 = _align_operand_types(x1, x2, "vdot()")
|
|
2734
|
+
if x1.get_partial_shape().rank == 0 or x2.get_partial_shape().rank == 0:
|
|
2735
|
+
return OpenVINOKerasTensor(ov_opset.multiply(x1, x2).output(0))
|
|
2736
|
+
flatten_shape = ov_opset.constant([-1], Type.i32).output(0)
|
|
2737
|
+
x1 = ov_opset.reshape(x1, flatten_shape, False).output(0)
|
|
2738
|
+
x2 = ov_opset.reshape(x2, flatten_shape, False).output(0)
|
|
2739
|
+
return OpenVINOKerasTensor(ov_opset.matmul(x1, x2, False, False).output(0))
|
|
1792
2740
|
|
|
1793
2741
|
|
|
1794
2742
|
def vstack(xs):
|
|
@@ -1874,14 +2822,27 @@ def negative(x):
|
|
|
1874
2822
|
return OpenVINOKerasTensor(ov_opset.negative(x).output(0))
|
|
1875
2823
|
|
|
1876
2824
|
|
|
2825
|
+
def nextafter(x1, x2):
|
|
2826
|
+
raise NotImplementedError(
|
|
2827
|
+
"`nextafter` is not supported with openvino backend"
|
|
2828
|
+
)
|
|
2829
|
+
|
|
2830
|
+
|
|
1877
2831
|
def square(x):
|
|
1878
2832
|
x = get_ov_output(x)
|
|
2833
|
+
x_type = x.get_element_type()
|
|
2834
|
+
if x_type == Type.boolean:
|
|
2835
|
+
x = ov_opset.convert(x, Type.i32).output(0)
|
|
1879
2836
|
const_two = ov_opset.constant(2, x.get_element_type()).output(0)
|
|
1880
2837
|
return OpenVINOKerasTensor(ov_opset.power(x, const_two).output(0))
|
|
1881
2838
|
|
|
1882
2839
|
|
|
1883
2840
|
def sqrt(x):
|
|
1884
2841
|
x = get_ov_output(x)
|
|
2842
|
+
x_type = x.get_element_type()
|
|
2843
|
+
if x_type.is_integral():
|
|
2844
|
+
ov_type = OPENVINO_DTYPES[config.floatx()]
|
|
2845
|
+
x = ov_opset.convert(x, ov_type).output(0)
|
|
1885
2846
|
return OpenVINOKerasTensor(ov_opset.sqrt(x).output(0))
|
|
1886
2847
|
|
|
1887
2848
|
|
|
@@ -1892,6 +2853,8 @@ def squeeze(x, axis=None):
|
|
|
1892
2853
|
for idx, dim in enumerate(x.get_partial_shape()):
|
|
1893
2854
|
if dim == 1:
|
|
1894
2855
|
axis.append(idx)
|
|
2856
|
+
if isinstance(axis, tuple):
|
|
2857
|
+
axis = list(axis)
|
|
1895
2858
|
axis = ov_opset.constant(axis, Type.i32).output(0)
|
|
1896
2859
|
return OpenVINOKerasTensor(ov_opset.squeeze(x, axis).output(0))
|
|
1897
2860
|
|
|
@@ -1916,20 +2879,135 @@ def transpose(x, axes=None):
|
|
|
1916
2879
|
return OpenVINOKerasTensor(ov_opset.transpose(x, axes).output(0))
|
|
1917
2880
|
|
|
1918
2881
|
|
|
2882
|
+
def _helper_trapezoid(y, axis):
|
|
2883
|
+
rank = y.get_partial_shape().rank.get_length()
|
|
2884
|
+
strides = ov_opset.constant([1] * rank, dtype=Type.i64).output(0)
|
|
2885
|
+
|
|
2886
|
+
# y[:-1]
|
|
2887
|
+
begin1 = ov_opset.constant([0] * rank, dtype=Type.i64).output(0)
|
|
2888
|
+
end1_list = [0] * rank
|
|
2889
|
+
end1_list[axis] = -1
|
|
2890
|
+
end1 = ov_opset.constant(end1_list, dtype=Type.i64).output(0)
|
|
2891
|
+
begin_mask1 = [1] * rank
|
|
2892
|
+
begin_mask1[axis] = 0
|
|
2893
|
+
end_mask1 = [1] * rank
|
|
2894
|
+
end_mask1[axis] = 0
|
|
2895
|
+
y1 = ov_opset.strided_slice(
|
|
2896
|
+
y, begin1, end1, strides, begin_mask1, end_mask1
|
|
2897
|
+
).output(0)
|
|
2898
|
+
|
|
2899
|
+
# y[1:]
|
|
2900
|
+
begin2_list = [0] * rank
|
|
2901
|
+
begin2_list[axis] = 1
|
|
2902
|
+
begin2 = ov_opset.constant(begin2_list, dtype=Type.i64).output(0)
|
|
2903
|
+
end2 = ov_opset.constant([0] * rank, dtype=Type.i64).output(0)
|
|
2904
|
+
begin_mask2 = [1] * rank
|
|
2905
|
+
begin_mask2[axis] = 0
|
|
2906
|
+
end_mask2 = [1] * rank
|
|
2907
|
+
y2 = ov_opset.strided_slice(
|
|
2908
|
+
y, begin2, end2, strides, begin_mask2, end_mask2
|
|
2909
|
+
).output(0)
|
|
2910
|
+
|
|
2911
|
+
return y1, y2
|
|
2912
|
+
|
|
2913
|
+
|
|
2914
|
+
def trapezoid(y, x=None, dx=1.0, axis=-1):
|
|
2915
|
+
y = get_ov_output(y)
|
|
2916
|
+
y_type = y.get_element_type()
|
|
2917
|
+
|
|
2918
|
+
if y_type.is_integral():
|
|
2919
|
+
y_type = OPENVINO_DTYPES[config.floatx()]
|
|
2920
|
+
y = ov_opset.convert(y, y_type).output(0)
|
|
2921
|
+
|
|
2922
|
+
y1, y2 = _helper_trapezoid(y, axis)
|
|
2923
|
+
y_final = ov_opset.add(y1, y2).output(0)
|
|
2924
|
+
const_two = ov_opset.constant(2, dtype=y_type).output(0)
|
|
2925
|
+
y_final = ov_opset.divide(y_final, const_two).output(0)
|
|
2926
|
+
|
|
2927
|
+
if x is not None:
|
|
2928
|
+
x = get_ov_output(x)
|
|
2929
|
+
x_type = x.get_element_type()
|
|
2930
|
+
if x_type.is_integral():
|
|
2931
|
+
x_type = OPENVINO_DTYPES[config.floatx()]
|
|
2932
|
+
x = ov_opset.convert(x, x_type).output(0)
|
|
2933
|
+
|
|
2934
|
+
x1, x2 = _helper_trapezoid(x, axis)
|
|
2935
|
+
x_final = ov_opset.subtract(x2, x1).output(0)
|
|
2936
|
+
|
|
2937
|
+
else:
|
|
2938
|
+
x_final = ov_opset.constant(dx, dtype=y_type).output(0)
|
|
2939
|
+
|
|
2940
|
+
result = ov_opset.multiply(y_final, x_final).output(0)
|
|
2941
|
+
const_axis = ov_opset.constant([axis], Type.i64).output(0)
|
|
2942
|
+
result = ov_opset.reduce_sum(result, const_axis, False).output(0)
|
|
2943
|
+
|
|
2944
|
+
return OpenVINOKerasTensor(result)
|
|
2945
|
+
|
|
2946
|
+
|
|
2947
|
+
def vander(x, N=None, increasing=False):
|
|
2948
|
+
x = get_ov_output(x)
|
|
2949
|
+
x_type = x.get_element_type()
|
|
2950
|
+
|
|
2951
|
+
shape_x = ov_opset.shape_of(x, Type.i64).output(0)
|
|
2952
|
+
|
|
2953
|
+
const_zero_1D = ov_opset.constant([0], dtype=Type.i64).output(0)
|
|
2954
|
+
const_zero = ov_opset.constant(0, dtype=Type.i64).output(0)
|
|
2955
|
+
const_one = ov_opset.constant(1, dtype=Type.i64).output(0)
|
|
2956
|
+
const_mone = ov_opset.constant(-1, dtype=Type.i64).output(0)
|
|
2957
|
+
|
|
2958
|
+
if N is None:
|
|
2959
|
+
const_N = ov_opset.squeeze(shape_x, const_zero_1D).output(0)
|
|
2960
|
+
const_N_1D = shape_x
|
|
2961
|
+
else:
|
|
2962
|
+
const_N = ov_opset.constant(N, Type.i64).output(0)
|
|
2963
|
+
const_N_1D = ov_opset.constant([N], Type.i64).output(0)
|
|
2964
|
+
|
|
2965
|
+
const_N_minus_one = ov_opset.subtract(const_N, const_one).output(0)
|
|
2966
|
+
if increasing:
|
|
2967
|
+
powers = ov_opset.range(const_zero, const_N, const_one, x_type).output(
|
|
2968
|
+
0
|
|
2969
|
+
)
|
|
2970
|
+
else:
|
|
2971
|
+
powers = ov_opset.range(
|
|
2972
|
+
const_N_minus_one, const_mone, const_mone, x_type
|
|
2973
|
+
).output(0)
|
|
2974
|
+
|
|
2975
|
+
target_shape = ov_opset.concat([shape_x, const_N_1D], 0).output(0)
|
|
2976
|
+
|
|
2977
|
+
const_one_1D = ov_opset.constant([1], dtype=Type.i64).output(0)
|
|
2978
|
+
|
|
2979
|
+
powers = ov_opset.unsqueeze(powers, const_zero_1D).output(0)
|
|
2980
|
+
x = ov_opset.unsqueeze(x, const_one_1D).output(0)
|
|
2981
|
+
|
|
2982
|
+
result = ov_opset.broadcast(x, target_shape).output(0)
|
|
2983
|
+
|
|
2984
|
+
result = ov_opset.power(result, powers).output(0)
|
|
2985
|
+
|
|
2986
|
+
return OpenVINOKerasTensor(result)
|
|
2987
|
+
|
|
2988
|
+
|
|
1919
2989
|
def var(x, axis=None, keepdims=False):
|
|
1920
2990
|
x = get_ov_output(x)
|
|
2991
|
+
x_type = x.get_element_type()
|
|
2992
|
+
x, axis = _resolve_axis(x, axis)
|
|
2993
|
+
|
|
2994
|
+
work_dtype = Type.f64 if x_type.is_integral() else x.get_element_type()
|
|
2995
|
+
if x_type.is_integral():
|
|
2996
|
+
x = ov_opset.convert(x, work_dtype).output(0)
|
|
1921
2997
|
if axis is None:
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
2998
|
+
const_zero = ov_opset.constant(0, dtype=work_dtype).output(0)
|
|
2999
|
+
return OpenVINOKerasTensor(
|
|
3000
|
+
ov_opset.broadcast(const_zero, ov_opset.shape_of(x)).output(0)
|
|
3001
|
+
)
|
|
1926
3002
|
# The variance is computed using $Var = E[|x|^2] - |E[x]|^2$, It is faster
|
|
1927
3003
|
# but less numerically stable.
|
|
1928
3004
|
mean = ov_opset.reduce_mean(x, axis, keepdims).output(0)
|
|
1929
|
-
const_two = ov_opset.constant(2,
|
|
3005
|
+
const_two = ov_opset.constant(2, work_dtype).output(0)
|
|
3006
|
+
|
|
1930
3007
|
squared_x = ov_opset.power(x, const_two).output(0)
|
|
1931
3008
|
squared_mean = ov_opset.power(mean, const_two).output(0)
|
|
1932
|
-
|
|
3009
|
+
|
|
3010
|
+
squared_x_mean = ov_opset.reduce_mean(squared_x, axis, keepdims).output(0)
|
|
1933
3011
|
variance = OpenVINOKerasTensor(
|
|
1934
3012
|
ov_opset.subtract(squared_x_mean, squared_mean).output(0)
|
|
1935
3013
|
)
|
|
@@ -1938,22 +3016,46 @@ def var(x, axis=None, keepdims=False):
|
|
|
1938
3016
|
|
|
1939
3017
|
def sum(x, axis=None, keepdims=False):
|
|
1940
3018
|
x = get_ov_output(x)
|
|
3019
|
+
x, axis = _resolve_axis(x, axis)
|
|
1941
3020
|
if axis is None:
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
return OpenVINOKerasTensor(ov_opset.reduce_sum(x, axis, keepdims).output(0))
|
|
3021
|
+
return OpenVINOKerasTensor(x)
|
|
3022
|
+
x = _upcast_type_if_needed(x)
|
|
3023
|
+
summed_value = ov_opset.reduce_sum(x, axis, keepdims).output(0)
|
|
3024
|
+
return OpenVINOKerasTensor(summed_value)
|
|
1947
3025
|
|
|
1948
3026
|
|
|
1949
3027
|
def eye(N, M=None, k=0, dtype=None):
|
|
1950
|
-
|
|
3028
|
+
dtype = standardize_dtype(dtype) or config.floatx()
|
|
3029
|
+
ov_type = OPENVINO_DTYPES[dtype]
|
|
3030
|
+
if M is None:
|
|
3031
|
+
M = N
|
|
3032
|
+
return OpenVINOKerasTensor(
|
|
3033
|
+
ov_opset.eye(
|
|
3034
|
+
ov_opset.constant(N, Type.i32),
|
|
3035
|
+
ov_opset.constant(M, Type.i32),
|
|
3036
|
+
ov_opset.constant(k, Type.i32),
|
|
3037
|
+
output_type=ov_type,
|
|
3038
|
+
).output(0)
|
|
3039
|
+
)
|
|
1951
3040
|
|
|
1952
3041
|
|
|
1953
3042
|
def floor_divide(x1, x2):
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
)
|
|
3043
|
+
x1_output = get_ov_output(x1)
|
|
3044
|
+
x2_output = get_ov_output(x2)
|
|
3045
|
+
if x1_output.get_element_type() == Type.boolean:
|
|
3046
|
+
x1_output = ov_opset.convert(x1_output, Type.i32).output(0)
|
|
3047
|
+
if isinstance(x2, (int, float)):
|
|
3048
|
+
if x1_output.get_element_type().is_integral() and isinstance(x2, float):
|
|
3049
|
+
ov_type = OPENVINO_DTYPES[config.floatx()]
|
|
3050
|
+
else:
|
|
3051
|
+
ov_type = x1_output.get_element_type()
|
|
3052
|
+
x1 = ov_opset.convert(x1_output, ov_type).output(0)
|
|
3053
|
+
x2 = ov_opset.convert(x2_output, ov_type).output(0)
|
|
3054
|
+
else:
|
|
3055
|
+
x1, x2 = _align_operand_types(x1_output, x2_output, "floor_divide()")
|
|
3056
|
+
div = ov_opset.divide(x1, x2).output(0)
|
|
3057
|
+
floored_div = ov_opset.floor(div).output(0)
|
|
3058
|
+
return OpenVINOKerasTensor(floored_div)
|
|
1957
3059
|
|
|
1958
3060
|
|
|
1959
3061
|
def logical_xor(x1, x2):
|
|
@@ -1965,16 +3067,88 @@ def logical_xor(x1, x2):
|
|
|
1965
3067
|
|
|
1966
3068
|
|
|
1967
3069
|
def corrcoef(x):
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
3070
|
+
x_ov = get_ov_output(x)
|
|
3071
|
+
x_type = x_ov.get_element_type()
|
|
3072
|
+
ov_type = x_type
|
|
3073
|
+
|
|
3074
|
+
if x_type.is_integral():
|
|
3075
|
+
ov_type = OPENVINO_DTYPES[config.floatx()]
|
|
3076
|
+
x_ov = ov_opset.convert(x_ov, ov_type).output(0)
|
|
3077
|
+
|
|
3078
|
+
const_one = ov_opset.constant(1, dtype=Type.i64).output(0)
|
|
3079
|
+
const_two = ov_opset.constant(2, dtype=ov_type).output(0)
|
|
3080
|
+
|
|
3081
|
+
mean = ov_opset.reduce_mean(x_ov, const_one, True).output(0)
|
|
3082
|
+
x_ov = ov_opset.subtract(x_ov, mean).output(0)
|
|
3083
|
+
|
|
3084
|
+
cov = ov_opset.matmul(x_ov, x_ov, False, True).output(0)
|
|
3085
|
+
xsqr = ov_opset.power(x_ov, const_two).output(0)
|
|
3086
|
+
xvar = ov_opset.reduce_sum(xsqr, const_one, True).output(0)
|
|
3087
|
+
xstd = ov_opset.sqrt(xvar).output(0)
|
|
3088
|
+
|
|
3089
|
+
den = ov_opset.matmul(xstd, xstd, False, True).output(0)
|
|
3090
|
+
|
|
3091
|
+
result = ov_opset.divide(cov, den).output(0)
|
|
3092
|
+
|
|
3093
|
+
return OpenVINOKerasTensor(result)
|
|
1971
3094
|
|
|
1972
3095
|
|
|
1973
3096
|
def correlate(x1, x2, mode="valid"):
|
|
1974
|
-
|
|
1975
|
-
|
|
3097
|
+
x1 = get_ov_output(x1)
|
|
3098
|
+
x2 = get_ov_output(x2)
|
|
3099
|
+
x1_type = x1.get_element_type()
|
|
3100
|
+
x2_type = x2.get_element_type()
|
|
3101
|
+
x1_type = ov_to_keras_type(x1_type)
|
|
3102
|
+
x2_type = ov_to_keras_type(x2_type)
|
|
3103
|
+
result_type = dtypes.result_type(x1_type, x2_type, float)
|
|
3104
|
+
|
|
3105
|
+
result_type = OPENVINO_DTYPES[result_type]
|
|
3106
|
+
x1 = ov_opset.convert(x1, result_type).output(0)
|
|
3107
|
+
x2 = ov_opset.convert(x2, result_type).output(0)
|
|
3108
|
+
|
|
3109
|
+
shape_filter = ov_opset.shape_of(x2, Type.i64).output(0)
|
|
3110
|
+
const_two = ov_opset.constant(2, Type.f64).output(0)
|
|
3111
|
+
const_one = ov_opset.constant(1, Type.i64).output(0)
|
|
3112
|
+
const_zero = ov_opset.constant(0, result_type).output(0)
|
|
3113
|
+
shape_filter_minus_one = ov_opset.subtract(shape_filter, const_one).output(
|
|
3114
|
+
0
|
|
1976
3115
|
)
|
|
1977
3116
|
|
|
3117
|
+
# padding x1
|
|
3118
|
+
if mode == "valid":
|
|
3119
|
+
pass
|
|
3120
|
+
|
|
3121
|
+
elif mode == "same":
|
|
3122
|
+
shape_minus_one_float = ov_opset.convert(
|
|
3123
|
+
shape_filter_minus_one, Type.f64
|
|
3124
|
+
).output(0)
|
|
3125
|
+
|
|
3126
|
+
right = ov_opset.divide(shape_minus_one_float, const_two).output(0)
|
|
3127
|
+
left = ov_opset.ceil(right).output(0)
|
|
3128
|
+
right = ov_opset.floor(right).output(0)
|
|
3129
|
+
left = ov_opset.convert(left, Type.i64).output(0)
|
|
3130
|
+
right = ov_opset.convert(right, Type.i64).output(0)
|
|
3131
|
+
x1 = ov_opset.pad(x1, left, right, "constant", const_zero).output(0)
|
|
3132
|
+
|
|
3133
|
+
elif mode == "full":
|
|
3134
|
+
pad = shape_filter_minus_one
|
|
3135
|
+
x1 = ov_opset.pad(x1, pad, pad, "constant", const_zero).output(0)
|
|
3136
|
+
|
|
3137
|
+
else:
|
|
3138
|
+
raise ValueError(
|
|
3139
|
+
f"mode: {mode} not available chose from valid, same, full."
|
|
3140
|
+
)
|
|
3141
|
+
|
|
3142
|
+
axes = ov_opset.constant([0, 1], dtype=Type.i64).output(0)
|
|
3143
|
+
x2 = ov_opset.unsqueeze(x2, axes).output(0)
|
|
3144
|
+
x1 = ov_opset.unsqueeze(x1, axes).output(0)
|
|
3145
|
+
|
|
3146
|
+
result = ov_opset.convolution(x1, x2, [1], [0], [0], [1]).output(0)
|
|
3147
|
+
|
|
3148
|
+
result = ov_opset.squeeze(result, axes).output(0)
|
|
3149
|
+
|
|
3150
|
+
return OpenVINOKerasTensor(result)
|
|
3151
|
+
|
|
1978
3152
|
|
|
1979
3153
|
def select(condlist, choicelist, default=0):
|
|
1980
3154
|
raise NotImplementedError("`select` is not supported with openvino backend")
|