Skip to content

Commit a66afe0

Browse files
baiyfqingqing01
authored andcommitted
Expose prior_box op into detection.py (#10773)
* package prior_box op * add doc * add unittest * add unittest * fix CI fails
1 parent 0ad9212 commit a66afe0

File tree

2 files changed

+114
-45
lines changed

2 files changed

+114
-45
lines changed

python/paddle/fluid/layers/detection.py

Lines changed: 96 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import math
2424

2525
__all__ = [
26+
'prior_box',
2627
'multi_box_head',
2728
'bipartite_match',
2829
'target_assign',
@@ -564,6 +565,98 @@ def __reshape_to_2d(var):
564565
return loss
565566

566567

568+
def prior_box(input,
569+
image,
570+
min_sizes,
571+
max_sizes=None,
572+
aspect_ratios=None,
573+
variance=[0.1, 0.1, 0.2, 0.2],
574+
flip=False,
575+
clip=False,
576+
steps=[0.0, 0.0],
577+
offset=0.5,
578+
name=None):
579+
"""
580+
**Prior box operator**
581+
582+
Generate prior boxes for SSD(Single Shot MultiBox Detector) algorithm.
583+
Each position of the input produce N prior boxes, N is determined by
584+
the count of min_sizes, max_sizes and aspect_ratios, The size of the
585+
box is in range(min_size, max_size) interval, which is generated in
586+
sequence according to the aspect_ratios.
587+
588+
Args:
589+
input(Variable): The Input Variables, the format is NCHW.
590+
image(Variable): The input image data of PriorBoxOp,
591+
the layout is NCHW.
592+
min_sizes(list|tuple): min sizes of generated prior boxes.
593+
max_sizes(list|tuple|None): max sizes of generated prior boxes.
594+
Default: None.
595+
aspect_ratios(list|tuple): the aspect ratios of generated prior
596+
boxes. Default: None.
597+
variance(list|tuple): the variances to be encoded in prior boxes.
598+
Default:[0.1, 0.1, 0.2, 0.2].
599+
flip(bool): Whether to flip aspect ratios. Default:False.
600+
clip(bool): Whether to clip out-of-boundary boxes. Default: False.
601+
step(list|turple): Prior boxes step across weight and height, If
602+
step[0] == 0.0/step[1] == 0.0, the prior boxes step across
603+
height/weight of the input will be automatically calculated.
604+
Default: [0.0]
605+
offset(float): Prior boxes center offset. Default: 0.5
606+
name(str): Name of the prior box op. Default: None.
607+
608+
Returns:
609+
boxes(Variable): the output prior boxes of PriorBox.
610+
The layout is [H, W, num_priors, 4].
611+
H is the height of input, W is the width of input,
612+
num_priors is the total
613+
box count of each position of input.
614+
Variances(Variable): the expanded variances of PriorBox.
615+
The layout is [H, W, num_priors, 4].
616+
H is the height of input, W is the width of input
617+
num_priors is the total
618+
box count of each position of input
619+
620+
621+
Examples:
622+
.. code-block:: python
623+
box, var = prior_box(
624+
input=conv1,
625+
image=images,
626+
min_sizes=[100.],
627+
flip=True,
628+
clip=True)
629+
"""
630+
helper = LayerHelper("prior_box", **locals())
631+
dtype = helper.input_dtype()
632+
633+
attrs = {
634+
'min_sizes': min_sizes,
635+
'aspect_ratios': aspect_ratios,
636+
'variances': variance,
637+
'flip': flip,
638+
'clip': clip,
639+
'step_w': steps[0],
640+
'step_h': steps[1],
641+
'offset': offset
642+
}
643+
if max_sizes is not None and len(max_sizes) > 0 and max_sizes[0] > 0:
644+
attrs['max_sizes'] = max_sizes
645+
646+
box = helper.create_tmp_variable(dtype)
647+
var = helper.create_tmp_variable(dtype)
648+
helper.append_op(
649+
type="prior_box",
650+
inputs={"Input": input,
651+
"Image": image},
652+
outputs={"Boxes": box,
653+
"Variances": var},
654+
attrs=attrs, )
655+
box.stop_gradient = True
656+
var.stop_gradient = True
657+
return box, var
658+
659+
567660
def multi_box_head(inputs,
568661
image,
569662
base_size,
@@ -660,47 +753,6 @@ def multi_box_head(inputs,
660753
clip=True)
661754
"""
662755

663-
def _prior_box_(input,
664-
image,
665-
min_sizes,
666-
max_sizes,
667-
aspect_ratios,
668-
variance,
669-
flip=False,
670-
clip=False,
671-
step_w=0.0,
672-
step_h=0.0,
673-
offset=0.5,
674-
name=None):
675-
helper = LayerHelper("prior_box", **locals())
676-
dtype = helper.input_dtype()
677-
678-
attrs = {
679-
'min_sizes': min_sizes,
680-
'aspect_ratios': aspect_ratios,
681-
'variances': variance,
682-
'flip': flip,
683-
'clip': clip,
684-
'step_w': step_w,
685-
'step_h': step_h,
686-
'offset': offset
687-
}
688-
if len(max_sizes) > 0 and max_sizes[0] > 0:
689-
attrs['max_sizes'] = max_sizes
690-
691-
box = helper.create_tmp_variable(dtype)
692-
var = helper.create_tmp_variable(dtype)
693-
helper.append_op(
694-
type="prior_box",
695-
inputs={"Input": input,
696-
"Image": image},
697-
outputs={"Boxes": box,
698-
"Variances": var},
699-
attrs=attrs, )
700-
box.stop_gradient = True
701-
var.stop_gradient = True
702-
return box, var
703-
704756
def _reshape_with_axis_(input, axis=1):
705757
if not (axis > 0 and axis < len(input.shape)):
706758
raise ValueError("The axis should be smaller than "
@@ -777,11 +829,10 @@ def _is_list_or_tuple_and_equal(data, length, err_info):
777829
aspect_ratio = aspect_ratios[i]
778830
if not _is_list_or_tuple_(aspect_ratio):
779831
aspect_ratio = [aspect_ratio]
832+
step = [step_w[i] if step_w else 0.0, step_h[i] if step_w else 0.0]
780833

781-
box, var = _prior_box_(input, image, min_size, max_size, aspect_ratio,
782-
variance, flip, clip, step_w[i]
783-
if step_w else 0.0, step_h[i]
784-
if step_w else 0.0, offset)
834+
box, var = prior_box(input, image, min_size, max_size, aspect_ratio,
835+
variance, flip, clip, step, offset)
785836

786837
box_results.append(box)
787838
var_results.append(var)

python/paddle/fluid/tests/test_detection.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,24 @@ def test_ssd_loss(self):
109109
print(str(program))
110110

111111

112+
class TestPriorBox(unittest.TestCase):
113+
def test_prior_box(self):
114+
data_shape = [3, 224, 224]
115+
images = fluid.layers.data(
116+
name='pixel', shape=data_shape, dtype='float32')
117+
conv1 = fluid.layers.conv2d(images, 3, 3, 2)
118+
box, var = layers.prior_box(
119+
input=conv1,
120+
image=images,
121+
min_sizes=[100.0],
122+
aspect_ratios=[1.],
123+
flip=True,
124+
clip=True)
125+
assert len(box.shape) == 4
126+
assert box.shape == var.shape
127+
assert box.shape[3] == 4
128+
129+
112130
class TestMultiBoxHead(unittest.TestCase):
113131
def test_multi_box_head(self):
114132
data_shape = [3, 224, 224]

0 commit comments

Comments
 (0)