def custom_mapper(dataset_dict): # it will be modified by code below dataset_dict = copy.deepcopy(dataset_dict) image = utils.read_image(dataset_dict["file_name"], format="BGR") transform_list = [ T.Resize((512, 512)), T.RandomBrightness(0.8, 1.8), T.RandomContrast(0.6, 1.3), T.RandomSaturation(0.8, 1.4), T.RandomRotation(angle=[30, 30]), T.RandomLighting(0.7), T.RandomFlip(prob=0.4, horizontal=False, vertical=True), ] image, transforms = T.apply_transform_gens(transform_list, 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 __init__(self, cfg, is_train=True): super().__init__(cfg, is_train) # Rebuild augmentations logger.info( "Rebuilding the augmentations. The previous augmentations will be overridden." ) self.augmentation = build_augmentation(cfg, is_train) self.cfg = cfg if cfg.INPUT.CROP.ENABLED and is_train: self.augmentation.insert( 0, RandomCropWithInstance( cfg.INPUT.CROP.TYPE, cfg.INPUT.CROP.SIZE, cfg.INPUT.CROP.CROP_INSTANCE, ), ) logging.getLogger(__name__).info("Cropping used in training: " + str(self.augmentation[0])) if cfg.INPUT.IS_ROTATE: self.augmentation.insert( 1, T.RandomRotation(angle=[-30, 30], sample_style="range")) logging.getLogger(__name__).info( "Rotation used in training: " + str(self.augmentation[1])) self.basis_loss_on = cfg.MODEL.BASIS_MODULE.LOSS_ON self.ann_set = cfg.MODEL.BASIS_MODULE.ANN_SET self.boxinst_enabled = cfg.MODEL.BOXINST.ENABLED if self.boxinst_enabled: self.use_instance_mask = False self.recompute_boxes = False
def __init__(self, cfg, is_train=True): assert cfg.MODEL.MASK_ON, '今回はセグメンテーションのみを対象にする' assert not cfg.MODEL.KEYPOINT_ON, 'キーポイントは扱わない' assert not cfg.MODEL.LOAD_PROPOSALS, 'pre-computed proposals っていうのがよくわからん・・・・とりあえず無効前提で' self.cont_gen = None self.bright_gen = None self.sat_gen = None self.cutout_gen = None self.extent_gen = None self.crop_gen = None self.rotate_gen = None self.shear_gen = None if is_train: if cfg.INPUT.CONTRAST.ENABLED: self.cont_gen = T.RandomContrast(cfg.INPUT.CONTRAST.RANGE[0], cfg.INPUT.CONTRAST.RANGE[1]) logging.getLogger(__name__).info('ContGen used in training.') if cfg.INPUT.BRIGHTNESS.ENABLED: self.bright_gen = T.RandomBrightness( cfg.INPUT.BRIGHTNESS.RANGE[0], cfg.INPUT.BRIGHTNESS.RANGE[1]) logging.getLogger(__name__).info('BrightGen used in training.') if cfg.INPUT.SATURATION.ENABLED: self.sat_gen = T.RandomSaturation( cfg.INPUT.SATURATION.RANGE[0], cfg.INPUT.SATURATION.RANGE[1]) logging.getLogger(__name__).info('SatGen used in training.') if cfg.INPUT.CUTOUT.ENABLED: self.cutout_gen = RandomCutout(cfg.INPUT.CUTOUT.NUM_HOLE_RANGE, cfg.INPUT.CUTOUT.RADIUS_RANGE, cfg.INPUT.CUTOUT.COLOR_RANGE) logging.getLogger(__name__).info('CutoutGen used in training.') if cfg.INPUT.EXTENT.ENABLED: self.extent_gen = T.RandomExtent( scale_range=(1, 1), shift_range=cfg.INPUT.EXTENT.SHIFT_RANGE) logging.getLogger(__name__).info('ExtentGen used in training.') if cfg.INPUT.CROP.ENABLED: self.crop_gen = T.RandomCrop(cfg.INPUT.CROP.TYPE, cfg.INPUT.CROP.SIZE) logging.getLogger(__name__).info('CropGen used in training: ' + str(self.crop_gen)) if cfg.INPUT.ROTATE.ENABLED: self.rotate_gen = T.RandomRotation(cfg.INPUT.ROTATE.ANGLE, expand=False) logging.getLogger(__name__).info('RotateGen used in training.') if cfg.INPUT.SHEAR.ENABLED: self.shear_gen = RandomShear(cfg.INPUT.SHEAR.ANGLE_H_RANGE, cfg.INPUT.SHEAR.ANGLE_V_RANGE) logging.getLogger(__name__).info('ShearGen used in training.') self.tfm_gens = utils.build_transform_gen(cfg, is_train) self.img_format = cfg.INPUT.FORMAT self.mask_format = cfg.INPUT.MASK_FORMAT self.is_train = is_train
def __init__(self, cfg, json_file_path, is_train=True): super().__init__(cfg, is_train=is_train) self.aug_handler = AugHandler.load_from_path(json_file_path) if is_train: self.tfm_gens = self.tfm_gens[:-1] #self.tfm_gens.insert(0, T.RandomFlip(prob=0.5, horizontal=True, vertical=False)) self.tfm_gens.insert(0, T.RandomCrop("relative_range", (0.8, 1.0))) self.tfm_gens.insert( 0, T.RandomRotation([0, 90, 180, 270], sample_style="choice"))
def build_augmentation(cfg, is_train): logger = logging.getLogger(__name__) result = utils.build_augmentation(cfg, is_train) if is_train: random_rotation = T.RandomRotation( cfg.INPUT.ROTATION_ANGLES, expand=False, sample_style="choice" ) result.append(random_rotation) logger.info("DensePose-specific augmentation used in training: " + str(random_rotation)) return result
def build_train_loader(cls, cfg): return build_detection_train_loader( cfg, mapper=DatasetMapper(cfg, is_train=True, augmentations=[ T.RandomCrop("absolute_range", (300, 600)), T.RandomRotation(random.randrange(0, 360)), T.RandomContrast(0.5, 1.5), T.RandomSaturation(0.5, 1.5) ]))
def build_augmentation(cfg, is_train): logger = logging.getLogger(__name__) result = utils.build_augmentation(cfg, is_train) if is_train: random_rotation = T.RandomRotation(cfg.INPUT.ROTATION_ANGLES, expand=False, sample_style="choice") # if cfg.MODEL.CONDINST.RAND_FLIP: # random_hflip = T.HFlipTransform(width=0) # result.append(random_hflip) logger.info("DensePose-specific augmentation used in training: " + str(random_rotation)) return result
def build_Pt_collect_train_aug(cfg): augs = [ T.ResizeShortestEdge(cfg.INPUT.MIN_SIZE_TRAIN, cfg.INPUT.MAX_SIZE_TRAIN, cfg.INPUT.MIN_SIZE_TRAIN_SAMPLING) ] if cfg.INPUT.CROP.ENABLED: augs.append(T.RandomCrop( cfg.INPUT.CROP.TYPE, cfg.INPUT.CROP.SIZE, )) augs.append(T.RandomRotation(angle=[-10, 10], )) augs.append(T.RandomFlip()) return augs
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_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
def __init__(self, cfg, is_train=True): if cfg.INPUT.CROP.ENABLED and is_train: self.crop_gen = T.RandomCrop(cfg.INPUT.CROP.TYPE, cfg.INPUT.CROP.SIZE) # logging.getLogger(__name__).info("CropGen used in training: " + str(self.crop_gen)) else: self.crop_gen = None self.tfm_gens = [ T.RandomBrightness(0.5, 1.6), T.RandomContrast(0.5, 1), T.RandomSaturation(0.5, 1), T.RandomRotation(angle=[-90, 90]), T.RandomFlip(horizontal=True, vertical=False), T.RandomCrop('relative_range', (0.4, 0.6)), T.Resize((640,640)), # CutOut() ] # self.tfm_gens = utils.build_transform_gen(cfg, is_train) # fmt: off self.img_format = cfg.INPUT.FORMAT self.mask_on = cfg.MODEL.MASK_ON self.mask_format = cfg.INPUT.MASK_FORMAT self.keypoint_on = cfg.MODEL.KEYPOINT_ON self.load_proposals = cfg.MODEL.LOAD_PROPOSALS # fmt: on if self.keypoint_on and is_train: # Flip only makes sense in training self.keypoint_hflip_indices = utils.create_keypoint_hflip_indices(cfg.DATASETS.TRAIN) else: self.keypoint_hflip_indices = None if self.load_proposals: self.min_box_side_len = cfg.MODEL.PROPOSAL_GENERATOR.MIN_SIZE self.proposal_topk = ( cfg.DATASETS.PRECOMPUTED_PROPOSAL_TOPK_TRAIN if is_train else cfg.DATASETS.PRECOMPUTED_PROPOSAL_TOPK_TEST ) self.is_train = is_train
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
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") image, transforms = T.apply_transform_gens(augmentations, image) dataset_dict["image"] = torch.as_tensor(image.transpose(2, 0, 1).astype("float32")) annos = [ detection_utils.transform_instance_annotations(obj, transforms, image.shape[:2]) for obj in dataset_dict.pop("annotations")
def build_train_loader(cls, cfg): mapper = DatasetMapper(cfg, is_train=True, augmentations=augmentations) return build_detection_train_loader(cfg,mapper=mapper) def build_hooks(self): res = super().build_hooks() hook = hooks.StopByProgressHook(patience=10*self.period_between_evals,delta_improvement=0.5,score_storage_key='segm/AP',save_name_base="best_model") #hook = hooks.StopByProgressHook(patience=2*self.period_between_evals,delta_improvement=0,score_storage_key='segm/AP',save_name_base="best_model") res.append(hook) return res augmentations = [ T.RandomFlip(prob=0.5, horizontal=True, vertical=False), T.RandomFlip(prob=0.5, horizontal=False, vertical=True), T.RandomRotation(angle = [-10,10], expand=True, center=None, sample_style='range'), T.RandomBrightness(0.9,1.1) ] def experiment(): result_df = pd.DataFrame(columns=['w20', 'size', 'AP', 'iter']) result_df.astype({'w20': 'bool', 'size': 'int32', 'AP': 'float32'}) date = datetime.date.today() time = datetime.datetime.now() try: for trial_id in range(10**6): sample_batch = generate_train_sets(True) sample_batch.extend(generate_train_sets(False))
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