首页 > 其他分享 >昇思学习打卡-11-SSD目标检测

昇思学习打卡-11-SSD目标检测

时间:2024-07-11 14:30:45浏览次数:19  
标签:11 box image mask label boxes np SSD 打卡

文章目录

模型介绍

SSD是单阶段的目标检测算法,通过卷积神经网络进行特征提取,取不同的特征层进行检测输出,所以SSD是一种多尺度的检测方法。在需要检测的特征层,直接使用一个3 ×3卷积,进行通道的变换。SSD采用了anchor的策略,预设不同长宽比例的anchor,每一个输出特征层基于anchor预测多个检测框(4或者6)。采用了多尺度检测方法,浅层用于检测小目标,深层用于检测大目标

模型的特点

  • 多尺度检测

    在SSD的网络结构图中我们可以看到,SSD使用了多个特征层,一共6种不同的特征图尺寸。大尺度特征图(较靠前的特征图)可以用来检测小物体,而小尺度特征图(较靠后的特征图)用来检测大物体。多尺度检测的方式,可以使得检测更加充分(SSD属于密集检测),更能检测出小目标。

  • 采用卷积进行检测

    与YOLO最后采用全连接层不同,SSD直接采用卷积对不同的特征图来进行提取检测结果。对于形状为m×n×p的特征图,只需要采用3×3×p这样比较小的卷积核得到检测值。

  • 预设anchor

    在YOLOv1中,直接由网络预测目标的尺寸,这种方式使得预测框的长宽比和尺寸没有限制,难以训练。在SSD中,采用预设边界框,我们习惯称它为anchor(在SSD论文中叫default bounding boxes),预测框的尺寸在anchor的指导下进行微调。

数据采样

部分实现

import cv2
import numpy as np

def _rand(a=0., b=1.):
    return np.random.rand() * (b - a) + a

def intersect(box_a, box_b):
    """Compute the intersect of two sets of boxes."""
    max_yx = np.minimum(box_a[:, 2:4], box_b[2:4])
    min_yx = np.maximum(box_a[:, :2], box_b[:2])
    inter = np.clip((max_yx - min_yx), a_min=0, a_max=np.inf)
    return inter[:, 0] * inter[:, 1]

def jaccard_numpy(box_a, box_b):
    """Compute the jaccard overlap of two sets of boxes."""
    inter = intersect(box_a, box_b)
    area_a = ((box_a[:, 2] - box_a[:, 0]) *
              (box_a[:, 3] - box_a[:, 1]))
    area_b = ((box_b[2] - box_b[0]) *
              (box_b[3] - box_b[1]))
    union = area_a + area_b - inter
    return inter / union

def random_sample_crop(image, boxes):
    """Crop images and boxes randomly."""
    height, width, _ = image.shape
    min_iou = np.random.choice([None, 0.1, 0.3, 0.5, 0.7, 0.9])

    if min_iou is None:
        return image, boxes

    for _ in range(50):
        image_t = image
        w = _rand(0.3, 1.0) * width
        h = _rand(0.3, 1.0) * height
        # aspect ratio constraint b/t .5 & 2
        if h / w < 0.5 or h / w > 2:
            continue

        left = _rand() * (width - w)
        top = _rand() * (height - h)
        rect = np.array([int(top), int(left), int(top + h), int(left + w)])
        overlap = jaccard_numpy(boxes, rect)

        # dropout some boxes
        drop_mask = overlap > 0
        if not drop_mask.any():
            continue

        if overlap[drop_mask].min() < min_iou and overlap[drop_mask].max() > (min_iou + 0.2):
            continue

        image_t = image_t[rect[0]:rect[2], rect[1]:rect[3], :]
        centers = (boxes[:, :2] + boxes[:, 2:4]) / 2.0
        m1 = (rect[0] < centers[:, 0]) * (rect[1] < centers[:, 1])
        m2 = (rect[2] > centers[:, 0]) * (rect[3] > centers[:, 1])

        # mask in that both m1 and m2 are true
        mask = m1 * m2 * drop_mask

        # have any valid boxes? try again if not
        if not mask.any():
            continue

        # take only matching gt boxes
        boxes_t = boxes[mask, :].copy()
        boxes_t[:, :2] = np.maximum(boxes_t[:, :2], rect[:2])
        boxes_t[:, :2] -= rect[:2]
        boxes_t[:, 2:4] = np.minimum(boxes_t[:, 2:4], rect[2:4])
        boxes_t[:, 2:4] -= rect[:2]

        return image_t, boxes_t
    return image, boxes

def ssd_bboxes_encode(boxes):
    """Labels anchors with ground truth inputs."""

    def jaccard_with_anchors(bbox):
        """Compute jaccard score a box and the anchors."""
        # Intersection bbox and volume.
        ymin = np.maximum(y1, bbox[0])
        xmin = np.maximum(x1, bbox[1])
        ymax = np.minimum(y2, bbox[2])
        xmax = np.minimum(x2, bbox[3])
        w = np.maximum(xmax - xmin, 0.)
        h = np.maximum(ymax - ymin, 0.)

        # Volumes.
        inter_vol = h * w
        union_vol = vol_anchors + (bbox[2] - bbox[0]) * (bbox[3] - bbox[1]) - inter_vol
        jaccard = inter_vol / union_vol
        return np.squeeze(jaccard)

    pre_scores = np.zeros((8732), dtype=np.float32)
    t_boxes = np.zeros((8732, 4), dtype=np.float32)
    t_label = np.zeros((8732), dtype=np.int64)
    for bbox in boxes:
        label = int(bbox[4])
        scores = jaccard_with_anchors(bbox)
        idx = np.argmax(scores)
        scores[idx] = 2.0
        mask = (scores > matching_threshold)
        mask = mask & (scores > pre_scores)
        pre_scores = np.maximum(pre_scores, scores * mask)
        t_label = mask * label + (1 - mask) * t_label
        for i in range(4):
            t_boxes[:, i] = mask * bbox[i] + (1 - mask) * t_boxes[:, i]

    index = np.nonzero(t_label)

    # Transform to tlbr.
    bboxes = np.zeros((8732, 4), dtype=np.float32)
    bboxes[:, [0, 1]] = (t_boxes[:, [0, 1]] + t_boxes[:, [2, 3]]) / 2
    bboxes[:, [2, 3]] = t_boxes[:, [2, 3]] - t_boxes[:, [0, 1]]

    # Encode features.
    bboxes_t = bboxes[index]
    default_boxes_t = default_boxes[index]
    bboxes_t[:, :2] = (bboxes_t[:, :2] - default_boxes_t[:, :2]) / (default_boxes_t[:, 2:] * 0.1)
    tmp = np.maximum(bboxes_t[:, 2:4] / default_boxes_t[:, 2:4], 0.000001)
    bboxes_t[:, 2:4] = np.log(tmp) / 0.2
    bboxes[index] = bboxes_t

    num_match = np.array([len(np.nonzero(t_label)[0])], dtype=np.int32)
    return bboxes, t_label.astype(np.int32), num_match

def preprocess_fn(img_id, image, box, is_training):
    """Preprocess function for dataset."""
    cv2.setNumThreads(2)

    def _infer_data(image, input_shape):
        img_h, img_w, _ = image.shape
        input_h, input_w = input_shape

        image = cv2.resize(image, (input_w, input_h))

        # When the channels of image is 1
        if len(image.shape) == 2:
            image = np.expand_dims(image, axis=-1)
            image = np.concatenate([image, image, image], axis=-1)

        return img_id, image, np.array((img_h, img_w), np.float32)

    def _data_aug(image, box, is_training, image_size=(300, 300)):
        ih, iw, _ = image.shape
        h, w = image_size
        if not is_training:
            return _infer_data(image, image_size)
        # Random crop
        box = box.astype(np.float32)
        image, box = random_sample_crop(image, box)
        ih, iw, _ = image.shape
        # Resize image
        image = cv2.resize(image, (w, h))
        # Flip image or not
        flip = _rand() < .5
        if flip:
            image = cv2.flip(image, 1, dst=None)
        # When the channels of image is 1
        if len(image.shape) == 2:
            image = np.expand_dims(image, axis=-1)
            image = np.concatenate([image, image, image], axis=-1)
        box[:, [0, 2]] = box[:, [0, 2]] / ih
        box[:, [1, 3]] = box[:, [1, 3]] / iw
        if flip:
            box[:, [1, 3]] = 1 - box[:, [3, 1]]
        box, label, num_match = ssd_bboxes_encode(box)
        return image, box, label, num_match

    return _data_aug(image, box, is_training, image_size=[300, 300])

网络结构

SSD网络由VGG16 Base Layer、Extra Feature Layer、Detection Layer、NMS、Anchor几部分构成
在这里插入图片描述
anchor会对应c个类别和4个回归偏移量是如何来的?下面重点理解一下Anchor

  • 概念:Anchor,也称为锚框,是一组预设的边界框,用于在训练时构建真实的边框位置相对于预设边框的偏移。这些预设的边界框具有不同的尺寸和长宽比,旨在覆盖图像中可能出现的各种目标大小和形状。
  • 作用:Anchor的主要作用是作为目标检测的起点,通过在这些预设的边界框上进行精细化的调整,使得模型能够更准确地预测出目标的实际位置和类别

损失函数

公式

使用2个损失函数,位置损失函数和置信度损失函数
在这里插入图片描述
其中:

  • N 是先验框的正样本数量;
  • c 为类别置信度预测值;
  • l 为先验框的所对应边界框的位置预测值;
  • g 为ground truth的位置参数
  • α 用以调整confidence loss和location loss之间的比例,默认为1。

位置损失函数使用smooth l1损失,位置信息为解码后的位置信息
在这里插入图片描述
置信度损失函数是多类置信度上的softmax损失
在这里插入图片描述

实现

def class_loss(logits, label):
    """Calculate category losses."""
    label = ops.one_hot(label, ops.shape(logits)[-1], Tensor(1.0, ms.float32), Tensor(0.0, ms.float32))
    weight = ops.ones_like(logits)
    pos_weight = ops.ones_like(logits)
    sigmiod_cross_entropy = ops.binary_cross_entropy_with_logits(logits, label, weight.astype(ms.float32), pos_weight.astype(ms.float32))
    sigmoid = ops.sigmoid(logits)
    label = label.astype(ms.float32)
    p_t = label * sigmoid + (1 - label) * (1 - sigmoid)
    modulating_factor = ops.pow(1 - p_t, 2.0)
    alpha_weight_factor = label * 0.75 + (1 - label) * (1 - 0.75)
    focal_loss = modulating_factor * alpha_weight_factor * sigmiod_cross_entropy
    return focal_loss

NMS

训练过程是不需要用到非极大值抑制(NMS),
推理时,例如输入一张图片要求输出框的时候,需要用到NMS过滤掉那些重叠度较大的预测框。
非极大值抑制的流程如下:

  • 根据置信度得分进行排序

  • 选择置信度最高的比边界框添加到最终输出列表中,将其从边界框列表中删除

  • 计算所有边界框的面积

  • 计算置信度最高的边界框与其它候选框的IoU

  • 删除IoU大于阈值的边界框

  • 重复上述过程,直至边界框列表为空

训练过程

在这里插入图片描述

先验框匹配
在训练过程中,首先要确定训练图片中的ground truth(真实目标)与哪个先验框来进行匹配,与之匹配的先验框所对应的边界框将负责预测它。
在这里插入图片描述

此章节学习到此结束,感谢昇思平台。

标签:11,box,image,mask,label,boxes,np,SSD,打卡
From: https://blog.csdn.net/weixin_42630613/article/details/107795559

相关文章

  • c语言(7.11)
    今天学习了if语句#include<stdio.h>intmain(){   /*inta=10;   if(a>5)   {      printf("真的大于5");   }*/      /*doubletemperature=38.5;   if(temperature>38)   {      printf("体温过高,语音报......
  • 【日记】什么时候混到连信封都要从单位顺这种地步了……(1171 字)
    正文早上5点半,被手机的暴雨红色预警吵醒了。它居然还会发出警报声,有点意外。当时翻身看手机,只见红红的一大片,我还以为是地震,给我瞬间吓清醒了。早上连发两个暴雨红色预警,中午消停了一会儿,晚上又开始发。今晚跟何老师清假了,说休息一天,怕去了之后回不来了。刚说完这句......
  • 11、Python之变量:看得见还是看不见
    引言在前面一篇关于Python变量的文章中,更多地结合对象的内存结构及字节码指令,来看不同代码针对不同的类型的对象的不同效果。今天这篇文章中,想对新手在使用Python变量中,可能遇到的其他困惑,再展开来说一下。大概分为这几个模块:1、几种变量赋值操作2、Python中的变量作用......
  • pwnable.tw | 第3题cve-2018-1106
    前言pwnable.tw第三题,开始上难度了,考验的是一款真实程序的漏洞利用。漏洞源于一款开源的苹果AFP协议服务器程序Netatalk,漏洞最早是2018年发现的,2019年在HITCONQuals展示了1day利用,相关文章如下:2018年漏洞作者的原文翻译:NetatalkCVE-2018-1160的发现与利用hitcon相关文章:HITC......
  • Windows11使用子系统Ubuntu20.04配置图形化界面和安装软件
    前言        在上一章节,我们在windows11下利用wsl2安装了Ubuntu-linux子系统,并下载了android10的源码进行编译(Ubuntu运行环境下Android10源码下载和编译_ubuntu18下载android10源码-CSDN博客)。如果想进行android源码以及framework的学习,一定需要代码编辑软件,我之前学......
  • laravel:访问es,索引和搜索(Laravel 11.15.0)
    一,安装需要的库1,包的地址:https://packagist.org/packages/elasticsearch/elasticsearch2,文档地址:https://www.elastic.co/guide/en/elasticsearch/client/php-api/current/index.html3,用composer从命令行安装[lhdop@blogdignews]$composerrequireelasticsearch/ela......
  • 墨烯的C语言技术栈-C语言基础-011
    函数在数学中f(x)=2*x+1这是数学的函数C语言是结构化的程序设计语言结构化分为三种(1)顺序结构(2)选择结构(3)循环结构这种三种以及这三种组合可以描述生活中的所有事比如//求两个任意整数和Add(intx,inty){ intz=0; z=x+y; returnz;}in......
  • Oracle 11g dg switchover切换操作流程
    主库切换为物理备库查看主库的状态--获取/确认主库的状态信息以及保护模式SQL> set linesize 720SQL> col name for a10SQL> col open_mode for a10SQL> col database_role for a14SQL> col switchover_status for a16SQL> col force_logging for a8SQ......
  • 285个地级市出口产品质量及技术复杂度(2011-2021年)
    出口产品质量与技术复杂度:衡量国家竞争力的关键指标出口产品质量是衡量国内企业生产的产品在国际市场上竞争力的重要标准。它不仅要求产品符合国际标准和目标市场的法律法规,而且需要保证产品质量的稳定性和可靠性。而出口技术复杂度则进一步体现了一个国家在出口商品中的技术......
  • G65 线性基+贪心法 P4570 [BJWC2011] 元素
    视频链接: P4570[BJWC2011]元素-洛谷|计算机科学教育新生态(luogu.com.cn)//线性基O(60*n)#include<iostream>#include<cstring>#include<algorithm>usingnamespacestd;#defineLLlonglongconstLLN=1005;intn,m;structnode{LLnum,val;}a......