Skip to content

Commit 81557da

Browse files
authored
[Cherry-pick] Add new func/class API psroi_pool and UT (#36111)
cherry-pick from #35352 Add new detection api paddle.vision.ops.psroi_pool and paddle.vision.ops.PSRoIPool
1 parent 6891134 commit 81557da

File tree

6 files changed

+526
-120
lines changed

6 files changed

+526
-120
lines changed

paddle/fluid/operators/psroi_pool_op.cc

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,26 @@ class PSROIPoolOpMaker : public framework::OpProtoAndCheckerMaker {
2525
public:
2626
void Make() override {
2727
AddInput("X",
28-
"Tensor, "
28+
"(Tensor), "
2929
"the input of PSROIPoolOp. "
3030
"The format of input tensor is NCHW. Where N is the batch size, "
3131
"C is the number of input channels, "
3232
"H is the height of the input feature map, and "
3333
"W is the width. The data type can be float32 or float64");
3434
AddInput("ROIs",
35-
"LoDTensor, "
35+
"(LoDTensor), "
3636
"ROIs (Regions of Interest) to pool over. "
3737
"should be a 2-D LoDTensor of shape (num_rois, 4) "
3838
"given as [(x1, y1, x2, y2), ...]. "
3939
"where (x1, y1) is the top left coordinates, and "
4040
"(x2, y2) is the bottom right coordinates. "
4141
"The roi batch index can be calculated from LoD.");
42+
AddInput("RoisNum",
43+
"(Tensor), "
44+
"The number of RoIs in each image.")
45+
.AsDispensable();
4246
AddOutput("Out",
43-
"Tensor, "
47+
"(Tensor), "
4448
"the output of PSROIPoolOp is a 4-D Tensor with shape "
4549
"(num_rois, output_channels, pooled_h, pooled_w). "
4650
"The data type is the same as `x` ");
@@ -65,8 +69,6 @@ class PSROIPoolOpMaker : public framework::OpProtoAndCheckerMaker {
6569
"the pooled output width.")
6670
.SetDefault(1);
6771
AddComment(R"Doc(
68-
**PSROIPool Operator,** `rois` **of this op should be a LoDTensor**
69-
7072
Position sensitive region of interest pooling (also known as PSROIPooling) is to perform
7173
position-sensitive average pooling on regions of interest specified by input, takes as
7274
input N position-sensitive score maps and a list of num_rois regions of interest.
@@ -106,7 +108,14 @@ class PSROIPoolOp : public framework::OperatorWithKernel {
106108
platform::errors::InvalidArgument(
107109
"ROIs should be a 2-D LoDTensor of shape (num_rois, 4) "
108110
"given as [(x1, y1, x2, y2), ...]"));
109-
111+
if (ctx->HasInput("RoisNum")) {
112+
auto rois_num_dims = ctx->GetInputDim("RoisNum");
113+
PADDLE_ENFORCE_EQ(rois_num_dims.size(), 1,
114+
platform::errors::InvalidArgument(
115+
"The second dimension of RoisNum should "
116+
"be 1, but received dimension is %d",
117+
rois_num_dims.size()));
118+
}
110119
int pooled_height = ctx->Attrs().Get<int>("pooled_height");
111120
int pooled_width = ctx->Attrs().Get<int>("pooled_width");
112121
int output_channels = ctx->Attrs().Get<int>("output_channels");
@@ -184,6 +193,7 @@ class PSROIPoolGradMaker : public framework::SingleGradOpMaker<T> {
184193
op->SetType("psroi_pool_grad");
185194
op->SetInput("X", this->Input("X"));
186195
op->SetInput("ROIs", this->Input("ROIs"));
196+
op->SetInput("RoisNum", this->Input("RoisNum"));
187197
op->SetInput(framework::GradVarName("Out"), this->OutputGrad("Out"));
188198
op->SetOutput(framework::GradVarName("X"), this->InputGrad("X"));
189199
op->SetAttrMap(this->Attrs());

paddle/fluid/operators/psroi_pool_op.cu

Lines changed: 77 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -185,34 +185,67 @@ class GPUPSROIPoolOpKernel : public framework::OpKernel<T> {
185185

186186
int rois_num = rois->dims()[0];
187187
if (rois_num == 0) return;
188-
189-
auto rois_lod = rois->lod().back();
190-
int rois_batch_size = rois_lod.size() - 1;
191-
PADDLE_ENFORCE_EQ(rois_batch_size, batch_size,
192-
platform::errors::InvalidArgument(
193-
"The batch size of input(ROIs) and input(X) must be "
194-
"the same but received batch size of input(ROIs) and "
195-
"input(X) is %d and %d respectively.",
196-
rois_batch_size, batch_size));
197-
int rois_num_with_lod = rois_lod[rois_batch_size];
198-
PADDLE_ENFORCE_EQ(rois_num, rois_num_with_lod,
199-
platform::errors::InvalidArgument(
200-
"The number of rois from input(ROIs) and its LOD "
201-
"must be the same. Received rois %d of input(ROIs) "
202-
"but the number of rois %d from its LOD is %d",
203-
rois_num, rois_num_with_lod));
204-
205-
// set rois batch id
188+
int rois_batch_size;
206189
framework::Tensor rois_batch_id_list;
207190
rois_batch_id_list.Resize({rois_num});
208191
int* rois_batch_id_data =
209192
rois_batch_id_list.mutable_data<int>(platform::CPUPlace());
210-
for (int n = 0; n < rois_batch_size; ++n) {
211-
for (size_t i = rois_lod[n]; i < rois_lod[n + 1]; ++i) {
212-
rois_batch_id_data[i] = n;
193+
194+
if (ctx.HasInput("RoisNum")) {
195+
auto* rois_num_t = ctx.Input<Tensor>("RoisNum");
196+
rois_batch_size = rois_num_t->numel();
197+
auto* rois_num_data = rois_num_t->data<int>();
198+
PADDLE_ENFORCE_EQ(
199+
rois_batch_size, batch_size,
200+
platform::errors::InvalidArgument(
201+
"The batch size of input(ROIs) and input(X) must be "
202+
"the same but received batch size of input(ROIs) and "
203+
"input(X) is %d and %d respectively.",
204+
rois_batch_size, batch_size));
205+
std::vector<int> rois_num_list(rois_batch_size);
206+
memory::Copy(platform::CPUPlace(), rois_num_list.data(),
207+
BOOST_GET_CONST(platform::CUDAPlace, ctx.GetPlace()),
208+
rois_num_data, sizeof(int) * rois_batch_size, 0);
209+
int rois_num_count = 0;
210+
for (int i = 0; i < rois_batch_size; ++i) {
211+
rois_num_count += rois_num_list[i];
212+
}
213+
PADDLE_ENFORCE_EQ(
214+
rois_num_count, rois_num,
215+
platform::errors::InvalidArgument(
216+
"the rois_num from input and RoisNum must be the same"));
217+
int start = 0;
218+
for (int n = 0; n < rois_batch_size; ++n) {
219+
for (int i = start; i < start + rois_num_list[n]; ++i) {
220+
rois_batch_id_data[i] = n;
221+
}
222+
start += rois_num_list[n];
223+
}
224+
} else {
225+
auto rois_lod = rois->lod().back();
226+
rois_batch_size = rois_lod.size() - 1;
227+
PADDLE_ENFORCE_EQ(
228+
rois_batch_size, batch_size,
229+
platform::errors::InvalidArgument(
230+
"The batch size of input(ROIs) and input(X) must be "
231+
"the same but received batch size of input(ROIs) and "
232+
"input(X) is %d and %d respectively.",
233+
rois_batch_size, batch_size));
234+
int rois_num_with_lod = rois_lod[rois_batch_size];
235+
PADDLE_ENFORCE_EQ(rois_num, rois_num_with_lod,
236+
platform::errors::InvalidArgument(
237+
"The number of rois from input(ROIs) and its LOD "
238+
"must be the same. Received rois %d of input(ROIs) "
239+
"but the number of rois %d from its LOD is %d",
240+
rois_num, rois_num_with_lod));
241+
242+
// set rois batch id
243+
for (int n = 0; n < rois_batch_size; ++n) {
244+
for (size_t i = rois_lod[n]; i < rois_lod[n + 1]; ++i) {
245+
rois_batch_id_data[i] = n;
246+
}
213247
}
214248
}
215-
216249
framework::Tensor rois_batch_id_list_gpu;
217250
framework::TensorCopy(rois_batch_id_list, ctx.GetPlace(),
218251
ctx.device_context(), &rois_batch_id_list_gpu);
@@ -257,14 +290,30 @@ class GPUPSROIPoolGradOpKernel : public framework::OpKernel<T> {
257290
rois_batch_id_list.Resize({rois_num});
258291
int* rois_batch_id_data =
259292
rois_batch_id_list.mutable_data<int>(platform::CPUPlace());
260-
auto rois_lod = rois->lod().back();
261-
int rois_batch_size = rois_lod.size() - 1;
262-
for (int n = 0; n < rois_batch_size; ++n) {
263-
for (size_t i = rois_lod[n]; i < rois_lod[n + 1]; ++i) {
264-
rois_batch_id_data[i] = n;
293+
int rois_batch_size;
294+
if (ctx.HasInput("RoisNum")) {
295+
auto* rois_num_t = ctx.Input<Tensor>("RoisNum");
296+
rois_batch_size = rois_num_t->numel();
297+
std::vector<int> rois_num_list(rois_batch_size);
298+
memory::Copy(platform::CPUPlace(), rois_num_list.data(),
299+
BOOST_GET_CONST(platform::CUDAPlace, ctx.GetPlace()),
300+
rois_num_t->data<int>(), sizeof(int) * rois_batch_size, 0);
301+
int start = 0;
302+
for (int n = 0; n < rois_batch_size; ++n) {
303+
for (int i = start; i < start + rois_num_list[n]; ++i) {
304+
rois_batch_id_data[i] = n;
305+
}
306+
start += rois_num_list[n];
307+
}
308+
} else {
309+
auto rois_lod = rois->lod().back();
310+
rois_batch_size = rois_lod.size() - 1;
311+
for (int n = 0; n < rois_batch_size; ++n) {
312+
for (size_t i = rois_lod[n]; i < rois_lod[n + 1]; ++i) {
313+
rois_batch_id_data[i] = n;
314+
}
265315
}
266316
}
267-
268317
framework::Tensor rois_batch_id_list_gpu;
269318
framework::TensorCopy(rois_batch_id_list, ctx.GetPlace(),
270319
ctx.device_context(), &rois_batch_id_list_gpu);

paddle/fluid/operators/psroi_pool_op.h

Lines changed: 71 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@ class CPUPSROIPoolOpKernel : public framework::OpKernel<T> {
4040
int width = in_dims[3];
4141
int rois_num = rois->dims()[0];
4242

43+
PADDLE_ENFORCE_EQ(input_channels,
44+
output_channels * pooled_height * pooled_width,
45+
platform::errors::InvalidArgument(
46+
"the channels of input "
47+
"X should equal the product of "
48+
"output_channels x pooled_height x pooled_width"));
49+
4350
auto in_stride = framework::stride(in_dims);
4451
auto out_stride = framework::stride(out->dims());
4552

@@ -49,32 +56,52 @@ class CPUPSROIPoolOpKernel : public framework::OpKernel<T> {
4956
rois_batch_id_list.Resize({rois_num});
5057
int* rois_batch_id_data =
5158
rois_batch_id_list.mutable_data<int>(ctx.GetPlace());
52-
53-
auto rois_lod = rois->lod().back();
54-
int rois_batch_size = rois_lod.size() - 1;
55-
PADDLE_ENFORCE_EQ(
56-
rois_batch_size, batch_size,
57-
platform::errors::InvalidArgument("the rois_batch_size and input(X) "
58-
"batch_size should be the same."));
59-
int rois_num_with_lod = rois_lod[rois_batch_size];
60-
PADDLE_ENFORCE_EQ(rois_num_with_lod, rois_num,
61-
platform::errors::InvalidArgument(
62-
"the rois_num from input and lod must be the same"));
63-
64-
PADDLE_ENFORCE_EQ(input_channels,
65-
output_channels * pooled_height * pooled_width,
66-
platform::errors::InvalidArgument(
67-
"the channels of input "
68-
"X should equal the product of "
69-
"output_channels x pooled_height x pooled_width"));
70-
71-
// calculate batch id index for each roi according to LoD
72-
for (int n = 0; n < rois_batch_size; ++n) {
73-
for (size_t i = rois_lod[n]; i < rois_lod[n + 1]; ++i) {
74-
rois_batch_id_data[i] = n;
59+
int rois_batch_size;
60+
if (ctx.HasInput("RoisNum")) {
61+
auto* rois_num_t = ctx.Input<framework::Tensor>("RoisNum");
62+
rois_batch_size = rois_num_t->numel();
63+
auto* rois_num_data = rois_num_t->data<int>();
64+
PADDLE_ENFORCE_EQ(
65+
rois_batch_size, batch_size,
66+
platform::errors::InvalidArgument(
67+
"The batch size of rois and the batch size of images "
68+
" must be the same. But received the batch size of rois is %d, "
69+
"and the batch size of images is %d",
70+
rois_batch_size, batch_size));
71+
int rois_num_count = 0;
72+
for (int i = 0; i < rois_batch_size; ++i) {
73+
rois_num_count += rois_num_data[i];
74+
}
75+
PADDLE_ENFORCE_EQ(
76+
rois_num_count, rois_num,
77+
platform::errors::InvalidArgument(
78+
"the rois_num from input and RoisNum must be the same"));
79+
int start = 0;
80+
for (int n = 0; n < rois_batch_size; ++n) {
81+
for (int i = start; i < start + rois_num_data[n]; ++i) {
82+
rois_batch_id_data[i] = n;
83+
}
84+
start += rois_num_data[n];
85+
}
86+
} else {
87+
auto rois_lod = rois->lod().back();
88+
rois_batch_size = rois_lod.size() - 1;
89+
PADDLE_ENFORCE_EQ(
90+
rois_batch_size, batch_size,
91+
platform::errors::InvalidArgument("the rois_batch_size and input(X) "
92+
"batch_size should be the same."));
93+
int rois_num_with_lod = rois_lod[rois_batch_size];
94+
PADDLE_ENFORCE_EQ(
95+
rois_num_with_lod, rois_num,
96+
platform::errors::InvalidArgument(
97+
"the rois_num from input and lod must be the same"));
98+
// calculate batch id index for each roi according to LoD
99+
for (int n = 0; n < rois_batch_size; ++n) {
100+
for (size_t i = rois_lod[n]; i < rois_lod[n + 1]; ++i) {
101+
rois_batch_id_data[i] = n;
102+
}
75103
}
76104
}
77-
78105
T* output_data = out->mutable_data<T>(ctx.GetPlace());
79106
const T* input_rois = rois->data<T>();
80107

@@ -93,7 +120,6 @@ class CPUPSROIPoolOpKernel : public framework::OpKernel<T> {
93120
static_cast<T>(round(offset_input_rois[2]) + 1.) * spatial_scale;
94121
T roi_end_h =
95122
static_cast<T>(round(offset_input_rois[3]) + 1.) * spatial_scale;
96-
97123
// Force too small rois to be 1 x 1
98124
T roi_height = std::max(roi_end_h - roi_start_h, (T)0.1); // avoid 0
99125
T roi_width = std::max(roi_end_w - roi_start_w, (T)0.1);
@@ -172,15 +198,28 @@ class CPUPSROIPoolGradOpKernel : public framework::OpKernel<T> {
172198
rois_batch_id_list.Resize({rois_num});
173199
int* rois_batch_id_data =
174200
rois_batch_id_list.mutable_data<int>(ctx.GetPlace());
175-
auto rois_lod = rois->lod().back();
176-
int rois_batch_size = rois_lod.size() - 1;
177-
// calculate batch id index for each roi according to LoD
178-
for (int n = 0; n < rois_batch_size; ++n) {
179-
for (size_t i = rois_lod[n]; i < rois_lod[n + 1]; ++i) {
180-
rois_batch_id_data[i] = n;
201+
int rois_batch_size;
202+
if (ctx.HasInput("RoisNum")) {
203+
auto* rois_num_t = ctx.Input<framework::Tensor>("RoisNum");
204+
rois_batch_size = rois_num_t->numel();
205+
auto* rois_num_data = rois_num_t->data<int>();
206+
int start = 0;
207+
for (int n = 0; n < rois_batch_size; ++n) {
208+
for (int i = start; i < start + rois_num_data[n]; ++i) {
209+
rois_batch_id_data[i] = n;
210+
}
211+
start += rois_num_data[n];
212+
}
213+
} else {
214+
auto rois_lod = rois->lod().back();
215+
rois_batch_size = rois_lod.size() - 1;
216+
// calculate batch id index for each roi according to LoD
217+
for (int n = 0; n < rois_batch_size; ++n) {
218+
for (size_t i = rois_lod[n]; i < rois_lod[n + 1]; ++i) {
219+
rois_batch_id_data[i] = n;
220+
}
181221
}
182222
}
183-
184223
const T* input_rois = rois->data<T>();
185224
const T* output_grad_data = output_grad->data<T>();
186225
T* input_grad_data = input_grad->mutable_data<T>(ctx.GetPlace());

paddle/fluid/pybind/op_function_generator.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ std::map<std::string, std::set<std::string>> op_ins_map = {
5454
{"gather", {"X", "Index", "Axis"}},
5555
{"roi_pool", {"X", "ROIs", "RoisNum"}},
5656
{"roi_align", {"X", "ROIs", "RoisNum"}},
57+
{"psroi_pool", {"X", "ROIs", "RoisNum"}},
5758
{"collect_fpn_proposals",
5859
{"MultiLevelRois", "MultiLevelScores", "MultiLevelRoIsNum"}},
5960
{"distribute_fpn_proposals", {"FpnRois", "RoisNum"}},

0 commit comments

Comments
 (0)