# 理论分析

system.png

YOLO从v2版本开始重新启用anchor box，YOLOv2网络的网络输出为尺寸为[b,125,13,13]的tensor，要将这个Tensor变为最终的输出结果，还需要以下的处理：

• 解码：从Tensor中解析出所有框的位置信息和类别信息
• NMS：筛选最能表现物品的识别框

tensor.png

## NMS

NMS为非最大值抑制，用在YOLO系统中的含义指从多个候选框标记同一个物品时，从中选择最合适的候选框。其基本思维很简单：使用置信度最高的候选框标记一个物体，若其他候选框与该候选框的IOU超过一个阈值，则认为其他候选框与该候选框标记的是同一个物体，丢弃其他候选框。

nms.png

# 代码分析

## 解码部分

def get_region_boxes(output, conf_thresh, num_classes, anchors, num_anchors, only_objectness=1, validation=False):
anchor_step = len(anchors) / num_anchors
if output.dim() == 3:
output = output.unsqueeze(0)
batch = output.size(0)
assert(output.size(1) == (5 + num_classes) * num_anchors)
h = output.size(2)
w = output.size(3)
output = output.view(batch * num_anchors, 5 + num_classes, h * w).transpose(
0, 1).contiguous().view(5 + num_classes, batch * num_anchors * h * w)
all_boxes = []

    grid_x = torch.linspace(0, w - 1, w).repeat(h, 1).repeat(batch *
num_anchors, 1, 1).view(batch * num_anchors * h * w).cuda()
grid_y = torch.linspace(0, h - 1, h).repeat(w, 1).t().repeat(
batch * num_anchors, 1, 1).view(batch * num_anchors * h * w).cuda()
print("outputs shape", output.shape)
xs = torch.sigmoid(output[0]) + grid_x
ys = torch.sigmoid(output[1]) + grid_y

。其中W和H分别为当前anchor box的建议尺寸。

    anchor_w = torch.Tensor(anchors).view(
num_anchors, anchor_step).index_select(1, torch.LongTensor([0]))
anchor_h = torch.Tensor(anchors).view(
num_anchors, anchor_step).index_select(1, torch.LongTensor([1]))
anchor_w = anchor_w.repeat(batch, 1).repeat(
1, 1, h * w).view(batch * num_anchors * h * w).cuda()
anchor_h = anchor_h.repeat(batch, 1).repeat(
1, 1, h * w).view(batch * num_anchors * h * w).cuda()
ws = torch.exp(output[2]) * anchor_w
hs = torch.exp(output[3]) * anchor_h

    det_confs = torch.sigmoid(output[4])
cls_confs = torch.nn.Softmax()(
Variable(output[5:5 + num_classes].transpose(0, 1))).data
cls_max_confs, cls_max_ids = torch.max(cls_confs, 1)
cls_max_confs = cls_max_confs.view(-1)
cls_max_ids = cls_max_ids.view(-1)

    sz_hw = h * w
sz_hwa = sz_hw * num_anchors
det_confs = convert2cpu(det_confs)
cls_max_confs = convert2cpu(cls_max_confs)
cls_max_ids = convert2cpu_long(cls_max_ids)
xs = convert2cpu(xs)
ys = convert2cpu(ys)
ws = convert2cpu(ws)
hs = convert2cpu(hs)
if validation:
cls_confs = convert2cpu(cls_confs.view(-1, num_classes))

    for b in range(batch):
boxes = []
# boxes为容纳所有候选框的list
for cy in range(h):
for cx in range(w):
for i in range(num_anchors):
# 遍历每一个anchor box，这里访问位于格点cx,cy的第i个anchor box
ind = b * sz_hwa + i * sz_hw + cy * w + cx
# 获取该anchor box在det_conf中对应的index
det_conf = det_confs[ind]
if only_objectness:
conf = det_confs[ind]
else:
conf = det_confs[ind] * cls_max_confs[ind]
# 处理置信度

if conf > conf_thresh:
# 若置信度大于阈值，则认为该anchor box有效
bcx = xs[ind]
bcy = ys[ind]
bw = ws[ind]
bh = hs[ind]
cls_max_conf = cls_max_confs[ind]
cls_max_id = cls_max_ids[ind]
# 获取所有相关信息，包括长，宽，位置，置信度和类别
box = [bcx / w, bcy / h, bw / w, bh / h,
det_conf, cls_max_conf, cls_max_id]
# 处理数据，其中位置信息x,y,尺寸信息w,h均归一化，使其与输入图片尺寸解耦
if (not only_objectness) and validation:
for c in range(num_classes):
tmp_conf = cls_confs[ind][c]
if c != cls_max_id and det_confs[ind] * tmp_conf > conf_thresh:
box.append(tmp_conf)
box.append(c)
boxes.append(box)
# 将处理好的anchor box信息保存在boxes中
all_boxes.append(boxes)
return all_boxes

## NMS部分

NMS也在utils.py中，函数名为nms。该函数中，首先实现对所有候选框的排序。这里使用det_confs获取了置信度从大到小的anchor box的坐标位置sortIds

def nms(boxes, nms_thresh):
if len(boxes) == 0:
return boxes

det_confs = torch.zeros(len(boxes))
for i in range(len(boxes)):
det_confs[i] = 1 - boxes[i][4]

_, sortIds = torch.sort(det_confs)

    out_boxes = []
for i in range(len(boxes)):
# 按置信度从高到低遍历
box_i = boxes[sortIds[i]]
if box_i[4] > 0:
# 置信度大于0表示该候选框没有在之前的筛选中被抛弃
out_boxes.append(box_i)
for j in range(i + 1, len(boxes)):
# 遍历所有置信度低于该候选框的候选框
box_j = boxes[sortIds[j]]
if bbox_iou(box_i, box_j, x1y1x2y2=False) > nms_thresh:
# 若置信度低的候选框与该候选框IOU大于一定值，抛弃低置信度候选框
box_j[4] = 0
return out_boxes

98 篇文章33 人订阅

0 条评论

## 相关文章

48150

### 决策树告诉你Hello Kitty到底是人是猫

Hello Kitty，一只以无嘴造型40年来风靡全球的萌萌猫，在其40岁生日时，居然被其形象拥有者宣称：HelloKitty不是猫！ 2014年八月，研究 H...

40570

14630

36460

65360

### 深度学习: VGGNet 网络

VGGNet 于2014年由牛津大学著名研究组VGG (Visual Geometry Group) 提出，斩获该年ImageNet竞赛中 Localizati...

97930

807110

59160

### SparkML模型选择（超参数调整）与调优

Spark ML模型选择与调优 本文主要讲解如何使用Spark MLlib的工具去调优ML算法和Pipelines。内置的交叉验证和其他工具允许用户优化算法和管...

52850

### 肤色检测算法 - 基于不同颜色空间简单区域划分的皮肤检测算法

由于能力有限，算法层面的东西自己去创新的很少，很多都是从现有的论文中学习，然后实践的。       本文涉及的很多算法，在网络上也有不少同类型的文...

39480