commit
3ed8528a40
@ -0,0 +1,96 @@
|
|||||||
|
/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License. */
|
||||||
|
|
||||||
|
#include "paddle/operators/iou_similarity_op.h"
|
||||||
|
|
||||||
|
namespace paddle {
|
||||||
|
namespace operators {
|
||||||
|
|
||||||
|
class IOUSimilarityOp : public framework::OperatorWithKernel {
|
||||||
|
public:
|
||||||
|
using framework::OperatorWithKernel::OperatorWithKernel;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void InferShape(framework::InferShapeContext *ctx) const override {
|
||||||
|
PADDLE_ENFORCE(ctx->HasInput("X"),
|
||||||
|
"Input(X) of IOUSimilarityOp should not be null.");
|
||||||
|
PADDLE_ENFORCE(ctx->HasInput("Y"),
|
||||||
|
"Input(Y) of IOUSimilarityOp should not be null.");
|
||||||
|
auto x_dims = ctx->GetInputDim("X");
|
||||||
|
auto y_dims = ctx->GetInputDim("Y");
|
||||||
|
|
||||||
|
PADDLE_ENFORCE_EQ(x_dims.size(), 2UL, "The rank of Input(X) must be 2.");
|
||||||
|
PADDLE_ENFORCE_EQ(x_dims[1], 4UL, "The shape of X is [N, 4]");
|
||||||
|
PADDLE_ENFORCE_EQ(y_dims.size(), 2UL, "The rank of Input(Y) must be 2.");
|
||||||
|
PADDLE_ENFORCE_EQ(y_dims[1], 4UL, "The shape of Y is [M, 4]");
|
||||||
|
|
||||||
|
ctx->ShareLoD("X", /*->*/ "Out");
|
||||||
|
ctx->SetOutputDim("Out", framework::make_ddim({x_dims[0], y_dims[0]}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class IOUSimilarityOpMaker : public framework::OpProtoAndCheckerMaker {
|
||||||
|
public:
|
||||||
|
IOUSimilarityOpMaker(OpProto *proto, OpAttrChecker *op_checker)
|
||||||
|
: OpProtoAndCheckerMaker(proto, op_checker) {
|
||||||
|
AddInput("X",
|
||||||
|
"(LoDTensor, default LoDTensor<float>) "
|
||||||
|
"Box list X is a 2-D LoDTensor with shape [N, 4] holds N boxes, "
|
||||||
|
"each box is represented as [xmin, ymin, xmax, ymax], "
|
||||||
|
"the shape of X is [N, 4]. [xmin, ymin] is the left top "
|
||||||
|
"coordinate of the box if the input is image feature map, they "
|
||||||
|
"are close to the origin of the coordinate system. "
|
||||||
|
"[xmax, ymax] is the right bottom coordinate of the box. "
|
||||||
|
"This tensor can contain LoD information to represent a batch "
|
||||||
|
"of inputs. One instance of this batch can contain different "
|
||||||
|
"numbers of entities.");
|
||||||
|
AddInput("Y",
|
||||||
|
"(Tensor, default Tensor<float>) "
|
||||||
|
"Box list Y holds M boxes, each box is represented as "
|
||||||
|
"[xmin, ymin, xmax, ymax], the shape of X is [N, 4]. "
|
||||||
|
"[xmin, ymin] is the left top coordinate of the box if the "
|
||||||
|
"input is image feature map, and [xmax, ymax] is the right "
|
||||||
|
"bottom coordinate of the box.");
|
||||||
|
|
||||||
|
AddOutput("Out",
|
||||||
|
"(LoDTensor, the lod is same as input X) The output of "
|
||||||
|
"iou_similarity op, a tensor with shape [N, M] "
|
||||||
|
"representing pairwise iou scores.");
|
||||||
|
|
||||||
|
AddComment(R"DOC(
|
||||||
|
IOU Similarity Operator.
|
||||||
|
Computes intersection-over-union (IOU) between two box lists.
|
||||||
|
Box list 'X' should be a LoDTensor and 'Y' is a common Tensor,
|
||||||
|
boxes in 'Y' are shared by all instance of the batched inputs of X.
|
||||||
|
Given two boxes A and B, the calculation of IOU is as follows:
|
||||||
|
|
||||||
|
$$
|
||||||
|
IOU(A, B) =
|
||||||
|
\frac{area(A\cap B)}{area(A)+area(B)-area(A\cap B)}
|
||||||
|
$$
|
||||||
|
|
||||||
|
)DOC");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace operators
|
||||||
|
} // namespace paddle
|
||||||
|
|
||||||
|
namespace ops = paddle::operators;
|
||||||
|
REGISTER_OP_WITHOUT_GRADIENT(iou_similarity, ops::IOUSimilarityOp,
|
||||||
|
ops::IOUSimilarityOpMaker);
|
||||||
|
|
||||||
|
REGISTER_OP_CPU_KERNEL(
|
||||||
|
iou_similarity,
|
||||||
|
ops::IOUSimilarityKernel<paddle::platform::CPUDeviceContext, float>,
|
||||||
|
ops::IOUSimilarityKernel<paddle::platform::CPUDeviceContext, double>);
|
@ -0,0 +1,21 @@
|
|||||||
|
/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License. */
|
||||||
|
|
||||||
|
#include "paddle/operators/iou_similarity_op.h"
|
||||||
|
|
||||||
|
namespace ops = paddle::operators;
|
||||||
|
REGISTER_OP_CUDA_KERNEL(
|
||||||
|
iou_similarity,
|
||||||
|
ops::IOUSimilarityKernel<paddle::platform::CUDADeviceContext, float>,
|
||||||
|
ops::IOUSimilarityKernel<paddle::platform::CUDADeviceContext, double>);
|
@ -0,0 +1,90 @@
|
|||||||
|
/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License. */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "paddle/framework/op_registry.h"
|
||||||
|
#include "paddle/platform/for_range.h"
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline HOSTDEVICE T IOUSimilarity(T xmin1, T ymin1, T xmax1, T ymax1, T xmin2,
|
||||||
|
T ymin2, T xmax2, T ymax2) {
|
||||||
|
constexpr T zero = static_cast<T>(0);
|
||||||
|
T area1 = (ymax1 - ymin1) * (xmax1 - xmin1);
|
||||||
|
T area2 = (ymax2 - ymin2) * (xmax2 - xmin2);
|
||||||
|
T inter_xmax = xmax1 > xmax2 ? xmax2 : xmax1;
|
||||||
|
T inter_ymax = ymax1 > ymax2 ? ymax2 : ymax1;
|
||||||
|
T inter_xmin = xmin1 > xmin2 ? xmin1 : xmin2;
|
||||||
|
T inter_ymin = ymin1 > ymin2 ? ymin1 : ymin2;
|
||||||
|
T inter_height = inter_ymax - inter_ymin;
|
||||||
|
T inter_width = inter_xmax - inter_xmin;
|
||||||
|
inter_height = inter_height > zero ? inter_height : zero;
|
||||||
|
inter_width = inter_width > zero ? inter_width : zero;
|
||||||
|
T inter_area = inter_width * inter_height;
|
||||||
|
T union_area = area1 + area2 - inter_area;
|
||||||
|
T sim_score = inter_area / union_area;
|
||||||
|
return sim_score;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct IOUSimilarityFunctor {
|
||||||
|
IOUSimilarityFunctor(const T* x, const T* y, T* z, int cols)
|
||||||
|
: x_(x), y_(y), z_(z), cols_(static_cast<size_t>(cols)) {}
|
||||||
|
|
||||||
|
inline HOSTDEVICE void operator()(size_t row_id) const {
|
||||||
|
T x_min1 = x_[row_id * 4];
|
||||||
|
T y_min1 = x_[row_id * 4 + 1];
|
||||||
|
T x_max1 = x_[row_id * 4 + 2];
|
||||||
|
T y_max1 = x_[row_id * 4 + 3];
|
||||||
|
for (size_t i = 0; i < cols_; ++i) {
|
||||||
|
T x_min2 = y_[i * 4];
|
||||||
|
T y_min2 = y_[i * 4 + 1];
|
||||||
|
T x_max2 = y_[i * 4 + 2];
|
||||||
|
T y_max2 = y_[i * 4 + 3];
|
||||||
|
|
||||||
|
T sim = IOUSimilarity(x_min1, y_min1, x_max1, y_max1, x_min2, y_min2,
|
||||||
|
x_max2, y_max2);
|
||||||
|
|
||||||
|
z_[row_id * cols_ + i] = sim;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const T* x_;
|
||||||
|
const T* y_;
|
||||||
|
T* z_;
|
||||||
|
const size_t cols_;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace paddle {
|
||||||
|
namespace operators {
|
||||||
|
|
||||||
|
template <typename DeviceContext, typename T>
|
||||||
|
class IOUSimilarityKernel : public framework::OpKernel<T> {
|
||||||
|
public:
|
||||||
|
void Compute(const framework::ExecutionContext& ctx) const override {
|
||||||
|
const framework::LoDTensor* in_x = ctx.Input<framework::LoDTensor>("X");
|
||||||
|
const framework::Tensor* in_y = ctx.Input<framework::Tensor>("Y");
|
||||||
|
framework::LoDTensor* out = ctx.Output<framework::LoDTensor>("Out");
|
||||||
|
|
||||||
|
int x_n = in_x->dims()[0];
|
||||||
|
int y_n = in_y->dims()[0];
|
||||||
|
IOUSimilarityFunctor<T> functor(in_x->data<T>(), in_y->data<T>(),
|
||||||
|
out->mutable_data<T>(ctx.GetPlace()), y_n);
|
||||||
|
|
||||||
|
platform::ForRange<DeviceContext> for_range(
|
||||||
|
static_cast<const DeviceContext&>(ctx.device_context()), x_n);
|
||||||
|
for_range(functor);
|
||||||
|
}
|
||||||
|
}; // namespace operators
|
||||||
|
|
||||||
|
} // namespace operators
|
||||||
|
} // namespace paddle
|
@ -0,0 +1,154 @@
|
|||||||
|
/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License. */
|
||||||
|
|
||||||
|
#include "paddle/operators/prior_box_op.h"
|
||||||
|
|
||||||
|
namespace paddle {
|
||||||
|
namespace operators {
|
||||||
|
|
||||||
|
class PriorBoxOp : public framework::OperatorWithKernel {
|
||||||
|
public:
|
||||||
|
using framework::OperatorWithKernel::OperatorWithKernel;
|
||||||
|
|
||||||
|
void InferShape(framework::InferShapeContext* ctx) const override {
|
||||||
|
PADDLE_ENFORCE(ctx->HasInput("Input"),
|
||||||
|
"Input(Input) of PriorBoxOp should not be null.");
|
||||||
|
PADDLE_ENFORCE(ctx->HasInput("Image"),
|
||||||
|
"Input(Image) of PriorBoxOp should not be null.");
|
||||||
|
|
||||||
|
auto image_dims = ctx->GetInputDim("Image");
|
||||||
|
auto input_dims = ctx->GetInputDim("Input");
|
||||||
|
PADDLE_ENFORCE(image_dims.size() == 4, "The layout of image is NCHW.");
|
||||||
|
PADDLE_ENFORCE(input_dims.size() == 4, "The layout of input is NCHW.");
|
||||||
|
|
||||||
|
PADDLE_ENFORCE_LT(input_dims[2], image_dims[2],
|
||||||
|
"The height of input must smaller than image.");
|
||||||
|
|
||||||
|
PADDLE_ENFORCE_LT(input_dims[3], image_dims[3],
|
||||||
|
"The width of input must smaller than image.");
|
||||||
|
|
||||||
|
auto min_sizes = ctx->Attrs().Get<std::vector<int>>("min_sizes");
|
||||||
|
auto max_sizes = ctx->Attrs().Get<std::vector<int>>("max_sizes");
|
||||||
|
auto variances = ctx->Attrs().Get<std::vector<float>>("variances");
|
||||||
|
auto aspect_ratios = ctx->Attrs().Get<std::vector<float>>("aspect_ratios");
|
||||||
|
bool flip = ctx->Attrs().Get<bool>("flip");
|
||||||
|
|
||||||
|
PADDLE_ENFORCE_GT(min_sizes.size(), 0,
|
||||||
|
"Size of min_sizes must be at least 1.");
|
||||||
|
for (size_t i = 0; i < min_sizes.size(); ++i) {
|
||||||
|
PADDLE_ENFORCE_GT(min_sizes[i], 0, "min_sizes[%d] must be positive.", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<float> aspect_ratios_vec;
|
||||||
|
ExpandAspectRatios(aspect_ratios, flip, aspect_ratios_vec);
|
||||||
|
|
||||||
|
int num_priors = aspect_ratios_vec.size() * min_sizes.size();
|
||||||
|
if (max_sizes.size() > 0) {
|
||||||
|
PADDLE_ENFORCE_EQ(max_sizes.size(), min_sizes.size(),
|
||||||
|
"The number of min_size and max_size must be equal.");
|
||||||
|
for (size_t i = 0; i < min_sizes.size(); ++i) {
|
||||||
|
PADDLE_ENFORCE_GT(max_sizes[i], min_sizes[i],
|
||||||
|
"max_size[%d] must be greater than min_size[%d].", i,
|
||||||
|
i);
|
||||||
|
num_priors += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PADDLE_ENFORCE_EQ(variances.size(), 4, "Must and only provide 4 variance.");
|
||||||
|
for (size_t i = 0; i < variances.size(); ++i) {
|
||||||
|
PADDLE_ENFORCE_GT(variances[i], 0.0,
|
||||||
|
"variance[%d] must be greater than 0.", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
const float step_h = ctx->Attrs().Get<float>("step_h");
|
||||||
|
PADDLE_ENFORCE_GT(step_h, 0.0, "step_h should be larger than 0.");
|
||||||
|
const float step_w = ctx->Attrs().Get<float>("step_w");
|
||||||
|
PADDLE_ENFORCE_GT(step_w, 0.0, "step_w should be larger than 0.");
|
||||||
|
|
||||||
|
std::vector<int64_t> dim_vec(4);
|
||||||
|
dim_vec[0] = input_dims[2];
|
||||||
|
dim_vec[1] = input_dims[3];
|
||||||
|
dim_vec[2] = num_priors;
|
||||||
|
dim_vec[3] = 4;
|
||||||
|
ctx->SetOutputDim("Boxes", framework::make_ddim(dim_vec));
|
||||||
|
ctx->SetOutputDim("Variances", framework::make_ddim(dim_vec));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class PriorBoxOpMaker : public framework::OpProtoAndCheckerMaker {
|
||||||
|
public:
|
||||||
|
PriorBoxOpMaker(OpProto* proto, OpAttrChecker* op_checker)
|
||||||
|
: OpProtoAndCheckerMaker(proto, op_checker) {
|
||||||
|
AddInput("Input",
|
||||||
|
"(Tensor, default Tensor<float>), "
|
||||||
|
"the input feature data of PriorBoxOp, The layout is NCHW.");
|
||||||
|
AddInput("Image",
|
||||||
|
"(Tensor, default Tensor<float>), "
|
||||||
|
"the input image data of PriorBoxOp, The layout is NCHW.");
|
||||||
|
AddOutput("Boxes",
|
||||||
|
"(Tensor, default Tensor<float>), the output prior boxes of "
|
||||||
|
"PriorBoxOp. The layout is [H, W, num_priors, 4]. "
|
||||||
|
"H is the height of input, W is the width of input, num_priors "
|
||||||
|
"is the box count of each position.");
|
||||||
|
AddOutput("Variances",
|
||||||
|
"(Tensor, default Tensor<float>), the expanded variances of "
|
||||||
|
"PriorBoxOp. The layout is [H, W, num_priors, 4]. "
|
||||||
|
"H is the height of input, W is the width of input, num_priors "
|
||||||
|
"is the box count of each position.");
|
||||||
|
AddAttr<std::vector<int>>("min_sizes", "(vector<int>) ",
|
||||||
|
"List of min sizes of generated prior boxes.");
|
||||||
|
AddAttr<std::vector<int>>("max_sizes", "(vector<int>) ",
|
||||||
|
"List of max sizes of generated prior boxes.");
|
||||||
|
AddAttr<std::vector<float>>(
|
||||||
|
"aspect_ratios", "(vector<float>) ",
|
||||||
|
"List of aspect ratios of generated prior boxes.");
|
||||||
|
AddAttr<std::vector<float>>(
|
||||||
|
"variances", "(vector<float>) ",
|
||||||
|
"List of variances to be encoded in prior boxes.");
|
||||||
|
AddAttr<bool>("flip", "(bool) ", "Whether to flip aspect ratios.")
|
||||||
|
.SetDefault(true);
|
||||||
|
AddAttr<bool>("clip", "(bool) ", "Whether to clip out-of-boundary boxes.")
|
||||||
|
.SetDefault(true);
|
||||||
|
AddAttr<float>("step_w",
|
||||||
|
"Prior boxes step across width, 0 for auto calculation.")
|
||||||
|
.SetDefault(0.0);
|
||||||
|
AddAttr<float>("step_h",
|
||||||
|
"Prior boxes step across height, 0 for auto calculation.")
|
||||||
|
.SetDefault(0.0);
|
||||||
|
AddAttr<float>("offset",
|
||||||
|
"(float) "
|
||||||
|
"Prior boxes center offset.")
|
||||||
|
.SetDefault(0.5);
|
||||||
|
AddComment(R"DOC(
|
||||||
|
Prior box operator
|
||||||
|
Generate prior boxes for SSD(Single Shot MultiBox Detector) algorithm.
|
||||||
|
Each position of the input produce N prior boxes, N is determined by
|
||||||
|
the count of min_sizes, max_sizes and aspect_ratios, The size of the
|
||||||
|
box is in range(min_size, max_size) interval, which is generated in
|
||||||
|
sequence according to the aspect_ratios.
|
||||||
|
|
||||||
|
Please get more information from the following papers:
|
||||||
|
https://arxiv.org/abs/1512.02325.
|
||||||
|
)DOC");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace operators
|
||||||
|
} // namespace paddle
|
||||||
|
|
||||||
|
namespace ops = paddle::operators;
|
||||||
|
REGISTER_OP_WITHOUT_GRADIENT(prior_box, ops::PriorBoxOp, ops::PriorBoxOpMaker);
|
||||||
|
REGISTER_OP_CPU_KERNEL(
|
||||||
|
prior_box, ops::PriorBoxOpKernel<paddle::platform::CPUPlace, float>,
|
||||||
|
ops::PriorBoxOpKernel<paddle::platform::CPUPlace, double>);
|
@ -0,0 +1,188 @@
|
|||||||
|
/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License. */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "paddle/framework/op_registry.h"
|
||||||
|
#include "paddle/operators/math/math_function.h"
|
||||||
|
#include "paddle/platform/transform.h"
|
||||||
|
|
||||||
|
namespace paddle {
|
||||||
|
namespace operators {
|
||||||
|
|
||||||
|
inline void ExpandAspectRatios(const std::vector<float>& input_aspect_ratior,
|
||||||
|
bool flip,
|
||||||
|
std::vector<float>& output_aspect_ratior) {
|
||||||
|
constexpr float epsilon = 1e-6;
|
||||||
|
output_aspect_ratior.clear();
|
||||||
|
output_aspect_ratior.push_back(1.);
|
||||||
|
for (size_t i = 0; i < input_aspect_ratior.size(); ++i) {
|
||||||
|
float ar = input_aspect_ratior[i];
|
||||||
|
bool already_exist = false;
|
||||||
|
for (size_t j = 0; j < output_aspect_ratior.size(); ++j) {
|
||||||
|
if (fabs(ar - output_aspect_ratior[j]) < epsilon) {
|
||||||
|
already_exist = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!already_exist) {
|
||||||
|
output_aspect_ratior.push_back(ar);
|
||||||
|
if (flip) {
|
||||||
|
output_aspect_ratior.push_back(1. / ar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct ClipFunctor {
|
||||||
|
HOSTDEVICE T operator()(T in) const {
|
||||||
|
return std::min<T>(std::max<T>(in, 0.), 1.);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Place, typename T>
|
||||||
|
class PriorBoxOpKernel : public framework::OpKernel<T> {
|
||||||
|
public:
|
||||||
|
void Compute(const framework::ExecutionContext& ctx) const override {
|
||||||
|
auto* input = ctx.Input<paddle::framework::Tensor>("Input");
|
||||||
|
auto* image = ctx.Input<paddle::framework::Tensor>("Image");
|
||||||
|
auto* boxes = ctx.Output<paddle::framework::Tensor>("Boxes");
|
||||||
|
auto* vars = ctx.Output<paddle::framework::Tensor>("Variances");
|
||||||
|
|
||||||
|
auto min_sizes = ctx.Attr<std::vector<int>>("min_sizes");
|
||||||
|
auto max_sizes = ctx.Attr<std::vector<int>>("max_sizes");
|
||||||
|
auto input_aspect_ratio = ctx.Attr<std::vector<float>>("aspect_ratios");
|
||||||
|
auto variances = ctx.Attr<std::vector<float>>("variances");
|
||||||
|
auto flip = ctx.Attr<bool>("flip");
|
||||||
|
auto clip = ctx.Attr<bool>("clip");
|
||||||
|
|
||||||
|
std::vector<float> aspect_ratios;
|
||||||
|
ExpandAspectRatios(input_aspect_ratio, flip, aspect_ratios);
|
||||||
|
|
||||||
|
T step_w = static_cast<T>(ctx.Attr<float>("step_w"));
|
||||||
|
T step_h = static_cast<T>(ctx.Attr<float>("step_h"));
|
||||||
|
T offset = static_cast<T>(ctx.Attr<float>("offset"));
|
||||||
|
|
||||||
|
auto img_width = image->dims()[3];
|
||||||
|
auto img_height = image->dims()[2];
|
||||||
|
|
||||||
|
auto feature_width = input->dims()[3];
|
||||||
|
auto feature_height = input->dims()[2];
|
||||||
|
|
||||||
|
T step_width, step_height;
|
||||||
|
if (step_w == 0 || step_h == 0) {
|
||||||
|
step_width = static_cast<T>(img_width) / feature_width;
|
||||||
|
step_height = static_cast<T>(img_height) / feature_height;
|
||||||
|
} else {
|
||||||
|
step_width = step_w;
|
||||||
|
step_height = step_h;
|
||||||
|
}
|
||||||
|
|
||||||
|
int num_priors = aspect_ratios.size() * min_sizes.size();
|
||||||
|
if (max_sizes.size() > 0) {
|
||||||
|
num_priors += max_sizes.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
boxes->mutable_data<T>(ctx.GetPlace());
|
||||||
|
vars->mutable_data<T>(ctx.GetPlace());
|
||||||
|
|
||||||
|
auto e_boxes = framework::EigenTensor<T, 4>::From(*boxes);
|
||||||
|
for (int h = 0; h < feature_height; ++h) {
|
||||||
|
for (int w = 0; w < feature_width; ++w) {
|
||||||
|
T center_x = (w + offset) * step_width;
|
||||||
|
T center_y = (h + offset) * step_height;
|
||||||
|
T box_width, box_height;
|
||||||
|
int idx = 0;
|
||||||
|
for (size_t s = 0; s < min_sizes.size(); ++s) {
|
||||||
|
int min_size = min_sizes[s];
|
||||||
|
// first prior: aspect_ratio = 1, size = min_size
|
||||||
|
box_width = box_height = min_size;
|
||||||
|
// xmin
|
||||||
|
e_boxes(h, w, idx, 0) = (center_x - box_width / 2.) / img_width;
|
||||||
|
// ymin
|
||||||
|
e_boxes(h, w, idx, 1) = (center_y - box_height / 2.) / img_height;
|
||||||
|
// xmax
|
||||||
|
e_boxes(h, w, idx, 2) = (center_x + box_width / 2.) / img_width;
|
||||||
|
// ymax
|
||||||
|
e_boxes(h, w, idx, 3) = (center_y + box_height / 2.) / img_height;
|
||||||
|
|
||||||
|
idx++;
|
||||||
|
if (max_sizes.size() > 0) {
|
||||||
|
int max_size = max_sizes[s];
|
||||||
|
// second prior: aspect_ratio = 1,
|
||||||
|
// size = sqrt(min_size * max_size)
|
||||||
|
box_width = box_height = sqrt(min_size * max_size);
|
||||||
|
// xmin
|
||||||
|
e_boxes(h, w, idx, 0) = (center_x - box_width / 2.) / img_width;
|
||||||
|
// ymin
|
||||||
|
e_boxes(h, w, idx, 1) = (center_y - box_height / 2.) / img_height;
|
||||||
|
// xmax
|
||||||
|
e_boxes(h, w, idx, 2) = (center_x + box_width / 2.) / img_width;
|
||||||
|
// ymax
|
||||||
|
e_boxes(h, w, idx, 3) = (center_y + box_height / 2.) / img_height;
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// rest of priors
|
||||||
|
for (size_t r = 0; r < aspect_ratios.size(); ++r) {
|
||||||
|
float ar = aspect_ratios[r];
|
||||||
|
if (fabs(ar - 1.) < 1e-6) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
box_width = min_size * sqrt(ar);
|
||||||
|
box_height = min_size / sqrt(ar);
|
||||||
|
// xmin
|
||||||
|
e_boxes(h, w, idx, 0) = (center_x - box_width / 2.) / img_width;
|
||||||
|
// ymin
|
||||||
|
e_boxes(h, w, idx, 1) = (center_y - box_height / 2.) / img_height;
|
||||||
|
// xmax
|
||||||
|
e_boxes(h, w, idx, 2) = (center_x + box_width / 2.) / img_width;
|
||||||
|
// ymax
|
||||||
|
e_boxes(h, w, idx, 3) = (center_y + box_height / 2.) / img_height;
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clip) {
|
||||||
|
platform::Transform<platform::CPUDeviceContext> trans;
|
||||||
|
ClipFunctor<T> clip_func;
|
||||||
|
trans(ctx.template device_context<platform::CPUDeviceContext>(),
|
||||||
|
boxes->data<T>(), boxes->data<T>() + boxes->numel(),
|
||||||
|
boxes->data<T>(), clip_func);
|
||||||
|
}
|
||||||
|
|
||||||
|
framework::Tensor var_t;
|
||||||
|
var_t.mutable_data<T>(
|
||||||
|
framework::make_ddim({1, static_cast<int>(variances.size())}),
|
||||||
|
ctx.GetPlace());
|
||||||
|
auto var_et = framework::EigenTensor<T, 2>::From(var_t);
|
||||||
|
for (size_t i = 0; i < variances.size(); ++i) {
|
||||||
|
var_et(0, i) = variances[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
int box_num = feature_height * feature_width * num_priors;
|
||||||
|
auto var_dim = vars->dims();
|
||||||
|
vars->Resize({box_num, static_cast<int>(variances.size())});
|
||||||
|
|
||||||
|
auto e_vars = framework::EigenMatrix<T, Eigen::RowMajor>::From(*vars);
|
||||||
|
e_vars = var_et.broadcast(Eigen::DSizes<int, 2>(box_num, 1));
|
||||||
|
|
||||||
|
vars->Resize(var_dim);
|
||||||
|
}
|
||||||
|
}; // namespace operators
|
||||||
|
|
||||||
|
} // namespace operators
|
||||||
|
} // namespace paddle
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue