1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173 |
- import collections
- import copy
- import os
- import os.path as osp
- import numpy as np
- import paddle
- from paddle.static import InputSpec
- import paddlers
- import paddlers.models.ppdet as ppdet
- from paddlers.models.ppdet.modeling.proposal_generator.target_layer import BBoxAssigner, MaskAssigner
- from paddlers.transforms import decode_image
- from paddlers.transforms.operators import _NormalizeBox, _PadBox, _BboxXYXY2XYWH, Resize, Pad
- from paddlers.transforms.batch_operators import BatchCompose, BatchRandomResize, BatchRandomResizeByShort, \
- _BatchPad, _Gt2YoloTarget
- from paddlers.models.ppdet.optimizer import ModelEMA
- import paddlers.utils.logging as logging
- from paddlers.utils.checkpoint import det_pretrain_weights_dict
- from .base import BaseModel
- from .utils.det_metrics import VOCMetric, COCOMetric
- __all__ = [
- "YOLOv3", "FasterRCNN", "PPYOLO", "PPYOLOTiny", "PPYOLOv2", "MaskRCNN"
- ]
- class BaseDetector(BaseModel):
- def __init__(self, model_name, num_classes=80, **params):
- self.init_params.update(locals())
- if 'with_net' in self.init_params:
- del self.init_params['with_net']
- super(BaseDetector, self).__init__('detector')
- if not hasattr(ppdet.modeling, model_name):
- raise ValueError("ERROR: There is no model named {}.".format(
- model_name))
- self.model_name = model_name
- self.num_classes = num_classes
- self.labels = None
- if params.get('with_net', True):
- params.pop('with_net', None)
- self.net = self.build_net(**params)
- def build_net(self, **params):
- with paddle.utils.unique_name.guard():
- net = ppdet.modeling.__dict__[self.model_name](**params)
- return net
- def _build_inference_net(self):
- infer_net = self.net
- infer_net.eval()
- return infer_net
- def _fix_transforms_shape(self, image_shape):
- raise NotImplementedError("_fix_transforms_shape: not implemented!")
- def _define_input_spec(self, image_shape):
- input_spec = [{
- "image": InputSpec(
- shape=image_shape, name='image', dtype='float32'),
- "im_shape": InputSpec(
- shape=[image_shape[0], 2], name='im_shape', dtype='float32'),
- "scale_factor": InputSpec(
- shape=[image_shape[0], 2], name='scale_factor', dtype='float32')
- }]
- return input_spec
- def _check_image_shape(self, image_shape):
- if len(image_shape) == 2:
- image_shape = [1, 3] + image_shape
- if image_shape[-2] % 32 > 0 or image_shape[-1] % 32 > 0:
- raise ValueError(
- "Height and width in fixed_input_shape must be a multiple of 32, but received {}.".
- format(image_shape[-2:]))
- return image_shape
- def _get_test_inputs(self, image_shape):
- if image_shape is not None:
- image_shape = self._check_image_shape(image_shape)
- self._fix_transforms_shape(image_shape[-2:])
- else:
- image_shape = [None, 3, -1, -1]
- self.fixed_input_shape = image_shape
- return self._define_input_spec(image_shape)
- def _get_backbone(self, backbone_name, **params):
- backbone = getattr(ppdet.modeling, backbone_name)(**params)
- return backbone
- def run(self, net, inputs, mode):
- net_out = net(inputs)
- if mode in ['train', 'eval']:
- outputs = net_out
- else:
- outputs = dict()
- for key in net_out:
- outputs[key] = net_out[key].numpy()
- return outputs
- def default_optimizer(self,
- parameters,
- learning_rate,
- warmup_steps,
- warmup_start_lr,
- lr_decay_epochs,
- lr_decay_gamma,
- num_steps_each_epoch,
- reg_coeff=1e-04,
- scheduler='Piecewise',
- num_epochs=None):
- if scheduler.lower() == 'piecewise':
- if warmup_steps > 0 and warmup_steps > lr_decay_epochs[
- 0] * num_steps_each_epoch:
- logging.error(
- "In function train(), parameters must satisfy: "
- "warmup_steps <= lr_decay_epochs[0] * num_samples_in_train_dataset. "
- "See this doc for more information: "
- "https://github.com/PaddlePaddle/PaddleRS/blob/develop/docs/parameters.md",
- exit=False)
- logging.error(
- "Either `warmup_steps` be less than {} or lr_decay_epochs[0] be greater than {} "
- "must be satisfied, please modify 'warmup_steps' or 'lr_decay_epochs' in train function".
- format(lr_decay_epochs[0] * num_steps_each_epoch,
- warmup_steps // num_steps_each_epoch),
- exit=True)
- boundaries = [b * num_steps_each_epoch for b in lr_decay_epochs]
- values = [(lr_decay_gamma**i) * learning_rate
- for i in range(len(lr_decay_epochs) + 1)]
- scheduler = paddle.optimizer.lr.PiecewiseDecay(boundaries, values)
- elif scheduler.lower() == 'cosine':
- if num_epochs is None:
- logging.error(
- "`num_epochs` must be set while using cosine annealing decay scheduler, but received {}".
- format(num_epochs),
- exit=False)
- if warmup_steps > 0 and warmup_steps > num_epochs * num_steps_each_epoch:
- logging.error(
- "In function train(), parameters must satisfy: "
- "warmup_steps <= num_epochs * num_samples_in_train_dataset. "
- "See this doc for more information: "
- "https://github.com/PaddlePaddle/PaddleRS/blob/develop/docs/parameters.md",
- exit=False)
- logging.error(
- "`warmup_steps` must be less than the total number of steps({}), "
- "please modify 'num_epochs' or 'warmup_steps' in train function".
- format(num_epochs * num_steps_each_epoch),
- exit=True)
- T_max = num_epochs * num_steps_each_epoch - warmup_steps
- scheduler = paddle.optimizer.lr.CosineAnnealingDecay(
- learning_rate=learning_rate,
- T_max=T_max,
- eta_min=0.0,
- last_epoch=-1)
- else:
- logging.error(
- "Invalid learning rate scheduler: {}!".format(scheduler),
- exit=True)
- if warmup_steps > 0:
- scheduler = paddle.optimizer.lr.LinearWarmup(
- learning_rate=scheduler,
- warmup_steps=warmup_steps,
- start_lr=warmup_start_lr,
- end_lr=learning_rate)
- optimizer = paddle.optimizer.Momentum(
- scheduler,
- momentum=.9,
- weight_decay=paddle.regularizer.L2Decay(coeff=reg_coeff),
- parameters=parameters)
- return optimizer
- def train(self,
- num_epochs,
- train_dataset,
- train_batch_size=64,
- eval_dataset=None,
- optimizer=None,
- save_interval_epochs=1,
- log_interval_steps=10,
- save_dir='output',
- pretrain_weights='IMAGENET',
- learning_rate=.001,
- warmup_steps=0,
- warmup_start_lr=0.0,
- lr_decay_epochs=(216, 243),
- lr_decay_gamma=0.1,
- metric=None,
- use_ema=False,
- early_stop=False,
- early_stop_patience=5,
- use_vdl=True,
- resume_checkpoint=None):
- """
- Train the model.
- Args:
- num_epochs (int): Number of epochs.
- train_dataset (paddlers.datasets.COCODetDataset|paddlers.datasets.VOCDetDataset):
- Training dataset.
- train_batch_size (int, optional): Total batch size among all cards used in
- training. Defaults to 64.
- eval_dataset (paddlers.datasets.COCODetDataset|paddlers.datasets.VOCDetDataset|None, optional):
- Evaluation dataset. If None, the model will not be evaluated during training
- process. Defaults to None.
- optimizer (paddle.optimizer.Optimizer|None, optional): Optimizer used for
- training. If None, a default optimizer will be used. Defaults to None.
- save_interval_epochs (int, optional): Epoch interval for saving the model.
- Defaults to 1.
- log_interval_steps (int, optional): Step interval for printing training
- information. Defaults to 10.
- save_dir (str, optional): Directory to save the model. Defaults to 'output'.
- pretrain_weights (str|None, optional): None or name/path of pretrained
- weights. If None, no pretrained weights will be loaded.
- Defaults to 'IMAGENET'.
- learning_rate (float, optional): Learning rate for training. Defaults to .001.
- warmup_steps (int, optional): Number of steps of warm-up training.
- Defaults to 0.
- warmup_start_lr (float, optional): Start learning rate of warm-up training.
- Defaults to 0..
- lr_decay_epochs (list|tuple, optional): Epoch milestones for learning
- rate decay. Defaults to (216, 243).
- lr_decay_gamma (float, optional): Gamma coefficient of learning rate decay.
- Defaults to .1.
- metric (str|None, optional): Evaluation metric. Choices are {'VOC', 'COCO', None}.
- If None, determine the metric according to the dataset format.
- Defaults to None.
- use_ema (bool, optional): Whether to use exponential moving average
- strategy. Defaults to False.
- early_stop (bool, optional): Whether to adopt early stop strategy.
- Defaults to False.
- early_stop_patience (int, optional): Early stop patience. Defaults to 5.
- use_vdl(bool, optional): Whether to use VisualDL to monitor the training
- process. Defaults to True.
- resume_checkpoint (str|None, optional): Path of the checkpoint to resume
- training from. If None, no training checkpoint will be resumed. At most
- Aone of `resume_checkpoint` and `pretrain_weights` can be set simultaneously.
- Defaults to None.
- """
- args = self._pre_train(locals())
- args.pop('self')
- return self._real_train(**args)
- def _pre_train(self, in_args):
- return in_args
- def _real_train(
- self, num_epochs, train_dataset, train_batch_size, eval_dataset,
- optimizer, save_interval_epochs, log_interval_steps, save_dir,
- pretrain_weights, learning_rate, warmup_steps, warmup_start_lr,
- lr_decay_epochs, lr_decay_gamma, metric, use_ema, early_stop,
- early_stop_patience, use_vdl, resume_checkpoint):
- if self.status == 'Infer':
- logging.error(
- "Exported inference model does not support training.",
- exit=True)
- if pretrain_weights is not None and resume_checkpoint is not None:
- logging.error(
- "`pretrain_weights` and `resume_checkpoint` cannot be set simultaneously.",
- exit=True)
- if train_dataset.__class__.__name__ == 'VOCDetDataset':
- train_dataset.data_fields = {
- 'im_id', 'image_shape', 'image', 'gt_bbox', 'gt_class',
- 'difficult'
- }
- elif train_dataset.__class__.__name__ == 'CocoDetection':
- if self.__class__.__name__ == 'MaskRCNN':
- train_dataset.data_fields = {
- 'im_id', 'image_shape', 'image', 'gt_bbox', 'gt_class',
- 'gt_poly', 'is_crowd'
- }
- else:
- train_dataset.data_fields = {
- 'im_id', 'image_shape', 'image', 'gt_bbox', 'gt_class',
- 'is_crowd'
- }
- if metric is None:
- if eval_dataset.__class__.__name__ == 'VOCDetDataset':
- self.metric = 'voc'
- elif eval_dataset.__class__.__name__ == 'COCODetDataset':
- self.metric = 'coco'
- else:
- assert metric.lower() in ['coco', 'voc'], \
- "Evaluation metric {} is not supported. Please choose from 'COCO' and 'VOC'."
- self.metric = metric.lower()
- self.labels = train_dataset.labels
- self.num_max_boxes = train_dataset.num_max_boxes
- train_dataset.batch_transforms = self._compose_batch_transform(
- train_dataset.transforms, mode='train')
-
- if optimizer is None:
- num_steps_each_epoch = len(train_dataset) // train_batch_size
- self.optimizer = self.default_optimizer(
- parameters=self.net.parameters(),
- learning_rate=learning_rate,
- warmup_steps=warmup_steps,
- warmup_start_lr=warmup_start_lr,
- lr_decay_epochs=lr_decay_epochs,
- lr_decay_gamma=lr_decay_gamma,
- num_steps_each_epoch=num_steps_each_epoch)
- else:
- self.optimizer = optimizer
-
- if pretrain_weights is not None:
- if not osp.exists(pretrain_weights):
- key = '_'.join([self.model_name, self.backbone_name])
- if key not in det_pretrain_weights_dict:
- logging.warning(
- "Path of pretrained weights ('{}') does not exist!".
- format(pretrain_weights))
- pretrain_weights = None
- elif pretrain_weights not in det_pretrain_weights_dict[key]:
- logging.warning(
- "Path of pretrained weights ('{}') does not exist!".
- format(pretrain_weights))
- pretrain_weights = det_pretrain_weights_dict[key][0]
- logging.warning(
- "`pretrain_weights` is forcibly set to '{}'. "
- "If you don't want to use pretrained weights, "
- "please set `pretrain_weights` to None.".format(
- pretrain_weights))
- else:
- if osp.splitext(pretrain_weights)[-1] != '.pdparams':
- logging.error(
- "Invalid pretrained weights. Please specify a .pdparams file.",
- exit=True)
- pretrained_dir = osp.join(save_dir, 'pretrain')
- self.initialize_net(
- pretrain_weights=pretrain_weights,
- save_dir=pretrained_dir,
- resume_checkpoint=resume_checkpoint,
- is_backbone_weights=(pretrain_weights == 'IMAGENET' and
- 'ESNet_' in self.backbone_name))
- if use_ema:
- ema = ModelEMA(model=self.net, decay=.9998, use_thres_step=True)
- else:
- ema = None
-
- self.train_loop(
- num_epochs=num_epochs,
- train_dataset=train_dataset,
- train_batch_size=train_batch_size,
- eval_dataset=eval_dataset,
- save_interval_epochs=save_interval_epochs,
- log_interval_steps=log_interval_steps,
- save_dir=save_dir,
- ema=ema,
- early_stop=early_stop,
- early_stop_patience=early_stop_patience,
- use_vdl=use_vdl)
- def quant_aware_train(self,
- num_epochs,
- train_dataset,
- train_batch_size=64,
- eval_dataset=None,
- optimizer=None,
- save_interval_epochs=1,
- log_interval_steps=10,
- save_dir='output',
- learning_rate=.00001,
- warmup_steps=0,
- warmup_start_lr=0.0,
- lr_decay_epochs=(216, 243),
- lr_decay_gamma=0.1,
- metric=None,
- use_ema=False,
- early_stop=False,
- early_stop_patience=5,
- use_vdl=True,
- resume_checkpoint=None,
- quant_config=None):
- """
- Quantization-aware training.
- Args:
- num_epochs (int): Number of epochs.
- train_dataset (paddlers.datasets.COCODetDataset|paddlers.datasets.VOCDetDataset):
- Training dataset.
- train_batch_size (int, optional): Total batch size among all cards used in
- training. Defaults to 64.
- eval_dataset (paddlers.datasets.COCODetDataset|paddlers.datasets.VOCDetDataset|None, optional):
- Evaluation dataset. If None, the model will not be evaluated during training
- process. Defaults to None.
- optimizer (paddle.optimizer.Optimizer or None, optional): Optimizer used for
- training. If None, a default optimizer will be used. Defaults to None.
- save_interval_epochs (int, optional): Epoch interval for saving the model.
- Defaults to 1.
- log_interval_steps (int, optional): Step interval for printing training
- information. Defaults to 10.
- save_dir (str, optional): Directory to save the model. Defaults to 'output'.
- learning_rate (float, optional): Learning rate for training.
- Defaults to .00001.
- warmup_steps (int, optional): Number of steps of warm-up training.
- Defaults to 0.
- warmup_start_lr (float, optional): Start learning rate of warm-up training.
- Defaults to 0..
- lr_decay_epochs (list or tuple, optional): Epoch milestones for learning rate
- decay. Defaults to (216, 243).
- lr_decay_gamma (float, optional): Gamma coefficient of learning rate decay.
- Defaults to .1.
- metric (str|None, optional): Evaluation metric. Choices are {'VOC', 'COCO', None}.
- If None, determine the metric according to the dataset format.
- Defaults to None.
- use_ema (bool, optional): Whether to use exponential moving average strategy.
- Defaults to False.
- early_stop (bool, optional): Whether to adopt early stop strategy.
- Defaults to False.
- early_stop_patience (int, optional): Early stop patience. Defaults to 5.
- use_vdl (bool, optional): Whether to use VisualDL to monitor the training
- process. Defaults to True.
- quant_config (dict or None, optional): Quantization configuration. If None,
- a default rule of thumb configuration will be used. Defaults to None.
- resume_checkpoint (str|None, optional): Path of the checkpoint to resume
- quantization-aware training from. If None, no training checkpoint will
- be resumed. Defaults to None.
- """
- self._prepare_qat(quant_config)
- self.train(
- num_epochs=num_epochs,
- train_dataset=train_dataset,
- train_batch_size=train_batch_size,
- eval_dataset=eval_dataset,
- optimizer=optimizer,
- save_interval_epochs=save_interval_epochs,
- log_interval_steps=log_interval_steps,
- save_dir=save_dir,
- pretrain_weights=None,
- learning_rate=learning_rate,
- warmup_steps=warmup_steps,
- warmup_start_lr=warmup_start_lr,
- lr_decay_epochs=lr_decay_epochs,
- lr_decay_gamma=lr_decay_gamma,
- metric=metric,
- use_ema=use_ema,
- early_stop=early_stop,
- early_stop_patience=early_stop_patience,
- use_vdl=use_vdl,
- resume_checkpoint=resume_checkpoint)
- def evaluate(self,
- eval_dataset,
- batch_size=1,
- metric=None,
- return_details=False):
- """
- Evaluate the model.
- Args:
- eval_dataset (paddlers.datasets.COCODetDataset|paddlers.datasets.VOCDetDataset):
- Evaluation dataset.
- batch_size (int, optional): Total batch size among all cards used for
- evaluation. Defaults to 1.
- metric (str|None, optional): Evaluation metric. Choices are {'VOC', 'COCO', None}.
- If None, determine the metric according to the dataset format.
- Defaults to None.
- return_details (bool, optional): Whether to return evaluation details.
- Defaults to False.
- Returns:
- If `return_details` is False, return collections.OrderedDict with key-value pairs:
- {"bbox_mmap": mean average precision (0.50, 11point)}.
- """
- if metric is None:
- if not hasattr(self, 'metric'):
- if eval_dataset.__class__.__name__ == 'VOCDetDataset':
- self.metric = 'voc'
- elif eval_dataset.__class__.__name__ == 'COCODetDataset':
- self.metric = 'coco'
- else:
- assert metric.lower() in ['coco', 'voc'], \
- "Evaluation metric {} is not supported. Please choose from 'COCO' and 'VOC'."
- self.metric = metric.lower()
- if self.metric == 'voc':
- eval_dataset.data_fields = {
- 'im_id', 'image_shape', 'image', 'gt_bbox', 'gt_class',
- 'difficult'
- }
- elif self.metric == 'coco':
- if self.__class__.__name__ == 'MaskRCNN':
- eval_dataset.data_fields = {
- 'im_id', 'image_shape', 'image', 'gt_bbox', 'gt_class',
- 'gt_poly', 'is_crowd'
- }
- else:
- eval_dataset.data_fields = {
- 'im_id', 'image_shape', 'image', 'gt_bbox', 'gt_class',
- 'is_crowd'
- }
- eval_dataset.batch_transforms = self._compose_batch_transform(
- eval_dataset.transforms, mode='eval')
- self._check_transforms(eval_dataset.transforms, 'eval')
- self.net.eval()
- nranks = paddle.distributed.get_world_size()
- local_rank = paddle.distributed.get_rank()
- if nranks > 1:
-
- if not paddle.distributed.parallel.parallel_helper._is_parallel_ctx_initialized(
- ):
- paddle.distributed.init_parallel_env()
- if batch_size > 1:
- logging.warning(
- "Detector only supports single card evaluation with batch_size=1 "
- "during evaluation, so batch_size is forcibly set to 1.")
- batch_size = 1
- if nranks < 2 or local_rank == 0:
- self.eval_data_loader = self.build_data_loader(
- eval_dataset, batch_size=batch_size, mode='eval')
- is_bbox_normalized = False
- if eval_dataset.batch_transforms is not None:
- is_bbox_normalized = any(
- isinstance(t, _NormalizeBox)
- for t in eval_dataset.batch_transforms.batch_transforms)
- if self.metric == 'voc':
- eval_metric = VOCMetric(
- labels=eval_dataset.labels,
- coco_gt=copy.deepcopy(eval_dataset.coco_gt),
- is_bbox_normalized=is_bbox_normalized,
- classwise=False)
- else:
- eval_metric = COCOMetric(
- coco_gt=copy.deepcopy(eval_dataset.coco_gt),
- classwise=False)
- scores = collections.OrderedDict()
- logging.info(
- "Start to evaluate(total_samples={}, total_steps={})...".format(
- eval_dataset.num_samples, eval_dataset.num_samples))
- with paddle.no_grad():
- for step, data in enumerate(self.eval_data_loader):
- outputs = self.run(self.net, data, 'eval')
- eval_metric.update(data, outputs)
- eval_metric.accumulate()
- self.eval_details = eval_metric.details
- scores.update(eval_metric.get())
- eval_metric.reset()
- if return_details:
- return scores, self.eval_details
- return scores
- def predict(self, img_file, transforms=None):
- """
- Do inference.
- Args:
- img_file (list[np.ndarray|str] | str | np.ndarray): Image path or decoded
- image data, which also could constitute a list, meaning all images to be
- predicted as a mini-batch.
- transforms (paddlers.transforms.Compose|None, optional): Transforms for
- inputs. If None, the transforms for evaluation process will be used.
- Defaults to None.
- Returns:
- If `img_file` is a string or np.array, the result is a list of dict with
- the following key-value pairs:
- category_id (int): Predicted category ID. 0 represents the first
- category in the dataset, and so on.
- category (str): Category name.
- bbox (list): Bounding box in [x, y, w, h] format.
- score (str): Confidence.
- mask (dict): Only for instance segmentation task. Mask of the object in
- RLE format.
- If `img_file` is a list, the result is a list composed of list of dicts
- with the above keys.
- """
- if transforms is None and not hasattr(self, 'test_transforms'):
- raise ValueError("transforms need to be defined, now is None.")
- if transforms is None:
- transforms = self.test_transforms
- if isinstance(img_file, (str, np.ndarray)):
- images = [img_file]
- else:
- images = img_file
- batch_samples = self.preprocess(images, transforms)
- self.net.eval()
- outputs = self.run(self.net, batch_samples, 'test')
- prediction = self.postprocess(outputs)
- if isinstance(img_file, (str, np.ndarray)):
- prediction = prediction[0]
- return prediction
- def preprocess(self, images, transforms, to_tensor=True):
- self._check_transforms(transforms, 'test')
- batch_samples = list()
- for im in images:
- if isinstance(im, str):
- im = decode_image(im, read_raw=True)
- sample = {'image': im}
- sample = transforms(sample)
- batch_samples.append(sample)
- batch_transforms = self._compose_batch_transform(transforms, 'test')
- batch_samples = batch_transforms(batch_samples)
- if to_tensor:
- for k in batch_samples:
- batch_samples[k] = paddle.to_tensor(batch_samples[k])
- return batch_samples
- def postprocess(self, batch_pred):
- infer_result = {}
- if 'bbox' in batch_pred:
- bboxes = batch_pred['bbox']
- bbox_nums = batch_pred['bbox_num']
- det_res = []
- k = 0
- for i in range(len(bbox_nums)):
- det_nums = bbox_nums[i]
- for j in range(det_nums):
- dt = bboxes[k]
- k = k + 1
- num_id, score, xmin, ymin, xmax, ymax = dt.tolist()
- if int(num_id) < 0:
- continue
- category = self.labels[int(num_id)]
- w = xmax - xmin
- h = ymax - ymin
- bbox = [xmin, ymin, w, h]
- dt_res = {
- 'category_id': int(num_id),
- 'category': category,
- 'bbox': bbox,
- 'score': score
- }
- det_res.append(dt_res)
- infer_result['bbox'] = det_res
- if 'mask' in batch_pred:
- masks = batch_pred['mask']
- bboxes = batch_pred['bbox']
- mask_nums = batch_pred['bbox_num']
- seg_res = []
- k = 0
- for i in range(len(mask_nums)):
- det_nums = mask_nums[i]
- for j in range(det_nums):
- mask = masks[k].astype(np.uint8)
- score = float(bboxes[k][1])
- label = int(bboxes[k][0])
- k = k + 1
- if label == -1:
- continue
- category = self.labels[int(label)]
- sg_res = {
- 'category_id': int(label),
- 'category': category,
- 'mask': mask.astype('uint8'),
- 'score': score
- }
- seg_res.append(sg_res)
- infer_result['mask'] = seg_res
- bbox_num = batch_pred['bbox_num']
- results = []
- start = 0
- for num in bbox_num:
- end = start + num
- curr_res = infer_result['bbox'][start:end]
- if 'mask' in infer_result:
- mask_res = infer_result['mask'][start:end]
- for box, mask in zip(curr_res, mask_res):
- box.update(mask)
- results.append(curr_res)
- start = end
- return results
- def _check_transforms(self, transforms, mode):
- super()._check_transforms(transforms, mode)
- if not isinstance(transforms.arrange,
- paddlers.transforms.ArrangeDetector):
- raise TypeError(
- "`transforms.arrange` must be an ArrangeDetector object.")
- class PicoDet(BaseDetector):
- def __init__(self,
- num_classes=80,
- backbone='ESNet_m',
- nms_score_threshold=.025,
- nms_topk=1000,
- nms_keep_topk=100,
- nms_iou_threshold=.6,
- **params):
- self.init_params = locals()
- if backbone not in {
- 'ESNet_s', 'ESNet_m', 'ESNet_l', 'LCNet', 'MobileNetV3',
- 'ResNet18_vd'
- }:
- raise ValueError(
- "backbone: {} is not supported. Please choose one of "
- "{'ESNet_s', 'ESNet_m', 'ESNet_l', 'LCNet', 'MobileNetV3', 'ResNet18_vd'}.".
- format(backbone))
- self.backbone_name = backbone
- if params.get('with_net', True):
- if backbone == 'ESNet_s':
- backbone = self._get_backbone(
- 'ESNet',
- scale=.75,
- feature_maps=[4, 11, 14],
- act="hard_swish",
- channel_ratio=[
- 0.875, 0.5, 0.5, 0.5, 0.625, 0.5, 0.625, 0.5, 0.5, 0.5,
- 0.5, 0.5, 0.5
- ])
- neck_out_channels = 96
- head_num_convs = 2
- elif backbone == 'ESNet_m':
- backbone = self._get_backbone(
- 'ESNet',
- scale=1.0,
- feature_maps=[4, 11, 14],
- act="hard_swish",
- channel_ratio=[
- 0.875, 0.5, 1.0, 0.625, 0.5, 0.75, 0.625, 0.625, 0.5,
- 0.625, 1.0, 0.625, 0.75
- ])
- neck_out_channels = 128
- head_num_convs = 4
- elif backbone == 'ESNet_l':
- backbone = self._get_backbone(
- 'ESNet',
- scale=1.25,
- feature_maps=[4, 11, 14],
- act="hard_swish",
- channel_ratio=[
- 0.875, 0.5, 1.0, 0.625, 0.5, 0.75, 0.625, 0.625, 0.5,
- 0.625, 1.0, 0.625, 0.75
- ])
- neck_out_channels = 160
- head_num_convs = 4
- elif backbone == 'LCNet':
- backbone = self._get_backbone(
- 'LCNet', scale=1.5, feature_maps=[3, 4, 5])
- neck_out_channels = 128
- head_num_convs = 4
- elif backbone == 'MobileNetV3':
- backbone = self._get_backbone(
- 'MobileNetV3',
- scale=1.0,
- with_extra_blocks=False,
- extra_block_filters=[],
- feature_maps=[7, 13, 16])
- neck_out_channels = 128
- head_num_convs = 4
- else:
- backbone = self._get_backbone(
- 'ResNet',
- depth=18,
- variant='d',
- return_idx=[1, 2, 3],
- freeze_at=-1,
- freeze_norm=False,
- norm_decay=0.)
- neck_out_channels = 128
- head_num_convs = 4
- neck = ppdet.modeling.CSPPAN(
- in_channels=[i.channels for i in backbone.out_shape],
- out_channels=neck_out_channels,
- num_features=4,
- num_csp_blocks=1,
- use_depthwise=True)
- head_conv_feat = ppdet.modeling.PicoFeat(
- feat_in=neck_out_channels,
- feat_out=neck_out_channels,
- num_fpn_stride=4,
- num_convs=head_num_convs,
- norm_type='bn',
- share_cls_reg=True, )
- loss_class = ppdet.modeling.VarifocalLoss(
- use_sigmoid=True, iou_weighted=True, loss_weight=1.0)
- loss_dfl = ppdet.modeling.DistributionFocalLoss(loss_weight=.25)
- loss_bbox = ppdet.modeling.GIoULoss(loss_weight=2.0)
- assigner = ppdet.modeling.SimOTAAssigner(
- candidate_topk=10, iou_weight=6, num_classes=num_classes)
- nms = ppdet.modeling.MultiClassNMS(
- nms_top_k=nms_topk,
- keep_top_k=nms_keep_topk,
- score_threshold=nms_score_threshold,
- nms_threshold=nms_iou_threshold)
- head = ppdet.modeling.PicoHead(
- conv_feat=head_conv_feat,
- num_classes=num_classes,
- fpn_stride=[8, 16, 32, 64],
- prior_prob=0.01,
- reg_max=7,
- cell_offset=.5,
- loss_class=loss_class,
- loss_dfl=loss_dfl,
- loss_bbox=loss_bbox,
- assigner=assigner,
- feat_in_chan=neck_out_channels,
- nms=nms)
- params.update({
- 'backbone': backbone,
- 'neck': neck,
- 'head': head,
- })
- super(PicoDet, self).__init__(
- model_name='PicoDet', num_classes=num_classes, **params)
- def _compose_batch_transform(self, transforms, mode='train'):
- default_batch_transforms = [_BatchPad(pad_to_stride=32)]
- if mode == 'eval':
- collate_batch = True
- else:
- collate_batch = False
- custom_batch_transforms = []
- for i, op in enumerate(transforms.transforms):
- if isinstance(op, (BatchRandomResize, BatchRandomResizeByShort)):
- if mode != 'train':
- raise ValueError(
- "{} cannot be present in the {} transforms.".format(
- op.__class__.__name__, mode) +
- "Please check the {} transforms.".format(mode))
- custom_batch_transforms.insert(0, copy.deepcopy(op))
- batch_transforms = BatchCompose(
- custom_batch_transforms + default_batch_transforms,
- collate_batch=collate_batch)
- return batch_transforms
- def _fix_transforms_shape(self, image_shape):
- if getattr(self, 'test_transforms', None):
- has_resize_op = False
- resize_op_idx = -1
- normalize_op_idx = len(self.test_transforms.transforms)
- for idx, op in enumerate(self.test_transforms.transforms):
- name = op.__class__.__name__
- if name == 'Resize':
- has_resize_op = True
- resize_op_idx = idx
- if name == 'Normalize':
- normalize_op_idx = idx
- if not has_resize_op:
- self.test_transforms.transforms.insert(
- normalize_op_idx,
- Resize(
- target_size=image_shape, interp='CUBIC'))
- else:
- self.test_transforms.transforms[
- resize_op_idx].target_size = image_shape
- def _get_test_inputs(self, image_shape):
- if image_shape is not None:
- image_shape = self._check_image_shape(image_shape)
- self._fix_transforms_shape(image_shape[-2:])
- else:
- image_shape = [None, 3, 320, 320]
- if getattr(self, 'test_transforms', None):
- for idx, op in enumerate(self.test_transforms.transforms):
- name = op.__class__.__name__
- if name == 'Resize':
- image_shape = [None, 3] + list(
- self.test_transforms.transforms[idx].target_size)
- logging.warning(
- '[Important!!!] When exporting inference model for {}, '
- 'if fixed_input_shape is not set, it will be forcibly set to {}. '
- 'Please ensure image shape after transforms is {}, if not, '
- 'fixed_input_shape should be specified manually.'
- .format(self.__class__.__name__, image_shape, image_shape[1:]))
- self.fixed_input_shape = image_shape
- return self._define_input_spec(image_shape)
- def _pre_train(self, in_args):
- optimizer = in_args['optimizer']
- if optimizer is None:
- num_steps_each_epoch = len(in_args['train_dataset']) // in_args[
- 'train_batch_size']
- optimizer = self.default_optimizer(
- parameters=self.net.parameters(),
- learning_rate=in_args['learning_rate'],
- warmup_steps=in_args['warmup_steps'],
- warmup_start_lr=in_args['warmup_start_lr'],
- lr_decay_epochs=in_args['lr_decay_epochs'],
- lr_decay_gamma=in_args['lr_decay_gamma'],
- num_steps_each_epoch=in_args['num_steps_each_epoch'],
- reg_coeff=4e-05,
- scheduler='Cosine',
- num_epochs=in_args['num_epochs'])
- in_args['optimizer'] = optimizer
- return in_args
- def build_data_loader(self, dataset, batch_size, mode='train'):
- if dataset.num_samples < batch_size:
- raise ValueError(
- 'The volume of dataset({}) must be larger than batch size({}).'
- .format(dataset.num_samples, batch_size))
- if mode != 'train':
- return paddle.io.DataLoader(
- dataset,
- batch_size=batch_size,
- shuffle=dataset.shuffle,
- drop_last=False,
- collate_fn=dataset.batch_transforms,
- num_workers=dataset.num_workers,
- return_list=True,
- use_shared_memory=False)
- else:
- return super(BaseDetector, self).build_data_loader(dataset,
- batch_size, mode)
- class YOLOv3(BaseDetector):
- def __init__(self,
- num_classes=80,
- backbone='MobileNetV1',
- anchors=[[10, 13], [16, 30], [33, 23], [30, 61], [62, 45],
- [59, 119], [116, 90], [156, 198], [373, 326]],
- anchor_masks=[[6, 7, 8], [3, 4, 5], [0, 1, 2]],
- ignore_threshold=0.7,
- nms_score_threshold=0.01,
- nms_topk=1000,
- nms_keep_topk=100,
- nms_iou_threshold=0.45,
- label_smooth=False,
- **params):
- self.init_params = locals()
- if backbone not in {
- 'MobileNetV1', 'MobileNetV1_ssld', 'MobileNetV3',
- 'MobileNetV3_ssld', 'DarkNet53', 'ResNet50_vd_dcn', 'ResNet34'
- }:
- raise ValueError(
- "backbone: {} is not supported. Please choose one of "
- "{'MobileNetV1', 'MobileNetV1_ssld', 'MobileNetV3', 'MobileNetV3_ssld', 'DarkNet53', "
- "'ResNet50_vd_dcn', 'ResNet34'}.".format(backbone))
- self.backbone_name = backbone
- if params.get('with_net', True):
- if paddlers.env_info['place'] == 'gpu' and paddlers.env_info[
- 'num'] > 1 and not os.environ.get('PADDLERS_EXPORT_STAGE'):
- norm_type = 'sync_bn'
- else:
- norm_type = 'bn'
- if 'MobileNetV1' in backbone:
- norm_type = 'bn'
- backbone = self._get_backbone('MobileNet', norm_type=norm_type)
- elif 'MobileNetV3' in backbone:
- backbone = self._get_backbone(
- 'MobileNetV3',
- norm_type=norm_type,
- feature_maps=[7, 13, 16])
- elif backbone == 'ResNet50_vd_dcn':
- backbone = self._get_backbone(
- 'ResNet',
- norm_type=norm_type,
- variant='d',
- return_idx=[1, 2, 3],
- dcn_v2_stages=[3],
- freeze_at=-1,
- freeze_norm=False)
- elif backbone == 'ResNet34':
- backbone = self._get_backbone(
- 'ResNet',
- depth=34,
- norm_type=norm_type,
- return_idx=[1, 2, 3],
- freeze_at=-1,
- freeze_norm=False,
- norm_decay=0.)
- else:
- backbone = self._get_backbone('DarkNet', norm_type=norm_type)
- neck = ppdet.modeling.YOLOv3FPN(
- norm_type=norm_type,
- in_channels=[i.channels for i in backbone.out_shape])
- loss = ppdet.modeling.YOLOv3Loss(
- num_classes=num_classes,
- ignore_thresh=ignore_threshold,
- label_smooth=label_smooth)
- yolo_head = ppdet.modeling.YOLOv3Head(
- in_channels=[i.channels for i in neck.out_shape],
- anchors=anchors,
- anchor_masks=anchor_masks,
- num_classes=num_classes,
- loss=loss)
- post_process = ppdet.modeling.BBoxPostProcess(
- decode=ppdet.modeling.YOLOBox(num_classes=num_classes),
- nms=ppdet.modeling.MultiClassNMS(
- score_threshold=nms_score_threshold,
- nms_top_k=nms_topk,
- keep_top_k=nms_keep_topk,
- nms_threshold=nms_iou_threshold))
- params.update({
- 'backbone': backbone,
- 'neck': neck,
- 'yolo_head': yolo_head,
- 'post_process': post_process
- })
- super(YOLOv3, self).__init__(
- model_name='YOLOv3', num_classes=num_classes, **params)
- self.anchors = anchors
- self.anchor_masks = anchor_masks
- def _compose_batch_transform(self, transforms, mode='train'):
- if mode == 'train':
- default_batch_transforms = [
- _BatchPad(pad_to_stride=-1), _NormalizeBox(),
- _PadBox(getattr(self, 'num_max_boxes', 50)), _BboxXYXY2XYWH(),
- _Gt2YoloTarget(
- anchor_masks=self.anchor_masks,
- anchors=self.anchors,
- downsample_ratios=getattr(self, 'downsample_ratios',
- [32, 16, 8]),
- num_classes=self.num_classes)
- ]
- else:
- default_batch_transforms = [_BatchPad(pad_to_stride=-1)]
- if mode == 'eval' and self.metric == 'voc':
- collate_batch = False
- else:
- collate_batch = True
- custom_batch_transforms = []
- for i, op in enumerate(transforms.transforms):
- if isinstance(op, (BatchRandomResize, BatchRandomResizeByShort)):
- if mode != 'train':
- raise ValueError(
- "{} cannot be present in the {} transforms. ".format(
- op.__class__.__name__, mode) +
- "Please check the {} transforms.".format(mode))
- custom_batch_transforms.insert(0, copy.deepcopy(op))
- batch_transforms = BatchCompose(
- custom_batch_transforms + default_batch_transforms,
- collate_batch=collate_batch)
- return batch_transforms
- def _fix_transforms_shape(self, image_shape):
- if getattr(self, 'test_transforms', None):
- has_resize_op = False
- resize_op_idx = -1
- normalize_op_idx = len(self.test_transforms.transforms)
- for idx, op in enumerate(self.test_transforms.transforms):
- name = op.__class__.__name__
- if name == 'Resize':
- has_resize_op = True
- resize_op_idx = idx
- if name == 'Normalize':
- normalize_op_idx = idx
- if not has_resize_op:
- self.test_transforms.transforms.insert(
- normalize_op_idx,
- Resize(
- target_size=image_shape, interp='CUBIC'))
- else:
- self.test_transforms.transforms[
- resize_op_idx].target_size = image_shape
- class FasterRCNN(BaseDetector):
- def __init__(self,
- num_classes=80,
- backbone='ResNet50',
- with_fpn=True,
- with_dcn=False,
- aspect_ratios=[0.5, 1.0, 2.0],
- anchor_sizes=[[32], [64], [128], [256], [512]],
- keep_top_k=100,
- nms_threshold=0.5,
- score_threshold=0.05,
- fpn_num_channels=256,
- rpn_batch_size_per_im=256,
- rpn_fg_fraction=0.5,
- test_pre_nms_top_n=None,
- test_post_nms_top_n=1000,
- **params):
- self.init_params = locals()
- if backbone not in {
- 'ResNet50', 'ResNet50_vd', 'ResNet50_vd_ssld', 'ResNet34',
- 'ResNet34_vd', 'ResNet101', 'ResNet101_vd', 'HRNet_W18'
- }:
- raise ValueError(
- "backbone: {} is not supported. Please choose one of "
- "{'ResNet50', 'ResNet50_vd', 'ResNet50_vd_ssld', 'ResNet34', 'ResNet34_vd', "
- "'ResNet101', 'ResNet101_vd', 'HRNet_W18'}.".format(backbone))
- self.backbone_name = backbone
- if params.get('with_net', True):
- dcn_v2_stages = [1, 2, 3] if with_dcn else [-1]
- if backbone == 'HRNet_W18':
- if not with_fpn:
- logging.warning(
- "Backbone {} should be used along with fpn enabled, 'with_fpn' is forcibly set to True".
- format(backbone))
- with_fpn = True
- if with_dcn:
- logging.warning(
- "Backbone {} should be used along with dcn disabled, 'with_dcn' is forcibly set to False".
- format(backbone))
- backbone = self._get_backbone(
- 'HRNet', width=18, freeze_at=0, return_idx=[0, 1, 2, 3])
- elif backbone == 'ResNet50_vd_ssld':
- if not with_fpn:
- logging.warning(
- "Backbone {} should be used along with fpn enabled, 'with_fpn' is forcibly set to True".
- format(backbone))
- with_fpn = True
- backbone = self._get_backbone(
- 'ResNet',
- variant='d',
- norm_type='bn',
- freeze_at=0,
- return_idx=[0, 1, 2, 3],
- num_stages=4,
- lr_mult_list=[0.05, 0.05, 0.1, 0.15],
- dcn_v2_stages=dcn_v2_stages)
- elif 'ResNet50' in backbone:
- if with_fpn:
- backbone = self._get_backbone(
- 'ResNet',
- variant='d' if '_vd' in backbone else 'b',
- norm_type='bn',
- freeze_at=0,
- return_idx=[0, 1, 2, 3],
- num_stages=4,
- dcn_v2_stages=dcn_v2_stages)
- else:
- if with_dcn:
- logging.warning(
- "Backbone {} without fpn should be used along with dcn disabled, 'with_dcn' is forcibly set to False".
- format(backbone))
- backbone = self._get_backbone(
- 'ResNet',
- variant='d' if '_vd' in backbone else 'b',
- norm_type='bn',
- freeze_at=0,
- return_idx=[2],
- num_stages=3)
- elif 'ResNet34' in backbone:
- if not with_fpn:
- logging.warning(
- "Backbone {} should be used along with fpn enabled, 'with_fpn' is forcibly set to True".
- format(backbone))
- with_fpn = True
- backbone = self._get_backbone(
- 'ResNet',
- depth=34,
- variant='d' if 'vd' in backbone else 'b',
- norm_type='bn',
- freeze_at=0,
- return_idx=[0, 1, 2, 3],
- num_stages=4,
- dcn_v2_stages=dcn_v2_stages)
- else:
- if not with_fpn:
- logging.warning(
- "Backbone {} should be used along with fpn enabled, 'with_fpn' is forcibly set to True".
- format(backbone))
- with_fpn = True
- backbone = self._get_backbone(
- 'ResNet',
- depth=101,
- variant='d' if 'vd' in backbone else 'b',
- norm_type='bn',
- freeze_at=0,
- return_idx=[0, 1, 2, 3],
- num_stages=4,
- dcn_v2_stages=dcn_v2_stages)
- rpn_in_channel = backbone.out_shape[0].channels
- if with_fpn:
- self.backbone_name = self.backbone_name + '_fpn'
- if 'HRNet' in self.backbone_name:
- neck = ppdet.modeling.HRFPN(
- in_channels=[i.channels for i in backbone.out_shape],
- out_channel=fpn_num_channels,
- spatial_scales=[
- 1.0 / i.stride for i in backbone.out_shape
- ],
- share_conv=False)
- else:
- neck = ppdet.modeling.FPN(
- in_channels=[i.channels for i in backbone.out_shape],
- out_channel=fpn_num_channels,
- spatial_scales=[
- 1.0 / i.stride for i in backbone.out_shape
- ])
- rpn_in_channel = neck.out_shape[0].channels
- anchor_generator_cfg = {
- 'aspect_ratios': aspect_ratios,
- 'anchor_sizes': anchor_sizes,
- 'strides': [4, 8, 16, 32, 64]
- }
- train_proposal_cfg = {
- 'min_size': 0.0,
- 'nms_thresh': .7,
- 'pre_nms_top_n': 2000,
- 'post_nms_top_n': 1000,
- 'topk_after_collect': True
- }
- test_proposal_cfg = {
- 'min_size': 0.0,
- 'nms_thresh': .7,
- 'pre_nms_top_n': 1000
- if test_pre_nms_top_n is None else test_pre_nms_top_n,
- 'post_nms_top_n': test_post_nms_top_n
- }
- head = ppdet.modeling.TwoFCHead(
- in_channel=neck.out_shape[0].channels, out_channel=1024)
- roi_extractor_cfg = {
- 'resolution': 7,
- 'spatial_scale': [1. / i.stride for i in neck.out_shape],
- 'sampling_ratio': 0,
- 'aligned': True
- }
- with_pool = False
- else:
- neck = None
- anchor_generator_cfg = {
- 'aspect_ratios': aspect_ratios,
- 'anchor_sizes': anchor_sizes,
- 'strides': [16]
- }
- train_proposal_cfg = {
- 'min_size': 0.0,
- 'nms_thresh': .7,
- 'pre_nms_top_n': 12000,
- 'post_nms_top_n': 2000,
- 'topk_after_collect': False
- }
- test_proposal_cfg = {
- 'min_size': 0.0,
- 'nms_thresh': .7,
- 'pre_nms_top_n': 6000
- if test_pre_nms_top_n is None else test_pre_nms_top_n,
- 'post_nms_top_n': test_post_nms_top_n
- }
- head = ppdet.modeling.Res5Head()
- roi_extractor_cfg = {
- 'resolution': 14,
- 'spatial_scale':
- [1. / i.stride for i in backbone.out_shape],
- 'sampling_ratio': 0,
- 'aligned': True
- }
- with_pool = True
- rpn_target_assign_cfg = {
- 'batch_size_per_im': rpn_batch_size_per_im,
- 'fg_fraction': rpn_fg_fraction,
- 'negative_overlap': .3,
- 'positive_overlap': .7,
- 'use_random': True
- }
- rpn_head = ppdet.modeling.RPNHead(
- anchor_generator=anchor_generator_cfg,
- rpn_target_assign=rpn_target_assign_cfg,
- train_proposal=train_proposal_cfg,
- test_proposal=test_proposal_cfg,
- in_channel=rpn_in_channel)
- bbox_assigner = BBoxAssigner(num_classes=num_classes)
- bbox_head = ppdet.modeling.BBoxHead(
- head=head,
- in_channel=head.out_shape[0].channels,
- roi_extractor=roi_extractor_cfg,
- with_pool=with_pool,
- bbox_assigner=bbox_assigner,
- num_classes=num_classes)
- bbox_post_process = ppdet.modeling.BBoxPostProcess(
- num_classes=num_classes,
- decode=ppdet.modeling.RCNNBox(num_classes=num_classes),
- nms=ppdet.modeling.MultiClassNMS(
- score_threshold=score_threshold,
- keep_top_k=keep_top_k,
- nms_threshold=nms_threshold))
- params.update({
- 'backbone': backbone,
- 'neck': neck,
- 'rpn_head': rpn_head,
- 'bbox_head': bbox_head,
- 'bbox_post_process': bbox_post_process
- })
- else:
- if backbone not in {'ResNet50', 'ResNet50_vd'}:
- with_fpn = True
- self.with_fpn = with_fpn
- super(FasterRCNN, self).__init__(
- model_name='FasterRCNN', num_classes=num_classes, **params)
- def _pre_train(self, in_args):
- train_dataset = in_args['train_dataset']
- if train_dataset.pos_num < len(train_dataset.file_list):
-
- train_dataset.num_workers = 0
- return in_args
- def _compose_batch_transform(self, transforms, mode='train'):
- if mode == 'train':
- default_batch_transforms = [
- _BatchPad(pad_to_stride=32 if self.with_fpn else -1)
- ]
- else:
- default_batch_transforms = [
- _BatchPad(pad_to_stride=32 if self.with_fpn else -1)
- ]
- custom_batch_transforms = []
- for i, op in enumerate(transforms.transforms):
- if isinstance(op, (BatchRandomResize, BatchRandomResizeByShort)):
- if mode != 'train':
- raise ValueError(
- "{} cannot be present in the {} transforms. ".format(
- op.__class__.__name__, mode) +
- "Please check the {} transforms.".format(mode))
- custom_batch_transforms.insert(0, copy.deepcopy(op))
- batch_transforms = BatchCompose(
- custom_batch_transforms + default_batch_transforms,
- collate_batch=False)
- return batch_transforms
- def _fix_transforms_shape(self, image_shape):
- if getattr(self, 'test_transforms', None):
- has_resize_op = False
- resize_op_idx = -1
- normalize_op_idx = len(self.test_transforms.transforms)
- for idx, op in enumerate(self.test_transforms.transforms):
- name = op.__class__.__name__
- if name == 'ResizeByShort':
- has_resize_op = True
- resize_op_idx = idx
- if name == 'Normalize':
- normalize_op_idx = idx
- if not has_resize_op:
- self.test_transforms.transforms.insert(
- normalize_op_idx,
- Resize(
- target_size=image_shape,
- keep_ratio=True,
- interp='CUBIC'))
- else:
- self.test_transforms.transforms[resize_op_idx] = Resize(
- target_size=image_shape, keep_ratio=True, interp='CUBIC')
- self.test_transforms.transforms.append(
- Pad(im_padding_value=[0., 0., 0.]))
- def _get_test_inputs(self, image_shape):
- if image_shape is not None:
- image_shape = self._check_image_shape(image_shape)
- self._fix_transforms_shape(image_shape[-2:])
- else:
- image_shape = [None, 3, -1, -1]
- if self.with_fpn:
- self.test_transforms.transforms.append(
- Pad(im_padding_value=[0., 0., 0.]))
- self.fixed_input_shape = image_shape
- return self._define_input_spec(image_shape)
- class PPYOLO(YOLOv3):
- def __init__(self,
- num_classes=80,
- backbone='ResNet50_vd_dcn',
- anchors=None,
- anchor_masks=None,
- use_coord_conv=True,
- use_iou_aware=True,
- use_spp=True,
- use_drop_block=True,
- scale_x_y=1.05,
- ignore_threshold=0.7,
- label_smooth=False,
- use_iou_loss=True,
- use_matrix_nms=True,
- nms_score_threshold=0.01,
- nms_topk=-1,
- nms_keep_topk=100,
- nms_iou_threshold=0.45,
- **params):
- self.init_params = locals()
- if backbone not in {
- 'ResNet50_vd_dcn', 'ResNet18_vd', 'MobileNetV3_large',
- 'MobileNetV3_small'
- }:
- raise ValueError(
- "backbone: {} is not supported. Please choose one of "
- "{'ResNet50_vd_dcn', 'ResNet18_vd', 'MobileNetV3_large', 'MobileNetV3_small'}.".
- format(backbone))
- self.backbone_name = backbone
- self.downsample_ratios = [
- 32, 16, 8
- ] if backbone == 'ResNet50_vd_dcn' else [32, 16]
- if params.get('with_net', True):
- if paddlers.env_info['place'] == 'gpu' and paddlers.env_info[
- 'num'] > 1 and not os.environ.get('PADDLERS_EXPORT_STAGE'):
- norm_type = 'sync_bn'
- else:
- norm_type = 'bn'
- if anchors is None and anchor_masks is None:
- if 'MobileNetV3' in backbone:
- anchors = [[11, 18], [34, 47], [51, 126], [115, 71],
- [120, 195], [254, 235]]
- anchor_masks = [[3, 4, 5], [0, 1, 2]]
- elif backbone == 'ResNet50_vd_dcn':
- anchors = [[10, 13], [16, 30], [33, 23], [30, 61],
- [62, 45], [59, 119], [116, 90], [156, 198],
- [373, 326]]
- anchor_masks = [[6, 7, 8], [3, 4, 5], [0, 1, 2]]
- else:
- anchors = [[10, 14], [23, 27], [37, 58], [81, 82],
- [135, 169], [344, 319]]
- anchor_masks = [[3, 4, 5], [0, 1, 2]]
- elif anchors is None or anchor_masks is None:
- raise ValueError("Please define both anchors and anchor_masks.")
- if backbone == 'ResNet50_vd_dcn':
- backbone = self._get_backbone(
- 'ResNet',
- variant='d',
- norm_type=norm_type,
- return_idx=[1, 2, 3],
- dcn_v2_stages=[3],
- freeze_at=-1,
- freeze_norm=False,
- norm_decay=0.)
- elif backbone == 'ResNet18_vd':
- backbone = self._get_backbone(
- 'ResNet',
- depth=18,
- variant='d',
- norm_type=norm_type,
- return_idx=[2, 3],
- freeze_at=-1,
- freeze_norm=False,
- norm_decay=0.)
- elif backbone == 'MobileNetV3_large':
- backbone = self._get_backbone(
- 'MobileNetV3',
- model_name='large',
- norm_type=norm_type,
- scale=1,
- with_extra_blocks=False,
- extra_block_filters=[],
- feature_maps=[13, 16])
- elif backbone == 'MobileNetV3_small':
- backbone = self._get_backbone(
- 'MobileNetV3',
- model_name='small',
- norm_type=norm_type,
- scale=1,
- with_extra_blocks=False,
- extra_block_filters=[],
- feature_maps=[9, 12])
- neck = ppdet.modeling.PPYOLOFPN(
- norm_type=norm_type,
- in_channels=[i.channels for i in backbone.out_shape],
- coord_conv=use_coord_conv,
- drop_block=use_drop_block,
- spp=use_spp,
- conv_block_num=0
- if ('MobileNetV3' in self.backbone_name or
- self.backbone_name == 'ResNet18_vd') else 2)
- loss = ppdet.modeling.YOLOv3Loss(
- num_classes=num_classes,
- ignore_thresh=ignore_threshold,
- downsample=self.downsample_ratios,
- label_smooth=label_smooth,
- scale_x_y=scale_x_y,
- iou_loss=ppdet.modeling.IouLoss(
- loss_weight=2.5, loss_square=True)
- if use_iou_loss else None,
- iou_aware_loss=ppdet.modeling.IouAwareLoss(loss_weight=1.0)
- if use_iou_aware else None)
- yolo_head = ppdet.modeling.YOLOv3Head(
- in_channels=[i.channels for i in neck.out_shape],
- anchors=anchors,
- anchor_masks=anchor_masks,
- num_classes=num_classes,
- loss=loss,
- iou_aware=use_iou_aware)
- if use_matrix_nms:
- nms = ppdet.modeling.MatrixNMS(
- keep_top_k=nms_keep_topk,
- score_threshold=nms_score_threshold,
- post_threshold=.05
- if 'MobileNetV3' in self.backbone_name else .01,
- nms_top_k=nms_topk,
- background_label=-1)
- else:
- nms = ppdet.modeling.MultiClassNMS(
- score_threshold=nms_score_threshold,
- nms_top_k=nms_topk,
- keep_top_k=nms_keep_topk,
- nms_threshold=nms_iou_threshold)
- post_process = ppdet.modeling.BBoxPostProcess(
- decode=ppdet.modeling.YOLOBox(
- num_classes=num_classes,
- conf_thresh=.005
- if 'MobileNetV3' in self.backbone_name else .01,
- scale_x_y=scale_x_y),
- nms=nms)
- params.update({
- 'backbone': backbone,
- 'neck': neck,
- 'yolo_head': yolo_head,
- 'post_process': post_process
- })
- super(YOLOv3, self).__init__(
- model_name='YOLOv3', num_classes=num_classes, **params)
- self.anchors = anchors
- self.anchor_masks = anchor_masks
- self.model_name = 'PPYOLO'
- def _get_test_inputs(self, image_shape):
- if image_shape is not None:
- image_shape = self._check_image_shape(image_shape)
- self._fix_transforms_shape(image_shape[-2:])
- else:
- image_shape = [None, 3, 608, 608]
- if getattr(self, 'test_transforms', None):
- for idx, op in enumerate(self.test_transforms.transforms):
- name = op.__class__.__name__
- if name == 'Resize':
- image_shape = [None, 3] + list(
- self.test_transforms.transforms[idx].target_size)
- logging.warning(
- '[Important!!!] When exporting inference model for {}, '
- 'if fixed_input_shape is not set, it will be forcibly set to {}. '
- 'Please ensure image shape after transforms is {}, if not, '
- 'fixed_input_shape should be specified manually.'
- .format(self.__class__.__name__, image_shape, image_shape[1:]))
- self.fixed_input_shape = image_shape
- return self._define_input_spec(image_shape)
- class PPYOLOTiny(YOLOv3):
- def __init__(self,
- num_classes=80,
- backbone='MobileNetV3',
- anchors=[[10, 15], [24, 36], [72, 42], [35, 87], [102, 96],
- [60, 170], [220, 125], [128, 222], [264, 266]],
- anchor_masks=[[6, 7, 8], [3, 4, 5], [0, 1, 2]],
- use_iou_aware=False,
- use_spp=True,
- use_drop_block=True,
- scale_x_y=1.05,
- ignore_threshold=0.5,
- label_smooth=False,
- use_iou_loss=True,
- use_matrix_nms=False,
- nms_score_threshold=0.005,
- nms_topk=1000,
- nms_keep_topk=100,
- nms_iou_threshold=0.45,
- **params):
- self.init_params = locals()
- if backbone != 'MobileNetV3':
- logging.warning("PPYOLOTiny only supports MobileNetV3 as backbone. "
- "Backbone is forcibly set to MobileNetV3.")
- self.backbone_name = 'MobileNetV3'
- self.downsample_ratios = [32, 16, 8]
- if params.get('with_net', True):
- if paddlers.env_info['place'] == 'gpu' and paddlers.env_info[
- 'num'] > 1 and not os.environ.get('PADDLERS_EXPORT_STAGE'):
- norm_type = 'sync_bn'
- else:
- norm_type = 'bn'
- backbone = self._get_backbone(
- 'MobileNetV3',
- model_name='large',
- norm_type=norm_type,
- scale=.5,
- with_extra_blocks=False,
- extra_block_filters=[],
- feature_maps=[7, 13, 16])
- neck = ppdet.modeling.PPYOLOTinyFPN(
- detection_block_channels=[160, 128, 96],
- in_channels=[i.channels for i in backbone.out_shape],
- spp=use_spp,
- drop_block=use_drop_block)
- loss = ppdet.modeling.YOLOv3Loss(
- num_classes=num_classes,
- ignore_thresh=ignore_threshold,
- downsample=self.downsample_ratios,
- label_smooth=label_smooth,
- scale_x_y=scale_x_y,
- iou_loss=ppdet.modeling.IouLoss(
- loss_weight=2.5, loss_square=True)
- if use_iou_loss else None,
- iou_aware_loss=ppdet.modeling.IouAwareLoss(loss_weight=1.0)
- if use_iou_aware else None)
- yolo_head = ppdet.modeling.YOLOv3Head(
- in_channels=[i.channels for i in neck.out_shape],
- anchors=anchors,
- anchor_masks=anchor_masks,
- num_classes=num_classes,
- loss=loss,
- iou_aware=use_iou_aware)
- if use_matrix_nms:
- nms = ppdet.modeling.MatrixNMS(
- keep_top_k=nms_keep_topk,
- score_threshold=nms_score_threshold,
- post_threshold=.05,
- nms_top_k=nms_topk,
- background_label=-1)
- else:
- nms = ppdet.modeling.MultiClassNMS(
- score_threshold=nms_score_threshold,
- nms_top_k=nms_topk,
- keep_top_k=nms_keep_topk,
- nms_threshold=nms_iou_threshold)
- post_process = ppdet.modeling.BBoxPostProcess(
- decode=ppdet.modeling.YOLOBox(
- num_classes=num_classes,
- conf_thresh=.005,
- downsample_ratio=32,
- clip_bbox=True,
- scale_x_y=scale_x_y),
- nms=nms)
- params.update({
- 'backbone': backbone,
- 'neck': neck,
- 'yolo_head': yolo_head,
- 'post_process': post_process
- })
- super(YOLOv3, self).__init__(
- model_name='YOLOv3', num_classes=num_classes, **params)
- self.anchors = anchors
- self.anchor_masks = anchor_masks
- self.model_name = 'PPYOLOTiny'
- def _get_test_inputs(self, image_shape):
- if image_shape is not None:
- image_shape = self._check_image_shape(image_shape)
- self._fix_transforms_shape(image_shape[-2:])
- else:
- image_shape = [None, 3, 320, 320]
- if getattr(self, 'test_transforms', None):
- for idx, op in enumerate(self.test_transforms.transforms):
- name = op.__class__.__name__
- if name == 'Resize':
- image_shape = [None, 3] + list(
- self.test_transforms.transforms[idx].target_size)
- logging.warning(
- '[Important!!!] When exporting inference model for {},'.format(
- self.__class__.__name__) +
- ' if fixed_input_shape is not set, it will be forcibly set to {}. '.
- format(image_shape) +
- 'Please check image shape after transforms is {}, if not, fixed_input_shape '.
- format(image_shape[1:]) + 'should be specified manually.')
- self.fixed_input_shape = image_shape
- return self._define_input_spec(image_shape)
- class PPYOLOv2(YOLOv3):
- def __init__(self,
- num_classes=80,
- backbone='ResNet50_vd_dcn',
- anchors=[[10, 13], [16, 30], [33, 23], [30, 61], [62, 45],
- [59, 119], [116, 90], [156, 198], [373, 326]],
- anchor_masks=[[6, 7, 8], [3, 4, 5], [0, 1, 2]],
- use_iou_aware=True,
- use_spp=True,
- use_drop_block=True,
- scale_x_y=1.05,
- ignore_threshold=0.7,
- label_smooth=False,
- use_iou_loss=True,
- use_matrix_nms=True,
- nms_score_threshold=0.01,
- nms_topk=-1,
- nms_keep_topk=100,
- nms_iou_threshold=0.45,
- **params):
- self.init_params = locals()
- if backbone not in {'ResNet50_vd_dcn', 'ResNet101_vd_dcn'}:
- raise ValueError(
- "backbone: {} is not supported. Please choose one of "
- "{'ResNet50_vd_dcn', 'ResNet101_vd_dcn'}.".format(backbone))
- self.backbone_name = backbone
- self.downsample_ratios = [32, 16, 8]
- if params.get('with_net', True):
- if paddlers.env_info['place'] == 'gpu' and paddlers.env_info[
- 'num'] > 1 and not os.environ.get('PADDLERS_EXPORT_STAGE'):
- norm_type = 'sync_bn'
- else:
- norm_type = 'bn'
- if backbone == 'ResNet50_vd_dcn':
- backbone = self._get_backbone(
- 'ResNet',
- variant='d',
- norm_type=norm_type,
- return_idx=[1, 2, 3],
- dcn_v2_stages=[3],
- freeze_at=-1,
- freeze_norm=False,
- norm_decay=0.)
- elif backbone == 'ResNet101_vd_dcn':
- backbone = self._get_backbone(
- 'ResNet',
- depth=101,
- variant='d',
- norm_type=norm_type,
- return_idx=[1, 2, 3],
- dcn_v2_stages=[3],
- freeze_at=-1,
- freeze_norm=False,
- norm_decay=0.)
- neck = ppdet.modeling.PPYOLOPAN(
- norm_type=norm_type,
- in_channels=[i.channels for i in backbone.out_shape],
- drop_block=use_drop_block,
- block_size=3,
- keep_prob=.9,
- spp=use_spp)
- loss = ppdet.modeling.YOLOv3Loss(
- num_classes=num_classes,
- ignore_thresh=ignore_threshold,
- downsample=self.downsample_ratios,
- label_smooth=label_smooth,
- scale_x_y=scale_x_y,
- iou_loss=ppdet.modeling.IouLoss(
- loss_weight=2.5, loss_square=True)
- if use_iou_loss else None,
- iou_aware_loss=ppdet.modeling.IouAwareLoss(loss_weight=1.0)
- if use_iou_aware else None)
- yolo_head = ppdet.modeling.YOLOv3Head(
- in_channels=[i.channels for i in neck.out_shape],
- anchors=anchors,
- anchor_masks=anchor_masks,
- num_classes=num_classes,
- loss=loss,
- iou_aware=use_iou_aware,
- iou_aware_factor=.5)
- if use_matrix_nms:
- nms = ppdet.modeling.MatrixNMS(
- keep_top_k=nms_keep_topk,
- score_threshold=nms_score_threshold,
- post_threshold=.01,
- nms_top_k=nms_topk,
- background_label=-1)
- else:
- nms = ppdet.modeling.MultiClassNMS(
- score_threshold=nms_score_threshold,
- nms_top_k=nms_topk,
- keep_top_k=nms_keep_topk,
- nms_threshold=nms_iou_threshold)
- post_process = ppdet.modeling.BBoxPostProcess(
- decode=ppdet.modeling.YOLOBox(
- num_classes=num_classes,
- conf_thresh=.01,
- downsample_ratio=32,
- clip_bbox=True,
- scale_x_y=scale_x_y),
- nms=nms)
- params.update({
- 'backbone': backbone,
- 'neck': neck,
- 'yolo_head': yolo_head,
- 'post_process': post_process
- })
- super(YOLOv3, self).__init__(
- model_name='YOLOv3', num_classes=num_classes, **params)
- self.anchors = anchors
- self.anchor_masks = anchor_masks
- self.model_name = 'PPYOLOv2'
- def _get_test_inputs(self, image_shape):
- if image_shape is not None:
- image_shape = self._check_image_shape(image_shape)
- self._fix_transforms_shape(image_shape[-2:])
- else:
- image_shape = [None, 3, 640, 640]
- if getattr(self, 'test_transforms', None):
- for idx, op in enumerate(self.test_transforms.transforms):
- name = op.__class__.__name__
- if name == 'Resize':
- image_shape = [None, 3] + list(
- self.test_transforms.transforms[idx].target_size)
- logging.warning(
- '[Important!!!] When exporting inference model for {},'.format(
- self.__class__.__name__) +
- ' if fixed_input_shape is not set, it will be forcibly set to {}. '.
- format(image_shape) +
- 'Please check image shape after transforms is {}, if not, fixed_input_shape '.
- format(image_shape[1:]) + 'should be specified manually.')
- self.fixed_input_shape = image_shape
- return self._define_input_spec(image_shape)
- class MaskRCNN(BaseDetector):
- def __init__(self,
- num_classes=80,
- backbone='ResNet50_vd',
- with_fpn=True,
- with_dcn=False,
- aspect_ratios=[0.5, 1.0, 2.0],
- anchor_sizes=[[32], [64], [128], [256], [512]],
- keep_top_k=100,
- nms_threshold=0.5,
- score_threshold=0.05,
- fpn_num_channels=256,
- rpn_batch_size_per_im=256,
- rpn_fg_fraction=0.5,
- test_pre_nms_top_n=None,
- test_post_nms_top_n=1000,
- **params):
- self.init_params = locals()
- if backbone not in {
- 'ResNet50', 'ResNet50_vd', 'ResNet50_vd_ssld', 'ResNet101',
- 'ResNet101_vd'
- }:
- raise ValueError(
- "backbone: {} is not supported. Please choose one of "
- "{'ResNet50', 'ResNet50_vd', 'ResNet50_vd_ssld', 'ResNet101', 'ResNet101_vd'}.".
- format(backbone))
- self.backbone_name = backbone + '_fpn' if with_fpn else backbone
- dcn_v2_stages = [1, 2, 3] if with_dcn else [-1]
- if params.get('with_net', True):
- if backbone == 'ResNet50':
- if with_fpn:
- backbone = self._get_backbone(
- 'ResNet',
- norm_type='bn',
- freeze_at=0,
- return_idx=[0, 1, 2, 3],
- num_stages=4,
- dcn_v2_stages=dcn_v2_stages)
- else:
- if with_dcn:
- logging.warning(
- "Backbone {} should be used along with dcn disabled, 'with_dcn' is forcibly set to False".
- format(backbone))
- backbone = self._get_backbone(
- 'ResNet',
- norm_type='bn',
- freeze_at=0,
- return_idx=[2],
- num_stages=3)
- elif 'ResNet50_vd' in backbone:
- if not with_fpn:
- logging.warning(
- "Backbone {} should be used along with fpn enabled, 'with_fpn' is forcibly set to True".
- format(backbone))
- with_fpn = True
- backbone = self._get_backbone(
- 'ResNet',
- variant='d',
- norm_type='bn',
- freeze_at=0,
- return_idx=[0, 1, 2, 3],
- num_stages=4,
- lr_mult_list=[0.05, 0.05, 0.1, 0.15]
- if '_ssld' in backbone else [1.0, 1.0, 1.0, 1.0],
- dcn_v2_stages=dcn_v2_stages)
- else:
- if not with_fpn:
- logging.warning(
- "Backbone {} should be used along with fpn enabled, 'with_fpn' is forcibly set to True".
- format(backbone))
- with_fpn = True
- backbone = self._get_backbone(
- 'ResNet',
- variant='d' if '_vd' in backbone else 'b',
- depth=101,
- norm_type='bn',
- freeze_at=0,
- return_idx=[0, 1, 2, 3],
- num_stages=4,
- dcn_v2_stages=dcn_v2_stages)
- rpn_in_channel = backbone.out_shape[0].channels
- if with_fpn:
- neck = ppdet.modeling.FPN(
- in_channels=[i.channels for i in backbone.out_shape],
- out_channel=fpn_num_channels,
- spatial_scales=[
- 1.0 / i.stride for i in backbone.out_shape
- ])
- rpn_in_channel = neck.out_shape[0].channels
- anchor_generator_cfg = {
- 'aspect_ratios': aspect_ratios,
- 'anchor_sizes': anchor_sizes,
- 'strides': [4, 8, 16, 32, 64]
- }
- train_proposal_cfg = {
- 'min_size': 0.0,
- 'nms_thresh': .7,
- 'pre_nms_top_n': 2000,
- 'post_nms_top_n': 1000,
- 'topk_after_collect': True
- }
- test_proposal_cfg = {
- 'min_size': 0.0,
- 'nms_thresh': .7,
- 'pre_nms_top_n': 1000
- if test_pre_nms_top_n is None else test_pre_nms_top_n,
- 'post_nms_top_n': test_post_nms_top_n
- }
- bb_head = ppdet.modeling.TwoFCHead(
- in_channel=neck.out_shape[0].channels, out_channel=1024)
- bb_roi_extractor_cfg = {
- 'resolution': 7,
- 'spatial_scale': [1. / i.stride for i in neck.out_shape],
- 'sampling_ratio': 0,
- 'aligned': True
- }
- with_pool = False
- m_head = ppdet.modeling.MaskFeat(
- in_channel=neck.out_shape[0].channels,
- out_channel=256,
- num_convs=4)
- m_roi_extractor_cfg = {
- 'resolution': 14,
- 'spatial_scale': [1. / i.stride for i in neck.out_shape],
- 'sampling_ratio': 0,
- 'aligned': True
- }
- mask_assigner = MaskAssigner(
- num_classes=num_classes, mask_resolution=28)
- share_bbox_feat = False
- else:
- neck = None
- anchor_generator_cfg = {
- 'aspect_ratios': aspect_ratios,
- 'anchor_sizes': anchor_sizes,
- 'strides': [16]
- }
- train_proposal_cfg = {
- 'min_size': 0.0,
- 'nms_thresh': .7,
- 'pre_nms_top_n': 12000,
- 'post_nms_top_n': 2000,
- 'topk_after_collect': False
- }
- test_proposal_cfg = {
- 'min_size': 0.0,
- 'nms_thresh': .7,
- 'pre_nms_top_n': 6000
- if test_pre_nms_top_n is None else test_pre_nms_top_n,
- 'post_nms_top_n': test_post_nms_top_n
- }
- bb_head = ppdet.modeling.Res5Head()
- bb_roi_extractor_cfg = {
- 'resolution': 14,
- 'spatial_scale':
- [1. / i.stride for i in backbone.out_shape],
- 'sampling_ratio': 0,
- 'aligned': True
- }
- with_pool = True
- m_head = ppdet.modeling.MaskFeat(
- in_channel=bb_head.out_shape[0].channels,
- out_channel=256,
- num_convs=0)
- m_roi_extractor_cfg = {
- 'resolution': 14,
- 'spatial_scale':
- [1. / i.stride for i in backbone.out_shape],
- 'sampling_ratio': 0,
- 'aligned': True
- }
- mask_assigner = MaskAssigner(
- num_classes=num_classes, mask_resolution=14)
- share_bbox_feat = True
- rpn_target_assign_cfg = {
- 'batch_size_per_im': rpn_batch_size_per_im,
- 'fg_fraction': rpn_fg_fraction,
- 'negative_overlap': .3,
- 'positive_overlap': .7,
- 'use_random': True
- }
- rpn_head = ppdet.modeling.RPNHead(
- anchor_generator=anchor_generator_cfg,
- rpn_target_assign=rpn_target_assign_cfg,
- train_proposal=train_proposal_cfg,
- test_proposal=test_proposal_cfg,
- in_channel=rpn_in_channel)
- bbox_assigner = BBoxAssigner(num_classes=num_classes)
- bbox_head = ppdet.modeling.BBoxHead(
- head=bb_head,
- in_channel=bb_head.out_shape[0].channels,
- roi_extractor=bb_roi_extractor_cfg,
- with_pool=with_pool,
- bbox_assigner=bbox_assigner,
- num_classes=num_classes)
- mask_head = ppdet.modeling.MaskHead(
- head=m_head,
- roi_extractor=m_roi_extractor_cfg,
- mask_assigner=mask_assigner,
- share_bbox_feat=share_bbox_feat,
- num_classes=num_classes)
- bbox_post_process = ppdet.modeling.BBoxPostProcess(
- num_classes=num_classes,
- decode=ppdet.modeling.RCNNBox(num_classes=num_classes),
- nms=ppdet.modeling.MultiClassNMS(
- score_threshold=score_threshold,
- keep_top_k=keep_top_k,
- nms_threshold=nms_threshold))
- mask_post_process = ppdet.modeling.MaskPostProcess(binary_thresh=.5)
- params.update({
- 'backbone': backbone,
- 'neck': neck,
- 'rpn_head': rpn_head,
- 'bbox_head': bbox_head,
- 'mask_head': mask_head,
- 'bbox_post_process': bbox_post_process,
- 'mask_post_process': mask_post_process
- })
- self.with_fpn = with_fpn
- super(MaskRCNN, self).__init__(
- model_name='MaskRCNN', num_classes=num_classes, **params)
- def _pre_train(self, in_args):
- train_dataset = in_args['train_dataset']
- if train_dataset.pos_num < len(train_dataset.file_list):
-
- train_dataset.num_workers = 0
- return in_args
- def _compose_batch_transform(self, transforms, mode='train'):
- if mode == 'train':
- default_batch_transforms = [
- _BatchPad(pad_to_stride=32 if self.with_fpn else -1)
- ]
- else:
- default_batch_transforms = [
- _BatchPad(pad_to_stride=32 if self.with_fpn else -1)
- ]
- custom_batch_transforms = []
- for i, op in enumerate(transforms.transforms):
- if isinstance(op, (BatchRandomResize, BatchRandomResizeByShort)):
- if mode != 'train':
- raise ValueError(
- "{} cannot be present in the {} transforms. ".format(
- op.__class__.__name__, mode) +
- "Please check the {} transforms.".format(mode))
- custom_batch_transforms.insert(0, copy.deepcopy(op))
- batch_transforms = BatchCompose(
- custom_batch_transforms + default_batch_transforms,
- collate_batch=False)
- return batch_transforms
- def _fix_transforms_shape(self, image_shape):
- if getattr(self, 'test_transforms', None):
- has_resize_op = False
- resize_op_idx = -1
- normalize_op_idx = len(self.test_transforms.transforms)
- for idx, op in enumerate(self.test_transforms.transforms):
- name = op.__class__.__name__
- if name == 'ResizeByShort':
- has_resize_op = True
- resize_op_idx = idx
- if name == 'Normalize':
- normalize_op_idx = idx
- if not has_resize_op:
- self.test_transforms.transforms.insert(
- normalize_op_idx,
- Resize(
- target_size=image_shape,
- keep_ratio=True,
- interp='CUBIC'))
- else:
- self.test_transforms.transforms[resize_op_idx] = Resize(
- target_size=image_shape, keep_ratio=True, interp='CUBIC')
- self.test_transforms.transforms.append(
- Pad(im_padding_value=[0., 0., 0.]))
- def _get_test_inputs(self, image_shape):
- if image_shape is not None:
- image_shape = self._check_image_shape(image_shape)
- self._fix_transforms_shape(image_shape[-2:])
- else:
- image_shape = [None, 3, -1, -1]
- if self.with_fpn:
- self.test_transforms.transforms.append(
- Pad(im_padding_value=[0., 0., 0.]))
- self.fixed_input_shape = image_shape
- return self._define_input_spec(image_shape)
|