faster rcnn训练流程的代码详解,请参照faster_pytorch框架食用。
Faster RCNN训练流程
1.加载数据和配置文件和网络
1 | #load data,cfg,net |
2.设置优化器
1 | optimizer = torch.optim.Adam(params[-8:], lr=lr) |
3.训练初始化
1 | train_loss = 0 |
4.训练
1 | net(im_data, im_info, gt_boxes, gt_ishard, dontcare_areas) |
fastrcnn/cfg:
RPN:
1 | # Max number of foreground examples |
Fast RCNN:
1 | # Minibatch size (number of regions of interest [ROIs]) |
具体分为下面几步:
RPN
1 | #计算特征 |
proposal layer
1 | rois = self.proposal_layer |
anchor target layer
产生anchors;
把anchor分配到ground truth上:
- 产生所有的基准anchor,即$w/16\times h/16\times9$.(62x37x9=20646)
- 将超出图像边界的anchor删除.(7858)
- 计算每个anchor对应的最大overlap的gt_boxes的下标,记录每个anchor对应的最大的overlap值=anchors数目
- 计算每个gt_boxes对应的最大overlap的anchor的下标,记录每个gt_boxes对应的最大的overlap值,有可能比gt_boxes数目多,因为可能有相同的overlap
给每个anchor打标签,是前景还是背景,还是不考虑的。
bg:每个 anchor对应最大的overlap值小于阈值0.3;
1
labels[max_overlaps < cfg.TRAIN.RPN_NEGATIVE_OVERLAP] = 0
fg:对应每个GT,有最大overlap的anchor;或者每个anchor与gt的最大overlap超过阈值0.7的anchor:
1
2
3labels[gt_argmax_overlaps] = 1
# fg label: above threshold IOU
labels[max_overlaps >= cfg.TRAIN.RPN_POSITIVE_OVERLAP] = 1
严格控制正负样本1:1(128,128)
边界框的回归目标
计算每一个anchor与重合度最高的那个ground truth的偏移值,即$t_x^*,t_y^*,t_w^*,t_h^{*}$,用于RPN层回归参数的学习。计算方法bbox_transform函数中:
1
2
3
4targets_dx = (gt_ctr_x - ex_ctr_x) / ex_widths
targets_dy = (gt_ctr_y - ex_ctr_y) / ex_heights
targets_dw = np.log(gt_widths / ex_widths)
targets_dh = np.log(gt_heights / ex_heights)
将裁剪过的anchors还原成未裁剪的anchos。返回RPN的region的label和回归目标系数。
RPN损失
类别交叉熵损失和回归损失L1smooth损失。
1 | def build_loss(self, rpn_cls_score_reshape, rpn_bbox_pred, rpn_data): |
proposal target layer:
proposal target layer加了gt box在roi里面,但是直接加的话,会导致损失为0,所以要先抖动(稍微处理一下)。
1.给RPN输出的proposal分配标签;
1 | # Select foreground RoIs as those with >= FG_THRESH overlap#找到IOU大于等于0.5的ROI,获得其引索 |
2.控制mini_batch里面的前景和背景ROI的数目
1 | # Guard against the case when an image has fewer than fg_rois_per_image |
此处没有dontcare的样本
2.计算proposal和groundtruth boxes的偏移量,用于网络最后一层参数的学习。
1.计算每个ROI和最佳匹配的GT的回归系数$t_x,t_y,t_w,t_h$.维度是【300,5】
1 | #传入值为rois的(x1,y1,x2,y2),对应最佳匹配GT的(x1,y1,x2,y2),对应的labels,#返回[标签,dx,dy,dw,dh],shape:(len(rois),5)[300,5] |
即:
1 | def _compute_targets(ex_rois, gt_rois, labels): |
2.再把目标拓展到每个类上:
1 | bbox_targets, bbox_inside_weights = \ |
即:
1 | def _get_bbox_regression_labels(bbox_target_data, num_classes): |
ROIPooling
池化:
1 | self.roi_pool = RoIPool(7, 7, 1.0/16) |
计算classification 层损失
将pooling后的特征送入两个FC层后,产生预测的分数和边界框回归系数:
1 |
计算分类损失
1 | def build_loss(self, cls_score, bbox_pred, roi_data): |
为什么这里的交叉熵损失的计算为什么送入的是cls_score (softmax的输入),而不是cls_prob(softmax层的输出),参见附录A。
计算回归损失
1 | # bounding box regression L1 loss |
计算总损失:
1 | loss = net.loss + net.rpn.loss |
Appendix:交叉熵损失的代码实现
pytorch中CrossEntropyLoss
是通过两个步骤计算出来的,第一步是计算log softmax
,第二步是计算cross entropy
(或者说是negative log likehood
),CrossEntropyLoss
不需要在网络的最后一层添加softmax和log
层,直接输出全连接层即可。而NLLLoss
则需要在定义网络的时候在最后一层添加softmax和log层。
log softmax:
1 | def log_softmax(input, dim=None, _stacklevel=3): |
NLL loss:
1 |
|