角度/方向损失
sin(a−b)=sinacosb−cosasinb
config参数
dir_offset=0.7854, # pi/4
dir_limit_offset=0,
box编解码
# Copyright (c) OpenMMLab. All rights reserved.
import torchfrom mmdet.core.bbox import BaseBBoxCoder
from mmdet.core.bbox.builder import BBOX_CODERSimport ipdb@BBOX_CODERS.register_module()
class DeltaXYZWLHRBBoxCoder(BaseBBoxCoder):"""Bbox Coder for 3D boxes.Args:code_size (int): The dimension of boxes to be encoded."""def __init__(self, code_size=7):super(DeltaXYZWLHRBBoxCoder, self).__init__()self.code_size = code_size@staticmethoddef encode(src_boxes, dst_boxes):"""Get box regression transformation deltas (dx, dy, dz, dw, dh, dl,dr, dv*) that can be used to transform the `src_boxes` into the`target_boxes`.Args:src_boxes (torch.Tensor): source boxes, e.g., object proposals.dst_boxes (torch.Tensor): target of the transformation, e.g.,ground-truth boxes.Returns:torch.Tensor: Box transformation deltas."""box_ndim = src_boxes.shape[-1]cas, cgs, cts = [], [], []if box_ndim > 7:xa, ya, za, wa, la, ha, ra, *cas = torch.split(src_boxes, 1, dim=-1)xg, yg, zg, wg, lg, hg, rg, *cgs = torch.split(dst_boxes, 1, dim=-1)cts = [g - a for g, a in zip(cgs, cas)]else:xa, ya, za, wa, la, ha, ra = torch.split(src_boxes, 1, dim=-1)xg, yg, zg, wg, lg, hg, rg = torch.split(dst_boxes, 1, dim=-1)za = za + ha / 2zg = zg + hg / 2diagonal = torch.sqrt(la**2 + wa**2)xt = (xg - xa) / diagonalyt = (yg - ya) / diagonalzt = (zg - za) / halt = torch.log(lg / la)wt = torch.log(wg / wa)ht = torch.log(hg / ha)rt = rg - rareturn torch.cat([xt, yt, zt, wt, lt, ht, rt, *cts], dim=-1)@staticmethoddef decode(anchors, deltas):"""Apply transformation `deltas` (dx, dy, dz, dw, dh, dl, dr, dv*) to`boxes`.Args:anchors (torch.Tensor): Parameters of anchors with shape (N, 7).deltas (torch.Tensor): Encoded boxes with shape(N, 7+n) [x, y, z, w, l, h, r, velo*].Returns:torch.Tensor: Decoded boxes."""cas, cts = [], []box_ndim = anchors.shape[-1]if box_ndim > 7:xa, ya, za, wa, la, ha, ra, *cas = torch.split(anchors, 1, dim=-1)xt, yt, zt, wt, lt, ht, rt, *cts = torch.split(deltas, 1, dim=-1)else:xa, ya, za, wa, la, ha, ra = torch.split(anchors, 1, dim=-1)xt, yt, zt, wt, lt, ht, rt = torch.split(deltas, 1, dim=-1)za = za + ha / 2diagonal = torch.sqrt(la**2 + wa**2)xg = xt * diagonal + xayg = yt * diagonal + yazg = zt * ha + zalg = torch.exp(lt) * lawg = torch.exp(wt) * wahg = torch.exp(ht) * harg = rt + razg = zg - hg / 2cgs = [t + a for t, a in zip(cts, cas)]return torch.cat([xg, yg, zg, wg, lg, hg, rg, *cgs], dim=-1)
训练-方向分类
mmdet3d/models/dense_heads/free_anchor3d_head.py
2个方向 0,1
self.dir_offset = 0.7854 = pi/4
matched_object_targets是编码后的
matched_anchors = anchors_[matched] # [38,25,9]matched_object_targets = self.bbox_coder.encode( # [38,25,9]matched_anchors,gt_bboxes_.unsqueeze(dim=1).expand_as(matched_anchors))if self.use_direction_classifier:# also calculate direction prob: P_{ij}^{dir}matched_dir_targets = get_direction_target( # [38,25] dir=0,1 0~2*PImatched_anchors,matched_object_targets,self.dir_offset,one_hot=False)loss_dir = self.loss_dir( # [38,25]dir_cls_preds_[matched].transpose(-2, -1), # [38,2,25] F.cross_entropymatched_dir_targets, # [38,25]reduction_override='none')
def get_direction_target(anchors,reg_targets,dir_offset=0,num_bins=2,one_hot=True):"""Encode direction to 0 ~ num_bins-1.Args:anchors (torch.Tensor): Concatenated multi-level anchor.reg_targets (torch.Tensor): Bbox regression targets.dir_offset (int): Direction offset.num_bins (int): Number of bins to divide 2*PI.one_hot (bool): Whether to encode as one hot.Returns:torch.Tensor: Encoded direction targets."""rot_gt = reg_targets[..., 6] + anchors[..., 6]offset_rot = limit_period(rot_gt - dir_offset, 0, 2 * np.pi)dir_cls_targets = torch.floor(offset_rot / (2 * np.pi / num_bins)).long()dir_cls_targets = torch.clamp(dir_cls_targets, min=0, max=num_bins - 1)if one_hot:dir_targets = torch.zeros(*list(dir_cls_targets.shape),num_bins,dtype=anchors.dtype,device=dir_cls_targets.device)dir_targets.scatter_(dir_cls_targets.unsqueeze(dim=-1).long(), 1.0)dir_cls_targets = dir_targetsreturn dir_cls_targets
def limit_period(val, offset=0.5, period=np.pi):"""Limit the value into a period for periodic function.Args:val (torch.Tensor): The value to be converted.offset (float, optional): Offset to set the value range. \Defaults to 0.5.period ([type], optional): Period of the value. Defaults to np.pi.Returns:torch.Tensor: Value in the range of \[-offset * period, (1-offset) * period]"""return val - torch.floor(val / period + offset) * period
训练-角度
mmdet3d/models/dense_heads/free_anchor3d_head.py
gt和pre都是编码后的偏移
sin(a−b)=sinacosb−cosasinb
if self.diff_rad_by_sin:bbox_preds_[matched], matched_object_targets = \self.add_sin_difference(bbox_preds_[matched], matched_object_targets)
def add_sin_difference(boxes1, boxes2):"""Convert the rotation difference to difference in sine function.Args:boxes1 (torch.Tensor): Original Boxes in shape (NxC), where C>=7and the 7th dimension is rotation dimension.boxes2 (torch.Tensor): Target boxes in shape (NxC), where C>=7 andthe 7th dimension is rotation dimension.Returns:tuple[torch.Tensor]: ``boxes1`` and ``boxes2`` whose 7th \dimensions are changed."""rad_pred_encoding = torch.sin(boxes1[..., 6:7]) * torch.cos(boxes2[..., 6:7])rad_tg_encoding = torch.cos(boxes1[..., 6:7]) * torch.sin(boxes2[...,6:7])boxes1 = torch.cat([boxes1[..., :6], rad_pred_encoding, boxes1[..., 7:]], dim=-1)boxes2 = torch.cat([boxes2[..., :6], rad_tg_encoding, boxes2[..., 7:]],dim=-1)return boxes1, boxes2
test
mmdet3d/models/dense_heads/anchor3d_head.py get_bboxes
self.dir_limit_offset = 0
self.dir_offset = 0.7854 = PI/4
bboxes = self.bbox_coder.decode(anchors, bbox_pred)dir_rot = limit_period(bboxes[..., 6] - self.dir_offset,self.dir_limit_offset, np.pi)bboxes[..., 6] = (dir_rot + self.dir_offset +np.pi * dir_scores.to(bboxes.dtype))
def limit_period(val, offset=0.5, period=np.pi):"""Limit the value into a period for periodic function.Args:val (torch.Tensor): The value to be converted.offset (float, optional): Offset to set the value range. \Defaults to 0.5.period ([type], optional): Period of the value. Defaults to np.pi.Returns:torch.Tensor: Value in the range of \[-offset * period, (1-offset) * period]"""return val - torch.floor(val / period + offset) * period
gt_bboxes_3d
limit rad to [-pi, pi]
参考
PointPillars论文解析和OpenPCDet代码解析_pointpillars代码解析-CSDN博客
https://github.com/open-mmlab/OpenPCDet/issues/80
MMDetection3D:数据加载简析 - 龙雪 - 博客园
https://zhuanlan.zhihu.com/p/270314921