ssd 订阅
固态驱动器(Solid State Disk或Solid State Drive,简称SSD),俗称固态硬盘,固态硬盘是用固态电子存储芯片阵列而制成的硬盘,因为台湾英语里把固体电容称之为Solid而得名。SSD由控制单元和存储单元(FLASH芯片、DRAM芯片)组成。固态硬盘在接口的规范和定义、功能及使用方法上与普通硬盘的完全相同,在产品外形和尺寸上也完全与普通硬盘一致。被广泛应用于军事、车载、工控、视频监控、网络监控、网络终端、电力、医疗、航空、导航设备等诸多领域。其芯片的工作温度范围很宽,商规产品(0~70℃)工规产品(-40~85℃)。虽然成本较高,但也正在逐渐普及到DIY市场。由于固态硬盘技术与传统硬盘技术不同,所以产生了不少新兴的存储器厂商。厂商只需购买NAND存储器,再配合适当的控制芯片,就可以制造固态硬盘了。新一代的固态硬盘普遍采用SATA-2接口、SATA-3接口、SAS接口、MSATA接口、PCI-E接口、NGFF接口、CFast接口、SFF-8639接口和M.2 NVME/SATA协议。 [1] 展开全文
固态驱动器(Solid State Disk或Solid State Drive,简称SSD),俗称固态硬盘,固态硬盘是用固态电子存储芯片阵列而制成的硬盘,因为台湾英语里把固体电容称之为Solid而得名。SSD由控制单元和存储单元(FLASH芯片、DRAM芯片)组成。固态硬盘在接口的规范和定义、功能及使用方法上与普通硬盘的完全相同,在产品外形和尺寸上也完全与普通硬盘一致。被广泛应用于军事、车载、工控、视频监控、网络监控、网络终端、电力、医疗、航空、导航设备等诸多领域。其芯片的工作温度范围很宽,商规产品(0~70℃)工规产品(-40~85℃)。虽然成本较高,但也正在逐渐普及到DIY市场。由于固态硬盘技术与传统硬盘技术不同,所以产生了不少新兴的存储器厂商。厂商只需购买NAND存储器,再配合适当的控制芯片,就可以制造固态硬盘了。新一代的固态硬盘普遍采用SATA-2接口、SATA-3接口、SAS接口、MSATA接口、PCI-E接口、NGFF接口、CFast接口、SFF-8639接口和M.2 NVME/SATA协议。 [1]
信息
英文缩写
SSD
应用领域
军事、车载、工控、电力、医疗等
外文名
Solid State Disk或Solid State Drive [2]
中文名
固态硬盘/固态驱动器
组    成
由控制单元与存储单元组成
固态硬盘分类
分类方式: 固态硬盘的存储介质分为两种,一种是采用闪存(FLASH芯片)作为存储介质,另外一种是采用DRAM作为存储介质。 基于闪存类:基于闪存的固态硬盘(IDEFLASH DISK、Serial ATA Flash Disk):采用FLASH芯片作为存储介质,这也是通常所说的SSD。它的外观可以被制作成多种模样,例如:笔记本硬盘、微硬盘、存储卡、U盘等样式。这种SSD固态硬盘最大的优点就是可以移动,而且数据保护不受电源控制,能适应于各种环境,适合于个人用户使用。 [1]  一般它擦写次数普遍为3000次左右,以常用的64G为例,在SSD的平衡写入机理下,可擦写的总数据量为64G X 3000 = 192000G,假如你是个变态视频王每天喜欢下载视频看完就删每天下载100G的话,可用天数为192000 / 100 = 1920,也就是 1920 / 366 = 5.25 年。如果你只是普通用户每天写入的数据远低于10G,就拿10G来算,可以不间断用52.5年,再如果你用的是128G的SSD的话,可以不间断用104年!这什么概念?它像普通硬盘HDD一样,理论上可以无限读写,基于DRAM类:基于DRAM的固态硬盘:采用DRAM作为存储介质,应用范围较窄。它仿效传统硬盘的设计,可被绝大部分操作系统的文件系统工具进行卷设置和管理,并提供工业标准的PCI和FC接口用于连接主机或者服务器。应用方式可分为SSD硬盘和SSD硬盘阵列两种。它是一种高性能的存储器,而且使用寿命很长,美中不足的是需要独立电源来保护数据安全。DRAM固态硬盘属于比较非主流的设备。 [1] 
收起全文
精华内容
下载资源
问答
  • SSD

    千次阅读 2019-05-20 20:49:37
    SSD算法详解论文背景算法简介算法结构算法细节多尺度特征映射对于检测的卷积预测默认边框与比例训练匹配策略训练目标物体尺寸与比例的选取绝对负样本挖掘数据增强 论文背景 论文全称:S...

    论文背景

    论文全称:Single Shot MultiBox Detector
    论文链接:https://arxiv.org/abs/1512.02325
    论文日期:2016.12.29

    算法简介

    本文既保证了检测速度的提高,同时保证了检测准确度的提高。
    本文是在faster RCNN与YOLO之后提出来的,与原先的目标检测算法不同,未采用两阶段的神经网络,而是将整个检测过程封装为单个神经网络。这是提高检测速度的关键。

    1. 消除了候选区域提取的过程,直接将整张图片输入;
    2. 同时去除了随后的对于像素点或者特征进行重采样的阶段。

    结果:
    SSD使用300×300的图片作为输入,在VOC2007上达到了检测速度为59FPS,检测准确率为74.3%mAP;
    SSD使用512×512的图片作为输入,在VOC2007数据集上检测准确率为76.9%mAP。
    Faster RCNN在VOC2007上达到了检测速度为7FPS,检测准确率为73.2%mAP。
    YOLO在VOC2007上达到了检测速度为45FPS,检测准确率为63.4%mAP;

    改进:

    1. 使用小卷积核来预测目标的类别,并且抵消边界框的定位;
    2. 对于不同比例的检测过程,使用独立的卷积核;(最重要的改进:使用不同的比例的多个层用于预测)
    3. 为了将检测器应用于多尺寸,从神经网络的后阶段将这些卷积核应用到多个特征图中。

    算法结构

    SSD在训练过程,需要一整张图片以及对每个物体的真实框标签作为输入;
    在卷积过程中,会对不同尺寸的几个特征映射中的每一个位置的的不同比例的少量默认框进行评估;
    对于每个默认框,对于所有的目标类别都预测形状偏移以及置信度;
    在训练时期,将这些默认框与真实框进行匹配;例如,对猫匹配两个默认框,对狗匹配一个默认框。这三个框被设为正样本,其他的被设为负样本。
    损失函数是定位损失(如L1)与置信度损失(如softmax)的权重和。
    在这里插入图片描述

    算法细节

    SSD是基于前馈卷积神经网络的算法,会生成一系列固定尺寸的边界框,并且会为这些框中对象类实例的出现打分。接着会跟着一个非极大值抑制算法得到最后的预测结果。

    截取分类之前的标准结构用来进行高质量的图片分类,然后添加辅助结构用来进行目标检测:

    多尺度特征映射

    在被截掉的基础神经网络后面加上了一些卷积特征层,这些层的尺寸逐渐减小,并允许在多个尺度上预测检测。 用于预测检测的卷积模型对于每个特征层是不同的。Overfeat和YOLO都是在单个尺度特征图上操作的。

    对于检测的卷积预测

    每一个加入的特征层(或者基础神经网络中存在的特征层)能使用卷积核集生成固定的检测预测集。一个特征层的尺寸是m×n×p,用于预测潜在检测参数的基本元素是3×3×p的小卷积核,其产生类别的分数或相对于默认框坐标的形状偏移。 在应用内核的每个m×n个位置处,它产生输出值。相对于每个特征图位置的默认框位置测量边界框偏移输出值。
    在这里插入图片描述
    SSD的几个特征层用来预测不同尺寸与比例的默认框与其置信度之间的偏移。
    default box在不同的feature层有不同的scale,在同一个feature层又有不同的aspect ratio,因此基本上可以覆盖输入图像中的各种形状和大小的object。
    针对conv4_3(4),fc7(6),conv6_2(6),conv7_2(6),conv8_2(4),conv9_2(4)的每一个再分别采用两个3×3大小的卷积核进行卷积,这两个卷积核是并列的,一个用来定位,一个用来计算置信度。
    SSD结构的倒数第二列的数字8732表示的是所有default box的数量:
    38×38×4+19×19×6+10×10×6+5×5×6+3×3×4+1×1×4=8732;
    括号里的数字代表default box的数量。

    默认边框与比例

    默认边界框类似于faster R-CNN中使用的锚框,但我们将它们应用于不同分辨率的多个特征图。允许在多个特征图中使用不同的默认框形状,这样我们就可以有效地离散可能的输出框形状的空间。
    本文将一组默认边界框与每个要素图单元关联,以用于网络顶部的多个特征图。默认框以卷积方式平铺特征图,使得相对于相应单元的每个框的位置被固定。在特征图中,我们预测相对于单元中的默认框形状的偏移,以及用于指出每个边界框中的一个类别实例是否出现的每类分数。特别是在对于给定位置的k中的每个边界框中,我们计算c类分数(每个类别都有一个分数)和相对于原始默认框形状的4个偏移量(中心点的坐标值以及边界框的长和宽)。这导致在特征图中的每个位置周围应用的总共(c + 4)k个滤波器,产生m×n特征图的(c + 4)kmn输出。

    训练

    训练SSD与训练一个有候选区域提取的检测算法的主要区别是,在一个固定的检测输出集中真实的信息需要被分配给特殊的输出。一旦分配被决定了,损失函数和反向传播都是端到端的了。
    训练包括选择一个默认框集,并且缩放检测器,以及负样本挖掘与数据增强策略。

    匹配策略

    在训练期间,我们需要确定哪些默认框对应于真实框,并相应地训练网络。 本文首先选取jaccard overlap最大的默认框,然后将其他默认框与其他真实框进行匹配,选择jaccard重叠高于阈值(0.5)的。 这简化了学习问题,允许网络预测多个重叠默认框的高分,而不是要求它只选择具有最大重叠的框。

    训练目标物体

    匹配类别p的第i个默认框与第j个真实框:
    在这里插入图片描述
    在这里插入图片描述
    整体损失函数:
    在这里插入图片描述
    定位损失(使用L1正则化):
    在这里插入图片描述
    置信度损失(使用softmax函数):
    在这里插入图片描述

    尺寸与比例的选取

    对于不同的输入尺寸的图片都能处理。
    使用低层的特征图能提高语义分割质量,低层能对输入的目标捕获更精细的细节,有利于分类。
    添加从特征图中合并的全局上下文可以帮助平滑分割结果。
    一个神经网络内不同层次的特征图有不同的感受野,在SSD中,不需要将默认框与每一层的实际感受野对应上,我们设计将默认图平铺,以至于特殊的特征图学会响应目标的特殊尺寸。
    如,用m个特征图用于预测,每一个特征图的默认框尺寸是(总共有6个默认框):
    a_r 属于 {1 ,2 ,3 ,1/2 ,1/3 }
    在这里插入图片描述
    在这里插入图片描述
    第6个默认框尺寸
    第6个默认框尺寸
    中心点坐标(对应于特征图的一个像素点)
    在这里插入图片描述
    |f_k|是第k个方形特征图的尺寸,即面积。

    绝对负样本挖掘

    解决正负样本不平衡问题,本文不使用所有的负样本,而是使用最高的置信度损失对每一默认框进行排序,然后选择其中排名最前的一个,这样能保证负样本与正样本的比例最高为3:1,同时发现这可以带来更快的优化和更稳定的训练。

    数据增强

    为了让模型对于不同的输入更鲁棒,每一张图片都被以下列任意一种方式进行了采样。

    1. 使用整张原始图片;
    2. 目标物体的最小jaccard overlop是0.1,0.3,0.5,0.7,0.9;
    3. 任意采样一部分。
      每个样本的大小都是[0.1,1]的原始图像,并且其中的比例在0.5和2之间。如果真实框的中心在采样部分,那么保留真实框的重叠部分, 在上述采样步骤之后,每个采样部分被调整为固定大小并且以0.5的概率水平地翻转。
          </div>
          <link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-258a4616f7.css" rel="stylesheet">
                  </div>
    
    展开全文
  • ssd

    2017-05-21 09:59:41
    摘要: 配置ssd 并且整理自己的数据进行训练,调用c++ 接口来做检测分类 最近一直在看深度学习的东西,用到了ssd,上网一搜,找到一篇不错的博客,http://www.cnblogs.com/objectDetect/p/5780006.html,官网,这篇...
    摘要: 配置ssd 并且整理自己的数据进行训练,调用c++ 接口来做检测分类

    最近一直在看深度学习的东西,用到了ssd,上网一搜,找到一篇不错的博客,http://www.cnblogs.com/objectDetect/p/5780006.html官网,这篇是连安装cuda到caffe环境的一系列http://blog.csdn.net/wopawn/article/details/52302164。经过磕磕绊绊,也决定写一篇相关的博客。

    ssd的demo是介绍了在voc数据集上训练和验证,所以想要简单的使用ssd训练自己的数据,就是做成类似voc 的数据再调用ssd 中的ssd_pascal.py进行训练。这里需要说明的是ssd项目中自带的ssd_pascal.py文件会在VGG的模型上再训练,以我的理解就是在VGG的模型上做fine-tuning。


    现在从头开始教程:

    1 安装ssd

    1.1 首先需要安装有git

    sudo apt-get install git
    

    1.2 git ssd 项目

    git clone https://github.com/weiliu89/caffe.git
    cd caffe
    git checkout ssd(出现“分支”则说明copy-check成功)
    

    记得一定要用git的方法,不要直接下载caffe-master.zip这种压缩包,里面没有git的配置,没用的。

    1.3 开始编译ssd

    先安装一些依赖

    sudo apt-get install libprotobuf-dev libleveldb-dev libsnappy-dev libopencv-dev libhdf5-serial-dev protobuf-compiler
    sudo apt-get install --no-install-recommends libboost-all-dev
    

    ubuntu14.04需要依赖

    sudo apt-get install libgflags-dev libgoogle-glog-dev liblmdb-dev
    

    ubuntu16.04需要cuda 8

    BLAS:可以通过

    sudo apt-get install libatlas-base-dev
    

    可以安装OpenBLAS 或者 MKL,MKL可以使CPU更好的工作。

    要python的话可能要安装

    sudo apt-get install python-pip python-numpy  python-scipy python-matplotlib python-sklearn python-skimage python-h5py python-protobuf python-leveldb python-networkx python-nose python-pandas python-gflags Cython ipython
    

    开始编译,编译有两种办法:

    1.3.1 直接make

    cd "<你的caffe项目>"
    cp Makefile.config.example Makefile.config
    

    如果你想直接用CPU而不用GPU,进入Makefile.config将 #CPU_ONLY:=1这句去掉注释,像下面这个

    # CPU-only switch (uncomment to build without GPU support).
    CPU_ONLY := 1
    

    如果要改BLAS:

    # BLAS choice:
    # atlas for ATLAS (default)
    # mkl for MKL
    # open for OpenBlas
    BLAS := atlas
    

    然后执行

    make all -j8
    sudo make install
    make runtest (这个不一定要)
    make pycaffe
    

    1.3.2 用cmake方法安装

    cd "<你的caffe项目>"
    mkdir build
    cd build
    ccmake ..
    make -j8
    sudo make install
    make runtest
    make pycaffe
    

    如果要改BLAS和单用CPU,在ccmake .. 中选择。

    装好在之后注意配置python caffe 环境

    vim /etc/profile
    

    在最后一行添加

    export PYTHONPATH=/home/........../caffe/python:$PYTHONPATH
    

    然后更新下环境

    source /etc/profile
    

    1.4 验证pycaffe环境

    python
    import caffe
    

    如果没有问题那就是成功了

    如果有错误那么就打开主目录下的.bashrc写入那句话,再试试看。

    2 训练自己模型

    训练VOC数据的方法上面那篇博客有讲,这里不再多说。讲讲训练自己数据。

    现在来看一下voc的标签00001.xml

    <annotation>
        <folder>VOC2007</folder>
        <filename>000018.jpg</filename>
        <source>
            <database>The VOC2007 Database</database>
            <annotation>PASCAL VOC2007</annotation>
            <image>flickr</image>
            <flickrid>340537267</flickrid>
        </source>
        <owner>
            <flickrid>Kathy Stern</flickrid>
            <name>Kathy Stern</name>
        </owner>
        <size>
            <width>380</width>
            <height>285</height>
            <depth>3</depth>
        </size>
        <segmented>0</segmented>
        <object>
            <name>dog</name>
            <pose>Left</pose>
            <truncated>0</truncated>
            <difficult>0</difficult>
            <bndbox>
                <xmin>31</xmin>
                <ymin>30</ymin>
                <xmax>358</xmax>
                <ymax>279</ymax>
            </bndbox>
        </object>
    </annotation>
    

    现在主要更改的是size中的width,height,object中的name和xmin,xmax,ymin,ymax这几个东西。

    所以每幅图片都要在样子更改,上面的博客推荐了一个bbox-tool,但是对于我来说不太好用,然后就写了一个基于opencv的程序,稍后放出。

    在ssd中voc的同级目录新建一个文件夹,讲所有图片和标签都放进去,做好链接文件夹下

    • trainval.txt 存放训练用的图片路径,格式类似
      data1/image1.jpg data1/image.xml
      
    • test.txt 存放测试用的图片路径,格式和trainval.txt相同
    • test_name_size.txt 存放测试用的图片,格式类似测试 “ 图片名 高 长“
      imagetest1 300 300
      
    • labelmap_indoor.prototxt 标签的名字,注意label 0 这类一定会存在,就是图片bounding box以外的数据标签

    数据做好之后运行create_data.sh进行整理数据,create_data.sh里面可能有些路径错误,可以自行改到自己的数据目录。

    运行create_data.sh之后会在当前目录和ssd的examples下新建一个数据目录,名字是当前目录的名字。

    3 训练

    打开ssd_pascal.py需要修改的有一下几点:

    • train_data和test_data , 指向examples中你的数据,例如
      train_data = "examples/indoor/indoor_trainval_lmdb"
      # The database file for testing data. Created by data/VOC0712/create_data.sh
      test_data = "examples/indoor/indoor_test_lmdb"
      
    • num_test_image该变量修改成自己数据集中测试数据图片的数量
    • num_classes 该变量修改成自己数据集中 标签类别数量数 + 1
    • gpus = "0,1,2,3" 电脑有几个gpu就写多少个,如果有一个就写gpus="0",两个就写gpus="0,1",以此类推。

    最后到caffe的根目录运行,ps:你的ssd_pascal.py的目录是example/yourSSD/ssd_pascal.py

    python example/yourSSD/ssd_pascal.py
    

    4 测试

    有好几种测试的方法,

    4.1 python

    在caffe的根目录运行ssd_pascal_webcam.py这个文件,这是使用摄像头实时测试的软件,读取的caffemodel是在caffe/models/VGGNet/VOC0712/SSD_300x300_webcam下最新的model,所以记得在这个文件夹中放入模型。还要更改下ssd_pascal_webcam.py中label_map_file到你的labelmap_voc.prototxt

    python examples/ssd/ssd_pascal_webcam.py
    

    4.2 c++

    编译完SSD后,C++版本的的可执行文件存放目录: .build_release/examples/ssd/ssd_detect.bin

    测试命令 ./.build_release/examples/ssd/ssd_detect.bin models/VGGNet/indoor/deploy.prototxt models/VGGNet/indoor/VGG_VOC0712_SSD_300x300_iter_60000.caffemodel pictures.txt

    ssd自带ssd_detect.cpp,可以拿来使用。

    4.2.1 用qt.pro件定义中需要引入你的caffe配置,例如

    LIBS += /home/xxx/caffe/build/lib/libcaffe.so 
    
    INCLUDEPATH += /home/xxx/caffe/include
    
    INCLUDEPATH += /home/xxx/caffe/build/include
    

    可能还会有一些编译问题:

    1. error while loading shared libraries: libglog.so.0: cannot open shared object file: No such file or directory解决
      LIBS +=/usr/lib/x86_64-linux-gnu/libglog.so
      
    2. libcaffe.so.1.0.0-rc3: cannot open shared object file: No such file or directory解决:在/etc/ld.so.conf.d/下新建caffe.conf文件,在caffe.conf中加入到libcaffe.so.1.0.0-rc3的位置,基本上是在build的lib里。

    4.2.2 使用cmake

    如果是使用cmake,注意安装ssd的时候一定要make install

    然后CMakeLists.txt

    find_package(OpenCV REQUIRED)
    find_package(Caffe REQUIRED)
    
    
    #option (CPU_ONLY "Use CPU or use GPU" ON)
    #option (USE_OPENCV "Use CPU or use GPU" ON)
    include_directories( ${Caffe_INCLUDE_DIRS} )
    add_definitions(${Caffe_DEFINITIONS}) # ex. -DCPU_ONLY
    add_executable(ssd_detect ssd_detect.cpp )
    

    使用cpu或者gpu可以在选项里面定义。

    展开全文
  • SSD原理解读-从入门到精通

    万次阅读 多人点赞 2018-08-27 08:00:47
    SSD原理解读-从入门到精通

    前言

    当初写这篇博客的初衷只是记录自己学习SSD的一些心得体会,纯属学习笔记,后来由于工作上的需要,需要对小伙伴进行目标检测方面的培训,后来就基于这篇博客进行了扩展,逐渐演变成了现在的样子,本文力求从一个初学者的角度去讲述目标检测和SSD(但是需要你具备CNN的基础),尽量使用通俗的语言并结合图表的方式让更多初学者更容易理解SSD这个算法,但是一个人的时间精力有限,不可能深入理解SSD的每一个细节,加上表达能力也有限,自己理解了的东西不一定在文中能够说明白,文中有什么不妥的地方,欢迎大家批评指正,也欢迎留言一起交流讨论。

    ps:平时会经常遇到有咨询关于如何使用C++加载onnx模型完成SSD或者YOLO推理的问题(据我观察很多人只会使用python语言),可以参考这篇博客:OpenCV加载onnx模型实现SSD,YOLOV3,YOLOV5的推理



    目标检测基础

    在实际的工作中发现,一些小伙伴在学习检测的时候对一些基础的东西理解的还不够,这里总结了比较重要的几点。

    传统目标检测的基本原理

    为什么要提传统目标检测呢?因为理解传统目标检测对于理解基于深度学习的目标检测非常重要,因为学到最后你会发现,两者的本质都是一样的,都是对滑动窗口的分类。下面我们看一下传统目标检测的基本原理。
    在这里插入图片描述
    主要分为两个步骤:训练+预测,其中训练主要是用来得到分类器,比如SVM,预测就是使用训练好的分类器对图像中的滑动窗口进行特征提取然后分类,最后得到检测的结果。下面以人脸检测为例:
    在这里插入图片描述
    假设我们需要训练一个人脸检测器,那第一步就是训练一个人脸的分类器,这个分类器有什么作用呢?它的作用就是将上图左边的很多图像划分为两类:人脸和非人脸。分类器训练好了之后,就可以进行检测了。
    在这里插入图片描述
    预测阶段有两种滑动窗口策略:

    1. 策略1:使用不同大小的滑动窗口,对每个滑动窗口提取特征并分类判断是否是人脸,最后经过NMS得到最后的检测结果,本文的SSD本质上就是这种策略,不同检测层的anchor就类似于不同大小的滑动窗口
    2. 策略2:构造图像金字塔,只使用一种大小的滑动窗口在所有金字塔图像上滑动,对每个滑动窗口提取特征并分类判断是否是人脸,最后经过NMS得到最后的检测结果,MTCNN就是采用了这种策略

    传统目标检测的代表主要有:

    1. HOG+SVM的行人检测
    2. Haar+Adaboost的人脸检测

    为什么要使用全卷积神经网络做检测

    我们知道经典的深度学习目标检测算法的代表SSD,YOLOV3和FasterRCNN的RPN都使用了全卷积神经网络,那为什么要使用全卷积呢?

    分类网络

    下面是一个典型的分类网络结构:
    在这里插入图片描述
    图片来自经典的人脸识别论文DeepID2:https://arxiv.org/abs/1406.4773

    我们知道典型的分类网络,比如VGG,ResNet等最后都会使用全连接层提取特征,然后经过softmax计算每一类的概率。

    典型的分类网络有如下特点:

    1. Softmax的前一层为全连接层,且输出节点数为分类的类别数,比如imagenet有1000类,则最后的全连接层有1000个输出节点,分别对应1000类的概率,VGG16中的fc8对应了这一层,上图有10000分类,所以fc2有10000个输出节点
    2. Softmax的倒数第二层也为全连接层,这一层一般是提取特征用的,比如VGG16中的fc7层就是用来提取特征的,上图中DeepID2层也是用来进行提取特征的
    3. 由于使用全连接层提取特征,所以提取的是全图的特征,所以一张图像中只能包含一个目标,如果有多个目标,提取出来的特征就不准确,影响最后的预测
    4. 由于全连接层的存在,网络的输入大小必须是固定的

    那如何才能提取多个目标的特征呢?

    使用卷积层代替全连接层进行特征提取

    在这里插入图片描述

    我们将图1简化为图2的表示形式,其中图2中省略了Input到DeepID2中间的层,我们看到当DeepID2是全连接层的时候,感受野对应了全图,所以提取的是全图的特征,现在我们把DeepID2替换为卷积层,其中卷积层的输出通道数为160,这是为了能够提取160维的特征向量,图3中我们可以看到当使用卷积层的时候,DeepID2的输出特征图的每个位置的感受野不是对应了全图,而是对应了原图的某一个滑动窗口,这样DeepID2这一层就可以提取原图多个滑动窗口的特征了,图3中我们可以看到一共提取出了25个滑动窗口的160维特征向量,然后我们就可以对这25个滑动窗口做分类了。这样就使得检测成为了可能。

    使用卷积层代替全连接层进行分类

    我们知道在分类网络中softmax的前一层使用的是全连接层,且该全连接层的输出节点数为分类数,比如上文中的DeepID2的后面的fc2层。
    在这里插入图片描述
    但是现在DeepID2这一层变成了卷积层之后,fc2层就不适合采用全连接层了。下面我们将fc2层替换为卷积层,我们采用1x1卷积(也可以使用3x3卷积),同时卷积层的输出通道数为10000,对应了10000分类。
    在这里插入图片描述
    我们看到当fc2采用1x1卷积的时候,fc2层的特征图中的每个位置对应了一个滑动窗口的10000分类,这样一共得到25x10000的特征向量,表示对25个滑动窗口的10000分类。最后将这25x10000的特征向量输入softmax,就可以实现对这25个滑动窗口的分类了。

    这其实就是经典的OverFeat的核心思想。

    注意:这里并没有说检测网络不能使用全连接层,其实检测网络也可以使用全连接层。检测网络只是使用卷积层代替全连接层提取特征,最后对特征进行分类和回归可以使用卷积层也可以使用全连接层,YOLOV1最后就使用了全连接层对特征进行分类和回归,只是这样会有一些缺点:网络的输入大小必须是固定的,而且最后检测的效果往往没有使用卷积层做分类和回归的效果好。

    确定每个滑动窗口的类别

    上文中,我们将传统的分类网络一步一步的修改成了一个检测网络,知道了如何提取多个目标的特征以及使用卷积层代替全连接层进行分类,现在我们还差最后一步:要对多个目标进行分类,还需要知道他们的groundtruth,也就是他们的类别,那么如何确定类别呢?
    这里就要用到anchor这项技术。

    anchor就是用来确定类别的。

    在这里插入图片描述
    我们知道anchor的参数是可以手动设置的,上图中
    anchor的大小被设置为 [x1,y1,x2,y2],这个anchor就是上文中提到的滑动窗口
    groundtruth对应 [x1’,y1’,x2’,y2’]
    然后通过计算anchor和groundtruth之间的IOU就可以确定这个滑动窗口的类别了(比如IOU>0.5的为正样本,IOU<0.3的为负样本)。关于anchor在下文中会有详细讨论。

    到这里,SSD的整体框架已经基本搭建好了。其实SSD的多个检测层就等价于多个DeepID2层,不同检测层有不同大小的滑动窗口,能够检测到不同大小的目标。每个检测层后面会接2路3x3卷积用来做分类和回归,对应了fc2层。
    在这里插入图片描述
    理解了上面的内容之后,其实就很容易理解SSD了。


    SSD效果为什么这么好

    虽然SSD这个算法出来已经两年了,但是至今依旧是目标检测中应用最广泛的算法,虽然后面有很多基于SSD改进的算法,但依旧没有哪一种可以完全超越SSD。那么为什么SSD效果这么好?SSD效果好主要有三点原因:

    1. 多尺度
    2. 设置了多种宽高比的anchor
    3. 数据增强

    注:

    1. anchor,default box,prior box表示的是同一个意思,本文统一使用更加常用的anchor来表示。实际上,anchor技术的鼻祖是DeepMultiBox(2014年CVPR:Scalable Object Detection using Deep Neural Networks),这篇论文里首次提出使用prior(先验框),并且提出使用prior做匹配。后面的众多工作,比如RCNN系列,YOLO系列都使用了anchor这个术语,而在SSD中anchor又叫default box,本质上都是表示的同一个东西。

    原因1:多尺度

    这里写图片描述

    由SSD的网络结构可以看出,SSD使用6个不同特征图检测不同尺度的目标。低层预测小目标,高层预测大目标。

    通过前面的学习,其实就很容易理解SSD中的多尺度检测,这6个检测层都是卷积层,对应了上文中的6个DeepID2层,每个DeepID2层对应了不同大小的滑动窗口(低层滑动窗口较小,高层滑动窗口较大),这样就可以检测到不同尺度的目标了。
    这里写图片描述

    作者在论文中通过实验验证了,采用多个特征图做检测能够大大提高检测精度,从上面的表格可以看出,采用6个特征图检测的时候,mAP为74.3%,如果只采用conv7做检测,mAP只有62.4%。

    原因2:设置了多种宽高比的anchor

    这里写图片描述

    在特征图的每个像素点处,生成不同宽高比的anchor,论文中设置的宽高比为{1,2,3,1/2,1/3}。假设每个像素点有k个anchor,需要对每个anchor进行分类和回归,其中用于分类的卷积核个数为ck(c表示类别数),回归的卷积核个数为4k。

    SSD300中anchor的数量:(38384 + 19196 + 10106 + 556 + 334 + 114)= 8732

    对于初学者一定有以下几个问题:

    1. 为什么要设置anchor?
    2. 为什么同一个检测层可以设置不同大小的anchor?
    3. 为什么一个检测层可以设置多个anchor?
    4. 为什么要设置多种宽高比的anchor?

    理论感受野和有效感受野

    NIPS 2016论文Understanding the Effective Receptive Field in Deep Convolutional Neural Networks[1]提出了有效感受野(Effective Receptive Field, ERF)理论。有效感受野的理解对于理解anchor非常重要。

    影响某个神经元输出的输入区域就是理论感受野,也就是我们平时说的感受野,但该输入区域的每个像素点对输出的重要性不同,越靠近中心的像素点影响越大,呈高斯分布,也就是说只有中间的一小部分区域对最后的输出有重要的影响,这个中间的一小部分区域就是有效感受野

    有效感受野在训练过程中是会发生变化的,影响有效感受野的因素:

    1. 数据集
    2. 层的类型(下采样,扩张卷积,跳层连接,非线性激活函数)
    3. 卷积层参数初始化方式(Uniform(参数全部设置为1), Random)
    4. 卷积层的个数

    下图展示了不同因素对有效感受野的影响
    卷积层层数,权值初始化方式以及非线性激活对ERF的影响
    卷积层层数,权值初始化方式以及非线性激活对ERF的影响

    在这里插入图片描述
    下采样和扩张卷积可以增大感受野

    在这里插入图片描述
    不同数据集对感受野的影响

    为什么要设置anchor?

    通过前面的学习,我们知道,在分类/识别问题中,通常整张图就包含一个目标,所以只需要对一个目标直接分类就好了,所以最后直接使用全连接层提取整幅图像的特征就可以了(全连接层理论感受野大小就是输入大小)。但是检测问题中,输入图像会包含有很多个目标,所以需要对多个目标进行特征提取,这个时候就不能使用全连接层了,只能使用卷积层,卷积层的输出特征图上每个位置对应原图的一个理论感受野,该位置提取的就是这个理论感受野区域的特征,然后我们只需要对这个特征进行分类和回归就可以实现检测了。在实际训练训练过程中,要想对这个特征进行分类,我们就需要知道这个特征提取的是什么目标的特征,所以我们需要知道两个东西:

    1. 这个特征对应了原图什么区域?
    2. 这个区域的label是什么?
      但是在实际训练过程中,我们并不知道这个理论感受野的大小,这个时候就出现了anchor技术。

    anchor作用:通过anchor设置每一层实际响应的区域,使得某一层对特定大小的目标响应。这样检测层提取的就是anchor对应区域的特征了。通过anchor我们就可以知道上面两个问题的答案了。

    论文中也提到:
    Feature maps from different levels within a network are known to have different (empirical) receptive field sizes. Fortunately,
    within the SSD framework, the default boxes do not necessary need to correspond to the actual receptive fields of each layer. We design the tiling of default boxes so that specific feature maps learn to be responsive to particular scales of the objects.
    通过设计anchor的平铺可以使得特定的特征图对特定大小的目标进行响应。

    下图可以更加形象的表示anchor的作用
    在这里插入图片描述
    图a中黑色虚线区域对应图b中的理论感受野,红色实线框是手动设置的anchor大小
    图b是使用图a中的anchor参数训练出来的模型,其中整个黑色区域就是理论感受野(TRF),对应a图的黑色虚线区域,中间呈高斯分布的白色点云区域就是由于设置了anchor而实际发生响应的区域,这个区域就是有效感受野(ERF),我们用anchor等价表示这个区域。
    我们可以看到通过在图a中设置anchor可以设置该层实际响应的区域,使得对特定大小的目标响应。

    这里还有几个问题需要说明一下。

    1. 为什么anchor可以设置实际响应的区域?
      这就是CNN的神奇之处,这个问题目前我还不知道如何解释,就像目前的深度学习依然是不可解释的一样,这点就当作一个结论记住就可以了。

    2. 为什么同一个检测层可以设置不同大小的anchor
      我们知道可以通过anchor设置每一层实际响应的区域,使得某一层对特定大小的目标响应。
      是否每一层只能对理论感受野响应呢?有效感受野理论表明,每一层实际响应的区域其实是有效感受野区域,而且这个有效感受野区域在训练过程中会发生变化(比如不同数据集的影响等),正是由于有效感受野有这个特性,所以我们可以在同一个检测层设置不同大小的anchor,也就是说你既可以设置anchor大小为理论感受野大小,也可以将anchor大小设置为其他大小,最后训练出来的网络会根据你的设置对特定大小的区域响应。

    3. 为什么在同一个特征图上可以设置多个anchor检测到不同尺度的目标
      刚开始学SSD的朋友一定有这样的疑惑,同一层的感受野是一样的,为什么在同一层可以设置多个anchor,然后在分类和回归两个分支上只需要使用不同通道的3x3卷积核就可以实现对不同anchor的检测?虽然分类和回归使用的是同一个特征图,但是不同通道的3x3卷积核会学习到那块区域的不同的特征,所以不同通道对应的anchor可以检测到不同尺度的目标。

    4. anchor本身不参与网络的实际训练,anchor影响的是classification和regression分支如何进行encode box(训练阶段)和decode box(测试阶段)。测试的时候,anchor就像滑动窗口一样,在图像中滑动,对每个anchor做分类和回归得到最终的结果。

    5. 关于anchor的进一步探讨,见另一篇博客:深入理解anchor,欢迎大家畅所欲言

    anchor与滑动窗口

    上文中提到了两个概念:滑动窗口和anchor,每个检测层对应了不同大小的滑动窗口,也对应着不同大小的anchor,那这两个概念有什么区别呢?

    这里我们不严格区分这两个概念,我们可以认为这两个表示的是同一个东西。

    这里有一点要注意:由于anchor是可以手动设置的,所以某一个检测层的滑动窗口大小是会随着anchor的大小发生变化的,这就是anchor的神奇之处!

    anchor的匹配

    前面我们知道了SSD提取的是anchor对应区域的特征,实际训练的时候还需要知道每个anchor的分类和回归的label,如何确定呢?SSD通过anchor与groundtruth匹配来确定label。
    在训练阶段,SSD会先寻找与每个anchor的IOU最大的那个ground truth(大于IOU阈值0.5),这个过程叫做匹配。如果一个anchor找到了匹配的ground truth,则该anchor就是正样本,该anchor的类别就是该ground truth的类别,如果没有找到,该anchor就是负样本。图1(b)中8x8特征图中的两个蓝色的anchor匹配到了猫,该anchor的类别为猫,图1©中4x4特征图中的一个红色的anchor匹配到了狗,该anchor的类别为狗。图2显示了实际的匹配过程,两个红色的anchor分别匹配到了猫和狗,左上角的anchor没有匹配,即为负样本。

    这里写图片描述
    图1

    在这里插入图片描述
    图 2(图中红色框表示anchor,绿色框表示groundtruth)

    关于匹配更多的细节,参考Caffe源码multibox_loss_layer.cpp中的FindMatches()函数,前面的博客:SSD源码解读3-MultiBoxLossLayer中也讲到了该函数。

    为什么要设置多种宽高比的anchor?

    由于现实中的目标会有各种宽高比(比如行人),设置多个宽高比可以检测到不同宽高比的目标。
    这里写图片描述

    作者实验结果表明,增加宽高比为1/2,2,1/3,3的default box,mAP从71.6%提高到了74.3%。

    如何选择anchor的scale和aspect ratio?

    假设我们用m个feature maps做预测,那么对于每个featuer map而言其anchor的scale是按以下公式计算的。
    Sk=Smin+SmaxSminm1(k1) S_k=S_{min}+{{S_{max}-S_{min}} \over {m-1}}(k-1)
    这里SminS_{min}是0.2,表示最低层的scale是0.2,SmaxS_{max}是0.9,表示最高层的scale是0.9。宽高比αr=1,2,3,1/2,1/3{\alpha}_r={1,2,3,1/2,1/3},因此每个anchor的宽wkα=Skαrw^{\alpha}_{k}=S_k \sqrt{{\alpha}_r},高hkα=Sk/αrh^{\alpha}_{k}={S_k / \sqrt{{\alpha}_r}},当aspect ratio为1时,作者还增加一种scale的anchor:Sk=SkSk+1S^{'}_k= \sqrt{S_kS_k+1},因此,对于每个feature map cell而言,一共有6种anchor。

    示例:
    假设m=6,即使用6个特征图做预测, 则每一层的scale:0.2,0.34,0.48,0.62,0.76,0.9
    对于第一层,scale=0.2,对应的6个anchor为:

    宽高比
    1 0.200000 0.200000
    2 0.282843 0.141421
    3 0.346410 0.115470
    1/2 0.141421 0.282843
    1/3 0.115412 0.346583
    最后增加的default box 0.260768 0.260768

    注:表格中每个宽高比的anchor的实际宽和高需要乘以输入图像的大小,如SSD300,则需要使用上面的数值乘以300得到anchor实际大小。

    Caffe源码中anchor的宽高比以及scale的设置参考prior_box_layer.cpp,前面的博客:SSD源码解读2-PriorBoxLayer也对该层进行过解读。

    原因3:数据增强

    SSD中使用了两种数据增强的方式
    1. 放大操作: 随机crop,patch与任意一个目标的IOU为0.1,0.3,0.5,0.7,0.9,每个patch的大小为原图大小的[0.1,1],宽高比在1/2到2之间。能够生成更多的尺度较大的目标
    2. 缩小操作: 首先创建16倍原图大小的画布,然后将原图放置其中,然后随机crop,能够生成更多尺度较小的目标

    这里写图片描述

    这里写图片描述

    作者实验表明,增加了数据增强后,mAP从65.5提高到了74.3!

    数据增强是SSD中最大的trick,已经成为了后面众多检测算法的标配了。

    数据增强对应Caffe源码annotated_data_layer.cpp,前面的博客:SSD源码解读1-数据层AnnotatedDataLayer也对该层进行过解读。


    SSD的缺点及改进

    1. SSD主要缺点:SSD对小目标的检测效果一般,作者认为小目标在高层没有足够的信息。

    论文原文:
    This is not surprising because those small objects may not even have any information at the very top layers. Increasing the input size (e.g. from 300× 300 to 512× 512) can help improve detecting small objects, but there is still a lot of room to improve.

    对小目标检测的改进可以从下面几个方面考虑:
    1. 增大输入尺寸
    2. 使用更低的特征图做检测(比如S3FD中使用更低的conv3_3检测)
    3. FPN(已经是检测网络的标配了)

    2. 关于anchor的设置的优化

    An alternative way of improving SSD is to design a better tiling of default boxes so that its position and scale are better aligned with the receptive field of each position on a feature map. We leave this for future work. P12
    论文中提到的anchor设置没有对齐感受野,通常几个像素的中心位置偏移,对大目标来说IOU变化不会很大,但对小目标IOU变化剧烈,尤其感受野不够大的时候,anchor很可能偏移出感受野区域,影响性能。
    关于anchor的设计,作者还提到了
    In practice, one can also design a distribution of default boxes to best fit a specific dataset. How to design the optimal tiling is an open question as well
    论文提到根据特定数据集设计default box,在YOLOV2中使用聚类的方式初始化anchor,能够更好的匹配到ground truth,帮助网络更好的训练


    SSD中的Mining机制

    在视觉任务中经常遇到两个问题:
    1. 类别不均衡
    2. 简单样本和困难样本不均衡 (easy sample overwhelming)。easy sample如果太多,可能会将有效梯度稀释掉。

    为了解决上述问题,研究人员提出了一些解决方案:
    1. Online Hard Example Mining, OHEM(2016)。将所有sample根据当前loss排序,选出loss最大的N个,其余的抛弃。这个方法就只处理了easy sample的问题。
    2. Focal Loss(2017), 最近提出来的。不会像OHEM那样抛弃一部分样本,focal loss考虑了每个样本, 不同的是难易样本上的loss权重是根据样本难度计算出来的。

    SSD中采用了一种新的Mining机制,OHNM(Online Hard Negative Mining),在Focal Loss里代号为OHEM 1:3,是对OHEM的一种改进。OHNM在计算loss时, 使用所有的positive anchor, 使用OHEM选择3倍于positive anchor的negative anchor。同时考虑了类间平衡与easy sample。通过OHNM让训练更快收敛同时也更加稳定。

    注意,SSD中mining具体实现的时候,MultiBoxLoss层的 mining_type可以选择MAX_NEGATIVE或者HARD_EXAMPL

    1. MAX_NEGATIVE对应OHNM, 只计算分类loss,不计算定位loss,只针对负样本选择loss最大的3倍于正样本数量的负样本
    2. HARD_EXAMPL对应OHEM ,会同时计算分类和定位loss,选择出loss最大的前topN个样本
      具体实现参考MineHardExamples()函数。

    SSD与MTCNN

    这里为什么会提到MTCNN[2]呢?如果你了解过MTCNN这个算法,一定对PNet这个网络不陌生,仔细比较SSD与PNet,你就会发现SSD与PNet之间有着千丝万缕的联系。

    这里写图片描述
    其实我对SSD的理解就是源于MTCNN中的PNet,实际上SSD可以看成是由6个不同的PNet组合而成。

    这里用原论文中的SSD300的结构与MTCNN作比较
    这里写图片描述

    这里写图片描述

    SSD与MTCNN的不同

    1. 生成训练数据的方式不同
      MTCNN需要事先手动将所有的训练样本生成好,然后输入到网络中训练, 而SSD不需要,SSD在训练过程中自动生成所有训练样本。SSD中实际的训练样本就是所有anchor,每个anchor的label由anchor与ground truth匹配来确定。SSD实现了真正意义上端到端的训练。
    2. MTCNN和SSD采用了两种不同的多尺度检测策略
      MTCNN:首先构建图像金字塔,然后使用固定大小的滑动窗口在金字塔每一级滑动,对每个滑动窗口分类回归。
      SSD: 在原图中设置了不同大小的滑动窗口,对不同大小的滑动窗口进行分类和回归。
      不管是MTCNN,还是SSD,本质上是对所有滑动窗口的分类。这与传统的目标检测方法本质上是一样的。
    3. Mining的方式不同
      MTCNN需要手动做mining,而SSD采用了OHNM训练过程中自动完成负样本的mining,解决了简单样本的问题和类别不平衡问题。
    4. 其实MTCNN中也是有anchor的, MTCNN中的anchor就是PNet的滑动窗口
      MTCNN的训练样本就是滑动窗口图像,而生成训练样本的时候使用滑动窗口与groundtruth进行匹配,得到分类和回归的label,所以anchor就是PNet的滑动窗口。不过与SSD的区别在于这个匹配过程不是训练过程中自动完成的,而是事先手动完成。
      判断什么是anchor的方法:使用什么匹配groundtruth的,那个就是anchor

    SSD与YOLOV3

    YOLOV3和SSD在很多地方都非常相似,连YOLOV3的作者都说了,YOLOV3只是借鉴了其他人的一些思想(So here’s the deal with YOLOv3: We mostly took goodideas from other people.),看完YOLOV3,我甚至都觉得YOLOV3就是抄的SSD。但是不管怎么样,目前工业界用的最多的目标检测算法就是SSD和YOLO。YOLOV3和SSD都使用了anchor技术+多尺度检测+FPN。但是在诸多细节上稍有不同。

    SSD与YOLOV3的不同

    1. 训练数据格式不同:SSD的训练数据坐标顺序为label x1 y1 x2 y2,而YOLOV3为 label x y w h(x,y表示中心点)
    2. 网络结构方面,对坐标偏移和类别预测的结构不同:SSD在每个检测层使用了两个分支分别做分类和回归,但是YOLOV3在每个检测层只使用了一个分支,也就是说只用了一个tensor预测了3部分内容:坐标偏移+目标置信度+分类置信度(通道数为4+1+classNum)。
    3. 坐标偏移量的编码形式不同。
      SSD和FasterRCNN使用了相同的编码方式在这里插入图片描述
      而YOLOV3使用了如下的编码方式
      在这里插入图片描述
      SSD的坐标偏移很好理解,就是ground truth和anchor之间的偏移,但是YOLOV3中的偏移有点不同,YOLOV3的代码中,cx和cy表示的是检测层特征图每个像素点的坐标(实际计算的时候,做了归一化处理),其实也就是anchor的中心点,所以第1,2个公式表示的就是预测框和anchor中心点的偏移,第3,4个公式和SSD的是一样的
    4. 训练中anchor的匹配策略不同。SSD中,如果一个anchor匹配到groundtruth了,就是正样本,否则为负样本,一个groundtruth可以有多个anchor匹配到,但是YOLOV3中,一个groundtruth只能有一个anchor匹配到,这个anchor负责预测这个groundtruth,而且YOLOV3用了双阈值处理,YOLOV3会忽略掉一部分样本。但是我在阅读作者源码的时候发现,源码和论文有点出入,训练的时候,并不是只有最佳匹配的anchor参与训练,只要IOU大于阈值的都会参与训练,但是在YOLOV2中,只有最佳匹配的anchor会参与训练。
    5. SSD使用了单阈值匹配,YOLOV3使用了双阈值匹配。前面也提到了这一点,SSD在区分正负anchor的时候,只用了一个阈值,但是YOLOV3使用了两个阈值。
    6. loss的形式不同。
      如果还有不同点没有列出的,欢迎留言补充。

    SSD和YOLOV3在众多细节上有所不同,但是孰优孰劣,目前还没有定论。只要用的好,这两个算法的性能都是非常不错的,能够熟练掌握其中的一种就够用了。


    与传统目标检测的关系

    基于深度学习的检测算法,不管是SSD,YOLOV3,FasterRCNN还是MTCNN,本质上都是一样的,都是对滑动窗口的分类


    结束语

    博客最初写于2018-08-27, 2019-11-10和2020-6-9分别对原博客做了两次重大修改,随着对SSD一遍又一遍的学习和思考,每一次都能够发现以前有些地方理解还是有点问题的,现在越来越能体会到,为什么经典需要反复阅读反复思考,每次都会有新的理解,每次都能发现不一样的东西。

    最后希望这篇文章能够帮助到你。


    2018-8-27 08:08:36
    Last Updated: 2020-6-9 14:11:48


    参考文献

    [1] [2016 NIPS] Understanding the Effective Receptive Field in Deep Convolutional Neural Networks
    [2] [2016 ISPL] Joint Face Detection and Alignment using Multi-task Cascaded Convolutional Networks
    [3] [2014 NIPS] Deep Learning Face Representation by Joint Identification-Verification


    非常感谢您的阅读,如果您觉得这篇文章对您有帮助,欢迎扫码进行赞赏。
    这里写图片描述

    展开全文
  • SSD目标检测】3:训练自己的数据集

    万次阅读 多人点赞 2018-07-20 14:22:34
    前言:上一章已经详细介绍了SSD——多目标定位检测识别算法,该框架是Google开源的代码,所以自然有很多前辈做改进了。我也不过是站在前辈的肩膀上,这一章就是讲解如何训练自己的数据集,让SSD框架识别。源码也无偿...

    前言:

    上两章已经详细介绍了SSD目标检测(1):图片+视频版物体定位(附源码)SSD目标检测(2):如何制作自己的数据集(详细说明附源码)。由于SSD框架是开源的代码,自然有很多前辈研究后做了改进。我也不过是站在前辈的肩膀上才能完成这篇博客,在这里表示感谢。
    这一章就是讲解如何使用自己的数据集,让SSD框架识别。

    -------------------------------------------------------------------------------------------------------------------------

    申明:

    1. 本博客用的测试数据集在这,只有20张标记图片。并不包含最后训练得到的模型。测试数据集只是测试程序的可行性,数据规模很小,有需要的同学自己下载。
    2. 博主没有物体检测的项目需求,本篇博客只是博主闲暇无聊研究如何用自己的数据集外测SSD,写博客的初衷一是为了记录二也是为后来人填坑——效果好坏受算法结构、受数据集、受训练次数因素影响,留言板处因为你的结果表现不优良而无视博主无偿付出的人,我劝你善良。

    -------------------------------------------------------------------------------------------------------------------------

    行文说明:

    要用SSD训练自己的数据集,首先要知道怎样制作自己的数据集,上一章已经有详细的介绍。有了准备好了的数据集后,再怎样调整代码可以使SSD框架运行得到结果,这一章都有详细介绍。所以行文大致分如下三个部分:

    1. 第一部分:SSD目标检测(2):如何制作自己的数据集(详细说明附源码)
    2. 第二部分:SSD框架细节调整
    3. 第三部分:模型展示

    在本文中,笔者的操作系统是win10,用的IDE是PyCharm,python3.6 + GTX1060 + cuda9 + cudnn7,在此情况下以下的步骤都是运行完好。Linux系统下笔者也成功运行,只是小部分实现的方式不相同,这里不做详细讲解,还望包涵。

    -------------------------------------------------------------------------------------------------------------------------
    -------------------------------------------------------------------------------------------------------------------------

    一、SSD框架细节调整说明

    1、前期准备工作

    第一步:先将SSD框架下载到本地,解压出来;SSD源码下载

    第二步:在解压出来的主目录下依次创建tfrecords_train_modelVOC2007文件夹,再将之前在SSD目标检测(2):如何制作自己的数据集(详细说明附源码)中制作的三个文件夹AnnotationsImageSetsJPEGImages全都拖入VOC2007文件夹内;

    第2.5步:为方便操作不易混淆,请在PyCharm里建立工程;得到的截图如下,截图说明如下:

    1. 请注意红色框VOCxxx使用的是具体的名字,不过一般都是VOC2007
    2. 目录对应的从属关系不要出错
    3. tfrecords_文件夹是用来存储.tfrecords文件(后面有程序可以直接生成)
    4. train_model文件夹是用来存储模型的记录与参数的
      这里写图片描述

    2、生成.tfrecords文件的代码微调说明

    第三步:修改标签项——打开datasets文件夹中pascalvoc_common.py文件,将自己的标签项填入。我之前做的图片标签.xml文件中,就只有一个标签项“watch”,所以要根据你自己数据集实际情况进行修改;
    在这里插入图片描述

    第四步:修改读取个数、读取方式——打开datasets文件夹中的pascalvoc_to_tfrecords.py文件,

    • 修改67行SAMPLES_PER_FILES的个数;
    • 修改83行读取方式为'rb'
    • 如果你的文件不是.jpg格式,也可以修改图片的类型;这里写图片描述

    3、生成.tfrecords文件

    第五步:生成.tfrecords文件——打开tf_convert_data.py文件,依次点击:runEdit Configuration,在Parameters中填入以下内容,再运行tf_convert_data.py文件,在面板中得到成功信息,可以在tfrecords_文件夹下看到生成的.tfrecords文件;

    --dataset_name=pascalvoc
    --dataset_dir=./VOC2007/
    --output_name=voc_2007_train
    --output_dir=./tfrecords_
    

    这里写图片描述

    4、重新训练模型的代码微调说明

    第六步:修改训练数据shape——打开datasets文件夹中的pascalvoc_2007.py文件,

    • 根据自己训练数据修改:NUM_CLASSES = 类别数

    说明:TRAIN_STATISTICS的数值我并没有深入了解,大于新数据集该标签的总数一般都不会报错。我的数据集是由20张、每张包含一只手表的图片组成,所以下图的值我设定为20,大于20也没有报错,如果你有更精确的想法,请留言告诉大家!
    在这里插入图片描述
    第七步:修改类别个数——打开nets文件夹中的ssd_vgg_300.py文件,

    • 根据自己训练类别数修改96 和97行:等于类别数+1这里写图片描述

    第八步:修改类别个数——打开eval_ssd_network.py文件,

    • 修改66行的类别个数:等于类别数+1
      这里写图片描述

    第九步:修改训练步数epoch——打开train_ssd_network.py文件,

    • 修改27行的数据格式,改为'NHWC'
    • 修改135行的类别个数:等于类别数+1
    • 修改154行训练总步数,None会无限训练下去;
    • 说明:60行、63行是关于模型保存的参数;
      这里写图片描述

    5、加载vgg_16,重新训练模型

    第十步:下载vgg_16模型——下载地址请点击,密码:ge3x;下载完成解压后存入checkpoint文件中;
    最后一步:重新训练模型——打开train_ssd_network.py文件,依次点击:runEdit Configuration,在Parameters中填入以下内容,再运行train_ssd_network.py文件

    --train_dir=./train_model/
    --dataset_dir=./tfrecords_/
    --dataset_name=pascalvoc_2007
    --dataset_split_name=train
    --model_name=ssd_300_vgg
    --checkpoint_path=./checkpoints/vgg_16.ckpt
    --checkpoint_model_scope=vgg_16
    --checkpoint_exclude_scopes=ssd_300_vgg/conv6,ssd_300_vgg/conv7,ssd_300_vgg/block8,ssd_300_vgg/block9,ssd_300_vgg/block10,ssd_300_vgg/block11,ssd_300_vgg/block4_box,ssd_300_vgg/block7_box,ssd_300_vgg/block8_box,ssd_300_vgg/block9_box,ssd_300_vgg/block10_box,ssd_300_vgg/block11_box
    --trainable_scopes=ssd_300_vgg/conv6,ssd_300_vgg/conv7,ssd_300_vgg/block8,ssd_300_vgg/block9,ssd_300_vgg/block10,ssd_300_vgg/block11,ssd_300_vgg/block4_box,ssd_300_vgg/block7_box,ssd_300_vgg/block8_box,ssd_300_vgg/block9_box,ssd_300_vgg/block10_box,ssd_300_vgg/block11_box
    --save_summaries_secs=60
    --save_interval_secs=100
    --weight_decay=0.0005
    --optimizer=adam
    --learning_rate=0.001
    --learning_rate_decay_factor=0.94
    --batch_size=4
    --gpu_memory_fraction=0.7
    

    注意:上面是输入参数:

    • --save_interval_secs是训练多少次保存参数的步长;
    • --optimizer是优化器;
    • --learning_rate是学习率;
    • --learning_rate_decay_factor是学习率衰减因子;
    • 如果你的机器比较强大,可以适当增大--batch_size的数值,以及调高GPU的占比--gpu_memory_fraction
    • --model_name:我并没有尝试使用其他的模型做增量训练,如果你有需要,也请留言联系我,我很乐意研究;

    若得到下图日志,即说明模型开始训练:
    在这里插入图片描述
    训练结束可以在train_model文件夹下看到生成的参数文件;
    在这里插入图片描述

    到这里,训练终于结束了!!!

    -------------------------------------------------------------------------------------------------------------------------
    -------------------------------------------------------------------------------------------------------------------------

    二、结果展示

    这是我训练的loss,我的数据集总共就20张图片,进行4.8W次训练用了将近一个小时,我的配置是GTX1060的单显卡;在这里插入图片描述
    1、在日志中,选取最后一次生成模型作为测试模型进行测试;
    2、在demo文件夹下放入测试图片;
    3、最后在notebooks文件夹下建立demo_test.py测试文件,代码如下:
    4、注意第48行,导入的新模型的名称是否正确

    # -*- coding:utf-8 -*-
    # -*- author:zzZ_CMing  CSDN address:https://blog.csdn.net/zzZ_CMing
    # -*- 2018/07/20; 15:19
    # -*- python3.6
    import os
    import math
    import random
    import numpy as np
    import tensorflow as tf
    import cv2
    import matplotlib.pyplot as plt
    import matplotlib.image as mpimg
    from nets import ssd_vgg_300, ssd_common, np_methods
    from preprocessing import ssd_vgg_preprocessing
    from notebooks import visualization
    import sys
    
    sys.path.append('../')
    slim = tf.contrib.slim
    # TensorFlow session: grow memory when needed. TF, DO NOT USE ALL MY GPU MEMORY!!!
    gpu_options = tf.GPUOptions(allow_growth=True)
    config = tf.ConfigProto(log_device_placement=False, gpu_options=gpu_options)
    isess = tf.InteractiveSession(config=config)
    
    
    # 定义数据格式,设置占位符
    net_shape = (300, 300)
    # 输入图像的通道排列形式,'NHWC'表示 [batch_size,height,width,channel]
    data_format = 'NHWC'
    # 预处理,以Tensorflow backend, 将输入图片大小改成 300x300,作为下一步输入
    img_input = tf.placeholder(tf.uint8, shape=(None, None, 3))
    # 数据预处理,将img_input输入的图像resize为300大小,labels_pre,bboxes_pre,bbox_img待解析
    image_pre, labels_pre, bboxes_pre, bbox_img = ssd_vgg_preprocessing.preprocess_for_eval(
        img_input, None, None, net_shape, data_format, resize=ssd_vgg_preprocessing.Resize.WARP_RESIZE)
    # 拓展为4维变量用于输入
    image_4d = tf.expand_dims(image_pre, 0)
    
    # 定义SSD模型
    # 是否复用,目前我们没有在训练所以为None
    reuse = True if 'ssd_net' in locals() else None
    # 调出基于VGG神经网络的SSD模型对象,注意这是一个自定义类对象
    ssd_net = ssd_vgg_300.SSDNet()
    # 得到预测类和预测坐标的Tensor对象,这两个就是神经网络模型的计算流程
    with slim.arg_scope(ssd_net.arg_scope(data_format=data_format)):
        predictions, localisations, _, _ = ssd_net.net(image_4d, is_training=False, reuse=reuse)
    
    # 导入新训练的模型参数
    ckpt_filename = '../train_model/model.ckpt-xxx'   # 注意xxx代表的数字是否和文件夹下的一致
    # ckpt_filename = '../checkpoints/VGG_VOC0712_SSD_300x300_ft_iter_120000.ckpt'
    isess.run(tf.global_variables_initializer())
    saver = tf.train.Saver()
    saver.restore(isess, ckpt_filename)
    
    # 在网络模型结构中,提取搜索网格的位置
    # 根据模型超参数,得到每个特征层(这里用了6个特征层,分别是4,7,8,9,10,11)的anchors_boxes
    ssd_anchors = ssd_net.anchors(net_shape)
    """
    每层的anchors_boxes包含4个arrayList,前两个List分别是该特征层下x,y坐标轴对于原图(300x300)大小的映射
    第三,四个List为anchor_box的长度和宽度,同样是经过归一化映射的,根据每个特征层box数量的不同,这两个List元素
    个数会变化。其中,长宽的值根据超参数anchor_sizes和anchor_ratios制定。
    """
    
    
    # 主流程函数
    def process_image(img, select_threshold=0.6, nms_threshold=.01, net_shape=(300, 300)):
        # select_threshold:box阈值——每个像素的box分类预测数据的得分会与box阈值比较,高于一个box阈值则认为这个box成功框到了一个对象
        # nms_threshold:重合度阈值——同一对象的两个框的重合度高于该阈值,则运行下面去重函数
    
        # 执行SSD模型,得到4维输入变量,分类预测,坐标预测,rbbox_img参数为最大检测范围,本文固定为[0,0,1,1]即全图
        rimg, rpredictions, rlocalisations, rbbox_img = isess.run([image_4d, predictions, localisations, bbox_img],
                                                                  feed_dict={img_input: img})
    
        # ssd_bboxes_select()函数根据每个特征层的分类预测分数,归一化后的映射坐标,
        # ancohor_box的大小,通过设定一个阈值计算得到每个特征层检测到的对象以及其分类和坐标
        rclasses, rscores, rbboxes = np_methods.ssd_bboxes_select(
            rpredictions, rlocalisations, ssd_anchors,
            select_threshold=select_threshold, img_shape=net_shape, num_classes=21, decode=True)
        """
        这个函数做的事情比较多,这里说的细致一些:
        首先是输入,输入的数据为每个特征层(一共6个,见上文)的:
                                                    rpredictions: 分类预测数据,
                                                    rlocalisations: 坐标预测数据,
                                                    ssd_anchors: anchors_box数据
                                                其中:
                                                   分类预测数据为当前特征层中每个像素的每个box的分类预测
                                                   坐标预测数据为当前特征层中每个像素的每个box的坐标预测
                                                   anchors_box数据为当前特征层中每个像素的每个box的修正数据
    
            函数根据坐标预测数据和anchors_box数据,计算得到每个像素的每个box的中心和长宽,这个中心坐标和长宽会根据一个算法进行些许的修正,
        从而得到一个更加准确的box坐标;修正的算法会在后文中详细解释,如果只是为了理解算法流程也可以不必深究这个,因为这个修正算法属于经验算
        法,并没有太多逻辑可循。
            修正完box和中心后,函数会计算每个像素的每个box的分类预测数据的得分,当这个分数高于一个阈值(这里是0.5)则认为这个box成功
        框到了一个对象,然后将这个box的坐标数据,所属分类和分类得分导出,从而得到:
            rclasses:所属分类
            rscores:分类得分
            rbboxes:坐标
            
            最后要注意的是,同一个目标可能会在不同的特征层都被检测到,并且他们的box坐标会有些许不同,这里并没有去掉重复的目标,而是在下文
        中专门用了一个函数来去重
        """
    
        # 检测有没有超出检测边缘
        rbboxes = np_methods.bboxes_clip(rbbox_img, rbboxes)
        rclasses, rscores, rbboxes = np_methods.bboxes_sort(rclasses, rscores, rbboxes, top_k=400)
        # 去重,将重复检测到的目标去掉
        rclasses, rscores, rbboxes = np_methods.bboxes_nms(rclasses, rscores, rbboxes, nms_threshold=nms_threshold)
        # 将box的坐标重新映射到原图上(上文所有的坐标都进行了归一化,所以要逆操作一次)
        rbboxes = np_methods.bboxes_resize(rbbox_img, rbboxes)
        return rclasses, rscores, rbboxes
    
    
    # 测试的文件夹
    path = '../demo/'
    image_names = sorted(os.listdir(path))
    # 文件夹中的第几张图,-1代表最后一张
    img = mpimg.imread(path + image_names[-1])
    rclasses, rscores, rbboxes = process_image(img)
    
    # visualization.bboxes_draw_on_img(img, rclasses, rscores, rbboxes, visualization.colors_plasma)
    visualization.plt_bboxes(img, rclasses, rscores, rbboxes)
    

    结果展示:这是我自己拍的照片,得到的识别效果还算勉强吧(请自动忽略我那性感的手毛!)
    在这里插入图片描述

    如果你的测试结果是下面这样的:

    导致的原因:

    1. 训练次数太少,loss过高——解决方法除了优化数据集外,就是增大训练次数(要明白谷歌公布的模型都是在大型集群上训练好多天的结果,我们就在GTX1060单显卡上训练4.8W次就想出非常好的结果?偶然的成功比失败更可怕,而且想弯道超谷歌不太可能吧!)
    2. 另外上面程序65行的select_thresholdnms_threshold参数你也可以做调整;观察下图可以发现误标框框的预测值都小于0.55,而唯一正确的框框预测值等于0.866。所以认真理解上面程序66、67行我写的注释,对你的问题会有帮助;
      在这里插入图片描述

    -------------------------------------------------------------------------------------------------------------------------
    本博客用的测试数据集在这,只有20张标记图片。并不包含最后训练得到的模型。
    申明:测试数据集只是测试程序的可行性,数据规模很小,有需要的同学自己下载。

    -------------------------------------------------------------------------------------------------------------------------

    如有不明白,欢迎留言咨询!

    展开全文
  • SSD8 SSD8 所有答案 SSD8 SSD8 所有答案 SSD8 SSD8 所有答案 SSD8 SSD8 所有答案 SSD8 SSD8 所有答案 SSD8 SSD8 所有答案
  • ssd9 ex3 ssd9 ex3 ssd9 ex3 ssd9 ex3 ssd9 ex3 ssd9 ex3 ssd9 ex3 ssd9 ex3 ssd9 ex3 ssd9 ex3 ssd9 ex3 ssd9 ex3 ssd9 ex3 ssd9 ex3 ssd9 ex3
  • 本文主要针对SSD的tensorflow框架下的实现的源码解读即对网络模型的理解。 【前言】 首先在github上下载tensorflow版的SSD repository:https://github.com/balancap/SSD-Tensorflow 同时附上论文地址:SSD 论文...
  • SSD-Pytorch训练和测试自己的数据集(新手必看)

    万次阅读 多人点赞 2019-03-24 16:37:26
    2.pytorch环境安装即SSD-pytorch代码下载 3.正常的修改 修改1:config.py 修改2:VOC0712.py 修改3:train.py 修改4:eval.py 修改5:ssd.py 4.遇到的问题和相应的解决办法 问题1: ...
  • SSD9 SSD9 exercise8 SSD9 exercise8SSD9 SSD9 exercise8 SSD9 exercise8SSD9 SSD9 exercise8 SSD9 exercise8SSD9 SSD9 exercise8 SSD9 exercise8SSD9 SSD9 exercise8 SSD9 exercise8SSD9 SSD9 exercise8 SSD9 ...
  • 睿智的目标检测23——Pytorch搭建SSD目标检测平台

    万次阅读 多人点赞 2020-03-20 14:48:05
    睿智的目标检测23——Pytorch搭建SSD目标检测平台学习前言什么是SSD目标检测算法源码下载SSD实现思路一、预测部分1、主干网络介绍2、从特征获取预测结果3、预测结果的解码4、在原图上进行绘制二、训练部分1、真实框...
  • SSD详解

    万次阅读 多人点赞 2018-03-05 21:57:25
    论文题目:SSD: Single Shot MultiBox Detector 论文链接:论文链接 论文代码:Caffe代码点击此处 This results in a significant improvement in speed for high-accuracy detection(59 FPS with mAP 74.3% ...
  • SSD模型详解

    万次阅读 2019-08-23 11:02:04
    ssd论文原文: https://arxiv.org/pdf/1512.02325.pdf 参考代码 https://github.com/PaddlePaddle/models/tree/develop/PaddleCV/ssd https://github.com/amdegroot/ssd.pytorch SSD网络总体描述 网络组成...
  • 本课程手把手讲解Caffe SSD框架代码编译和安装过程,并详细介绍如何基于一个无人零售商品数据集来成功训练出SSD和Mobilenet SSD模型,然后将它们量化且移植到海思开发板上正确运行。 课程主要内容有: 1. caffe SSD...
  • yolo-v3和SSD的一些对比

    万次阅读 多人点赞 2018-05-28 17:12:01
    初步总结的SSD和yolo-v3之间的一些区别。 其中的一些概念还有待充分解释。 SSD YOLOv3 Loss Softmax loss Logistic loss Prediction multiple feature maps + anchor boxes + ...
  • SSD9 exam2 SSD9 exam2 SSD9 exam2 SSD9 exam2SSD9 exam2 SSD9 exam2 SSD9 exam2 SSD9 exam2SSD9 exam2 SSD9 exam2 SSD9 exam2 SSD9 exam2
  • SSD算法详解

    万次阅读 多人点赞 2019-01-21 16:41:34
    SSD github : https://github.com/weiliu89/caffe/tree/ssd SSD paper :https://arxiv.org/abs/1512.02325 SSD 动态PPT:...
  • SSD简介

    2020-03-07 23:59:00
    SSD简介 概念 SSD(Solid State Drive),即固态硬盘,是一种以半导体闪存(NAND FLASH)为介质的存储设备。 SSD组成 SSD主要部件为控制器和存储芯片, SSD硬件包括主控,闪存 ,缓存芯片DRAM(可选),PCB(电源...
  • ssd9 ex6 ssd9 ex6 ssd9 ex6 ssd9 ex6 ssd9 ex6ssd9 ex6 ssd9 ex6 ssd9 ex6 ssd9 ex6 ssd9 ex6ssd9 ex6 ssd9 ex6 ssd9 ex6 ssd9 ex6 ssd9 ex6ssd9 ex6 ssd9 ex6 ssd9 ex6 ssd9 ex6 ssd9 ex6ssd9 ex6 ssd9 ex6 ssd9 ...
  • ssd2020

    2020-04-11 10:17:21
    SSD_RFB https://github.com/JJZHK/SSD_RFB SSD300 SSD512 RFB RFB512 FSSD FSSD512 VGG16 76.3%????mAP???? 78.8%????mAP???? 78.8%????mAP???? 79.8%????mAP???? 78.2%????mAP???? - Resnet50...
  • caffe ssd

    2018-08-08 11:00:02
    https://github.com/weiliu89/caffe/tree/ssd ...examples/ssd/ plot_detections.py score_ssd_coco.py score_ssd_pascal.py ssd_coco.py ssd_detect.cpp ssd_ilsvrc.py ssd_pascal.py ssd_pascal_orig.py ...
  • SSD介绍

    2018-12-18 13:06:29
    SSD概述 SSD这个行业和产品我相信大家并不陌生,发展到今天可以说是格局已定,取代HDD是大势所趋。产品的应用经历了推销质疑到现在全面普及以及替代HDD的时代,剩下的全面取代HDD,只是时间的问题。 SSD的优点 速度...
  • SSD算法的改进版之R-SSD

    万次阅读 热门讨论 2017-08-12 20:57:59
    论文:Enhancement of SSD by concatenating feature maps for object detection 论文链接:https://arxiv.org/abs/1705.09587算法详解: SSD算法在object detection领域的效果有目共睹,是proposal-free方面的...
  • ssd5 exam3 ssd5 exam3 ssd5 exam3 ssd5 exam3 ssd5 exam3 ssd5 exam3ssd5 exam3 ssd5 exam3 ssd5 exam3ssd5 exam3 ssd5 exam3 ssd5 exam3ssd5 exam3 ssd5 exam3 ssd5 exam3
  • SSD 记录

    2019-05-06 16:39:36
    这篇博客总结的挺好:SSD原理解读-从入门到精通 1. 对为什么设置 default box 进行了阐述 2. SSD 的本质 下面一篇博客,对文章的每一节进行了翻译及解读:论文阅读:SSD: Single Shot MultiBox ...
  • SSD目标检测】2:如何制作自己的数据集

    万次阅读 多人点赞 2018-07-20 14:04:07
    想制作自己的数据集当然要先了解SSD使用的数据集VOC2007长啥样。VOC2007下载链接 ,密码是:m5io(VOC2007完整下载有3个压缩包+1个PDF,上面链接里只包含其中一个压缩包VOCtrainval_06-Nov-2007)。打开压缩包就如下...
  • 最近能在网上看到很多关于M1 Mac的SSD存在大量读写的状况,很多伙伴都担心自己的SSD寿命会因此快速损耗。一下将介绍如何查看SSD的状态。 smartctl 安装 首先,我们想要查看SSD的状况,需要使用一个smartctl的工具。...
  • SSD2825 & SSD2828 用户手册和驱动代码

    热门讨论 2015-05-12 10:41:26
    SSD2825 和 SSD2828 用户手册和驱动代码(C语言)。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 37,655
精华内容 15,062
关键字:

ssd