精华内容
下载资源
问答
  • 睿智的目标检测29——Pytorch搭建Centernet目标检测平台学习前言什么是Centernet目标检测算法源码下载Centernet实现思路一、预测部分1、主干网络介绍2、利用初步特征获得高分辨率特征图3、Center Head从特征获取预测...

    学习前言

    Pytorch版本的实现也要做一下。
    在这里插入图片描述

    什么是Centernet目标检测算法

    在这里插入图片描述
    如今常见的目标检测算法通常使用先验框的设定,即先在图片上设定大量的先验框,网络的预测结果会对先验框进行调整获得预测框,先验框很大程度上提高了网络的检测能力,但是也会收到物体尺寸的限制。

    Centernet采用不同的方法,构建模型时将目标作为一个点——即目标BBox的中心点。

    Centernet的检测器采用关键点估计来找到中心点,并回归到其他目标属性。
    在这里插入图片描述
    论文中提到:模型是端到端可微的,更简单,更快,更精确。Centernet的模型实现了速度和精确的很好权衡。

    源码下载

    https://github.com/bubbliiiing/centernet-pytorch
    喜欢的可以点个star噢。

    Centernet实现思路

    一、预测部分

    1、主干网络介绍

    Centernet用到的主干特征网络有多种,一般是以Hourglass Network、DLANet或者Resnet为主干特征提取网络,由于centernet所用到的Hourglass Network参数量太大,有19000W参数,DLANet并没有keras资源,本文以Resnet为例子进行解析。

    ResNet50有两个基本的块,分别名为Conv Block和Identity Block,其中Conv Block输入和输出的维度是不一样的,所以不能连续串联,它的作用是改变网络的维度;Identity Block输入维度和输出维度相同,可以串联,用于加深网络的。
    Conv Block的结构如下:
    在这里插入图片描述
    Identity Block的结构如下:
    在这里插入图片描述
    这两个都是残差网络结构。
    当我们输入的图片是512x512x3的时候,整体的特征层shape变化为:
    在这里插入图片描述
    我们取出最终一个block的输出进行下一步的处理。也就是图上的C5,它的shape为16x16x2048。利用主干特征提取网络,我们获取到了一个初步的特征层,其shape为16x16x2048。

    from __future__ import absolute_import
    from __future__ import division
    from __future__ import print_function
    
    import pdb
    import math
    import torch
    import torch.nn as nn
    import torch.nn.functional as F
    import torch.utils.model_zoo as model_zoo
    from torchvision.models.utils import load_state_dict_from_url
    from torch.autograd import Variable
    
    
    model_urls = {
    'resnet18': 'https://s3.amazonaws.com/pytorch/models/resnet18-5c106cde.pth',
    'resnet34': 'https://s3.amazonaws.com/pytorch/models/resnet34-333f7ec4.pth',
    'resnet50': 'https://s3.amazonaws.com/pytorch/models/resnet50-19c8e357.pth',
    'resnet101': 'https://s3.amazonaws.com/pytorch/models/resnet101-5d3b4d8f.pth',
    'resnet152': 'https://s3.amazonaws.com/pytorch/models/resnet152-b121ed2d.pth',
    }
    
    
    class Bottleneck(nn.Module):
        expansion = 4
    
        def __init__(self, inplanes, planes, stride=1, downsample=None):
            super(Bottleneck, self).__init__()
            self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, stride=stride, bias=False) # change
            self.bn1 = nn.BatchNorm2d(planes)
            self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=1, # change
                        padding=1, bias=False)
            self.bn2 = nn.BatchNorm2d(planes)
            self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False)
            self.bn3 = nn.BatchNorm2d(planes * 4)
            self.relu = nn.ReLU(inplace=True)
            self.downsample = downsample
            self.stride = stride
    
        def forward(self, x):
            residual = x
    
            out = self.conv1(x)
            out = self.bn1(out)
            out = self.relu(out)
    
            out = self.conv2(out)
            out = self.bn2(out)
            out = self.relu(out)
    
            out = self.conv3(out)
            out = self.bn3(out)
    
            if self.downsample is not None:
                residual = self.downsample(x)
    
            out += residual
            out = self.relu(out)
    
            return out
    
    
    class ResNet(nn.Module):
        def __init__(self, block, layers, num_classes=1000):
            self.inplanes = 64
            super(ResNet, self).__init__()
            self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3,bias=False)
            self.bn1 = nn.BatchNorm2d(64)
            self.relu = nn.ReLU(inplace=True)
            self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=0, ceil_mode=True) # change
            self.layer1 = self._make_layer(block, 64, layers[0])
            self.layer2 = self._make_layer(block, 128, layers[1], stride=2)
            self.layer3 = self._make_layer(block, 256, layers[2], stride=2)
            self.layer4 = self._make_layer(block, 512, layers[3], stride=2)
            
            self.avgpool = nn.AvgPool2d(7)
            self.fc = nn.Linear(512 * block.expansion, num_classes)
    
            for m in self.modules():
                if isinstance(m, nn.Conv2d):
                    n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
                    m.weight.data.normal_(0, math.sqrt(2. / n))
                elif isinstance(m, nn.BatchNorm2d):
                    m.weight.data.fill_(1)
                    m.bias.data.zero_()
    
        def _make_layer(self, block, planes, blocks, stride=1):
            downsample = None
            if stride != 1 or self.inplanes != planes * block.expansion:
                downsample = nn.Sequential(
                    nn.Conv2d(self.inplanes, planes * block.expansion,
                        kernel_size=1, stride=stride, bias=False),
                nn.BatchNorm2d(planes * block.expansion),
            )
    
            layers = []
            layers.append(block(self.inplanes, planes, stride, downsample))
            self.inplanes = planes * block.expansion
            for i in range(1, blocks):
                layers.append(block(self.inplanes, planes))
    
            return nn.Sequential(*layers)
    
        def forward(self, x):
            x = self.conv1(x)
            x = self.bn1(x)
            x = self.relu(x)
            x = self.maxpool(x)
    
            x = self.layer1(x)
            x = self.layer2(x)
            x = self.layer3(x)
            x = self.layer4(x)
    
            x = self.avgpool(x)
            x = x.view(x.size(0), -1)
            x = self.fc(x)
    
            return x
    
    def resnet50(pretrain = True):
        model = ResNet(Bottleneck, [3, 4, 6, 3])
        
        if pretrain:
            state_dict = load_state_dict_from_url(model_urls['resnet50'])
            model.load_state_dict(state_dict)
    
        # 获取特征提取部分
        features = list([model.conv1, model.bn1, model.relu, model.maxpool, model.layer1, model.layer2, model.layer3, model.layer4])
        features = nn.Sequential(*features)
        return features
    

    2、利用初步特征获得高分辨率特征图

    在这里插入图片描述
    利用上一步获得到的resnet50的最后一个特征层的shape为(16,16,2048)。

    对于该特征层,centernet利用三次反卷积进行上采样,从而更高的分辨率输出。为了节省计算量,这3个反卷积的输出通道数分别为256,128,64。

    每一次反卷积,特征层的高和宽会变为原来的两倍,因此,在进行三次反卷积上采样后,我们获得的特征层的高和宽变为原来的8倍,此时特征层的高和宽为128x128,通道数为64。

    此时我们获得了一个128x128x64的有效特征层(高分辨率特征图),我们会利用该有效特征层获得最终的预测结果。

    实现代码如下:

    #---------------------------------------#
    #   进行三次上采样
    #---------------------------------------#
    class Decoder(nn.Module):
        def __init__(self, inplanes, bn_momentum=0.1):
            super(Decoder, self).__init__()
            self.bn_momentum = bn_momentum
    
            self.inplanes = inplanes
            self.deconv_with_bias = False
            # 16, 16, 2048  ->  32, 32, 256 -> 64, 64, 128 -> 128, 128, 64
            self.deconv_layers = self._make_deconv_layer(
                num_layers=3,
                num_filters=[256, 128, 64],
                num_kernels=[4, 4, 4],
            )
    
        def _make_deconv_layer(self, num_layers, num_filters, num_kernels):
            layers = []
            for i in range(num_layers):
                kernel = num_kernels[i]
                planes = num_filters[i]
    
                layers.append(
                    nn.ConvTranspose2d(
                        in_channels=self.inplanes,
                        out_channels=planes,
                        kernel_size=kernel,
                        stride=2,
                        padding=1,
                        output_padding=0,
                        bias=self.deconv_with_bias))
                layers.append(nn.BatchNorm2d(planes, momentum=self.bn_momentum))
                layers.append(nn.ReLU(inplace=True))
                self.inplanes = planes
            return nn.Sequential(*layers)
    
        def forward(self, x):
            return self.deconv_layers(x)
    

    3、Center Head从特征获取预测结果

    在这里插入图片描述
    通过上一步我们可以获得一个128x128x64的高分辨率特征图。

    这个特征层相当于将整个图片划分成128x128个区域,每个区域存在一个特征点,如果某个物体的中心落在这个区域,那么就由这个特征点来确定。
    某个物体的中心落在这个区域,则由这个区域左上角的特征点来约定

    我们可以利用这个特征层进行三个卷积,分别是:
    1、热力图预测,此时卷积的通道数为num_classes,最终结果为(128,128,num_classes),代表每一个热力点是否有物体存在,以及物体的种类;
    2、中心点预测,此时卷积的通道数为2,最终结果为(128,128,2),代表每一个物体中心距离热力点偏移的情况;
    3、宽高预测,此时卷积的通道数为2,最终结果为(128,128,2),代表每一个物体宽高的预测情况;

    在这里插入图片描述
    实现代码为:

    #---------------------------------------#
    #   CenterHead
    #   利用特征层获得最终的预测结果
    #---------------------------------------#
    class Head(nn.Module):
        def __init__(self, num_classes=80, out_channel=64, bn_momentum=0.1):
            super(Head, self).__init__()
    
            self.cls_head = nn.Sequential(
                nn.Conv2d(64, out_channel,
                          kernel_size=3, padding=1, bias=False),
                nn.BatchNorm2d(out_channel, momentum=bn_momentum),
                nn.ReLU(inplace=True),
                nn.Conv2d(out_channel, num_classes,
                          kernel_size=1, stride=1, padding=0))
            self.wh_head = nn.Sequential(
                nn.Conv2d(64, out_channel,
                          kernel_size=3, padding=1, bias=False),
                nn.BatchNorm2d(out_channel, momentum=bn_momentum),
                nn.ReLU(inplace=True),
                nn.Conv2d(out_channel, 2,
                          kernel_size=1, stride=1, padding=0))
            self.reg_head = nn.Sequential(
                nn.Conv2d(64, out_channel,
                          kernel_size=3, padding=1, bias=False),
                nn.BatchNorm2d(out_channel, momentum=bn_momentum),
                nn.ReLU(inplace=True),
                nn.Conv2d(out_channel, 2,
                          kernel_size=1, stride=1, padding=0))
    
        def forward(self, x):
            hm = self.cls_head(x).sigmoid_()
            wh = self.wh_head(x)
            offset = self.reg_head(x)
            return hm, wh, offset
    

    4、预测结果的解码

    在对预测结果进行解码之前,我们再来看看预测结果代表了什么,预测结果可以分为3个部分:

    1、heatmap热力图预测,此时卷积的通道数为num_classes,最终结果为(128,128,num_classes),代表每一个热力点是否有物体存在,以及物体的种类,最后一维度num_classes中的预测值代表属于每一个类的概率;
    2、reg中心点预测,此时卷积的通道数为2,最终结果为(128,128,2),代表每一个物体中心距离热力点偏移的情况,最后一维度2中的预测值代表当前这个特征点向右下角偏移的情况;
    3、wh宽高预测,此时卷积的通道数为2,最终结果为(128,128,2),代表每一个物体宽高的预测情况,最后一维度2中的预测值代表当前这个特征点对应的预测框的宽高;

    特征层相当于将图像划分成128x128个特征点每个特征点负责预测中心落在其右下角一片区域的物体。在这里插入图片描述

    如图所示,蓝色的点为128x128的特征点,此时我们对左图红色的三个点进行解码操作演示:
    1、进行中心点偏移,利用reg中心点预测对特征点坐标进行偏移,左图红色的三个特征点偏移后是右图橙色的三个点;
    2、利用中心点加上和减去 wh宽高预测结果除以2,获得预测框的左上角和右下角。
    3、此时获得的预测框就可以绘制在图片上了。
    在这里插入图片描述
    除去这样的解码操作,还有非极大抑制的操作需要进行,防止同一种类的框的堆积。

    在论文中所说,centernet不像其它目标检测算法,在解码之后需要进行非极大抑制,centernet的非极大抑制在解码之前进行。采用的方法是最大池化利用3x3的池化核在热力图上搜索,然后只保留一定区域内得分最大的框。

    在实际使用时发现,当目标为小目标时,确实可以不在解码之后进行非极大抑制的后处理,如果目标为大目标,网络无法正确判断目标的中心时,还是需要进行非击大抑制的后处理的。

    def pool_nms(hm, pool_size=3):
        pad = (pool_size - 1) // 2
        hm_max = F.max_pool2d(hm, pool_size, stride=1, padding=pad)
        keep = (hm_max == hm).float()
        return hm * keep
    
    def decode_bbox(pred_hms, pred_whs, pred_offsets, image_size, threshold, cuda, topk=100):
        pred_hms = pool_nms(pred_hms)
        
        h, w = image_size[0], image_size[1]
        b, c, output_h, output_w = pred_hms.shape
        detects = []
        for batch in range(b):
            heat_map    = pred_hms[batch].permute(1,2,0).view([-1,c])
            pred_wh     = pred_whs[batch].permute(1,2,0).view([-1,2])
            pred_offset = pred_offsets[batch].permute(1,2,0).view([-1,2])
    
            yv, xv = torch.meshgrid(torch.arange(0, output_w), torch.arange(0, output_h))
    
            xv, yv = xv.flatten().float(), yv.flatten().float()
            if cuda:
                xv = xv.cuda()
                yv = yv.cuda()
    
            class_conf, class_pred = torch.max(heat_map, dim=-1)
            mask = class_conf > threshold
    
            pred_wh_mask = pred_wh[mask]
            pred_offset_mask = pred_offset[mask]
            if len(pred_wh_mask)==0:
                detects.append([])
                continue     
            xv_mask = torch.unsqueeze(xv[mask] + pred_offset_mask[..., 0],-1)
            yv_mask = torch.unsqueeze(yv[mask] + pred_offset_mask[..., 1],-1)
    
            half_w, half_h = pred_wh_mask[..., 0:1] / 2, pred_wh_mask[..., 1:2] / 2
            bboxes = torch.cat([xv_mask - half_w, yv_mask - half_h, xv_mask + half_w, yv_mask + half_h], dim=1)
            bboxes[:, [0, 2]] *= w / output_w
            bboxes[:, [1, 3]] *= h / output_h
    
            detect = torch.cat([bboxes,torch.unsqueeze(class_conf[mask],-1),torch.unsqueeze(class_pred[mask],-1).float()],dim=-1)
    
            arg_sort = torch.argsort(detect[:,-2], descending=True)
            detect = detect[arg_sort]
    
            detects.append(detect.cpu().numpy()[:topk])
        return detects
    

    5、在原图上进行绘制

    通过第三步,我们可以获得预测框在原图上的位置,而且这些预测框都是经过筛选的。这些筛选后的框可以直接绘制在图片上,就可以获得结果了。

    二、训练部分

    1、真实框的处理

    既然在centernet中,物体的中心落在哪个特征点的右下角就由哪个特征点来负责预测,那么在训练的时候我们就需要找到真实框和特征点之间的关系。

    真实框和特征点之间的关系,对应方式如下:
    1、找到真实框的中心,通过真实框的中心找到其对应的特征点。
    2、根据该真实框的种类,对网络应该有的热力图进行设置,即heatmap热力图。其实就是将对应的特征点里面的对应的种类,它的中心值设置为1,然后这个特征点附近的其它特征点中该种类对应的值按照高斯分布不断下降
    在这里插入图片描述
    3、除去heatmap热力图外,还需要设置特征点对应的reg中心点和wh宽高,在找到真实框对应的特征点后,还需要设置该特征点对应的reg中心和wh宽高。这里的reg中心和wh宽高都是对于128x128的特征层的。
    4、在获得网络应该有的预测结果后,就可以将预测结果和应该有的预测结果进行对比,对网络进行反向梯度调整了。

    实现代码如下:

    class Generator(object):
        def __init__(self,batch_size,train_lines,val_lines,
                    input_size,num_classes):
            
            self.batch_size = batch_size
            self.train_lines = train_lines
            self.val_lines = val_lines
            self.input_size = input_size
            self.output_size = (int(input_size[0]/4) , int(input_size[1]/4))
            self.num_classes = num_classes
            
        def get_random_data(self, annotation_line, input_shape, random=True, jitter=.3, hue=.1, sat=1.5, val=1.5, proc_img=True):
            '''r实时数据增强的随机预处理'''
            line = annotation_line.split()
            image = Image.open(line[0])
            iw, ih = image.size
            h, w = input_shape
            box = np.array([np.array(list(map(int,box.split(',')))) for box in line[1:]])
    
            # resize image
            new_ar = w/h * rand(1-jitter,1+jitter)/rand(1-jitter,1+jitter)
            scale = rand(0.5, 1.5)
            if new_ar < 1:
                nh = int(scale*h)
                nw = int(nh*new_ar)
            else:
                nw = int(scale*w)
                nh = int(nw/new_ar)
            image = image.resize((nw,nh), Image.BICUBIC)
    
            # place image
            dx = int(rand(0, w-nw))
            dy = int(rand(0, h-nh))
            new_image = Image.new('RGB', (w,h), (128,128,128))
            new_image.paste(image, (dx, dy))
            image = new_image
    
            # flip image or not
            flip = rand()<.5
            if flip: image = image.transpose(Image.FLIP_LEFT_RIGHT)
    
            # distort image
            hue = rand(-hue, hue)
            sat = rand(1, sat) if rand()<.5 else 1/rand(1, sat)
            val = rand(1, val) if rand()<.5 else 1/rand(1, val)
            x = cv2.cvtColor(np.array(image,np.float32)/255, cv2.COLOR_RGB2HSV)
            x[..., 0] += hue*360
            x[..., 0][x[..., 0]>1] -= 1
            x[..., 0][x[..., 0]<0] += 1
            x[..., 1] *= sat
            x[..., 2] *= val
            x[x[:,:, 0]>360, 0] = 360
            x[:, :, 1:][x[:, :, 1:]>1] = 1
            x[x<0] = 0
            image_data = cv2.cvtColor(x, cv2.COLOR_HSV2RGB)*255
    
            # correct boxes
            box_data = np.zeros((len(box),5))
            if len(box)>0:
                np.random.shuffle(box)
                box[:, [0,2]] = box[:, [0,2]]*nw/iw + dx
                box[:, [1,3]] = box[:, [1,3]]*nh/ih + dy
                if flip: box[:, [0,2]] = w - box[:, [2,0]]
                box[:, 0:2][box[:, 0:2]<0] = 0
                box[:, 2][box[:, 2]>w] = w
                box[:, 3][box[:, 3]>h] = h
                box_w = box[:, 2] - box[:, 0]
                box_h = box[:, 3] - box[:, 1]
                box = box[np.logical_and(box_w>1, box_h>1)] # discard invalid box
                box_data = np.zeros((len(box),5))
                box_data[:len(box)] = box
            if len(box) == 0:
                return image_data, []
    
            if (box_data[:,:4]>0).any():
                return image_data, box_data
            else:
                return image_data, []
    
        def generate(self, train=True):
            while True:
                if train:
                    # 打乱
                    shuffle(self.train_lines)
                    lines = self.train_lines
                else:
                    shuffle(self.val_lines)
                    lines = self.val_lines
                batch_images = np.zeros((self.batch_size, self.input_size[2], self.input_size[0], self.input_size[1]), dtype=np.float32)
    
                batch_hms = np.zeros((self.batch_size, self.output_size[0], self.output_size[1], self.num_classes),
                                    dtype=np.float32)
                batch_whs = np.zeros((self.batch_size, self.output_size[0], self.output_size[1], 2), dtype=np.float32)
                batch_regs = np.zeros((self.batch_size, self.output_size[0], self.output_size[1], 2), dtype=np.float32)
                batch_reg_masks = np.zeros((self.batch_size, self.output_size[0], self.output_size[1]), dtype=np.float32)
                
                b = 0
                for annotation_line in lines:  
                    img,y=self.get_random_data(annotation_line,self.input_size[0:2])
    
                    if len(y)==0:
                        continue
                    boxes = np.array(y[:,:4],dtype=np.float32)
                    boxes[:,0] = boxes[:,0]/self.input_size[1]*self.output_size[1]
                    boxes[:,1] = boxes[:,1]/self.input_size[0]*self.output_size[0]
                    boxes[:,2] = boxes[:,2]/self.input_size[1]*self.output_size[1]
                    boxes[:,3] = boxes[:,3]/self.input_size[0]*self.output_size[0]
                    if ((boxes[:,3]-boxes[:,1])<=0).any() and ((boxes[:,2]-boxes[:,0])<=0).any():
                        continue
    
                    for i in range(boxes.shape[0]):
                        bbox = boxes[i].copy()
                        bbox = np.array(bbox)
                        bbox[[0, 2]] = np.clip(bbox[[0, 2]], 0, self.output_size[1] - 1)
                        bbox[[1, 3]] = np.clip(bbox[[1, 3]], 0, self.output_size[0] - 1)
                        cls_id = int(y[i,-1])
                        
                        h, w = bbox[3] - bbox[1], bbox[2] - bbox[0]
                        if h > 0 and w > 0:
                            radius = gaussian_radius((math.ceil(h), math.ceil(w)))
                            radius = max(0, int(radius))
                            ct = np.array([(bbox[0] + bbox[2]) / 2, (bbox[1] + bbox[3]) / 2], dtype=np.float32)
                            ct_int = ct.astype(np.int32)
                            batch_hms[b, :, :, cls_id] = draw_gaussian(batch_hms[b, :, :, cls_id], ct_int, radius)
                            
                            batch_whs[b, ct_int[1], ct_int[0]] = 1. * w, 1. * h
                            batch_regs[b, ct_int[1], ct_int[0]] = ct - ct_int
                            batch_reg_masks[b, ct_int[1], ct_int[0]] = 1
    
                    batch_images[b] = np.transpose(preprocess_image(img), (2, 0, 1))
                    b = b + 1
                    if b == self.batch_size:
                        b = 0
                        yield batch_images, batch_hms, batch_whs, batch_regs, batch_reg_masks
                        batch_images = np.zeros((self.batch_size, self.input_size[2], self.input_size[0], self.input_size[1]), dtype=np.float32)
    
                        batch_hms = np.zeros((self.batch_size, self.output_size[0], self.output_size[1], self.num_classes),
                                            dtype=np.float32)
                        batch_whs = np.zeros((self.batch_size, self.output_size[0], self.output_size[1], 2), dtype=np.float32)
                        batch_regs = np.zeros((self.batch_size, self.output_size[0], self.output_size[1], 2), dtype=np.float32)
                        batch_reg_masks = np.zeros((self.batch_size, self.output_size[0], self.output_size[1]), dtype=np.float32)
    

    2、利用处理完的真实框与对应图片的预测结果计算loss

    loss计算分为三个部分,分别是:
    1、热力图的loss
    2、reg中心点的loss
    3、wh宽高的loss

    具体情况如下:
    1、热力图的loss采用focal loss的思想进行运算,其中 α 和 β 是Focal Loss的超参数,而其中的N是正样本的数量,用于进行标准化。 α 和 β在这篇论文中和分别是2和4。
    整体思想和Focal Loss类似,对于容易分类的样本,适当减少其训练比重也就是loss值。
    在公式中,带帽子的Y是预测值,不戴帽子的Y是真实值。
    在这里插入图片描述
    2、reg中心点的loss和wh宽高的loss使用的是普通L1损失函数

    在这里插入图片描述

    reg中心点预测和wh宽高预测都直接采用了特征层坐标的尺寸,也就是在0到128之内。
    由于wh宽高预测的loss会比较大,其loss乘上了一个系数,论文是0.1。
    reg中心点预测的系数则为1。

    总的loss就变成了:
    在这里插入图片描述
    实现代码如下:

    def focal_loss(pred, target):
        pred = pred.permute(0,2,3,1)
    
        pos_inds = target.eq(1).float()
        neg_inds = target.lt(1).float()
    
        neg_weights = torch.pow(1 - target, 4)
        
        pred = torch.clamp(pred, 1e-12)
    
        pos_loss = torch.log(pred) * torch.pow(1 - pred, 2) * pos_inds
        neg_loss = torch.log(1 - pred) * torch.pow(pred, 2) * neg_weights * neg_inds
    
        num_pos = pos_inds.float().sum()
        pos_loss = pos_loss.sum()
        neg_loss = neg_loss.sum()
    
        if num_pos == 0:
            loss = -neg_loss
        else:
            loss = -(pos_loss + neg_loss) / num_pos
        return loss
    
    
    def reg_l1_loss(pred, target, mask):
        pred = pred.permute(0,2,3,1)
        expand_mask = torch.unsqueeze(mask,-1).repeat(1,1,1,2)
    
        loss = F.l1_loss(pred * expand_mask, target * expand_mask, reduction='sum')
        loss = loss / (mask.sum() + 1e-4)
        return loss
    
    c_loss = focal_loss(hm, batch_hms)
    wh_loss = 0.1*reg_l1_loss(wh, batch_whs, batch_reg_masks)
    off_loss = reg_l1_loss(offset, batch_regs, batch_reg_masks)
    loss = c_loss + wh_loss + off_loss
    loss.backward()
    optimizer.step()
    

    训练自己的Centernet模型

    Centernet整体的文件夹构架如下:
    在这里插入图片描述
    本文使用VOC格式进行训练。
    训练前将标签文件放在VOCdevkit文件夹下的VOC2007文件夹下的Annotation中。
    在这里插入图片描述
    训练前将图片文件放在VOCdevkit文件夹下的VOC2007文件夹下的JPEGImages中。
    在这里插入图片描述
    在训练前利用voc2centernet.py文件生成对应的txt。
    在这里插入图片描述
    再运行根目录下的voc_annotation.py,运行前需要将classes改成你自己的classes。

    classes = ["aeroplane", "bicycle", "bird", "boat", "bottle", "bus", "car", "cat", "chair", "cow", "diningtable", "dog", "horse", "motorbike", "person", "pottedplant", "sheep", "sofa", "train", "tvmonitor"]
    

    在这里插入图片描述
    就会生成对应的2007_train.txt,每一行对应其图片位置及其真实框的位置。
    在这里插入图片描述
    在训练前需要修改model_data里面的voc_classes.txt文件,需要将classes改成你自己的classes。
    在这里插入图片描述
    然后运行train.py就可以开始训练啦。
    在这里插入图片描述
    运行train.py即可开始训练。
    在这里插入图片描述

    展开全文
  • 目标检测:YOLOv3: 训练自己的数据

    万次阅读 多人点赞 2018-03-26 10:59:02
    update:20200424 YOLOV4...不改源码,不用重新编译 修改coco.names中内容,为自己的检测目标类别 B.改源码,需要重新编译[ 先 make clean ,然后再 make] 原因是作者在代码中设置了默认,所以修改 examples/darknet.c...

     

    update:20200424

    YOLOV4出来啦!!!快去把玩一下!!!

    https://github.com/AlexeyAB/darknet

     

    ------------------------------ 本文仅供学习交流,如有错误,望交流指教 ------------------------------

    windows       版本:请参考:https://github.com/AlexeyAB/darknet

    linux               版本:请参考本文与 https://pjreddie.com/darknet/yolo

    caffe-yolov3 版本:请参考:https://blog.csdn.net/Chen_yingpeng/article/details/80692018【测试可用】

    第一部分:论文与代码

    第二部分:如何训练自己的数据

    第三部分:疑惑解释

    第四部分:测试相关

    第一部分:论文与代码

    论  文:https://pjreddie.com/media/files/papers/YOLOv3.pdf

    翻  译:https://zhuanlan.zhihu.com/p/34945787

    代  码:https://github.com/pjreddie/darknet

    官  网:https://pjreddie.com/darknet/yolo

    旧  版:

     https://pjreddie.com/darknet/yolov2/

     https://pjreddie.com/darknet/yolov1/

     

    第二部分:如何训练自己的数据

     

    说明:

    (1)平台 linux + 作者官方代码 【训练指令请参考官网教程:https://pjreddie.com/darknet/yolo】
    迭代:900 次
    速度:稍微慢于v2
    测试:记得更改cfg文件

    目的:给网友提供参考,所以样本和迭代次数较少,仅供学习!

    (2)为了方便大家学习,这里提供了182张训练数据、标注以及对应的配置文件,数据是4类【人,车头,车尾,车侧身】: 

    训练数据、配置文件、模型、训练日志、标注工具放在QQ群:371315462935621769

    具体下载地址在群文件的YOLOv3.txt!

    群基本满了,进群也是潜水,所以直接下载吧:

        百度云:
        链接:https://pan.baidu.com/s/1wEtpdQBuMtXn_9CGhEvHTQ
        密码:bwpx

        CSDN

          https://download.csdn.net/download/lilai619/11130832

    【群文件补充了training_list.txt以及labels文件】,欢迎目标检测与语义分割的小伙伴进群交流。

    训练自己的数据主要分以下几步:

    (0)数据集制作:

    A.制作VOC格式的xml文件

    工具:LabelImg 【群文件提供了exe免安装版本以及使用说明】

    B.将VOC格式的xml文件转换成YOLO格式的txt文件

    脚本:voc_label.py,根据自己的数据集修改就行了。

    (1)文件修改

    (A)关于 .data .names 两个文件修改非常简单,参考官网或者群文件YOLOv3.txt连接中的文件。

    (B)关于cfg修改,以6目标检测为例,主要有以下几处调整(蓝色标出),也可参考我上传的文件,里面对应的是4类。#表示注释,根据训练和测试,自行修改。

    [net]
    # Testing
    # batch=1
    # subdivisions=1
    # Training
     batch=64

     subdivisions=8

    ......

    [convolutional]
    size=1
    stride=1
    pad=1
    filters=33###75

     

    activation=linear

    [yolo]
    mask = 6,7,8
    anchors = 10,13,  16,30,  33,23,  30,61,  62,45,  59,119,  116,90,  156,198,  373,326
    classes=6###20
    num=9
    jitter=.3
    ignore_thresh = .5
    truth_thresh = 1
    random=0###1

     

    ......

    [convolutional]
    size=1
    stride=1
    pad=1
    filters=33###75
    activation=linear

    [yolo]
    mask = 3,4,5
    anchors = 10,13,  16,30,  33,23,  30,61,  62,45,  59,119,  116,90,  156,198,  373,326
    classes=6###20
    num=9
    jitter=.3
    ignore_thresh = .5
    truth_thresh = 1
    random=0###1

    ......

    [convolutional]
    size=1
    stride=1
    pad=1
    filters=33###75
    activation=linear

    [yolo]
    mask = 0,1,2
    anchors = 10,13,  16,30,  33,23,  30,61,  62,45,  59,119,  116,90,  156,198,  373,326
    classes=6###20
    num=9
    jitter=.3
    ignore_thresh = .5
    truth_thresh = 1
    random=0###1

    A.filters数目是怎么计算的:3x(classes数目+5),和聚类数目分布有关论文中有说明;

    B.如果想修改默认anchors数值,使用k-means即可;

    C.如果显存很小,将random设置为0,即关闭多尺度训练;

    D.其他参数如何调整,有空再补;

    E.前100次迭代loss较大,后面会很快收敛;

    Region xx: cfg文件中yolo-layer的索引;

    Avg IOU:   当前迭代中,预测的box与标注的box的平均交并比,越大越好,期望数值为1;

    Class:        标注物体的分类准确率,越大越好,期望数值为1;

    obj:            越大越好,期望数值为1;

    No obj:      越小越好;

    .5R:            以IOU=0.5为阈值时候的recall; recall = 检出的正样本/实际的正样本

    0.75R:         以IOU=0.75为阈值时候的recall;

    count:        正样本数目。

    F.模型测试:

    6类测试效果模型与配置文件稍后放到群文件,但数据暂不提供】

              

    4类的测试效果,182张迭代900次时的检测效果。【群文件的YOLOv3.txt有百度云盘的下载地址】

    配置文件中的相关参数:完整版本见群文件。

     

    训练指令;多GPU训练指令;恢复训练指令

     

    第三部分:训练问题详解

    图片来自群文件,侵权联系删除

    Tips0: 数据集问题

    如果是学习如何训练,建议不要用VOC或者COCO,这两个数据集复杂,类别较多,复现作者的效果需要一定的功力,迭代差不多5w次,就可以看到初步的效果。所以,不如挑个简单数据集的或者手动标注个几百张就可以进行训练学习。

    Tips1: CUDA: out of memory 以及 resizing 问题

    显存不够,调小batch,关闭多尺度训练:random = 0。

    Tips2: 在迭代前期,loss很大,正常吗?

    经过几个数据集的测试,前期loss偏大是正常的,后面就很快收敛了。

    Tips3: YOLOV3中的mask作用?

    参考#558 #567

    Every layer has to know about all of the anchor boxes but is only predicting some subset of them. This could probably be named something better but the mask tells the layer which of the bounding boxes it is responsible for predicting. The first yolo layer predicts 6,7,8 because those are the largest boxes and it's at the coarsest scale. The 2nd yolo layer predicts some smallers ones, etc.

    The layer assumes if it isn't passed a mask that it is responsible for all the bounding boxes, hence the ifstatement thing.

    Tips3: YOLOV3中的num作用?

    #参考567

    num is 9 but each yolo layer is only actually looking at 3 (that's what the mask thing does). so it's (20+1+4)*3 = 75. If you use a different number of anchors you have to figure out which layer you want to predict which anchors and the number of filters will depend on that distribution.

    according to paper, each yolo (detection) layer get 3 anchors with associated with its size, mask is selected anchor indices.

    Tips4: YOLOV3训练出现nan的问题?

    参考#566

    You must be training on a lot of small objects! nan's appear when there are no objects in a batch of images since i definitely divide by zero. For example, Avg IOU is the sum of IOUs for all objects at that level / # of objects, if that is zero you get nan. I could probably change this so it just does a check for zero 1st, just wasn't a priority.

    所以在显存允许的情况下,可适当增加batch大小,可以一定程度上减少NAN的出现。

    Tips5: Anchor box作用是?

    参考#568

    Here's a quick explanation based on what I understand (which might be wrong but hopefully gets the gist of it). After doing some clustering studies on ground truth labels, it turns out that most bounding boxes have certain height-width ratios. So instead of directly predicting a bounding box, YOLOv2 (and v3) predict off-sets from a predetermined set of boxes with particular height-width ratios - those predetermined set of boxes are the anchor boxes.

     

    Anchors are initial sizes (width, height) some of which (the closest to the object size) will be resized to the object size - using some outputs from the neural network (final feature map):

    darknet/src/yolo_layer.c

    Lines 88 to 89 in 6f6e475

     b.w = exp(x[index + 2*stride]) * biases[2*n] / w;
     b.h = exp(x[index + 3*stride]) * biases[2*n+1] / h;

     

    • x[...] - outputs of the neural network

    • biases[...] - anchors

    • b.w and b.h result width and height of bounded box that will be showed on the result image

    Thus, the network should not predict the final size of the object, but should only adjust the size of the nearest anchor to the size of the object.

    In Yolo v3 anchors (width, height) - are sizes of objects on the image that resized to the network size (width= and height= in the cfg-file).

    In Yolo v2 anchors (width, height) - are sizes of objects relative to the final feature map (32 times smaller than in Yolo v3 for default cfg-files).

     

    Tips6: YOLOv2和YOLOv3中anchor box为什么相差很多?

    参考#562 #555

     

    Now anchors depends on size of the network-input rather than size of the network-output (final-feature-map): #555 (comment)
    So values of the anchors 32 times more.

    Now filters=(classes+1+coords)*anchors_num where anchors_num is a number of masks for this layer.
    If mask is absence then anchors_num = num for this layer:

    darknet/src/yolo_layer.c

    Lines 31 to 37 in e4acba6

     if(mask) l.mask = mask;
     else{
     l.mask = calloc(n, sizeof(int));
     for(i = 0; i < n; ++i){
     l.mask[i] = i;
     }
     }

     

    Each [yolo] layer uses only those anchors whose indices are specified in the mask=

     

     

    So YOLOv2 I made some design choice errors, I made the anchor box size be relative to the feature size in the last layer. Since the network was downsampling by 32 this means it was relative to 32 pixels so an anchor of 9x9 was actually 288px x 288px.

    In YOLOv3 anchor sizes are actual pixel values. this simplifies a lot of stuff and was only a little bit harder to implement

     

    Tips7: YOLOv3打印的参数都是什么含义?

     

    详见yolo_layer.c文件的forward_yolo_layer函数。

        printf("Region %d Avg IOU: %f, Class: %f, Obj: %f, No Obj: %f, .5R: %f, .75R: %f,  count: %d\n", net.index, avg_iou/count, avg_cat/class_count, avg_obj/count, avg_anyobj/(l.w*l.h*l.n*l.batch), recall/count, recall75/count, count);

    刚开始迭代,由于没有预测出相应的目标,所以查全率较低【.5R 0.75R】,会出现大面积为0的情况,这个是正常的。

     

    第四部分:测试问题

    由于比较忙,评论不会及时回复。请大家参考下方问题、评论区或者加群讨论。

    (1)** Error in `./darknet': free(): invalid next size (fast): 0x000055d39b90cbb0 ***已放弃 (核心已转储) 

    请使用以下测试指令!

    ./darknet detect cfg/yolov3.cfg yolov3.weights data/dog.jpg

    训练与测试指令,请参考官网连接:https://pjreddie.com/darknet/yolo/

    (2)如何进行模型的评估(valid)?

    评估指令,请参考官网连接:https://pjreddie.com/darknet/yolo/

    (3)bounding box正确,标签错乱,这里提供两种方案供选择。

    A.不改源码,不用重新编译

       修改coco.names中内容,为自己的检测目标类别

    B.改源码,需要重新编译[ 先 make clean ,然后再 make]

    原因是作者在代码中设置了默认,所以修改 examples/darknet.c文件,将箭头指示的文件替换成自己的。然后重新编译即可。

    (4)模型保存问题

    A:保存模型出错?

    一般是 .data 文件中指定的文件夹无法创建,导致模型保存时出错。自己手动创建即可。

    B:模型什么时候保存?如何更改

    迭代次数小于1000时,每100次保存一次,大于1000时,没10000次保存一次。

    自己可以根据需求进行更改,然后重新编译即可[ 先 make clean ,然后再 make]

    代码位置: examples/detector.c line 138

    C:使用预训练模型直接保存问题

    darknet53.conv.74作为预训练权重文件,因为只包含卷积层,所以可以从头开始训练。

    xxx.weights作为预权重文件训练,因为包含所有层,相当于恢复快照训练,会从已经保存的迭代次数往下训练。如果cfg中迭代次数没改,所以不会继续训练,直接保存结束。

    (5)中文标签问题

    这个解决方案较多,我就简单的说一下我的方案【群文件labels提供了参考代码】

    A:首先生成对应的中文标签,

    修改代码中的字体,将其替换成指中文字体,如果提示提示缺少**模块,安装就行了。

     

    B:添加自己的读取标签和画框函数

    (6)图片上添加置信值

    代码比较熟悉的童鞋,使用opencv在画框的函数里面添加一下就行了。

    (7)图片保存名称

    测试的时候,保存的默认名称是predictions.自己改成对应的图片名称即可。

    (8)Floating, point, exception (core, dumped)

    https://github.com/pjreddie/darknet/issues/140#issuecomment-375791093

    (9)多GPU训练时模型保存问题

    https://github.com/pjreddie/darknet/issues/664#issuecomment-405448653

    假设你有3块GPU,当单张GPU运行100次时【该保存模型了】,实际上迭代了100*3=300次【3块卡嘛】,当单张GPU运行200次时【该保存模型了】,实际上迭代了200*3=600次【3块卡嘛】,依次类推。

    第五部分:论文阅读

    优点:速度快,精度提升,小目标检测有改善;

    不足:中大目标有一定程度的削弱,遮挡漏检,速度稍慢于V2。

     

     

    v2: anchors[k-means]+多尺度+跨尺度特征融合
    v3: anchors[k-means]+多尺度+跨尺度特征融合


    v2,v3两者都是有上面的共同特点,简单的多尺度不是提升小目标的检测的关键。


    v2: 32x的下采样,然后使用anchor进行回归预测box
    问题:较大的下采样因子,通常可以带来较大的感受野,这对于分类任务是有利,但会损害目标检测和定位【小目标在下采样过程中消失,大目标边界定位不准】


    v3: 针对这个问题,进行了调整。就是在网络的3个不同的尺度进行了box的预测。【说白了就是FPN的思想】在下采样的前期就进行目标的预测,这样就可以改善小目标检测和定位问题。
    不理解的话,稍微看一下FPN,就明白了。这个才是v3提升小目标的关键所在。

     

                                                                (๑•ᴗ•๑)觉得有用,赏个植发的小钱钱。(๑•ᴗ•๑)

       

     

     

     

    展开全文
  • 除本课程《YOLOv4目标检测实战:训练自己的数据集》外,本人将推出有关YOLOv4目标检测的系列课程。请持续关注该系列的其它视频课程,包括: 《YOLOv4目标检测实战:人脸口罩佩戴识别》 《YOLOv4目标检测实战:中国...
  • 2020年写给自己人生目标规划

    千次阅读 2020-01-05 23:32:16
    2020年写给自己的人生目标1. 目标规则2. 初级目标3. 中级目标4. 终极目标实现: 1. 目标规则 符合SMART原则: 1.具体的 2.可衡量的 3.可达成的 4.相关性 5.时限性 2. 初级目标 在成都培训的期间,找到适合自己的...


    1. 目标规则

    符合SMART原则:
    1.具体的
    2.可衡量的
    3.可达成的
    4.相关性
    5.时限性

    2. 初级目标

    在成都培训的期间,找到适合自己的学习方法,毕业时的第一份工作争取可以达到5k-7k的工作,达到经济独立,踏进IT行业的第一步。

    3. 中级目标

    25岁(周岁)大概2023年的生日前,可以完全融入IT行业圈,在博客上有一些知名度,争取向管理层迈进IT行业的第二步,工资方面达到1W以上,另外也要提升自己的英语水平,基本上可以达到生活上可以与人交流的水平。

    4. 终极目标

    30岁前可以拥有带团队的能力,工作稳定,并且有自己的经济能力可以组件自己的家庭。(终极目标随成长的速度而变化)

    实现:

    1. 每天写 1 页或以上的学习总结记录,保证每天有所成长。
    2. 每天学习时间最低达到10点30以后才可以回去休息,如学习超过12点可以奖励自己吃夜宵。
    3. 每天睡眠不可超过8个小时,保证7小时即可,如果超过8小时,处罚自己学习至11点30才可回去休息。
    4. 每天坚持自己写博客,最低一周2篇博客,提升自己的写作能力
    5. 睡觉前腾出10-30分钟时间来学习英语知识,在空闲时可以听关于英语方面的音频。
    6. 一周最低锻炼身体一次,时间最低为30分钟左右。
    7. 所有事情处理完,学有余力或工作后能提前完成时,保证随身带着一本扩展书籍,方便自己的阅读。
    展开全文
  • 【YOLO】如何提高目标检测效果

    千次阅读 热门讨论 2019-04-30 14:57:08
    参考GitHub上的文章,总结了提高YOLO目标检测效果的方法。

    参考:https://github.com/AlexeyAB/darknet#how-to-train-to-detect-your-custom-objects

    1. 训练前

    (1)在.cfg文件中设置flag random=1,它将通过不同分辨率来训练yolo以提高精度。

    (2)提高.cfg文件中网络的分辨率,(例如height = 608width = 608或者任意32的倍数),这样可以提高精度。

    (3)确保数据集中每个类都带有标签,并且保证标签正确。(可以用这个工具来检查数据集: https://github.com/AlexeyAB/Yolo_mark

    (4)对于要检测的每个对象,训练数据集中必须至少有一个类似的对象,其形状、侧面、相对大小、旋转角度、倾斜、照明等条件大致相同。

    (5)数据集中应包括对象的不同缩放、旋转、照明、不同的面、不同背景的图像,最好为每个类提供2000个以上不同的图像,并且训练(2000* 类的数量)的迭代次数或更多。

    (6)确保训练的数据集中包含不想被检测的不带标签的对象,即负样本,负样本的数量最好和正样本的数量相同。

    (7)对于目标物体较多的图像,在.cfg文件中最后一个[yolo]层和[region]层加入max=200参数或者更高的值。(yolov3可以检测到的对象的全局最大数目是0.0615234375 *(width*height),其中width和height是.cfg文件中[net]部分的参数)

    (8)训练小物体时(图像调整到416x416后物体小于16x16),将.cfg文件中720行左右的[route]参数替换为layers = -1, 11,并且将717行左右的[upsample]参数改为stride =4

    (9)对于都包含小对象和大对象可以使用以下的修改模型:
    Full-model: 5 yolo layers: https://raw.githubusercontent.com/AlexeyAB/darknet/master/cfg/yolov3_5l.cfg
    Tiny-model: 3 yolo layers: https://raw.githubusercontent.com/AlexeyAB/darknet/master/cfg/yolov3-tiny_3l.cfg
    Spatial-full-model: 3 yolo layers: https://raw.githubusercontent.com/AlexeyAB/darknet/master/cfg/yolov3-spp.cfg

    (10)如果要训练区分左右的对象(例如左手右手,道路上左转右转标志等),需要禁用数据翻转增强,在.cfg文件中17行左右的位置加入flip=0

    (11)一般规律——训练数据集应该包含一组您想要检测的对象的相对大小相近的样本。简单来说,就是需要检测的对象在图像中的百分比是多少,那么训练的图像中也应该包含这个百分比的对象。例如:如果训练的时候目标在图像中都占80-90%,那检测的时候很可能就检测不出目标占0-10%情况。

    train_network_width * train_obj_width / train_image_width ~= detection_network_width * detection_obj_width / detection_image_width
    train_network_height * train_obj_height / train_image_height ~= detection_network_height * detection_obj_height / detection_image_height
    object width in percent from Training dataset ~= object width in percent from Test dataset

    (12)同一个对象在不同的光照条件、侧面、尺寸、倾斜或旋转30度的情况下,对于神经网络的内部来说,都是不同的对象。因此,如果想检测更多的不同对象,就应该选择更复杂的神经网络。

    (13)在.cfg中重新计算锚(anchors)的width和height:在.cfg文件中的3个[yolo]层中的每个层中设置相同的9个锚,但是应该为每个[yolo]层更改锚点masks=的索引,以便[yolo]第一层的锚点大于60x60,第二层大于30x30,第三层剩余。此外,还应在每个[yolo]层之前更改过滤器filters=(classes + 5) * <number of mask>。如果许多计算出的锚找不到适当的层,那么只需尝试使用所有的默认锚。

    2. 训练后(对于检测)

    通过在.cfg文件中设置(height=608width=608)或(height=832width=832)或(32的任意值倍数)来提高网络的分辨率,这将提高精度并使检测小对象成为可能。
    这里提高了网络的分辨率,但是可以不需要重新训练(即使之前使用416*416分辨率训练的)。但是为了提高精度,还是建议使用更高的分辨率来重新训练。
    注意:如果出现了Out of memory的错误,建议提高.cfg文件中的subdivisions=16参数,改成32或者64等。

    拓展

    1)如何使用官方模型进行检测:https://blog.csdn.net/qinchang1/article/details/89435023
    2)如何训练自己的YOLO模型:https://blog.csdn.net/qinchang1/article/details/89608058

    如有错误,欢迎指正!

    展开全文
  • 本文总结一些自己见过的小目标检测提升的思路,欢迎各位大佬讨论。 数据增强 数据增强方面,论文推荐Augmentation for small object detection。 小目标检测中的数据扩展(Augmentation for small object detection...
  • 请持续关注该系列的其它视频课程,包括: 《YOLOv4目标检测实战:训练自己的数据集》 《YOLOv4目标检测实战:人脸口罩佩戴识别》 《YOLOv4目标检测实战:中国交通标志识别》 《YOLOv4目标检测:原理与源码解析》
  • 需要学习Ubuntus系统YOLOv4-tiny的同学请前往《YOLOv4-tiny目标检测实战:训练自己的数据集》 YOLOv4-tiny来了!速度大幅提升! YOLOv4-tiny在COCO上的性能可达到:40.2% AP50, 371 FPS (GTX 1080 Ti)。相较于...
  • Tensorflow目标检测之yolov3训练自己的模型

    千次阅读 多人点赞 2019-11-26 16:19:18
    Tensorflow官方目标检测给出了SSD、Faster rcnn等预训练模型,但没有给yolov3的预训练模型,但有热心的人已经实现了基于tensorflow来复现yolov3的算法,本文对该代码的训练测试流程做一介绍。 代码起源于YunYang...
  • 目标优化

    万次阅读 多人点赞 2018-09-14 11:40:57
    最优化问题的分类 1)无约束和有约束条件;...使多个目标在给定区域同时尽可能最佳,多目标优化的解通常是一组均衡解(即一组由众多 Pareto最优解组成的最优解集合 ,集合中的各个元素称为 Pareto最优解或非劣最...
  • 睿智的目标检测27——Pytorch搭建Faster R-CNN目标检测平台学习前言什么是FasterRCNN目标检测算法源码下载Faster-RCNN实现思路一、预测部分1、主干网络介绍2、获得Proposal建议框3、Proposal建议框的解码4、对...
  • 目标跟踪

    千次阅读 2019-11-27 19:54:52
    本篇是基于单目标跟踪的论述 目标跟踪概述 1.1 定义: 1,单目标,即在给定的视频中只跟踪一个目标 2,在第一帧中会通过矩形的bounding box将目标给出。给定后,使用tracker找出每一帧的目标。 3,短期 ...
  • 本科毕设做的是嵌入式系统的实时目标检测,具体点就是在树莓派4B上训练自己的轻量化目标检测网络。 花了一个月跑了个baseline,从数据集标注到训练和优化再到可视化,由于在嵌入式上搞实时目标检测中英文资料都很少...
  • 目标检测

    万次阅读 2019-02-26 19:22:31
    文章目录第八章 目标检测8.1 基本概念8.1.1 什么是目标检测?8.1.2 目标检测要解决的核心问题?8.1.2 目标检测算法分类?8.2 Two Stage目标检测算法8.2.1 R-CNN8.2.2 Fast R-CNN8.2.3 Faster R-CNN8.2.4 R-FCN8.2.5 ...
  • TensorFlow内包含了一个强大的物体检测API,我们可以利用这API来训练自己的数据集实现特殊的目标检测。 Dat Tran就分享了自己实现可爱的浣熊检测器的经历,在文章中作者把检测器的训练流程进行了梳理,我们可以...
  • Retinanet 较之 SSD, YOLO系one stage目标检测网络,在保证检测速度的基础上,很大的提高了在样本类别分布不平衡情况下的检测精度,这得益于He Kaiming等人所提出的Focal Loss Paper可见 Focal Loss for Dense ...
  • 在验证阶段直接调小score_threshold,可以将mAP快速提升,但是实际上你的模型预测的结果,置信度还是很低。 2.调小batch_size 将原本的batch_size调小,同时增大learning_rate,batch_size可以尝试慢慢调小,因为...
  • 目标管理

    万次阅读 热门讨论 2019-09-24 17:36:35
    书中介绍了很多管理工具,大部分内容同事已经分享过了,其中有一章没讲的是目标管理,正好最近又参加了《目标管理》的培训,就结合起来说说目标管理吧。 "企业管理说到底就是目标管理。" -- 彼得 · 德鲁克 《管理...
  • 如何制定人生目标和实现目标

    千次阅读 2017-01-11 22:54:56
    如何制定人生目标和实现目标 第一步:分析你的需求。你也许会问:这一步怎么做呢?不妨试试以下方法。开动脑筋,写下来10条未来5年你认为自己应做的事情,要确切,但不要有限制和顾虑那些是自己做不到的,给自己...
  • 笔记来源:DeepLearning-500-questions 上次学习了目标检测的基本概念和一些...我们将分析FPN以理解多尺度特征图如何提高准确率,特别是小目标的检测,其在单次检测器中的检测效果通常很差。然后我们将分析Focal ...
  • v4目标检测算法详解及预训练模型使用与自己训练模型一、YOLO简介二、YOLO v3三、YOLO v4四、预训练模型使用(基于Darknet的GPU版本)五、自己训练模型(使用GPU) 一、YOLO简介 YOLO是目前比较流行的目标检测算法,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 683,141
精华内容 273,256
关键字:

如何提高自己的目标