From 769c41ac9074080cc66754516643478e9de58004 Mon Sep 17 00:00:00 2001 From: bw4sz Date: Fri, 13 Dec 2024 10:20:31 -0800 Subject: [PATCH 1/4] silence predict tile stdout if needed, see https://github.com/Lightning-AI/pytorch-lightning/issues/13358 --- src/deepforest/main.py | 12 +++++++++--- src/deepforest/predict.py | 12 +++++++----- tests/test_main.py | 19 +++++++++++++++++++ 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/src/deepforest/main.py b/src/deepforest/main.py index 320beca0..b9875ad7 100644 --- a/src/deepforest/main.py +++ b/src/deepforest/main.py @@ -477,7 +477,8 @@ def predict_tile(self, thickness=1, crop_model=None, crop_transform=None, - crop_augment=False): + crop_augment=False, + verbose=True): """For images too large to input into the model, predict_tile cuts the image into overlapping windows, predicts trees on each window and reassambles into a single array. @@ -498,6 +499,7 @@ def predict_tile(self, cropModel: a deepforest.model.CropModel object to predict on crops crop_transform: a torchvision.transforms object to apply to crops crop_augment: a boolean to apply augmentations to crops + verbose: a boolean to print the number of predictions in overlapping windows (deprecated) return_plot: return a plot of the image with predictions overlaid (deprecated) color: color of the bounding box as a tuple of BGR color, e.g. orange annotations is (0, 165, 255) (deprecated) thickness: thickness of the rectangle border line in px @@ -529,7 +531,7 @@ def predict_tile(self, warnings.warn( "More than one GPU detected. Using only the first GPU for predict_tile.") self.config["devices"] = 1 - self.create_trainer() + self.create_trainer(enable_progress_bar=verbose) if (raster_path is None) and (image is None): raise ValueError( @@ -560,6 +562,9 @@ def predict_tile(self, patch_overlap=patch_overlap, patch_size=patch_size) + if not verbose: + self.create_trainer(enable_progress_bar=False) + batched_results = self.trainer.predict(self, self.predict_dataloader(ds)) # Flatten list from batched prediction @@ -573,7 +578,8 @@ def predict_tile(self, ds.windows, sigma=sigma, thresh=thresh, - iou_threshold=iou_threshold) + iou_threshold=iou_threshold, + verbose=verbose) results["label"] = results.label.apply( lambda x: self.numeric_to_label_dict[x]) if raster_path: diff --git a/src/deepforest/predict.py b/src/deepforest/predict.py index 03fcb11f..c9059ea4 100644 --- a/src/deepforest/predict.py +++ b/src/deepforest/predict.py @@ -61,7 +61,7 @@ def _predict_image_(model, return df -def mosiac(boxes, windows, sigma=0.5, thresh=0.001, iou_threshold=0.1): +def mosiac(boxes, windows, sigma=0.5, thresh=0.001, iou_threshold=0.1, verbose=True): # transform the coordinates to original system for index, _ in enumerate(boxes): xmin, ymin, xmax, ymax = windows[index].getRect() @@ -71,9 +71,10 @@ def mosiac(boxes, windows, sigma=0.5, thresh=0.001, iou_threshold=0.1): boxes[index].ymax += ymin predicted_boxes = pd.concat(boxes) - print( - f"{predicted_boxes.shape[0]} predictions in overlapping windows, applying non-max supression" - ) + if verbose: + print( + f"{predicted_boxes.shape[0]} predictions in overlapping windows, applying non-max supression" + ) # move prediciton to tensor boxes = torch.tensor(predicted_boxes[["xmin", "ymin", "xmax", "ymax"]].values, dtype=torch.float32) @@ -98,7 +99,8 @@ def mosiac(boxes, windows, sigma=0.5, thresh=0.001, iou_threshold=0.1): mosaic_df = pd.DataFrame(image_detections, columns=["xmin", "ymin", "xmax", "ymax", "label", "score"]) - print(f"{mosaic_df.shape[0]} predictions kept after non-max suppression") + if verbose: + print(f"{mosaic_df.shape[0]} predictions kept after non-max suppression") return mosaic_df diff --git a/tests/test_main.py b/tests/test_main.py index a8c3543e..86d9b125 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -322,6 +322,25 @@ def test_predict_tile_no_mosaic(m, raster_path): assert len(prediction[0]) == 2 assert prediction[0][1].shape == (300, 300, 3) +@pytest.mark.parametrize("verbose", [True, False]) +def test_predict_tile_verbose(m, raster_path, capsys, verbose): + m.config["train"]["fast_dev_run"] = False + m.create_trainer() + prediction = m.predict_tile(raster_path=raster_path, + patch_size=300, + patch_overlap=0, + mosaic=True, + verbose=verbose) + + # Check no output was printed + if not verbose: + captured = capsys.readouterr() + print(captured.out) + assert not captured.out + else: + captured = capsys.readouterr() + print(captured.out) + assert captured.out def test_evaluate(m, tmpdir): csv_file = get_data("OSBS_029.csv") From 804a0fa54c29dbf02e92b8f08b777b2776222680 Mon Sep 17 00:00:00 2001 From: Ethan White Date: Tue, 7 Jan 2025 10:02:21 -0500 Subject: [PATCH 2/4] Just run problem test --- .github/workflows/Conda-app.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/Conda-app.yml b/.github/workflows/Conda-app.yml index 7a18cbf6..174900d7 100644 --- a/.github/workflows/Conda-app.yml +++ b/.github/workflows/Conda-app.yml @@ -2,9 +2,9 @@ name: Conda package on: push: - branches: [ main ] + branches: [main] pull_request: - branches: [ main ] + branches: [main] jobs: ci: @@ -35,7 +35,7 @@ jobs: - name: Install opencv dependencies run: | sudo apt-get update - sudo apt-get install -y libgl1 and libglx-mesa0 + sudo apt-get install -y libgl1 and libglx-mesa0 - name: Install Conda environment with Micromamba uses: mamba-org/setup-micromamba@v1 @@ -50,7 +50,7 @@ jobs: run: pip install . -U - name: Run pytest - run: pytest -v + run: pytest -v -k test_predict_tile_verbose - name: Check style run: yapf -d --recursive src/deepforest/ --style=.style.yapf From c2403d40fa49f04ab502f75bb63124884862c352 Mon Sep 17 00:00:00 2001 From: Ethan White Date: Tue, 7 Jan 2025 10:43:12 -0500 Subject: [PATCH 3/4] Try full tests on Ubuntu 22.04 --- .github/workflows/Conda-app.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/Conda-app.yml b/.github/workflows/Conda-app.yml index 174900d7..d9ef00a1 100644 --- a/.github/workflows/Conda-app.yml +++ b/.github/workflows/Conda-app.yml @@ -19,7 +19,7 @@ jobs: - "3.10" os: - - "ubuntu-latest" + - "ubuntu-22.04" runs-on: "${{ matrix.os }}" @@ -50,7 +50,7 @@ jobs: run: pip install . -U - name: Run pytest - run: pytest -v -k test_predict_tile_verbose + run: pytest -v - name: Check style run: yapf -d --recursive src/deepforest/ --style=.style.yapf From e36909c9e78bb9e2b412214e878f07ad2ef50d58 Mon Sep 17 00:00:00 2001 From: Ethan White Date: Tue, 7 Jan 2025 11:03:07 -0500 Subject: [PATCH 4/4] Try just testing verbose=False --- tests/test_main.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/test_main.py b/tests/test_main.py index 86d9b125..d7773262 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -322,8 +322,7 @@ def test_predict_tile_no_mosaic(m, raster_path): assert len(prediction[0]) == 2 assert prediction[0][1].shape == (300, 300, 3) -@pytest.mark.parametrize("verbose", [True, False]) -def test_predict_tile_verbose(m, raster_path, capsys, verbose): +def test_predict_tile_verbose(m, raster_path, capsys, verbose=False): m.config["train"]["fast_dev_run"] = False m.create_trainer() prediction = m.predict_tile(raster_path=raster_path, @@ -331,7 +330,7 @@ def test_predict_tile_verbose(m, raster_path, capsys, verbose): patch_overlap=0, mosaic=True, verbose=verbose) - + # Check no output was printed if not verbose: captured = capsys.readouterr()