Skip to content

Commit 3859fb4

Browse files
lkartheejames77777778fcholletlpizzinidevhertschuh
authored
Merge master into mlx (#19557)
* Introduce float8 training (#19488) * Add float8 training support * Add tests for fp8 training * Add `quantize_and_dequantize` test * Fix bugs and add float8 correctness tests * Cleanup * Address comments and cleanup * Add docstrings and some minor refactoring * Add `QuantizedFloat8DTypePolicy` * Add dtype policy setter * Fix torch dynamo issue by using `self._dtype_policy` * Improve test coverage * Add LoRA to ConvND layers (#19516) * Add LoRA to `BaseConv` * Add tests * Fix typo * Fix tests * Fix tests * Add path to run keras on dm-tree when optree is not available. * feat(losses): add Tversky loss implementation (#19511) * feat(losses): add Tversky loss implementation * adjusted documentation * Update KLD docs * Models and layers now return owned metrics recursively. (#19522) - added `Layer.metrics` to return all metrics owned by the layer and its sub-layers recursively. - `Layer.metrics_variables` now returns variables from all metrics recursively, not just the layer and its direct sub-layers. - `Model.metrics` now returns all metrics recursively, not just the model level metrics. - `Model.metrics_variables` now returns variables from all metrics recursively, not just the model level metrics. - added test coverage to test metrics and variables 2 levels deep. This is consistent with the Keras 2 behavior and how `Model/Layer.variables` and `Model/Layer.weights` work. * Update IoU ignore_class handling * Fix `RandomBrightness`, Enhance `IndexLookup` Initialization and Expand Test Coverage for `Preprocessing Layers` (#19513) * Add tests for CategoryEncoding class in category_encoding_test.py * fix * Fix IndexLookup class initialization and add test cases * Add test case for IndexLookupLayerTest without vocabulary * Fix IndexLookup class initialization * Add normalization test cases * Add test cases for Hashing class * Fix value range validation error in RandomBrightness class * Refactor IndexLookup class initialization and add test cases * Reffix ndexLookup class initialization and afix est cases * Add test for spectral norm * Add missing test decorator * Fix torch test * Fix code format * Generate API (#19530) * API Generator for Keras * API Generator for Keras * Generates API Gen via api_gen.sh * Remove recursive import of _tf_keras * Generate API Files via api_gen.sh * Update APIs * Added metrics from custom `train_step`/`test_step` are now returned. (#19529) This works the same way as in Keras 2, whereby the metrics are returned directly from the logs if the set of keys doesn't match the model metrics. * Use temp dir and abs path in `api_gen.py` (#19533) * Use temp dir and abs path * Use temp dir and abs path * Update Readme * Update API * Fix gradient accumulation when using `overwrite_with_gradient` during float8 training (#19534) * Fix gradient accumulation with `overwrite_with_gradient` in float8 training * Add comments * Fix annotation * Update code path in ignore path (#19537) * Add operations per run (#19538) * Include input shapes in model visualization. * Add pad_to_aspect_ratio feature in ops.image.resize * Add pad_to_aspect_ratio feature in Resizing layer. * Fix incorrect usage of `quantize` (#19541) * Add logic to prevent double quantization * Add detailed info for double quantization error * Update error msg * Add eigh op. * Add keepdim in argmax/argmin. * Fix small bug in model.save_weights (#19545) * Update public APIs. * eigh should work on JAX GPU * Copy init to keras/__init__.py (#19551) * Revert "Copy init to keras/__init__.py (#19551)" (#19552) This reverts commit da9af61. * fixes for master --------- Co-authored-by: james77777778 <[email protected]> Co-authored-by: Francois Chollet <[email protected]> Co-authored-by: Luca Pizzini <[email protected]> Co-authored-by: hertschuh <[email protected]> Co-authored-by: Faisal Alsrheed <[email protected]> Co-authored-by: Ramesh Sampath <[email protected]> Co-authored-by: Sachin Prasad <[email protected]> Co-authored-by: Uwe Schmidt <[email protected]>
1 parent 47c032d commit 3859fb4

File tree

769 files changed

+11122
-4404
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

769 files changed

+11122
-4404
lines changed

.github/workflows/actions.yml

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@ jobs:
2424
KERAS_HOME: .github/workflows/config/${{ matrix.backend }}
2525
steps:
2626
- uses: actions/checkout@v4
27-
- name: Check for changes in keras/applications
27+
- name: Check for changes in keras/src/applications
2828
uses: dorny/paths-filter@v3
2929
id: filter
3030
with:
3131
filters: |
3232
applications:
33-
- 'keras/applications/**'
33+
- 'keras/src/applications/**'
3434
- name: Set up Python
3535
uses: actions/setup-python@v5
3636
with:
@@ -49,13 +49,13 @@ jobs:
4949
run: |
5050
pip install -r requirements.txt --progress-bar off --upgrade
5151
pip uninstall -y keras keras-nightly
52-
pip install tf_keras==2.16.0rc0 --progress-bar off --upgrade
52+
pip install tf_keras==2.16.0 --progress-bar off --upgrade
5353
pip install -e "." --progress-bar off --upgrade
5454
- name: Test applications with pytest
5555
if: ${{ steps.filter.outputs.applications == 'true' }}
5656
run: |
57-
pytest keras/applications --cov=keras/applications
58-
coverage xml --include='keras/applications/*' -o apps-coverage.xml
57+
pytest keras/src/applications --cov=keras/src/applications
58+
coverage xml --include='keras/src/applications/*' -o apps-coverage.xml
5959
- name: Codecov keras.applications
6060
if: ${{ steps.filter.outputs.applications == 'true' }}
6161
uses: codecov/codecov-action@v4
@@ -80,8 +80,8 @@ jobs:
8080
pytest integration_tests/torch_workflow_test.py
8181
- name: Test with pytest
8282
run: |
83-
pytest keras --ignore keras/applications --cov=keras
84-
coverage xml --omit='keras/applications/*' -o core-coverage.xml
83+
pytest keras --ignore keras/src/applications --cov=keras
84+
coverage xml --omit='keras/src/applications/*,keras/api' -o core-coverage.xml
8585
- name: Codecov keras
8686
uses: codecov/codecov-action@v4
8787
with:
@@ -115,5 +115,14 @@ jobs:
115115
pip install -r requirements.txt --progress-bar off --upgrade
116116
pip uninstall -y keras keras-nightly
117117
pip install -e "." --progress-bar off --upgrade
118+
- name: Check for API changes
119+
run: |
120+
bash shell/api_gen.sh
121+
git status
122+
clean=$(git status | grep "nothing to commit")
123+
if [ -z "$clean" ]; then
124+
echo "Please run shell/api_gen.sh to generate API."
125+
exit 1
126+
fi
118127
- name: Lint
119128
run: bash shell/lint.sh

.github/workflows/nightly.yml

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ jobs:
5555
pytest integration_tests/torch_workflow_test.py
5656
- name: Test with pytest
5757
run: |
58-
pytest keras --ignore keras/applications --cov=keras
58+
pytest keras --ignore keras/src/applications --cov=keras
5959
6060
format:
6161
name: Check the code format
@@ -81,6 +81,15 @@ jobs:
8181
pip install -r requirements.txt --progress-bar off --upgrade
8282
pip uninstall -y keras keras-nightly
8383
pip install -e "." --progress-bar off --upgrade
84+
- name: Check for API changes
85+
run: |
86+
bash shell/api_gen.sh
87+
git status
88+
clean=$(git status | grep "nothing to commit")
89+
if [ -z "$clean" ]; then
90+
echo "Please run shell/api_gen.sh to generate API."
91+
exit 1
92+
fi
8493
- name: Lint
8594
run: bash shell/lint.sh
8695

@@ -108,4 +117,4 @@ jobs:
108117
with:
109118
password: ${{ secrets.PYPI_NIGHTLY_API_TOKEN }}
110119
packages-dir: dist/
111-
verbose: true
120+
verbose: true

.github/workflows/stale-issue-pr.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ on:
44
- cron: "30 1 * * *"
55
jobs:
66
close-issues:
7+
# Don't do this in forks
8+
if: github.repository == 'keras-team/keras'
79
runs-on: ubuntu-latest
810
permissions:
911
issues: write
@@ -12,6 +14,7 @@ jobs:
1214
- name: Awaiting response issues
1315
uses: actions/stale@v9
1416
with:
17+
operations-per-run: 500
1518
days-before-issue-stale: 14
1619
days-before-issue-close: 14
1720
stale-issue-label: "stale"
@@ -34,6 +37,7 @@ jobs:
3437
- name: Contribution issues
3538
uses: actions/stale@v9
3639
with:
40+
operations-per-run: 500
3741
days-before-issue-stale: 180
3842
days-before-issue-close: 365
3943
stale-issue-label: "stale"

.kokoro/github/ubuntu/gpu/build.sh

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ then
3434
python3 -c 'import tensorflow as tf;assert len(tf.config.list_physical_devices("GPU")) > 0'
3535

3636
# TODO: keras/layers/merging/merging_test.py::MergingLayersTest::test_sparse_dot_2d Fatal Python error: Aborted
37-
pytest keras --ignore keras/applications \
38-
--ignore keras/layers/merging/merging_test.py \
37+
pytest keras --ignore keras/src/applications \
38+
--ignore keras/src/layers/merging/merging_test.py \
3939
--cov=keras
4040
fi
4141

@@ -51,11 +51,11 @@ then
5151
# TODO: keras/layers/merging/merging_test.py::MergingLayersTest::test_sparse_dot_2d Fatal Python error: Aborted
5252
# TODO: keras/trainers/data_adapters/py_dataset_adapter_test.py::PyDatasetAdapterTest::test_basic_flow0 Fatal Python error: Aborted
5353
# keras/backend/jax/distribution_lib_test.py is configured for CPU test for now.
54-
pytest keras --ignore keras/applications \
55-
--ignore keras/layers/merging/merging_test.py \
56-
--ignore keras/trainers/data_adapters/py_dataset_adapter_test.py \
57-
--ignore keras/backend/jax/distribution_lib_test.py \
58-
--ignore keras/distribution/distribution_lib_test.py \
54+
pytest keras --ignore keras/src/applications \
55+
--ignore keras/src/layers/merging/merging_test.py \
56+
--ignore keras/src/trainers/data_adapters/py_dataset_adapter_test.py \
57+
--ignore keras/src/backend/jax/distribution_lib_test.py \
58+
--ignore keras/src/distribution/distribution_lib_test.py \
5959
--cov=keras
6060
fi
6161

@@ -68,6 +68,6 @@ then
6868
# Raise error if GPU is not detected.
6969
python3 -c 'import torch;assert torch.cuda.is_available()'
7070

71-
pytest keras --ignore keras/applications \
71+
pytest keras --ignore keras/src/applications \
7272
--cov=keras
7373
fi

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,12 @@ pip install -r requirements.txt
5050
python pip_build.py --install
5151
```
5252

53+
3. Run API generation script when creating PRs that update `keras_export` public APIs:
54+
55+
```
56+
./shell/api_gen.sh
57+
```
58+
5359
#### Adding GPU support
5460

5561
The `requirements.txt` file will install a CPU-only version of TensorFlow, JAX, and PyTorch. For GPU support, we also

api_gen.py

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
"""Script to generate keras public API in `keras/api` directory.
2+
3+
Usage:
4+
5+
Run via `./shell/api_gen.sh`.
6+
It generates API and formats user and generated APIs.
7+
"""
8+
9+
import os
10+
import shutil
11+
12+
import namex
13+
14+
package = "keras"
15+
16+
17+
def ignore_files(_, filenames):
18+
return [f for f in filenames if f.endswith("_test.py")]
19+
20+
21+
def copy_source_to_build_directory(root_path):
22+
# Copy sources (`keras/` directory and setup files) to build dir
23+
build_dir = os.path.join(root_path, "tmp_build_dir")
24+
if os.path.exists(build_dir):
25+
shutil.rmtree(build_dir)
26+
os.mkdir(build_dir)
27+
shutil.copytree(
28+
package, os.path.join(build_dir, package), ignore=ignore_files
29+
)
30+
return build_dir
31+
32+
33+
def create_legacy_directory(package_dir):
34+
src_dir = os.path.join(package_dir, "src")
35+
api_dir = os.path.join(package_dir, "api")
36+
# Make keras/_tf_keras/ by copying keras/
37+
tf_keras_dirpath_parent = os.path.join(api_dir, "_tf_keras")
38+
tf_keras_dirpath = os.path.join(tf_keras_dirpath_parent, "keras")
39+
os.makedirs(tf_keras_dirpath, exist_ok=True)
40+
with open(os.path.join(tf_keras_dirpath_parent, "__init__.py"), "w") as f:
41+
f.write("from keras.api._tf_keras import keras\n")
42+
with open(os.path.join(api_dir, "__init__.py")) as f:
43+
init_file = f.read()
44+
init_file = init_file.replace(
45+
"from keras.api import _legacy",
46+
"from keras.api import _tf_keras",
47+
)
48+
with open(os.path.join(api_dir, "__init__.py"), "w") as f:
49+
f.write(init_file)
50+
# Remove the import of `_tf_keras` in `keras/_tf_keras/keras/__init__.py`
51+
init_file = init_file.replace("from keras.api import _tf_keras\n", "\n")
52+
with open(os.path.join(tf_keras_dirpath, "__init__.py"), "w") as f:
53+
f.write(init_file)
54+
for dirname in os.listdir(api_dir):
55+
dirpath = os.path.join(api_dir, dirname)
56+
if os.path.isdir(dirpath) and dirname not in (
57+
"_legacy",
58+
"_tf_keras",
59+
"src",
60+
):
61+
destpath = os.path.join(tf_keras_dirpath, dirname)
62+
if os.path.exists(destpath):
63+
shutil.rmtree(destpath)
64+
shutil.copytree(
65+
dirpath,
66+
destpath,
67+
ignore=ignore_files,
68+
)
69+
70+
# Copy keras/_legacy/ file contents to keras/_tf_keras/keras
71+
legacy_submodules = [
72+
path[:-3]
73+
for path in os.listdir(os.path.join(src_dir, "legacy"))
74+
if path.endswith(".py")
75+
]
76+
legacy_submodules += [
77+
path
78+
for path in os.listdir(os.path.join(src_dir, "legacy"))
79+
if os.path.isdir(os.path.join(src_dir, "legacy", path))
80+
]
81+
82+
for root, _, fnames in os.walk(os.path.join(package_dir, "_legacy")):
83+
for fname in fnames:
84+
if fname.endswith(".py"):
85+
legacy_fpath = os.path.join(root, fname)
86+
tf_keras_root = root.replace("/_legacy", "/_tf_keras/keras")
87+
core_api_fpath = os.path.join(
88+
root.replace("/_legacy", ""), fname
89+
)
90+
if not os.path.exists(tf_keras_root):
91+
os.makedirs(tf_keras_root)
92+
tf_keras_fpath = os.path.join(tf_keras_root, fname)
93+
with open(legacy_fpath) as f:
94+
legacy_contents = f.read()
95+
legacy_contents = legacy_contents.replace(
96+
"keras.api._legacy", "keras.api._tf_keras.keras"
97+
)
98+
if os.path.exists(core_api_fpath):
99+
with open(core_api_fpath) as f:
100+
core_api_contents = f.read()
101+
core_api_contents = core_api_contents.replace(
102+
"from keras.api import _tf_keras\n", ""
103+
)
104+
for legacy_submodule in legacy_submodules:
105+
core_api_contents = core_api_contents.replace(
106+
f"from keras.api import {legacy_submodule}\n",
107+
"",
108+
)
109+
core_api_contents = core_api_contents.replace(
110+
f"keras.api.{legacy_submodule}",
111+
f"keras.api._tf_keras.keras.{legacy_submodule}",
112+
)
113+
legacy_contents = core_api_contents + "\n" + legacy_contents
114+
with open(tf_keras_fpath, "w") as f:
115+
f.write(legacy_contents)
116+
117+
# Delete keras/api/_legacy/
118+
shutil.rmtree(os.path.join(api_dir, "_legacy"))
119+
120+
121+
def export_version_string(api_init_fname):
122+
with open(api_init_fname) as f:
123+
contents = f.read()
124+
with open(api_init_fname, "w") as f:
125+
contents += "from keras.src.version import __version__\n"
126+
f.write(contents)
127+
128+
129+
def update_package_init(init_fname):
130+
contents = """
131+
# Import everything from /api/ into keras.
132+
from keras.api import * # noqa: F403
133+
from keras.api import __version__ # Import * ignores names start with "_".
134+
135+
import os
136+
137+
# Add everything in /api/ to the module search path.
138+
__path__.append(os.path.join(os.path.dirname(__file__), "api")) # noqa: F405
139+
140+
# Don't pollute namespace.
141+
del os
142+
143+
# Never autocomplete `.src` or `.api` on an imported keras object.
144+
def __dir__():
145+
keys = dict.fromkeys((globals().keys()))
146+
keys.pop("src")
147+
keys.pop("api")
148+
return list(keys)
149+
150+
151+
# Don't import `.src` or `.api` during `from keras import *`.
152+
__all__ = [
153+
name
154+
for name in globals().keys()
155+
if not (name.startswith("_") or name in ("src", "api"))
156+
]"""
157+
with open(init_fname) as f:
158+
init_contents = f.read()
159+
with open(init_fname, "w") as f:
160+
f.write(init_contents.replace("\nfrom keras import api", contents))
161+
162+
163+
def build():
164+
# Backup the `keras/__init__.py` and restore it on error in api gen.
165+
root_path = os.path.dirname(os.path.abspath(__file__))
166+
code_api_dir = os.path.join(root_path, package, "api")
167+
code_init_fname = os.path.join(root_path, package, "__init__.py")
168+
# Create temp build dir
169+
build_dir = copy_source_to_build_directory(root_path)
170+
build_api_dir = os.path.join(build_dir, package, "api")
171+
build_init_fname = os.path.join(build_dir, package, "__init__.py")
172+
build_api_init_fname = os.path.join(build_api_dir, "__init__.py")
173+
try:
174+
os.chdir(build_dir)
175+
# Generates `keras/api` directory.
176+
if os.path.exists(build_api_dir):
177+
shutil.rmtree(build_api_dir)
178+
if os.path.exists(build_init_fname):
179+
os.remove(build_init_fname)
180+
os.makedirs(build_api_dir)
181+
namex.generate_api_files(
182+
"keras", code_directory="src", target_directory="api"
183+
)
184+
# Creates `keras/__init__.py` importing from `keras/api`
185+
update_package_init(build_init_fname)
186+
# Add __version__ to keras package
187+
export_version_string(build_api_init_fname)
188+
# Creates `_tf_keras` with full keras API
189+
create_legacy_directory(package_dir=os.path.join(build_dir, package))
190+
# Copy back the keras/api and keras/__init__.py from build directory
191+
if os.path.exists(code_api_dir):
192+
shutil.rmtree(code_api_dir)
193+
shutil.copytree(build_api_dir, code_api_dir)
194+
shutil.copy(build_init_fname, code_init_fname)
195+
finally:
196+
# Clean up: remove the build directory (no longer needed)
197+
shutil.rmtree(build_dir)
198+
199+
200+
if __name__ == "__main__":
201+
build()

conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
import pytest # noqa: E402
1616

17-
from keras.backend import backend # noqa: E402
17+
from keras.src.backend import backend # noqa: E402
1818

1919

2020
def pytest_configure(config):

integration_tests/basic_full_flow.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
import pytest
33

44
import keras
5-
from keras import layers
6-
from keras import losses
7-
from keras import metrics
8-
from keras import optimizers
9-
from keras import testing
5+
from keras.src import layers
6+
from keras.src import losses
7+
from keras.src import metrics
8+
from keras.src import optimizers
9+
from keras.src import testing
1010

1111

1212
class MyModel(keras.Model):

0 commit comments

Comments
 (0)