def mapper(dataset_dict): # Implement a mapper, similar to the default DatasetMapper, but with your own customizations dataset_dict = copy.deepcopy( dataset_dict) # it will be modified by code below image = utils.read_image(dataset_dict["file_name"], format="BGR") image, transforms = T.apply_transform_gens([ T.RandomFlip(prob=0.50, horizontal=True, vertical=False), T.RandomApply(tfm_or_aug=T.RandomBrightness(intensity_min=0.7, intensity_max=1.1), prob=0.40), T.RandomApply(tfm_or_aug=T.RandomSaturation(intensity_min=0.7, intensity_max=1.1), prob=0.40) ], image) dataset_dict["image"] = torch.as_tensor( image.transpose(2, 0, 1).astype("float32")) annos = [ utils.transform_instance_annotations(obj, transforms, image.shape[:2]) for obj in dataset_dict.pop("annotations") if obj.get("iscrowd", 0) == 0 ] instances = utils.annotations_to_instances(annos, image.shape[:2]) dataset_dict["instances"] = utils.filter_empty_instances(instances) return dataset_dict
def bulb_traffic_light_augmentation(cfg, is_train): if is_train: min_size = cfg.INPUT.MIN_SIZE_TRAIN max_size = cfg.INPUT.MAX_SIZE_TRAIN sample_style = cfg.INPUT.MIN_SIZE_TRAIN_SAMPLING else: min_size = cfg.INPUT.MIN_SIZE_TEST max_size = cfg.INPUT.MAX_SIZE_TEST sample_style = "choice" if sample_style == "range": assert len(min_size) == 2, "more than 2 ({}) min_size(s) are provided for ranges".format( len(min_size) ) logger = logging.getLogger(__name__) augmentation = [] augmentation.append(T.ResizeShortestEdge(min_size, max_size, sample_style)) if is_train: train_augmentation = [ # T.RandomFlip(), # T.RandomApply(T.RandomFlip(prob=0.5, horizontal=False, vertical=True), prob=0.3), # T.RandomApply(T.RandomRotation(angle=[-5, 5]), prob=0.15), T.RandomApply(T.RandomContrast(intensity_min=0.8, intensity_max=1.2), prob=0.15), T.RandomApply(T.RandomBrightness(intensity_min=0.8, intensity_max=1.2), prob=0.15), T.RandomApply(T.RandomSaturation(intensity_min=0.8, intensity_max=1.2), prob=0.15), T.RandomApply(T.RandomLighting(0.8), prob=0.15) ] augmentation.extend(train_augmentation) logger.info("Augmentations used in training: " + str(augmentation)) return augmentation
def test_random_apply_wrapping_std_transform_probability_occured_evaluation(self): transform_mock = mock.MagicMock(name="MockTransform", spec=T.Transform) image_mock = mock.MagicMock(name="MockImage") random_apply = T.RandomApply(transform_mock, prob=0.001) with mock.patch.object(random_apply, "_rand_range", return_value=0.0001): transform = random_apply.get_transform(image_mock) self.assertIs(transform, transform_mock)
def test_random_apply_prob_out_of_range_check(self): test_probabilities = {0.0: True, 0.5: True, 1.0: True, -0.01: False, 1.01: False} for given_probability, is_valid in test_probabilities.items(): if not is_valid: self.assertRaises(AssertionError, T.RandomApply, None, prob=given_probability) else: T.RandomApply(T.NoOpTransform(), prob=given_probability)
def test_random_apply_probability_not_occured_evaluation(self): transform_mock = mock.MagicMock(name="MockTransform", spec=T.Augmentation) image_mock = mock.MagicMock(name="MockImage") random_apply = T.RandomApply(transform_mock, prob=0.001) with mock.patch.object(random_apply, "_rand_range", return_value=0.9): transform = random_apply.get_transform(image_mock) transform_mock.get_transform.assert_not_called() self.assertIsInstance(transform, T.NoOpTransform)
def test_random_apply_wrapping_aug_probability_occured_evaluation(self): transform_mock = mock.MagicMock(name="MockTransform", spec=T.Augmentation) image_mock = mock.MagicMock(name="MockImage") random_apply = T.RandomApply(transform_mock, prob=0.001) with mock.patch.object(random_apply, "_rand_range", return_value=0.0001): transform = random_apply.get_transform(image_mock) transform_mock.get_transform.assert_called_once_with(image_mock) self.assertIsNot(transform, transform_mock)
def build_train_loader(cls, cfg): dataloader = build_detection_train_loader( cfg, mapper=DatasetMapper( cfg, is_train=True, augmentations=[ T.RandomApply(tfm_or_aug=T.RandomBrightness(0.8, 1.2), prob=0.2), T.RandomApply(tfm_or_aug=T.RandomContrast(0.8, 1.2), prob=0.1), T.RandomFlip(prob=0.25, horizontal=True, vertical=False), T.RandomRotation(angle=[0, 90, 180, 270], expand=True, center=None, sample_style='choice', interp=None) ])) return dataloader
def build_train_aug(cfg): augs = [ T.ResizeShortestEdge(cfg.INPUT.MIN_SIZE_TRAIN, cfg.INPUT.MAX_SIZE_TRAIN, cfg.INPUT.MIN_SIZE_TRAIN_SAMPLING), T.RandomContrast(0.5, 1.5), T.RandomBrightness(0.5, 1.5), T.RandomSaturation(0.5, 1.5), T.RandomFlip(), T.RandomApply(T.RandomExtent([1.0, 2.0], [0.2, 0.2])), ] if cfg.INPUT.CROP.ENABLED: augs.insert(0, T.RandomCrop(cfg.INPUT.CROP.TYPE, cfg.INPUT.CROP.SIZE)) return augs
def build_aug_transforms( cfg: detectron2.config.CfgNode, flip_horiz: bool = True, flip_vert: bool = False, max_rotate: int = 10, brightness_limits: Tuple[int, int] = (0.8, 1.4), contrast_limits: Tuple[int, int] = (0.8, 1.4), saturation_limits: Tuple[int, int] = (0.8, 1.4), p_lighting: float = 0.75 ) -> detectron2.data.transforms.AugmentationList: "Build a list of detectron2 augmentations" augs = [] augs.append( T.ResizeShortestEdge(cfg.INPUT.MIN_SIZE_TRAIN, cfg.INPUT.MAX_SIZE_TRAIN, cfg.INPUT.MIN_SIZE_TRAIN_SAMPLING)) if flip_horiz: augs.append(T.RandomFlip(prob=0.5, horizontal=True, vertical=False)) if flip_vert: augs.append(T.RandomFlip(prob=0.5, horizontal=False, vertical=True)) if max_rotate: augs.append( T.RandomRotation(angle=[-max_rotate, max_rotate], expand=False)) if brightness_limits: augs.append( T.RandomApply(prob=p_lighting, tfm_or_aug=T.RandomBrightness(*brightness_limits))) if contrast_limits: augs.append( T.RandomApply(prob=p_lighting, tfm_or_aug=T.RandomContrast(*contrast_limits))) if saturation_limits: augs.append( T.RandomApply(prob=p_lighting, tfm_or_aug=T.RandomSaturation(*saturation_limits))) return augs
def build_augmentations(cfg): # augs = [ # T.ResizeShortestEdge(cfg.INPUT.MIN_SIZE_TRAIN, cfg.INPUT.MAX_SIZE_TRAIN, cfg.INPUT.MIN_SIZE_TRAIN_SAMPLING), # T.RandomBrightness(0.7, 0.9), # T.RandomFlip(prob=0.5), # T.RandomApply(T.RandomRotation(angle=[-25, 25]), prob=0.5), # T.RandomApply(prob=0.2, tfm_or_aug=T.RandomLighting(scale=0.5)) # ] augs = [ T.RandomFlip(prob=0.5), T.RandomApply(T.RandomRotation(angle=[-25, 25]), prob=0.9) ] if cfg.INPUT.CROP.ENABLED: #instead of appending, putting cropping in front augs = [ T.RandomCrop_CategoryAreaConstraint(cfg.INPUT.CROP.TYPE, cfg.INPUT.CROP.SIZE) ] + augs return augs
from detectron2.data import MetadataCatalog from detectron2.data import DatasetCatalog from detectron2 import model_zoo from detectron2.engine import DefaultTrainer from detectron2.engine import DefaultPredictor from detectron2.evaluation import COCOEvaluator from detectron2.config import get_cfg from detectron2.data import build_detection_train_loader, build_detection_test_loader, DatasetMapper, detection_utils from detectron2.data.samplers import GroupedBatchSampler, TrainingSampler, InferenceSampler, RepeatFactorTrainingSampler import detectron2.data.transforms as T augmentations = [ T.RandomFlip(prob=0.25, horizontal=True, vertical=False), T.RandomFlip(prob=0.25, horizontal=False, vertical=True), T.RandomApply(tfm_or_aug=T.RandomBrightness(intensity_min=0.75, intensity_max=1.25), prob=0.25), T.RandomApply(tfm_or_aug=T.RandomContrast(intensity_min=0.75, intensity_max=1.25), prob=0.25), T.RandomApply(tfm_or_aug=T.RandomCrop(crop_type="relative_range", crop_size=(0.75, 0.75)), prob=0.25), T.RandomApply(tfm_or_aug=T.RandomSaturation(intensity_min=0.75, intensity_max=1.25), prob=0.25), T.RandomApply(tfm_or_aug=T.RandomRotation(angle=[-30,30], expand=True, center=None, sample_style="range", interp=None), prob=0.25) ] def mapper(dataset_dict): # Implement a mapper, similar to the default DatasetMapper, but with your own customizations dataset_dict = copy.deepcopy(dataset_dict) # it will be modified by code below image = detection_utils.read_image(dataset_dict["file_name"], format="BGR")
def do_train(cfg, model, resume=False): model.train() optimizer = build_optimizer(cfg, model) scheduler = build_lr_scheduler(cfg, optimizer) checkpointer = DetectionCheckpointer( model, cfg.OUTPUT_DIR, optimizer=optimizer, scheduler=scheduler ) start_iter = ( checkpointer.resume_or_load(cfg.MODEL.WEIGHTS, resume=resume).get("iteration", -1) + 1 ) max_iter = cfg.SOLVER.MAX_ITER writers = ( [ CommonMetricPrinter(max_iter), JSONWriter(os.path.join(cfg.OUTPUT_DIR, "metrics.json")), TensorboardXWriter(cfg.OUTPUT_DIR), ] if comm.is_main_process() else [] ) min_size = cfg.INPUT.MIN_SIZE_TRAIN max_size = cfg.INPUT.MAX_SIZE_TRAIN, sample_style = cfg.INPUT.MIN_SIZE_TRAIN_SAMPLING data_loader = build_detection_train_loader(cfg, mapper=DatasetMapper(cfg, is_train=True, augmentations=[ T.ResizeShortestEdge(min_size, max_size, sample_style), T.RandomApply(T.RandomFlip(prob = 1, vertical = False), prob = 0.5), T.RandomApply(T.RandomRotation(angle = [180], sample_style = 'choice'), prob = 0.1), T.RandomApply(T.RandomRotation(angle = [-10,10], sample_style = 'range'), prob = 0.9), T.RandomApply(T.RandomBrightness(0.5,1.5), prob = 0.5), T.RandomApply(T.RandomContrast(0.5,1.5), prob = 0.5) ])) best_model_weight = copy.deepcopy(model.state_dict()) best_val_loss = None data_val_loader = build_detection_test_loader(cfg, cfg.DATASETS.TEST[0], mapper = DatasetMapper(cfg, True)) logger.info("Starting training from iteration {}".format(start_iter)) with EventStorage(start_iter) as storage: for data, iteration in zip(data_loader, range(start_iter, max_iter)): iteration += 1 start = time.time() storage.step() loss_dict = model(data) losses = sum(loss_dict.values()) assert torch.isfinite(losses).all(), loss_dict loss_dict_reduced = {k: v.item() for k, v in comm.reduce_dict(loss_dict).items()} losses_reduced = sum(loss for loss in loss_dict_reduced.values()) if comm.is_main_process(): storage.put_scalars(total_loss=losses_reduced, **loss_dict_reduced) optimizer.zero_grad() losses.backward() optimizer.step() storage.put_scalar("lr", optimizer.param_groups[0]["lr"], smoothing_hint=False) scheduler.step() if ( cfg.TEST.EVAL_PERIOD > 0 and iteration % cfg.TEST.EVAL_PERIOD == 0 and iteration != max_iter ): logger.setLevel(logging.CRITICAL) print('validating') val_total_loss = do_val_monitor(cfg, model, data_val_loader) logger.setLevel(logging.DEBUG) logger.info(f"validation loss of iteration {iteration}th: {val_total_loss}") storage.put_scalar(name = 'val_total_loss', value = val_total_loss) if best_val_loss is None or val_total_loss < best_val_loss: best_val_loss = val_total_loss best_model_weight = copy.deepcopy(model.state_dict()) comm.synchronize() # สร้าง checkpointer เพิ่มให้ save best model โดยดูจาก val loss if iteration - start_iter > 5 and (iteration % 20 == 0 or iteration == max_iter): for writer in writers: writer.write() model.load_state_dict(best_model_weight) experiment_name = os.getenv('MLFLOW_EXPERIMENT_NAME') checkpointer.save(f'model_{experiment_name}') return model