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
@@ -0,0 +1,62 @@
1
+ """Adaptive Average Pooling 2D layer."""
2
+
3
+ from keras.src.api_export import keras_export
4
+ from keras.src.layers.pooling.base_adaptive_pooling import (
5
+ BaseAdaptiveAveragePooling,
6
+ )
7
+
8
+
9
+ @keras_export("keras.layers.AdaptiveAveragePooling2D")
10
+ class AdaptiveAveragePooling2D(BaseAdaptiveAveragePooling):
11
+ """Adaptive average pooling operation for 2D spatial data.
12
+
13
+ This layer applies an adaptive average pooling operation, which pools the
14
+ input such that the output has a target spatial size specified by
15
+ `output_size`, regardless of the input spatial size. The kernel size
16
+ and stride are automatically computed to achieve the target output size.
17
+
18
+ Args:
19
+ output_size: Integer or tuple of 2 integers specifying the
20
+ target output size.
21
+ If an integer, the same value is used for both height and width.
22
+ data_format: string, either `"channels_last"` or `"channels_first"`.
23
+ `"channels_last"` corresponds to inputs with shape
24
+ `(batch, height, width, channels)`.
25
+ `"channels_first"` corresponds to inputs with shape
26
+ `(batch, channels, height, width)`.
27
+ Defaults to the value found in your Keras config file at
28
+ `~/.keras/keras.json`. If never set, `"channels_last"` is used.
29
+
30
+ Input shape:
31
+ - If `data_format="channels_last"`: 4D tensor
32
+ `(batch_size, height, width, channels)`
33
+ - If `data_format="channels_first"`: 4D tensor
34
+ `(batch_size, channels, height, width)`
35
+
36
+ Output shape:
37
+ - If `data_format="channels_last"`:
38
+ `(batch_size, output_height, output_width, channels)`
39
+ - If `data_format="channels_first"`:
40
+ `(batch_size, channels, output_height, output_width)`
41
+
42
+ Examples:
43
+ >>> import numpy as np
44
+ >>> input_img = np.random.rand(1, 64, 64, 3)
45
+ >>> layer = AdaptiveAveragePooling2D(output_size=32)
46
+ >>> output_img = layer(input_img)
47
+ >>> output_img.shape
48
+ (1, 32, 32, 3)
49
+ """
50
+
51
+ def __init__(self, output_size, data_format=None, **kwargs):
52
+ if isinstance(output_size, int):
53
+ output_size_tuple = (output_size, output_size)
54
+ elif isinstance(output_size, (tuple, list)) and len(output_size) == 2:
55
+ output_size_tuple = tuple(output_size)
56
+ else:
57
+ raise TypeError(
58
+ f"`output_size` must be an integer or (height, width) tuple. "
59
+ f"Received: {output_size} of type {type(output_size)}"
60
+ )
61
+
62
+ super().__init__(output_size_tuple, data_format, **kwargs)
@@ -0,0 +1,63 @@
1
+ """Adaptive Average Pooling 3D layer."""
2
+
3
+ from keras.src.api_export import keras_export
4
+ from keras.src.layers.pooling.base_adaptive_pooling import (
5
+ BaseAdaptiveAveragePooling,
6
+ )
7
+
8
+
9
+ @keras_export("keras.layers.AdaptiveAveragePooling3D")
10
+ class AdaptiveAveragePooling3D(BaseAdaptiveAveragePooling):
11
+ """Adaptive average pooling operation for 3D volumetric data.
12
+
13
+ This layer applies an adaptive average pooling operation, which pools the
14
+ input such that the output has a target spatial size specified by
15
+ `output_size`, regardless of the input spatial size. The kernel size
16
+ and stride are automatically computed to achieve the target output size.
17
+
18
+ Args:
19
+ output_size: Integer or tuple of 3 integers specifying the
20
+ target output size.
21
+ If an integer, the same value is used for depth, height, and width.
22
+ data_format: string, either `"channels_last"` or `"channels_first"`.
23
+ `"channels_last"` corresponds to inputs with shape
24
+ `(batch, depth, height, width, channels)`.
25
+ `"channels_first"` corresponds to inputs with shape
26
+ `(batch, channels, depth, height, width)`.
27
+ Defaults to the value found in your Keras config file at
28
+ `~/.keras/keras.json`. If never set, `"channels_last"` is used.
29
+
30
+ Input shape:
31
+ - If `data_format="channels_last"`: 5D tensor
32
+ `(batch_size, depth, height, width, channels)`
33
+ - If `data_format="channels_first"`: 5D tensor
34
+ `(batch_size, channels, depth, height, width)`
35
+
36
+ Output shape:
37
+ - If `data_format="channels_last"`:
38
+ `(batch_size, output_depth, output_height, output_width, channels)`
39
+ - If `data_format="channels_first"`:
40
+ `(batch_size, channels, output_depth, output_height, output_width)`
41
+
42
+ Examples:
43
+ >>> import numpy as np
44
+ >>> input_vol = np.random.rand(1, 32, 32, 32, 3)
45
+ >>> layer = AdaptiveAveragePooling3D(output_size=16)
46
+ >>> output_vol = layer(input_vol)
47
+ >>> output_vol.shape
48
+ (1, 16, 16, 16, 3)
49
+ """
50
+
51
+ def __init__(self, output_size, data_format=None, **kwargs):
52
+ if isinstance(output_size, int):
53
+ output_size_tuple = (output_size, output_size, output_size)
54
+ elif isinstance(output_size, (tuple, list)) and len(output_size) == 3:
55
+ output_size_tuple = tuple(output_size)
56
+ else:
57
+ raise TypeError(
58
+ f"`output_size` must be an integer or "
59
+ f"(depth, height, width) tuple. "
60
+ f"Received: {output_size} of type {type(output_size)}"
61
+ )
62
+
63
+ super().__init__(output_size_tuple, data_format, **kwargs)
@@ -0,0 +1,65 @@
1
+ """Adaptive Max Pooling 1D layer."""
2
+
3
+ from keras.src.api_export import keras_export
4
+ from keras.src.layers.pooling.base_adaptive_pooling import (
5
+ BaseAdaptiveMaxPooling,
6
+ )
7
+
8
+
9
+ @keras_export("keras.layers.AdaptiveMaxPooling1D")
10
+ class AdaptiveMaxPooling1D(BaseAdaptiveMaxPooling):
11
+ """Adaptive max pooling operation for 1D temporal or spatial data.
12
+
13
+ This layer applies an adaptive max pooling operation, which pools the
14
+ input such that the output has a target length specified by `output_size`,
15
+ regardless of the input length. The kernel size and stride are automatically
16
+ computed to achieve the target output size.
17
+
18
+ Args:
19
+ output_size: Integer specifying the target output length.
20
+ data_format: string, either `"channels_last"` or `"channels_first"`.
21
+ `"channels_last"` corresponds to inputs with shape
22
+ `(batch, length, channels)`.
23
+ `"channels_first"` corresponds to inputs with shape
24
+ `(batch, channels, length)`.
25
+ Defaults to the value found in your Keras config file at
26
+ `~/.keras/keras.json`. If never set, `"channels_last"` is used.
27
+
28
+ Input shape:
29
+ - If `data_format="channels_last"`: 3D tensor
30
+ `(batch_size, length, channels)`
31
+ - If `data_format="channels_first"`: 3D tensor
32
+ `(batch_size, channels, length)`
33
+
34
+ Output shape:
35
+ - If `data_format="channels_last"`:
36
+ `(batch_size, output_length, channels)`
37
+ - If `data_format="channels_first"`:
38
+ `(batch_size, channels, output_length)`
39
+
40
+ Examples:
41
+ >>> import numpy as np
42
+ >>> input_seq = np.random.rand(1, 64, 3)
43
+ >>> layer = AdaptiveMaxPooling1D(output_size=32)
44
+ >>> output_seq = layer(input_seq)
45
+ >>> output_seq.shape
46
+ (1, 32, 3)
47
+ """
48
+
49
+ def __init__(self, output_size, data_format=None, **kwargs):
50
+ if isinstance(output_size, int):
51
+ output_size = (output_size,)
52
+ elif isinstance(output_size, (tuple, list)):
53
+ if len(output_size) != 1:
54
+ raise ValueError(
55
+ f"For 1D input, `output_size` tuple must have length 1. "
56
+ f"Received: {output_size}"
57
+ )
58
+ output_size = tuple(output_size)
59
+ else:
60
+ raise TypeError(
61
+ f"`output_size` must be an integer or tuple of 1 integer. "
62
+ f"Received: {output_size} of type {type(output_size)}"
63
+ )
64
+
65
+ super().__init__(output_size, data_format, **kwargs)
@@ -0,0 +1,62 @@
1
+ """Adaptive Max Pooling 2D layer."""
2
+
3
+ from keras.src.api_export import keras_export
4
+ from keras.src.layers.pooling.base_adaptive_pooling import (
5
+ BaseAdaptiveMaxPooling,
6
+ )
7
+
8
+
9
+ @keras_export("keras.layers.AdaptiveMaxPooling2D")
10
+ class AdaptiveMaxPooling2D(BaseAdaptiveMaxPooling):
11
+ """Adaptive max pooling operation for 2D spatial data.
12
+
13
+ This layer applies an adaptive max pooling operation, which pools the
14
+ input such that the output has a target spatial size specified by
15
+ `output_size`, regardless of the input spatial size. The kernel size
16
+ and stride are automatically computed to achieve the target output size.
17
+
18
+ Args:
19
+ output_size: Integer or tuple of 2 integers specifying the
20
+ target output size.
21
+ If an integer, the same value is used for both height and width.
22
+ data_format: string, either `"channels_last"` or `"channels_first"`.
23
+ `"channels_last"` corresponds to inputs with shape
24
+ `(batch, height, width, channels)`.
25
+ `"channels_first"` corresponds to inputs with shape
26
+ `(batch, channels, height, width)`.
27
+ Defaults to the value found in your Keras config file at
28
+ `~/.keras/keras.json`. If never set, `"channels_last"` is used.
29
+
30
+ Input shape:
31
+ - If `data_format="channels_last"`: 4D tensor
32
+ `(batch_size, height, width, channels)`
33
+ - If `data_format="channels_first"`: 4D tensor
34
+ `(batch_size, channels, height, width)`
35
+
36
+ Output shape:
37
+ - If `data_format="channels_last"`:
38
+ `(batch_size, output_height, output_width, channels)`
39
+ - If `data_format="channels_first"`:
40
+ `(batch_size, channels, output_height, output_width)`
41
+
42
+ Examples:
43
+ >>> import numpy as np
44
+ >>> input_img = np.random.rand(1, 64, 64, 3)
45
+ >>> layer = AdaptiveMaxPooling2D(output_size=32)
46
+ >>> output_img = layer(input_img)
47
+ >>> output_img.shape
48
+ (1, 32, 32, 3)
49
+ """
50
+
51
+ def __init__(self, output_size, data_format=None, **kwargs):
52
+ if isinstance(output_size, int):
53
+ output_size_tuple = (output_size, output_size)
54
+ elif isinstance(output_size, (tuple, list)) and len(output_size) == 2:
55
+ output_size_tuple = tuple(output_size)
56
+ else:
57
+ raise TypeError(
58
+ f"`output_size` must be an integer or (height, width) tuple. "
59
+ f"Received: {output_size} of type {type(output_size)}"
60
+ )
61
+
62
+ super().__init__(output_size_tuple, data_format, **kwargs)
@@ -0,0 +1,63 @@
1
+ """Adaptive Max Pooling 3D layer."""
2
+
3
+ from keras.src.api_export import keras_export
4
+ from keras.src.layers.pooling.base_adaptive_pooling import (
5
+ BaseAdaptiveMaxPooling,
6
+ )
7
+
8
+
9
+ @keras_export("keras.layers.AdaptiveMaxPooling3D")
10
+ class AdaptiveMaxPooling3D(BaseAdaptiveMaxPooling):
11
+ """Adaptive max pooling operation for 3D volumetric data.
12
+
13
+ This layer applies an adaptive max pooling operation, which pools the
14
+ input such that the output has a target spatial size specified by
15
+ `output_size`, regardless of the input spatial size. The kernel size
16
+ and stride are automatically computed to achieve the target output size.
17
+
18
+ Args:
19
+ output_size: Integer or tuple of 3 integers specifying the
20
+ target output size.
21
+ If an integer, the same value is used for depth, height, and width.
22
+ data_format: string, either `"channels_last"` or `"channels_first"`.
23
+ `"channels_last"` corresponds to inputs with shape
24
+ `(batch, depth, height, width, channels)`.
25
+ `"channels_first"` corresponds to inputs with shape
26
+ `(batch, channels, depth, height, width)`.
27
+ Defaults to the value found in your Keras config file at
28
+ `~/.keras/keras.json`. If never set, `"channels_last"` is used.
29
+
30
+ Input shape:
31
+ - If `data_format="channels_last"`: 5D tensor
32
+ `(batch_size, depth, height, width, channels)`
33
+ - If `data_format="channels_first"`: 5D tensor
34
+ `(batch_size, channels, depth, height, width)`
35
+
36
+ Output shape:
37
+ - If `data_format="channels_last"`:
38
+ `(batch_size, output_depth, output_height, output_width, channels)`
39
+ - If `data_format="channels_first"`:
40
+ `(batch_size, channels, output_depth, output_height, output_width)`
41
+
42
+ Examples:
43
+ >>> import numpy as np
44
+ >>> input_vol = np.random.rand(1, 32, 32, 32, 3)
45
+ >>> layer = AdaptiveMaxPooling3D(output_size=16)
46
+ >>> output_vol = layer(input_vol)
47
+ >>> output_vol.shape
48
+ (1, 16, 16, 16, 3)
49
+ """
50
+
51
+ def __init__(self, output_size, data_format=None, **kwargs):
52
+ if isinstance(output_size, int):
53
+ output_size_tuple = (output_size, output_size, output_size)
54
+ elif isinstance(output_size, (tuple, list)) and len(output_size) == 3:
55
+ output_size_tuple = tuple(output_size)
56
+ else:
57
+ raise TypeError(
58
+ f"`output_size` must be an integer or "
59
+ f"(depth, height, width) tuple. "
60
+ f"Received: {output_size} of type {type(output_size)}"
61
+ )
62
+
63
+ super().__init__(output_size_tuple, data_format, **kwargs)
@@ -0,0 +1,63 @@
1
+ """Base classes for adaptive pooling layers."""
2
+
3
+ from keras.src import ops
4
+ from keras.src.backend import config
5
+ from keras.src.layers.layer import Layer
6
+
7
+
8
+ class BaseAdaptivePooling(Layer):
9
+ """Base class shared by all adaptive pooling layers."""
10
+
11
+ def __init__(self, output_size, data_format=None, **kwargs):
12
+ """Initialize base adaptive pooling layer.
13
+
14
+ Args:
15
+ output_size: Normalized spatial output size as a tuple
16
+ (for example, (32,), (32, 32), or (32, 32, 32)).
17
+ data_format: Either "channels_last" or "channels_first".
18
+ **kwargs: Additional layer keyword arguments.
19
+ """
20
+ super().__init__(**kwargs)
21
+ self.output_size = output_size
22
+ self.data_format = data_format or config.image_data_format()
23
+ if self.data_format not in {"channels_first", "channels_last"}:
24
+ raise ValueError(
25
+ f"Invalid data_format: {self.data_format}. "
26
+ "Expected 'channels_first' or 'channels_last'."
27
+ )
28
+
29
+ def compute_output_shape(self, input_shape):
30
+ """Return the output shape tensor after pooling."""
31
+ batch_size = input_shape[0]
32
+ if self.data_format == "channels_last":
33
+ channels = input_shape[-1]
34
+ return (batch_size, *self.output_size, channels)
35
+ else:
36
+ channels = input_shape[1]
37
+ return (batch_size, channels, *self.output_size)
38
+
39
+ def get_config(self):
40
+ config_dict = {
41
+ "output_size": self.output_size,
42
+ "data_format": self.data_format,
43
+ }
44
+ base_config = super().get_config()
45
+ return {**base_config, **config_dict}
46
+
47
+
48
+ class BaseAdaptiveAveragePooling(BaseAdaptivePooling):
49
+ """Base class for adaptive average pooling in 1D, 2D, and 3D."""
50
+
51
+ def call(self, inputs):
52
+ return ops.adaptive_average_pool(
53
+ inputs, output_size=self.output_size, data_format=self.data_format
54
+ )
55
+
56
+
57
+ class BaseAdaptiveMaxPooling(BaseAdaptivePooling):
58
+ """Base class for adaptive max pooling in 1D, 2D, and 3D."""
59
+
60
+ def call(self, inputs):
61
+ return ops.adaptive_max_pool(
62
+ inputs, output_size=self.output_size, data_format=self.data_format
63
+ )
@@ -95,9 +95,6 @@ class Discretization(DataLayer):
95
95
  dtype=None,
96
96
  name=None,
97
97
  ):
98
- if dtype is None:
99
- dtype = "int64" if output_mode == "int" else backend.floatx()
100
-
101
98
  super().__init__(name=name, dtype=dtype)
102
99
 
103
100
  if sparse and not backend.SUPPORTS_SPARSE_TENSORS:
@@ -155,6 +152,10 @@ class Discretization(DataLayer):
155
152
  def input_dtype(self):
156
153
  return backend.floatx()
157
154
 
155
+ @property
156
+ def output_dtype(self):
157
+ return self.compute_dtype if self.output_mode != "int" else "int32"
158
+
158
159
  def adapt(self, data, steps=None):
159
160
  """Computes bin boundaries from quantiles in a input dataset.
160
161
 
@@ -213,7 +214,7 @@ class Discretization(DataLayer):
213
214
  self.summary = np.array([[], []], dtype="float32")
214
215
 
215
216
  def compute_output_spec(self, inputs):
216
- return backend.KerasTensor(shape=inputs.shape, dtype=self.compute_dtype)
217
+ return backend.KerasTensor(shape=inputs.shape, dtype=self.output_dtype)
217
218
 
218
219
  def load_own_variables(self, store):
219
220
  if len(store) == 1:
@@ -234,7 +235,7 @@ class Discretization(DataLayer):
234
235
  indices,
235
236
  output_mode=self.output_mode,
236
237
  depth=len(self.bin_boundaries) + 1,
237
- dtype=self.compute_dtype,
238
+ dtype=self.output_dtype,
238
239
  sparse=self.sparse,
239
240
  backend_module=self.backend,
240
241
  )
@@ -4,6 +4,7 @@ import numpy as np
4
4
 
5
5
  from keras.src import backend
6
6
  from keras.src.layers.layer import Layer
7
+ from keras.src.saving import serialization_lib
7
8
  from keras.src.utils import argument_validation
8
9
  from keras.src.utils import numerical_utils
9
10
  from keras.src.utils import tf_utils
@@ -178,7 +179,12 @@ class IndexLookup(Layer):
178
179
  self.vocabulary_dtype = tf.as_dtype(vocabulary_dtype).name
179
180
  self._frozen_vocab_size = kwargs.pop("vocabulary_size", None)
180
181
 
181
- self.input_vocabulary = vocabulary
182
+ # Remember original `vocabulary` as `input_vocabulary` for serialization
183
+ # via `get_config`. However, if `vocabulary` is a file path or a URL, we
184
+ # serialize the vocabulary as an asset and clear the original path/URL.
185
+ self.input_vocabulary = (
186
+ vocabulary if not isinstance(vocabulary, str) else None
187
+ )
182
188
  self.input_idf_weights = idf_weights
183
189
 
184
190
  # We set this hidden attr to
@@ -382,6 +388,18 @@ class IndexLookup(Layer):
382
388
  )
383
389
 
384
390
  if isinstance(vocabulary, str):
391
+ if serialization_lib.in_safe_mode():
392
+ raise ValueError(
393
+ "Requested the loading of a vocabulary file outside of the "
394
+ "model archive. This carries a potential risk of loading "
395
+ "arbitrary and sensitive files and thus it is disallowed "
396
+ "by default. If you trust the source of the artifact, you "
397
+ "can override this error by passing `safe_mode=False` to "
398
+ "the loading function, or calling "
399
+ "`keras.config.enable_unsafe_deserialization(). "
400
+ f"Vocabulary file: '{vocabulary}'"
401
+ )
402
+
385
403
  if not tf.io.gfile.exists(vocabulary):
386
404
  raise ValueError(
387
405
  f"Vocabulary file {vocabulary} does not exist."
@@ -6,6 +6,7 @@ from keras.src import backend
6
6
  from keras.src import ops
7
7
  from keras.src.api_export import keras_export
8
8
  from keras.src.layers.preprocessing.data_layer import DataLayer
9
+ from keras.src.trainers.data_adapters.py_dataset_adapter import PyDataset
9
10
  from keras.src.utils.module_utils import tensorflow as tf
10
11
 
11
12
 
@@ -43,10 +44,12 @@ class Normalization(DataLayer):
43
44
  will be broadcast to the shape of the kept axes above;
44
45
  if the value(s) cannot be broadcast, an error will be raised when
45
46
  this layer's `build()` method is called.
47
+ `mean` and `variance` must be specified together.
46
48
  variance: The variance value(s) to use during normalization. The passed
47
49
  value(s) will be broadcast to the shape of the kept axes above;
48
50
  if the value(s) cannot be broadcast, an error will be raised when
49
51
  this layer's `build()` method is called.
52
+ `mean` and `variance` must be specified together.
50
53
  invert: If `True`, this layer will apply the inverse transformation
51
54
  to its inputs: it would turn a normalized input back into its
52
55
  original form.
@@ -227,6 +230,18 @@ class Normalization(DataLayer):
227
230
  # Batch dataset if it isn't batched
228
231
  data = data.batch(128)
229
232
  input_shape = tuple(data.element_spec.shape)
233
+ elif isinstance(data, PyDataset):
234
+ data = data[0]
235
+ if isinstance(data, tuple):
236
+ # handling (x, y) or (x, y, sample_weight)
237
+ data = data[0]
238
+ input_shape = data.shape
239
+ else:
240
+ raise TypeError(
241
+ f"Unsupported data type: {type(data)}. `adapt` supports "
242
+ f"`np.ndarray`, backend tensors, `tf.data.Dataset`, and "
243
+ f"`keras.utils.PyDataset`."
244
+ )
230
245
 
231
246
  if not self.built:
232
247
  self.build(input_shape)
@@ -246,7 +261,7 @@ class Normalization(DataLayer):
246
261
  elif backend.is_tensor(data):
247
262
  total_mean = ops.mean(data, axis=self._reduce_axis)
248
263
  total_var = ops.var(data, axis=self._reduce_axis)
249
- elif isinstance(data, tf.data.Dataset):
264
+ elif isinstance(data, (tf.data.Dataset, PyDataset)):
250
265
  total_mean = ops.zeros(self._mean_and_var_shape)
251
266
  total_var = ops.zeros(self._mean_and_var_shape)
252
267
  total_count = 0
@@ -48,13 +48,55 @@ class Dropout(Layer):
48
48
  )
49
49
  self.rate = rate
50
50
  self.seed = seed
51
- self.noise_shape = noise_shape
51
+ self.noise_shape = self._validate_noise_shape(noise_shape)
52
52
  if rate > 0:
53
53
  self.seed_generator = backend.random.SeedGenerator(seed)
54
54
  self.supports_masking = True
55
55
 
56
56
  self._build_at_init()
57
57
 
58
+ def _validate_noise_shape(self, noise_shape):
59
+ if noise_shape is None:
60
+ return None
61
+
62
+ if isinstance(noise_shape, str):
63
+ raise ValueError(
64
+ f"Invalid value received for argument `noise_shape`. "
65
+ f"Expected a tuple or list of integers. "
66
+ f"Received: noise_shape={noise_shape}"
67
+ )
68
+
69
+ if not isinstance(noise_shape, tuple):
70
+ try:
71
+ noise_shape = tuple(noise_shape)
72
+ except TypeError:
73
+ raise ValueError(
74
+ f"Invalid value received for argument `noise_shape`. "
75
+ f"Expected an iterable of integers "
76
+ f"(e.g., a tuple or list). "
77
+ f"Received: noise_shape={noise_shape}"
78
+ )
79
+
80
+ for i, dim in enumerate(noise_shape):
81
+ if dim is not None:
82
+ if not isinstance(dim, int):
83
+ raise ValueError(
84
+ f"Invalid value received for argument `noise_shape`. "
85
+ f"Expected all elements to be integers or None. "
86
+ f"Received element at index {i}: {dim} "
87
+ f"(type: {type(dim).__name__})"
88
+ )
89
+
90
+ if dim <= 0:
91
+ raise ValueError(
92
+ f"Invalid value received for argument `noise_shape`. "
93
+ f"Expected all dimensions to be positive integers "
94
+ f"or None. "
95
+ f"Received negative or zero value at index {i}: {dim}"
96
+ )
97
+
98
+ return noise_shape
99
+
58
100
  def call(self, inputs, training=False):
59
101
  if training and self.rate > 0:
60
102
  return backend.random.dropout(
@@ -261,7 +261,7 @@ class GRUCell(Layer, DropoutRNNCell):
261
261
  matrix_x = ops.matmul(inputs, self.kernel)
262
262
  if self.use_bias:
263
263
  # biases: bias_z_i, bias_r_i, bias_h_i
264
- matrix_x += input_bias
264
+ matrix_x = ops.add(matrix_x, input_bias)
265
265
 
266
266
  x_z, x_r, x_h = ops.split(matrix_x, 3, axis=-1)
267
267
 
@@ -276,9 +276,9 @@ class LSTMCell(Layer, DropoutRNNCell):
276
276
 
277
277
  z = ops.matmul(inputs, self.kernel)
278
278
 
279
- z += ops.matmul(h_tm1, self.recurrent_kernel)
279
+ z = ops.add(z, ops.matmul(h_tm1, self.recurrent_kernel))
280
280
  if self.use_bias:
281
- z += self.bias
281
+ z = ops.add(z, self.bias)
282
282
 
283
283
  z = ops.split(z, 4, axis=1)
284
284
  c, o = self._compute_carry_and_output_fused(z, c_tm1)
@@ -212,6 +212,7 @@ class RNN(Layer):
212
212
  self.supports_masking = True
213
213
  self.input_spec = None
214
214
  self.states = None
215
+ self._expected_batch_size = None
215
216
 
216
217
  state_size = getattr(self.cell, "state_size", None)
217
218
  if state_size is None:
@@ -283,6 +284,9 @@ class RNN(Layer):
283
284
  f"batch size: sequence.shape={sequences_shape}"
284
285
  )
285
286
  self._create_state_variables(sequences_shape[0])
287
+ self._expected_batch_size = ops.shape(
288
+ tree.flatten(self.states)[0]
289
+ )[0]
286
290
 
287
291
  @tracking.no_automatic_dependency_tracking
288
292
  def _create_state_variables(self, batch_size):
@@ -382,6 +386,21 @@ class RNN(Layer):
382
386
  initial_state = self.get_initial_state(
383
387
  batch_size=ops.shape(sequences)[0]
384
388
  )
389
+ if self.stateful:
390
+ actual_batch_size = sequences.shape[0]
391
+ if (
392
+ self._expected_batch_size is not None
393
+ and actual_batch_size is not None
394
+ and actual_batch_size != self._expected_batch_size
395
+ ):
396
+ raise ValueError(
397
+ f"If an RNN is stateful, the batch size of the "
398
+ f"input sequences must be the same as the batch "
399
+ f"size of the initial state. \n"
400
+ f"- Expected batch size: {self._expected_batch_size}\n"
401
+ f"- Received batch size: {actual_batch_size}"
402
+ )
403
+
385
404
  # RNN expect the states in a list, even if single state.
386
405
  if not tree.is_nested(initial_state):
387
406
  initial_state = [initial_state]
@@ -160,7 +160,7 @@ class SimpleRNNCell(Layer, DropoutRNNCell):
160
160
  sequence = sequence * dp_mask
161
161
  h = ops.matmul(sequence, self.kernel)
162
162
  if self.bias is not None:
163
- h += self.bias
163
+ h = ops.add(h, self.bias)
164
164
 
165
165
  if training and rec_dp_mask is not None:
166
166
  prev_output = prev_output * rec_dp_mask
keras/src/losses/loss.py CHANGED
@@ -211,7 +211,7 @@ def apply_mask(sample_weight, mask, dtype, reduction):
211
211
  dtype,
212
212
  )
213
213
  valid = ops.sum(mask) # May be 0!
214
- mask *= total / (valid + backend.epsilon())
214
+ mask *= ops.divide_no_nan(total, valid)
215
215
 
216
216
  if sample_weight is not None:
217
217
  sample_weight = ops.cast(sample_weight, dtype=dtype)