def setUp(self): self.tmp_dir = rv_config.get_tmp_dir() self.class_config = ClassConfig(names=['one', 'two']) self.class_config.update() self.class_config.ensure_null_class() self.null_class_id = self.class_config.get_null_class_id()
def _test_class_inf(self, props, exp_class_ids, default_class_id=None): geojson = { 'type': 'FeatureCollection', 'features': [{ 'properties': props, 'geometry': { 'type': 'Point', 'coordinates': [1, 1] } }] } json_to_file(geojson, self.uri) class_config = ClassConfig(names=['building', 'car', 'tree']) class_id_to_filter = { 0: ['==', 'type', 'building'], 1: ['any', ['==', 'type', 'car'], ['==', 'type', 'auto']] } vs_cfg = GeoJSONVectorSourceConfig( uri=self.uri, class_id_to_filter=class_id_to_filter, default_class_id=default_class_id) vs = vs_cfg.build(class_config, IdentityCRSTransformer()) trans_geojson = vs.get_geojson() class_ids = [ f['properties']['class_id'] for f in trans_geojson['features'] ] self.assertEqual(class_ids, exp_class_ids)
def test_accounts_for_aoi(self): class_config = ClassConfig(names=['car', 'building', 'background']) label_source_uri = data_file_path('evaluator/cc-label-filtered.json') label_source_cfg = ChipClassificationLabelSourceConfig( vector_source=GeoJSONVectorSourceConfig( uri=label_source_uri, default_class_id=None)) label_store_uri = data_file_path('evaluator/cc-label-full.json') label_store_cfg = ChipClassificationGeoJSONStoreConfig( uri=label_store_uri) raster_source_uri = data_file_path('evaluator/cc-label-img-blank.tif') raster_source_cfg = RasterioSourceConfig(uris=[raster_source_uri]) aoi_uri = data_file_path('evaluator/cc-label-aoi.json') s = SceneConfig( id='test', raster_source=raster_source_cfg, label_source=label_source_cfg, label_store=label_store_cfg, aoi_uris=[aoi_uri]) with rv_config.get_tmp_dir() as tmp_dir: scene = s.build(class_config, tmp_dir) output_uri = os.path.join(tmp_dir, 'eval.json') evaluator = ChipClassificationEvaluatorConfig( output_uri=output_uri).build(class_config) evaluator.process([scene], tmp_dir) overall = file_to_json(output_uri)['overall'] for item in overall: self.assertEqual(item['f1'], 1.0)
def test_get_labels_rgb(self): data = np.zeros((10, 10, 3), dtype=np.uint8) data[7:, 7:, :] = [1, 1, 1] null_class_id = 2 raster_source = MockRasterSource([0, 1, 2], 3) raster_source.set_raster(data) rgb_class_config = ClassConfig(names=['a'], colors=['#010101']) rgb_class_config.ensure_null_class() label_source = SemanticSegmentationLabelSource( raster_source, null_class_id, rgb_class_config=rgb_class_config) with label_source.activate(): window = Box.make_square(7, 7, 3) labels = label_source.get_labels(window=window) label_arr = labels.get_label_arr(window) expected_label_arr = np.zeros((3, 3)) np.testing.assert_array_equal(label_arr, expected_label_arr)
def test_rgb_class_config_null_class(self): raster_source_cfg = RasterioSourceConfig(uris=['/abc/def.tif']) rgb_class_config = ClassConfig(names=['a'], colors=['#010101']) cfg = SemanticSegmentationLabelSourceConfig( raster_source=raster_source_cfg, rgb_class_config=rgb_class_config) cfg.update() self.assertEqual(len(cfg.rgb_class_config), 2) self.assertIn('null', cfg.rgb_class_config.names)
def test_compute_ignore_class(self): class_config = ClassConfig(names=['one', 'two']) class_config.update() class_config.ensure_null_class() null_class_id = class_config.get_null_class_id() gt_array = np.zeros((4, 4, 1), dtype=np.uint8) gt_array[0, 0, 0] = 2 gt_raster = MockRasterSource([0], 1) gt_raster.set_raster(gt_array) gt_label_source = SemanticSegmentationLabelSource( gt_raster, null_class_id) pred_array = np.zeros((4, 4, 1), dtype=np.uint8) pred_array[0, 0, 0] = 1 pred_raster = MockRasterSource([0], 1) pred_raster.set_raster(pred_array) pred_label_source = SemanticSegmentationLabelSource( pred_raster, null_class_id) eval = SemanticSegmentationEvaluation(class_config) eval.compute(gt_label_source.get_labels(), pred_label_source.get_labels()) self.assertAlmostEqual(1.0, eval.class_to_eval_item[0].f1) self.assertAlmostEqual(1.0, eval.avg_item.f1)
def setUp(self): self.crs_transformer = IdentityCRSTransformer() self.extent = Box.make_square(0, 0, 10) self.tmp_dir_obj = rv_config.get_tmp_dir() self.tmp_dir = self.tmp_dir_obj.name self.class_id = 0 self.background_class_id = 1 self.line_buffer = 1 self.class_config = ClassConfig(names=['a']) self.uri = join(self.tmp_dir, 'tmp.json')
def setUp(self): self.crs_transformer = DoubleCRSTransformer() self.geojson = { 'type': 'FeatureCollection', 'features': [{ 'type': 'Feature', 'geometry': { 'type': 'MultiPolygon', 'coordinates': [[[[0., 0.], [0., 2.], [2., 2.], [2., 0.], [0., 0.]]]] }, 'properties': { 'class_name': 'car', 'class_id': 0, 'score': 0.0 } }, { 'type': 'Feature', 'geometry': { 'type': 'Polygon', 'coordinates': [[[2., 2.], [2., 4.], [4., 4.], [4., 2.], [2., 2.]]] }, 'properties': { 'score': 0.0, 'class_name': 'house', 'class_id': 1 } }] } self.class_config = ClassConfig(names=['car', 'house']) self.box1 = Box.make_square(0, 0, 4) self.box2 = Box.make_square(4, 4, 4) self.class_id1 = 0 self.class_id2 = 1 self.background_class_id = 2 geoms = [] for f in self.geojson['features']: g = shape(f['geometry']) g.class_id = f['properties']['class_id'] geoms.append(g) self.str_tree = STRtree(geoms) self.file_name = 'labels.json' self.tmp_dir = rv_config.get_tmp_dir() self.uri = os.path.join(self.tmp_dir.name, self.file_name) json_to_file(self.geojson, self.uri)
def test_compute(self): class_config = ClassConfig(names=['one', 'two']) class_config.update() class_config.ensure_null_class() null_class_id = class_config.get_null_class_id() gt_array = np.zeros((4, 4, 1), dtype=np.uint8) gt_array[2, 2, 0] = 1 gt_array[0, 0, 0] = 2 gt_raster = MockRasterSource([0], 1) gt_raster.set_raster(gt_array) gt_label_source = SemanticSegmentationLabelSource( gt_raster, null_class_id) p_array = np.zeros((4, 4, 1), dtype=np.uint8) p_array[1, 1, 0] = 1 p_raster = MockRasterSource([0], 1) p_raster.set_raster(p_array) p_label_source = SemanticSegmentationLabelSource( p_raster, null_class_id) eval = SemanticSegmentationEvaluation(class_config) eval.compute(gt_label_source.get_labels(), p_label_source.get_labels()) tp0 = 16 - 3 # 4*4 - 3 true positives for class 0 fp0 = 1 # 1 false positive (2,2) and one don't care at (0,0) fn0 = 1 # one false negative (1,1) precision0 = float(tp0) / (tp0 + fp0) recall0 = float(tp0) / (tp0 + fn0) f10 = 2 * float(precision0 * recall0) / (precision0 + recall0) tp1 = 0 # 0 true positives for class 1 fn1 = 1 # one false negative (2,2) precision1 = 0 # float(tp1) / (tp1 + fp1) where fp1 == 1 recall1 = float(tp1) / (tp1 + fn1) f11 = None self.assertAlmostEqual(precision0, eval.class_to_eval_item[0].precision) self.assertAlmostEqual(recall0, eval.class_to_eval_item[0].recall) self.assertAlmostEqual(f10, eval.class_to_eval_item[0].f1) self.assertEqual(precision1, eval.class_to_eval_item[1].precision) self.assertAlmostEqual(recall1, eval.class_to_eval_item[1].recall) self.assertAlmostEqual(f11, eval.class_to_eval_item[1].f1) avg_conf_mat = np.array([[0, 0, 0], [13., 1, 0], [1, 0, 0]]) avg_recall = (14 / 15) * recall0 + (1 / 15) * recall1 self.assertTrue(np.array_equal(avg_conf_mat, eval.avg_item.conf_mat)) self.assertEqual(avg_recall, eval.avg_item.recall)
def transform_geojson(self, geojson, line_bufs=None, point_bufs=None, crs_transformer=None, to_map_coords=False): if crs_transformer is None: crs_transformer = IdentityCRSTransformer() class_config = ClassConfig(names=['building']) json_to_file(geojson, self.uri) cfg = GeoJSONVectorSourceConfig( uri=self.uri, line_bufs=line_bufs, point_bufs=point_bufs, default_class_id=0) source = cfg.build(class_config, crs_transformer) return source.get_geojson(to_map_coords=to_map_coords)
def setUp(self): self.file_name = 'labels.json' self.tmp_dir = rv_config.get_tmp_dir() self.file_path = os.path.join(self.tmp_dir.name, self.file_name) self.crs_transformer = DoubleCRSTransformer() self.geojson = { 'type': 'FeatureCollection', 'features': [{ 'type': 'Feature', 'geometry': { 'type': 'Polygon', 'coordinates': [[[0., 0.], [0., 1.], [1., 1.], [1., 0.], [0., 0.]]] }, 'properties': { 'class_id': 0, 'score': 0.9 } }, { 'type': 'Feature', 'geometry': { 'type': 'Polygon', 'coordinates': [[[1., 1.], [1., 2.], [2., 2.], [2., 1.], [1., 1.]]] }, 'properties': { 'score': 0.9, 'class_id': 1 } }] } self.extent = Box.make_square(0, 0, 10) self.class_config = ClassConfig(names=['car', 'house']) json_to_file(self.geojson, self.file_path)
def test_vector_compute(self): class_config = ClassConfig(names=['one', 'two']) class_config.update() class_config.ensure_null_class() gt_uri = data_file_path('2-gt-polygons.geojson') pred_uri = data_file_path('2-pred-polygons.geojson') eval = SemanticSegmentationEvaluation(class_config) eval.compute_vector(gt_uri, pred_uri, 'polygons', 0) # NOTE: The two geojson files referenced above contain three # unique geometries total, each file contains two geometries, # and there is one geometry shared between the two. tp = 1.0 fp = 1.0 fn = 1.0 precision = float(tp) / (tp + fp) recall = float(tp) / (tp + fn) self.assertAlmostEqual(precision, eval.class_to_eval_item[0].precision) self.assertAlmostEqual(recall, eval.class_to_eval_item[0].recall)
def get_config(runner, root_uri, data_uri=None, full_train=False): def get_path(part): if full_train: return join(data_uri, part) else: return join(dirname(__file__), part) class_config = ClassConfig(names=['red', 'green'], colors=['red', 'green']) def make_scene(id, img_path, label_path): raster_source = RasterioSourceConfig(channel_order=[0, 1, 2], uris=[img_path]) label_source = SemanticSegmentationLabelSourceConfig( rgb_class_config=class_config, raster_source=RasterioSourceConfig(uris=[label_path])) label_store = SemanticSegmentationLabelStoreConfig( rgb=True, vector_output=[ PolygonVectorOutputConfig(class_id=0), BuildingVectorOutputConfig(class_id=1) ]) return SceneConfig(id=id, raster_source=raster_source, label_source=label_source, label_store=label_store) chip_sz = 300 img_sz = chip_sz data = SemanticSegmentationImageDataConfig(img_sz=img_sz, augmentors=[]) if full_train: model = SemanticSegmentationModelConfig(backbone=Backbone.resnet50) solver = SolverConfig(lr=1e-4, num_epochs=300, batch_sz=8, one_cycle=True, sync_interval=300) else: pretrained_uri = ( 'https://github.com/azavea/raster-vision-data/releases/download/v0.12/' 'semantic-segmentation.pth') model = SemanticSegmentationModelConfig(backbone=Backbone.resnet50, init_weights=pretrained_uri) solver = SolverConfig(lr=1e-9, num_epochs=1, batch_sz=2, one_cycle=True, sync_interval=200) backend = PyTorchSemanticSegmentationConfig(data=data, model=model, solver=solver, log_tensorboard=False, run_tensorboard=False) scenes = [ make_scene('test-scene', get_path('scene/image.tif'), get_path('scene/labels.tif')), make_scene('test-scene2', get_path('scene/image2.tif'), get_path('scene/labels2.tif')) ] scene_dataset = DatasetConfig(class_config=class_config, train_scenes=scenes, validation_scenes=scenes) chip_options = SemanticSegmentationChipOptions( window_method=SemanticSegmentationWindowMethod.sliding, stride=chip_sz) return SemanticSegmentationConfig(root_uri=root_uri, dataset=scene_dataset, backend=backend, train_chip_sz=chip_sz, predict_chip_sz=chip_sz, chip_options=chip_options)
def get_config(runner, raw_uri: str, processed_uri: str, root_uri: str, test: bool = False) -> SemanticSegmentationConfig: """Generate the pipeline config for this task. This function will be called by RV, with arguments from the command line, when this example is run. Args: runner (Runner): Runner for the pipeline. raw_uri (str): Directory where the raw data resides processed_uri (str): Directory for storing processed data. E.g. crops for testing. root_uri (str): Directory where all the output will be written. test (bool, optional): Whether to run in test mode. Defaults to False. Returns: SemanticSegmentationConfig: A pipeline config. """ if not test: train_ids, val_ids = TRAIN_IDS, VAL_IDS else: train_ids, val_ids = TEST_MODE_TRAIN_IDS, TEST_MODE_VAL_IDS raw_uri = UriPath(raw_uri) processed_uri = UriPath(processed_uri) # ------------------------------- # Configure dataset generation # ------------------------------- class_config = ClassConfig(names=CLASS_NAMES, colors=CLASS_COLORS) chip_options = SemanticSegmentationChipOptions( window_method=SemanticSegmentationWindowMethod.sliding, stride=CHIP_SIZE) _make_scene = partial(make_scene, raw_uri, processed_uri, class_config, test_mode=test) dataset_config = DatasetConfig( class_config=class_config, train_scenes=[_make_scene(scene_id) for scene_id in train_ids], validation_scenes=[_make_scene(scene_id) for scene_id in val_ids]) # -------------------------------------------- # Configure PyTorch backend and training # -------------------------------------------- model_config = SemanticSegmentationModelConfig(backbone=Backbone.resnet50) solver_config = SolverConfig(lr=LR, num_epochs=NUM_EPOCHS, batch_sz=BATCH_SIZE, test_num_epochs=TEST_MODE_NUM_EPOCHS, test_batch_sz=TEST_MODE_BATCH_SIZE, one_cycle=ONE_CYCLE) backend_config = PyTorchSemanticSegmentationConfig( model=model_config, solver=solver_config, log_tensorboard=LOG_TENSORBOARD, run_tensorboard=RUN_TENSORBOARD, test_mode=test) # ----------------------------------------------- # Pass configurations to the pipeline config # ----------------------------------------------- pipeline_config = SemanticSegmentationConfig( root_uri=root_uri, train_chip_sz=CHIP_SIZE, predict_chip_sz=CHIP_SIZE, chip_options=chip_options, dataset=dataset_config, backend=backend_config, channel_display_groups=CHANNEL_DISPLAY_GROUPS) return pipeline_config
def get_config(runner, root_uri, analyze_uri, chip_uri, json, chip_sz=512, batch_sz=32, epochs=33, preshrink=1, small_test=False, architecture='cheaplab', level='L1C'): chip_sz = int(chip_sz) epochs = int(epochs) batch_sz = int(batch_sz) preshrink = int(preshrink) assert (architecture in ['cheaplab', 'fpn-resnet18']) assert (level in ['L1C', 'L2A']) if level == 'L1C': channel_order = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] elif level == 'L2A': channel_order = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] num_channels = len(channel_order) class_config = ClassConfig(names=["background", "cloud"], colors=["brown", "white"]) class_id_filter_dict = { 0: ['==', 'default', 'Background'], 1: ['==', 'default', 'Cloud'], } train_crops = [] val_crops = [] for x in range(0, 5): for y in range(0, 5): x_start = x / 5.0 x_end = 0.80 - x_start y_start = y / 5.0 y_end = 0.80 - y_start crop = [x_start, y_start, x_end, y_end] if x == y: val_crops.append(crop) else: train_crops.append(crop) scenes = get_scenes(json, channel_order, class_config, class_id_filter_dict, level, train_crops=train_crops, val_crops=val_crops) train_scenes, validation_scenes = scenes if small_test: train_scenes = train_scenes[0:2] validation_scenes = validation_scenes[0:2] print(f"{len(train_scenes)} training scenes") print(f"{len(validation_scenes)} validation scenes") dataset = DatasetConfig( class_config=class_config, train_scenes=train_scenes, validation_scenes=validation_scenes, ) if architecture == 'fpn-resnet18': external_def = ExternalModuleConfig( github_repo='AdeelH/pytorch-fpn:0.1', name='pytorch-fpn', entrypoint='make_segm_fpn_resnet', entrypoint_kwargs={ 'name': 'resnet18', 'fpn_type': 'fpn', 'num_classes': 2, 'fpn_channels': 256, 'in_channels': len(channel_order), 'out_size': (chip_sz, chip_sz) }) else: external_def = ExternalModuleConfig( github_repo='jamesmcclain/CheapLab:08d260b', name='cheaplab', entrypoint='make_cheaplab_model', entrypoint_kwargs={ 'preshrink': preshrink, 'num_channels': num_channels }) model = SemanticSegmentationModelConfig(external_def=external_def) external_loss_def = ExternalModuleConfig( github_repo='jamesmcclain/CheapLab:08d260b', name='bce_loss', entrypoint='make_bce_loss', force_reload=False, entrypoint_kwargs={}) backend = PyTorchSemanticSegmentationConfig( model=model, solver=SolverConfig(lr=1e-4, num_epochs=epochs, batch_sz=batch_sz, external_loss_def=external_loss_def, ignore_last_class='force'), log_tensorboard=False, run_tensorboard=False, num_workers=0, preview_batch_limit=8) chip_options = SemanticSegmentationChipOptions( window_method=SemanticSegmentationWindowMethod.sliding, stride=chip_sz) return SemanticSegmentationConfig(root_uri=root_uri, analyze_uri=analyze_uri, chip_uri=chip_uri, dataset=dataset, backend=backend, train_chip_sz=chip_sz, predict_chip_sz=chip_sz, chip_options=chip_options, chip_nodata_threshold=.75, img_format='npy', label_format='npy')
def get_config(runner, root_uri, data_uri=None, full_train=False): def get_path(part): if full_train: return join(data_uri, part) else: return join(dirname(__file__), part) class_config = ClassConfig(names=['car', 'building', 'background'], colors=['red', 'blue', 'black']) def make_scene(img_path, label_path): id = basename(img_path) label_source = ChipClassificationLabelSourceConfig( vector_source=GeoJSONVectorSourceConfig(uri=label_path, default_class_id=None, ignore_crs_field=True), ioa_thresh=0.5, use_intersection_over_cell=False, pick_min_class_id=True, background_class_id=2, infer_cells=True) raster_source = RasterioSourceConfig( channel_order=[0, 1, 2], uris=[img_path], transformers=[StatsTransformerConfig()]) return SceneConfig(id=id, raster_source=raster_source, label_source=label_source) scenes = [ make_scene(get_path('scene/image.tif'), get_path('scene/labels.json')), make_scene(get_path('scene/image2.tif'), get_path('scene/labels2.json')) ] scene_dataset = DatasetConfig(class_config=class_config, train_scenes=scenes, validation_scenes=scenes) chip_sz = 200 img_sz = chip_sz data = ClassificationImageDataConfig(img_sz=img_sz, augmentors=[]) if full_train: model = ClassificationModelConfig(backbone=Backbone.resnet18) solver = SolverConfig(lr=1e-4, num_epochs=300, batch_sz=8, one_cycle=True, sync_interval=300) else: pretrained_uri = ( 'https://github.com/azavea/raster-vision-data/releases/download/v0.12/' 'chip-classification.pth') model = ClassificationModelConfig(backbone=Backbone.resnet18, init_weights=pretrained_uri) solver = SolverConfig(lr=1e-9, num_epochs=1, batch_sz=2, one_cycle=True, sync_interval=200) backend = PyTorchChipClassificationConfig(data=data, model=model, solver=solver, log_tensorboard=False, run_tensorboard=False) config = ChipClassificationConfig(root_uri=root_uri, dataset=scene_dataset, backend=backend, train_chip_sz=chip_sz, predict_chip_sz=chip_sz) return config
class TestSemanticSegmentationEvaluator(unittest.TestCase): def setUp(self): self.tmp_dir = rv_config.get_tmp_dir() self.class_config = ClassConfig(names=['one', 'two']) self.class_config.update() self.class_config.ensure_null_class() self.null_class_id = self.class_config.get_null_class_id() def tearDown(self): self.tmp_dir.cleanup() def get_scene(self, class_id): # Make scene where ground truth is all set to class_id # and predictions are set to half 0's and half 1's scene_id = str(class_id) rs = MockRasterSource(channel_order=[0, 1, 2], num_channels=3) rs.set_raster(np.zeros((10, 10, 3))) gt_rs = MockRasterSource(channel_order=[0], num_channels=1) gt_arr = np.full((10, 10, 1), class_id) gt_rs.set_raster(gt_arr) gt_ls = SemanticSegmentationLabelSource(gt_rs, self.null_class_id) pred_rs = MockRasterSource(channel_order=[0], num_channels=1) pred_arr = np.zeros((10, 10, 1)) pred_arr[5:10, :, :] = 1 pred_rs.set_raster(pred_arr) pred_ls = SemanticSegmentationLabelSource(pred_rs, self.null_class_id) return Scene(scene_id, rs, gt_ls, pred_ls) def test_evaluator(self): output_uri = join(self.tmp_dir.name, 'out.json') scenes = [self.get_scene(0), self.get_scene(1)] evaluator = SemanticSegmentationEvaluator(self.class_config, output_uri, None) evaluator.process(scenes, self.tmp_dir.name) eval_json = file_to_json(output_uri) exp_eval_json = file_to_json(data_file_path('expected-eval.json')) self.assertDictEqual(eval_json, exp_eval_json) def get_vector_scene(self, class_id, use_aoi=False): gt_uri = data_file_path('{}-gt-polygons.geojson'.format(class_id)) pred_uri = data_file_path('{}-pred-polygons.geojson'.format(class_id)) scene_id = str(class_id) rs = MockRasterSource(channel_order=[0, 1, 3], num_channels=3) rs.set_raster(np.zeros((10, 10, 3))) crs_transformer = IdentityCRSTransformer() extent = Box.make_square(0, 0, 360) config = RasterizedSourceConfig( vector_source=GeoJSONVectorSourceConfig(uri=gt_uri, default_class_id=0), rasterizer_config=RasterizerConfig(background_class_id=1)) gt_rs = config.build(self.class_config, crs_transformer, extent) gt_ls = SemanticSegmentationLabelSource(gt_rs, self.null_class_id) config = RasterizedSourceConfig( vector_source=GeoJSONVectorSourceConfig(uri=pred_uri, default_class_id=0), rasterizer_config=RasterizerConfig(background_class_id=1)) pred_rs = config.build(self.class_config, crs_transformer, extent) pred_ls = SemanticSegmentationLabelSource(pred_rs, self.null_class_id) pred_ls.vector_output = [ PolygonVectorOutputConfig(uri=pred_uri, denoise=0, class_id=class_id) ] if use_aoi: aoi_uri = data_file_path('{}-aoi.geojson'.format(class_id)) aoi_geojson = file_to_json(aoi_uri) aoi_polygons = [shape(aoi_geojson['features'][0]['geometry'])] return Scene(scene_id, rs, gt_ls, pred_ls, aoi_polygons) return Scene(scene_id, rs, gt_ls, pred_ls) def test_vector_evaluator(self): output_uri = join(self.tmp_dir.name, 'raster-out.json') vector_output_uri = join(self.tmp_dir.name, 'vector-out.json') scenes = [self.get_vector_scene(0), self.get_vector_scene(1)] evaluator = SemanticSegmentationEvaluator(self.class_config, output_uri, vector_output_uri) evaluator.process(scenes, self.tmp_dir.name) vector_eval_json = file_to_json(vector_output_uri) exp_vector_eval_json = file_to_json( data_file_path('expected-vector-eval.json')) # NOTE: The precision and recall values found in the file # `expected-vector-eval.json` are equal to fractions of the # form (n-1)/n for n <= 7 which can be seen to be (and have # been manually verified to be) correct. self.assertDictEqual(vector_eval_json, exp_vector_eval_json) def test_vector_evaluator_with_aoi(self): output_uri = join(self.tmp_dir.name, 'raster-out.json') vector_output_uri = join(self.tmp_dir.name, 'vector-out.json') scenes = [self.get_vector_scene(0, use_aoi=True)] evaluator = SemanticSegmentationEvaluator(self.class_config, output_uri, vector_output_uri) evaluator.process(scenes, self.tmp_dir.name) vector_eval_json = file_to_json(vector_output_uri) exp_vector_eval_json = file_to_json( data_file_path('expected-vector-eval-with-aoi.json')) # NOTE: The precision and recall values found in the file # `expected-vector-eval.json` are equal to fractions of the # form (n-1)/n for n <= 7 which can be seen to be (and have # been manually verified to be) correct. self.assertDictEqual(vector_eval_json, exp_vector_eval_json)
def get_config(runner, root_uri, data_uri=None, full_train=False): def get_path(part): if full_train: return join(data_uri, part) else: return join(dirname(__file__), part) class_config = ClassConfig(names=['car', 'building'], colors=['blue', 'red']) def make_scene(scene_id, img_path, label_path): raster_source = RasterioSourceConfig(channel_order=[0, 1, 2], uris=[img_path]) label_source = ObjectDetectionLabelSourceConfig( vector_source=GeoJSONVectorSourceConfig(uri=label_path, default_class_id=None)) return SceneConfig(id=scene_id, raster_source=raster_source, label_source=label_source) chip_sz = 300 img_sz = chip_sz data = ObjectDetectionImageDataConfig(img_sz=img_sz, augmentors=[]) if full_train: model = ObjectDetectionModelConfig(backbone=Backbone.resnet18) solver = SolverConfig(lr=1e-4, num_epochs=300, batch_sz=8, one_cycle=True, sync_interval=300) else: pretrained_uri = ( 'https://github.com/azavea/raster-vision-data/releases/download/v0.12/' 'object-detection.pth') model = ObjectDetectionModelConfig(backbone=Backbone.resnet18, init_weights=pretrained_uri) solver = SolverConfig(lr=1e-9, num_epochs=1, batch_sz=2, one_cycle=True, sync_interval=200) backend = PyTorchObjectDetectionConfig(data=data, model=model, solver=solver, log_tensorboard=False, run_tensorboard=False) scenes = [ make_scene('od_test', get_path('scene/image.tif'), get_path('scene/labels.json')), make_scene('od_test-2', get_path('scene/image2.tif'), get_path('scene/labels2.json')) ] scene_dataset = DatasetConfig(class_config=class_config, train_scenes=scenes, validation_scenes=scenes) chip_options = ObjectDetectionChipOptions(neg_ratio=1.0, ioa_thresh=1.0) predict_options = ObjectDetectionPredictOptions(merge_thresh=0.1, score_thresh=0.5) return ObjectDetectionConfig(root_uri=root_uri, dataset=scene_dataset, backend=backend, train_chip_sz=chip_sz, predict_chip_sz=chip_sz, chip_options=chip_options, predict_options=predict_options)
def get_config(runner, raw_uri: str, processed_uri: str, root_uri: str, nochip: bool = True, test: bool = False) -> SemanticSegmentationConfig: """Generate the pipeline config for this task. This function will be called by RV, with arguments from the command line, when this example is run. Args: runner (Runner): Runner for the pipeline. raw_uri (str): Directory where the raw data resides processed_uri (str): Directory for storing processed data. E.g. crops for testing. root_uri (str): Directory where all the output will be written. nochip (bool, optional): If True, read directly from the TIFF during training instead of from pre-generated chips. The analyze and chip commands should not be run, if this is set to True. Defaults to True. test (bool, optional): If True, does the following simplifications: (1) Uses only the first 2 scenes (2) Uses only a 600x600 crop of the scenes (3) Enables test mode in the learner, which makes it use the test_batch_sz and test_num_epochs, among other things. Defaults to False. Returns: SemanticSegmentationConfig: A pipeline config. """ if not test: train_ids, val_ids = TRAIN_IDS, VAL_IDS else: train_ids, val_ids = TEST_MODE_TRAIN_IDS, TEST_MODE_VAL_IDS raw_uri = UriPath(raw_uri) processed_uri = UriPath(processed_uri) # ------------------------------- # Configure dataset generation # ------------------------------- class_config = ClassConfig(names=CLASS_NAMES, colors=CLASS_COLORS) _make_scene = partial(make_scene, raw_uri, processed_uri, class_config, test_mode=test) dataset_config = DatasetConfig( class_config=class_config, train_scenes=[_make_scene(scene_id) for scene_id in train_ids], validation_scenes=[_make_scene(scene_id) for scene_id in val_ids], img_channels=5) chip_options = SemanticSegmentationChipOptions( window_method=SemanticSegmentationWindowMethod.sliding, stride=CHIP_SIZE) if nochip: window_opts = GeoDataWindowConfig(method=GeoDataWindowMethod.sliding, size=CHIP_SIZE, stride=chip_options.stride) data = SemanticSegmentationGeoDataConfig( scene_dataset=dataset_config, window_opts=window_opts, img_sz=CHIP_SIZE, num_workers=4, channel_display_groups=CHANNEL_DISPLAY_GROUPS) else: data = SemanticSegmentationImageDataConfig( img_sz=CHIP_SIZE, num_workers=4, channel_display_groups=CHANNEL_DISPLAY_GROUPS) # -------------------------------------------- # Configure PyTorch backend and training # -------------------------------------------- model_config = SemanticSegmentationModelConfig(backbone=Backbone.resnet50) solver_config = SolverConfig(lr=LR, num_epochs=NUM_EPOCHS, batch_sz=BATCH_SIZE, test_num_epochs=TEST_MODE_NUM_EPOCHS, test_batch_sz=TEST_MODE_BATCH_SIZE, one_cycle=ONE_CYCLE) backend_config = PyTorchSemanticSegmentationConfig( data=data, model=model_config, solver=solver_config, log_tensorboard=LOG_TENSORBOARD, run_tensorboard=RUN_TENSORBOARD, test_mode=test) # ----------------------------------------------- # Pass configurations to the pipeline config # ----------------------------------------------- pipeline_config = SemanticSegmentationConfig( root_uri=root_uri, train_chip_sz=CHIP_SIZE, predict_chip_sz=CHIP_SIZE, chip_options=chip_options, dataset=dataset_config, backend=backend_config, channel_display_groups=CHANNEL_DISPLAY_GROUPS) return pipeline_config
def get_config(runner, root_uri, json, dataset, catalog_dir='/vsizip//workdir', imagery_dir='/opt/data', chip_sz=512, N=None): chip_sz = int(chip_sz) if dataset == 'cloud': class_config = ClassConfig( names=[ 'algal_bloom', 'normal_water', 'cloud', 'cloud_shadow', 'other' ], colors=['green', 'blue', 'white', 'gray', 'brown']) class_id_filter_dict = { 0: ['==', 'default', 'Algal bloom'], 1: ['==', 'default', 'Non-algal-bloomed water'], 2: ['==', 'default', 'Cloud'], 3: ['==', 'default', 'Cloud shadow'], 0xff: ['==', 'default', 'Other '], } elif dataset == 'tree': class_config = ClassConfig(names=['green_stage', 'red_stage', 'other'], colors=['green', 'brown', 'cyan']) class_id_filter_dict = { 0: ['==', 'default', "Green stage conifer"], 1: ['==', 'default', "Red stage conifer"], 0xff: ['==', 'default', "Other"], } else: raise Exception() train_crops = [] val_crops = [] for x in range(0, 5): for y in range(0, 5): x_start = x / 5.0 x_end = 0.80 - x_start y_start = y / 5.0 y_end = 0.80 - y_start crop = [x_start, y_start, x_end, y_end] if x == y: val_crops.append(crop) else: train_crops.append(crop) scenes = get_scenes(json, class_config, class_id_filter_dict, catalog_dir, imagery_dir, train_crops=train_crops, val_crops=val_crops, N=N) train_scenes, validation_scenes = scenes print(f'{len(train_scenes)} training scenes') print(f'{len(validation_scenes)} validation scenes') dataset = DatasetConfig( class_config=class_config, train_scenes=train_scenes, validation_scenes=validation_scenes, ) solver = SolverConfig() data = SemanticSegmentationImageDataConfig(img_sz=chip_sz, num_workers=0, preview_batch_limit=8) model = SemanticSegmentationModelConfig() backend = PyTorchSemanticSegmentationConfig(model=model, data=data, solver=solver) chip_options = SemanticSegmentationChipOptions( window_method=SemanticSegmentationWindowMethod.sliding, stride=chip_sz) return SemanticSegmentationConfig(root_uri=root_uri, dataset=dataset, backend=backend, train_chip_sz=chip_sz, predict_chip_sz=chip_sz, chip_options=chip_options, chip_nodata_threshold=.75, img_format='npy', label_format='png')