#ifndef CAFFE2_OPERATORS_COLLECT_AND_DISTRIBUTE_FPN_RPN_PROPOSALS_OP_H_ #define CAFFE2_OPERATORS_COLLECT_AND_DISTRIBUTE_FPN_RPN_PROPOSALS_OP_H_ #include "caffe2/core/export_caffe2_op_to_c10.h" #include "caffe2/core/context.h" #include "caffe2/core/operator.h" #include "caffe2/utils/eigen_utils.h" #include "caffe2/utils/math.h" C10_DECLARE_EXPORT_CAFFE2_OP_TO_C10(CollectAndDistributeFpnRpnProposals); C10_DECLARE_EXPORT_CAFFE2_OP_TO_C10(CollectRpnProposals); C10_DECLARE_EXPORT_CAFFE2_OP_TO_C10(DistributeFpnProposals); namespace caffe2 { namespace utils { // Compute the area of an array of boxes. ERArrXXf BoxesArea(const ERArrXXf& boxes, const bool legacy_plus_one = false); // Determine which FPN level each RoI in a set of RoIs should map to based // on the heuristic in the FPN paper. ERArrXXf MapRoIsToFpnLevels( Eigen::Ref rois, const float k_min, const float k_max, const float s0, const float lvl0, const bool legacy_plus_one = false); // Sort RoIs from highest to lowest individual RoI score based on // values from scores array and limit to n results void SortAndLimitRoIsByScores( Eigen::Ref scores, int n, ERArrXXf& rois); // Updates arr to be indices that would sort the array. Implementation of // https://docs.scipy.org/doc/numpy/reference/generated/numpy.argsort.html void ArgSort(EArrXi& arr); // Update out_filtered and out_indices with rows from rois where lvl matches // value in lvls passed in. void RowsWhereRoILevelEquals( Eigen::Ref rois, const ERArrXXf& lvls, const int lvl, ERArrXXf* out_filtered, EArrXi* out_indices); } // namespace utils // C++ implementation of CollectAndDistributeFpnRpnProposalsOp // Merge RPN proposals generated at multiple FPN levels and then // distribute those proposals to their appropriate FPN levels for Faster // RCNN. An anchor at one FPN level may predict an RoI that will map to // another level, hence the need to redistribute the proposals. // Reference: // facebookresearch/Detectron/detectron/ops/collect_and_distribute_fpn_rpn_proposals.py template class CollectAndDistributeFpnRpnProposalsOp final : public Operator { public: USE_OPERATOR_CONTEXT_FUNCTIONS; template explicit CollectAndDistributeFpnRpnProposalsOp(Args&&... args) : Operator(std::forward(args)...), roi_canonical_scale_( this->template GetSingleArgument("roi_canonical_scale", 224)), roi_canonical_level_( this->template GetSingleArgument("roi_canonical_level", 4)), roi_max_level_( this->template GetSingleArgument("roi_max_level", 5)), roi_min_level_( this->template GetSingleArgument("roi_min_level", 2)), rpn_max_level_( this->template GetSingleArgument("rpn_max_level", 6)), rpn_min_level_( this->template GetSingleArgument("rpn_min_level", 2)), rpn_post_nms_topN_( this->template GetSingleArgument("rpn_post_nms_topN", 2000)), legacy_plus_one_( this->template GetSingleArgument("legacy_plus_one", true)) { CAFFE_ENFORCE_GE( roi_max_level_, roi_min_level_, "roi_max_level " + c10::to_string(roi_max_level_) + " must be greater than or equal to roi_min_level " + c10::to_string(roi_min_level_) + "."); CAFFE_ENFORCE_GE( rpn_max_level_, rpn_min_level_, "rpn_max_level " + c10::to_string(rpn_max_level_) + " must be greater than or equal to rpn_min_level " + c10::to_string(rpn_min_level_) + "."); } ~CollectAndDistributeFpnRpnProposalsOp() override {} bool RunOnDevice() override; protected: // ROI_CANONICAL_SCALE int roi_canonical_scale_{224}; // ROI_CANONICAL_LEVEL int roi_canonical_level_{4}; // ROI_MAX_LEVEL int roi_max_level_{5}; // ROI_MIN_LEVEL int roi_min_level_{2}; // RPN_MAX_LEVEL int rpn_max_level_{6}; // RPN_MIN_LEVEL int rpn_min_level_{2}; // RPN_POST_NMS_TOP_N int rpn_post_nms_topN_{2000}; // The infamous "+ 1" for box width and height dating back to the DPM days bool legacy_plus_one_{true}; }; template class CollectRpnProposalsOp final : public Operator { public: USE_OPERATOR_CONTEXT_FUNCTIONS; template explicit CollectRpnProposalsOp(Args&&... args) : Operator(std::forward(args)...), rpn_max_level_( this->template GetSingleArgument("rpn_max_level", 6)), rpn_min_level_( this->template GetSingleArgument("rpn_min_level", 2)), rpn_post_nms_topN_( this->template GetSingleArgument("rpn_post_nms_topN", 2000)) { CAFFE_ENFORCE_GE( rpn_max_level_, rpn_min_level_, "rpn_max_level " + c10::to_string(rpn_max_level_) + " must be greater than or equal to rpn_min_level " + c10::to_string(rpn_min_level_) + "."); } ~CollectRpnProposalsOp() override {} bool RunOnDevice() override; protected: // RPN_MAX_LEVEL int rpn_max_level_{6}; // RPN_MIN_LEVEL int rpn_min_level_{2}; // RPN_POST_NMS_TOP_N int rpn_post_nms_topN_{2000}; }; template class DistributeFpnProposalsOp final : public Operator { public: USE_OPERATOR_CONTEXT_FUNCTIONS; template explicit DistributeFpnProposalsOp(Args&&... args) : Operator(std::forward(args)...), roi_canonical_scale_( this->template GetSingleArgument("roi_canonical_scale", 224)), roi_canonical_level_( this->template GetSingleArgument("roi_canonical_level", 4)), roi_max_level_( this->template GetSingleArgument("roi_max_level", 5)), roi_min_level_( this->template GetSingleArgument("roi_min_level", 2)), legacy_plus_one_( this->template GetSingleArgument("legacy_plus_one", true)) { CAFFE_ENFORCE_GE( roi_max_level_, roi_min_level_, "roi_max_level " + c10::to_string(roi_max_level_) + " must be greater than or equal to roi_min_level " + c10::to_string(roi_min_level_) + "."); } ~DistributeFpnProposalsOp() override {} bool RunOnDevice() override; protected: // ROI_CANONICAL_SCALE int roi_canonical_scale_{224}; // ROI_CANONICAL_LEVEL int roi_canonical_level_{4}; // ROI_MAX_LEVEL int roi_max_level_{5}; // ROI_MIN_LEVEL int roi_min_level_{2}; // The infamous "+ 1" for box width and height dating back to the DPM days bool legacy_plus_one_{true}; }; } // namespace caffe2 #endif // CAFFE2_OPERATORS_COLLECT_AND_DISTRIBUTE_FPN_RPN_PROPOSALS_OP_H_