diff --git a/python/paddle/fluid/evaluator.py b/python/paddle/fluid/evaluator.py index 5ac5450fae948fd1027bc7d1d6454348c4caf4be..5ea1d1e5358a29c235564fd1544c7eca5eb44637 100644 --- a/python/paddle/fluid/evaluator.py +++ b/python/paddle/fluid/evaluator.py @@ -23,10 +23,6 @@ from .layer_helper import LayerHelper from .initializer import Constant from .layers import detection -__all__ = [ - 'DetectionMAP', -] - def _clone_var_(block, var): assert isinstance(var, Variable) @@ -124,147 +120,3 @@ class Evaluator: ) self.states.append(state) return state - - -class DetectionMAP(Evaluator): - """ - Warning: This would be deprecated in the future. Please use fluid.metrics.DetectionMAP - instead. - Calculate the detection mean average precision (mAP). - - The general steps are as follows: - 1. calculate the true positive and false positive according to the input - of detection and labels. - 2. calculate mAP value, support two versions: '11 point' and 'integral'. - - Please get more information from the following articles: - https://sanchom.wordpress.com/tag/average-precision/ - https://arxiv.org/abs/1512.02325 - - Args: - input (Variable): The detection results, which is a LoDTensor with shape - [M, 6]. The layout is [label, confidence, xmin, ymin, xmax, ymax]. - gt_label (Variable): The ground truth label index, which is a LoDTensor - with shape [N, 1]. - gt_box (Variable): The ground truth bounding box (bbox), which is a - LoDTensor with shape [N, 4]. The layout is [xmin, ymin, xmax, ymax]. - gt_difficult (Variable|None): Whether this ground truth is a difficult - bounding bbox, which can be a LoDTensor [N, 1] or not set. If None, - it means all the ground truth labels are not difficult bbox. - class_num (int): The class number. - background_label (int): The index of background label, the background - label will be ignored. If set to -1, then all categories will be - considered, 0 by default. - overlap_threshold (float): The threshold for deciding true/false - positive, 0.5 by default. - evaluate_difficult (bool): Whether to consider difficult ground truth - for evaluation, True by default. This argument does not work when - gt_difficult is None. - ap_version (string): The average precision calculation ways, it must be - 'integral' or '11point'. Please check - https://sanchom.wordpress.com/tag/average-precision/ for details. - - 11point: the 11-point interpolated average precision. - - integral: the natural integral of the precision-recall curve. - - Examples: - .. code-block:: python - - exe = fluid.executor(place) - map_evaluator = fluid.Evaluator.DetectionMAP(input, - gt_label, gt_box, gt_difficult) - cur_map, accum_map = map_evaluator.get_map_var() - fetch = [cost, cur_map, accum_map] - for epoch in PASS_NUM: - map_evaluator.reset(exe) - for data in batches: - loss, cur_map_v, accum_map_v = exe.run(fetch_list=fetch) - - In the above example: - - 'cur_map_v' is the mAP of current mini-batch. - 'accum_map_v' is the accumulative mAP of one pass. - """ - - def __init__( - self, - input, - gt_label, - gt_box, - gt_difficult=None, - class_num=None, - background_label=0, - overlap_threshold=0.5, - evaluate_difficult=True, - ap_version='integral', - ): - super().__init__("map_eval") - - gt_label = layers.cast(x=gt_label, dtype=gt_box.dtype) - if gt_difficult: - gt_difficult = layers.cast(x=gt_difficult, dtype=gt_box.dtype) - label = layers.concat([gt_label, gt_difficult, gt_box], axis=1) - else: - label = layers.concat([gt_label, gt_box], axis=1) - - # calculate mean average precision (mAP) of current mini-batch - map = detection.detection_map( - input, - label, - class_num, - background_label, - overlap_threshold=overlap_threshold, - evaluate_difficult=evaluate_difficult, - ap_version=ap_version, - ) - - self._create_state(dtype='int32', shape=None, suffix='accum_pos_count') - self._create_state(dtype='float32', shape=None, suffix='accum_true_pos') - self._create_state( - dtype='float32', shape=None, suffix='accum_false_pos' - ) - - self.has_state = None - var = self.helper.create_variable( - persistable=True, dtype='int32', shape=[1] - ) - self.helper.set_variable_initializer( - var, initializer=Constant(value=int(0)) - ) - self.has_state = var - - # calculate accumulative mAP - accum_map = detection.detection_map( - input, - label, - class_num, - background_label, - overlap_threshold=overlap_threshold, - evaluate_difficult=evaluate_difficult, - has_state=self.has_state, - input_states=self.states, - out_states=self.states, - ap_version=ap_version, - ) - - layers.fill_constant( - shape=self.has_state.shape, - value=1, - dtype=self.has_state.dtype, - out=self.has_state, - ) - - self.cur_map = map - self.accum_map = accum_map - - def get_map_var(self): - return self.cur_map, self.accum_map - - def reset(self, executor, reset_program=None): - if reset_program is None: - reset_program = Program() - with program_guard(main_program=reset_program): - var = _clone_var_(reset_program.current_block(), self.has_state) - layers.fill_constant( - shape=var.shape, value=0, dtype=var.dtype, out=var - ) - executor.run(reset_program) diff --git a/python/paddle/fluid/layers/detection.py b/python/paddle/fluid/layers/detection.py index 9a0af76269a7b778c6b159490f3514de692f170b..5837d0b52e9f0bf322c4643fd5956644daf8a8b2 100644 --- a/python/paddle/fluid/layers/detection.py +++ b/python/paddle/fluid/layers/detection.py @@ -231,106 +231,6 @@ def polygon_box_transform(input, name=None): return output -@templatedoc() -def detection_map( - detect_res, - label, - class_num, - background_label=0, - overlap_threshold=0.3, - evaluate_difficult=True, - has_state=None, - input_states=None, - out_states=None, - ap_version='integral', -): - """ - ${comment} - - Args: - detect_res: ${detect_res_comment} - label: ${label_comment} - class_num: ${class_num_comment} - background_label: ${background_label_comment} - overlap_threshold: ${overlap_threshold_comment} - evaluate_difficult: ${evaluate_difficult_comment} - has_state: ${has_state_comment} - input_states: (tuple|None) If not None, It contains 3 elements: - (1) pos_count ${pos_count_comment}. - (2) true_pos ${true_pos_comment}. - (3) false_pos ${false_pos_comment}. - out_states: (tuple|None) If not None, it contains 3 elements. - (1) accum_pos_count ${accum_pos_count_comment}. - (2) accum_true_pos ${accum_true_pos_comment}. - (3) accum_false_pos ${accum_false_pos_comment}. - ap_version: ${ap_type_comment} - - Returns: - ${map_comment} - - - Examples: - .. code-block:: python - - import paddle.fluid as fluid - from fluid.layers import detection - detect_res = fluid.data( - name='detect_res', - shape=[10, 6], - dtype='float32') - label = fluid.data( - name='label', - shape=[10, 6], - dtype='float32') - - map_out = detection.detection_map(detect_res, label, 21) - """ - helper = LayerHelper("detection_map", **locals()) - - def __create_var(type): - return helper.create_variable_for_type_inference(dtype=type) - - map_out = __create_var('float32') - accum_pos_count_out = ( - out_states[0] if out_states is not None else __create_var('int32') - ) - accum_true_pos_out = ( - out_states[1] if out_states is not None else __create_var('float32') - ) - accum_false_pos_out = ( - out_states[2] if out_states is not None else __create_var('float32') - ) - - pos_count = input_states[0] if input_states is not None else None - true_pos = input_states[1] if input_states is not None else None - false_pos = input_states[2] if input_states is not None else None - - helper.append_op( - type="detection_map", - inputs={ - 'Label': label, - 'DetectRes': detect_res, - 'HasState': has_state, - 'PosCount': pos_count, - 'TruePos': true_pos, - 'FalsePos': false_pos, - }, - outputs={ - 'MAP': map_out, - 'AccumPosCount': accum_pos_count_out, - 'AccumTruePos': accum_true_pos_out, - 'AccumFalsePos': accum_false_pos_out, - }, - attrs={ - 'overlap_threshold': overlap_threshold, - 'evaluate_difficult': evaluate_difficult, - 'ap_type': ap_version, - 'class_num': class_num, - }, - ) - return map_out - - def prior_box( input, image, diff --git a/python/paddle/fluid/metrics.py b/python/paddle/fluid/metrics.py index 8e79a2429d3ac40d93f4c1b3222d651b40e74691..82921b9b60877ded96c132ed29c44e2c35914eb4 100644 --- a/python/paddle/fluid/metrics.py +++ b/python/paddle/fluid/metrics.py @@ -33,7 +33,6 @@ __all__ = [ 'Accuracy', 'ChunkEvaluator', 'EditDistance', - 'DetectionMAP', 'Auc', ] @@ -816,219 +815,3 @@ class Auc(MetricBase): return ( auc / tot_pos / tot_neg if tot_pos > 0.0 and tot_neg > 0.0 else 0.0 ) - - -class DetectionMAP: - """ - Calculate the detection mean average precision (mAP). - - The general steps are as follows: - - 1. calculate the true positive and false positive according to the input - of detection and labels. - 2. calculate mAP value, support two versions: '11 point' and 'integral'. - 11point: the 11-point interpolated average precision. - integral: the natural integral of the precision-recall curve. - - Please get more information from the following articles: - - https://sanchom.wordpress.com/tag/average-precision/ - - https://arxiv.org/abs/1512.02325 - - Args: - input (Variable): LoDTensor, The detection results, which is a LoDTensor with shape - [M, 6]. The layout is [label, confidence, xmin, ymin, xmax, ymax]. - The data type is float32 or float64. - gt_label (Variable): LoDTensor, The ground truth label index, which is a LoDTensor - with shape [N, 1].The data type is float32 or float64. - gt_box (Variable): LoDTensor, The ground truth bounding box (bbox), which is a - LoDTensor with shape [N, 4]. The layout is [xmin, ymin, xmax, ymax]. - The data type is float32 or float64. - gt_difficult (Variable|None): LoDTensor, Whether this ground truth is a difficult - bounding bbox, which can be a LoDTensor [N, 1] or not set. If None, - it means all the ground truth labels are not difficult bbox.The - data type is int. - class_num (int): The class number. - background_label (int): The index of background label, the background - label will be ignored. If set to -1, then all categories will be - considered, 0 by default. - overlap_threshold (float): The threshold for deciding true/false - positive, 0.5 by default. - evaluate_difficult (bool): Whether to consider difficult ground truth - for evaluation, True by default. This argument does not work when - gt_difficult is None. - ap_version (str): The average precision calculation ways, it must be - 'integral' or '11point'. Please check - https://sanchom.wordpress.com/tag/average-precision/ for details. - - Examples: - .. code-block:: python - - import paddle.fluid as fluid - - import paddle - paddle.enable_static() - - batch_size = None # can be any size - image_boxs_num = 10 - bounding_bboxes_num = 21 - - pb = fluid.data(name='prior_box', shape=[image_boxs_num, 4], - dtype='float32') - - pbv = fluid.data(name='prior_box_var', shape=[image_boxs_num, 4], - dtype='float32') - - loc = fluid.data(name='target_box', shape=[batch_size, bounding_bboxes_num, 4], - dtype='float32') - - scores = fluid.data(name='scores', shape=[batch_size, bounding_bboxes_num, image_boxs_num], - dtype='float32') - - nmsed_outs = fluid.layers.detection_output(scores=scores, - loc=loc, prior_box=pb, prior_box_var=pbv) - - gt_box = fluid.data(name="gt_box", shape=[batch_size, 4], dtype="float32") - gt_label = fluid.data(name="gt_label", shape=[batch_size, 1], dtype="float32") - difficult = fluid.data(name="difficult", shape=[batch_size, 1], dtype="float32") - - exe = fluid.Executor(fluid.CUDAPlace(0)) - map_evaluator = fluid.metrics.DetectionMAP(nmsed_outs, gt_label, gt_box, difficult, class_num = 3) - - cur_map, accum_map = map_evaluator.get_map_var() - - - """ - - def __init__( - self, - input, - gt_label, - gt_box, - gt_difficult=None, - class_num=None, - background_label=0, - overlap_threshold=0.5, - evaluate_difficult=True, - ap_version='integral', - ): - - self.helper = LayerHelper('map_eval') - gt_label = layers.cast(x=gt_label, dtype=gt_box.dtype) - if gt_difficult: - gt_difficult = layers.cast(x=gt_difficult, dtype=gt_box.dtype) - label = layers.concat([gt_label, gt_difficult, gt_box], axis=1) - else: - label = layers.concat([gt_label, gt_box], axis=1) - - # calculate mean average precision (mAP) of current mini-batch - map = detection.detection_map( - input, - label, - class_num, - background_label, - overlap_threshold=overlap_threshold, - evaluate_difficult=evaluate_difficult, - ap_version=ap_version, - ) - - states = [] - states.append( - self._create_state( - dtype='int32', shape=None, suffix='accum_pos_count' - ) - ) - states.append( - self._create_state( - dtype='float32', shape=None, suffix='accum_true_pos' - ) - ) - states.append( - self._create_state( - dtype='float32', shape=None, suffix='accum_false_pos' - ) - ) - var = self._create_state(dtype='int32', shape=[1], suffix='has_state') - self.helper.set_variable_initializer( - var, initializer=Constant(value=int(0)) - ) - self.has_state = var - - # calculate accumulative mAP - accum_map = detection.detection_map( - input, - label, - class_num, - background_label, - overlap_threshold=overlap_threshold, - evaluate_difficult=evaluate_difficult, - has_state=self.has_state, - input_states=states, - out_states=states, - ap_version=ap_version, - ) - - layers.fill_constant( - shape=self.has_state.shape, - value=1, - dtype=self.has_state.dtype, - out=self.has_state, - ) - - self.cur_map = map - self.accum_map = accum_map - - def _create_state(self, suffix, dtype, shape): - """ - Create state variable. - Args: - suffix(str): the state suffix. - dtype(str|core.VarDesc.VarType): the state data type - shape(tuple|list): the shape of state - Returns: State variable - """ - state = self.helper.create_variable( - name="_".join([unique_name.generate(self.helper.name), suffix]), - persistable=True, - dtype=dtype, - shape=shape, - ) - return state - - def get_map_var(self): - """ - Returns: mAP variable of current mini-batch and - accumulative mAP variable cross mini-batches. - """ - return self.cur_map, self.accum_map - - def reset(self, executor, reset_program=None): - """ - Reset metric states at the begin of each pass/user specified batch. - Args: - executor(Executor): a executor for executing - the reset_program. - reset_program(Program|None): a single Program for reset process. - If None, will create a Program. - """ - - def _clone_var_(block, var): - assert isinstance(var, Variable) - return block.create_var( - name=var.name, - shape=var.shape, - dtype=var.dtype, - type=var.type, - lod_level=var.lod_level, - persistable=var.persistable, - ) - - if reset_program is None: - reset_program = Program() - with program_guard(main_program=reset_program): - var = _clone_var_(reset_program.current_block(), self.has_state) - layers.fill_constant( - shape=var.shape, value=0, dtype=var.dtype, out=var - ) - executor.run(reset_program) diff --git a/python/paddle/fluid/tests/test_detection.py b/python/paddle/fluid/tests/test_detection.py index 23bcf526c7e33e319c17f0b268eb8f79b3486d52..c3edd1dc0d05698bf462390c4a8f17bb43d7510e 100644 --- a/python/paddle/fluid/tests/test_detection.py +++ b/python/paddle/fluid/tests/test_detection.py @@ -24,7 +24,6 @@ import paddle.fluid.layers as layers from paddle.fluid import core from paddle.fluid.dygraph import base from paddle.fluid.framework import Program, program_guard -from paddle.fluid.layers import detection paddle.enable_static() @@ -387,29 +386,6 @@ class TestMultiBoxHead(unittest.TestCase): return mbox_locs, mbox_confs, box, var -class TestDetectionMAP(unittest.TestCase): - def test_detection_map(self): - program = Program() - with program_guard(program): - detect_res = layers.data( - name='detect_res', - shape=[10, 6], - append_batch_size=False, - dtype='float32', - ) - label = layers.data( - name='label', - shape=[10, 6], - append_batch_size=False, - dtype='float32', - ) - - map_out = detection.detection_map(detect_res, label, 21) - self.assertIsNotNone(map_out) - self.assertEqual(map_out.shape, (1,)) - print(str(program)) - - class TestGenerateProposals(LayerTest): def test_generate_proposals(self): scores_np = np.random.rand(2, 3, 4, 4).astype('float32') diff --git a/python/paddle/fluid/tests/unittests/test_layers.py b/python/paddle/fluid/tests/unittests/test_layers.py index a3d684afa87dd08b6d0dd8535fc60131367d12e1..9bdd52c6b3d862e4b7bbbd9e4f406c6e43539146 100644 --- a/python/paddle/fluid/tests/unittests/test_layers.py +++ b/python/paddle/fluid/tests/unittests/test_layers.py @@ -2922,37 +2922,6 @@ class TestBook(LayerTest): ) -class TestMetricsDetectionMap(unittest.TestCase): - def test_detection_map(self): - program = fluid.Program() - with program_guard(program): - detect_res = fluid.layers.data( - name='detect_res', - shape=[10, 6], - append_batch_size=False, - dtype='float32', - ) - label = fluid.layers.data( - name='label', - shape=[10, 1], - append_batch_size=False, - dtype='float32', - ) - box = fluid.layers.data( - name='bbox', - shape=[10, 4], - append_batch_size=False, - dtype='float32', - ) - map_eval = fluid.metrics.DetectionMAP( - detect_res, label, box, class_num=21 - ) - cur_map, accm_map = map_eval.get_map_var() - self.assertIsNotNone(cur_map) - self.assertIsNotNone(accm_map) - print(str(program)) - - class ExampleNet(paddle.nn.Layer): def __init__(self): super().__init__()