1 #include "caffe2/operators/collect_and_distribute_fpn_rpn_proposals_op.h" 8 ERArrXXf BoxesArea(
const ERArrXXf& boxes) {
14 const auto w = boxes.col(2) - boxes.col(0) + 1;
15 const auto h = boxes.col(3) - boxes.col(1) + 1;
16 const ERArrXXf areas = w * h;
17 CAFFE_ENFORCE((areas >= 0).all(),
"Negative areas founds: ", boxes);
23 ERArrXXf MapRoIsToFpnLevels(Eigen::Ref<const ERArrXXf> rois,
24 const float k_min,
const float k_max,
25 const float s0,
const float lvl0) {
27 ERArrXXf s = BoxesArea(rois).sqrt();
35 auto target_lvls = (lvl0 + (s / s0 + 1e-6).log() / log(2)).floor();
36 auto target_lvls_clipped = target_lvls.min(k_max).max(k_min);
37 return target_lvls_clipped;
42 void SortAndLimitRoIsByScores(Eigen::Ref<const EArrXf> scores,
int n,
44 CAFFE_ENFORCE(rois.rows() == scores.size(),
"RoIs and scores count mismatch");
46 std::vector<int> idxs(rois.rows());
47 std::iota(idxs.begin(), idxs.end(), 0);
50 auto comp = [&scores](
int lhs,
int rhs) {
51 if (scores(lhs) > scores(rhs))
return true;
52 if (scores(lhs) < scores(rhs))
return false;
56 ERArrXXf rois_copy = rois;
59 if (n > 0 && n < rois.rows()) {
60 std::nth_element(idxs.begin(), idxs.begin() + n, idxs.end(), comp);
61 rois.resize(n, rois.cols());
65 std::sort(idxs.begin(), idxs.begin() + n, comp);
67 for (
int i = 0; i < n; i++) {
68 rois.row(i) = rois_copy.row(idxs[i]);
74 void ArgSort(EArrXi& arr) {
76 std::vector<int> idxs(arr.size());
77 std::iota(std::begin(idxs), std::end(idxs), 0);
78 std::sort(idxs.begin(), idxs.end(), [&arr](
int lhs,
int rhs) {
79 return arr(lhs) < arr(rhs);
82 for (
int i = 0; i < arr.size(); i++) {
89 void RowsWhereRoILevelEquals(Eigen::Ref<const ERArrXXf> rois,
90 const ERArrXXf& lvls,
const int lvl,
91 ERArrXXf* out_filtered, EArrXi* out_indices) {
92 CAFFE_ENFORCE(out_filtered !=
nullptr,
"Output filtered required");
93 CAFFE_ENFORCE(out_indices !=
nullptr,
"Output indices required");
94 CAFFE_ENFORCE(rois.rows() == lvls.rows(),
"RoIs and lvls count mismatch");
96 int filtered_size = (lvls == lvl).rowwise().any().count();
98 out_filtered->resize(filtered_size, rois.cols());
99 out_indices->resize(filtered_size);
100 for (
int i = 0, filtered_idx = 0; i < rois.rows(); i++) {
101 auto lvl_row = lvls.row(i);
102 if ((lvl_row == lvl).any()) {
103 out_filtered->row(filtered_idx) = rois.row(i);
104 (*out_indices)(filtered_idx) = i;
113 bool CollectAndDistributeFpnRpnProposalsOp<CPUContext>::RunOnDevice() {
114 int num_rpn_lvls = rpn_max_level_ - rpn_min_level_ + 1;
115 CAFFE_ENFORCE_EQ(InputSize(), 2 * num_rpn_lvls);
117 int num_roi_lvls = roi_max_level_ - roi_min_level_ + 1;
118 CAFFE_ENFORCE_EQ(OutputSize(), num_roi_lvls + 2);
129 int proposal_num = 0;
130 for (
int i = 0; i < num_rpn_lvls; i++) {
131 const auto& roi_in = Input(i);
132 proposal_num += roi_in.size(0);
134 ERArrXXf rois(proposal_num, 5);
135 EArrXf scores(proposal_num);
137 for (
int i = 0; i < num_rpn_lvls; i++) {
138 const auto& roi_in = Input(i);
139 const int n = roi_in.size(0);
141 Eigen::Map<const ERArrXXf> roi(roi_in.data<
float>(), n, 5);
142 rois.block(len, 0, n, 5) = roi;
144 const auto& score_in = Input(num_rpn_lvls + i);
148 Eigen::Map<const EArrXf> score(score_in.data<
float>(), n);
149 scores.segment(len, n) = score;
158 utils::SortAndLimitRoIsByScores(scores, rpn_post_nms_topN_, rois);
165 const int lvl_min = roi_min_level_;
166 const int lvl_max = roi_max_level_;
167 const int canon_scale = roi_canonical_scale_;
168 const int canon_level = roi_canonical_level_;
169 auto rois_block = rois.block(0, 1, rois.rows(), 4);
170 auto lvls = utils::MapRoIsToFpnLevels(rois_block,
172 canon_scale, canon_level);
178 auto* rois_out = Output(0, {rois.rows(), rois.cols()}, at::dtype<float>());
179 Eigen::Map<ERArrXXf> rois_out_mat(
180 rois_out->template mutable_data<float>(), rois.rows(), rois.cols());
197 EArrXi rois_idx_restore;
198 for (
int i = 0, lvl = lvl_min; i < num_roi_lvls; i++, lvl++) {
199 ERArrXXf blob_roi_level;
201 utils::RowsWhereRoILevelEquals(rois, lvls, lvl, &blob_roi_level, &idx_lvl);
205 auto* roi_out = Output(
207 {blob_roi_level.rows(), blob_roi_level.cols()},
209 Eigen::Map<ERArrXXf> roi_out_mat(
210 roi_out->template mutable_data<float>(),
211 blob_roi_level.rows(),
212 blob_roi_level.cols());
213 roi_out_mat = blob_roi_level;
216 rois_idx_restore.conservativeResize(rois_idx_restore.size() + idx_lvl.size());
217 rois_idx_restore.tail(idx_lvl.size()) = idx_lvl;
219 utils::ArgSort(rois_idx_restore);
221 auto* rois_idx_restore_out =
222 Output(OutputSize() - 1, {rois_idx_restore.size()}, at::dtype<int>());
223 Eigen::Map<EArrXi> rois_idx_restore_out_mat(
224 rois_idx_restore_out->template mutable_data<int>(),
225 rois_idx_restore.size());
226 rois_idx_restore_out_mat = rois_idx_restore;
233 REGISTER_CPU_OPERATOR(CollectAndDistributeFpnRpnProposals, CollectAndDistributeFpnRpnProposalsOp<CPUContext>);
235 OPERATOR_SCHEMA(CollectAndDistributeFpnRpnProposals)
236 .NumInputs(2, INT_MAX)
237 .NumOutputs(3, INT_MAX)
239 Merge RPN proposals generated at multiple FPN levels and then 240 distribute those proposals to their appropriate FPN levels for Faster RCNN. 241 An anchor at one FPN level may predict an RoI that will map to another level, 242 hence the need to redistribute the proposals. 244 Only inference is supported. To train, please use the original Python 245 operator in Detectron. 247 Inputs and outputs are examples only; if min/max levels change, 248 the number of inputs and outputs, as well as their level numbering, 251 .Arg("roi_canonical_scale",
"(int) ROI_CANONICAL_SCALE")
252 .Arg(
"roi_canonical_level",
"(int) ROI_CANONICAL_LEVEL")
253 .Arg(
"roi_max_level",
"(int) ROI_MAX_LEVEL")
254 .Arg(
"roi_min_level",
"(int) ROI_MIN_LEVEL")
255 .Arg(
"rpn_max_level",
"(int) RPN_MAX_LEVEL")
256 .Arg(
"rpn_min_level",
"(int) RPN_MIN_LEVEL")
257 .Arg(
"rpn_post_nms_topN",
"(int) RPN_POST_NMS_TOP_N")
261 "RPN proposals for FPN level 2, " 262 "format (image_index, x1, y1, x2, y2). See rpn_rois " 263 "documentation from GenerateProposals.")
267 "RPN proposals for FPN level 3, " 268 "format (image_index, x1, y1, x2, y2). See rpn_rois " 269 "documentation from GenerateProposals.")
273 "RPN proposals for FPN level 4, " 274 "format (image_index, x1, y1, x2, y2). See rpn_rois " 275 "documentation from GenerateProposals.")
279 "RPN proposals for FPN level 5, " 280 "format (image_index, x1, y1, x2, y2). See rpn_rois " 281 "documentation from GenerateProposals.")
285 "RPN proposals for FPN level 6, " 286 "format (image_index, x1, y1, x2, y2). See rpn_rois " 287 "documentation from GenerateProposals.")
290 "rpn_roi_probs_fpn2",
291 "RPN objectness probabilities for FPN level 2. " 292 "See rpn_roi_probs documentation from GenerateProposals.")
295 "rpn_roi_probs_fpn3",
296 "RPN objectness probabilities for FPN level 3. " 297 "See rpn_roi_probs documentation from GenerateProposals.")
300 "rpn_roi_probs_fpn4",
301 "RPN objectness probabilities for FPN level 4. " 302 "See rpn_roi_probs documentation from GenerateProposals.")
305 "rpn_roi_probs_fpn5",
306 "RPN objectness probabilities for FPN level 5. " 307 "See rpn_roi_probs documentation from GenerateProposals.")
310 "rpn_roi_probs_fpn6",
311 "RPN objectness probabilities for FPN level 6. " 312 "See rpn_roi_probs documentation from GenerateProposals.")
316 "Top proposals limited to rpn_post_nms_topN total, " 317 "format (image_index, x1, y1, x2, y2)")
321 "RPN proposals for ROI level 2, " 322 "format (image_index, x1, y1, x2, y2)")
326 "RPN proposals for ROI level 3, " 327 "format (image_index, x1, y1, x2, y2)")
331 "RPN proposals for ROI level 4, " 332 "format (image_index, x1, y1, x2, y2)")
336 "RPN proposals for ROI level 5, " 337 "format (image_index, x1, y1, x2, y2)")
341 "Permutation on the concatenation of all " 342 "rois_fpni, i=min...max, such that when applied the RPN RoIs are " 343 "restored to their original order in the input blobs.");
345 SHOULD_NOT_DO_GRADIENT(CollectAndDistributeFpnRpnProposals);
A global dictionary that holds information about what Caffe2 modules have been loaded in the current ...