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
keras/src/backend/numpy/numpy.py
CHANGED
|
@@ -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=
|
|
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,38 @@ 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
|
+
|
|
762
|
+
def kron(x1, x2):
|
|
763
|
+
x1 = convert_to_tensor(x1)
|
|
764
|
+
x2 = convert_to_tensor(x2)
|
|
765
|
+
dtype = dtypes.result_type(x1.dtype, x2.dtype)
|
|
766
|
+
return np.kron(x1, x2).astype(dtype)
|
|
767
|
+
|
|
768
|
+
|
|
769
|
+
def lcm(x1, x2):
|
|
770
|
+
x1 = convert_to_tensor(x1)
|
|
771
|
+
x2 = convert_to_tensor(x2)
|
|
772
|
+
dtype = dtypes.result_type(x1.dtype, x2.dtype)
|
|
773
|
+
return np.lcm(x1, x2).astype(dtype)
|
|
774
|
+
|
|
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
|
+
|
|
745
789
|
def less(x1, x2):
|
|
746
790
|
return np.less(x1, x2)
|
|
747
791
|
|
|
@@ -821,6 +865,13 @@ def logaddexp(x1, x2):
|
|
|
821
865
|
return np.logaddexp(x1, x2)
|
|
822
866
|
|
|
823
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
|
+
|
|
824
875
|
def logical_and(x1, x2):
|
|
825
876
|
return np.logical_and(x1, x2)
|
|
826
877
|
|
|
@@ -967,6 +1018,10 @@ def prod(x, axis=None, keepdims=False, dtype=None):
|
|
|
967
1018
|
return np.prod(x, axis=axis, keepdims=keepdims, dtype=dtype)
|
|
968
1019
|
|
|
969
1020
|
|
|
1021
|
+
def ptp(x, axis=None, keepdims=False):
|
|
1022
|
+
return np.ptp(x, axis=axis, keepdims=keepdims)
|
|
1023
|
+
|
|
1024
|
+
|
|
970
1025
|
def quantile(x, q, axis=None, method="linear", keepdims=False):
|
|
971
1026
|
axis = standardize_axis_for_numpy(axis)
|
|
972
1027
|
x = convert_to_tensor(x)
|
|
@@ -1024,7 +1079,9 @@ def searchsorted(sorted_sequence, values, side="left"):
|
|
|
1024
1079
|
f"sorted_sequence.shape={sorted_sequence.shape}"
|
|
1025
1080
|
)
|
|
1026
1081
|
out_type = (
|
|
1027
|
-
"int32"
|
|
1082
|
+
"int32"
|
|
1083
|
+
if sorted_sequence.shape[0] <= np.iinfo(np.int32).max
|
|
1084
|
+
else "int64"
|
|
1028
1085
|
)
|
|
1029
1086
|
return np.searchsorted(sorted_sequence, values, side=side).astype(out_type)
|
|
1030
1087
|
|
|
@@ -1071,6 +1128,11 @@ def split(x, indices_or_sections, axis=0):
|
|
|
1071
1128
|
return np.split(x, indices_or_sections, axis=axis)
|
|
1072
1129
|
|
|
1073
1130
|
|
|
1131
|
+
def array_split(x, indices_or_sections, axis=0):
|
|
1132
|
+
axis = standardize_axis_for_numpy(axis)
|
|
1133
|
+
return np.array_split(x, indices_or_sections, axis=axis)
|
|
1134
|
+
|
|
1135
|
+
|
|
1074
1136
|
def stack(x, axis=0):
|
|
1075
1137
|
axis = standardize_axis_for_numpy(axis)
|
|
1076
1138
|
dtype_set = set([getattr(a, "dtype", type(a)) for a in x])
|
|
@@ -1146,8 +1208,10 @@ def trace(x, offset=0, axis1=0, axis2=1):
|
|
|
1146
1208
|
axis2 = standardize_axis_for_numpy(axis2)
|
|
1147
1209
|
x = convert_to_tensor(x)
|
|
1148
1210
|
dtype = standardize_dtype(x.dtype)
|
|
1149
|
-
if dtype
|
|
1150
|
-
dtype =
|
|
1211
|
+
if dtype in ("bool", "int8", "int16"):
|
|
1212
|
+
dtype = "int32"
|
|
1213
|
+
elif dtype in ("uint8", "uint16"):
|
|
1214
|
+
dtype = "uint32"
|
|
1151
1215
|
return np.trace(x, offset=offset, axis1=axis1, axis2=axis2, dtype=dtype)
|
|
1152
1216
|
|
|
1153
1217
|
|
|
@@ -1275,6 +1339,14 @@ def negative(x):
|
|
|
1275
1339
|
return np.negative(x)
|
|
1276
1340
|
|
|
1277
1341
|
|
|
1342
|
+
def nextafter(x1, x2):
|
|
1343
|
+
x1 = convert_to_tensor(x1)
|
|
1344
|
+
x2 = convert_to_tensor(x2)
|
|
1345
|
+
dtype = dtypes.result_type(x1.dtype, x2.dtype, float)
|
|
1346
|
+
|
|
1347
|
+
return np.nextafter(x1, x2).astype(dtype)
|
|
1348
|
+
|
|
1349
|
+
|
|
1278
1350
|
def square(x):
|
|
1279
1351
|
x = convert_to_tensor(x)
|
|
1280
1352
|
if standardize_dtype(x.dtype) == "bool":
|
|
@@ -1303,6 +1375,23 @@ def transpose(x, axes=None):
|
|
|
1303
1375
|
return np.transpose(x, axes=axes)
|
|
1304
1376
|
|
|
1305
1377
|
|
|
1378
|
+
def trapezoid(y, x=None, dx=1.0, axis=-1):
|
|
1379
|
+
y = convert_to_tensor(y)
|
|
1380
|
+
result_dtype = dtypes.result_type(y.dtype, float)
|
|
1381
|
+
if x is not None:
|
|
1382
|
+
x = convert_to_tensor(x)
|
|
1383
|
+
dx = convert_to_tensor(dx)
|
|
1384
|
+
return np.trapezoid(y, x, dx=dx, axis=axis).astype(result_dtype)
|
|
1385
|
+
|
|
1386
|
+
|
|
1387
|
+
def vander(x, N=None, increasing=False):
|
|
1388
|
+
x = convert_to_tensor(x)
|
|
1389
|
+
result_dtype = dtypes.result_type(x.dtype)
|
|
1390
|
+
compute_dtype = dtypes.result_type(x.dtype, config.floatx())
|
|
1391
|
+
x = x.astype(compute_dtype)
|
|
1392
|
+
return np.vander(x, N=N, increasing=increasing).astype(result_dtype)
|
|
1393
|
+
|
|
1394
|
+
|
|
1306
1395
|
def var(x, axis=None, keepdims=False):
|
|
1307
1396
|
axis = standardize_axis_for_numpy(axis)
|
|
1308
1397
|
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
|
|
@@ -179,6 +178,10 @@ class OpenVINOKerasTensor:
|
|
|
179
178
|
first, other = align_operand_types(
|
|
180
179
|
first, other, "OpenVINOKerasTensor::__sub__"
|
|
181
180
|
)
|
|
181
|
+
if first.get_element_type() == Type.boolean:
|
|
182
|
+
return OpenVINOKerasTensor(
|
|
183
|
+
ov_opset.logical_xor(first, other).output(0)
|
|
184
|
+
)
|
|
182
185
|
return OpenVINOKerasTensor(ov_opset.subtract(first, other).output(0))
|
|
183
186
|
|
|
184
187
|
def __rsub__(self, other):
|
|
@@ -526,31 +529,11 @@ def ov_to_keras_type(ov_type):
|
|
|
526
529
|
|
|
527
530
|
@contextlib.contextmanager
|
|
528
531
|
def device_scope(device_name):
|
|
529
|
-
|
|
530
|
-
global_state.set_global_attribute("openvino_device", current_device)
|
|
532
|
+
yield
|
|
531
533
|
|
|
532
534
|
|
|
533
535
|
def get_device():
|
|
534
|
-
|
|
535
|
-
if device is None:
|
|
536
|
-
return "CPU"
|
|
537
|
-
return device
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
def _parse_device_input(device_name):
|
|
541
|
-
if isinstance(device_name, str):
|
|
542
|
-
# We support string value like "cpu:0", "gpu:1", and need to convert
|
|
543
|
-
# "gpu" to "cuda"
|
|
544
|
-
device_name = device_name.upper()
|
|
545
|
-
device_type, _ = device_name.split(":")
|
|
546
|
-
return device_type
|
|
547
|
-
else:
|
|
548
|
-
raise ValueError(
|
|
549
|
-
"Invalid value for argument `device_name`. "
|
|
550
|
-
"Expected a string like 'gpu:0' or 'cpu'. "
|
|
551
|
-
f"Received: device_name='{device_name}'"
|
|
552
|
-
)
|
|
553
|
-
return device_name
|
|
536
|
+
return "CPU"
|
|
554
537
|
|
|
555
538
|
|
|
556
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")
|
keras/src/backend/openvino/nn.py
CHANGED
|
@@ -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
|
-
|
|
42
|
-
|
|
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
|
-
|
|
48
|
-
|
|
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
|
-
|
|
132
|
-
|
|
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
|
-
|
|
144
|
-
|
|
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
|
-
|
|
378
|
-
"`
|
|
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
|
-
|
|
384
|
-
|
|
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
|
-
|
|
469
|
-
|
|
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
|
-
|
|
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
|
-
|
|
503
|
-
|
|
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")
|