From 50889c809e59417b2880a6b50ebea3e2735b0fa0 Mon Sep 17 00:00:00 2001 From: felix Date: Wed, 10 Apr 2024 07:45:53 +0200 Subject: [PATCH 01/18] tf upgrade by keeping keras v2 --- docs/source/using_doctr/using_model_export.rst | 2 ++ doctr/file_utils.py | 8 ++++++++ doctr/models/modules/transformer/tensorflow.py | 2 -- doctr/models/recognition/parseq/tensorflow.py | 3 --- doctr/transforms/modules/tensorflow.py | 1 - pyproject.toml | 10 ++++------ .../classification/train_tensorflow_character.py | 8 +++++++- .../classification/train_tensorflow_orientation.py | 8 +++++++- references/detection/train_tensorflow.py | 8 +++++++- references/recognition/train_tensorflow.py | 10 ++++++++-- tests/tensorflow/test_models_classification_tf.py | 1 + tests/tensorflow/test_models_detection_tf.py | 2 ++ tests/tensorflow/test_models_recognition_tf.py | 1 + 13 files changed, 47 insertions(+), 17 deletions(-) diff --git a/docs/source/using_doctr/using_model_export.rst b/docs/source/using_doctr/using_model_export.rst index 48f570f699..b2fcbb0a79 100644 --- a/docs/source/using_doctr/using_model_export.rst +++ b/docs/source/using_doctr/using_model_export.rst @@ -57,6 +57,7 @@ It defines a common format for representing models, including the network struct .. code:: python3 import tensorflow as tf + tf.config.run_functions_eagerly(True) # Required for some models from doctr.models import vitstr_small from doctr.models.utils import export_model_to_onnx @@ -65,6 +66,7 @@ It defines a common format for representing models, including the network struct model = vitstr_small(pretrained=True, exportable=True) dummy_input = [tf.TensorSpec([batch_size, input_shape], tf.float32, name="input")] model_path, output = export_model_to_onnx(model, model_name="vitstr.onnx", dummy_input=dummy_input) + tf.config.run_functions_eagerly(False) # Revert after conversion back to default .. tab:: PyTorch diff --git a/doctr/file_utils.py b/doctr/file_utils.py index 68e9dfffac..c201ffbb77 100644 --- a/doctr/file_utils.py +++ b/doctr/file_utils.py @@ -76,6 +76,14 @@ " is installed and that either USE_TF or USE_TORCH is enabled." ) +if _tf_available: # Compatibility fix to make sure tf.keras stays at Keras 2 + if "TF_USE_LEGACY_KERAS" not in os.environ: + os.environ["TF_USE_LEGACY_KERAS"] = "1" + elif os.environ["TF_USE_LEGACY_KERAS"] != "1": + raise ValueError( + "docTR is only compatible with Keras 2, but you have explicitly set `TF_USE_LEGACY_KERAS` to `0`. " + ) + def requires_package(name: str, extra_message: Optional[str] = None) -> None: # pragma: no cover """ diff --git a/doctr/models/modules/transformer/tensorflow.py b/doctr/models/modules/transformer/tensorflow.py index eef4f3dbea..3fc1d17f27 100644 --- a/doctr/models/modules/transformer/tensorflow.py +++ b/doctr/models/modules/transformer/tensorflow.py @@ -13,8 +13,6 @@ __all__ = ["Decoder", "PositionalEncoding", "EncoderBlock", "PositionwiseFeedForward", "MultiHeadAttention"] -tf.config.run_functions_eagerly(True) - class PositionalEncoding(layers.Layer, NestedObject): """Compute positional encoding""" diff --git a/doctr/models/recognition/parseq/tensorflow.py b/doctr/models/recognition/parseq/tensorflow.py index bca7806903..4d46b8687e 100644 --- a/doctr/models/recognition/parseq/tensorflow.py +++ b/doctr/models/recognition/parseq/tensorflow.py @@ -167,7 +167,6 @@ def __init__( self.postprocessor = PARSeqPostProcessor(vocab=self.vocab) - @tf.function def generate_permutations(self, seqlen: tf.Tensor) -> tf.Tensor: # Generates permutations of the target sequence. # Translated from https://github.com/baudm/parseq/blob/main/strhub/models/parseq/system.py @@ -214,7 +213,6 @@ def generate_permutations(self, seqlen: tf.Tensor) -> tf.Tensor: ) return combined - @tf.function def generate_permutations_attention_masks(self, permutation: tf.Tensor) -> Tuple[tf.Tensor, tf.Tensor]: # Generate source and target mask for the decoder attention. sz = permutation.shape[0] @@ -234,7 +232,6 @@ def generate_permutations_attention_masks(self, permutation: tf.Tensor) -> Tuple target_mask = mask[1:, :-1] return tf.cast(source_mask, dtype=tf.bool), tf.cast(target_mask, dtype=tf.bool) - @tf.function def decode( self, target: tf.Tensor, diff --git a/doctr/transforms/modules/tensorflow.py b/doctr/transforms/modules/tensorflow.py index b3f7bcfd8a..8dd870e3e7 100644 --- a/doctr/transforms/modules/tensorflow.py +++ b/doctr/transforms/modules/tensorflow.py @@ -395,7 +395,6 @@ def __init__(self, kernel_shape: Union[int, Iterable[int]], std: Tuple[float, fl def extra_repr(self) -> str: return f"kernel_shape={self.kernel_shape}, std={self.std}" - @tf.function def __call__(self, img: tf.Tensor) -> tf.Tensor: return tf.squeeze( _gaussian_filter( diff --git a/pyproject.toml b/pyproject.toml index aa0e02f98e..9338887ca7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -52,9 +52,8 @@ dependencies = [ [project.optional-dependencies] tf = [ - # cf. https://github.com/mindee/doctr/pull/1182 - # cf. https://github.com/mindee/doctr/pull/1461 - "tensorflow>=2.11.0,<2.16.0", + "tensorflow>=2.15.0", + "tf-keras>=2.15.0", # Keep keras 2 compatibility "tf2onnx>=1.16.0,<2.0.0", # cf. https://github.com/onnx/tensorflow-onnx/releases/tag/v1.16.0 # TODO: This is a temporary fix until we can upgrade to a newer version of tensorflow "numpy>=1.16.0,<2.0.0", @@ -98,9 +97,8 @@ docs = [ ] dev = [ # Tensorflow - # cf. https://github.com/mindee/doctr/pull/1182 - # cf. https://github.com/mindee/doctr/pull/1461 - "tensorflow>=2.11.0,<2.16.0", + "tensorflow>=2.15.0", + "tf-keras>=2.15.0", # Keep keras 2 compatibility "tf2onnx>=1.16.0,<2.0.0", # cf. https://github.com/onnx/tensorflow-onnx/releases/tag/v1.16.0 # PyTorch "torch>=1.12.0,<3.0.0", diff --git a/references/classification/train_tensorflow_character.py b/references/classification/train_tensorflow_character.py index b2d24f2dbf..e647e14ddd 100644 --- a/references/classification/train_tensorflow_character.py +++ b/references/classification/train_tensorflow_character.py @@ -6,6 +6,7 @@ import os os.environ["USE_TF"] = "1" +os.environ["TF_USE_LEGACY_KERAS"] = "1" # docTR requires Keras v2 os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2" import datetime @@ -82,6 +83,11 @@ def record_lr( return lr_recorder[: len(loss_recorder)], loss_recorder +@tf.function +def apply_grads(optimizer, grads, model): + optimizer.apply_gradients(zip(grads, model.trainable_weights)) + + def fit_one_epoch(model, train_loader, batch_transforms, optimizer, amp=False): # Iterate over the batches of the dataset pbar = tqdm(train_loader, position=1) @@ -94,7 +100,7 @@ def fit_one_epoch(model, train_loader, batch_transforms, optimizer, amp=False): grads = tape.gradient(train_loss, model.trainable_weights) if amp: grads = optimizer.get_unscaled_gradients(grads) - optimizer.apply_gradients(zip(grads, model.trainable_weights)) + apply_grads(optimizer, grads, model) pbar.set_description(f"Training loss: {train_loss.numpy().mean():.6}") diff --git a/references/classification/train_tensorflow_orientation.py b/references/classification/train_tensorflow_orientation.py index e063174944..f4a0d21516 100644 --- a/references/classification/train_tensorflow_orientation.py +++ b/references/classification/train_tensorflow_orientation.py @@ -6,6 +6,7 @@ import os os.environ["USE_TF"] = "1" +os.environ["TF_USE_LEGACY_KERAS"] = "1" # docTR requires Keras v2 os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2" import datetime @@ -96,6 +97,11 @@ def record_lr( return lr_recorder[: len(loss_recorder)], loss_recorder +@tf.function +def apply_grads(optimizer, grads, model): + optimizer.apply_gradients(zip(grads, model.trainable_weights)) + + def fit_one_epoch(model, train_loader, batch_transforms, optimizer, amp=False): # Iterate over the batches of the dataset pbar = tqdm(train_loader, position=1) @@ -108,7 +114,7 @@ def fit_one_epoch(model, train_loader, batch_transforms, optimizer, amp=False): grads = tape.gradient(train_loss, model.trainable_weights) if amp: grads = optimizer.get_unscaled_gradients(grads) - optimizer.apply_gradients(zip(grads, model.trainable_weights)) + apply_grads(optimizer, grads, model) pbar.set_description(f"Training loss: {train_loss.numpy().mean():.6}") diff --git a/references/detection/train_tensorflow.py b/references/detection/train_tensorflow.py index b9c14494ad..adc4af0d69 100644 --- a/references/detection/train_tensorflow.py +++ b/references/detection/train_tensorflow.py @@ -6,6 +6,7 @@ import os os.environ["USE_TF"] = "1" +os.environ["TF_USE_LEGACY_KERAS"] = "1" # docTR requires Keras v2 os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2" import datetime @@ -82,6 +83,11 @@ def record_lr( return lr_recorder[: len(loss_recorder)], loss_recorder +@tf.function +def apply_grads(optimizer, grads, model): + optimizer.apply_gradients(zip(grads, model.trainable_weights)) + + def fit_one_epoch(model, train_loader, batch_transforms, optimizer, amp=False): train_iter = iter(train_loader) # Iterate over the batches of the dataset @@ -94,7 +100,7 @@ def fit_one_epoch(model, train_loader, batch_transforms, optimizer, amp=False): grads = tape.gradient(train_loss, model.trainable_weights) if amp: grads = optimizer.get_unscaled_gradients(grads) - optimizer.apply_gradients(zip(grads, model.trainable_weights)) + apply_grads(optimizer, grads, model) pbar.set_description(f"Training loss: {train_loss.numpy():.6}") diff --git a/references/recognition/train_tensorflow.py b/references/recognition/train_tensorflow.py index c76355a2f2..7801307382 100644 --- a/references/recognition/train_tensorflow.py +++ b/references/recognition/train_tensorflow.py @@ -6,6 +6,7 @@ import os os.environ["USE_TF"] = "1" +os.environ["TF_USE_LEGACY_KERAS"] = "1" # docTR requires Keras v2 os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2" import datetime @@ -83,6 +84,11 @@ def record_lr( return lr_recorder[: len(loss_recorder)], loss_recorder +@tf.function +def apply_grads(optimizer, grads, model): + optimizer.apply_gradients(zip(grads, model.trainable_weights)) + + def fit_one_epoch(model, train_loader, batch_transforms, optimizer, amp=False): train_iter = iter(train_loader) # Iterate over the batches of the dataset @@ -95,7 +101,7 @@ def fit_one_epoch(model, train_loader, batch_transforms, optimizer, amp=False): grads = tape.gradient(train_loss, model.trainable_weights) if amp: grads = optimizer.get_unscaled_gradients(grads) - optimizer.apply_gradients(zip(grads, model.trainable_weights)) + apply_grads(optimizer, grads, model) pbar.set_description(f"Training loss: {train_loss.numpy().mean():.6}") @@ -254,7 +260,7 @@ def main(args): T.RandomSaturation(0.3), T.RandomContrast(0.3), T.RandomBrightness(0.3), - T.RandomApply(T.RandomShadow(), 0.4), + # T.RandomApply(T.RandomShadow(), 0.4), # NOTE: RandomShadow is broken atm T.RandomApply(T.GaussianNoise(mean=0.1, std=0.1), 0.1), T.RandomApply(T.GaussianBlur(kernel_shape=3, std=(0.1, 0.1)), 0.3), ]), diff --git a/tests/tensorflow/test_models_classification_tf.py b/tests/tensorflow/test_models_classification_tf.py index 11f4ea4114..9d8c362fde 100644 --- a/tests/tensorflow/test_models_classification_tf.py +++ b/tests/tensorflow/test_models_classification_tf.py @@ -252,6 +252,7 @@ def test_models_onnx_export(arch_name, input_shape, output_size): model_path, output = export_model_to_onnx( model, model_name=os.path.join(tmpdir, "model"), dummy_input=dummy_input ) + tf.config.run_functions_eagerly(False) # Revert after conversion back to default assert os.path.exists(model_path) # Inference diff --git a/tests/tensorflow/test_models_detection_tf.py b/tests/tensorflow/test_models_detection_tf.py index ba5f50542b..86e68dc574 100644 --- a/tests/tensorflow/test_models_detection_tf.py +++ b/tests/tensorflow/test_models_detection_tf.py @@ -257,6 +257,8 @@ def test_models_onnx_export(arch_name, input_shape, output_size): model, model_name=os.path.join(tmpdir, "model"), dummy_input=dummy_input ) assert os.path.exists(model_path) + tf.config.run_functions_eagerly(False) # Revert after conversion back to default + # Inference ort_session = onnxruntime.InferenceSession( os.path.join(tmpdir, "model.onnx"), providers=["CPUExecutionProvider"] diff --git a/tests/tensorflow/test_models_recognition_tf.py b/tests/tensorflow/test_models_recognition_tf.py index 7da1cb534a..4c59025baf 100644 --- a/tests/tensorflow/test_models_recognition_tf.py +++ b/tests/tensorflow/test_models_recognition_tf.py @@ -214,6 +214,7 @@ def test_models_onnx_export(arch_name, input_shape): large_model=True if arch_name == "master" else False, ) assert os.path.exists(model_path) + tf.config.run_functions_eagerly(False) # Revert after conversion back to default if arch_name == "master": # large models are exported as zip archive From 54c3ff559270c7d9002261f08be6464e74e7df69 Mon Sep 17 00:00:00 2001 From: felix Date: Thu, 11 Apr 2024 10:52:25 +0200 Subject: [PATCH 02/18] update --- doctr/models/recognition/crnn/tensorflow.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/doctr/models/recognition/crnn/tensorflow.py b/doctr/models/recognition/crnn/tensorflow.py index d366bfc14b..a5ff2d0572 100644 --- a/doctr/models/recognition/crnn/tensorflow.py +++ b/doctr/models/recognition/crnn/tensorflow.py @@ -136,15 +136,13 @@ def __init__( top_paths: int = 1, cfg: Optional[Dict[str, Any]] = None, ) -> None: - # Initialize kernels - h, w, c = feature_extractor.output_shape[1:] - super().__init__() + self.feat_extractor = feature_extractor + h, w, c = feature_extractor.output_shape[1:] self.vocab = vocab self.max_length = w self.cfg = cfg self.exportable = exportable - self.feat_extractor = feature_extractor self.decoder = Sequential([ layers.Bidirectional(layers.LSTM(units=rnn_units, return_sequences=True)), From 21520073bb6081d2f8824b60b4ebc62cac7907d7 Mon Sep 17 00:00:00 2001 From: felix Date: Thu, 11 Apr 2024 11:12:21 +0200 Subject: [PATCH 03/18] add missing os envs in scripts --- doctr/models/recognition/crnn/tensorflow.py | 6 ++++-- references/classification/latency_tensorflow.py | 1 + references/detection/evaluate_tensorflow.py | 1 + references/detection/latency_tensorflow.py | 1 + references/recognition/evaluate_tensorflow.py | 1 + references/recognition/latency_tensorflow.py | 1 + 6 files changed, 9 insertions(+), 2 deletions(-) diff --git a/doctr/models/recognition/crnn/tensorflow.py b/doctr/models/recognition/crnn/tensorflow.py index a5ff2d0572..d366bfc14b 100644 --- a/doctr/models/recognition/crnn/tensorflow.py +++ b/doctr/models/recognition/crnn/tensorflow.py @@ -136,13 +136,15 @@ def __init__( top_paths: int = 1, cfg: Optional[Dict[str, Any]] = None, ) -> None: - super().__init__() - self.feat_extractor = feature_extractor + # Initialize kernels h, w, c = feature_extractor.output_shape[1:] + + super().__init__() self.vocab = vocab self.max_length = w self.cfg = cfg self.exportable = exportable + self.feat_extractor = feature_extractor self.decoder = Sequential([ layers.Bidirectional(layers.LSTM(units=rnn_units, return_sequences=True)), diff --git a/references/classification/latency_tensorflow.py b/references/classification/latency_tensorflow.py index fc010df91a..27d4f4b533 100644 --- a/references/classification/latency_tensorflow.py +++ b/references/classification/latency_tensorflow.py @@ -13,6 +13,7 @@ import tensorflow as tf os.environ["USE_TF"] = "1" +os.environ["TF_USE_LEGACY_KERAS"] = "1" # docTR requires Keras v2 os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2" from doctr.models import classification diff --git a/references/detection/evaluate_tensorflow.py b/references/detection/evaluate_tensorflow.py index abf012ed83..3fe27acfe1 100644 --- a/references/detection/evaluate_tensorflow.py +++ b/references/detection/evaluate_tensorflow.py @@ -8,6 +8,7 @@ from doctr.file_utils import CLASS_NAME os.environ["USE_TF"] = "1" +os.environ["TF_USE_LEGACY_KERAS"] = "1" # docTR requires Keras v2 os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2" import time diff --git a/references/detection/latency_tensorflow.py b/references/detection/latency_tensorflow.py index e3e0d1d8af..5094cbf437 100644 --- a/references/detection/latency_tensorflow.py +++ b/references/detection/latency_tensorflow.py @@ -13,6 +13,7 @@ import tensorflow as tf os.environ["USE_TF"] = "1" +os.environ["TF_USE_LEGACY_KERAS"] = "1" # docTR requires Keras v2 os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2" from doctr.models import detection diff --git a/references/recognition/evaluate_tensorflow.py b/references/recognition/evaluate_tensorflow.py index 4c9d125285..19e3136a11 100644 --- a/references/recognition/evaluate_tensorflow.py +++ b/references/recognition/evaluate_tensorflow.py @@ -6,6 +6,7 @@ import os os.environ["USE_TF"] = "1" +os.environ["TF_USE_LEGACY_KERAS"] = "1" # docTR requires Keras v2 os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2" import time diff --git a/references/recognition/latency_tensorflow.py b/references/recognition/latency_tensorflow.py index 405cf56892..355d0ec5b0 100644 --- a/references/recognition/latency_tensorflow.py +++ b/references/recognition/latency_tensorflow.py @@ -13,6 +13,7 @@ import tensorflow as tf os.environ["USE_TF"] = "1" +os.environ["TF_USE_LEGACY_KERAS"] = "1" # docTR requires Keras v2 os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2" from doctr.models import recognition From 824526af5ca0803711fdae089362220fce92b328 Mon Sep 17 00:00:00 2001 From: felix Date: Mon, 15 Apr 2024 10:01:55 +0200 Subject: [PATCH 04/18] update --- .github/workflows/references.yml | 4 ++-- references/classification/README.md | 6 +++--- references/detection/README.md | 2 +- references/recognition/README.md | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/references.yml b/.github/workflows/references.yml index 56856ba1d3..be59a36cfb 100644 --- a/.github/workflows/references.yml +++ b/.github/workflows/references.yml @@ -263,7 +263,7 @@ jobs: pip install -e .[torch,viz,html] --upgrade - if: matrix.framework == 'tensorflow' name: Benchmark latency (TF) - run: python references/recognition/latency_tensorflow.py crnn_mobilenet_v3_small --it 5 + run: TF_USE_LEGACY_KERAS=1 python references/recognition/latency_tensorflow.py crnn_mobilenet_v3_small --it 5 - if: matrix.framework == 'pytorch' name: Benchmark latency (PT) run: python references/recognition/latency_pytorch.py crnn_mobilenet_v3_small --it 5 @@ -408,7 +408,7 @@ jobs: pip install -e .[torch,viz,html] --upgrade - if: matrix.framework == 'tensorflow' name: Benchmark latency (TF) - run: python references/detection/latency_tensorflow.py db_mobilenet_v3_large --it 5 --size 512 + run: TF_USE_LEGACY_KERAS=1 python references/detection/latency_tensorflow.py db_mobilenet_v3_large --it 5 --size 512 - if: matrix.framework == 'pytorch' name: Benchmark latency (PT) run: python references/detection/latency_pytorch.py db_mobilenet_v3_large --it 5 --size 512 diff --git a/references/classification/README.md b/references/classification/README.md index d0e5c3b83a..38ed2b5240 100644 --- a/references/classification/README.md +++ b/references/classification/README.md @@ -16,7 +16,7 @@ pip install -r references/requirements.txt You can start your training in TensorFlow: ```shell -python references/classification/train_tensorflow_character.py mobilenet_v3_large --epochs 5 +"TF_USE_LEGACY_KERAS"=1 python references/classification/train_tensorflow_character.py mobilenet_v3_large --epochs 5 ``` or PyTorch: @@ -30,7 +30,7 @@ python references/classification/train_pytorch_character.py mobilenet_v3_large - You can start your training in TensorFlow: ```shell -python references/classification/train_tensorflow_orientation.py path/to/your/train_set path/to/your/val_set resnet18 page --epochs 5 +"TF_USE_LEGACY_KERAS"=1 python references/classification/train_tensorflow_orientation.py path/to/your/train_set path/to/your/val_set resnet18 page --epochs 5 ``` or PyTorch: @@ -61,7 +61,7 @@ Feel free to inspect the multiple script option to customize your training to yo Character classification: ```python -python references/classification/train_tensorflow_character.py --help +"TF_USE_LEGACY_KERAS"=1 python references/classification/train_tensorflow_character.py --help ``` Orientation classification: diff --git a/references/detection/README.md b/references/detection/README.md index 7a07b4cb6b..9b9ba2a07e 100644 --- a/references/detection/README.md +++ b/references/detection/README.md @@ -16,7 +16,7 @@ pip install -r references/requirements.txt You can start your training in TensorFlow: ```shell -python references/detection/train_tensorflow.py path/to/your/train_set path/to/your/val_set db_resnet50 --epochs 5 +TF_USE_LEGACY_KERAS=1 python references/detection/train_tensorflow.py path/to/your/train_set path/to/your/val_set db_resnet50 --epochs 5 ``` or PyTorch: diff --git a/references/recognition/README.md b/references/recognition/README.md index b82a0d99b5..10bafe8ce5 100644 --- a/references/recognition/README.md +++ b/references/recognition/README.md @@ -16,7 +16,7 @@ pip install -r references/requirements.txt You can start your training in TensorFlow: ```shell -python references/recognition/train_tensorflow.py crnn_vgg16_bn --train_path path/to/your/train_set --val_path path/to/your/val_set --epochs 5 +TF_USE_LEGACY_KERAS=1 python references/recognition/train_tensorflow.py crnn_vgg16_bn --train_path path/to/your/train_set --val_path path/to/your/val_set --epochs 5 ``` or PyTorch: @@ -81,7 +81,7 @@ When typing your labels, be aware that the VOCAB doesn't handle spaces. Also mak Feel free to inspect the multiple script option to customize your training to your own needs! -```python +```shell python references/recognition/train_pytorch.py --help ``` From c4f2f5412c921d50b9008c7dcd1b2d73861d1b4d Mon Sep 17 00:00:00 2001 From: felix Date: Mon, 15 Apr 2024 10:55:58 +0200 Subject: [PATCH 05/18] update --- references/classification/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/references/classification/README.md b/references/classification/README.md index 38ed2b5240..6d5ee668bb 100644 --- a/references/classification/README.md +++ b/references/classification/README.md @@ -30,7 +30,7 @@ python references/classification/train_pytorch_character.py mobilenet_v3_large - You can start your training in TensorFlow: ```shell -"TF_USE_LEGACY_KERAS"=1 python references/classification/train_tensorflow_orientation.py path/to/your/train_set path/to/your/val_set resnet18 page --epochs 5 +TF_USE_LEGACY_KERAS=1 python references/classification/train_tensorflow_orientation.py path/to/your/train_set path/to/your/val_set resnet18 page --epochs 5 ``` or PyTorch: @@ -60,12 +60,12 @@ Feel free to inspect the multiple script option to customize your training to yo Character classification: -```python -"TF_USE_LEGACY_KERAS"=1 python references/classification/train_tensorflow_character.py --help +```shell +TF_USE_LEGACY_KERAS=1 python references/classification/train_tensorflow_character.py --help ``` Orientation classification: -```python +```shell python references/classification/train_tensorflow_orientation.py --help ``` From 97419ccf78f536c3bef6f88e917b5485326a1f86 Mon Sep 17 00:00:00 2001 From: felix Date: Tue, 23 Apr 2024 08:23:17 +0200 Subject: [PATCH 06/18] update --- .github/workflows/references.yml | 4 ++-- pyproject.toml | 2 ++ references/classification/README.md | 4 ++-- references/classification/latency_tensorflow.py | 9 ++++----- references/classification/train_tensorflow_character.py | 1 - .../classification/train_tensorflow_orientation.py | 1 - references/detection/README.md | 2 +- references/detection/evaluate_tensorflow.py | 1 - references/detection/latency_tensorflow.py | 9 ++++----- references/detection/train_tensorflow.py | 1 - references/recognition/README.md | 2 +- references/recognition/evaluate_tensorflow.py | 1 - references/recognition/latency_tensorflow.py | 9 ++++----- references/recognition/train_tensorflow.py | 1 - 14 files changed, 20 insertions(+), 27 deletions(-) diff --git a/.github/workflows/references.yml b/.github/workflows/references.yml index be59a36cfb..56856ba1d3 100644 --- a/.github/workflows/references.yml +++ b/.github/workflows/references.yml @@ -263,7 +263,7 @@ jobs: pip install -e .[torch,viz,html] --upgrade - if: matrix.framework == 'tensorflow' name: Benchmark latency (TF) - run: TF_USE_LEGACY_KERAS=1 python references/recognition/latency_tensorflow.py crnn_mobilenet_v3_small --it 5 + run: python references/recognition/latency_tensorflow.py crnn_mobilenet_v3_small --it 5 - if: matrix.framework == 'pytorch' name: Benchmark latency (PT) run: python references/recognition/latency_pytorch.py crnn_mobilenet_v3_small --it 5 @@ -408,7 +408,7 @@ jobs: pip install -e .[torch,viz,html] --upgrade - if: matrix.framework == 'tensorflow' name: Benchmark latency (TF) - run: TF_USE_LEGACY_KERAS=1 python references/detection/latency_tensorflow.py db_mobilenet_v3_large --it 5 --size 512 + run: python references/detection/latency_tensorflow.py db_mobilenet_v3_large --it 5 --size 512 - if: matrix.framework == 'pytorch' name: Benchmark latency (PT) run: python references/detection/latency_pytorch.py db_mobilenet_v3_large --it 5 --size 512 diff --git a/pyproject.toml b/pyproject.toml index 9338887ca7..1d48ddbc72 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -52,6 +52,7 @@ dependencies = [ [project.optional-dependencies] tf = [ + # cf. https://github.com/mindee/doctr/pull/1461 "tensorflow>=2.15.0", "tf-keras>=2.15.0", # Keep keras 2 compatibility "tf2onnx>=1.16.0,<2.0.0", # cf. https://github.com/onnx/tensorflow-onnx/releases/tag/v1.16.0 @@ -97,6 +98,7 @@ docs = [ ] dev = [ # Tensorflow + # cf. https://github.com/mindee/doctr/pull/1461 "tensorflow>=2.15.0", "tf-keras>=2.15.0", # Keep keras 2 compatibility "tf2onnx>=1.16.0,<2.0.0", # cf. https://github.com/onnx/tensorflow-onnx/releases/tag/v1.16.0 diff --git a/references/classification/README.md b/references/classification/README.md index 6d5ee668bb..d2594e1f4c 100644 --- a/references/classification/README.md +++ b/references/classification/README.md @@ -30,7 +30,7 @@ python references/classification/train_pytorch_character.py mobilenet_v3_large - You can start your training in TensorFlow: ```shell -TF_USE_LEGACY_KERAS=1 python references/classification/train_tensorflow_orientation.py path/to/your/train_set path/to/your/val_set resnet18 page --epochs 5 +python references/classification/train_tensorflow_orientation.py path/to/your/train_set path/to/your/val_set resnet18 page --epochs 5 ``` or PyTorch: @@ -61,7 +61,7 @@ Feel free to inspect the multiple script option to customize your training to yo Character classification: ```shell -TF_USE_LEGACY_KERAS=1 python references/classification/train_tensorflow_character.py --help +python references/classification/train_tensorflow_character.py --help ``` Orientation classification: diff --git a/references/classification/latency_tensorflow.py b/references/classification/latency_tensorflow.py index 27d4f4b533..639b60e3a5 100644 --- a/references/classification/latency_tensorflow.py +++ b/references/classification/latency_tensorflow.py @@ -9,14 +9,13 @@ import os import time -import numpy as np -import tensorflow as tf - os.environ["USE_TF"] = "1" -os.environ["TF_USE_LEGACY_KERAS"] = "1" # docTR requires Keras v2 os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2" -from doctr.models import classification +from doctr.models import classification # isort: skip + +import numpy as np +import tensorflow as tf def main(args): diff --git a/references/classification/train_tensorflow_character.py b/references/classification/train_tensorflow_character.py index e647e14ddd..dff3c0138c 100644 --- a/references/classification/train_tensorflow_character.py +++ b/references/classification/train_tensorflow_character.py @@ -6,7 +6,6 @@ import os os.environ["USE_TF"] = "1" -os.environ["TF_USE_LEGACY_KERAS"] = "1" # docTR requires Keras v2 os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2" import datetime diff --git a/references/classification/train_tensorflow_orientation.py b/references/classification/train_tensorflow_orientation.py index f4a0d21516..0699786f69 100644 --- a/references/classification/train_tensorflow_orientation.py +++ b/references/classification/train_tensorflow_orientation.py @@ -6,7 +6,6 @@ import os os.environ["USE_TF"] = "1" -os.environ["TF_USE_LEGACY_KERAS"] = "1" # docTR requires Keras v2 os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2" import datetime diff --git a/references/detection/README.md b/references/detection/README.md index 9b9ba2a07e..7a07b4cb6b 100644 --- a/references/detection/README.md +++ b/references/detection/README.md @@ -16,7 +16,7 @@ pip install -r references/requirements.txt You can start your training in TensorFlow: ```shell -TF_USE_LEGACY_KERAS=1 python references/detection/train_tensorflow.py path/to/your/train_set path/to/your/val_set db_resnet50 --epochs 5 +python references/detection/train_tensorflow.py path/to/your/train_set path/to/your/val_set db_resnet50 --epochs 5 ``` or PyTorch: diff --git a/references/detection/evaluate_tensorflow.py b/references/detection/evaluate_tensorflow.py index 3fe27acfe1..abf012ed83 100644 --- a/references/detection/evaluate_tensorflow.py +++ b/references/detection/evaluate_tensorflow.py @@ -8,7 +8,6 @@ from doctr.file_utils import CLASS_NAME os.environ["USE_TF"] = "1" -os.environ["TF_USE_LEGACY_KERAS"] = "1" # docTR requires Keras v2 os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2" import time diff --git a/references/detection/latency_tensorflow.py b/references/detection/latency_tensorflow.py index 5094cbf437..ba2c8e7c1c 100644 --- a/references/detection/latency_tensorflow.py +++ b/references/detection/latency_tensorflow.py @@ -9,14 +9,13 @@ import os import time -import numpy as np -import tensorflow as tf - os.environ["USE_TF"] = "1" -os.environ["TF_USE_LEGACY_KERAS"] = "1" # docTR requires Keras v2 os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2" -from doctr.models import detection +from doctr.models import detection # isort: skip + +import numpy as np +import tensorflow as tf def main(args): diff --git a/references/detection/train_tensorflow.py b/references/detection/train_tensorflow.py index adc4af0d69..5154f60f0d 100644 --- a/references/detection/train_tensorflow.py +++ b/references/detection/train_tensorflow.py @@ -6,7 +6,6 @@ import os os.environ["USE_TF"] = "1" -os.environ["TF_USE_LEGACY_KERAS"] = "1" # docTR requires Keras v2 os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2" import datetime diff --git a/references/recognition/README.md b/references/recognition/README.md index 10bafe8ce5..5823030120 100644 --- a/references/recognition/README.md +++ b/references/recognition/README.md @@ -16,7 +16,7 @@ pip install -r references/requirements.txt You can start your training in TensorFlow: ```shell -TF_USE_LEGACY_KERAS=1 python references/recognition/train_tensorflow.py crnn_vgg16_bn --train_path path/to/your/train_set --val_path path/to/your/val_set --epochs 5 +python references/recognition/train_tensorflow.py crnn_vgg16_bn --train_path path/to/your/train_set --val_path path/to/your/val_set --epochs 5 ``` or PyTorch: diff --git a/references/recognition/evaluate_tensorflow.py b/references/recognition/evaluate_tensorflow.py index 19e3136a11..4c9d125285 100644 --- a/references/recognition/evaluate_tensorflow.py +++ b/references/recognition/evaluate_tensorflow.py @@ -6,7 +6,6 @@ import os os.environ["USE_TF"] = "1" -os.environ["TF_USE_LEGACY_KERAS"] = "1" # docTR requires Keras v2 os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2" import time diff --git a/references/recognition/latency_tensorflow.py b/references/recognition/latency_tensorflow.py index 355d0ec5b0..fc30cc051e 100644 --- a/references/recognition/latency_tensorflow.py +++ b/references/recognition/latency_tensorflow.py @@ -9,14 +9,13 @@ import os import time -import numpy as np -import tensorflow as tf - os.environ["USE_TF"] = "1" -os.environ["TF_USE_LEGACY_KERAS"] = "1" # docTR requires Keras v2 os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2" -from doctr.models import recognition +from doctr.models import recognition # isort: skip + +import numpy as np +import tensorflow as tf def main(args): diff --git a/references/recognition/train_tensorflow.py b/references/recognition/train_tensorflow.py index 7801307382..d0f195eeb2 100644 --- a/references/recognition/train_tensorflow.py +++ b/references/recognition/train_tensorflow.py @@ -6,7 +6,6 @@ import os os.environ["USE_TF"] = "1" -os.environ["TF_USE_LEGACY_KERAS"] = "1" # docTR requires Keras v2 os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2" import datetime From 96d099b3a65d7e474529c3baaf1922f53bd4fee8 Mon Sep 17 00:00:00 2001 From: felix Date: Tue, 23 Apr 2024 08:28:36 +0200 Subject: [PATCH 07/18] update --- references/classification/README.md | 2 +- tests/tensorflow/test_models_classification_tf.py | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/references/classification/README.md b/references/classification/README.md index d2594e1f4c..6646b0d8ca 100644 --- a/references/classification/README.md +++ b/references/classification/README.md @@ -16,7 +16,7 @@ pip install -r references/requirements.txt You can start your training in TensorFlow: ```shell -"TF_USE_LEGACY_KERAS"=1 python references/classification/train_tensorflow_character.py mobilenet_v3_large --epochs 5 +python references/classification/train_tensorflow_character.py mobilenet_v3_large --epochs 5 ``` or PyTorch: diff --git a/tests/tensorflow/test_models_classification_tf.py b/tests/tensorflow/test_models_classification_tf.py index 9d8c362fde..dc8ca63274 100644 --- a/tests/tensorflow/test_models_classification_tf.py +++ b/tests/tensorflow/test_models_classification_tf.py @@ -252,9 +252,8 @@ def test_models_onnx_export(arch_name, input_shape, output_size): model_path, output = export_model_to_onnx( model, model_name=os.path.join(tmpdir, "model"), dummy_input=dummy_input ) - tf.config.run_functions_eagerly(False) # Revert after conversion back to default - assert os.path.exists(model_path) + tf.config.run_functions_eagerly(False) # Revert after conversion back to default # Inference ort_session = onnxruntime.InferenceSession( os.path.join(tmpdir, "model.onnx"), providers=["CPUExecutionProvider"] From 93440e39ec09db7d8b497bf7e212888d7cca1930 Mon Sep 17 00:00:00 2001 From: felix Date: Tue, 23 Apr 2024 08:30:10 +0200 Subject: [PATCH 08/18] update --- pyproject.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 1d48ddbc72..277e34357b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -53,8 +53,8 @@ dependencies = [ [project.optional-dependencies] tf = [ # cf. https://github.com/mindee/doctr/pull/1461 - "tensorflow>=2.15.0", - "tf-keras>=2.15.0", # Keep keras 2 compatibility + "tensorflow>=2.15.0,<3.0.0", + "tf-keras>=2.15.0,<3.0.0", # Keep keras 2 compatibility "tf2onnx>=1.16.0,<2.0.0", # cf. https://github.com/onnx/tensorflow-onnx/releases/tag/v1.16.0 # TODO: This is a temporary fix until we can upgrade to a newer version of tensorflow "numpy>=1.16.0,<2.0.0", @@ -99,8 +99,8 @@ docs = [ dev = [ # Tensorflow # cf. https://github.com/mindee/doctr/pull/1461 - "tensorflow>=2.15.0", - "tf-keras>=2.15.0", # Keep keras 2 compatibility + "tensorflow>=2.15.0,<3.0.0", + "tf-keras>=2.15.0,<3.0.0", # Keep keras 2 compatibility "tf2onnx>=1.16.0,<2.0.0", # cf. https://github.com/onnx/tensorflow-onnx/releases/tag/v1.16.0 # PyTorch "torch>=1.12.0,<3.0.0", From c75f3972b4fe56dbfbb36ff793359c51b87f5c66 Mon Sep 17 00:00:00 2001 From: felix Date: Tue, 23 Apr 2024 09:01:06 +0200 Subject: [PATCH 09/18] update --- doctr/file_utils.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/doctr/file_utils.py b/doctr/file_utils.py index c201ffbb77..7f35b34ae8 100644 --- a/doctr/file_utils.py +++ b/doctr/file_utils.py @@ -76,13 +76,13 @@ " is installed and that either USE_TF or USE_TORCH is enabled." ) -if _tf_available: # Compatibility fix to make sure tf.keras stays at Keras 2 - if "TF_USE_LEGACY_KERAS" not in os.environ: - os.environ["TF_USE_LEGACY_KERAS"] = "1" - elif os.environ["TF_USE_LEGACY_KERAS"] != "1": - raise ValueError( - "docTR is only compatible with Keras 2, but you have explicitly set `TF_USE_LEGACY_KERAS` to `0`. " - ) +# Compatibility fix to make sure tf.keras stays at Keras 2 +if "TF_USE_LEGACY_KERAS" not in os.environ: + os.environ["TF_USE_LEGACY_KERAS"] = "1" +elif os.environ["TF_USE_LEGACY_KERAS"] != "1": + raise ValueError( + "docTR is only compatible with Keras 2, but you have explicitly set `TF_USE_LEGACY_KERAS` to `0`. " + ) def requires_package(name: str, extra_message: Optional[str] = None) -> None: # pragma: no cover From d691a023a2f261e7d395a65f36182dd2ab735f90 Mon Sep 17 00:00:00 2001 From: felix Date: Wed, 24 Apr 2024 10:27:00 +0200 Subject: [PATCH 10/18] test --- doctr/file_utils.py | 5 +++++ references/classification/latency_tensorflow.py | 8 ++++++-- references/classification/train_tensorflow_character.py | 4 ++++ references/classification/train_tensorflow_orientation.py | 4 ++++ references/detection/evaluate_tensorflow.py | 4 ++++ references/detection/latency_tensorflow.py | 7 ++++++- references/detection/train_tensorflow.py | 4 ++++ references/recognition/evaluate_tensorflow.py | 4 ++++ references/recognition/latency_tensorflow.py | 8 ++++++-- references/recognition/train_tensorflow.py | 4 ++++ 10 files changed, 47 insertions(+), 5 deletions(-) diff --git a/doctr/file_utils.py b/doctr/file_utils.py index 7f35b34ae8..b2b6174a70 100644 --- a/doctr/file_utils.py +++ b/doctr/file_utils.py @@ -85,6 +85,11 @@ ) +def ensure_keras_v2() -> None: # pragma: no cover + if not os.environ.get("TF_USE_LEGACY_KERAS") == "1": + os.environ["TF_USE_LEGACY_KERAS"] = "1" + + def requires_package(name: str, extra_message: Optional[str] = None) -> None: # pragma: no cover """ package requirement helper diff --git a/references/classification/latency_tensorflow.py b/references/classification/latency_tensorflow.py index 639b60e3a5..5a1d3f7845 100644 --- a/references/classification/latency_tensorflow.py +++ b/references/classification/latency_tensorflow.py @@ -9,14 +9,18 @@ import os import time +from doctr.file_utils import ensure_keras_v2 + +ensure_keras_v2() + os.environ["USE_TF"] = "1" os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2" -from doctr.models import classification # isort: skip - import numpy as np import tensorflow as tf +from doctr.models import classification + def main(args): if args.gpu: diff --git a/references/classification/train_tensorflow_character.py b/references/classification/train_tensorflow_character.py index dff3c0138c..b659a6e251 100644 --- a/references/classification/train_tensorflow_character.py +++ b/references/classification/train_tensorflow_character.py @@ -5,6 +5,10 @@ import os +from doctr.file_utils import ensure_keras_v2 + +ensure_keras_v2() + os.environ["USE_TF"] = "1" os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2" diff --git a/references/classification/train_tensorflow_orientation.py b/references/classification/train_tensorflow_orientation.py index 0699786f69..7896fee4fa 100644 --- a/references/classification/train_tensorflow_orientation.py +++ b/references/classification/train_tensorflow_orientation.py @@ -5,6 +5,10 @@ import os +from doctr.file_utils import ensure_keras_v2 + +ensure_keras_v2() + os.environ["USE_TF"] = "1" os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2" diff --git a/references/detection/evaluate_tensorflow.py b/references/detection/evaluate_tensorflow.py index abf012ed83..7b31906409 100644 --- a/references/detection/evaluate_tensorflow.py +++ b/references/detection/evaluate_tensorflow.py @@ -5,6 +5,10 @@ import os +from doctr.file_utils import ensure_keras_v2 + +ensure_keras_v2() + from doctr.file_utils import CLASS_NAME os.environ["USE_TF"] = "1" diff --git a/references/detection/latency_tensorflow.py b/references/detection/latency_tensorflow.py index ba2c8e7c1c..b2d973fa6f 100644 --- a/references/detection/latency_tensorflow.py +++ b/references/detection/latency_tensorflow.py @@ -9,14 +9,19 @@ import os import time +from doctr.file_utils import ensure_keras_v2 + +ensure_keras_v2() + os.environ["USE_TF"] = "1" os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2" -from doctr.models import detection # isort: skip import numpy as np import tensorflow as tf +from doctr.models import detection + def main(args): if args.gpu: diff --git a/references/detection/train_tensorflow.py b/references/detection/train_tensorflow.py index 5154f60f0d..6ae9762aed 100644 --- a/references/detection/train_tensorflow.py +++ b/references/detection/train_tensorflow.py @@ -5,6 +5,10 @@ import os +from doctr.file_utils import ensure_keras_v2 + +ensure_keras_v2() + os.environ["USE_TF"] = "1" os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2" diff --git a/references/recognition/evaluate_tensorflow.py b/references/recognition/evaluate_tensorflow.py index 4c9d125285..0bec225fcf 100644 --- a/references/recognition/evaluate_tensorflow.py +++ b/references/recognition/evaluate_tensorflow.py @@ -5,6 +5,10 @@ import os +from doctr.file_utils import ensure_keras_v2 + +ensure_keras_v2() + os.environ["USE_TF"] = "1" os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2" diff --git a/references/recognition/latency_tensorflow.py b/references/recognition/latency_tensorflow.py index fc30cc051e..dfae409473 100644 --- a/references/recognition/latency_tensorflow.py +++ b/references/recognition/latency_tensorflow.py @@ -9,14 +9,18 @@ import os import time +from doctr.file_utils import ensure_keras_v2 + +ensure_keras_v2() + os.environ["USE_TF"] = "1" os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2" -from doctr.models import recognition # isort: skip - import numpy as np import tensorflow as tf +from doctr.models import recognition + def main(args): if args.gpu: diff --git a/references/recognition/train_tensorflow.py b/references/recognition/train_tensorflow.py index d0f195eeb2..5c32f76bc4 100644 --- a/references/recognition/train_tensorflow.py +++ b/references/recognition/train_tensorflow.py @@ -5,6 +5,10 @@ import os +from doctr.file_utils import ensure_keras_v2 + +ensure_keras_v2() + os.environ["USE_TF"] = "1" os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2" From 30c1978d7e99bc2b0963d82be1aa51dda601f07c Mon Sep 17 00:00:00 2001 From: felix Date: Fri, 30 Aug 2024 14:56:09 +0200 Subject: [PATCH 11/18] update --- doctr/models/recognition/parseq/tensorflow.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doctr/models/recognition/parseq/tensorflow.py b/doctr/models/recognition/parseq/tensorflow.py index 4d46b8687e..ceb6c49b5d 100644 --- a/doctr/models/recognition/parseq/tensorflow.py +++ b/doctr/models/recognition/parseq/tensorflow.py @@ -218,7 +218,7 @@ def generate_permutations_attention_masks(self, permutation: tf.Tensor) -> Tuple sz = permutation.shape[0] mask = tf.ones((sz, sz), dtype=tf.float32) - for i in range(sz - 1): + for i in tf.range(sz - 1): query_idx = int(permutation[i]) masked_keys = permutation[i + 1 :].numpy().tolist() indices = tf.constant([[query_idx, j] for j in masked_keys], dtype=tf.int32) @@ -264,7 +264,7 @@ def decode_autoregressive(self, features: tf.Tensor, max_len: Optional[int] = No query_mask = tf.cast(tf.linalg.band_part(tf.ones((max_length, max_length)), -1, 0), dtype=tf.bool) pos_logits = [] - for i in range(max_length): + for i in tf.range(max_length): # Decode one token at a time without providing information about the future tokens tgt_out = self.decode( ys[:, : i + 1], From fec9dafead1a79923101f96157f334568d90da63 Mon Sep 17 00:00:00 2001 From: felix Date: Fri, 30 Aug 2024 15:59:43 +0200 Subject: [PATCH 12/18] update --- docs/source/using_doctr/using_model_export.rst | 2 -- doctr/file_utils.py | 4 ++++ doctr/models/recognition/parseq/tensorflow.py | 4 ++-- tests/tensorflow/test_models_classification_tf.py | 1 - tests/tensorflow/test_models_detection_tf.py | 1 - tests/tensorflow/test_models_recognition_tf.py | 1 - 6 files changed, 6 insertions(+), 7 deletions(-) diff --git a/docs/source/using_doctr/using_model_export.rst b/docs/source/using_doctr/using_model_export.rst index b2fcbb0a79..48f570f699 100644 --- a/docs/source/using_doctr/using_model_export.rst +++ b/docs/source/using_doctr/using_model_export.rst @@ -57,7 +57,6 @@ It defines a common format for representing models, including the network struct .. code:: python3 import tensorflow as tf - tf.config.run_functions_eagerly(True) # Required for some models from doctr.models import vitstr_small from doctr.models.utils import export_model_to_onnx @@ -66,7 +65,6 @@ It defines a common format for representing models, including the network struct model = vitstr_small(pretrained=True, exportable=True) dummy_input = [tf.TensorSpec([batch_size, input_shape], tf.float32, name="input")] model_path, output = export_model_to_onnx(model, model_name="vitstr.onnx", dummy_input=dummy_input) - tf.config.run_functions_eagerly(False) # Revert after conversion back to default .. tab:: PyTorch diff --git a/doctr/file_utils.py b/doctr/file_utils.py index b2b6174a70..6588541c80 100644 --- a/doctr/file_utils.py +++ b/doctr/file_utils.py @@ -79,6 +79,10 @@ # Compatibility fix to make sure tf.keras stays at Keras 2 if "TF_USE_LEGACY_KERAS" not in os.environ: os.environ["TF_USE_LEGACY_KERAS"] = "1" + import tensorflow as tf + + # Enable eager execution - this is required for some models to work properly + tf.config.run_functions_eagerly(True) elif os.environ["TF_USE_LEGACY_KERAS"] != "1": raise ValueError( "docTR is only compatible with Keras 2, but you have explicitly set `TF_USE_LEGACY_KERAS` to `0`. " diff --git a/doctr/models/recognition/parseq/tensorflow.py b/doctr/models/recognition/parseq/tensorflow.py index ceb6c49b5d..4d46b8687e 100644 --- a/doctr/models/recognition/parseq/tensorflow.py +++ b/doctr/models/recognition/parseq/tensorflow.py @@ -218,7 +218,7 @@ def generate_permutations_attention_masks(self, permutation: tf.Tensor) -> Tuple sz = permutation.shape[0] mask = tf.ones((sz, sz), dtype=tf.float32) - for i in tf.range(sz - 1): + for i in range(sz - 1): query_idx = int(permutation[i]) masked_keys = permutation[i + 1 :].numpy().tolist() indices = tf.constant([[query_idx, j] for j in masked_keys], dtype=tf.int32) @@ -264,7 +264,7 @@ def decode_autoregressive(self, features: tf.Tensor, max_len: Optional[int] = No query_mask = tf.cast(tf.linalg.band_part(tf.ones((max_length, max_length)), -1, 0), dtype=tf.bool) pos_logits = [] - for i in tf.range(max_length): + for i in range(max_length): # Decode one token at a time without providing information about the future tokens tgt_out = self.decode( ys[:, : i + 1], diff --git a/tests/tensorflow/test_models_classification_tf.py b/tests/tensorflow/test_models_classification_tf.py index dc8ca63274..654ba082f7 100644 --- a/tests/tensorflow/test_models_classification_tf.py +++ b/tests/tensorflow/test_models_classification_tf.py @@ -253,7 +253,6 @@ def test_models_onnx_export(arch_name, input_shape, output_size): model, model_name=os.path.join(tmpdir, "model"), dummy_input=dummy_input ) assert os.path.exists(model_path) - tf.config.run_functions_eagerly(False) # Revert after conversion back to default # Inference ort_session = onnxruntime.InferenceSession( os.path.join(tmpdir, "model.onnx"), providers=["CPUExecutionProvider"] diff --git a/tests/tensorflow/test_models_detection_tf.py b/tests/tensorflow/test_models_detection_tf.py index 86e68dc574..c43903c2b4 100644 --- a/tests/tensorflow/test_models_detection_tf.py +++ b/tests/tensorflow/test_models_detection_tf.py @@ -257,7 +257,6 @@ def test_models_onnx_export(arch_name, input_shape, output_size): model, model_name=os.path.join(tmpdir, "model"), dummy_input=dummy_input ) assert os.path.exists(model_path) - tf.config.run_functions_eagerly(False) # Revert after conversion back to default # Inference ort_session = onnxruntime.InferenceSession( diff --git a/tests/tensorflow/test_models_recognition_tf.py b/tests/tensorflow/test_models_recognition_tf.py index 4c59025baf..7da1cb534a 100644 --- a/tests/tensorflow/test_models_recognition_tf.py +++ b/tests/tensorflow/test_models_recognition_tf.py @@ -214,7 +214,6 @@ def test_models_onnx_export(arch_name, input_shape): large_model=True if arch_name == "master" else False, ) assert os.path.exists(model_path) - tf.config.run_functions_eagerly(False) # Revert after conversion back to default if arch_name == "master": # large models are exported as zip archive From c489805975f10aaa025c6cb014bf27a2a6f47c90 Mon Sep 17 00:00:00 2001 From: felix Date: Fri, 30 Aug 2024 16:14:12 +0200 Subject: [PATCH 13/18] up --- doctr/file_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doctr/file_utils.py b/doctr/file_utils.py index 6588541c80..fcad746072 100644 --- a/doctr/file_utils.py +++ b/doctr/file_utils.py @@ -77,7 +77,7 @@ ) # Compatibility fix to make sure tf.keras stays at Keras 2 -if "TF_USE_LEGACY_KERAS" not in os.environ: +if "TF_USE_LEGACY_KERAS" not in os.environ and _tf_available: os.environ["TF_USE_LEGACY_KERAS"] = "1" import tensorflow as tf From 0f8b1b99605ac603d28e83aa79da71f8a376ec73 Mon Sep 17 00:00:00 2001 From: felix Date: Mon, 2 Sep 2024 08:11:09 +0200 Subject: [PATCH 14/18] update --- doctr/file_utils.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/doctr/file_utils.py b/doctr/file_utils.py index fcad746072..7e904f67c1 100644 --- a/doctr/file_utils.py +++ b/doctr/file_utils.py @@ -65,6 +65,10 @@ _tf_available = False else: logging.info(f"TensorFlow version {_tf_version} available.") + import tensorflow as tf + + # Enable eager execution - this is required for some models to work properly + tf.config.run_functions_eagerly(True) else: # pragma: no cover logging.info("Disabling Tensorflow because USE_TORCH is set") _tf_available = False @@ -77,12 +81,9 @@ ) # Compatibility fix to make sure tf.keras stays at Keras 2 -if "TF_USE_LEGACY_KERAS" not in os.environ and _tf_available: +if "TF_USE_LEGACY_KERAS" not in os.environ: os.environ["TF_USE_LEGACY_KERAS"] = "1" - import tensorflow as tf - # Enable eager execution - this is required for some models to work properly - tf.config.run_functions_eagerly(True) elif os.environ["TF_USE_LEGACY_KERAS"] != "1": raise ValueError( "docTR is only compatible with Keras 2, but you have explicitly set `TF_USE_LEGACY_KERAS` to `0`. " From 605e050bb0ca8b5a2a2fe25eff2712451e51cd4f Mon Sep 17 00:00:00 2001 From: felix Date: Mon, 2 Sep 2024 08:39:56 +0200 Subject: [PATCH 15/18] update --- doctr/file_utils.py | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/doctr/file_utils.py b/doctr/file_utils.py index 7e904f67c1..1fc5cc3c41 100644 --- a/doctr/file_utils.py +++ b/doctr/file_utils.py @@ -35,6 +35,20 @@ logging.info("Disabling PyTorch because USE_TF is set") _torch_available = False +# Compatibility fix to make sure tf.keras stays at Keras 2 +if "TF_USE_LEGACY_KERAS" not in os.environ: + os.environ["TF_USE_LEGACY_KERAS"] = "1" + +elif os.environ["TF_USE_LEGACY_KERAS"] != "1": + raise ValueError( + "docTR is only compatible with Keras 2, but you have explicitly set `TF_USE_LEGACY_KERAS` to `0`. " + ) + + +def ensure_keras_v2() -> None: # pragma: no cover + if not os.environ.get("TF_USE_LEGACY_KERAS") == "1": + os.environ["TF_USE_LEGACY_KERAS"] = "1" + if USE_TF in ENV_VARS_TRUE_AND_AUTO_VALUES and USE_TORCH not in ENV_VARS_TRUE_VALUES: _tf_available = importlib.util.find_spec("tensorflow") is not None @@ -65,6 +79,7 @@ _tf_available = False else: logging.info(f"TensorFlow version {_tf_version} available.") + ensure_keras_v2() import tensorflow as tf # Enable eager execution - this is required for some models to work properly @@ -80,20 +95,6 @@ " is installed and that either USE_TF or USE_TORCH is enabled." ) -# Compatibility fix to make sure tf.keras stays at Keras 2 -if "TF_USE_LEGACY_KERAS" not in os.environ: - os.environ["TF_USE_LEGACY_KERAS"] = "1" - -elif os.environ["TF_USE_LEGACY_KERAS"] != "1": - raise ValueError( - "docTR is only compatible with Keras 2, but you have explicitly set `TF_USE_LEGACY_KERAS` to `0`. " - ) - - -def ensure_keras_v2() -> None: # pragma: no cover - if not os.environ.get("TF_USE_LEGACY_KERAS") == "1": - os.environ["TF_USE_LEGACY_KERAS"] = "1" - def requires_package(name: str, extra_message: Optional[str] = None) -> None: # pragma: no cover """ From 784fcb71b9eb43e7b242e23b0f5417b35cff3a70 Mon Sep 17 00:00:00 2001 From: felix Date: Tue, 1 Oct 2024 13:57:20 +0200 Subject: [PATCH 16/18] rebase and update --- docs/source/using_doctr/using_model_export.rst | 2 +- doctr/file_utils.py | 2 +- doctr/io/image/tensorflow.py | 2 +- doctr/models/classification/magc_resnet/tensorflow.py | 4 ++-- doctr/models/classification/mobilenet/tensorflow.py | 4 ++-- doctr/models/classification/predictor/tensorflow.py | 2 +- doctr/models/classification/resnet/tensorflow.py | 6 +++--- doctr/models/classification/textnet/tensorflow.py | 2 +- doctr/models/classification/vgg/tensorflow.py | 4 ++-- doctr/models/classification/vit/tensorflow.py | 2 +- .../differentiable_binarization/tensorflow.py | 4 ++-- doctr/models/detection/fast/tensorflow.py | 2 +- doctr/models/detection/linknet/tensorflow.py | 2 +- doctr/models/detection/predictor/tensorflow.py | 2 +- doctr/models/modules/layers/tensorflow.py | 2 +- doctr/models/modules/transformer/tensorflow.py | 2 +- doctr/models/modules/vision_transformer/tensorflow.py | 2 +- doctr/models/recognition/crnn/tensorflow.py | 4 ++-- doctr/models/recognition/master/tensorflow.py | 2 +- doctr/models/recognition/parseq/tensorflow.py | 2 +- doctr/models/recognition/sar/tensorflow.py | 2 +- doctr/models/recognition/vitstr/tensorflow.py | 2 +- doctr/models/utils/tensorflow.py | 6 +++--- pyproject.toml | 2 -- .../classification/train_tensorflow_character.py | 2 +- .../classification/train_tensorflow_orientation.py | 2 +- references/detection/evaluate_tensorflow.py | 2 +- references/detection/train_tensorflow.py | 2 +- references/recognition/evaluate_tensorflow.py | 2 +- references/recognition/train_tensorflow.py | 2 +- tests/tensorflow/test_models_classification_tf.py | 9 ++++----- tests/tensorflow/test_models_detection_tf.py | 11 +++++------ tests/tensorflow/test_models_factory.py | 6 +++--- tests/tensorflow/test_models_recognition_tf.py | 5 ++--- tests/tensorflow/test_models_utils_tf.py | 2 +- 35 files changed, 53 insertions(+), 58 deletions(-) diff --git a/docs/source/using_doctr/using_model_export.rst b/docs/source/using_doctr/using_model_export.rst index 48f570f699..c62c36169b 100644 --- a/docs/source/using_doctr/using_model_export.rst +++ b/docs/source/using_doctr/using_model_export.rst @@ -31,7 +31,7 @@ Advantages: .. code:: python3 import tensorflow as tf - from keras import mixed_precision + from tensorflow.keras import mixed_precision mixed_precision.set_global_policy('mixed_float16') predictor = ocr_predictor(reco_arch="crnn_mobilenet_v3_small", det_arch="linknet_resnet34", pretrained=True) diff --git a/doctr/file_utils.py b/doctr/file_utils.py index 1fc5cc3c41..fc1129b0c1 100644 --- a/doctr/file_utils.py +++ b/doctr/file_utils.py @@ -35,7 +35,7 @@ logging.info("Disabling PyTorch because USE_TF is set") _torch_available = False -# Compatibility fix to make sure tf.keras stays at Keras 2 +# Compatibility fix to make sure tensorflow.keras stays at Keras 2 if "TF_USE_LEGACY_KERAS" not in os.environ: os.environ["TF_USE_LEGACY_KERAS"] = "1" diff --git a/doctr/io/image/tensorflow.py b/doctr/io/image/tensorflow.py index 3b1f1ed0e2..28fb2fadd5 100644 --- a/doctr/io/image/tensorflow.py +++ b/doctr/io/image/tensorflow.py @@ -7,8 +7,8 @@ import numpy as np import tensorflow as tf -from keras.utils import img_to_array from PIL import Image +from tensorflow.keras.utils import img_to_array from doctr.utils.common_types import AbstractPath diff --git a/doctr/models/classification/magc_resnet/tensorflow.py b/doctr/models/classification/magc_resnet/tensorflow.py index 12f7c6beea..fc7678f661 100644 --- a/doctr/models/classification/magc_resnet/tensorflow.py +++ b/doctr/models/classification/magc_resnet/tensorflow.py @@ -9,8 +9,8 @@ from typing import Any, Dict, List, Optional, Tuple import tensorflow as tf -from keras import activations, layers -from keras.models import Sequential +from tensorflow.keras import activations, layers +from tensorflow.keras.models import Sequential from doctr.datasets import VOCABS diff --git a/doctr/models/classification/mobilenet/tensorflow.py b/doctr/models/classification/mobilenet/tensorflow.py index 6250abc666..ff57c221dc 100644 --- a/doctr/models/classification/mobilenet/tensorflow.py +++ b/doctr/models/classification/mobilenet/tensorflow.py @@ -9,8 +9,8 @@ from typing import Any, Dict, List, Optional, Tuple, Union import tensorflow as tf -from keras import layers -from keras.models import Sequential +from tensorflow.keras import layers +from tensorflow.keras.models import Sequential from ....datasets import VOCABS from ...utils import conv_sequence, load_pretrained_params diff --git a/doctr/models/classification/predictor/tensorflow.py b/doctr/models/classification/predictor/tensorflow.py index ba26e1db54..23efbf6579 100644 --- a/doctr/models/classification/predictor/tensorflow.py +++ b/doctr/models/classification/predictor/tensorflow.py @@ -7,7 +7,7 @@ import numpy as np import tensorflow as tf -from keras import Model +from tensorflow.keras import Model from doctr.models.preprocessor import PreProcessor from doctr.utils.repr import NestedObject diff --git a/doctr/models/classification/resnet/tensorflow.py b/doctr/models/classification/resnet/tensorflow.py index 3e78ae0ae2..364b03c3a2 100644 --- a/doctr/models/classification/resnet/tensorflow.py +++ b/doctr/models/classification/resnet/tensorflow.py @@ -7,9 +7,9 @@ from typing import Any, Callable, Dict, List, Optional, Tuple import tensorflow as tf -from keras import layers -from keras.applications import ResNet50 -from keras.models import Sequential +from tensorflow.keras import layers +from tensorflow.keras.applications import ResNet50 +from tensorflow.keras.models import Sequential from doctr.datasets import VOCABS diff --git a/doctr/models/classification/textnet/tensorflow.py b/doctr/models/classification/textnet/tensorflow.py index 3d79b15f09..b0bb9a7205 100644 --- a/doctr/models/classification/textnet/tensorflow.py +++ b/doctr/models/classification/textnet/tensorflow.py @@ -7,7 +7,7 @@ from copy import deepcopy from typing import Any, Dict, List, Optional, Tuple -from keras import Sequential, layers +from tensorflow.keras import Sequential, layers from doctr.datasets import VOCABS diff --git a/doctr/models/classification/vgg/tensorflow.py b/doctr/models/classification/vgg/tensorflow.py index d9e7bb374b..9ecdabd040 100644 --- a/doctr/models/classification/vgg/tensorflow.py +++ b/doctr/models/classification/vgg/tensorflow.py @@ -6,8 +6,8 @@ from copy import deepcopy from typing import Any, Dict, List, Optional, Tuple -from keras import layers -from keras.models import Sequential +from tensorflow.keras import layers +from tensorflow.keras.models import Sequential from doctr.datasets import VOCABS diff --git a/doctr/models/classification/vit/tensorflow.py b/doctr/models/classification/vit/tensorflow.py index 28ff2e244e..8531193939 100644 --- a/doctr/models/classification/vit/tensorflow.py +++ b/doctr/models/classification/vit/tensorflow.py @@ -7,7 +7,7 @@ from typing import Any, Dict, Optional, Tuple import tensorflow as tf -from keras import Sequential, layers +from tensorflow.keras import Sequential, layers from doctr.datasets import VOCABS from doctr.models.modules.transformer import EncoderBlock diff --git a/doctr/models/detection/differentiable_binarization/tensorflow.py b/doctr/models/detection/differentiable_binarization/tensorflow.py index 7fdbd43ce0..45e522b872 100644 --- a/doctr/models/detection/differentiable_binarization/tensorflow.py +++ b/doctr/models/detection/differentiable_binarization/tensorflow.py @@ -10,8 +10,8 @@ import numpy as np import tensorflow as tf -from keras import Model, Sequential, layers, losses -from keras.applications import ResNet50 +from tensorflow.keras import Model, Sequential, layers, losses +from tensorflow.keras.applications import ResNet50 from doctr.file_utils import CLASS_NAME from doctr.models.utils import IntermediateLayerGetter, _bf16_to_float32, conv_sequence, load_pretrained_params diff --git a/doctr/models/detection/fast/tensorflow.py b/doctr/models/detection/fast/tensorflow.py index 80fc31fea3..91d6c8cc4d 100644 --- a/doctr/models/detection/fast/tensorflow.py +++ b/doctr/models/detection/fast/tensorflow.py @@ -10,7 +10,7 @@ import numpy as np import tensorflow as tf -from keras import Model, Sequential, layers +from tensorflow.keras import Model, Sequential, layers from doctr.file_utils import CLASS_NAME from doctr.models.utils import IntermediateLayerGetter, _bf16_to_float32, load_pretrained_params diff --git a/doctr/models/detection/linknet/tensorflow.py b/doctr/models/detection/linknet/tensorflow.py index 683c49373a..df8233cf20 100644 --- a/doctr/models/detection/linknet/tensorflow.py +++ b/doctr/models/detection/linknet/tensorflow.py @@ -10,7 +10,7 @@ import numpy as np import tensorflow as tf -from keras import Model, Sequential, layers, losses +from tensorflow.keras import Model, Sequential, layers, losses from doctr.file_utils import CLASS_NAME from doctr.models.classification import resnet18, resnet34, resnet50 diff --git a/doctr/models/detection/predictor/tensorflow.py b/doctr/models/detection/predictor/tensorflow.py index a7ccd4a9ac..a3d5085847 100644 --- a/doctr/models/detection/predictor/tensorflow.py +++ b/doctr/models/detection/predictor/tensorflow.py @@ -7,7 +7,7 @@ import numpy as np import tensorflow as tf -from keras import Model +from tensorflow.keras import Model from doctr.models.detection._utils import _remove_padding from doctr.models.preprocessor import PreProcessor diff --git a/doctr/models/modules/layers/tensorflow.py b/doctr/models/modules/layers/tensorflow.py index b1019be778..68849fbf6e 100644 --- a/doctr/models/modules/layers/tensorflow.py +++ b/doctr/models/modules/layers/tensorflow.py @@ -7,7 +7,7 @@ import numpy as np import tensorflow as tf -from keras import layers +from tensorflow.keras import layers from doctr.utils.repr import NestedObject diff --git a/doctr/models/modules/transformer/tensorflow.py b/doctr/models/modules/transformer/tensorflow.py index 3fc1d17f27..50c7cef04d 100644 --- a/doctr/models/modules/transformer/tensorflow.py +++ b/doctr/models/modules/transformer/tensorflow.py @@ -7,7 +7,7 @@ from typing import Any, Callable, Optional, Tuple import tensorflow as tf -from keras import layers +from tensorflow.keras import layers from doctr.utils.repr import NestedObject diff --git a/doctr/models/modules/vision_transformer/tensorflow.py b/doctr/models/modules/vision_transformer/tensorflow.py index a73aa4c706..8386172eb1 100644 --- a/doctr/models/modules/vision_transformer/tensorflow.py +++ b/doctr/models/modules/vision_transformer/tensorflow.py @@ -7,7 +7,7 @@ from typing import Any, Tuple import tensorflow as tf -from keras import layers +from tensorflow.keras import layers from doctr.utils.repr import NestedObject diff --git a/doctr/models/recognition/crnn/tensorflow.py b/doctr/models/recognition/crnn/tensorflow.py index d366bfc14b..fb5cb72dff 100644 --- a/doctr/models/recognition/crnn/tensorflow.py +++ b/doctr/models/recognition/crnn/tensorflow.py @@ -7,8 +7,8 @@ from typing import Any, Dict, List, Optional, Tuple, Union import tensorflow as tf -from keras import layers -from keras.models import Model, Sequential +from tensorflow.keras import layers +from tensorflow.keras.models import Model, Sequential from doctr.datasets import VOCABS diff --git a/doctr/models/recognition/master/tensorflow.py b/doctr/models/recognition/master/tensorflow.py index 5b8192dee6..42cd216b2c 100644 --- a/doctr/models/recognition/master/tensorflow.py +++ b/doctr/models/recognition/master/tensorflow.py @@ -7,7 +7,7 @@ from typing import Any, Dict, List, Optional, Tuple import tensorflow as tf -from keras import Model, layers +from tensorflow.keras import Model, layers from doctr.datasets import VOCABS from doctr.models.classification import magc_resnet31 diff --git a/doctr/models/recognition/parseq/tensorflow.py b/doctr/models/recognition/parseq/tensorflow.py index 4d46b8687e..b0e21a50d6 100644 --- a/doctr/models/recognition/parseq/tensorflow.py +++ b/doctr/models/recognition/parseq/tensorflow.py @@ -10,7 +10,7 @@ import numpy as np import tensorflow as tf -from keras import Model, layers +from tensorflow.keras import Model, layers from doctr.datasets import VOCABS from doctr.models.modules.transformer import MultiHeadAttention, PositionwiseFeedForward diff --git a/doctr/models/recognition/sar/tensorflow.py b/doctr/models/recognition/sar/tensorflow.py index 0776414c7a..89e93ea51e 100644 --- a/doctr/models/recognition/sar/tensorflow.py +++ b/doctr/models/recognition/sar/tensorflow.py @@ -7,7 +7,7 @@ from typing import Any, Dict, List, Optional, Tuple import tensorflow as tf -from keras import Model, Sequential, layers +from tensorflow.keras import Model, Sequential, layers from doctr.datasets import VOCABS from doctr.utils.repr import NestedObject diff --git a/doctr/models/recognition/vitstr/tensorflow.py b/doctr/models/recognition/vitstr/tensorflow.py index 985f49a470..6b38cf7548 100644 --- a/doctr/models/recognition/vitstr/tensorflow.py +++ b/doctr/models/recognition/vitstr/tensorflow.py @@ -7,7 +7,7 @@ from typing import Any, Dict, List, Optional, Tuple import tensorflow as tf -from keras import Model, layers +from tensorflow.keras import Model, layers from doctr.datasets import VOCABS diff --git a/doctr/models/utils/tensorflow.py b/doctr/models/utils/tensorflow.py index 51a2bc69a5..6f7dc14ab3 100644 --- a/doctr/models/utils/tensorflow.py +++ b/doctr/models/utils/tensorflow.py @@ -8,7 +8,7 @@ import tensorflow as tf import tf2onnx -from keras import Model, layers +from tensorflow.keras import Model, layers from doctr.utils.data import download_from_url @@ -77,7 +77,7 @@ def conv_sequence( ) -> List[layers.Layer]: """Builds a convolutional-based layer sequence - >>> from keras import Sequential + >>> from tensorflow.keras import Sequential >>> from doctr.models import conv_sequence >>> module = Sequential(conv_sequence(32, 'relu', True, kernel_size=3, input_shape=[224, 224, 3])) @@ -113,7 +113,7 @@ def conv_sequence( class IntermediateLayerGetter(Model): """Implements an intermediate layer getter - >>> from keras.applications import ResNet50 + >>> from tensorflow.keras.applications import ResNet50 >>> from doctr.models import IntermediateLayerGetter >>> target_layers = ["conv2_block3_out", "conv3_block4_out", "conv4_block6_out", "conv5_block3_out"] >>> feat_extractor = IntermediateLayerGetter(ResNet50(include_top=False, pooling=False), target_layers) diff --git a/pyproject.toml b/pyproject.toml index 277e34357b..9745f8a7c4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -56,8 +56,6 @@ tf = [ "tensorflow>=2.15.0,<3.0.0", "tf-keras>=2.15.0,<3.0.0", # Keep keras 2 compatibility "tf2onnx>=1.16.0,<2.0.0", # cf. https://github.com/onnx/tensorflow-onnx/releases/tag/v1.16.0 - # TODO: This is a temporary fix until we can upgrade to a newer version of tensorflow - "numpy>=1.16.0,<2.0.0", ] torch = [ "torch>=1.12.0,<3.0.0", diff --git a/references/classification/train_tensorflow_character.py b/references/classification/train_tensorflow_character.py index b659a6e251..2c754df3d4 100644 --- a/references/classification/train_tensorflow_character.py +++ b/references/classification/train_tensorflow_character.py @@ -17,7 +17,7 @@ import numpy as np import tensorflow as tf -from keras import Model, mixed_precision, optimizers +from tensorflow.keras import Model, mixed_precision, optimizers from tqdm.auto import tqdm from doctr.models import login_to_hub, push_to_hf_hub diff --git a/references/classification/train_tensorflow_orientation.py b/references/classification/train_tensorflow_orientation.py index 7896fee4fa..e29001e7bc 100644 --- a/references/classification/train_tensorflow_orientation.py +++ b/references/classification/train_tensorflow_orientation.py @@ -17,7 +17,7 @@ import numpy as np import tensorflow as tf -from keras import Model, mixed_precision, optimizers +from tensorflow.keras import Model, mixed_precision, optimizers from tqdm.auto import tqdm from doctr.models import login_to_hub, push_to_hf_hub diff --git a/references/detection/evaluate_tensorflow.py b/references/detection/evaluate_tensorflow.py index 7b31906409..ea77037804 100644 --- a/references/detection/evaluate_tensorflow.py +++ b/references/detection/evaluate_tensorflow.py @@ -18,7 +18,7 @@ from pathlib import Path import tensorflow as tf -from keras import mixed_precision +from tensorflow.keras import mixed_precision from tqdm import tqdm gpu_devices = tf.config.experimental.list_physical_devices("GPU") diff --git a/references/detection/train_tensorflow.py b/references/detection/train_tensorflow.py index 6ae9762aed..a5a1caf2c5 100644 --- a/references/detection/train_tensorflow.py +++ b/references/detection/train_tensorflow.py @@ -18,7 +18,7 @@ import numpy as np import tensorflow as tf -from keras import Model, mixed_precision, optimizers +from tensorflow.keras import Model, mixed_precision, optimizers from tqdm.auto import tqdm from doctr.models import login_to_hub, push_to_hf_hub diff --git a/references/recognition/evaluate_tensorflow.py b/references/recognition/evaluate_tensorflow.py index 0bec225fcf..4e00715513 100644 --- a/references/recognition/evaluate_tensorflow.py +++ b/references/recognition/evaluate_tensorflow.py @@ -15,7 +15,7 @@ import time import tensorflow as tf -from keras import mixed_precision +from tensorflow.keras import mixed_precision from tqdm import tqdm gpu_devices = tf.config.experimental.list_physical_devices("GPU") diff --git a/references/recognition/train_tensorflow.py b/references/recognition/train_tensorflow.py index 5c32f76bc4..ba560c285e 100644 --- a/references/recognition/train_tensorflow.py +++ b/references/recognition/train_tensorflow.py @@ -19,7 +19,7 @@ import numpy as np import tensorflow as tf -from keras import Model, mixed_precision, optimizers +from tensorflow.keras import Model, mixed_precision, optimizers from tqdm.auto import tqdm from doctr.models import login_to_hub, push_to_hf_hub diff --git a/tests/tensorflow/test_models_classification_tf.py b/tests/tensorflow/test_models_classification_tf.py index 654ba082f7..89181aace0 100644 --- a/tests/tensorflow/test_models_classification_tf.py +++ b/tests/tensorflow/test_models_classification_tf.py @@ -2,7 +2,6 @@ import tempfile import cv2 -import keras import numpy as np import onnxruntime import psutil @@ -38,7 +37,7 @@ def test_classification_architectures(arch_name, input_shape, output_size): # Model batch_size = 2 - keras.backend.clear_session() + tf.keras.backend.clear_session() model = classification.__dict__[arch_name](pretrained=True, include_top=True, input_shape=input_shape) # Forward out = model(tf.random.uniform(shape=[batch_size, *input_shape], maxval=1, dtype=tf.float32)) @@ -47,7 +46,7 @@ def test_classification_architectures(arch_name, input_shape, output_size): assert out.dtype == tf.float32 assert out.numpy().shape == (batch_size, *output_size) # Check that you can load pretrained up to the classification layer with differing number of classes to fine-tune - keras.backend.clear_session() + tf.keras.backend.clear_session() assert classification.__dict__[arch_name]( pretrained=True, include_top=True, input_shape=input_shape, num_classes=10 ) @@ -63,7 +62,7 @@ def test_classification_architectures(arch_name, input_shape, output_size): def test_classification_models(arch_name, input_shape): batch_size = 8 reco_model = classification.__dict__[arch_name](pretrained=True, input_shape=input_shape) - assert isinstance(reco_model, keras.Model) + assert isinstance(reco_model, tf.keras.Model) input_tensor = tf.random.uniform(shape=[batch_size, *input_shape], minval=0, maxval=1) out = reco_model(input_tensor) @@ -232,7 +231,7 @@ def test_page_orientation_model(mock_payslip): def test_models_onnx_export(arch_name, input_shape, output_size): # Model batch_size = 2 - keras.backend.clear_session() + tf.keras.backend.clear_session() if "orientation" in arch_name: model = classification.__dict__[arch_name](pretrained=True, input_shape=input_shape) else: diff --git a/tests/tensorflow/test_models_detection_tf.py b/tests/tensorflow/test_models_detection_tf.py index c43903c2b4..7dbb090bf2 100644 --- a/tests/tensorflow/test_models_detection_tf.py +++ b/tests/tensorflow/test_models_detection_tf.py @@ -2,7 +2,6 @@ import os import tempfile -import keras import numpy as np import onnxruntime import psutil @@ -38,13 +37,13 @@ ) def test_detection_models(arch_name, input_shape, output_size, out_prob, train_mode): batch_size = 2 - keras.backend.clear_session() + tf.keras.backend.clear_session() if arch_name == "fast_tiny_rep": model = reparameterize(detection.fast_tiny(pretrained=True, input_shape=input_shape)) train_mode = False # Reparameterized model is not trainable else: model = detection.__dict__[arch_name](pretrained=True, input_shape=input_shape) - assert isinstance(model, keras.Model) + assert isinstance(model, tf.keras.Model) input_tensor = tf.random.uniform(shape=[batch_size, *input_shape], minval=0, maxval=1) target = [ {CLASS_NAME: np.array([[0.5, 0.5, 1, 1], [0.5, 0.5, 0.8, 0.8]], dtype=np.float32)}, @@ -153,7 +152,7 @@ def test_rotated_detectionpredictor(mock_pdf): ) def test_detection_zoo(arch_name): # Model - keras.backend.clear_session() + tf.keras.backend.clear_session() predictor = detection.zoo.detection_predictor(arch_name, pretrained=False) # object check assert isinstance(predictor, DetectionPredictor) @@ -178,7 +177,7 @@ def test_fast_reparameterization(): base_model_params = np.sum([np.prod(v.shape) for v in base_model.trainable_variables]) assert math.isclose(base_model_params, 13535296) # base model params base_out = base_model(dummy_input, training=False)["logits"] - keras.backend.clear_session() + tf.keras.backend.clear_session() rep_model = reparameterize(base_model) rep_model_params = np.sum([np.prod(v.shape) for v in base_model.trainable_variables]) assert math.isclose(rep_model_params, 8520256) # reparameterized model params @@ -242,7 +241,7 @@ def test_dilate(): def test_models_onnx_export(arch_name, input_shape, output_size): # Model batch_size = 2 - keras.backend.clear_session() + tf.keras.backend.clear_session() if arch_name == "fast_tiny_rep": model = reparameterize(detection.fast_tiny(pretrained=True, exportable=True, input_shape=input_shape)) else: diff --git a/tests/tensorflow/test_models_factory.py b/tests/tensorflow/test_models_factory.py index 0860d8612c..f20745c344 100644 --- a/tests/tensorflow/test_models_factory.py +++ b/tests/tensorflow/test_models_factory.py @@ -2,8 +2,8 @@ import os import tempfile -import keras import pytest +import tensorflow as tf from doctr import models from doctr.models.factory import _save_model_and_config_for_hf_hub, from_hub, push_to_hf_hub @@ -50,7 +50,7 @@ def test_push_to_hf_hub(): ) def test_models_for_hub(arch_name, task_name, dummy_model_id, tmpdir): with tempfile.TemporaryDirectory() as tmp_dir: - keras.backend.clear_session() + tf.backend.clear_session() model = models.__dict__[task_name].__dict__[arch_name](pretrained=True) _save_model_and_config_for_hf_hub(model, arch=arch_name, task=task_name, save_dir=tmp_dir) @@ -65,6 +65,6 @@ def test_models_for_hub(arch_name, task_name, dummy_model_id, tmpdir): assert all(key in model.cfg.keys() for key in tmp_config.keys()) # test from hub - keras.backend.clear_session() + tf.keras.backend.clear_session() hub_model = from_hub(repo_id=dummy_model_id) assert isinstance(hub_model, type(model)) diff --git a/tests/tensorflow/test_models_recognition_tf.py b/tests/tensorflow/test_models_recognition_tf.py index 7da1cb534a..bdc8441c8f 100644 --- a/tests/tensorflow/test_models_recognition_tf.py +++ b/tests/tensorflow/test_models_recognition_tf.py @@ -2,7 +2,6 @@ import shutil import tempfile -import keras import numpy as np import onnxruntime import psutil @@ -41,7 +40,7 @@ def test_recognition_models(arch_name, input_shape, train_mode, mock_vocab): batch_size = 4 reco_model = recognition.__dict__[arch_name](vocab=mock_vocab, pretrained=True, input_shape=input_shape) - assert isinstance(reco_model, keras.Model) + assert isinstance(reco_model, tf.keras.Model) input_tensor = tf.random.uniform(shape=[batch_size, *input_shape], minval=0, maxval=1) target = ["i", "am", "a", "jedi"] @@ -195,7 +194,7 @@ def test_recognition_zoo_error(): def test_models_onnx_export(arch_name, input_shape): # Model batch_size = 2 - keras.backend.clear_session() + tf.backend.clear_session() model = recognition.__dict__[arch_name](pretrained=True, exportable=True, input_shape=input_shape) # SAR, MASTER, ViTSTR export currently only available with constant batch size if arch_name in ["sar_resnet31", "master", "vitstr_small", "parseq"]: diff --git a/tests/tensorflow/test_models_utils_tf.py b/tests/tensorflow/test_models_utils_tf.py index b57b41b14b..4783a09b40 100644 --- a/tests/tensorflow/test_models_utils_tf.py +++ b/tests/tensorflow/test_models_utils_tf.py @@ -2,7 +2,7 @@ import pytest import tensorflow as tf -from keras.applications import ResNet50 +from tensorflow.keras.applications import ResNet50 from doctr.models.classification import mobilenet_v3_small from doctr.models.utils import ( From 5497ccc8fd4b0bc2188e74c72db2e759d846046b Mon Sep 17 00:00:00 2001 From: felix Date: Tue, 1 Oct 2024 14:03:23 +0200 Subject: [PATCH 17/18] update --- tests/tensorflow/test_models_factory.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tensorflow/test_models_factory.py b/tests/tensorflow/test_models_factory.py index f20745c344..a4483800c9 100644 --- a/tests/tensorflow/test_models_factory.py +++ b/tests/tensorflow/test_models_factory.py @@ -50,7 +50,7 @@ def test_push_to_hf_hub(): ) def test_models_for_hub(arch_name, task_name, dummy_model_id, tmpdir): with tempfile.TemporaryDirectory() as tmp_dir: - tf.backend.clear_session() + tf.keras.backend.clear_session() model = models.__dict__[task_name].__dict__[arch_name](pretrained=True) _save_model_and_config_for_hf_hub(model, arch=arch_name, task=task_name, save_dir=tmp_dir) From 9940348d954602acbaa0adb5d7f58c1bd5f0d36a Mon Sep 17 00:00:00 2001 From: felix Date: Tue, 1 Oct 2024 14:19:33 +0200 Subject: [PATCH 18/18] update --- tests/tensorflow/test_models_recognition_tf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tensorflow/test_models_recognition_tf.py b/tests/tensorflow/test_models_recognition_tf.py index bdc8441c8f..162c446d35 100644 --- a/tests/tensorflow/test_models_recognition_tf.py +++ b/tests/tensorflow/test_models_recognition_tf.py @@ -194,7 +194,7 @@ def test_recognition_zoo_error(): def test_models_onnx_export(arch_name, input_shape): # Model batch_size = 2 - tf.backend.clear_session() + tf.keras.backend.clear_session() model = recognition.__dict__[arch_name](pretrained=True, exportable=True, input_shape=input_shape) # SAR, MASTER, ViTSTR export currently only available with constant batch size if arch_name in ["sar_resnet31", "master", "vitstr_small", "parseq"]: