We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Semantic Segmentation Scenes w/ 0 Chips Fail
Semantic segmentation scenes with zero chips cause raster-vision to halt.  This can be an issue when using finely-cropped scenes and filtering by nodata.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `rastervision_core/rastervision/core/rv_pipeline/semantic_segmentation.py`
Content:
```
1 import logging
2 from typing import List, Sequence
3 
4 import numpy as np
5 
6 from rastervision.core.box import Box
7 from rastervision.core.data import ClassConfig, Scene
8 from rastervision.core.rv_pipeline.rv_pipeline import RVPipeline
9 from rastervision.core.rv_pipeline.utils import (fill_no_data,
10                                                  nodata_below_threshold)
11 from rastervision.core.rv_pipeline.semantic_segmentation_config import (
12     SemanticSegmentationWindowMethod, SemanticSegmentationChipOptions)
13 
14 log = logging.getLogger(__name__)
15 
16 
17 def get_train_windows(scene: Scene,
18                       class_config: ClassConfig,
19                       chip_size: int,
20                       chip_options: SemanticSegmentationChipOptions,
21                       chip_nodata_threshold: float = 1.) -> List[Box]:
22     """Get training windows covering a scene.
23 
24     Args:
25         scene: The scene over-which windows are to be generated.
26 
27     Returns:
28         A list of windows, list(Box)
29     """
30     co = chip_options
31     raster_source = scene.raster_source
32     extent = raster_source.get_extent()
33     label_source = scene.ground_truth_label_source
34 
35     def filter_windows(windows: Sequence[Box]) -> List[Box]:
36         """Filter out chips that
37         (1) are outside the AOI
38         (2) only consist of null labels
39         (3) have NODATA proportion >= chip_nodata_threshold
40         """
41         total_windows = len(windows)
42         if scene.aoi_polygons:
43             windows = Box.filter_by_aoi(windows, scene.aoi_polygons)
44             log.info(f'AOI filtering: {len(windows)}/{total_windows} '
45                      'chips accepted')
46 
47         filt_windows = []
48         for w in windows:
49             chip = raster_source.get_chip(w)
50             nodata_below_thresh = nodata_below_threshold(
51                 chip, chip_nodata_threshold, nodata_val=0)
52 
53             label_arr = label_source.get_labels(w).get_label_arr(w)
54             null_labels = label_arr == class_config.get_null_class_id()
55 
56             if not np.all(null_labels) and nodata_below_thresh:
57                 filt_windows.append(w)
58         log.info('Label and NODATA filtering: '
59                  f'{len(filt_windows)}/{len(windows)} chips accepted')
60 
61         windows = filt_windows
62         return windows
63 
64     def should_use_window(window: Box) -> bool:
65         if co.negative_survival_prob >= 1.0:
66             return True
67         else:
68             target_class_ids = co.target_class_ids or list(
69                 range(len(class_config)))
70             is_pos = label_source.enough_target_pixels(
71                 window, co.target_count_threshold, target_class_ids)
72             should_use = is_pos or (np.random.rand() <
73                                     co.negative_survival_prob)
74             return should_use
75 
76     if co.window_method == SemanticSegmentationWindowMethod.sliding:
77         stride = co.stride or int(round(chip_size / 2))
78         windows = list(filter_windows((extent.get_windows(chip_size, stride))))
79         a_window = windows[0]
80         windows = list(filter(should_use_window, windows))
81         if len(windows) == 0:
82             windows = [a_window]
83     elif co.window_method == SemanticSegmentationWindowMethod.random_sample:
84         windows = []
85         attempts = 0
86 
87         while attempts < co.chips_per_scene:
88             window = extent.make_random_square(chip_size)
89             if not filter_windows([window]):
90                 continue
91 
92             attempts += 1
93             if co.negative_survival_prob >= 1.0:
94                 windows.append(window)
95             elif attempts == co.chips_per_scene and len(windows) == 0:
96                 # Ensure there is at least one window per scene.
97                 windows.append(window)
98             elif should_use_window(window):
99                 windows.append(window)
100 
101     return windows
102 
103 
104 class SemanticSegmentation(RVPipeline):
105     def __init__(self, config: 'RVPipelineConfig', tmp_dir: str):
106         super().__init__(config, tmp_dir)
107         if self.config.dataset.img_channels is None:
108             self.config.dataset.img_channels = self.get_img_channels()
109 
110             self.config.dataset.update()
111             self.config.dataset.validate_config()
112 
113             self.config.update()
114             self.config.validate_config()
115 
116     def get_img_channels(self):
117         ''' Determine img_channels from the first training scene. '''
118         class_config = self.config.dataset.class_config
119         scene_cfg = self.config.dataset.train_scenes[0]
120         scene = scene_cfg.build(
121             class_config, self.tmp_dir, use_transformers=False)
122         with scene.activate():
123             img_channels = scene.raster_source.num_channels
124         return img_channels
125 
126     def chip(self, *args, **kwargs):
127         log.info(f'Chip options: {self.config.chip_options}')
128         return super().chip(*args, **kwargs)
129 
130     def get_train_windows(self, scene):
131         return get_train_windows(
132             scene,
133             self.config.dataset.class_config,
134             self.config.train_chip_sz,
135             self.config.chip_options,
136             chip_nodata_threshold=self.config.chip_nodata_threshold)
137 
138     def get_train_labels(self, window, scene):
139         return scene.ground_truth_label_source.get_labels(window=window)
140 
141     def post_process_sample(self, sample):
142         # Use null label for each pixel with NODATA.
143         img = sample.chip
144         label_arr = sample.labels.get_label_arr(sample.window)
145         null_class_id = self.config.dataset.class_config.get_null_class_id()
146         sample.chip = fill_no_data(img, label_arr, null_class_id)
147         return sample
148 
149     def post_process_batch(self, windows, chips, labels):
150         # Fill in null class for any NODATA pixels.
151         null_class_id = self.config.dataset.class_config.get_null_class_id()
152         for window, chip in zip(windows, chips):
153             label_arr = labels.get_label_arr(window)
154             label_arr[np.sum(chip, axis=2) == 0] = null_class_id
155             labels.set_label_arr(window, label_arr)
156 
157         return labels
158
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/rastervision_core/rastervision/core/rv_pipeline/semantic_segmentation.py b/rastervision_core/rastervision/core/rv_pipeline/semantic_segmentation.py
--- a/rastervision_core/rastervision/core/rv_pipeline/semantic_segmentation.py
+++ b/rastervision_core/rastervision/core/rv_pipeline/semantic_segmentation.py
@@ -75,11 +75,15 @@
 
     if co.window_method == SemanticSegmentationWindowMethod.sliding:
         stride = co.stride or int(round(chip_size / 2))
-        windows = list(filter_windows((extent.get_windows(chip_size, stride))))
-        a_window = windows[0]
-        windows = list(filter(should_use_window, windows))
-        if len(windows) == 0:
-            windows = [a_window]
+        unfiltered_windows = extent.get_windows(chip_size, stride)
+        windows = list(filter_windows(unfiltered_windows))
+        if len(windows) > 0:
+            a_window = windows[0]
+            windows = list(filter(should_use_window, windows))
+            if len(windows) == 0:
+                windows = [a_window]
+        elif len(windows) == 0:
+            return [unfiltered_windows[0]]
     elif co.window_method == SemanticSegmentationWindowMethod.random_sample:
         windows = []
         attempts = 0

{"golden_diff": "diff --git a/rastervision_core/rastervision/core/rv_pipeline/semantic_segmentation.py b/rastervision_core/rastervision/core/rv_pipeline/semantic_segmentation.py\n--- a/rastervision_core/rastervision/core/rv_pipeline/semantic_segmentation.py\n+++ b/rastervision_core/rastervision/core/rv_pipeline/semantic_segmentation.py\n@@ -75,11 +75,15 @@\n \n     if co.window_method == SemanticSegmentationWindowMethod.sliding:\n         stride = co.stride or int(round(chip_size / 2))\n-        windows = list(filter_windows((extent.get_windows(chip_size, stride))))\n-        a_window = windows[0]\n-        windows = list(filter(should_use_window, windows))\n-        if len(windows) == 0:\n-            windows = [a_window]\n+        unfiltered_windows = extent.get_windows(chip_size, stride)\n+        windows = list(filter_windows(unfiltered_windows))\n+        if len(windows) > 0:\n+            a_window = windows[0]\n+            windows = list(filter(should_use_window, windows))\n+            if len(windows) == 0:\n+                windows = [a_window]\n+        elif len(windows) == 0:\n+            return [unfiltered_windows[0]]\n     elif co.window_method == SemanticSegmentationWindowMethod.random_sample:\n         windows = []\n         attempts = 0\n", "issue": "Semantic Segmentation Scenes w/ 0 Chips Fail\nSemantic segmentation scenes with zero chips cause raster-vision to halt.  This can be an issue when using finely-cropped scenes and filtering by nodata.\n", "before_files": [{"content": "import logging\nfrom typing import List, Sequence\n\nimport numpy as np\n\nfrom rastervision.core.box import Box\nfrom rastervision.core.data import ClassConfig, Scene\nfrom rastervision.core.rv_pipeline.rv_pipeline import RVPipeline\nfrom rastervision.core.rv_pipeline.utils import (fill_no_data,\n                                                 nodata_below_threshold)\nfrom rastervision.core.rv_pipeline.semantic_segmentation_config import (\n    SemanticSegmentationWindowMethod, SemanticSegmentationChipOptions)\n\nlog = logging.getLogger(__name__)\n\n\ndef get_train_windows(scene: Scene,\n                      class_config: ClassConfig,\n                      chip_size: int,\n                      chip_options: SemanticSegmentationChipOptions,\n                      chip_nodata_threshold: float = 1.) -> List[Box]:\n    \"\"\"Get training windows covering a scene.\n\n    Args:\n        scene: The scene over-which windows are to be generated.\n\n    Returns:\n        A list of windows, list(Box)\n    \"\"\"\n    co = chip_options\n    raster_source = scene.raster_source\n    extent = raster_source.get_extent()\n    label_source = scene.ground_truth_label_source\n\n    def filter_windows(windows: Sequence[Box]) -> List[Box]:\n        \"\"\"Filter out chips that\n        (1) are outside the AOI\n        (2) only consist of null labels\n        (3) have NODATA proportion >= chip_nodata_threshold\n        \"\"\"\n        total_windows = len(windows)\n        if scene.aoi_polygons:\n            windows = Box.filter_by_aoi(windows, scene.aoi_polygons)\n            log.info(f'AOI filtering: {len(windows)}/{total_windows} '\n                     'chips accepted')\n\n        filt_windows = []\n        for w in windows:\n            chip = raster_source.get_chip(w)\n            nodata_below_thresh = nodata_below_threshold(\n                chip, chip_nodata_threshold, nodata_val=0)\n\n            label_arr = label_source.get_labels(w).get_label_arr(w)\n            null_labels = label_arr == class_config.get_null_class_id()\n\n            if not np.all(null_labels) and nodata_below_thresh:\n                filt_windows.append(w)\n        log.info('Label and NODATA filtering: '\n                 f'{len(filt_windows)}/{len(windows)} chips accepted')\n\n        windows = filt_windows\n        return windows\n\n    def should_use_window(window: Box) -> bool:\n        if co.negative_survival_prob >= 1.0:\n            return True\n        else:\n            target_class_ids = co.target_class_ids or list(\n                range(len(class_config)))\n            is_pos = label_source.enough_target_pixels(\n                window, co.target_count_threshold, target_class_ids)\n            should_use = is_pos or (np.random.rand() <\n                                    co.negative_survival_prob)\n            return should_use\n\n    if co.window_method == SemanticSegmentationWindowMethod.sliding:\n        stride = co.stride or int(round(chip_size / 2))\n        windows = list(filter_windows((extent.get_windows(chip_size, stride))))\n        a_window = windows[0]\n        windows = list(filter(should_use_window, windows))\n        if len(windows) == 0:\n            windows = [a_window]\n    elif co.window_method == SemanticSegmentationWindowMethod.random_sample:\n        windows = []\n        attempts = 0\n\n        while attempts < co.chips_per_scene:\n            window = extent.make_random_square(chip_size)\n            if not filter_windows([window]):\n                continue\n\n            attempts += 1\n            if co.negative_survival_prob >= 1.0:\n                windows.append(window)\n            elif attempts == co.chips_per_scene and len(windows) == 0:\n                # Ensure there is at least one window per scene.\n                windows.append(window)\n            elif should_use_window(window):\n                windows.append(window)\n\n    return windows\n\n\nclass SemanticSegmentation(RVPipeline):\n    def __init__(self, config: 'RVPipelineConfig', tmp_dir: str):\n        super().__init__(config, tmp_dir)\n        if self.config.dataset.img_channels is None:\n            self.config.dataset.img_channels = self.get_img_channels()\n\n            self.config.dataset.update()\n            self.config.dataset.validate_config()\n\n            self.config.update()\n            self.config.validate_config()\n\n    def get_img_channels(self):\n        ''' Determine img_channels from the first training scene. '''\n        class_config = self.config.dataset.class_config\n        scene_cfg = self.config.dataset.train_scenes[0]\n        scene = scene_cfg.build(\n            class_config, self.tmp_dir, use_transformers=False)\n        with scene.activate():\n            img_channels = scene.raster_source.num_channels\n        return img_channels\n\n    def chip(self, *args, **kwargs):\n        log.info(f'Chip options: {self.config.chip_options}')\n        return super().chip(*args, **kwargs)\n\n    def get_train_windows(self, scene):\n        return get_train_windows(\n            scene,\n            self.config.dataset.class_config,\n            self.config.train_chip_sz,\n            self.config.chip_options,\n            chip_nodata_threshold=self.config.chip_nodata_threshold)\n\n    def get_train_labels(self, window, scene):\n        return scene.ground_truth_label_source.get_labels(window=window)\n\n    def post_process_sample(self, sample):\n        # Use null label for each pixel with NODATA.\n        img = sample.chip\n        label_arr = sample.labels.get_label_arr(sample.window)\n        null_class_id = self.config.dataset.class_config.get_null_class_id()\n        sample.chip = fill_no_data(img, label_arr, null_class_id)\n        return sample\n\n    def post_process_batch(self, windows, chips, labels):\n        # Fill in null class for any NODATA pixels.\n        null_class_id = self.config.dataset.class_config.get_null_class_id()\n        for window, chip in zip(windows, chips):\n            label_arr = labels.get_label_arr(window)\n            label_arr[np.sum(chip, axis=2) == 0] = null_class_id\n            labels.set_label_arr(window, label_arr)\n\n        return labels\n", "path": "rastervision_core/rastervision/core/rv_pipeline/semantic_segmentation.py"}], "after_files": [{"content": "import logging\nfrom typing import List, Sequence\n\nimport numpy as np\n\nfrom rastervision.core.box import Box\nfrom rastervision.core.data import ClassConfig, Scene\nfrom rastervision.core.rv_pipeline.rv_pipeline import RVPipeline\nfrom rastervision.core.rv_pipeline.utils import (fill_no_data,\n                                                 nodata_below_threshold)\nfrom rastervision.core.rv_pipeline.semantic_segmentation_config import (\n    SemanticSegmentationWindowMethod, SemanticSegmentationChipOptions)\n\nlog = logging.getLogger(__name__)\n\n\ndef get_train_windows(scene: Scene,\n                      class_config: ClassConfig,\n                      chip_size: int,\n                      chip_options: SemanticSegmentationChipOptions,\n                      chip_nodata_threshold: float = 1.) -> List[Box]:\n    \"\"\"Get training windows covering a scene.\n\n    Args:\n        scene: The scene over-which windows are to be generated.\n\n    Returns:\n        A list of windows, list(Box)\n    \"\"\"\n    co = chip_options\n    raster_source = scene.raster_source\n    extent = raster_source.get_extent()\n    label_source = scene.ground_truth_label_source\n\n    def filter_windows(windows: Sequence[Box]) -> List[Box]:\n        \"\"\"Filter out chips that\n        (1) are outside the AOI\n        (2) only consist of null labels\n        (3) have NODATA proportion >= chip_nodata_threshold\n        \"\"\"\n        total_windows = len(windows)\n        if scene.aoi_polygons:\n            windows = Box.filter_by_aoi(windows, scene.aoi_polygons)\n            log.info(f'AOI filtering: {len(windows)}/{total_windows} '\n                     'chips accepted')\n\n        filt_windows = []\n        for w in windows:\n            chip = raster_source.get_chip(w)\n            nodata_below_thresh = nodata_below_threshold(\n                chip, chip_nodata_threshold, nodata_val=0)\n\n            label_arr = label_source.get_labels(w).get_label_arr(w)\n            null_labels = label_arr == class_config.get_null_class_id()\n\n            if not np.all(null_labels) and nodata_below_thresh:\n                filt_windows.append(w)\n        log.info('Label and NODATA filtering: '\n                 f'{len(filt_windows)}/{len(windows)} chips accepted')\n\n        windows = filt_windows\n        return windows\n\n    def should_use_window(window: Box) -> bool:\n        if co.negative_survival_prob >= 1.0:\n            return True\n        else:\n            target_class_ids = co.target_class_ids or list(\n                range(len(class_config)))\n            is_pos = label_source.enough_target_pixels(\n                window, co.target_count_threshold, target_class_ids)\n            should_use = is_pos or (np.random.rand() <\n                                    co.negative_survival_prob)\n            return should_use\n\n    if co.window_method == SemanticSegmentationWindowMethod.sliding:\n        stride = co.stride or int(round(chip_size / 2))\n        unfiltered_windows = extent.get_windows(chip_size, stride)\n        windows = list(filter_windows(unfiltered_windows))\n        if len(windows) > 0:\n            a_window = windows[0]\n            windows = list(filter(should_use_window, windows))\n            if len(windows) == 0:\n                windows = [a_window]\n        elif len(windows) == 0:\n            return [unfiltered_windows[0]]\n    elif co.window_method == SemanticSegmentationWindowMethod.random_sample:\n        windows = []\n        attempts = 0\n\n        while attempts < co.chips_per_scene:\n            window = extent.make_random_square(chip_size)\n            if not filter_windows([window]):\n                continue\n\n            attempts += 1\n            if co.negative_survival_prob >= 1.0:\n                windows.append(window)\n            elif attempts == co.chips_per_scene and len(windows) == 0:\n                # Ensure there is at least one window per scene.\n                windows.append(window)\n            elif should_use_window(window):\n                windows.append(window)\n\n    return windows\n\n\nclass SemanticSegmentation(RVPipeline):\n    def __init__(self, config: 'RVPipelineConfig', tmp_dir: str):\n        super().__init__(config, tmp_dir)\n        if self.config.dataset.img_channels is None:\n            self.config.dataset.img_channels = self.get_img_channels()\n\n            self.config.dataset.update()\n            self.config.dataset.validate_config()\n\n            self.config.update()\n            self.config.validate_config()\n\n    def get_img_channels(self):\n        ''' Determine img_channels from the first training scene. '''\n        class_config = self.config.dataset.class_config\n        scene_cfg = self.config.dataset.train_scenes[0]\n        scene = scene_cfg.build(\n            class_config, self.tmp_dir, use_transformers=False)\n        with scene.activate():\n            img_channels = scene.raster_source.num_channels\n        return img_channels\n\n    def chip(self, *args, **kwargs):\n        log.info(f'Chip options: {self.config.chip_options}')\n        return super().chip(*args, **kwargs)\n\n    def get_train_windows(self, scene):\n        return get_train_windows(\n            scene,\n            self.config.dataset.class_config,\n            self.config.train_chip_sz,\n            self.config.chip_options,\n            chip_nodata_threshold=self.config.chip_nodata_threshold)\n\n    def get_train_labels(self, window, scene):\n        return scene.ground_truth_label_source.get_labels(window=window)\n\n    def post_process_sample(self, sample):\n        # Use null label for each pixel with NODATA.\n        img = sample.chip\n        label_arr = sample.labels.get_label_arr(sample.window)\n        null_class_id = self.config.dataset.class_config.get_null_class_id()\n        sample.chip = fill_no_data(img, label_arr, null_class_id)\n        return sample\n\n    def post_process_batch(self, windows, chips, labels):\n        # Fill in null class for any NODATA pixels.\n        null_class_id = self.config.dataset.class_config.get_null_class_id()\n        for window, chip in zip(windows, chips):\n            label_arr = labels.get_label_arr(window)\n            label_arr[np.sum(chip, axis=2) == 0] = null_class_id\n            labels.set_label_arr(window, label_arr)\n\n        return labels\n", "path": "rastervision_core/rastervision/core/rv_pipeline/semantic_segmentation.py"}]}