keras-nightly 3.12.0.dev2025092403__py3-none-any.whl → 3.14.0.dev2026010104__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.
Files changed (133) hide show
  1. keras/__init__.py +1 -0
  2. keras/_tf_keras/keras/__init__.py +1 -0
  3. keras/_tf_keras/keras/callbacks/__init__.py +3 -0
  4. keras/_tf_keras/keras/distillation/__init__.py +16 -0
  5. keras/_tf_keras/keras/distribution/__init__.py +3 -0
  6. keras/_tf_keras/keras/layers/__init__.py +21 -0
  7. keras/_tf_keras/keras/ops/__init__.py +13 -0
  8. keras/_tf_keras/keras/ops/image/__init__.py +1 -0
  9. keras/_tf_keras/keras/ops/linalg/__init__.py +1 -0
  10. keras/_tf_keras/keras/ops/nn/__init__.py +3 -0
  11. keras/_tf_keras/keras/ops/numpy/__init__.py +9 -0
  12. keras/_tf_keras/keras/quantizers/__init__.py +12 -0
  13. keras/callbacks/__init__.py +3 -0
  14. keras/distillation/__init__.py +16 -0
  15. keras/distribution/__init__.py +3 -0
  16. keras/layers/__init__.py +21 -0
  17. keras/ops/__init__.py +13 -0
  18. keras/ops/image/__init__.py +1 -0
  19. keras/ops/linalg/__init__.py +1 -0
  20. keras/ops/nn/__init__.py +3 -0
  21. keras/ops/numpy/__init__.py +9 -0
  22. keras/quantizers/__init__.py +12 -0
  23. keras/src/applications/imagenet_utils.py +4 -1
  24. keras/src/backend/common/backend_utils.py +30 -6
  25. keras/src/backend/common/dtypes.py +1 -1
  26. keras/src/backend/common/name_scope.py +2 -1
  27. keras/src/backend/common/variables.py +33 -16
  28. keras/src/backend/jax/core.py +92 -3
  29. keras/src/backend/jax/distribution_lib.py +16 -2
  30. keras/src/backend/jax/linalg.py +4 -0
  31. keras/src/backend/jax/nn.py +485 -20
  32. keras/src/backend/jax/numpy.py +92 -23
  33. keras/src/backend/jax/optimizer.py +3 -2
  34. keras/src/backend/jax/trainer.py +14 -2
  35. keras/src/backend/numpy/linalg.py +4 -0
  36. keras/src/backend/numpy/nn.py +313 -2
  37. keras/src/backend/numpy/numpy.py +76 -7
  38. keras/src/backend/openvino/__init__.py +1 -0
  39. keras/src/backend/openvino/core.py +2 -23
  40. keras/src/backend/openvino/linalg.py +4 -0
  41. keras/src/backend/openvino/nn.py +271 -20
  42. keras/src/backend/openvino/numpy.py +1030 -185
  43. keras/src/backend/openvino/random.py +7 -14
  44. keras/src/backend/tensorflow/layer.py +43 -9
  45. keras/src/backend/tensorflow/linalg.py +24 -0
  46. keras/src/backend/tensorflow/nn.py +545 -1
  47. keras/src/backend/tensorflow/numpy.py +264 -54
  48. keras/src/backend/torch/core.py +3 -1
  49. keras/src/backend/torch/linalg.py +4 -0
  50. keras/src/backend/torch/nn.py +125 -0
  51. keras/src/backend/torch/numpy.py +84 -8
  52. keras/src/callbacks/__init__.py +1 -0
  53. keras/src/callbacks/callback_list.py +45 -11
  54. keras/src/callbacks/model_checkpoint.py +5 -0
  55. keras/src/callbacks/orbax_checkpoint.py +299 -0
  56. keras/src/callbacks/terminate_on_nan.py +54 -5
  57. keras/src/datasets/cifar10.py +5 -0
  58. keras/src/distillation/__init__.py +1 -0
  59. keras/src/distillation/distillation_loss.py +390 -0
  60. keras/src/distillation/distiller.py +598 -0
  61. keras/src/distribution/distribution_lib.py +14 -0
  62. keras/src/export/__init__.py +2 -0
  63. keras/src/export/export_utils.py +39 -2
  64. keras/src/export/litert.py +248 -0
  65. keras/src/export/openvino.py +1 -1
  66. keras/src/export/tf2onnx_lib.py +3 -0
  67. keras/src/layers/__init__.py +13 -0
  68. keras/src/layers/activations/softmax.py +9 -4
  69. keras/src/layers/attention/attention.py +1 -1
  70. keras/src/layers/attention/multi_head_attention.py +4 -1
  71. keras/src/layers/core/dense.py +191 -172
  72. keras/src/layers/core/einsum_dense.py +235 -186
  73. keras/src/layers/core/embedding.py +83 -93
  74. keras/src/layers/core/input_layer.py +1 -0
  75. keras/src/layers/core/reversible_embedding.py +390 -0
  76. keras/src/layers/input_spec.py +17 -17
  77. keras/src/layers/layer.py +40 -15
  78. keras/src/layers/merging/dot.py +4 -1
  79. keras/src/layers/pooling/adaptive_average_pooling1d.py +65 -0
  80. keras/src/layers/pooling/adaptive_average_pooling2d.py +62 -0
  81. keras/src/layers/pooling/adaptive_average_pooling3d.py +63 -0
  82. keras/src/layers/pooling/adaptive_max_pooling1d.py +65 -0
  83. keras/src/layers/pooling/adaptive_max_pooling2d.py +62 -0
  84. keras/src/layers/pooling/adaptive_max_pooling3d.py +63 -0
  85. keras/src/layers/pooling/base_adaptive_pooling.py +63 -0
  86. keras/src/layers/preprocessing/discretization.py +6 -5
  87. keras/src/layers/preprocessing/index_lookup.py +19 -1
  88. keras/src/layers/preprocessing/normalization.py +16 -1
  89. keras/src/layers/regularization/dropout.py +43 -1
  90. keras/src/layers/rnn/gru.py +1 -1
  91. keras/src/layers/rnn/lstm.py +2 -2
  92. keras/src/layers/rnn/rnn.py +19 -0
  93. keras/src/layers/rnn/simple_rnn.py +1 -1
  94. keras/src/losses/loss.py +1 -1
  95. keras/src/metrics/confusion_metrics.py +7 -6
  96. keras/src/models/cloning.py +4 -0
  97. keras/src/models/functional.py +11 -3
  98. keras/src/models/model.py +156 -27
  99. keras/src/ops/image.py +184 -3
  100. keras/src/ops/linalg.py +93 -0
  101. keras/src/ops/nn.py +268 -2
  102. keras/src/ops/numpy.py +541 -43
  103. keras/src/optimizers/adafactor.py +29 -10
  104. keras/src/optimizers/base_optimizer.py +22 -3
  105. keras/src/optimizers/loss_scale_optimizer.py +51 -18
  106. keras/src/optimizers/muon.py +65 -31
  107. keras/src/optimizers/schedules/learning_rate_schedule.py +4 -3
  108. keras/src/quantizers/__init__.py +12 -1
  109. keras/src/quantizers/gptq.py +8 -6
  110. keras/src/quantizers/gptq_config.py +36 -1
  111. keras/src/quantizers/gptq_core.py +150 -78
  112. keras/src/quantizers/quantization_config.py +232 -0
  113. keras/src/quantizers/quantizers.py +114 -38
  114. keras/src/quantizers/utils.py +23 -0
  115. keras/src/random/seed_generator.py +4 -2
  116. keras/src/saving/file_editor.py +81 -6
  117. keras/src/saving/saving_lib.py +1 -1
  118. keras/src/testing/__init__.py +1 -0
  119. keras/src/testing/test_case.py +45 -5
  120. keras/src/trainers/compile_utils.py +14 -5
  121. keras/src/utils/backend_utils.py +31 -4
  122. keras/src/utils/dataset_utils.py +234 -35
  123. keras/src/utils/file_utils.py +49 -11
  124. keras/src/utils/image_utils.py +14 -2
  125. keras/src/utils/jax_layer.py +187 -36
  126. keras/src/utils/module_utils.py +18 -0
  127. keras/src/utils/progbar.py +10 -12
  128. keras/src/utils/rng_utils.py +9 -1
  129. keras/src/version.py +1 -1
  130. {keras_nightly-3.12.0.dev2025092403.dist-info → keras_nightly-3.14.0.dev2026010104.dist-info}/METADATA +16 -6
  131. {keras_nightly-3.12.0.dev2025092403.dist-info → keras_nightly-3.14.0.dev2026010104.dist-info}/RECORD +133 -116
  132. {keras_nightly-3.12.0.dev2025092403.dist-info → keras_nightly-3.14.0.dev2026010104.dist-info}/WHEEL +0 -0
  133. {keras_nightly-3.12.0.dev2025092403.dist-info → keras_nightly-3.14.0.dev2026010104.dist-info}/top_level.txt +0 -0
@@ -173,15 +173,18 @@ def append(x1, x2, axis=None):
173
173
  return np.append(x1, x2, axis=axis)
174
174
 
175
175
 
176
- def arange(start, stop=None, step=1, dtype=None):
176
+ def arange(start, stop=None, step=None, dtype=None):
177
177
  if dtype is None:
178
- dtypes_to_resolve = [
179
- getattr(start, "dtype", type(start)),
180
- getattr(step, "dtype", type(step)),
181
- ]
178
+ dtypes_to_resolve = [getattr(start, "dtype", type(start))]
182
179
  if stop is not None:
183
180
  dtypes_to_resolve.append(getattr(stop, "dtype", type(stop)))
181
+ if step is not None:
182
+ dtypes_to_resolve.append(getattr(step, "dtype", type(step)))
184
183
  dtype = dtypes.result_type(*dtypes_to_resolve)
184
+ if stop is None:
185
+ start, stop = 0, start
186
+ if step is None:
187
+ step = 1
185
188
  return np.arange(start, stop, step=step, dtype=dtype)
186
189
 
187
190
 
@@ -291,6 +294,11 @@ def array(x, dtype=None):
291
294
  return convert_to_tensor(x, dtype=dtype)
292
295
 
293
296
 
297
+ def view(x, dtype=None):
298
+ x = convert_to_tensor(x)
299
+ return x.view(dtype=dtype)
300
+
301
+
294
302
  def average(x, axis=None, weights=None):
295
303
  axis = standardize_axis_for_numpy(axis)
296
304
  x = convert_to_tensor(x)
@@ -604,6 +612,10 @@ def empty(shape, dtype=None):
604
612
  return np.empty(shape, dtype=dtype)
605
613
 
606
614
 
615
+ def empty_like(x, dtype=None):
616
+ return np.empty_like(x, dtype=dtype)
617
+
618
+
607
619
  def equal(x1, x2):
608
620
  return np.equal(x1, x2)
609
621
 
@@ -742,6 +754,11 @@ def isposinf(x):
742
754
  return np.isposinf(x)
743
755
 
744
756
 
757
+ def isreal(x):
758
+ x = convert_to_tensor(x)
759
+ return np.isreal(x)
760
+
761
+
745
762
  def kron(x1, x2):
746
763
  x1 = convert_to_tensor(x1)
747
764
  x2 = convert_to_tensor(x2)
@@ -756,6 +773,19 @@ def lcm(x1, x2):
756
773
  return np.lcm(x1, x2).astype(dtype)
757
774
 
758
775
 
776
+ def ldexp(x1, x2):
777
+ x1 = convert_to_tensor(x1)
778
+ x2 = convert_to_tensor(x2)
779
+ dtype = dtypes.result_type(x1.dtype, x2.dtype, float)
780
+
781
+ if standardize_dtype(x2.dtype) not in dtypes.INT_TYPES:
782
+ raise TypeError(
783
+ f"ldexp exponent must be an integer type. "
784
+ f"Received: x2 dtype={x2.dtype}"
785
+ )
786
+ return np.ldexp(x1, x2).astype(dtype)
787
+
788
+
759
789
  def less(x1, x2):
760
790
  return np.less(x1, x2)
761
791
 
@@ -835,6 +865,13 @@ def logaddexp(x1, x2):
835
865
  return np.logaddexp(x1, x2)
836
866
 
837
867
 
868
+ def logaddexp2(x1, x2):
869
+ x1 = convert_to_tensor(x1)
870
+ x2 = convert_to_tensor(x2)
871
+ dtype = dtypes.result_type(x1.dtype, x2.dtype, float)
872
+ return np.logaddexp2(x1, x2).astype(dtype)
873
+
874
+
838
875
  def logical_and(x1, x2):
839
876
  return np.logical_and(x1, x2)
840
877
 
@@ -1087,6 +1124,11 @@ def split(x, indices_or_sections, axis=0):
1087
1124
  return np.split(x, indices_or_sections, axis=axis)
1088
1125
 
1089
1126
 
1127
+ def array_split(x, indices_or_sections, axis=0):
1128
+ axis = standardize_axis_for_numpy(axis)
1129
+ return np.array_split(x, indices_or_sections, axis=axis)
1130
+
1131
+
1090
1132
  def stack(x, axis=0):
1091
1133
  axis = standardize_axis_for_numpy(axis)
1092
1134
  dtype_set = set([getattr(a, "dtype", type(a)) for a in x])
@@ -1162,8 +1204,10 @@ def trace(x, offset=0, axis1=0, axis2=1):
1162
1204
  axis2 = standardize_axis_for_numpy(axis2)
1163
1205
  x = convert_to_tensor(x)
1164
1206
  dtype = standardize_dtype(x.dtype)
1165
- if dtype not in ("int64", "uint32", "uint64"):
1166
- dtype = dtypes.result_type(dtype, "int32")
1207
+ if dtype in ("bool", "int8", "int16"):
1208
+ dtype = "int32"
1209
+ elif dtype in ("uint8", "uint16"):
1210
+ dtype = "uint32"
1167
1211
  return np.trace(x, offset=offset, axis1=axis1, axis2=axis2, dtype=dtype)
1168
1212
 
1169
1213
 
@@ -1291,6 +1335,14 @@ def negative(x):
1291
1335
  return np.negative(x)
1292
1336
 
1293
1337
 
1338
+ def nextafter(x1, x2):
1339
+ x1 = convert_to_tensor(x1)
1340
+ x2 = convert_to_tensor(x2)
1341
+ dtype = dtypes.result_type(x1.dtype, x2.dtype, float)
1342
+
1343
+ return np.nextafter(x1, x2).astype(dtype)
1344
+
1345
+
1294
1346
  def square(x):
1295
1347
  x = convert_to_tensor(x)
1296
1348
  if standardize_dtype(x.dtype) == "bool":
@@ -1319,6 +1371,23 @@ def transpose(x, axes=None):
1319
1371
  return np.transpose(x, axes=axes)
1320
1372
 
1321
1373
 
1374
+ def trapezoid(y, x=None, dx=1.0, axis=-1):
1375
+ y = convert_to_tensor(y)
1376
+ result_dtype = dtypes.result_type(y.dtype, float)
1377
+ if x is not None:
1378
+ x = convert_to_tensor(x)
1379
+ dx = convert_to_tensor(dx)
1380
+ return np.trapezoid(y, x, dx=dx, axis=axis).astype(result_dtype)
1381
+
1382
+
1383
+ def vander(x, N=None, increasing=False):
1384
+ x = convert_to_tensor(x)
1385
+ result_dtype = dtypes.result_type(x.dtype)
1386
+ compute_dtype = dtypes.result_type(x.dtype, config.floatx())
1387
+ x = x.astype(compute_dtype)
1388
+ return np.vander(x, N=N, increasing=increasing).astype(result_dtype)
1389
+
1390
+
1322
1391
  def var(x, axis=None, keepdims=False):
1323
1392
  axis = standardize_axis_for_numpy(axis)
1324
1393
  x = convert_to_tensor(x)
@@ -15,6 +15,7 @@ from keras.src.backend.openvino.core import compute_output_spec
15
15
  from keras.src.backend.openvino.core import cond
16
16
  from keras.src.backend.openvino.core import convert_to_numpy
17
17
  from keras.src.backend.openvino.core import convert_to_tensor
18
+ from keras.src.backend.openvino.core import device_scope
18
19
  from keras.src.backend.openvino.core import is_tensor
19
20
  from keras.src.backend.openvino.core import random_seed_dtype
20
21
  from keras.src.backend.openvino.core import shape
@@ -13,7 +13,6 @@ from openvino import compile_model
13
13
  from keras.src import tree
14
14
  from keras.src.backend.common import KerasVariable
15
15
  from keras.src.backend.common import dtypes
16
- from keras.src.backend.common import global_state
17
16
  from keras.src.backend.common import standardize_dtype
18
17
  from keras.src.backend.common.dtypes import result_type
19
18
  from keras.src.backend.common.keras_tensor import KerasTensor
@@ -530,31 +529,11 @@ def ov_to_keras_type(ov_type):
530
529
 
531
530
  @contextlib.contextmanager
532
531
  def device_scope(device_name):
533
- current_device = _parse_device_input(device_name)
534
- global_state.set_global_attribute("openvino_device", current_device)
532
+ yield
535
533
 
536
534
 
537
535
  def get_device():
538
- device = global_state.get_global_attribute("openvino_device", None)
539
- if device is None:
540
- return "CPU"
541
- return device
542
-
543
-
544
- def _parse_device_input(device_name):
545
- if isinstance(device_name, str):
546
- # We support string value like "cpu:0", "gpu:1", and need to convert
547
- # "gpu" to "cuda"
548
- device_name = device_name.upper()
549
- device_type, _ = device_name.split(":")
550
- return device_type
551
- else:
552
- raise ValueError(
553
- "Invalid value for argument `device_name`. "
554
- "Expected a string like 'gpu:0' or 'cpu'. "
555
- f"Received: device_name='{device_name}'"
556
- )
557
- return device_name
536
+ return "CPU"
558
537
 
559
538
 
560
539
  class Variable(KerasVariable):
@@ -56,3 +56,7 @@ def svd(x, full_matrices=True, compute_uv=True):
56
56
 
57
57
  def lstsq(a, b, rcond=None):
58
58
  raise NotImplementedError("`lstsq` is not supported with openvino backend")
59
+
60
+
61
+ def jvp(fun, primals, tangents, has_aux=False):
62
+ raise NotImplementedError("`jvp` is not supported with openvino backend")
@@ -2,6 +2,7 @@ import openvino.opset14 as ov_opset
2
2
  from openvino import Type
3
3
 
4
4
  from keras.src import backend
5
+ from keras.src.backend.openvino.core import OPENVINO_DTYPES
5
6
  from keras.src.backend.openvino.core import OpenVINOKerasTensor
6
7
  from keras.src.backend.openvino.core import get_ov_output
7
8
 
@@ -16,6 +17,23 @@ def relu6(x):
16
17
  return OpenVINOKerasTensor(ov_opset.clamp(x, 0.0, 6.0).output(0))
17
18
 
18
19
 
20
+ def celu(x, alpha=1.0):
21
+ x = get_ov_output(x)
22
+ const_zero = get_ov_output(0.0, x.get_element_type())
23
+ const_alpha = get_ov_output(alpha, x.get_element_type())
24
+ const_one = get_ov_output(1.0, x.get_element_type())
25
+ exp_x_div_alpha = ov_opset.exp(ov_opset.divide(x, const_alpha)).output(0)
26
+ negative_branch = ov_opset.multiply(
27
+ const_alpha, ov_opset.subtract(exp_x_div_alpha, const_one)
28
+ )
29
+
30
+ celu_x = ov_opset.add(
31
+ ov_opset.maximum(x, const_zero).output(0),
32
+ ov_opset.minimum(negative_branch, const_zero).output(0),
33
+ )
34
+ return OpenVINOKerasTensor(celu_x.output(0))
35
+
36
+
19
37
  def sigmoid(x):
20
38
  x = get_ov_output(x)
21
39
  return OpenVINOKerasTensor(ov_opset.sigmoid(x).output(0))
@@ -26,6 +44,39 @@ def tanh(x):
26
44
  return OpenVINOKerasTensor(ov_opset.tanh(x).output(0))
27
45
 
28
46
 
47
+ def tanh_shrink(x):
48
+ x = get_ov_output(x)
49
+ return OpenVINOKerasTensor(ov_opset.subtract(x, ov_opset.tanh(x)).output(0))
50
+
51
+
52
+ def hard_tanh(x):
53
+ x = get_ov_output(x)
54
+ return OpenVINOKerasTensor(ov_opset.clamp(x, -1.0, 1.0).output(0))
55
+
56
+
57
+ def soft_shrink(x, threshold=0.5):
58
+ x = get_ov_output(x)
59
+ et = x.get_element_type()
60
+ thr = get_ov_output(threshold, et)
61
+ zero = get_ov_output(0.0, et)
62
+ abs_x = ov_opset.abs(x)
63
+ sub = ov_opset.subtract(abs_x, thr)
64
+ shrunk = ov_opset.maximum(sub, zero)
65
+ sign = ov_opset.sign(x)
66
+ out = ov_opset.multiply(sign, shrunk)
67
+ return OpenVINOKerasTensor(out.output(0))
68
+
69
+
70
+ def hard_shrink(x, threshold=0.5):
71
+ x = get_ov_output(x)
72
+ et = x.get_element_type()
73
+ thr = get_ov_output(threshold, et)
74
+ zero = get_ov_output(0.0, et)
75
+ cond = ov_opset.greater(ov_opset.abs(x), thr)
76
+ out = ov_opset.select(cond, x, zero)
77
+ return OpenVINOKerasTensor(out.output(0))
78
+
79
+
29
80
  def softplus(x):
30
81
  x = get_ov_output(x)
31
82
  return OpenVINOKerasTensor(ov_opset.softplus(x).output(0))
@@ -38,14 +89,15 @@ def softsign(x):
38
89
 
39
90
  def silu(x):
40
91
  x = get_ov_output(x)
41
- return OpenVINOKerasTensor(
42
- ov_opset.multiply(x, ov_opset.sigmoid(x)).output(0)
43
- )
92
+ beta = get_ov_output(1.0, x.get_element_type())
93
+ return OpenVINOKerasTensor(ov_opset.swish(x, beta=beta).output(0))
44
94
 
45
95
 
46
96
  def log_sigmoid(x):
47
- raise NotImplementedError(
48
- "`log_sigmoid` is not supported with openvino backend"
97
+ x = get_ov_output(x)
98
+ neg_x = ov_opset.negative(x)
99
+ return OpenVINOKerasTensor(
100
+ ov_opset.negative(ov_opset.softplus(neg_x)).output(0)
49
101
  )
50
102
 
51
103
 
@@ -58,6 +110,17 @@ def leaky_relu(x, negative_slope=0.2):
58
110
  return OpenVINOKerasTensor(leaky_relu)
59
111
 
60
112
 
113
+ def sparse_sigmoid(x):
114
+ x = get_ov_output(x)
115
+ et = x.get_element_type()
116
+ one = get_ov_output(1.0, et)
117
+ neg_one = get_ov_output(-1.0, et)
118
+ half = get_ov_output(0.5, et)
119
+ y = ov_opset.minimum(ov_opset.maximum(x, neg_one), one)
120
+ out = ov_opset.multiply(half, ov_opset.add(y, one))
121
+ return OpenVINOKerasTensor(out.output(0))
122
+
123
+
61
124
  def hard_sigmoid(x):
62
125
  x = get_ov_output(x)
63
126
  alpha = get_ov_output(1.0 / 6.0, x.get_element_type())
@@ -121,6 +184,48 @@ def log_softmax(x, axis=-1):
121
184
  return OpenVINOKerasTensor(ov_opset.log_softmax(x, axis).output(0))
122
185
 
123
186
 
187
+ def squareplus(x, b=4):
188
+ x = get_ov_output(x)
189
+ et = x.get_element_type()
190
+ b = get_ov_output(b, et)
191
+ two = get_ov_output(2.0, et)
192
+ x_squared = ov_opset.multiply(x, x)
193
+ inside = ov_opset.add(x_squared, b)
194
+ root = ov_opset.sqrt(inside)
195
+ summed = ov_opset.add(x, root)
196
+ out = ov_opset.divide(summed, two)
197
+ return OpenVINOKerasTensor(out.output(0))
198
+
199
+
200
+ def sparse_plus(x):
201
+ x = get_ov_output(x)
202
+ et = x.get_element_type()
203
+ one = get_ov_output(1.0, et)
204
+ neg_one = get_ov_output(-1.0, et)
205
+ zero = get_ov_output(0.0, et)
206
+ quarter = get_ov_output(0.25, et)
207
+ x_plus_1 = ov_opset.add(x, one)
208
+ quad = ov_opset.multiply(quarter, ov_opset.multiply(x_plus_1, x_plus_1))
209
+ leq_than_neg_one = ov_opset.less_equal(x, neg_one)
210
+ less_than_one = ov_opset.less(x, one)
211
+ out = ov_opset.select(
212
+ leq_than_neg_one,
213
+ zero,
214
+ ov_opset.select(less_than_one, quad, x),
215
+ )
216
+ return OpenVINOKerasTensor(out.output(0))
217
+
218
+
219
+ def threshold(x, threshold, default_value):
220
+ x = get_ov_output(x)
221
+ et = x.get_element_type()
222
+ thr = get_ov_output(threshold, et)
223
+ dv = get_ov_output(default_value, et)
224
+ cond = ov_opset.greater(x, thr)
225
+ out = ov_opset.select(cond, x, dv)
226
+ return OpenVINOKerasTensor(out.output(0))
227
+
228
+
124
229
  def max_pool(
125
230
  inputs,
126
231
  pool_size,
@@ -128,8 +233,18 @@ def max_pool(
128
233
  padding="valid",
129
234
  data_format=None,
130
235
  ):
131
- raise NotImplementedError(
132
- "`max_pool` is not supported with openvino backend"
236
+ num_spatial_dims = (
237
+ get_ov_output(inputs).get_partial_shape().rank.get_length() - 2
238
+ )
239
+ kwargs = {"dilations": [1] * num_spatial_dims} # required for ov max_pool
240
+ return _pool(
241
+ inputs,
242
+ pool_size,
243
+ ov_opset.max_pool,
244
+ strides,
245
+ padding,
246
+ data_format,
247
+ **kwargs,
133
248
  )
134
249
 
135
250
 
@@ -140,11 +255,62 @@ def average_pool(
140
255
  padding="valid",
141
256
  data_format=None,
142
257
  ):
143
- raise NotImplementedError(
144
- "`average_pool` is not supported with openvino backend"
258
+ return _pool(
259
+ inputs,
260
+ pool_size,
261
+ ov_opset.avg_pool,
262
+ strides,
263
+ padding,
264
+ data_format,
265
+ exclude_pad=True,
145
266
  )
146
267
 
147
268
 
269
+ def adaptive_average_pool(inputs, output_size, data_format=None):
270
+ """Adaptive average pooling - OpenVINO backend not yet supported."""
271
+ raise NotImplementedError("Adaptive pooling not implemented for OpenVINO.")
272
+
273
+
274
+ def adaptive_max_pool(inputs, output_size, data_format=None):
275
+ """Adaptive max pooling - OpenVINO backend not yet supported."""
276
+ raise NotImplementedError("Adaptive pooling not implemented for OpenVINO.")
277
+
278
+
279
+ def _pool(
280
+ inputs,
281
+ pool_size,
282
+ pooling_func,
283
+ strides=None,
284
+ padding="valid",
285
+ data_format=None,
286
+ **kwargs,
287
+ ):
288
+ data_format = backend.standardize_data_format(data_format)
289
+ inputs = get_ov_output(inputs)
290
+
291
+ num_spatial_dims = inputs.get_partial_shape().rank.get_length() - 2
292
+ if isinstance(pool_size, int):
293
+ pool_size = [pool_size] * num_spatial_dims
294
+
295
+ if strides is None:
296
+ strides = pool_size
297
+
298
+ strides = _adjust_strides_dilation(strides, num_spatial_dims)
299
+ pad_mode, pads_begin, pads_end = _adjust_padding(padding)
300
+ inputs = _adjust_input(inputs, num_spatial_dims, data_format)
301
+ pool_kwargs = {
302
+ "kernel_shape": pool_size,
303
+ "strides": strides,
304
+ "auto_pad": pad_mode,
305
+ "pads_begin": pads_begin,
306
+ "pads_end": pads_end,
307
+ **kwargs,
308
+ }
309
+ pooled = pooling_func(inputs, **pool_kwargs).output(0)
310
+ adjusted_pooled = _adjust_outputs(pooled, num_spatial_dims, data_format)
311
+ return OpenVINOKerasTensor(adjusted_pooled)
312
+
313
+
148
314
  def _adjust_strides_dilation(
149
315
  x,
150
316
  num_spatial_dims,
@@ -374,15 +540,33 @@ def conv_transpose(
374
540
 
375
541
 
376
542
  def one_hot(x, num_classes, axis=-1, dtype=None, sparse=False):
377
- raise NotImplementedError(
378
- "`one_hot` is not supported with openvino backend"
379
- )
543
+ if sparse:
544
+ raise ValueError("`sparse=True` is not supported with openvino backend")
545
+ x = get_ov_output(x)
546
+ if dtype is None:
547
+ dtype = backend.floatx()
548
+ ov_dtype = OPENVINO_DTYPES[dtype]
549
+ on_value = get_ov_output(1, ov_dtype)
550
+ off_value = get_ov_output(0, ov_dtype)
551
+ one_hot_encoded = ov_opset.one_hot(
552
+ x,
553
+ depth=num_classes,
554
+ axis=axis,
555
+ on_value=on_value,
556
+ off_value=off_value,
557
+ ).output(0)
558
+ return OpenVINOKerasTensor(one_hot_encoded)
380
559
 
381
560
 
382
561
  def multi_hot(x, num_classes, axis=-1, dtype=None, sparse=False):
383
- raise NotImplementedError(
384
- "`multi_hot` is not supported with openvino backend"
385
- )
562
+ reduction_axis = 1 if len(x.shape) > 1 else 0
563
+ if backend.standardize_dtype(dtype) == "bool":
564
+ outputs = one_hot(x, num_classes, axis=axis, dtype=dtype, sparse=sparse)
565
+ result = ov_opset.reduce_logical_or(outputs, reduction_axis)
566
+ else:
567
+ outputs = one_hot(x, num_classes, axis=axis, dtype=dtype)
568
+ result = ov_opset.reduce_max(outputs, reduction_axis)
569
+ return OpenVINOKerasTensor(result.output(0))
386
570
 
387
571
 
388
572
  def categorical_crossentropy(target, output, from_logits=False, axis=-1):
@@ -465,9 +649,15 @@ def batch_normalization(
465
649
 
466
650
 
467
651
  def ctc_loss(target, output, target_length, output_length, mask_index=0):
468
- raise NotImplementedError(
469
- "`ctc_loss` is not supported with openvino backend"
652
+ target = get_ov_output(target)
653
+ output = get_ov_output(output)
654
+ target_length = get_ov_output(target_length)
655
+ output_length = get_ov_output(output_length)
656
+ ctc_loss_ = ov_opset.ctc_loss(
657
+ output, output_length, target, target_length, blank_index=mask_index
470
658
  )
659
+ ctc_loss_ = ov_opset.convert(ctc_loss_, OPENVINO_DTYPES[backend.floatx()])
660
+ return OpenVINOKerasTensor(ctc_loss_.output(0))
471
661
 
472
662
 
473
663
  def ctc_decode(
@@ -485,7 +675,27 @@ def ctc_decode(
485
675
 
486
676
 
487
677
  def psnr(x1, x2, max_val):
488
- raise NotImplementedError("`psnr` is not supported with openvino backend")
678
+ from keras.src.backend.openvino.numpy import log10
679
+
680
+ x1 = get_ov_output(x1)
681
+ x2 = get_ov_output(x2)
682
+ max_val = get_ov_output(max_val, x1.get_element_type())
683
+ diff = ov_opset.subtract(x1, x2)
684
+ squared_diff = ov_opset.multiply(diff, diff)
685
+ reduction_axes = list(range(0, x1.get_partial_shape().rank.get_length()))
686
+ mse = ov_opset.reduce_mean(squared_diff, reduction_axes).output(0)
687
+ log_max_val = get_ov_output(log10(OpenVINOKerasTensor(max_val)))
688
+ log_mse = get_ov_output(log10(OpenVINOKerasTensor(mse)))
689
+
690
+ psnr = ov_opset.subtract(
691
+ ov_opset.multiply(
692
+ ov_opset.constant(20, log_max_val.get_element_type()), log_max_val
693
+ ),
694
+ ov_opset.multiply(
695
+ ov_opset.constant(10, log_mse.get_element_type()), log_mse
696
+ ),
697
+ ).output(0)
698
+ return OpenVINOKerasTensor(psnr)
489
699
 
490
700
 
491
701
  def dot_product_attention(
@@ -499,6 +709,47 @@ def dot_product_attention(
499
709
  flash_attention=None,
500
710
  attn_logits_soft_cap=None,
501
711
  ):
502
- raise NotImplementedError(
503
- "`dot_product_attention` is not supported with openvino backend"
712
+ if bias is not None:
713
+ raise NotImplementedError(
714
+ "`dot_product_attention` with `bias` is not supported "
715
+ "with openvino backend"
716
+ )
717
+ if flash_attention:
718
+ raise NotImplementedError(
719
+ "`dot_product_attention` with `flash_attention` is not supported "
720
+ "with openvino backend"
721
+ )
722
+ if attn_logits_soft_cap is not None:
723
+ raise NotImplementedError(
724
+ "`dot_product_attention` with `attn_logits_soft_cap` is not "
725
+ "supported with openvino backend"
726
+ )
727
+ query = get_ov_output(query)
728
+ key = get_ov_output(key)
729
+ value = get_ov_output(value)
730
+ if query.get_element_type() != key.get_element_type():
731
+ ov_type = OPENVINO_DTYPES[backend.floatx()]
732
+ query = ov_opset.convert(query, ov_type).output(0)
733
+ key = ov_opset.convert(key, ov_type).output(0)
734
+ if value.get_element_type() != query.get_element_type():
735
+ value = ov_opset.convert(value, query.get_element_type()).output(0)
736
+ axes_const = ov_opset.constant([0, 2, 1, 3], Type.i32).output(0)
737
+
738
+ query = ov_opset.transpose(query, axes_const)
739
+ key = ov_opset.transpose(key, axes_const)
740
+ value = ov_opset.transpose(value, axes_const)
741
+ mask = get_ov_output(mask) if mask is not None else None
742
+ scale = (
743
+ get_ov_output(scale, query.get_element_type())
744
+ if scale is not None
745
+ else None
746
+ )
747
+ dpa = ov_opset.scaled_dot_product_attention(
748
+ query, key, value, attention_mask=mask, scale=scale, causal=is_causal
504
749
  )
750
+ dpa = ov_opset.transpose(dpa, axes_const)
751
+ return OpenVINOKerasTensor(dpa.output(0))
752
+
753
+
754
+ def unfold(input, kernel_size, dilation=1, padding=0, stride=1):
755
+ raise NotImplementedError("`unfold` is not supported with openvino backend")