rpn_head.py 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654
  1. # Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. from __future__ import absolute_import
  15. from __future__ import division
  16. from __future__ import print_function
  17. import numpy as np
  18. from paddle import fluid
  19. from paddle.fluid.param_attr import ParamAttr
  20. from paddle.fluid.initializer import Normal
  21. from paddle.fluid.regularizer import L2Decay
  22. from paddle.fluid.initializer import Constant
  23. __all__ = ['RPNHead', 'FPNRPNHead']
  24. class RPNHead(object):
  25. def __init__(
  26. self,
  27. #anchor_generator
  28. stride=[16.0, 16.0],
  29. anchor_sizes=[32, 64, 128, 256, 512],
  30. aspect_ratios=[0.5, 1., 2.],
  31. variance=[1., 1., 1., 1.],
  32. #rpn_target_assign
  33. rpn_batch_size_per_im=256,
  34. rpn_straddle_thresh=0.,
  35. rpn_fg_fraction=0.5,
  36. rpn_positive_overlap=0.7,
  37. rpn_negative_overlap=0.3,
  38. use_random=True,
  39. rpn_cls_loss='SigmoidCrossEntropy',
  40. rpn_focal_loss_gamma=2,
  41. rpn_focal_loss_alpha=0.25,
  42. #train_proposal
  43. train_pre_nms_top_n=12000,
  44. train_post_nms_top_n=2000,
  45. train_nms_thresh=.7,
  46. train_min_size=.0,
  47. train_eta=1.,
  48. #test_proposal
  49. test_pre_nms_top_n=6000,
  50. test_post_nms_top_n=1000,
  51. test_nms_thresh=.7,
  52. test_min_size=.0,
  53. test_eta=1.,
  54. #num_classes
  55. num_classes=1):
  56. super(RPNHead, self).__init__()
  57. self.stride = stride
  58. self.anchor_sizes = anchor_sizes
  59. self.aspect_ratios = aspect_ratios
  60. self.variance = variance
  61. self.rpn_batch_size_per_im = rpn_batch_size_per_im
  62. self.rpn_straddle_thresh = rpn_straddle_thresh
  63. self.rpn_fg_fraction = rpn_fg_fraction
  64. self.rpn_positive_overlap = rpn_positive_overlap
  65. self.rpn_negative_overlap = rpn_negative_overlap
  66. self.use_random = use_random
  67. self.train_pre_nms_top_n = train_pre_nms_top_n
  68. self.train_post_nms_top_n = train_post_nms_top_n
  69. self.train_nms_thresh = train_nms_thresh
  70. self.train_min_size = train_min_size
  71. self.train_eta = train_eta
  72. self.test_pre_nms_top_n = test_pre_nms_top_n
  73. self.test_post_nms_top_n = test_post_nms_top_n
  74. self.test_nms_thresh = test_nms_thresh
  75. self.test_min_size = test_min_size
  76. self.test_eta = test_eta
  77. self.num_classes = num_classes
  78. self.rpn_cls_loss = rpn_cls_loss
  79. self.rpn_focal_loss_gamma = rpn_focal_loss_gamma
  80. self.rpn_focal_loss_alpha = rpn_focal_loss_alpha
  81. def _get_output(self, input):
  82. """
  83. Get anchor and RPN head output.
  84. Args:
  85. input(Variable): feature map from backbone with shape of [N, C, H, W]
  86. Returns:
  87. rpn_cls_score(Variable): Output of rpn head with shape of
  88. [N, num_anchors, H, W].
  89. rpn_bbox_pred(Variable): Output of rpn head with shape of
  90. [N, num_anchors * 4, H, W].
  91. """
  92. dim_out = input.shape[1]
  93. rpn_conv = fluid.layers.conv2d(
  94. input=input,
  95. num_filters=dim_out,
  96. filter_size=3,
  97. stride=1,
  98. padding=1,
  99. act='relu',
  100. name='conv_rpn',
  101. param_attr=ParamAttr(
  102. name="conv_rpn_w", initializer=Normal(
  103. loc=0., scale=0.01)),
  104. bias_attr=ParamAttr(
  105. name="conv_rpn_b", learning_rate=2., regularizer=L2Decay(0.)))
  106. # Generate anchors
  107. self.anchor, self.anchor_var = fluid.layers.anchor_generator(
  108. input=rpn_conv,
  109. stride=self.stride,
  110. anchor_sizes=self.anchor_sizes,
  111. aspect_ratios=self.aspect_ratios,
  112. variance=self.variance)
  113. num_anchor = self.anchor.shape[2]
  114. # Proposal classification scores
  115. if self.rpn_cls_loss == 'SigmoidCrossEntropy':
  116. bias_init = None
  117. elif self.rpn_cls_loss == 'SigmoidFocalLoss':
  118. value = float(-np.log((1 - 0.01) / 0.01))
  119. bias_init = Constant(value=value)
  120. self.rpn_cls_score = fluid.layers.conv2d(
  121. rpn_conv,
  122. num_filters=num_anchor * self.num_classes,
  123. filter_size=1,
  124. stride=1,
  125. padding=0,
  126. act=None,
  127. name='rpn_cls_score',
  128. param_attr=ParamAttr(
  129. name="rpn_cls_logits_w",
  130. initializer=Normal(
  131. loc=0., scale=0.01)),
  132. bias_attr=ParamAttr(
  133. name="rpn_cls_logits_b",
  134. initializer=bias_init,
  135. learning_rate=2.,
  136. regularizer=L2Decay(0.)))
  137. # Proposal bbox regression deltas
  138. self.rpn_bbox_pred = fluid.layers.conv2d(
  139. rpn_conv,
  140. num_filters=4 * num_anchor,
  141. filter_size=1,
  142. stride=1,
  143. padding=0,
  144. act=None,
  145. name='rpn_bbox_pred',
  146. param_attr=ParamAttr(
  147. name="rpn_bbox_pred_w", initializer=Normal(
  148. loc=0., scale=0.01)),
  149. bias_attr=ParamAttr(
  150. name="rpn_bbox_pred_b",
  151. learning_rate=2.,
  152. regularizer=L2Decay(0.)))
  153. return self.rpn_cls_score, self.rpn_bbox_pred
  154. def get_proposals(self, body_feats, im_info, mode='train'):
  155. """
  156. Get proposals according to the output of backbone.
  157. Args:
  158. body_feats (dict): The dictionary of feature maps from backbone.
  159. im_info(Variable): The information of image with shape [N, 3] with
  160. shape (height, width, scale).
  161. body_feat_names(list): A list of names of feature maps from
  162. backbone.
  163. Returns:
  164. rpn_rois(Variable): Output proposals with shape of (rois_num, 4).
  165. """
  166. # In RPN Heads, only the last feature map of backbone is used.
  167. # And body_feat_names[-1] represents the last level name of backbone.
  168. body_feat = list(body_feats.values())[-1]
  169. rpn_cls_score, rpn_bbox_pred = self._get_output(body_feat)
  170. if self.num_classes == 1:
  171. rpn_cls_prob = fluid.layers.sigmoid(
  172. rpn_cls_score, name='rpn_cls_prob')
  173. else:
  174. rpn_cls_score = fluid.layers.transpose(
  175. rpn_cls_score, perm=[0, 2, 3, 1])
  176. rpn_cls_score = fluid.layers.reshape(
  177. rpn_cls_score, shape=(0, 0, 0, -1, self.num_classes))
  178. rpn_cls_prob_tmp = fluid.layers.softmax(
  179. rpn_cls_score, use_cudnn=False, name='rpn_cls_prob')
  180. rpn_cls_prob_slice = fluid.layers.slice(
  181. rpn_cls_prob_tmp,
  182. axes=[4],
  183. starts=[1],
  184. ends=[self.num_classes])
  185. rpn_cls_prob, _ = fluid.layers.topk(rpn_cls_prob_slice, 1)
  186. rpn_cls_prob = fluid.layers.reshape(
  187. rpn_cls_prob, shape=(0, 0, 0, -1))
  188. rpn_cls_prob = fluid.layers.transpose(
  189. rpn_cls_prob, perm=[0, 3, 1, 2])
  190. if mode == 'train':
  191. rpn_rois, rpn_roi_probs = fluid.layers.generate_proposals(
  192. scores=rpn_cls_prob,
  193. bbox_deltas=rpn_bbox_pred,
  194. im_info=im_info,
  195. anchors=self.anchor,
  196. variances=self.anchor_var,
  197. pre_nms_top_n=self.train_pre_nms_top_n,
  198. post_nms_top_n=self.train_post_nms_top_n,
  199. nms_thresh=self.train_nms_thresh,
  200. min_size=self.train_min_size,
  201. eta=self.train_eta)
  202. else:
  203. rpn_rois, rpn_roi_probs = fluid.layers.generate_proposals(
  204. scores=rpn_cls_prob,
  205. bbox_deltas=rpn_bbox_pred,
  206. im_info=im_info,
  207. anchors=self.anchor,
  208. variances=self.anchor_var,
  209. pre_nms_top_n=self.test_pre_nms_top_n,
  210. post_nms_top_n=self.test_post_nms_top_n,
  211. nms_thresh=self.test_nms_thresh,
  212. min_size=self.test_min_size,
  213. eta=self.test_eta)
  214. return rpn_rois
  215. def _transform_input(self, rpn_cls_score, rpn_bbox_pred, anchor,
  216. anchor_var):
  217. rpn_cls_score = fluid.layers.transpose(
  218. rpn_cls_score, perm=[0, 2, 3, 1])
  219. rpn_bbox_pred = fluid.layers.transpose(
  220. rpn_bbox_pred, perm=[0, 2, 3, 1])
  221. anchor = fluid.layers.reshape(anchor, shape=(-1, 4))
  222. anchor_var = fluid.layers.reshape(anchor_var, shape=(-1, 4))
  223. rpn_cls_score = fluid.layers.reshape(
  224. x=rpn_cls_score, shape=(0, -1, self.num_classes))
  225. rpn_bbox_pred = fluid.layers.reshape(x=rpn_bbox_pred, shape=(0, -1, 4))
  226. return rpn_cls_score, rpn_bbox_pred, anchor, anchor_var
  227. def _get_loss_input(self):
  228. for attr in ['rpn_cls_score', 'rpn_bbox_pred', 'anchor', 'anchor_var']:
  229. if not getattr(self, attr, None):
  230. raise ValueError("self.{} should not be None,".format(attr),
  231. "call RPNHead.get_proposals first")
  232. return self._transform_input(self.rpn_cls_score, self.rpn_bbox_pred,
  233. self.anchor, self.anchor_var)
  234. def get_loss(self, im_info, gt_box, is_crowd, gt_label=None):
  235. """
  236. Sample proposals and Calculate rpn loss.
  237. Args:
  238. im_info(Variable): The information of image with shape [N, 3] with
  239. shape (height, width, scale).
  240. gt_box(Variable): The ground-truth bounding boxes with shape [M, 4].
  241. M is the number of groundtruth.
  242. is_crowd(Variable): Indicates groud-truth is crowd or not with
  243. shape [M, 1]. M is the number of groundtruth.
  244. Returns:
  245. Type: dict
  246. rpn_cls_loss(Variable): RPN classification loss.
  247. rpn_bbox_loss(Variable): RPN bounding box regression loss.
  248. """
  249. rpn_cls, rpn_bbox, anchor, anchor_var = self._get_loss_input()
  250. if self.num_classes == 1:
  251. if self.rpn_cls_loss == 'SigmoidCrossEntropy':
  252. score_pred, loc_pred, score_tgt, loc_tgt, bbox_weight = \
  253. fluid.layers.rpn_target_assign(
  254. bbox_pred=rpn_bbox,
  255. cls_logits=rpn_cls,
  256. anchor_box=anchor,
  257. anchor_var=anchor_var,
  258. gt_boxes=gt_box,
  259. is_crowd=is_crowd,
  260. im_info=im_info,
  261. rpn_batch_size_per_im=self.rpn_batch_size_per_im,
  262. rpn_straddle_thresh=self.rpn_straddle_thresh,
  263. rpn_fg_fraction=self.rpn_fg_fraction,
  264. rpn_positive_overlap=self.rpn_positive_overlap,
  265. rpn_negative_overlap=self.rpn_negative_overlap,
  266. use_random=self.use_random)
  267. score_tgt = fluid.layers.cast(x=score_tgt, dtype='float32')
  268. score_tgt.stop_gradient = True
  269. rpn_cls_loss = fluid.layers.sigmoid_cross_entropy_with_logits(
  270. x=score_pred, label=score_tgt)
  271. elif self.rpn_cls_loss == 'SigmoidFocalLoss':
  272. binary_gt_label = fluid.layers.full_like(
  273. gt_box, fill_value=1, dtype='int32')
  274. binary_gt_label = fluid.layers.reduce_sum(
  275. binary_gt_label, dim=1, keep_dim=True)
  276. data = fluid.layers.fill_constant(
  277. shape=[1], value=4, dtype='int32')
  278. binary_gt_label = fluid.layers.greater_equal(binary_gt_label,
  279. data)
  280. binary_gt_label = fluid.layers.cast(
  281. binary_gt_label, dtype='int32')
  282. score_pred, loc_pred, score_tgt, loc_tgt, bbox_weight, fg_num = \
  283. fluid.layers.retinanet_target_assign(
  284. bbox_pred=rpn_bbox,
  285. cls_logits=rpn_cls,
  286. anchor_box=anchor,
  287. anchor_var=anchor_var,
  288. gt_boxes=gt_box,
  289. gt_labels=binary_gt_label,
  290. is_crowd=is_crowd,
  291. im_info=im_info,
  292. positive_overlap=self.rpn_positive_overlap,
  293. negative_overlap=self.rpn_negative_overlap,
  294. num_classes=1)
  295. fg_num = fluid.layers.reduce_sum(fg_num, name='fg_num')
  296. score_tgt = fluid.layers.cast(score_tgt, 'int32')
  297. rpn_cls_loss = fluid.layers.sigmoid_focal_loss(
  298. x=score_pred,
  299. label=score_tgt,
  300. fg_num=fg_num,
  301. gamma=self.rpn_focal_loss_gamma,
  302. alpha=self.rpn_focal_loss_alpha)
  303. else:
  304. score_pred, loc_pred, score_tgt, loc_tgt, bbox_weight = \
  305. fluid.layers.rpn_target_assign(
  306. bbox_pred=rpn_bbox,
  307. cls_logits=rpn_cls,
  308. anchor_box=anchor,
  309. anchor_var=anchor_var,
  310. gt_boxes=gt_box,
  311. gt_labels=gt_label,
  312. is_crowd=is_crowd,
  313. num_classes=self.num_classes,
  314. im_info=im_info,
  315. rpn_batch_size_per_im=self.rpn_batch_size_per_im,
  316. rpn_straddle_thresh=self.rpn_straddle_thresh,
  317. rpn_fg_fraction=self.rpn_fg_fraction,
  318. rpn_positive_overlap=self.rpn_positive_overlap,
  319. rpn_negative_overlap=self.rpn_negative_overlap,
  320. use_random=self.use_random)
  321. labels_int64 = fluid.layers.cast(x=score_tgt, dtype='int64')
  322. labels_int64.stop_gradient = True
  323. rpn_cls_loss = fluid.layers.softmax_with_cross_entropy(
  324. logits=score_pred,
  325. label=labels_int64,
  326. numeric_stable_mode=True)
  327. if self.rpn_cls_loss == 'SigmoidCrossEntropy':
  328. rpn_cls_loss = fluid.layers.reduce_mean(
  329. rpn_cls_loss, name='loss_rpn_cls')
  330. elif self.rpn_cls_loss == 'SigmoidFocalLoss':
  331. rpn_cls_loss = fluid.layers.reduce_sum(
  332. rpn_cls_loss, name='loss_rpn_cls')
  333. loc_tgt = fluid.layers.cast(x=loc_tgt, dtype='float32')
  334. loc_tgt.stop_gradient = True
  335. rpn_reg_loss = fluid.layers.smooth_l1(
  336. x=loc_pred,
  337. y=loc_tgt,
  338. sigma=3.0,
  339. inside_weight=bbox_weight,
  340. outside_weight=bbox_weight)
  341. rpn_reg_loss = fluid.layers.reduce_sum(
  342. rpn_reg_loss, name='loss_rpn_bbox')
  343. if self.rpn_cls_loss == 'SigmoidCrossEntropy':
  344. score_shape = fluid.layers.shape(score_tgt)
  345. score_shape = fluid.layers.cast(x=score_shape, dtype='float32')
  346. norm = fluid.layers.reduce_prod(score_shape)
  347. norm.stop_gradient = True
  348. rpn_reg_loss = rpn_reg_loss / norm
  349. elif self.rpn_cls_loss == 'SigmoidFocalLoss':
  350. rpn_reg_loss = rpn_reg_loss / fluid.layers.cast(fg_num,
  351. rpn_reg_loss.dtype)
  352. return {'loss_rpn_cls': rpn_cls_loss, 'loss_rpn_bbox': rpn_reg_loss}
  353. class FPNRPNHead(RPNHead):
  354. def __init__(
  355. self,
  356. anchor_start_size=32,
  357. aspect_ratios=[0.5, 1., 2.],
  358. variance=[1., 1., 1., 1.],
  359. num_chan=256,
  360. min_level=2,
  361. max_level=6,
  362. #rpn_target_assign
  363. rpn_batch_size_per_im=256,
  364. rpn_straddle_thresh=0.,
  365. rpn_fg_fraction=0.5,
  366. rpn_positive_overlap=0.7,
  367. rpn_negative_overlap=0.3,
  368. use_random=True,
  369. rpn_cls_loss='SigmoidCrossEntropy',
  370. rpn_focal_loss_gamma=2,
  371. rpn_focal_loss_alpha=0.25,
  372. #train_proposal
  373. train_pre_nms_top_n=2000,
  374. train_post_nms_top_n=2000,
  375. train_nms_thresh=.7,
  376. train_min_size=.0,
  377. train_eta=1.,
  378. #test_proposal
  379. test_pre_nms_top_n=1000,
  380. test_post_nms_top_n=1000,
  381. test_nms_thresh=.7,
  382. test_min_size=.0,
  383. test_eta=1.,
  384. #num_classes
  385. num_classes=1):
  386. super(FPNRPNHead, self).__init__(
  387. aspect_ratios=aspect_ratios,
  388. variance=variance,
  389. rpn_batch_size_per_im=rpn_batch_size_per_im,
  390. rpn_straddle_thresh=rpn_straddle_thresh,
  391. rpn_fg_fraction=rpn_fg_fraction,
  392. rpn_positive_overlap=rpn_positive_overlap,
  393. rpn_negative_overlap=rpn_negative_overlap,
  394. use_random=use_random,
  395. train_pre_nms_top_n=train_pre_nms_top_n,
  396. train_post_nms_top_n=train_post_nms_top_n,
  397. train_nms_thresh=train_nms_thresh,
  398. train_min_size=train_min_size,
  399. train_eta=train_eta,
  400. test_pre_nms_top_n=test_pre_nms_top_n,
  401. test_post_nms_top_n=test_post_nms_top_n,
  402. test_nms_thresh=test_nms_thresh,
  403. test_min_size=test_min_size,
  404. test_eta=test_eta,
  405. num_classes=num_classes,
  406. rpn_cls_loss=rpn_cls_loss,
  407. rpn_focal_loss_gamma=rpn_focal_loss_gamma,
  408. rpn_focal_loss_alpha=rpn_focal_loss_alpha)
  409. self.anchor_start_size = anchor_start_size
  410. self.num_chan = num_chan
  411. self.min_level = min_level
  412. self.max_level = max_level
  413. self.num_classes = num_classes
  414. self.fpn_rpn_list = []
  415. self.anchors_list = []
  416. self.anchor_var_list = []
  417. def _get_output(self, input, feat_lvl):
  418. """
  419. Get anchor and FPN RPN head output at one level.
  420. Args:
  421. input(Variable): Body feature from backbone.
  422. feat_lvl(int): Indicate the level of rpn output corresponding
  423. to the level of feature map.
  424. Return:
  425. rpn_cls_score(Variable): Output of one level of fpn rpn head with
  426. shape of [N, num_anchors, H, W].
  427. rpn_bbox_pred(Variable): Output of one level of fpn rpn head with
  428. shape of [N, num_anchors * 4, H, W].
  429. """
  430. slvl = str(feat_lvl)
  431. conv_name = 'conv_rpn_fpn' + slvl
  432. cls_name = 'rpn_cls_logits_fpn' + slvl
  433. bbox_name = 'rpn_bbox_pred_fpn' + slvl
  434. conv_share_name = 'conv_rpn_fpn' + str(self.min_level)
  435. cls_share_name = 'rpn_cls_logits_fpn' + str(self.min_level)
  436. bbox_share_name = 'rpn_bbox_pred_fpn' + str(self.min_level)
  437. num_anchors = len(self.aspect_ratios)
  438. conv_rpn_fpn = fluid.layers.conv2d(
  439. input=input,
  440. num_filters=self.num_chan,
  441. filter_size=3,
  442. padding=1,
  443. act='relu',
  444. name=conv_name,
  445. param_attr=ParamAttr(
  446. name=conv_share_name + '_w',
  447. initializer=Normal(
  448. loc=0., scale=0.01)),
  449. bias_attr=ParamAttr(
  450. name=conv_share_name + '_b',
  451. learning_rate=2.,
  452. regularizer=L2Decay(0.)))
  453. self.anchors, self.anchor_var = fluid.layers.anchor_generator(
  454. input=conv_rpn_fpn,
  455. anchor_sizes=(self.anchor_start_size * 2.
  456. **(feat_lvl - self.min_level), ),
  457. stride=(2.**feat_lvl, 2.**feat_lvl),
  458. aspect_ratios=self.aspect_ratios,
  459. variance=self.variance)
  460. cls_num_filters = num_anchors * self.num_classes
  461. if self.rpn_cls_loss == 'SigmoidCrossEntropy':
  462. bias_init = None
  463. elif self.rpn_cls_loss == 'SigmoidFocalLoss':
  464. value = float(-np.log((1 - 0.01) / 0.01))
  465. bias_init = Constant(value=value)
  466. self.rpn_cls_score = fluid.layers.conv2d(
  467. input=conv_rpn_fpn,
  468. num_filters=cls_num_filters,
  469. filter_size=1,
  470. act=None,
  471. name=cls_name,
  472. param_attr=ParamAttr(
  473. name=cls_share_name + '_w',
  474. initializer=Normal(
  475. loc=0., scale=0.01)),
  476. bias_attr=ParamAttr(
  477. name=cls_share_name + '_b',
  478. initializer=bias_init,
  479. learning_rate=2.,
  480. regularizer=L2Decay(0.)))
  481. self.rpn_bbox_pred = fluid.layers.conv2d(
  482. input=conv_rpn_fpn,
  483. num_filters=num_anchors * 4,
  484. filter_size=1,
  485. act=None,
  486. name=bbox_name,
  487. param_attr=ParamAttr(
  488. name=bbox_share_name + '_w',
  489. initializer=Normal(
  490. loc=0., scale=0.01)),
  491. bias_attr=ParamAttr(
  492. name=bbox_share_name + '_b',
  493. learning_rate=2.,
  494. regularizer=L2Decay(0.)))
  495. return self.rpn_cls_score, self.rpn_bbox_pred
  496. def _get_single_proposals(self, body_feat, im_info, feat_lvl,
  497. mode='train'):
  498. """
  499. Get proposals in one level according to the output of fpn rpn head
  500. Args:
  501. body_feat(Variable): the feature map from backone.
  502. im_info(Variable): The information of image with shape [N, 3] with
  503. format (height, width, scale).
  504. feat_lvl(int): Indicate the level of proposals corresponding to
  505. the feature maps.
  506. Returns:
  507. rpn_rois_fpn(Variable): Output proposals with shape of (rois_num, 4).
  508. rpn_roi_probs_fpn(Variable): Scores of proposals with
  509. shape of (rois_num, 1).
  510. """
  511. rpn_cls_score_fpn, rpn_bbox_pred_fpn = self._get_output(body_feat,
  512. feat_lvl)
  513. if self.num_classes == 1:
  514. rpn_cls_prob_fpn = fluid.layers.sigmoid(
  515. rpn_cls_score_fpn, name='rpn_cls_prob_fpn' + str(feat_lvl))
  516. else:
  517. rpn_cls_score_fpn = fluid.layers.transpose(
  518. rpn_cls_score_fpn, perm=[0, 2, 3, 1])
  519. rpn_cls_score_fpn = fluid.layers.reshape(
  520. rpn_cls_score_fpn, shape=(0, 0, 0, -1, self.num_classes))
  521. rpn_cls_prob_fpn = fluid.layers.softmax(
  522. rpn_cls_score_fpn,
  523. use_cudnn=False,
  524. name='rpn_cls_prob_fpn' + str(feat_lvl))
  525. rpn_cls_prob_fpn = fluid.layers.slice(
  526. rpn_cls_prob_fpn,
  527. axes=[4],
  528. starts=[1],
  529. ends=[self.num_classes])
  530. rpn_cls_prob_fpn, _ = fluid.layers.topk(rpn_cls_prob_fpn, 1)
  531. rpn_cls_prob_fpn = fluid.layers.reshape(
  532. rpn_cls_prob_fpn, shape=(0, 0, 0, -1))
  533. rpn_cls_prob_fpn = fluid.layers.transpose(
  534. rpn_cls_prob_fpn, perm=[0, 3, 1, 2])
  535. if mode == 'train':
  536. rpn_rois_fpn, rpn_roi_prob_fpn = fluid.layers.generate_proposals(
  537. scores=rpn_cls_prob_fpn,
  538. bbox_deltas=rpn_bbox_pred_fpn,
  539. im_info=im_info,
  540. anchors=self.anchors,
  541. variances=self.anchor_var,
  542. pre_nms_top_n=self.train_pre_nms_top_n,
  543. post_nms_top_n=self.train_post_nms_top_n,
  544. nms_thresh=self.train_nms_thresh,
  545. min_size=self.train_min_size,
  546. eta=self.train_eta)
  547. else:
  548. rpn_rois_fpn, rpn_roi_prob_fpn = fluid.layers.generate_proposals(
  549. scores=rpn_cls_prob_fpn,
  550. bbox_deltas=rpn_bbox_pred_fpn,
  551. im_info=im_info,
  552. anchors=self.anchors,
  553. variances=self.anchor_var,
  554. pre_nms_top_n=self.test_pre_nms_top_n,
  555. post_nms_top_n=self.test_post_nms_top_n,
  556. nms_thresh=self.test_nms_thresh,
  557. min_size=self.test_min_size,
  558. eta=self.test_eta)
  559. return rpn_rois_fpn, rpn_roi_prob_fpn
  560. def get_proposals(self, fpn_feats, im_info, mode='train'):
  561. """
  562. Get proposals in multiple levels according to the output of fpn
  563. rpn head
  564. Args:
  565. fpn_feats(dict): A dictionary represents the output feature map
  566. of FPN with their name.
  567. im_info(Variable): The information of image with shape [N, 3] with
  568. format (height, width, scale).
  569. Return:
  570. rois_list(Variable): Output proposals in shape of [rois_num, 4]
  571. """
  572. rois_list = []
  573. roi_probs_list = []
  574. fpn_feat_names = list(fpn_feats.keys())
  575. for lvl in range(self.min_level, self.max_level + 1):
  576. fpn_feat_name = fpn_feat_names[self.max_level - lvl]
  577. fpn_feat = fpn_feats[fpn_feat_name]
  578. rois_fpn, roi_probs_fpn = self._get_single_proposals(
  579. fpn_feat, im_info, lvl, mode)
  580. self.fpn_rpn_list.append((self.rpn_cls_score, self.rpn_bbox_pred))
  581. rois_list.append(rois_fpn)
  582. roi_probs_list.append(roi_probs_fpn)
  583. self.anchors_list.append(self.anchors)
  584. self.anchor_var_list.append(self.anchor_var)
  585. post_nms_top_n = self.train_post_nms_top_n if mode == 'train' else \
  586. self.test_post_nms_top_n
  587. rois_collect = fluid.layers.collect_fpn_proposals(
  588. rois_list,
  589. roi_probs_list,
  590. self.min_level,
  591. self.max_level,
  592. post_nms_top_n,
  593. name='collect')
  594. return rois_collect
  595. def _get_loss_input(self):
  596. rpn_clses = []
  597. rpn_bboxes = []
  598. anchors = []
  599. anchor_vars = []
  600. for i in range(len(self.fpn_rpn_list)):
  601. single_input = self._transform_input(
  602. self.fpn_rpn_list[i][0], self.fpn_rpn_list[i][1],
  603. self.anchors_list[i], self.anchor_var_list[i])
  604. rpn_clses.append(single_input[0])
  605. rpn_bboxes.append(single_input[1])
  606. anchors.append(single_input[2])
  607. anchor_vars.append(single_input[3])
  608. rpn_cls = fluid.layers.concat(rpn_clses, axis=1)
  609. rpn_bbox = fluid.layers.concat(rpn_bboxes, axis=1)
  610. anchors = fluid.layers.concat(anchors)
  611. anchor_var = fluid.layers.concat(anchor_vars)
  612. return rpn_cls, rpn_bbox, anchors, anchor_var