• YOLO v3源码详解


    数据读取代码详解 

    传入参数:训练集txt路径和线程数

    在初始化操作中,读取txt文件的图片名称,并找到相应的labels地址 ,读取图片,将图片调整为RGB格式,并进行padding操作,将图片大小调整为640*640

    标签的处理

    首先读取标签文件,由于图像经过了padding,首先,需要对真实框进行调整,并将真实框由(x1,y1,x2,y2)格式转变为(x,y,w,h)格式,再对图像做数据增强处理(翻转),并调整真实框

    代码如下:

    1. class ListDataset(Dataset):
    2. def __init__(self, list_path, img_size=416, augment=True, multiscale=True, normalized_labels=True):
    3. with open(list_path, "r") as file:
    4. self.img_files = file.readlines()
    5. self.label_files = [
    6. path.replace("train2017", "trainval2017").replace(".png", ".txt").replace(".jpg", ".txt")
    7. for path in self.img_files
    8. ]
    9. self.img_size = img_size
    10. self.max_objects = 100
    11. self.augment = augment
    12. self.multiscale = multiscale
    13. self.normalized_labels = normalized_labels
    14. self.min_size = self.img_size - 3 * 32
    15. self.max_size = self.img_size + 3 * 32
    16. self.batch_count = 0
    17. def __getitem__(self, index):
    18. # ---------
    19. # Image
    20. # ---------
    21. img_path = self.img_files[index % len(self.img_files)].rstrip()
    22. # img_path = 'E:\\eclipse-workspace\\PyTorch\\PyTorch-YOLOv3\\data\\coco' + img_path
    23. #print (img_path)
    24. # Extract image as PyTorch tensor
    25. img = transforms.ToTensor()(Image.open(img_path).convert('RGB'))
    26. # Handle images with less than three channels
    27. if len(img.shape) != 3:
    28. img = img.unsqueeze(0)
    29. img = img.expand((3, img.shape[1:]))
    30. _, h, w = img.shape
    31. h_factor, w_factor = (h, w) if self.normalized_labels else (1, 1)
    32. # Pad to square resolution
    33. img, pad = pad_to_square(img, 0)
    34. _, padded_h, padded_w = img.shape
    35. # ---------
    36. # Label
    37. # ---------
    38. # 取出标签文件,定位到自己的标签文件中
    39. label_path = self.label_files[index % len(self.img_files)].rstrip()
    40. # label_path = 'E:\\eclipse-workspace\\PyTorch\\PyTorch-YOLOv3\\data\\coco\\labels' + label_path
    41. #print (label_path)
    42. # ---------------
    43. # 对真实框进行调整
    44. # ---------------
    45. targets = None
    46. if os.path.exists(label_path):
    47. boxes = torch.from_numpy(np.loadtxt(label_path).reshape(-1, 5))
    48. # Extract coordinates for unpadded + unscaled image
    49. x1 = w_factor * (boxes[:, 1] - boxes[:, 3] / 2)
    50. y1 = h_factor * (boxes[:, 2] - boxes[:, 4] / 2)
    51. x2 = w_factor * (boxes[:, 1] + boxes[:, 3] / 2)
    52. y2 = h_factor * (boxes[:, 2] + boxes[:, 4] / 2)
    53. # Adjust for added padding
    54. x1 += pad[0]
    55. y1 += pad[2]
    56. x2 += pad[1]
    57. y2 += pad[3]
    58. # Returns (x, y, w, h)
    59. boxes[:, 1] = ((x1 + x2) / 2) / padded_w
    60. boxes[:, 2] = ((y1 + y2) / 2) / padded_h
    61. boxes[:, 3] *= w_factor / padded_w
    62. boxes[:, 4] *= h_factor / padded_h
    63. targets = torch.zeros((len(boxes), 6))
    64. targets[:, 1:] = boxes
    65. # Apply augmentations
    66. # 数据增强:翻转
    67. if self.augment:
    68. if np.random.random() < 0.5:
    69. img, targets = horisontal_flip(img, targets)
    70. return img_path, img, targets
    71. def collate_fn(self, batch):
    72. paths, imgs, targets = list(zip(*batch))
    73. # Remove empty placeholder targets
    74. targets = [boxes for boxes in targets if boxes is not None]
    75. # Add sample index to targets
    76. for i, boxes in enumerate(targets):
    77. boxes[:, 0] = i
    78. targets = torch.cat(targets, 0)
    79. # Selects new image size every tenth batch
    80. if self.multiscale and self.batch_count % 10 == 0:
    81. self.img_size = random.choice(range(self.min_size, self.max_size + 1, 32))
    82. # Resize images to input shape
    83. imgs = torch.stack([resize(img, self.img_size) for img in imgs])
    84. self.batch_count += 1
    85. return paths, imgs, targets
    86. def __len__(self):
    87. return len(self.img_files)

     2.基于配置文件构建网络模型

    YOLO v3网络结构

    [convolutional]模块:由卷积、batchnormalization、leakey Relu激活层组成
    shortcut层:即残差连接层,如上图所示,特征图经过1*1的卷积降低特征通道和3*3的卷积后使用一个残差连接,不涉及特征图缩小
    route层:特征图经过上采样后与上一层的特征图相连
    

    route层和shortcut层在初始化操作时,均先创建一个空层,等前向传播时在进行构建

    YOLO层共有三层,完成对特征图网格存在物体的位置和类别的检测,并完成损失函数的构建。

    代码如下:

    1. def create_modules(module_defs):
    2. """
    3. Constructs module list of layer blocks from module configuration in module_defs
    4. """
    5. hyperparams = module_defs.pop(0)
    6. output_filters = [int(hyperparams["channels"])]
    7. module_list = nn.ModuleList()
    8. for module_i, module_def in enumerate(module_defs):
    9. modules = nn.Sequential()
    10. if module_def["type"] == "convolutional":
    11. bn = int(module_def["batch_normalize"])
    12. filters = int(module_def["filters"])
    13. kernel_size = int(module_def["size"])
    14. pad = (kernel_size - 1) // 2
    15. modules.add_module(
    16. f"conv_{module_i}",
    17. nn.Conv2d(
    18. in_channels=output_filters[-1],
    19. out_channels=filters,
    20. kernel_size=kernel_size,
    21. stride=int(module_def["stride"]),
    22. padding=pad,
    23. bias=not bn,
    24. ),
    25. )
    26. if bn:
    27. modules.add_module(f"batch_norm_{module_i}", nn.BatchNorm2d(filters, momentum=0.9, eps=1e-5))
    28. if module_def["activation"] == "leaky":
    29. modules.add_module(f"leaky_{module_i}", nn.LeakyReLU(0.1))
    30. elif module_def["type"] == "maxpool":
    31. kernel_size = int(module_def["size"])
    32. stride = int(module_def["stride"])
    33. if kernel_size == 2 and stride == 1:
    34. modules.add_module(f"_debug_padding_{module_i}", nn.ZeroPad2d((0, 1, 0, 1)))
    35. maxpool = nn.MaxPool2d(kernel_size=kernel_size, stride=stride, padding=int((kernel_size - 1) // 2))
    36. modules.add_module(f"maxpool_{module_i}", maxpool)
    37. elif module_def["type"] == "upsample":
    38. upsample = Upsample(scale_factor=int(module_def["stride"]), mode="nearest")
    39. modules.add_module(f"upsample_{module_i}", upsample)
    40. elif module_def["type"] == "route": # 输入1:26*26*256 输入2:26*26*128 输出:26*26*(256+128)
    41. layers = [int(x) for x in module_def["layers"].split(",")]
    42. filters = sum([output_filters[1:][i] for i in layers])
    43. modules.add_module(f"route_{module_i}", EmptyLayer())
    44. # 残差连接
    45. elif module_def["type"] == "shortcut":
    46. filters = output_filters[1:][int(module_def["from"])]
    47. modules.add_module(f"shortcut_{module_i}", EmptyLayer())
    48. # 构建yolo层
    49. elif module_def["type"] == "yolo":
    50. anchor_idxs = [int(x) for x in module_def["mask"].split(",")]
    51. # Extract anchors 得到锚框的比例
    52. anchors = [int(x) for x in module_def["anchors"].split(",")]
    53. anchors = [(anchors[i], anchors[i + 1]) for i in range(0, len(anchors), 2)]
    54. # 取anchor_idxs指定的锚框(6,7,8)
    55. anchors = [anchors[i] for i in anchor_idxs]
    56. num_classes = int(module_def["classes"])
    57. img_size = int(hyperparams["height"])
    58. # Define detection layer
    59. yolo_layer = YOLOLayer(anchors, num_classes, img_size)
    60. modules.add_module(f"yolo_{module_i}", yolo_layer)
    61. # Register module list and number of output filters
    62. module_list.append(modules)
    63. output_filters.append(filters)
    64. return hyperparams, module_list

     3.YOLO层定义解析

    输出结果         

            对于输入的特征图,首先reshape成[图片数,网格h,网格w,一个网格锚框数,类别数+4(x,y,w,h)+1(是否存在物体)]大小,取出x,y,w,h,pred_conf,pred_cls,根据论文,对x,y,pred_conf,pred_cl输入sigmoid函数,得到最终的预测的结果,此时得到的是物体在特征图网格的存在物体的置信度,类别置信度、和相对于网格的相对位置,将相对位置转为特征图的绝对位置,并进一步得到真实位置,输出结果

    损失函数的构建

            取出target标签中的真实框,对每一个先验框计算IOU值,shape[num_anchors,num_gtboxs],即每一个先验框与每一个真实框的IOU,取每一个真实框IOU最大的先验框,此框必定包含物体。同时,IOU超过了指定的阈值也看做是有物体,由此可以构建包含物体的矩阵obj_mask和不包含物体的矩阵nonobj_mask。然后获得获得每个网格物体真实坐标相对于左上角的偏移量,将真实框的标签转换为one-hot编码形式,计算预测框和真实一样的索引,以及与真实框想匹配的预测框之间的iou值。

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

    代码如下:

    1. def build_targets(pred_boxes, pred_cls, target, anchors, ignore_thres):
    2. ByteTensor = torch.cuda.ByteTensor if pred_boxes.is_cuda else torch.ByteTensor
    3. FloatTensor = torch.cuda.FloatTensor if pred_boxes.is_cuda else torch.FloatTensor
    4. nB = pred_boxes.size(0) # batchsieze 4
    5. nA = pred_boxes.size(1) # 每个格子对应了多少个anchor
    6. nC = pred_cls.size(-1) # 类别的数量
    7. nG = pred_boxes.size(2) # gridsize
    8. # Output tensors
    9. # 初始化操作
    10. obj_mask = ByteTensor(nB, nA, nG, nG).fill_(0) # obj,anchor包含物体, 即为1,默认为0 考虑前景
    11. noobj_mask = ByteTensor(nB, nA, nG, nG).fill_(1) # noobj, anchor不包含物体, 则为1,默认为1 考虑背景
    12. class_mask = FloatTensor(nB, nA, nG, nG).fill_(0) # 类别掩膜,类别预测正确即为1,默认全为0
    13. iou_scores = FloatTensor(nB, nA, nG, nG).fill_(0) # 预测框与真实框的iou得分
    14. tx = FloatTensor(nB, nA, nG, nG).fill_(0) # 真实框相对于网格的位置
    15. ty = FloatTensor(nB, nA, nG, nG).fill_(0)
    16. tw = FloatTensor(nB, nA, nG, nG).fill_(0)
    17. th = FloatTensor(nB, nA, nG, nG).fill_(0)
    18. tcls = FloatTensor(nB, nA, nG, nG, nC).fill_(0)
    19. # Convert to position relative to box
    20. # 真实框
    21. target_boxes = target[:, 2:6] * nG #target中的xywh都是0-1的,可以得到其在当前gridsize上的xywh
    22. gxy = target_boxes[:, :2]
    23. gwh = target_boxes[:, 2:]
    24. # Get anchors with best iou
    25. # 对每一个先验框计算IOU值,shape[num_anchors,num_gtboxs]
    26. # 即每一个先验框与每一个真实框的IOU
    27. ious = torch.stack([bbox_wh_iou(anchor, gwh) for anchor in anchors]) #每一种规格的anchor跟每个标签上的框的IOU得分
    28. # print (ious.shape)
    29. # 取每一个真实框IOU最大的先验框
    30. best_ious, best_n = ious.max(0)
    31. # Separate target values
    32. # 所属图片及类别标签
    33. b, target_labels = target[:, :2].long().t() # 真实框所对应的batch,以及每个框所代表的实际类别
    34. gx, gy = gxy.t()
    35. gw, gh = gwh.t()
    36. gi, gj = gxy.long().t() #位置信息,向下取整
    37. # Set masks
    38. obj_mask[b, best_n, gj, gi] = 1 # 实际包含物体网格的设置成1
    39. noobj_mask[b, best_n, gj, gi] = 0 # 实际不包含物体网格的设置成1
    40. # Set noobj mask to zero where iou exceeds ignore threshold
    41. # IOU超过了指定的阈值也看做是有物体
    42. for i, anchor_ious in enumerate(ious.t()):
    43. noobj_mask[b[i], anchor_ious > ignore_thres, gj[i], gi[i]] = 0
    44. # Coordinates 按照论文中的公式
    45. # 相对位置:获得每个网格物体真实坐标相对于左上角的偏移量
    46. tx[b, best_n, gj, gi] = gx - gx.floor()
    47. ty[b, best_n, gj, gi] = gy - gy.floor()
    48. # Width and height
    49. tw[b, best_n, gj, gi] = torch.log(gw / anchors[best_n][:, 0] + 1e-16)
    50. th[b, best_n, gj, gi] = torch.log(gh / anchors[best_n][:, 1] + 1e-16)
    51. # One-hot encoding of label
    52. tcls[b, best_n, gj, gi, target_labels] = 1 #将真实框的标签转换为one-hot编码形式
    53. # Compute label correctness and iou at best anchor 计算预测的和真实一样的索引
    54. class_mask[b, best_n, gj, gi] = (pred_cls[b, best_n, gj, gi].argmax(-1) == target_labels).float()
    55. # 与真实框想匹配的预测框之间的iou值
    56. iou_scores[b, best_n, gj, gi] = bbox_iou(pred_boxes[b, best_n, gj, gi], target_boxes, x1y1x2y2=False)
    57. tconf = obj_mask.float() # 真实框的置信度,也就是1
    58. return iou_scores, class_mask, obj_mask, noobj_mask, tx, ty, tw, th, tcls, tconf

    损失函数公式

            论文中给出的损失函数公式:

    式(10-3)中,是一个指示函数,当第i个子图像块的第j个预测框框中了目标时,=1,否则=0。因此式中

    表示包含目标的框的位置损失和置信度损失如前所述,式中x、y和\hat{x},\hat{y}分别表示预测框和目标框的中心点相对于子图像块的归一化坐标,w、h和\hat{w},\hat{h}分别表示预测框和目标框相对于整幅图像的宽和高的归一化宽和高,这部分仅将框中目标的预测框的损失进行计算和梯度回传;表示未包含目标的预测框的置信度损失,因为没有目标,其框中目标的置信度\hat{C}_{i}的值为0;公式中表示包含目标的分类损失。式中的\lambda表示加权系数,用于平衡各部分损失的比例。

    代码如下:

    1. loss_x = self.mse_loss(x[obj_mask], tx[obj_mask]) # 只计算有目标的
    2. loss_y = self.mse_loss(y[obj_mask], ty[obj_mask])
    3. loss_w = self.mse_loss(w[obj_mask], tw[obj_mask])
    4. loss_h = self.mse_loss(h[obj_mask], th[obj_mask])
    5. loss_conf_obj = self.bce_loss(pred_conf[obj_mask], tconf[obj_mask])
    6. loss_conf_noobj = self.bce_loss(pred_conf[noobj_mask], tconf[noobj_mask])
    7. loss_conf = self.obj_scale * loss_conf_obj + self.noobj_scale * loss_conf_noobj #有物体越接近1越好 没物体的越接近0越好
    8. loss_cls = self.bce_loss(pred_cls[obj_mask], tcls[obj_mask]) #分类损失
    9. total_loss = loss_x + loss_y + loss_w + loss_h + loss_conf + loss_cls #总损失

    其中,代码中的bce损失:

    f(x,y)=-\sum y_{i}log(x_{i})+(1-y_{i})log(1-x_{i})

    总体代码如下:

    1. class YOLOLayer(nn.Module):
    2. """Detection layer"""
    3. def __init__(self, anchors, num_classes, img_dim=416):
    4. super(YOLOLayer, self).__init__()
    5. self.anchors = anchors # 每个网格的预设锚框(3个)
    6. self.num_anchors = len(anchors) # 每个网格的锚框数量(3)
    7. self.num_classes = num_classes
    8. self.ignore_thres = 0.5
    9. self.mse_loss = nn.MSELoss()
    10. self.bce_loss = nn.BCELoss()
    11. self.obj_scale = 1
    12. self.noobj_scale = 100
    13. self.metrics = {}
    14. self.img_dim = img_dim
    15. self.grid_size = 0 # grid size
    16. def compute_grid_offsets(self, grid_size, cuda=True):
    17. # 网格大小
    18. self.grid_size = grid_size
    19. g = self.grid_size
    20. FloatTensor = torch.cuda.FloatTensor if cuda else torch.FloatTensor
    21. # 特征图缩放大小
    22. self.stride = self.img_dim / self.grid_size
    23. # Calculate offsets for each grid
    24. self.grid_x = torch.arange(g).repeat(g, 1).view([1, 1, g, g]).type(FloatTensor)
    25. self.grid_y = torch.arange(g).repeat(g, 1).t().view([1, 1, g, g]).type(FloatTensor)
    26. self.scaled_anchors = FloatTensor([(a_w / self.stride, a_h / self.stride) for a_w, a_h in self.anchors])
    27. self.anchor_w = self.scaled_anchors[:, 0:1].view((1, self.num_anchors, 1, 1))
    28. self.anchor_h = self.scaled_anchors[:, 1:2].view((1, self.num_anchors, 1, 1))
    29. def forward(self, x, targets=None, img_dim=None):
    30. # Tensors for cuda support
    31. print (x.shape)
    32. # 为cpu和gpu指定数据类型
    33. FloatTensor = torch.cuda.FloatTensor if x.is_cuda else torch.FloatTensor
    34. LongTensor = torch.cuda.LongTensor if x.is_cuda else torch.LongTensor
    35. ByteTensor = torch.cuda.ByteTensor if x.is_cuda else torch.ByteTensor
    36. # 图像大小,为了让模型适应多种图像,随机选取图像大小,但是都是32的倍数
    37. self.img_dim = img_dim
    38. # 一个batch有多少张图片
    39. num_samples = x.size(0)
    40. # 最终网格大小
    41. grid_size = x.size(2)
    42. # 相当于reshape操作,预测矩阵转换为:[图片数,网格h,网格w,一个网格锚框数,类别数+4(x,y,w,h)+1(是否存在物体)]
    43. prediction = (
    44. x.view(num_samples, self.num_anchors, self.num_classes + 5, grid_size, grid_size)
    45. .permute(0, 1, 3, 4, 2)
    46. .contiguous()
    47. )
    48. # print (prediction.shape)
    49. # Get outputs 将预测结果进行拆分为x,y,w,h,confidence
    50. x = torch.sigmoid(prediction[..., 0]) # Center x
    51. y = torch.sigmoid(prediction[..., 1]) # Center y
    52. w = prediction[..., 2] # Width
    53. h = prediction[..., 3] # Height
    54. # 存在物体置信度
    55. pred_conf = torch.sigmoid(prediction[..., 4]) # Conf
    56. # 类别置信度 YOLO v3使用多个sigmoid替换softmax
    57. pred_cls = torch.sigmoid(prediction[..., 5:]) # Cls pred.
    58. # If grid size does not match current we compute new offsets
    59. # 返回网格的坐标,比如14*14的特征图网格,得到每一个网格(x,y)坐标
    60. # 以及特征图缩小后,先验框的w,h
    61. if grid_size != self.grid_size:
    62. self.compute_grid_offsets(grid_size, cuda=x.is_cuda)
    63. # Add offset and scale with anchors #特征图中的实际位置
    64. # 相对位置得到对应的绝对位置比如之前的位置是0.5,0.5变为 11.5,11.5
    65. # 对特征图先验框的h,w也进行调整
    66. pred_boxes = FloatTensor(prediction[..., :4].shape)
    67. pred_boxes[..., 0] = x.data + self.grid_x
    68. pred_boxes[..., 1] = y.data + self.grid_y
    69. pred_boxes[..., 2] = torch.exp(w.data) * self.anchor_w
    70. pred_boxes[..., 3] = torch.exp(h.data) * self.anchor_h
    71. # print(pred_boxes.shape)
    72. # 将特征图的(x,y,w,h)还原到原始图像中,并reshape成[num_samples,num_anchors*grid_size*grid_size,4]
    73. output = torch.cat(
    74. (
    75. pred_boxes.view(num_samples, -1, 4) * self.stride, #还原到原始图中
    76. pred_conf.view(num_samples, -1, 1),
    77. pred_cls.view(num_samples, -1, self.num_classes),
    78. ),
    79. -1,
    80. )
    81. # print(output.shape)
    82. # 没有物体
    83. if targets is None:
    84. return output, 0
    85. else:
    86. #
    87. iou_scores, class_mask, obj_mask, noobj_mask, tx, ty, tw, th, tcls, tconf = build_targets(
    88. pred_boxes=pred_boxes,
    89. pred_cls=pred_cls,
    90. target=targets,
    91. anchors=self.scaled_anchors,
    92. ignore_thres=self.ignore_thres,
    93. )
    94. # iou_scores:真实值与最匹配的anchor的IOU得分值 class_mask:分类正确的索引 obj_mask:
    95. # 目标框所在位置的最好anchor置为1 noobj_mask obj_mask那里置0,还有计算的iou大于阈值的也置0,其他都为1
    96. # tx, ty, tw, th, 对应的对于该大小的特征图的xywh目标值也就是我们需要拟合的值
    97. # tconf 目标置信度
    98. # Loss : Mask outputs to ignore non-existing objects (except with conf. loss)
    99. loss_x = self.mse_loss(x[obj_mask], tx[obj_mask]) # 只计算有目标的
    100. loss_y = self.mse_loss(y[obj_mask], ty[obj_mask])
    101. loss_w = self.mse_loss(w[obj_mask], tw[obj_mask])
    102. loss_h = self.mse_loss(h[obj_mask], th[obj_mask])
    103. loss_conf_obj = self.bce_loss(pred_conf[obj_mask], tconf[obj_mask])
    104. loss_conf_noobj = self.bce_loss(pred_conf[noobj_mask], tconf[noobj_mask])
    105. loss_conf = self.obj_scale * loss_conf_obj + self.noobj_scale * loss_conf_noobj #有物体越接近1越好 没物体的越接近0越好
    106. loss_cls = self.bce_loss(pred_cls[obj_mask], tcls[obj_mask]) #分类损失
    107. total_loss = loss_x + loss_y + loss_w + loss_h + loss_conf + loss_cls #总损失
    108. # Metrics
    109. cls_acc = 100 * class_mask[obj_mask].mean()
    110. conf_obj = pred_conf[obj_mask].mean()
    111. conf_noobj = pred_conf[noobj_mask].mean()
    112. conf50 = (pred_conf > 0.5).float()
    113. iou50 = (iou_scores > 0.5).float()
    114. iou75 = (iou_scores > 0.75).float()
    115. detected_mask = conf50 * class_mask * tconf
    116. precision = torch.sum(iou50 * detected_mask) / (conf50.sum() + 1e-16)
    117. recall50 = torch.sum(iou50 * detected_mask) / (obj_mask.sum() + 1e-16)
    118. recall75 = torch.sum(iou75 * detected_mask) / (obj_mask.sum() + 1e-16)
    119. self.metrics = {
    120. "loss": to_cpu(total_loss).item(),
    121. "x": to_cpu(loss_x).item(),
    122. "y": to_cpu(loss_y).item(),
    123. "w": to_cpu(loss_w).item(),
    124. "h": to_cpu(loss_h).item(),
    125. "conf": to_cpu(loss_conf).item(),
    126. "cls": to_cpu(loss_cls).item(),
    127. "cls_acc": to_cpu(cls_acc).item(),
    128. "recall50": to_cpu(recall50).item(),
    129. "recall75": to_cpu(recall75).item(),
    130. "precision": to_cpu(precision).item(),
    131. "conf_obj": to_cpu(conf_obj).item(),
    132. "conf_noobj": to_cpu(conf_noobj).item(),
    133. "grid_size": grid_size,
    134. }
    135. return output, total_loss

    训练模型

     coco数据集读取与预处理

            coco数据集是采用json存储的,我们首先需要将coco数据集转为YOLO格式,如图所示:

    路径放置不重要,写绝对路径就好,train2017和val2017存入训练集和验证集图片,labels放入YOLO格式的标签,val.txt与train.txt为训练集图片名称或者地址。有用的就是这些啦,其它的就不要看啦,我习惯于将一个数据集变成多种数据集格式存储在一起,coco2yolo是我写的转YOLO的代码

     数据集文件做好之后,将文件的路径写入配置文件config/coco.data

    参数说明

    --data_config config/coco.data  
    --pretrained_weights weights/darknet53.conv.74
    --epochs:训练轮次
    --batch_size:每一批次的图片数量
    --gradient_accumulations:先累积梯度,每gradient_accumulations进行一次梯度下降
    --model_def:模型配置文件
    --data_config:数据配置文件
    --pretrained_weights:预训练模型
    --img_size:图像大小
    --checkpoint_interval:保存模型的间隔
    --evaluation_interval:在验证集验证的间隔
    --compute_map:为真,每10个批次计算一次mAP
    --multiscale_training:多尺寸训练

    训练步骤

    1.  按上述流程准备好数据

    2. 修改数据配置文件:config/coco.data

    3. 命令行指定参数或配置运行参数(配置形参)

     测试与训练参数基本一致,不在赘述

    模型的预测

    模型的预测比较简单,准备好预测图片的文件夹即可

    配置参数

    image_folder:图片路径 model_def:模型配置yolov3.cfg/yolov3-tiny.cfg weights_path:权重文件 class_path:存储数据集所有类别的txt文件 conf_thres:置信度阈值,在非极大值抑制时,当存在物体的置信度>conf_thres才认为存在物体 nms_thres:非极大值抑制时的IOU阈值,当相同类别的预测框IOU超过nms_thres即认为表示同一物体,需要过滤 batch_size:每一批次的图片数量

     运行detect.py即可

            

  • 相关阅读:
    配置企业通过5G链路接入Internet实例
    L16.linux命令每日一练 -- 第三章 文件过滤及内容编辑处理命令 -- cat和tac命令
    python+pytest接口自动化(5)-requests发送post请求
    java 企业工程管理系统软件源码+Spring Cloud + Spring Boot +二次开发+ MybatisPlus + Redis
    损失函数中的均方误差以及平方误差
    看完这篇文章,才发现我的测试用例写的就是垃圾
    Zoho Creator推出全新的Canvas布局设计器功能
    继承需要记忆的知识点
    Nerstudio 相机优化代码理解
    ArduPilot开源飞控之AP_Baro_SITL
  • 原文地址:https://blog.csdn.net/qq_52053775/article/details/126214252