Skip to content

Commit 4a55fb5

Browse files
shippingwangqingqing01
authored andcommitted
Add density_prior_box_op (#14226)
Density prior box operator for image detection model.
1 parent 9a6e239 commit 4a55fb5

File tree

7 files changed

+613
-0
lines changed

7 files changed

+613
-0
lines changed

paddle/fluid/API.spec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,7 @@ paddle.fluid.layers.hard_shrink ArgSpec(args=['x', 'threshold'], varargs=None, k
274274
paddle.fluid.layers.cumsum ArgSpec(args=['x', 'axis', 'exclusive', 'reverse'], varargs=None, keywords=None, defaults=(None, None, None))
275275
paddle.fluid.layers.thresholded_relu ArgSpec(args=['x', 'threshold'], varargs=None, keywords=None, defaults=(None,))
276276
paddle.fluid.layers.prior_box ArgSpec(args=['input', 'image', 'min_sizes', 'max_sizes', 'aspect_ratios', 'variance', 'flip', 'clip', 'steps', 'offset', 'name', 'min_max_aspect_ratios_order'], varargs=None, keywords=None, defaults=(None, [1.0], [0.1, 0.1, 0.2, 0.2], False, False, [0.0, 0.0], 0.5, None, False))
277+
paddle.fluid.layers.density_prior_box ArgSpec(args=['input', 'image', 'densities', 'fixed_sizes', 'fixed_ratios', 'variance', 'clip', 'steps', 'offset', 'name'], varargs=None, keywords=None, defaults=(None, None, None, [0.1, 0.1, 0.2, 0.2], False, [0.0, 0.0], 0.5, None))
277278
paddle.fluid.layers.multi_box_head ArgSpec(args=['inputs', 'image', 'base_size', 'num_classes', 'aspect_ratios', 'min_ratio', 'max_ratio', 'min_sizes', 'max_sizes', 'steps', 'step_w', 'step_h', 'offset', 'variance', 'flip', 'clip', 'kernel_size', 'pad', 'stride', 'name', 'min_max_aspect_ratios_order'], varargs=None, keywords=None, defaults=(None, None, None, None, None, None, None, 0.5, [0.1, 0.1, 0.2, 0.2], True, False, 1, 0, 1, None, False))
278279
paddle.fluid.layers.bipartite_match ArgSpec(args=['dist_matrix', 'match_type', 'dist_threshold', 'name'], varargs=None, keywords=None, defaults=(None, None, None))
279280
paddle.fluid.layers.target_assign ArgSpec(args=['input', 'matched_indices', 'negative_indices', 'mismatch_value', 'name'], varargs=None, keywords=None, defaults=(None, None, None))

paddle/fluid/operators/detection/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ iou_similarity_op.cu)
2222
detection_library(mine_hard_examples_op SRCS mine_hard_examples_op.cc)
2323
detection_library(multiclass_nms_op SRCS multiclass_nms_op.cc poly_util.cc gpc.cc)
2424
detection_library(prior_box_op SRCS prior_box_op.cc prior_box_op.cu)
25+
detection_library(density_prior_box_op SRCS density_prior_box_op.cc)
2526
detection_library(anchor_generator_op SRCS anchor_generator_op.cc
2627
anchor_generator_op.cu)
2728
detection_library(target_assign_op SRCS target_assign_op.cc
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
/*Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
2+
Licensed under the Apache License, Version 2.0 (the "License");
3+
you may not use this file except in compliance with the License.
4+
You may obtain a copy of the License at
5+
http://www.apache.org/licenses/LICENSE-2.0
6+
Unless required by applicable law or agreed to in writing, software
7+
distributed under the License is distributed on an "AS IS" BASIS,
8+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9+
See the License for the specific language governing permissions and
10+
limitations under the License. */
11+
12+
#include "paddle/fluid/operators/detection/density_prior_box_op.h"
13+
14+
namespace paddle {
15+
namespace operators {
16+
17+
class DensityPriorBoxOp : public framework::OperatorWithKernel {
18+
public:
19+
using framework::OperatorWithKernel::OperatorWithKernel;
20+
21+
void InferShape(framework::InferShapeContext* ctx) const override {
22+
PADDLE_ENFORCE(ctx->HasInput("Input"),
23+
"Input(Input) of DensityPriorBoxOp should not be null.");
24+
PADDLE_ENFORCE(ctx->HasInput("Image"),
25+
"Input(Image) of DensityPriorBoxOp should not be null.");
26+
27+
auto image_dims = ctx->GetInputDim("Image");
28+
auto input_dims = ctx->GetInputDim("Input");
29+
PADDLE_ENFORCE(image_dims.size() == 4, "The layout of image is NCHW.");
30+
PADDLE_ENFORCE(input_dims.size() == 4, "The layout of input is NCHW.");
31+
32+
PADDLE_ENFORCE_LT(input_dims[2], image_dims[2],
33+
"The height of input must smaller than image.");
34+
35+
PADDLE_ENFORCE_LT(input_dims[3], image_dims[3],
36+
"The width of input must smaller than image.");
37+
auto variances = ctx->Attrs().Get<std::vector<float>>("variances");
38+
39+
auto fixed_sizes = ctx->Attrs().Get<std::vector<float>>("fixed_sizes");
40+
auto fixed_ratios = ctx->Attrs().Get<std::vector<float>>("fixed_ratios");
41+
auto densities = ctx->Attrs().Get<std::vector<int>>("densities");
42+
43+
PADDLE_ENFORCE_EQ(fixed_sizes.size(), densities.size(),
44+
"The number of fixed_sizes and densities must be equal.");
45+
size_t num_priors = 0;
46+
if ((fixed_sizes.size() > 0) && (densities.size() > 0)) {
47+
for (size_t i = 0; i < densities.size(); ++i) {
48+
if (fixed_ratios.size() > 0) {
49+
num_priors += (fixed_ratios.size()) * (pow(densities[i], 2));
50+
}
51+
}
52+
}
53+
std::vector<int64_t> dim_vec(4);
54+
dim_vec[0] = input_dims[2];
55+
dim_vec[1] = input_dims[3];
56+
dim_vec[2] = num_priors;
57+
dim_vec[3] = 4;
58+
ctx->SetOutputDim("Boxes", framework::make_ddim(dim_vec));
59+
ctx->SetOutputDim("Variances", framework::make_ddim(dim_vec));
60+
}
61+
62+
protected:
63+
framework::OpKernelType GetExpectedKernelType(
64+
const framework::ExecutionContext& ctx) const override {
65+
return framework::OpKernelType(
66+
framework::ToDataType(ctx.Input<framework::Tensor>("Input")->type()),
67+
platform::CPUPlace());
68+
}
69+
};
70+
71+
class DensityPriorBoxOpMaker : public framework::OpProtoAndCheckerMaker {
72+
public:
73+
void Make() override {
74+
AddInput(
75+
"Input",
76+
"(Tensor, default Tensor<float>), "
77+
"the input feature data of DensityPriorBoxOp, the layout is NCHW.");
78+
AddInput("Image",
79+
"(Tensor, default Tensor<float>), "
80+
"the input image data of DensityPriorBoxOp, the layout is NCHW.");
81+
AddOutput("Boxes",
82+
"(Tensor, default Tensor<float>), the output prior boxes of "
83+
"DensityPriorBoxOp. The layout is [H, W, num_priors, 4]. "
84+
"H is the height of input, W is the width of input, num_priors "
85+
"is the box count of each position.");
86+
AddOutput("Variances",
87+
"(Tensor, default Tensor<float>), the expanded variances of "
88+
"DensityPriorBoxOp. The layout is [H, W, num_priors, 4]. "
89+
"H is the height of input, W is the width of input, num_priors "
90+
"is the box count of each position.");
91+
AddAttr<std::vector<float>>("variances",
92+
"(vector<float>) List of variances to be "
93+
"encoded in density prior boxes.")
94+
.AddCustomChecker([](const std::vector<float>& variances) {
95+
PADDLE_ENFORCE_EQ(variances.size(), 4,
96+
"Must and only provide 4 variance.");
97+
for (size_t i = 0; i < variances.size(); ++i) {
98+
PADDLE_ENFORCE_GT(variances[i], 0.0,
99+
"variance[%d] must be greater than 0.", i);
100+
}
101+
});
102+
AddAttr<bool>("clip", "(bool) Whether to clip out-of-boundary boxes.")
103+
.SetDefault(true);
104+
105+
AddAttr<float>(
106+
"step_w",
107+
"Density prior boxes step across width, 0.0 for auto calculation.")
108+
.SetDefault(0.0)
109+
.AddCustomChecker([](const float& step_w) {
110+
PADDLE_ENFORCE_GE(step_w, 0.0, "step_w should be larger than 0.");
111+
});
112+
AddAttr<float>(
113+
"step_h",
114+
"Density prior boxes step across height, 0.0 for auto calculation.")
115+
.SetDefault(0.0)
116+
.AddCustomChecker([](const float& step_h) {
117+
PADDLE_ENFORCE_GE(step_h, 0.0, "step_h should be larger than 0.");
118+
});
119+
120+
AddAttr<float>("offset",
121+
"(float) "
122+
"Density prior boxes center offset.")
123+
.SetDefault(0.5);
124+
AddAttr<std::vector<float>>("fixed_sizes",
125+
"(vector<float>) List of fixed sizes "
126+
"of generated density prior boxes.")
127+
.SetDefault(std::vector<float>{})
128+
.AddCustomChecker([](const std::vector<float>& fixed_sizes) {
129+
for (size_t i = 0; i < fixed_sizes.size(); ++i) {
130+
PADDLE_ENFORCE_GT(fixed_sizes[i], 0.0,
131+
"fixed_sizes[%d] should be larger than 0.", i);
132+
}
133+
});
134+
135+
AddAttr<std::vector<float>>("fixed_ratios",
136+
"(vector<float>) List of fixed ratios "
137+
"of generated density prior boxes.")
138+
.SetDefault(std::vector<float>{})
139+
.AddCustomChecker([](const std::vector<float>& fixed_ratios) {
140+
for (size_t i = 0; i < fixed_ratios.size(); ++i) {
141+
PADDLE_ENFORCE_GT(fixed_ratios[i], 0.0,
142+
"fixed_ratios[%d] should be larger than 0.", i);
143+
}
144+
});
145+
146+
AddAttr<std::vector<int>>("densities",
147+
"(vector<float>) List of densities "
148+
"of generated density prior boxes.")
149+
.SetDefault(std::vector<int>{})
150+
.AddCustomChecker([](const std::vector<int>& densities) {
151+
for (size_t i = 0; i < densities.size(); ++i) {
152+
PADDLE_ENFORCE_GT(densities[i], 0,
153+
"densities[%d] should be larger than 0.", i);
154+
}
155+
});
156+
AddComment(R"DOC(
157+
Density Prior box operator
158+
Each position of the input produce N density prior boxes, N is determined by
159+
the count of fixed_ratios, densities, the calculation of N is as follows:
160+
for density in densities:
161+
N += size(fixed_ratios)*density^2
162+
)DOC");
163+
}
164+
};
165+
166+
} // namespace operators
167+
} // namespace paddle
168+
169+
namespace ops = paddle::operators;
170+
REGISTER_OPERATOR(density_prior_box, ops::DensityPriorBoxOp,
171+
ops::DensityPriorBoxOpMaker,
172+
paddle::framework::EmptyGradOpMaker);
173+
174+
REGISTER_OP_CPU_KERNEL(density_prior_box, ops::DensityPriorBoxOpKernel<float>,
175+
ops::DensityPriorBoxOpKernel<double>);
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved.
2+
licensed under the Apache License, Version 2.0 (the "License");
3+
you may not use this file except in compliance with the License.
4+
You may obtain a copy of the License at
5+
http://www.apache.org/licenses/LICENSE-2.0
6+
Unless required by applicable law or agreed to in writing, software
7+
distributed under the License is distributed on an "AS IS" BASIS,
8+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9+
See the License for the specific language governing permissions and
10+
limitations under the License. */
11+
12+
#pragma once
13+
#include <algorithm>
14+
#include <vector>
15+
#include "paddle/fluid/operators/detection/prior_box_op.h"
16+
17+
namespace paddle {
18+
namespace operators {
19+
20+
template <typename T>
21+
class DensityPriorBoxOpKernel : public framework::OpKernel<T> {
22+
public:
23+
void Compute(const framework::ExecutionContext& ctx) const override {
24+
auto* input = ctx.Input<paddle::framework::Tensor>("Input");
25+
auto* image = ctx.Input<paddle::framework::Tensor>("Image");
26+
auto* boxes = ctx.Output<paddle::framework::Tensor>("Boxes");
27+
auto* vars = ctx.Output<paddle::framework::Tensor>("Variances");
28+
29+
auto variances = ctx.Attr<std::vector<float>>("variances");
30+
auto clip = ctx.Attr<bool>("clip");
31+
32+
auto fixed_sizes = ctx.Attr<std::vector<float>>("fixed_sizes");
33+
auto fixed_ratios = ctx.Attr<std::vector<float>>("fixed_ratios");
34+
auto densities = ctx.Attr<std::vector<int>>("densities");
35+
36+
T step_w = static_cast<T>(ctx.Attr<float>("step_w"));
37+
T step_h = static_cast<T>(ctx.Attr<float>("step_h"));
38+
T offset = static_cast<T>(ctx.Attr<float>("offset"));
39+
40+
auto img_width = image->dims()[3];
41+
auto img_height = image->dims()[2];
42+
43+
auto feature_width = input->dims()[3];
44+
auto feature_height = input->dims()[2];
45+
46+
T step_width, step_height;
47+
if (step_w == 0 || step_h == 0) {
48+
step_width = static_cast<T>(img_width) / feature_width;
49+
step_height = static_cast<T>(img_height) / feature_height;
50+
} else {
51+
step_width = step_w;
52+
step_height = step_h;
53+
}
54+
int num_priors = 0;
55+
if (fixed_sizes.size() > 0 && densities.size() > 0) {
56+
for (size_t i = 0; i < densities.size(); ++i) {
57+
if (fixed_ratios.size() > 0) {
58+
num_priors += (fixed_ratios.size()) * (pow(densities[i], 2));
59+
}
60+
}
61+
}
62+
63+
boxes->mutable_data<T>(ctx.GetPlace());
64+
vars->mutable_data<T>(ctx.GetPlace());
65+
auto e_boxes = framework::EigenTensor<T, 4>::From(*boxes).setConstant(0.0);
66+
67+
int step_average = static_cast<int>((step_width + step_height) * 0.5);
68+
69+
for (int h = 0; h < feature_height; ++h) {
70+
for (int w = 0; w < feature_width; ++w) {
71+
T center_x = (w + offset) * step_width;
72+
T center_y = (h + offset) * step_height;
73+
int idx = 0;
74+
// Generate density prior boxes with fixed sizes.
75+
for (size_t s = 0; s < fixed_sizes.size(); ++s) {
76+
auto fixed_size = fixed_sizes[s];
77+
int density = densities[s];
78+
// Generate density prior boxes with fixed ratios.
79+
if (fixed_ratios.size() > 0) {
80+
for (size_t r = 0; r < fixed_ratios.size(); ++r) {
81+
float ar = fixed_ratios[r];
82+
int shift = step_average / density;
83+
float box_width_ratio = fixed_size * sqrt(ar);
84+
float box_height_ratio = fixed_size / sqrt(ar);
85+
for (int di = 0; di < density; ++di) {
86+
for (int dj = 0; dj < density; ++dj) {
87+
float center_x_temp =
88+
center_x - step_average / 2. + shift / 2. + dj * shift;
89+
float center_y_temp =
90+
center_y - step_average / 2. + shift / 2. + di * shift;
91+
e_boxes(h, w, idx, 0) =
92+
(center_x_temp - box_width_ratio / 2.) / img_width >= 0
93+
? (center_x_temp - box_width_ratio / 2.) / img_width
94+
: 0;
95+
e_boxes(h, w, idx, 1) =
96+
(center_y_temp - box_height_ratio / 2.) / img_height >= 0
97+
? (center_y_temp - box_height_ratio / 2.) / img_height
98+
: 0;
99+
e_boxes(h, w, idx, 2) =
100+
(center_x_temp + box_width_ratio / 2.) / img_width <= 1
101+
? (center_x_temp + box_width_ratio / 2.) / img_width
102+
: 1;
103+
e_boxes(h, w, idx, 3) =
104+
(center_y_temp + box_height_ratio / 2.) / img_height <= 1
105+
? (center_y_temp + box_height_ratio / 2.) / img_height
106+
: 1;
107+
idx++;
108+
}
109+
}
110+
}
111+
}
112+
}
113+
}
114+
}
115+
if (clip) {
116+
platform::Transform<platform::CPUDeviceContext> trans;
117+
ClipFunctor<T> clip_func;
118+
trans(ctx.template device_context<platform::CPUDeviceContext>(),
119+
boxes->data<T>(), boxes->data<T>() + boxes->numel(),
120+
boxes->data<T>(), clip_func);
121+
}
122+
framework::Tensor var_t;
123+
var_t.mutable_data<T>(
124+
framework::make_ddim({1, static_cast<int>(variances.size())}),
125+
ctx.GetPlace());
126+
127+
auto var_et = framework::EigenTensor<T, 2>::From(var_t);
128+
129+
for (size_t i = 0; i < variances.size(); ++i) {
130+
var_et(0, i) = variances[i];
131+
}
132+
133+
int box_num = feature_height * feature_width * num_priors;
134+
auto var_dim = vars->dims();
135+
vars->Resize({box_num, static_cast<int>(variances.size())});
136+
137+
auto e_vars = framework::EigenMatrix<T, Eigen::RowMajor>::From(*vars);
138+
139+
e_vars = var_et.broadcast(Eigen::DSizes<int, 2>(box_num, 1));
140+
141+
vars->Resize(var_dim);
142+
}
143+
}; // namespace operators
144+
145+
} // namespace operators
146+
} // namespace paddle

0 commit comments

Comments
 (0)