深度学习从入门到精通——yolov1

YOLOV1

  • 速度快,能够达到实时的要求。在 Titan X 的 GPU 上 能够达到 45 帧每秒。

  • 使用全图作为 Context 信息,背景错误(把背景错认为物体)比较少。

  • 泛化能力强。

  • YOLO的核心思想就是利用整张图作为网络的输入,直接在输出层回归bounding box的位置和bounding box所属的类别,属于one-Stage 网络。Faster RCNN中也直接用整张图作为输入,但是faster-RCNN整体还是采用了RCNN那种 proposal+classifier的思想,只不过是将提取proposal的步骤放在CNN中实现了。

实现方法

  • 将一幅图像分成SxS个网格(grid cell),如果某个object的中心 落在这个网格中,则这个网格就负责预测这个object。

  • 每个网格要预测B个bounding box,每个bounding box除了要回归自身的位置之外,还要附带预测一个confidence值。
    这个confidence代表了所预测的box中含有object的置信度和这个box预测的有多准两重信息,其值是这样计算的:

  • 每个bounding box要预测(x, y, w, h)和confidence共5个值,每个网格还要预测一个类别信息,记为C类。则SxS个网格,每个网格要预测B个bounding box还要预测C个categories。输出就是S x S x (5*B+C)的一个tensor。
    注意:class信息是针对每个网格的,confidence信息是针对每个bounding box的。

推理细节

这段代码实现了一个基于 YOLOv1(You Only Look Once)的神经网络模型,用于目标检测任务。YOLOv1 是一种单阶段目标检测算法,它通过回归问题的方式在图像上直接预测边界框和类别。以下是对代码的详细讲解:

代码概述

这段代码定义了一个名为 YOLOv1 的神经网络模型类,继承自 nn.Module,使用 PyTorch 框架。模型分为多层卷积层和全连接层,用于特征提取和检测目标。

1. __init__ 方法

__init__ 方法用于初始化模型结构和参数。

  • 参数

    • params: 包含模型超参数的字典,如 dropoutnum_class
    • dropout_prop: Dropout 概率,用于防止过拟合。
    • num_classes: 类别数量。
  • 模型结构

    • 卷积层和池化层
      • 模型主要由 24 层卷积层(layer1layer24)组成,配合批归一化(BatchNorm)和 Leaky ReLU 激活函数。每层卷积的作用是提取图像中的特征。
      • 在特定层之后使用最大池化层(MaxPool2D)来减少特征图的尺寸,同时保留最显著的特征。
    • 全连接层
      • 两个全连接层 fc1fc2 用于最终的输出。第一个全连接层 fc1 将特征图展平并通过一层含有 4096 个神经元的层,并使用 Leaky ReLU 激活函数和 Dropout 层进行正则化。
      • 第二个全连接层 fc2 输出目标检测所需的 7x7x(5 + num_classes) 大小的张量,其中 5 包括边界框的4个坐标和置信度得分。
  • 权重初始化

    • 使用 kaiming_normal_ 方法初始化卷积层的权重,这是适合 Leaky ReLU 激活函数的一种初始化方法。
    • 批归一化层的权重初始化为 1,偏置初始化为 0。

2. forward 方法

forward 方法定义了模型的前向传播逻辑,即如何将输入图像转换为输出预测。

  • 输入

    • x: 输入图像张量,形状为 (batch_size, channels, height, width)
  • 前向传播

    • 输入图像首先通过层层卷积处理,每层的输出作为下一层的输入。
    • 卷积层的最后输出被展平(flatten),然后通过全连接层处理。
    • 输出经过两个全连接层 fc1fc2 后,得到形状为 (batch_size, 7, 7, 5 + num_classes) 的张量。
  • 输出处理

    • 对输出张量中的部分值进行 Sigmoid 函数处理:
      • out[:, :, :, 0]:边界框的置信度得分通过 Sigmoid 函数归一化到 [0, 1]。
      • out[:, :, :, 5:]:类别预测也通过 Sigmoid 函数处理,表示每个网格单元内是否存在某个类别。
  • 输出

    • 最终输出的是一个四维张量,形状为 (batch_size, 7, 7, 5 + num_classes),用于表示每个 7x7 网格的目标信息。

这段代码实现了 YOLOv1 模型,用于目标检测任务。模型通过多层卷积提取图像特征,然后通过全连接层输出每个网格内目标的边界框和类别信息。模型的输出经过 Sigmoid 函数处理,以确保输出的置信度和类别概率在合理范围内。YOLOv1 的设计使得目标检测可以在单次前向传播中完成,实现了较高的实时性。

class YOLOv1(nn.Module):def __init__(self, params):self.dropout_prop = params["dropout"]self.num_classes = params["num_class"]super(YOLOv1, self).__init__()# LAYER 1self.layer1 = nn.Sequential(nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3),nn.BatchNorm2d(64),nn.LeakyReLU(),nn.MaxPool2d(kernel_size=2, stride=2))# LAYER 2self.layer2 = nn.Sequential(nn.Conv2d(64, 192, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(192, momentum=0.01),nn.LeakyReLU(),nn.MaxPool2d(kernel_size=2, stride=2))# LAYER 3self.layer3 = nn.Sequential(nn.Conv2d(192, 128, kernel_size=1, stride=1, padding=0),nn.BatchNorm2d(128, momentum=0.01),nn.LeakyReLU())self.layer4 = nn.Sequential(nn.Conv2d(128, 256, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(256, momentum=0.01),nn.LeakyReLU())self.layer5 = nn.Sequential(nn.Conv2d(256, 256, kernel_size=1, stride=1, padding=1),nn.BatchNorm2d(256, momentum=0.01),nn.LeakyReLU())self.layer6 = nn.Sequential(nn.Conv2d(256, 512, kernel_size=3, stride=1, padding=0),nn.BatchNorm2d(512, momentum=0.01),nn.LeakyReLU(),nn.MaxPool2d(kernel_size=2, stride=2))# LAYER 4self.layer7 = nn.Sequential(nn.Conv2d(512, 256, kernel_size=1, stride=1, padding=0),nn.BatchNorm2d(256, momentum=0.01),nn.LeakyReLU())self.layer8 = nn.Sequential(nn.Conv2d(256, 512, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(512, momentum=0.01),nn.LeakyReLU())self.layer9 = nn.Sequential(nn.Conv2d(512, 256, kernel_size=1, stride=1, padding=0),nn.BatchNorm2d(256, momentum=0.01),nn.LeakyReLU())self.layer10 = nn.Sequential(nn.Conv2d(256, 512, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(512, momentum=0.01),nn.LeakyReLU())self.layer11 = nn.Sequential(nn.Conv2d(512, 256, kernel_size=1, stride=1, padding=0),nn.BatchNorm2d(256, momentum=0.01),nn.LeakyReLU())self.layer12 = nn.Sequential(nn.Conv2d(256, 512, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(512, momentum=0.01),nn.LeakyReLU())self.layer13 = nn.Sequential(nn.Conv2d(512, 256, kernel_size=1, stride=1, padding=0),nn.BatchNorm2d(256, momentum=0.01),nn.LeakyReLU())self.layer14 = nn.Sequential(nn.Conv2d(256, 512, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(512, momentum=0.01),nn.LeakyReLU())self.layer15 = nn.Sequential(nn.Conv2d(512, 512, kernel_size=1, stride=1, padding=0),nn.BatchNorm2d(512, momentum=0.01),nn.LeakyReLU())self.layer16 = nn.Sequential(nn.Conv2d(512, 1024, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(1024, momentum=0.01),nn.LeakyReLU(),nn.MaxPool2d(kernel_size=2, stride=2))# LAYER 5self.layer17 = nn.Sequential(nn.Conv2d(1024, 512, kernel_size=1, stride=1, padding=0),nn.BatchNorm2d(512, momentum=0.01),nn.LeakyReLU())self.layer18 = nn.Sequential(nn.Conv2d(512, 1024, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(1024, momentum=0.01),nn.LeakyReLU())self.layer19 = nn.Sequential(nn.Conv2d(1024, 512, kernel_size=1, stride=1, padding=0),nn.BatchNorm2d(512, momentum=0.01),nn.LeakyReLU())self.layer20 = nn.Sequential(nn.Conv2d(512, 1024, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(1024, momentum=0.01),nn.LeakyReLU())self.layer21 = nn.Sequential(nn.Conv2d(1024, 1024, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(1024, momentum=0.01),nn.LeakyReLU())self.layer22 = nn.Sequential(nn.Conv2d(1024, 1024, kernel_size=3, stride=2, padding=1),nn.BatchNorm2d(1024, momentum=0.01),nn.LeakyReLU())# LAYER 6self.layer23 = nn.Sequential(nn.Conv2d(1024, 1024, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(1024, momentum=0.01),nn.LeakyReLU())self.layer24 = nn.Sequential(nn.Conv2d(1024, 1024, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(1024, momentum=0.01),nn.LeakyReLU())self.fc1 = nn.Sequential(nn.Linear(7 * 7 * 1024, 4096),nn.LeakyReLU(),nn.Dropout(self.dropout_prop))self.fc2 = nn.Sequential(nn.Linear(4096, 7 * 7 * ((5) + self.num_classes)))for m in self.modules():if isinstance(m, nn.Conv2d):nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity="leaky_relu")elif isinstance(m, nn.BatchNorm2d):nn.init.constant_(m.weight, 1)nn.init.constant_(m.bias, 0)def forward(self, x):out = self.layer1(x)out = self.layer2(out)out = self.layer3(out)out = self.layer4(out)out = self.layer5(out)out = self.layer6(out)out = self.layer7(out)out = self.layer8(out)out = self.layer9(out)out = self.layer10(out)out = self.layer11(out)out = self.layer12(out)out = self.layer13(out)out = self.layer14(out)out = self.layer15(out)out = self.layer16(out)out = self.layer17(out)out = self.layer18(out)out = self.layer19(out)out = self.layer20(out)out = self.layer21(out)out = self.layer22(out)out = self.layer23(out)out = self.layer24(out)out = out.reshape(out.size(0), -1)out = self.fc1(out)out = self.fc2(out)out = out.reshape((-1, 7, 7, ((5) + self.num_classes)))out[:, :, :, 0] = torch.sigmoid(out[:, :, :, 0])  # sigmoid to objness1_outputout[:, :, :, 5:] = torch.sigmoid(out[:, :, :, 5:])  # sigmoid to class_outputreturn out

损失函数设计

  • 针对一个网格,一个框对应的(X,Y,W,H,C),分别代表框的信息,以及对应的置信度信息

  • 针对VOC数据集,额外判断20类别

  • 输出 20(类别信息)+置信度(置信度)+(X,Y,W,H)(位置信息)

  • lambda_coord = 5, lambda_noobj = 0.5 主要解决类别不平衡的问题,让置信度高也就是含有真实目标得损失权重更大。

这段代码实现了 YOLO(You Only Look Once)模型的损失函数,用于计算预测结果与目标标签之间的误差。YOLO 是一种单阶段目标检测算法,它将图像分成网格,并在每个网格中预测多个边界框和对应的类别概率。以下是对代码的详细解析:

代码概述

  1. one_hot 函数

    • 功能:将类别标签转换为 one-hot 编码格式,用于多类分类问题。
    • 输入
      • output: 模型的输出张量,用于确定 one-hot 编码的形状。
      • label: 标签张量,包含类别索引。
      • device: 指定使用 CPU 还是 GPU。
    • 实现
      • 先将标签从 GPU 转换到 CPU,并转换为 NumPy 数组。
      • 创建一个形状与 output 相同的零张量 dst
      • 使用嵌套循环遍历每个样本和每个网格单元,将 dst 中对应的类别位置设置为 1。
      • 最后将 dst 转换为 PyTorch 张量,并根据 device 参数选择在 CPU 还是 GPU 上进行计算。
  2. detection_loss_4_yolo 函数

    • 功能:计算 YOLO 模型的损失函数,包括坐标损失、尺寸损失、置信度损失和类别损失。
    • 输入
      • output: 模型输出的预测值,形状为 (batch_size, 7, 7, 5 + num_classes)
      • target: 真实标签值,形状与 output 相同。
      • device: 指定使用 CPU 还是 GPU。
    • 实现
      • 超参数
        • lambda_coordlambda_noobj 分别是对坐标损失和非目标置信度损失的权重,用于平衡不同部分的损失。
      • 输出和标签分割
        • outputtarget 张量按各部分切分,提取置信度、坐标偏移、宽高比例和类别预测等信息。
      • one-hot 编码
        • 使用 one_hot 函数将类别标签转换为 one-hot 编码格式。
      • 损失计算
        • 坐标损失:对目标存在的网格单元,计算预测的中心点偏移与真实值的平方误差,并乘以 lambda_coord
        • 尺寸损失:对目标存在的网格单元,计算预测的宽高平方根与真实值平方根之间的平方误差,并乘以 lambda_coord
        • 类别损失:计算类别预测与真实值的 one-hot 编码之间的平方误差。
        • 置信度损失:对目标存在的网格单元,计算预测置信度与真实置信度(1)的平方误差;对非目标存在的网格单元,计算预测置信度与零之间的平方误差,并乘以 lambda_noobj
      • 总损失:将各部分损失加总并除以批次大小,得到最终的平均损失。
  3. 返回值

    • 函数返回总损失,以及各部分损失的平均值,便于进一步分析模型的训练情况。

这段代码定义了 YOLO 模型的损失函数,用于计算模型预测与真实标签之间的误差。通过平衡各部分的损失,特别是对含有物体的格点加大权重,使得模型更关注重要的检测区域。这种设计使得 YOLO 能够在保持高效的同时,保持较高的检测精度。

def one_hot(output, label, device):label = label.cpu().data.numpy()b, s1, s2, c = output.shapedst = np.zeros([b, s1, s2, c], dtype=np.float32)for k in range(b):for i in range(s1):for j in range(s2):dst[k][i][j][int(label[k][i][j])] = 1.result = torch.from_numpy(dst)if device == 'cpu':result = result.type(torch.FloatTensor)else:result = result.type(torch.FloatTensor).cuda()return result
# def detection_loss_4_yolo(output, target):
def detection_loss_4_yolo(output, target, device):# hyper parameter# 就是让含有物体的格点,在损失函数中的权重更大,让模型更加“重视”含有物体的格点所造成的损失lambda_coord = 5lambda_noobj = 0.5# check batch sizeb, _, _, _ = target.shape_, _, _, n = output.shape# output tensor slice# output tensor shape is [batch, 7, 7, 5 + classes]# 置信度,x,y, w,h, 类别objness1_output = output[:, :, :, 0]x_offset1_output = output[:, :, :, 1]y_offset1_output = output[:, :, :, 2]width_ratio1_output = output[:, :, :, 3]height_ratio1_output = output[:, :, :, 4]class_output = output[:, :, :, 5:]num_cls = class_output.shape[-1]# label tensor sliceobjness_label = target[:, :, :, 0]x_offset_label = target[:, :, :, 1]y_offset_label = target[:, :, :, 2]width_ratio_label = target[:, :, :, 3]height_ratio_label = target[:, :, :, 4]class_label = one_hot(class_output, target[:, :, :, 5], device)#全部设置为正 noobjness_label = torch.neg(torch.add(objness_label, -1))obj_coord1_loss = lambda_coord * \torch.sum(objness_label *(torch.pow(x_offset1_output - x_offset_label, 2) +torch.pow(y_offset1_output - y_offset_label, 2)))obj_size1_loss = lambda_coord * \torch.sum(objness_label *(torch.pow(width_ratio1_output - torch.sqrt(width_ratio_label), 2) +torch.pow(height_ratio1_output - torch.sqrt(height_ratio_label), 2)))objectness_cls_map = objness_label.unsqueeze(-1)for i in range(num_cls - 1):objectness_cls_map = torch.cat((objectness_cls_map, objness_label.unsqueeze(-1)), dim=3)obj_class_loss = torch.sum(objectness_cls_map * torch.pow(class_output - class_label, 2))noobjness1_loss = lambda_noobj * torch.sum(noobjness_label * torch.pow(objness1_output - objness_label, 2))objness1_loss = torch.sum(objness_label * torch.pow(objness1_output - objness_label, 2))total_loss = (obj_coord1_loss + obj_size1_loss + noobjness1_loss + objness1_loss + obj_class_loss)total_loss = total_loss / breturn total_loss, obj_coord1_loss / b, obj_size1_loss / b, obj_class_loss / b, noobjness1_loss / b, objness1_loss / b
class YoloV1Loss(nn.Module):"""yolo-v1 损失函数定义实现"""def __init__(self, s=7, b=2, l_coord=5, l_noobj=0.5,device=torch.device('cuda' if torch.cuda.is_available() else 'cpu')):""" 为了更重视8维的坐标预测,给这些算是前面赋予更大的loss weight对于有物体的记为λcoord,在pascal VOC训练中取5,对于没有object的bbox的confidence loss,前面赋予更小的loss weight 记为 λnoobj,在pascal VOC训练中取0.5, 有object的bbox的confidence loss"""super(YoloV1Loss, self).__init__()self.s = s  # 正方形网格数self.b = b  # 每个格的预测框数self.l_coord = l_coord  # 损失函数坐标回归权重self.l_noobj = l_noobj  # 损失函数类别分类权重self.device = devicedef forward(self, predict_tensor, target_tensor):""":param predict_tensor:(tensor) size(batch_size, S, S, Bx5+20=30) [x, y, w, h, c]---预测对应的格式:param target_tensor:(tensor) size(batch_size, S, S, 30) --- 标签的准确格式:return:"""N = predict_tensor.size()[0]# 具有目标标签的索引(bs, 7, 7, 30)中7*7方格中的哪个方格包含目标coo_mask = target_tensor[:, :, :, 4] > 0  # coo_mask.shape = (bs, 7, 7)# 不具有目标的标签索引noo_mask = target_tensor[:, :, :, 4] == 0# 得到含物体的坐标等信息(coo_mask扩充到与target_tensor一样形状, 沿最后一维扩充)coo_mask = coo_mask.unsqueeze(-1).expand_as(target_tensor)# 得到不含物体的坐标等信息noo_mask = noo_mask.unsqueeze(-1).expand_as(target_tensor)# coo_pred:tensor[, 30](所有batch数据都压缩在一起)coo_pred = predict_tensor[coo_mask].view(-1, 30)# box[x1,y1,w1,h1,c1], [x2,y2,w2,h2,c2]box_pred = coo_pred[:, :10].contiguous().view(-1, 5)# class[...]class_pred = coo_pred[:, 10:]coo_target = target_tensor[coo_mask].view(-1, 30)box_target = coo_target[:, :10].contiguous().view(-1, 5)class_target = coo_target[:, 10:]# compute not contain obj lossnoo_pred = predict_tensor[noo_mask].view(-1, 30)noo_target = target_tensor[noo_mask].view(-1, 30)# noo pred只需要计算 Obj1、2 的损失 size[,2]noo_pred_mask = torch.ByteTensor(noo_pred.size()).to(self.device)noo_pred_mask.zero_()noo_pred_mask[:, 4] = 1noo_pred_mask[:, 9] = 1# 获取不包含目标框的置信度值noo_pred_c = noo_pred[noo_pred_mask]noo_target_c = noo_target[noo_pred_mask]# 不含object bbox confidence 预测nooobj_loss = F.mse_loss(noo_pred_c, noo_target_c, reduction='sum')# compute contain obj losscoo_response_mask = torch.ByteTensor(box_target.size()).to(self.device)coo_response_mask.zero_()coo_not_response_mask = torch.ByteTensor(box_target.size()).to(self.device)coo_not_response_mask.zero_()box_target_iou = torch.zeros(box_target.size()).to(self.device)# 从两个gt bbox框中二选一(同一个格点的两个gt bbox是一样的)for i in range(0, box_target.size()[0], 2):# choose the best iou boxbox1 = box_pred[i:i + self.b]  # 获取当前格点预测的b个boxbox1_xyxy = torch.FloatTensor(box1.size())# (x,y,w,h)box1_xyxy[:, :2] = box1[:, :2] / self.s - 0.5 * box1[:, 2:4]box1_xyxy[:, 2:4] = box1[:, :2] / self.s + 0.5 * box1[:, 2:4]box2 = box_target[i].view(-1, 5)box2_xyxy = torch.FloatTensor(box2.size())box2_xyxy[:, :2] = box2[:, :2] / self.s - 0.5 * box2[:, 2:4]box2_xyxy[:, 2:4] = box2[:, :2] / self.s + 0.5 * box2[:, 2:4]# iou(pred_box[2,], target_box[2,])iou = self.compute_iou(box1_xyxy[:, :4], box2_xyxy[:, :4])# target匹配到的box, 在self.b个预测box中获取与target box iou 值最大的那个的索引max_iou, max_index = iou.max(0)_logger.info("max_iou: {}, max_index:{}".format(max_iou, max_index))max_index = max_index.to(self.device)coo_response_mask[i + max_index] = 1coo_not_response_mask[i + 1 - max_index] = 1'''we want the confidence score to equal theintersection over union (IOU) between the predicted boxand the ground truth'''# iou value 作为box包含目标的confidence(赋值在向量的第五个位置)box_target_iou[i + max_index, torch.LongTensor([4]).to(self.device)] = max_iou.to(self.device)box_target_iou = box_target_iou.to(self.device)# 1.response loss# temp = box_pred[coo_response_mask]# box_pred[coo_response_mask]将coo_response_mask对应值为1的索引在box_pred的值取出组成一维向量box_pred_response = box_pred[coo_response_mask].view(-1, 5)box_target_response_iou = box_target_iou[coo_response_mask].view(-1, 5)box_target_response = box_target[coo_response_mask].view(-1, 5)# 包含目标box confidence的损失contain_loss = F.mse_loss(box_pred_response[:, 4], box_target_response_iou[:, 4], reduction='sum')# 包含目标box的损失loc_loss = (F.mse_loss(box_pred_response[:, :2],box_target_response[:, :2],reduction='sum') +F.mse_loss(torch.sqrt(box_pred_response[:, 2:4]),torch.sqrt(box_target_response[:, 2:4]),reduction='sum'))# 2.not response lossbox_pred_not_response = box_pred[coo_not_response_mask].view(-1, 5)box_target_not_response = box_target[coo_not_response_mask].view(-1, 5)box_target_not_response[:, 4] = 0# not_contain_loss = F.mse_loss(box_pred_response[:,4], box_target_response[:,4], size_average=False)# I believe this bug is simply a typo(包含目标格点上不包含目标的box confidence的损失)not_contain_loss = F.mse_loss(box_pred_not_response[:, 4], box_target_not_response[:, 4], reduction='sum')# 3.class loss(分类损失)class_loss = F.mse_loss(class_pred, class_target, reduction='sum')return (self.l_coord * loc_loss + 2 * contain_loss +not_contain_loss + self.l_noobj * nooobj_loss + class_loss) / Ndef compute_iou(self, box1, box2):"""iou的作用是,当一个物体有多个框时,选一个相比ground truth最大的执行度的为物体的预测,然后将剩下的框降序排列,如果后面的框中有与这个框的iou大于一定的阈值时则将这个框舍去(这样就可以抑制一个物体有多个框的出现了),目标检测算法中都会用到这种思想。Compute the intersection over union of two set of boxes, each box is [x1,y1,x2,y2].Args:box1: (tensor) bounding boxes, sized [N,4].box2: (tensor) bounding boxes, sized [M,4].Return:(tensor) iou, sized [N,M]."""N = box1.size(0)M = box2.size(0)# torch.max(input, other, out=None) → Tensor# Each element of the tensor input is compared with the corresponding element# of the tensor other and an element-wise maximum is taken.# left toplt = torch.max(box1[:, :2].unsqueeze(1).expand(N, M, 2),  # [N,2] -> [N,1,2] -> [N,M,2]box2[:, :2].unsqueeze(0).expand(N, M, 2),  # [M,2] -> [1,M,2] -> [N,M,2])# right bottomrb = torch.min(box1[:, 2:].unsqueeze(1).expand(N, M, 2),  # [N,2] -> [N,1,2] -> [N,M,2]box2[:, 2:].unsqueeze(0).expand(N, M, 2),  # [M,2] -> [1,M,2] -> [N,M,2])wh = rb - lt  # [N,M,2]wh[wh < 0] = 0  # clip at 0inter = wh[:, :, 0] * wh[:, :, 1]  # [N,M]area1 = (box1[:, 2] - box1[:, 0]) * (box1[:, 3] - box1[:, 1])  # [N,]area2 = (box2[:, 2] - box2[:, 0]) * (box2[:, 3] - box2[:, 1])  # [M,]area1 = area1.unsqueeze(1).expand_as(inter)  # [N,] -> [N,1] -> [N,M]area2 = area2.unsqueeze(0).expand_as(inter)  # [M,] -> [1,M] -> [N,M]iou = inter / (area1 + area2 - inter)return iou

缺点

  • YOLO对相互靠的很近的物体,还有很小的群体 检测效果不好,这是因为一个网格中只预测了两个框,并且只属于一类。
  • 对测试图像中,同一类物体出现的新的不常见的长宽比和其他情况是。泛化能力偏弱。
  • 由于损失函数的问题,定位误差是影响检测效果的主要原因。尤其是大小物体的处理上,还有待加强。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/53309.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Agent AI智能体的未来:角色、发展路径及挑战

引言 人工智能技术的迅猛发展正在深刻改变我们的生活和社会结构。其中&#xff0c;Agent AI智能体作为人工智能领域的一个重要分支&#xff0c;因其高度的自主性和适应性而备受关注。Agent AI智能体不仅可以执行复杂的任务&#xff0c;还能根据环境变化自我调整策略&#xff0…

数据库和MySQL

ER图 实体&#xff08;矩形&#xff09;&#xff1a;通常是现实世界的业务对象&#xff0c;当然使用一些逻辑对象也可以。 属性&#xff08;椭圆&#xff09;&#xff1a;实体拥有的属性。 联系&#xff08;菱形&#xff09;&#xff1a;实体与实体之间的关系。 函数依赖 函数依…

【JVM】Java内存分配与回收:深入理解Java内存管理

Java内存分配与回收&#xff1a;深入理解Java内存管理 引言 Java虚拟机&#xff08;JVM&#xff09;的内存管理是确保Java应用程序性能和稳定性的关键。理解Java的内存分配方式和回收过程对于开发者来说至关重要。 基础知识 JVM内存模型&#xff1a;JVM内存分为堆&#xff…

(11)(1.1) 有刷电机

文章目录 前言 1 经过验证的电机驱动器 2 连接和配置 3 参数说明 前言 ArduPilot 支持多种控制有刷电机的方法。 支持 RC PWM 输入&#xff08;宽度为 1ms 至 2ms 的 PWM 信号&#xff09;的有刷电机 ESC 最容易使用&#xff0c;因为不需要特殊配置&#xff0c;本文档的其…

使用python+opencv解析图像和文本数据

1. 创建虚拟环境 新建文件夹, 并在文件夹中创建虚拟环境,可以使用Vscode打开文件夹, 然后在终端中输入以下命令: python -m venv venv2. 激活虚拟环境 在终端中输入以下命令: venv\Scripts\activate3. 安装依赖 在终端中输入以下命令: pip install opencv-pythonpip inst…

5.程序转换语意学

目录 1.显示的初始化操作 2.参数的初始化 3.返回值的初始化 4.在使用者层面做优化 5.Copy Constructor要不要&#xff1f; 1.显示的初始化操作 已知有这样的定义&#xff1a; X x0; 下面的三个定义&#xff0c;每一个都明显地以x0来初始化其class object&#xff1b; …

深度学习示例2-多输入多输出的神经网络模型

一、代码示例 from tensorflow import keras from tensorflow.keras import layers import numpy as np# 定义 多输入 多输出的模型 vocabulary_size = 1000 num_tags = 100 num_departments = 4title = keras.Input(shape=(vocabulary_size,), name = "title") tex…

kali——msfconsole的使用

目录 前言 msfconsole的使用基础 启动mfsconsole 各种辅助模块的使用 端口扫描模块&#xff08;portscan&#xff09; 查看端口扫描的模块 使用模块 查看所需设置 手动设置 执行 退出 各种漏洞模块的使用 nmap扫描主机漏洞 查看漏洞模块 使用漏洞模块 查看所需设…

Prometheus通过node_exporter监控Node节点,Node节点的详细指标解读

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

webpack基本使用(基础)

文章目录 概要理解 一、使用示例1.引入库2.创建config/webpack.dev.js 测试环境3.创建config/webpack.prod.js 正式环境3.创建eslintrc.js4.创建babel.config.js5.package.json 总结 概要理解 vue或者react 通常用webpack作为打包工具&#xff0c;打包成浏览器识别的html、css…

吴恩达深度学习笔记:卷积神经网络(Foundations of Convolutional Neural Networks)1.9-1.10

目录 第四门课 卷积神经网络&#xff08;Convolutional Neural Networks&#xff09;第一周 卷积神经网络&#xff08;Foundations of Convolutional Neural Networks&#xff09;1.9 池化层&#xff08;Pooling layers&#xff09;1.10 卷 积 神 经 网 络 示 例 &#xff08; …

Linux_kernel汇编驱动06

一、ARM汇编语言&#xff08;GUN-gcc编译器下&#xff09; 1、语句格式 {symbol} {instruction|directive|pseudo-instruction} { comment} symbol&#xff1a;为符号。 在ARM汇编语言中&#xff0c;符号必须从一行的行头开始&#xff0c;并且符号中不能包含空格。 在指令和伪指…

基于C++实现(MFC界面)家谱管理系统

一、题目&#xff1a;家谱管理系统 二、内容&#xff1a; 2.1 概述 2.1.1 选题原因 做此题的原因是因为可以比较方便的记录家族历代成员的情况与关系&#xff0c;能很好的保存家族每一代的信息&#xff0c;而不用人工纸质的方式来存取家谱&#xff0c;更便于人们保存和使用…

爬虫练习(js逆向解密)

目标 网站地址交易列表 - 福建省公共资源交易电子公共服务平台 (fj.gov.cn) 抓取内容如下&#xff1a; 分析 查找js代码 点击下一页翻页的时候&#xff0c;查看请求返回的数据&#xff0c;发现data数据是经过加密后得到的 通过全局搜索data,发现有两千多个结果&#xff0c;一个…

AI超强语音转文本SenseVoice,本地化部署教程!

文章目录 模型介绍SenseVoice在线预览链接本地化部署VsCode 远程连接 模型介绍 SenseVoice专注于高精度多语言语音识别、情感辨识和音频事件检测 多语言识别&#xff1a; 采用超过40万小时数据训练&#xff0c;支持超过50种语言&#xff0c;识别效果上优于Whisper模型。富文本…

【Kubernetes知识点问答题】Docker CE 部署

目录 1.ca-certificates, gnupg, lsb-release 三个包的解释。 2.docker-ce, docker-ce-cli, containerd.io, docker-compose-plugin 作用。 3.K8s 在 1.2 之后就不再支持 docker&#xff0c;请解释对错。 4.举例说明创建容器以及以交互方式访问容器的命令&#xff1f; 1.ca-…

跨境电商代购系统中前台基本功能介绍:帮助更快的了解跨境代购业务

前台多语言&#xff1a;可支持语言有中文&#xff08;繁体&#xff09;中文&#xff08;简体&#xff09;英文等。多语言使用百度翻译引擎接口实现&#xff0c;翻译效果与百度一致&#xff1b;网站语言分为两大块&#xff1a;1.系统后台有语言包可以编辑修改网站标题以及发布文…

WPS中JS宏使用说明(持续优化...)

前言 好久没发文章了&#xff0c;今天闲来无事发篇文章找找之前的码字感觉。 正文 最近在写教案&#xff0c;发现之前的技术又可以派上用场了。就是JS&#xff0c;全称JavaScript&#xff0c;这个语言太强大了&#xff0c;我发现WPS里的宏现在默认就是JS。功能选项如下图&…

MySQL数据库安装(详细)—>Mariadb的安装(day21)

该网盘链接有效期为7天&#xff0c;有需要评论区扣我&#xff1a; 通过网盘分享的文件&#xff1a;mariadb-10.3.7-winx64.msi 链接: https://pan.baidu.com/s/1-r_w3NuP8amhIEedmTkWsQ?pwd2ua7 提取码: 2ua7 1 双击打开安装软件 本次安装的是mariaDB&#xff0c;双击打开mar…

Java运行环境的下载、安装、配置与运行

一、实验目的及要求 目的&#xff1a;掌握如何下载java JDK软件包&#xff0c;如何设置Java程序的运行环境&#xff0c;如何编写与运行Java程序&#xff0c;了解Java概貌。 要求&#xff1a; 1、安装Java JDK软件包&#xff1b; 2、练习编写简单的Java Application程序并掌握…