yolo-v3看不懂?手撕代码逐行讲解,附带网盘完整代码实现

目录

一:读取数据

二:初始化模型

Route 层用于将来自不同层的特征图进行连接或拼接。

Shortcut 层用于执行残差连接,将前一层的特征图与当前层的特征图相加。

 最重要的一层 yolo层:

 三:初始化完所有有网络层后,开始处理数据

四:开始训练

五:损失

六:完整代码网盘链接(附带训练集,和测试的demo)


不多说一句话,直接开撕!!!

一:读取数据

yolo-v3看不懂?手撕代码逐行讲解,附带网盘完整代码实现_第1张图片

读取coco.data文件yolo-v3看不懂?手撕代码逐行讲解,附带网盘完整代码实现_第2张图片

二:初始化模型

yolo-v3看不懂?手撕代码逐行讲解,附带网盘完整代码实现_第3张图片

 接下里继续搭建模型,

yolo-v3看不懂?手撕代码逐行讲解,附带网盘完整代码实现_第4张图片

卷积后紧跟BN层,V3版本已经丢掉了Dropout层了

Route 层用于将来自不同层的特征图进行连接或拼接。

Shortcut 层用于执行残差连接,将前一层的特征图与当前层的特征图相加。

CBL(conv+BN+Leaky relu)+Res+ResX+上采样下采样

yolo-v3看不懂?手撕代码逐行讲解,附带网盘完整代码实现_第5张图片yolo-v3看不懂?手撕代码逐行讲解,附带网盘完整代码实现_第6张图片

 #当前层与前面的第几层做操作。如果layers是第四层,那么就第四层做拼接操作————————做特征融合的(做乘法法)
        elif module_def["type"] == "route": # 输入1:26*26*256 输入2:26*26*128  输出:26*26*(256+128)
            layers = [int(x) for x in module_def["layers"].split(",")]
            filters = sum([output_filters[1:][i] for i in layers])
            modules.add_module(f"route_{module_i}", EmptyLayer())

        #跟上面的route很像————————做残差网络的(做加法)
        elif module_def["type"] == "shortcut":
            filters = output_filters[1:][int(module_def["from"])]
            modules.add_module(f"shortcut_{module_i}", EmptyLayer())

 最重要的一层 yolo层:

        这表示只选择了锚框列表中索引为6、7、8的三个锚框用于预测目标框。这个选择是根据训练数据集和目标类别的特点进行的。 yolov3是kmean聚类,他们通过经验和实验,对锚框的尺寸进行了调整和优化,以便在特定任务和数据集上获得更好的性能。这种自定义的锚框设置是基于作者的经验和实践,可能是为了在特定任务中获得更好的结果。
yolo-v3看不懂?手撕代码逐行讲解,附带网盘完整代码实现_第7张图片

提前设置好了输入的图片是416

 进入yolo层的定义,初始化需要的参数

yolo-v3看不懂?手撕代码逐行讲解,附带网盘完整代码实现_第8张图片

 三:初始化完所有有网络层后,开始处理数据

        collate_fn是一个函数,用于在数据加载器中将多个样本组合成一个批次。它定义了如何对样本进行分组和处理,以确保组合成的批次具有一致的形状和大小。

 yolo-v3看不懂?手撕代码逐行讲解,附带网盘完整代码实现_第9张图片

 collate_fn函数yolo-v3看不懂?手撕代码逐行讲解,附带网盘完整代码实现_第10张图片

这个就是利用collate_fn分组后的结果

yolo-v3看不懂?手撕代码逐行讲解,附带网盘完整代码实现_第11张图片

四:开始训练

yolo-v3看不懂?手撕代码逐行讲解,附带网盘完整代码实现_第12张图片

 首先先加入Darknet的forward函数,将图片传入,输入到定义好的各个网络层,其中重点看yolo层 。

yolo-v3看不懂?手撕代码逐行讲解,附带网盘完整代码实现_第13张图片

每一层做完后,都需要append到layer_outputs里面存储。

直接跳到看yolo层的训练

打断点,进入到yolo层的forward哈函数:

第一次yolo层,传入的是11*11的图片

yolo-v3看不懂?手撕代码逐行讲解,附带网盘完整代码实现_第14张图片

         4+1+80 grid_size网格的大小(x+y+w+h+confidence+predictor(80个列别的概率 )=85),后面用sigmoid把self.num_classes + 5个类别转成概率,虽然可以直接在 x.view 中完成维度交换,但是将其分成两个步骤可以更好地表达代码的意图,提高可读性和可维护性。这样的做法也更加符合代码编写的规范和风格。

 获取这6个变量的信息

yolo-v3看不懂?手撕代码逐行讲解,附带网盘完整代码实现_第15张图片

 最后取出数据保存到pred_boxes中

还原到原始图中,上面先把高宽成了下采样后的,不过这个是保存在output中的。注意:下面传入的pred_boxes值没有改变

 yolo-v3看不懂?手撕代码逐行讲解,附带网盘完整代码实现_第16张图片

先筛选一些iou,再拿这些锚框去跟真实框进行iou计算, 也就是说iou是随便生成的,然后才真正的用筛选好的锚框去跟真实框做iou,

def build_targets(pred_boxes, pred_cls, target, anchors, ignore_thres):
    ByteTensor = torch.cuda.ByteTensor if pred_boxes.is_cuda else torch.ByteTensor
    FloatTensor = torch.cuda.FloatTensor if pred_boxes.is_cuda else torch.FloatTensor

    nB = pred_boxes.size(0)   
    nA = pred_boxes.size(1)   
    nC = pred_cls.size(-1)   
    nG = pred_boxes.size(2)   

     
    obj_mask = ByteTensor(nB, nA, nG, nG).fill_(0)   
    noobj_mask = ByteTensor(nB, nA, nG, nG).fill_(1)   
    class_mask = FloatTensor(nB, nA, nG, nG).fill_(0)   
    iou_scores = FloatTensor(nB, nA, nG, nG).fill_(0)   
    tx = FloatTensor(nB, nA, nG, nG).fill_(0)   
    ty = FloatTensor(nB, nA, nG, nG).fill_(0)
    tw = FloatTensor(nB, nA, nG, nG).fill_(0)
    th = FloatTensor(nB, nA, nG, nG).fill_(0)
    tcls = FloatTensor(nB, nA, nG, nG, nC).fill_(0)

     
    target_boxes = target[:, 2:6] * nG   
    gxy = target_boxes[:, :2]
    gwh = target_boxes[:, 2:] 
     
    ious = torch.stack([bbox_wh_iou(anchor, gwh) for anchor in anchors])   
    print(ious.shape)   
    best_ious, best_n = ious.max(0)   
     
    b, target_labels = target[:, :2].long().t()   
    gx, gy = gxy.t()   
    gw, gh = gwh.t()   
    gi, gj = gxy.long().t()   
     
    obj_mask[b, best_n, gj, gi] = 1   
    print(obj_mask.shape)
    noobj_mask[b, best_n, gj, gi] = 0   

     
    for i, anchor_ious in enumerate(ious.t()):   
        noobj_mask[b[i], anchor_ious > ignore_thres, gj[i], gi[i]] = 0   
         
     
    tx[b, best_n, gj, gi] = gx - gx.floor()   
    print(tx.shape)
    ty[b, best_n, gj, gi] = gy - gy.floor() 
     
    tw[b, best_n, gj, gi] = torch.log(gw / anchors[best_n][:, 0] + 1e-16)   
    print(tw.shape)   
    th[b, best_n, gj, gi] = torch.log(gh / anchors[best_n][:, 1] + 1e-16)
     
    tcls[b, best_n, gj, gi, target_labels] = 1   
    print(tcls.shape)
     
    hyt = pred_cls[b, best_n, gj, gi].argmax(-1)
    class_mask[b, best_n, gj, gi] = (pred_cls[b, best_n, gj, gi].argmax(-1) == target_labels).float()
    iou_scores[b, best_n, gj, gi] = bbox_iou(pred_boxes[b, best_n, gj, gi], target_boxes,
                                             x1y1x2y2=False)   

    tconf = obj_mask.float()   
    return iou_scores, class_mask, obj_mask, noobj_mask, tx, ty, tw, th, tcls, tconf

得出来这些值后:

iou_scores:真实值与最匹配的anchor的IOU得分值 class_mask:分类正确的索引 obj_mask:目标框所在位置的最好anchor置为1 noobj_mask obj_mask那里置0,还有计算的iou大于阈值的也置0,其他都为1 tx, ty, tw, th, 对应的对于该大小的特征图的xywh目标值也就是我们需要拟合的值 tconf 目标置信度

五:损失

yolo-v3看不懂?手撕代码逐行讲解,附带网盘完整代码实现_第17张图片

六:完整代码网盘链接(附带训练集,和测试的demo)

链接:https://pan.baidu.com/s/1pPh9T4cfMJ4TM4KdQHqcAw?pwd=4986 
提取码:4986

你可能感兴趣的:(yolo,YOLO,神经网络,深度学习,计算机视觉,目标检测)