所有文章
YOLOv2的Anchor锚框机制详解
本文总结了YOLOv2模型基于Faster R-CNN的理论,在其模型网格预测框设计上增加的Anchor机制的来源、在YOLOv2模型中的计算和训练流程,尝试更清楚的认识YOLOv2模型的工作原理。 Anchor锚框的概念 首先给出Anchor框的定义:所谓的Anchor就是在每一个图像分割网格中,在训练之前提前固定放置一些尺寸大小和长宽比例不同的边界框,通常情况下,对于每一个网格而言,提前放置的边界框的大小和数量都是相同的。在推理的时候,模型基于输入图像中待检物体的情况,对每一个提前放置的边界框预测出若干的偏移量(中心位置的偏移量,宽高的偏移量等),然后基于这些偏移量调整之前放置的边界框,得出最终的预测边界框。因此,在每个网格处提前放置的边界框就是anchor框,其本质就是提供边界框的尺寸预计,然后用模型在推理过程中计算出来的偏移量来调整其位置和尺寸,从而得到最终的边界框尺寸。 从下图中可以直接的看出所谓的Anchor框究竟是什么:下图中把整幅图像分成与YOLOv1一样的7x7网格,然后在每个网格上提前放置了三个大小和比例不同的anchor框。为了方便演示,下图中仅对每六个网格放一组anchor框,实际中应该是每个网格都有一组anchor框,全画出来密密麻麻,演示反而不够直观。 !image.png 从Anchor框这个概念来讲,YOLOv1版本并没有提前放置anchor框的设计,而只是为每个网格定义了两个BOX,这两个BOX的中心位置和尺寸大小都是需要模型在基于输入图像推理的过程在预测出来的。所以从这个角度上讲,YOLOv1就是典型的Anchor-free(不依赖于Anchor)的模型。 每个网格提前预设Anchor框的设计,首先来源于另外一种目标检测模型:Faster R-CNN。 Faster R-CNN是一个两阶段的目标检测模型,在第一个阶段定位物体,第二个阶段识别物体的类别。其对物体定位检测的思路与YOLOv1是类似的,也是把输入图像分为多个网格,然后逐网格找物体,只不过Faster R-CNN的第一阶段只查找哪个网格中有物体,不关注该物体的类别,在第二个阶段再去识别检测到的物体的具体类别,而YOLOv1则是同时定位物体和识别物体的类别。这就是Faster R-CNN与YOLO各版本的目标查找和预测流程的最大差异所在。 对于Faster R-CNN模型而言,首先会把输入分割为多个网格,然后为每个网格预置 k 个不同尺寸和不同宽高比的ancher框(如上图所示)。在YOLOv2版本中,也把这个预置Anchor框的机制导入了进来,显著的提升了模型的mAP指标。增加Anchor框以后,在推理阶段,模型就不需要从头直接预测待检物体的尺寸与坐标,而只需要预测Anchor框到真实物体的偏移量即可,这样就降低了预测的难度。 YOLOv2锚框的k均值聚类算法 但问题是,如果确定每个网格应该放几个Anchor框,以及各个Anchor框的大小和长宽比又如何确定呢? 对于Faster R-CNN模型而言,其Anchor框的数量、尺寸等参数都是作为超参数由人工设定的。这种设计很难确保人工指定的Anchor框的参数与数据集之间是相互匹配的,所以对于不同数据集的输入,其网络性能的表现很难稳定。 对于以上问题,YOLOv2模型的做法,是采用 k 均值聚类算法,从指定的数据集中提取出来最适合的Anchor框。 首先把整个训练集中图片的所有真值标记框(GT,Ground Truth)全部提取出来,然后缩放到统一的输入尺寸(416x416):该算法只关心真值框的width和height信息,也就是长宽比。 !image.png 传统的K-means聚类算法在进行聚类计算的过程中使用的是欧氏距离,但是这样也就意味着较大尺寸的Anchor框相比较小尺寸会产生更多的错误,聚类计算的结果也就会发生偏离。而YOLOv2聚类计算的目的,是让预先选定的Anchor框的尺寸与其接近的真值框有更大的IoU,与Anchor框和真值框的尺寸大小无关。因此YOLOv2模型定义了以下距离公式执行聚类算法: !image.png 从以上统计出来的所有真值框列表中随机挑选出来5个做为初始Anchor框,执行以下所描述的k均值聚类算法: - 基于以上所描述的聚类算法,计算数据集中所有真值框与5个Anchor框之间的dist值,每个真值框与哪个Anchor框之间的dist值最大,就把这个真值框与该Anchor框归为一类。直到所有的真值框按照以上逻辑计算完毕,被分为以Anchor框为标准的5个集合。 - 对每个集合中所包含的真值框列表进行以下计算: - 取出所有真值框的width(之前已经统一缩放真值框的分辨率为416x416),计算出来所有width的几何平均值,把该组合Anchor框的width替换为计算出来的这个几何平均值。 - 同样的,取出所有真值框的height,计算出来所有height的几何平均值,把该组合Anchor框的height替换为计算出来的这个几何平均值。 - 经过以上运算以后,就得到5个新的Anchor框的(width,height)。 - 然后基于这5个新的Anchor框重新从头执行这个聚类算法,得到新的Anchor框的(width,height)。经过以上的反复迭代计算,最终新Anchor框的width和height基本不再变化,这就是最终由算法自动基于数据集所自动生成的Anchor框。 以上的整个k均值聚类算法的执行流程可以简化为下图所示: !image.png 基于以上逻辑和流程计算出来5个Anchor框的长宽参数以后,就可以按照其面积大小为顺序,写入YOLOv2模型的cfg文件中,后续在模型的训练和推理过程中,每个网格都会放置5组以上长宽比例的Anchor框用于对图像的中物体进行检测。 > 不过从以上计算逻辑也可以看出来这个算法存在的严重局限性:通过以上算法选出来的Anchor框是基于指定的数据集的,那么也就只能在这个数据集上有良好的表现。如果新的数据集的待检对象尺寸等与训练数据集存在较大差异化的,初选的anchor框就不合适了。 基于Anchor的Bounding Box预测 经过如上所述的Anchor框的聚类计算以后,在模型开始正式训练之前,就得到了5组长宽比确定下来的Anchor框。在训练过程中有了这个Anchor边界框的先验尺寸信息,网络就不必再从头去学习整个目标框的宽高了。 假设预定义Anchor框的尺寸为 p_w 和 p_h , 待检物体中心所在网格的左上角坐标位置为 grid_x,grid_y ,网络推理输出的中心偏移量是 (t_x,t_y) ,网络输出宽高的偏移量是 (t_w,t_h) 。那么YOLOv2模型使用以下公式计算待检物体的中心坐标和边界框: !image.png YOLOv2模型预测输出的中心偏移量 (t_x,t_y) ,是其相对所在网格左上角位置的相对偏移量。而且在计算实际中心位置时,还会使用Sigmoid函数限制叠加到 grid_x,grid_y 之上的偏移量在0-1之间,这样就可以使得预测出来的bounding box的中心点保持在该网格内部,不会偏移很多超出到网格之外。 可基于下图来理解上面的公式:虚线框为Anchor框,蓝色框为模型预测输出计算出来的Bounding box。 !image.png 参考资料 - 《YOLO目标检测》杨建华,李瑞峰 第6章 YOLOv2 - 《深度学习之Pytorch物体检测实战》 董洪义 6.2 依赖锚框:YOLOv2 - YOLOv2 詳細解讀. YOLOv2 是在 YOLOv1 的基礎上使用了上圖紅色框框裡的方法改進,在… | by Steven Meng | Medium
YOLOv1模型的损失函数与训练过程解读
本文对YOLOv1模型的训练正样本标记方法、损失函数以及基于训练样本对模型进行训练的完整过程进行了总结,为理解YOLO后续版本的处理流程打好基础。 YOLOv1训练正样本的标记 如YOLOv1输出信息以及NMS过滤算法详细解读一文所总结的,YOLOv1对于图像中物体的检测逻辑是,如果一个物体的中心点落在某个网格内,就由这个网格负责检测该物体,这样也就意味着,在制作YOLOv1训练样本的时候,只有包含待检物体中心点的网格被认为是有物体的。 以下图进行解释: !image.png 尽管图中的小猫这个物体的标记检测框占据的多达24个网格,但是因为这个标记框的中心位置落在粉色网格中,所以,对于YOLOv1模型在制作这个图像的训练样本时,只有粉色网格会被标记为有物体,该网格的检测置信度接近1;其他网格均为无物体,网格的检测置信度接近0。 > 有物体的网格会被标记为正样本候选区域,也就是说,在训练过程中,训练的正样本(positive sample)只会从此网格处的预测中得到,而其他区域的预测都是该目标的负样本。 YOLOv1的损失函数解读 从总体上看,YOLOv1的损失函数的计算主要包含三个部分: - 坐标损失(x,y,w,h):评估模型输出的检测框与训练样本标记框的贴合程度。 - 置信度损失(confidence):衡量模型输出的每个预测框的confidence值与该框中是否真正包含待检目标之间的吻合程度。 - 类别判断损失(class):判断模型输出的类别判断是否与训练样本的标记分类一致。 下图是损失函数计算过程中用到的各个参数的含义: !image.png 下图是YOLOv1损失函数的计算公式: !image.png YOLOv1损失函数的前两行表示预测边界框坐标位置参数的损失,第三和第四行表示正样本和负样本边界框置信度的损失,最后一行则是正样本处的类别损失。 以上损失函数的计算逻辑看上去很复杂,但是实际的计算逻辑还是比较直观的,以下分为3个部分分别详细解释。 坐标损失 坐标损失的计算,关键是要理解 的含义: - 对于训练样本的每一个标记框(也就是所谓的ground truth),先找到这个标记框中心所在的网格。然后计算这个网格输出的两个预测框与该标记框的IOU,把IOU值较大的那个预测框的 值设置为1,另外一个预测框的 值为0。 - 在这种情况下,实际上对于训练样本的每一个标记框,实际上都只会找到一个值为1的预测框。 以上逻辑就是找到训练样本每一个标记框所对应的负责预测框。然后就是按照对应的公式,分别计算标记框和负责预测框中心坐标以及长宽的损失值,两个损失值的和就是总的坐标损失值。 从以上的损失函数的计算公式可以看到,坐标损失值还需要乘以 的系数,这是为了加大预测框定位精度损失在整个损失值中的权重,优先更精确的对预测框定位。 置信度损失 置信度损失的计算包含两个部分:负责预测框的损失,不负责预测框的损失。 负责预测框的损失:对于训练样本的每一个标记框(ground truth),仍然是按照与以上计算坐标损失相同的步骤,找到这个标记框对应的负责预测框。每个标记框只会有一个负责预测框,然后计算标记框与负责预测框的置信度损失,此时标记框的置信度为1,负责预测框的置信度则是模型对这个预测框的置信度输出值。 不负责预测框的损失:不负责预测框的逻辑很简单。模型输出的98的预测框,除了上面的负责预测框以外,其他的97个框都是不负责预测框。 按照以上公式分别计算负责预测框的损失值和不负责预测框的损失值,然后把不负责预测框的损失值乘以0.5以压制背景框对真实预测框损失值的影响,两者相加就是整个置信度的损失值。 类别损失 类别损失的计算,仍然是仅对负责预测框进行类别损失的计算,其他预测框的类别损失值均为0。 对于每一个负责预测框,计算这个预测框的20种类别识别概率与训练样本标记框(ground truth)类别的损失。值得注意的是,训练样本标记框的类别是以one-hot形式提供的20维标签(只有一个类别为1,其他全部为0),所以类别损失就是每个负责预测框对应的20个类别的识别概率,与标记框one-hot类别的20维概率标签之差的平方差。 参考资料 - 《YOLO目标检测》杨建华,李瑞峰 第三章 YOLOv1 - YOLO演進 — 1. 在上篇文章有提到過 YOLO 的作法以及如何訓練,在這篇再更詳細的說明YOLO… | by 李謦伊 | 謦伊的閱讀筆記 | Medium
YOLOv1输出信息以及NMS过滤算法详细解读
对于YOLOv1模型的网络架构,在[[YOLOv1模型网络架构解读]]一文中已经有非常详尽的解释。以下是YOLOv1网络的架构图: !image.png 从以上架构图上可以看到,相比于对图像类别进行识别的各种经典卷积神经网络模型而言,YOLOv1的网络结构并没有特别大的创新点,仍然是在网络的前半段通过反复的卷积+池化操作提取图像中的特征,在网络的后半段通过连续两个全连接层进行类别识别和位置判断。但相比其他网络,YOLOv1架构在设计上的精髓在于其最后的7x7x30的输出解读、对模型参数的训练及其损失函数的评估设计方面。 YOLOv1模型的输出信息 YOLOv1的输出是一个7x7x30的三维张量,可以认为该模型把输入的448x448分辨率切分为7x7的网格,从每个网络中搜索待识别对象的中心点及其Bounding Box、置信度、对象类别等信息,每个网络通过一个30个元素的向量来表征该网格中检测到的这些信息。 如下图所示,每个网格会输出两个Bounding BOX的信息,每个BOX的信息包含检测物体中心点坐标(相对于该网格左上角)以及该检测物体的长宽(相对于整幅图即448x448的长宽比例),这个检测框的置信度信息。 !image.png 需要注意,YOLOv1对于图像中物体的检测逻辑是,如果一个物体的中心点落在某个网格内,就由这个网格负责检测和输出该物体对应的Bounding Box等信息。因此,每个网格输出BOX信息中,x和y表示这个待检物体的中心点相对于当前网格左上角的位置,而w和h则表示这个网格预测Bounding Box的相对于整个输入图像分辨率的长和宽。 每个BOX都有一个置信度Confidence的参数,这个参数用于表征当前BOX中真正包含待检物体的概率,如果这个BOX中包含有某个待检物体的中心点的话,这个置信度参数会比较高,达到接近1的程度;而如果这个BOX中不包含任何待检物体的中心点,那么其置信度会接近0,这样就会在后面的过滤算法中被过滤掉。 20 Classes则用于表示各个待检物体类别的最终识别概率。对于VOC数据集而言,可以支持对20种类别的检测识别,如果是COCO数据集的话,各个网格输出的类别数量就需要修改为80个种类的识别概率了。 两个BOX,一组类别识别概率? 从以上所总结的YOLOv1模型各个网格的输出信息可以看到,每个网格的输出包含了两个预测BOX的信息,以及一组识别待检物体的识别概率。那么如果一个网格中刚好包含了两个待检物体的中心,那这组类别识别概率究竟表示的是哪一个物体的识别类别呢? 答案是:这种情况下肯定会漏检,这也是YOLOv1在密集小目标场景下召回率骤降的根本原因所在,也是后续版本(YOLOv2起)引入anchor、把“负责检测单元”从网格细化到“网格+anchor”甚至“pixel”级别的动机。 基于下图来理解这个事情: !image.png 对于每个网格所输出的两个BOX而言,这个网格在输出时只会把两个BOX与实际待检物体吻合度(实际上就是IOU指标)最好的那个框标记为正样本。对于上图而言,实际物体的Bounding Box是上图中的浅灰色框,那么预测框A的吻合度远好于预测框B。那么,这个网格的输出中,预测框A的置信度就会比较高,预测框B的置信度会被压得比较低,而这个网络中所包含的类别信息对应的也就是预测框A所圈选的部分图像的类别识别概率。 因此,YOLOv1整个输入图像被划分为7x7个网格,每个网格输出两个BOX,看起来YOLOv1最多可以实现对7x7x2=98个物体的检测,但实际上,每个网格最多只能输出一个BOX及其对应的识别类别,所以整个图像最多也就只能识别49个独立物体。即:每个网格输出的两个BOX不是为了确保在一个网格中检测出来两个物体,而是为了在一个网格中检测出来物体以后,通过两个BOX提供二选一的选项,让模型能够选择匹配性最好的框来定位其位置。 NMS NMS:Non Maximal Suppression,非极大值抑制算法,顾名思义就是抑制不是极大值的边框,这里的抑制通常是过滤掉针对同一个检测物体的冗余边框。 如上所述,对于每一个输入YOLOv1模型进行推理和检测的图片而言,模型会通过7x7x30这个三维张量输出7x7x2=98个预测框。这98个预测框还需要经过NMS算法的过滤才真正输出最终的检测结果,否则一个物体可能会包含多个输出检测框。 NMS算法的基本执行逻辑:利用得分高的边框抑制得分低且重叠程度高的边框。 NMS算法的执行,按照其所支持的类别分类独立进行处理,每进行一次NMS运算,得到一个类别的最终检测框。但不同类别的计算逻辑是完全相同的,最终把所有类别的最终检测框汇总在一起就是模型最终的检测结果。 步骤0: 首先针对某个指定的类别,通过BOX的置信度confidence和这个类别的识别概率相乘得到这个BOX针对这个类别的分数score。因为模型输出98个BOX,所以每个类别也就有98个score。 步骤1:对这个类别的98个score与NMS的检测阈值(例如0.2)进行比较,小于这个阈值的BOX删除掉,只保留大于阈值的BOX放入备选列表。 步骤2:对备选列表中所有BOX基于score的大小降序排序,把备选列表中score最大的那个BOX直接放入该类别的检测输出中。 步骤3:计算备选列表中score值最大的BOX,与备选列表中所有其他BOX计算IOU指标,当计算出来的IOU值>IOU阈值(一般为0.5)时,表示两个BOX检测的是同一个目标,此时把score较小的那个BOX从备选列表中删除。 步骤4:从当前备选列表中把score最大值的BOX删除掉。 反复执行以上的步骤2-步骤4,直到备选列表的BOX为空。此时就得到了这个类别的检测输出结果,然后对所有的20个类别全部执行完成以上步骤,把所有类别的检测输出结果汇总,就是模型最终的检测输出。 !image.png 如上图是针对小狗这个类别的NMS算法过滤流程。 - 首先针对小狗这个类别,通过每个BOX的置信度及其所属网格中小狗这个类别的识别概率相乘,得到98个分数score。 - 对这98个score与阈值0.2进行比较,删掉阈值小于0.2的BOX,把其他的BOX放入备选列表中。 - 对备选列表中的BOX基于score进行降序排序,score最大的BOX直接放入小狗这个类别的检测输出中,同时执行以上描述的NMS算法,每次都是把score最大的BOX放入该类别的输出列表,并通过IOU去掉与该BOX重合度较大的其他BOX(避免一个检测物体出现多个检测框),直到整个备选列表中的BOX全部清空。 参考资料 - 《深度学习之Pytorch物体检测实战》6.1 无锚框预测YOLOv1 - All of the start: YOLOv1. YOLO: you only look once. | by John Shen | Medium - YOLOv1 詳細解讀. 設計概念: | by Steven Meng | Medium
YOLOv2模型网络架构解读
本文对YOLOv2模型的BN层、Darknet-19主干网络,以及模型的总体结构进行了详细的总结和学习。 批归一化BN层的引入 在YOLOv1模型的主干网络所使用的卷积结构,仍然采用的是传统的线性卷积+非线性激活函数的模式,并没有用到在后来十分流行的各种归一化层的设计。因为批归一化层(Batch Normalization,BN)在越来越多的模型中应用,其工作性能得到了业界的广泛认可,因此逐步成为卷积神经网络的标配设计。YOLOv2模型的架构设计中也就顺势引进了被广泛验证的BN层。 具体来讲,就是在网络架构的卷积结构由之前的线性卷积+非线性激活函数的模式,变成了线性卷积层+BN层+非线性激活函数的形式。这种结构也称之为CBL(Conv-BN-LeakyReLU)结构。 !image.png Darknet-19主干网络 如[[YOLOv1模型网络架构解读]]所介绍的,YOLOv1模型的主干网络采用了类似GoogLeNet的设计。到了YOLOv2版本,作者设计了一个新的名为DarkNet-19的网络结构取代了前一代的主干网络。 Darknet-19网络包含有19个卷积层,而且每个卷积层都是以上所描述的CBL结构,即卷积层+BN层+激活函数的形式。下图为Darknet-19网络架构各层的配置参数: - 下表Output对应的特征图维度,对应的是输入分辨率为224x224的图片。当Darknet-19作为YOLOv2的主干网络使用时(输入图像分辨率416x416),其各层输出的特征图维度要对应发生变化。 !image.png > 以上的架构图中,darknet-19网络可以分为两个部分,前半部分是特征提取部分,预训练完成后会被作为YOLOv2的主干网络;最后的卷积层+全局平均池化层+Softmax部分是分类部分,在YOLOv2模型中会被去掉。 可以看到,以上的darknet-19网络架构中,共包含了19个卷积层(3x3卷积和1x1卷积),5个2x2最大池化层,最后借鉴了NiN网络(参考[[CNN经典网络模型架构学习之NiN]])的做法,使用全局平均池化层代替全连接层,在最后一层使用Softmax输出1000个分类的预测结果。 Darknet-19的作者团队用ImageNet数据集去训练网络参数,最终的检测精度上,DarkNet-19网络达到了VGG网络相同的水平,但模型更小(参数量只有25.5M),浮点运算量更是只有其1/5左右,因此运算速度极快。 Darknet-19网络在ImageNet数据集上预训练完毕后,去掉其中用于分类任务的最后一层卷积、平均池化层和Softmax层等,然后将其用作YOLOv2的新主干网络。 Passthrough与Reorg 在主干网络的设计上,除了设计了一个新的darknet-19主干网络以外,YOLOv2还借鉴了SSD模型使用更高分辨率特征图的设计。 > 通常,不同的特征图的分辨率不同,越是浅层的特征图,越被较少地做降采样处理,因而分辨率就越高,所划分的网格就越精细,这显然有助于去提取更多的细节信息。 对于YOLOv2的主干网络设计而言,除了主干网络darknet-19特征提取部分最后一个卷积层(第19个卷积层,如下图红色箭头所示)输出的低分辨率特征图以外,YOLOv2还从darknet-19网络的第13个卷积层输出(如下图绿色箭头所指)高分辨率特征图,然后把两个特征图合并在一起作为整个主干网络的特征提取输出。在这种情况下,主干网络的特征输出中网络尾段低分辨率的特征和网络中段高分辨率的特征,提取出来的信息更加完整。这就是YOLOv2模型的所谓Passthrough架构。 !image.png 在输入图像分辨率为416x416的情况下,主干网络中段输出的高分辨率特征图的维度是26x26x512,而其末端输出的低分辨率特征图的维度是13x13x1024。不同分辨率的特征图要如何才能合并在一起输出呢?答案是Reorg操作。 Darknet-19末端的低分辨率特征图维度为13x13x1024,再经过一个3x3,stride=1的CBL卷积块处理,仍然是13x13x1024维度。 而Darknet-19中段的高分辨率特征图维度为26x26x512,则要执行一个reorg的操作,总体数据量不变,但是分辨率会减半,通道数增加为原来的四倍。对于单通道特征图的Reorg操作(相当于只是把数据重排一下而已)如下图所示,一个通道变成了4个通道。通过这样的操作,中段高分辨率的维度就变成了13x13x2048。 !image.png 经过以上的各自处理后,末端和中段的特征图的空间分辨率都变成了13x13,现在就只需要把所有的特征图合并在一起就可以了。因此经过以上合并后,输出的特征图的通道数就是1024+2048=3072通道,整体的特征图数据维度就是13x13x3072。 YOLOv2模型的总体架构 YOLOv2模型的总体网络架构如下图所示: !image.png > 需要注意的是,上面的总体网络架构图与Passthrough部分所提供的网络架构图,在主干网络经过merge以后输出的通道数有分歧。上图中中段高分辨率特征图在Passthrough的处理过程中会通过一个卷积CBL块先降低到64通道,再reorg为13x13x256维度,因此Merge后输出的总的特征数据维度就是13x13x1280;而前一节的网络结构图中,Passthrough的处理过程中对高分辨率特征数据不做降通道操作,直接reorg为13x13x2048维度,这样Merge后的总的特征输出数据的维度就是13x13x3072。不过Merge后输出无论是1280通道还是3072通道,后续都会通过一个CBL卷积块把通道数降低为1024。真正用于最终预测的特征数据维度都是13x13x1024。 输入图像的分辨率为RGB 3通道416x416分辨率的图像,经过其主干网络darknet-19处理并合并其末端和中段特征提取数据后,最终输出的特征图为13x13x1024维度。然后再基于这个13x13x1024维度的特征数据进行图像中待检物体类别和位置的预测。 最后的这个预测过程就比较简单了:就是对13x13x1024的特征提取数据执行1x1卷积操作。最终的输出数据维度根据待检物体的类别数量来确定。YOLOv2的每个网格中包含有5个预测BOX(在YOLOv2的术语也称为anchor),每个BOX所包含的数据有:中心坐标x和y,长宽度w和h,置信度confidence,各个类别的概率(依据待识别物体的类别种类数量而定)。 - 对于COCO数据集而言,可以支持80个类别的检测。那么每个anchor的数据量是85,每个网格包含5个anchor,因此每个网格的数据量就是425,针对COCO数据集而言模型输出推理结果的数据维度就是13x13x425。 - 而对于VOC数据集而言,支持20种类别,每个网格的数据量是125,针对COCO数据集而言模型输出推理结果的数据维度就是13x13x125。 从以上的YOLOv2的总体架构图可以看出,所有的网络层都是卷积网络,YOLOv1的全连接层被彻底拿掉了,所以YOLOv2也就成了全卷积网络。 参考资料 - 《YOLO目标检测》杨建华,李瑞峰 第6章 YOLOv2 - DAY28 深度學習-卷積神經網路-Yolo v2 (二) - iT 邦幫忙::一起幫忙解決難題,拯救 IT 人的一天
YOLOv1模型网络架构解读
YOLOv1的架构总结 YOLOv1的架构设计逻辑是:仅使用一个完整的卷积神经网络结构来端到端地检测图像中所包含的目标及其位置,对应于当时在目标检测领域主流的R-CNN系列为代表的two-stage流派,YOLOv1的架构可以说是开启了one-state来实现目标位置检测+类别识别的架构设计思路的先河。 YOLOv1的网络架构参考了GoogLeNet网络来设计主干网络,但并未采用GoogLeNet的Inception模块,而采用了串联的1x1卷积和3x3卷积层所组成的模块,因此其主干网络的架构非常简单。 YOLOv1网络的架构图如下所示: !image.png 从以上YOLOv1的架构图可以看到,YOLOv1模型包含有24个卷积层用于提取输入图像的特征信息,以及两个全连接层用于预测图像中所包含的目标位置、置信度以及类别识别几率信息。卷积层部分,采用了多个1x1卷积层用于压缩特征图的通道数量。而激活函数方面,除了最后一层采用线性激活以外,其他各层均采用了Leaky ReLU。 整个网络架构与各种经典的基于卷积神经网络的图像识别模型没有太大差异,其差异主要在图像的分类和输出部分。最后一个卷积层输出的特征图是1024通道7x7分辨率。这个特征图展平(flatten)为7x7x1024的一维向量,经过连续的两个全连接层(分别包含4096个和1470个神经元)进行处理,最后的1470个神经元的全连接层输出最终的预测。因为YOLOv1执行的目标检测任务是一个空间任务,所以这个全连接层的1470个输出数据转换为7x7x30的三维张量,其中7x7是这个三维张量的空间分辨率,30则是这个张量的通道数量。 后续部分对这个7x7x30所代表的目标检测信息详细解释。 因为在图像在进行目标位置及其类别的检测和识别需要更细粒度的视觉信息,所以YOLOv1的图像输入分辨率从各种图像识别模型标准输入的224x224分辨率,提升为448x448。 YOLOv1的参数量 YOLOv1模型存在的一个明显的问题就是参数量实在是太大了。 仅计算最后一个卷积层的输出(维度为7x7x1024),与第一个全连接层(4096个神经元)之间的连接,其参数量就达到了:7x7x1024x4096,大概2亿个参数。这样势必导致模型的推理速度很慢,以及模型运行需要的内存空间也会比较大。 不过这也是没办法的事情,毕竟在YOLOv1模型所推出的2015年,卷积神经网络架构的标准设计就是卷积层与全连接层相连,各自分工,那么全连接层参数众多的问题就很难避免,直到全局平均池化层的出现,才解决了这个问题。 YOLOv1的执行流程 YOLOv1对进行推理的图片所进行的目标检测流程主要可以分为输入图像的预处理、基于卷积神经网络提取特征、基于全连接层进行目标及其位置检测、最终输出检测结果这几个步骤。 !image.png 输入图像的预处理环节主要包含两个方面。首先如上所述,YOLOv1的输入图片的分辨率为448x448的RGB图像,所以对于不同分辨率的图像,首先要缩放到这个尺寸。同时为了避免输入图像的长宽比失真,对于长宽比非1:1的输入图像,还需要通过填充等步骤来进行处理。经过以上分辨率缩放等环节的处理后,再执行像素归一化,把输入图像中各个像素的值从[0,255]缩放到[0,1]区间,或进一步标准化为均值为0、方差为1的分布。 接下来经过以上预处理以后的RGB三通道448x448分辨率的图像,经过连续24个卷积层(包含对应的池化层)处理,逐步提取其中所包含的特征,输出7x7x1024的特征图。这个7x7x1024的特征图展平之后,再经过两个全连接层基于特征数据进行目标种类和位置检测,检测结果resize为7x7x30的三维张量,对这个输出的三维张量进行解析就可以得到图像中所包含的目标种类及其位置。 _整个执行流程的关键,实际上就在于卷积层输出的7x7x1024特征图中所包含的信息,与整个模型最终输出的7x7x30三维张量的映射_。 从以上的这一点上,可以把整个流程看成是对输入的448x448分辨率的图像切分为7x7的网格,无论是卷积层输出的7x7x1024的特征图,还是最终输出的7x7x30的三维张量,其中的1024和30对应的都是每一个网格的特征信息和检测结果:对于每一网格而言,经过24个卷积层的处理,得到一个长度为1024的特征向量,这个特征向量中包含了该网格中的某种高级特征信息。然后在全连接层中再通过遍历这些网格、处理其中的特征信息来预测每个网格处是否有目标的中心点坐标,以及相应的目标类别,把结果输出为一个长度为30的向量,用以表征该网格的检测信息。 !image.png 因此,从以上流程可以看到,图像的输入以及卷积层的检测,与之前的图像识别模型如VGG、GoogLeNet等并无区别,YOLOv1的最大差异在于全连接层的处理结果,需要resize为一个三维张量进行输出。这个三维张量中所包含的数据,就对应了从输入图像中检测到的目标种类和位置。 YOLOv1的输出信息解读 如上所述,YOLOv1的输出为一个7x7x30的三维张量,对应为7x7个网格,那么每个网格所包含的输出信息就是一个长度为30的一维向量。这个一维向量包含以下信息:两个目标检测边界框BOX1和BOX2的参数,以及20个目标检测种类的识别概率。 每个BOX的参数包含其中心坐标(x,y)和长宽参数(w,h),以及这个BOX检测的置信度confidence,因此每个BOX有5个参数。两个BOX的5个参数,再加上20个目标检测类别的识别概率,总共加起来就是长度为30的一维向量。如下图所示。 > 为什么是20个种类?这是因为YOLOv1的原论文是使用VOC数据集进行训练的。VOC数据集总共支持对20个种类的目标进行检测,所以默认YOLOv1模型的输出就是20个类别的识别率。如果使用支持80个类别的COCO数据集,那么每个网格的输出长度就应该是2x5+80=90。 !image.png 如何检测? YOLOv1在“谁来负责进行目标预测”的这个问题上有一个最核心的设计:待检物体的中心点落在哪个网格cell里,就由那个cell负责把这个物体找出来。 这一点,对于理解YOLOv1的输出而言非常关键。 以下图为例,尽管小猫这个物体在整个图像中占据的范围跨越了多个网格,但其中心点在粉色网格中,那么YOLOv1模型的输出中,就只有粉色网格所输出的BOX包含有小猫这个待检物体的相关检测信息,其他网格就都成为背景框。 !image.png BOX的坐标位置参数 如上所述,每个网格中包含有两个BOX的检测结果,其中的每个BOX用x,y,w,h来表示其在网格中的位置。仍然使用上面的小猫图对x,y,w,h参数进行解释。 粉色网格输出的其中一个BOX会对应对小猫的检测框信息,其中(x,y)表示这个预测BOX的中心相对于其所在网格左上角的偏移量。以上图的小猫为例说明,粉色框中的红点为小猫的中心点,那么小猫这个检测框(大的红框)所应对的(x,y)就是红点相对于粉色框左上角的偏移量。w和h则表示这个预测BOX(大的红框)的width和height在整幅图像(448x448分辨率)中的长和宽上所占的比例。 BOX的置信度Confidence如何理解? BOX边界框的置信度参数Confidence,本质上就是用来判断这个BOX中是否包含有某个待检物体的中心点。理想情况下,依据YOLOv1的设定,包含有待检物体中心点的网格所输出的边界框置信度很高,而不包含中心点的网格则输出的边界框置信度很低甚至为0。 > BOX的置信度直接决定一个网格中是否包含有某个待检目标的中心点。 在后期处理中,通过判断Confidence这个参数,就可以知道当前网格中是否包含有某个待检物体的中心点,在确认该网格包含有待检物体的中心点的情况下,再检查20个目标检测类别的识别概率,判断这个待检物体的类别。 如果同一个网格中包含了两个物体的中心点? 按照YOLOv1的设计,每个网格的输出信息只能把两个预测框里最好的那一个标记成“正样本”,并且只能给它分配 1 个类别标签。 因此,当两个不同物体的中心不幸落在同一个网格里时,YOLOv1网络只能: - 选其中一个物体(通常是与默认框 IoU 更大的那个)当作该网格的回归/分类目标; - 另一个物体会直接被当成不存在,训练时既无坐标损失也无类别损失; - 在推理阶段,这个网格最多只能输出第一个物体的检测框,第二个物体必然漏检。 这就是 YOLOv1 在密集小目标场景下召回率骤降的根本原因。 参考资料 - YOLOv1 詳細解讀. 設計概念: | by Steven Meng | Medium - 《YOLO目标检测》第3章 YOLOv1 - YOLO演進 — 1. 在上篇文章有提到過 YOLO 的作法以及如何訓練,在這篇再更詳細的說明YOLO… | by 李謦伊 | 謦伊的閱讀筆記 | Medium
CNN经典网络模型架构学习之Resnet
Resnet网络架构是由微软亚洲研究院的何恺明等人在2015年提出,其论文为《Deep Residual Learning for Image Recognition》,在2015年的ImageNet图像识别竞赛中获得了分类、检测、定位等多个任务的冠军。这个模型的核心贡献在于解决了深层网络的训练难题,使得训练上百层甚至上千层的网络成为可能,极大地推动了计算机视觉的发展。 深层网络的训练问题 在Resnet网络架构提出之前,人们在进行深度神经网络的研究和训练过程中发现: - 网络的层次结构越深,层次越多,从理论上看其表达能力就越强,就越能够用于处理复杂的问题。 - 但是,当网络层数达到一定程度之后,模型训练和识别的准确率反而会下降。这种情况下的下降不是过拟合的问题,因为无论是训练还是验证数据的准确率都会变差。网络层数的增加,不仅没有优化网络的性能,反而导致其输出的精度指标变差,这个问题被称为深度网络的退化问题。 如下图所示,更深的网络层数(56层 vs 20层)不仅没有带来更加的效果,反而在训练集和测试集上均又有所“退化”。 !image.png > 需要注意的是,resnet所面对的问题,并非是深度网络训练过程中梯度反向传递时存在的梯度消失和梯度爆炸的问题。梯度消失和梯度爆炸的问题,是因为深度网络的层数增加之后,在训练过程的梯度向前反向传递流程中,梯度数值趋向为0或者始终保持为无穷大,导致网络参数几乎无法更新或者保持为发散状态的情况。实际上这两个问题在网络中增加BatchNorm的方式已经得到解决。Resnet面对的网络退化”问题,是一个独立于梯度消失/爆炸的全新问题。 Resnet通过在模型的架构设计中引入残差块的方式,解决了以上的网络退化问题,自此深度网络的层数得到了大幅度的提升。从下图可以看到,2014年的ImageNet数据集图像识别竞赛的冠军得主GoogLeNet只有22层,而到了2015年的冠军ResNet,其网络深度就达到了152层。 !image.png 残差块 传统的神经网络结构,一般都是将不同的卷积层、池化层、全连接层等按照一定的顺序简单的连接在一起,并且网络中的每一层只接收来自其上一层的信息,不会跨越层次结构接收更靠前的层的输出,并且每一层的输出也只会传递给下一层。如下图左侧正常块的各层连接模式。这样的层次结构模式,在网络层次加深以后,这种单一的连接方式会导致网络性能的退化。 而ResNet引入了残差块的概念。在传统的网络连接中,加入了短连接,模型的输入数据可以通过跨层连接的方式,更快的向前传播。如下图右侧所示。 !image.png 残差映射为何可行? 假设我们的原始输入为 x ,而我们期望网络学习到的理想的映射为 f(x) , 如果采用传统神经网络连接模式的正常连接结构的话,就需要直接从网络块的输入 x 拟合出来其映射 f(x) ,而如果采用残差块的模式,对于这个残差块本身而言,需要拟合出来的就不是 f(x),而只需要拟合出来残差映射 f(x)-x 就可以了。而残差映射的学习在现实中更容易实现和优化,这就是残差块能够解决问题的逻辑所在。 以下图为例进行解释。以下网络块要学习的映射是 H(x),如果直接用其输入 x 学习和训练出来对应的映射 H(x),这就是传统网络连接的做法。对于Resnet所使用的残差块而言,输入仍然是 x,输入也仍然是需要学习的映射 H(x),把输入 x 通过短连接(short connection)的方式,直接连接到输出,与残差块的输出 F(x) 相加,作为整个模块的输出 H(x),这样的话,对于残差块内部参数的学习的目标,就不再是直接从 x 到 H(x) 的映射,而是 x 到 F(x) 也就是 H(x)-x 的映射。_而在神经网络中学习和优化残差而言,会比直接学习最终的映射要来得更加容易。_ !image.png 举个简单的例子。假设输入 x 为2.9,模型的期望输出 H(x) 为3.0,两者之间的差值为3.0-2.9=0.1。 当使用传统网络结构的普通块来进行以上的映射,其从输入到输出的误差的变化是以其期望输出的3.0来进行评估;而如果按照残差块来实现以上映射,对于残差块内部参数的训练而言,其要训练的目标是残差 F(x)=H(x)-x=0.1,也就是说这个网络块的训练误差的变化是以这个差值的0.1来进行评估。 由此可以发现,采用残差的方式,可以更加凸显出来模型训练过程中的误差变化,模型也就更加容易训练和收敛。 典型残差块的结构 在作者的论文中,作者提出了两种残差块的结构,如下图所示: !image.png 对于层数不是很多的网络,使用左侧的连续3x3卷积-relu-3x3卷积的方式构成基础的残差块。而对于大于50层的网络,考虑到训练的深度和时间,作者提出了右侧的这种bottleneck的设计方式,增加了1x1卷积降维后再升维的方式,在节省大量参数的同时,兼顾考虑了深层网络的性能和时间复杂度。 Resnet模型架构 Resnet有不同网络层数的版本,例如18层,34层,50层,101层,152层等。其中最常用的是50层的网络结构,即Resnet-50。 Resnet模型的整体架构,基本上可以分为三个部分:输入层,中间连续的残差块,以及最后的输出层。 其中,输入层和输出层对于Resnet的所有版本都是相同的,各个版本的区别主要就是中间连续的残差块的数量和结构。 ResNet的输入层,也就是其网络结构的前两层,跟CNN经典网络模型架构学习之GoogLeNet笔记所介绍的GoogLeNet中的一样: 输入图像首先进行7x7,步幅为2的卷积处理,,输出通道数为64的特征图,然后接步幅为2的的2x2最大池化层。 Resnet中间的残差块部分,就由连续相连的基本残差块组成。只不过,对于各个不同版本的Resnet模型而言,其所包含的残差块的配置和数量各有区别。 !image.png 以Resnet34为例,残差块部分包含有:连续三个64通道3x3卷积残差块,连续四个128通道3x3卷积残差块,连续六个256通道3x3卷积残差块,以及连续三个512通道3x3卷积残差块。最终输出7x7x512的特征图给输出层部分。整个Resnet34模型的结构,共计1个7x7卷积层,32个3x3卷积层,以及一个全连接层,总共就是34个参数层。 下图为Resnet34模型的网络架构图: !image.png 残差块部分所输出的特征图,再继续经过全局平均池化层的处理,送入最后一层的1000个神经元的全连接层,配合Softmax激活函数实现对ImageNet数据集1000个识别类型的识别概率输出。 参考资料 - ResNet: Revolutionizing Deep Learning in Image Recognition - The Annotated ResNet-50 | Towards Data Science - ResNet详解与实践-CSDN博客 - 直觀理解ResNet —簡介、 觀念及實作(Python Keras) | by Chi Ming Lee | Medium
目标检测模型的评价指标详解:mAP,召回率,准确率
对于计算机视觉中的目标检测领域而言,主要的评估指标就是mAP与召回率、准确率。本文对IoU、准确率、召回率、AP以及mAP的概念和计算逻辑进行了详细的整理。 IOU IOU:Intersection Over Union。 对于目标检测算法的执行而言,每一张训练图片中的每个待检测物体,都会标注一个该物体位置对应的bounding box,这个标注的bounding box就是真实物体区域对应的检测区域。而目标检测算法对图片中物体所进行的检测和推理,会输出一个检测出来的Bounding box。IOU指标就是通过两个Bouding Box重合的程度,来评估目标检测算法对于该物体的检测精度。标注Bounding Box与检测Bounding Box的重合度越高,表示检测的精度越好。 !image.png 用下图可以非常直观的解释IoU如何计算。具体的解释就是:系统检测到的物体区域与真实物体区域的交集(如下图中Area of Overlap部分,也就是Intersection部分),除以两个区域之间的并集(如下图中Area of Union部分,也就是Union部分)。 !image.png 因此,对于一个检测图片中的某个待检物体而言,其IoU指标的计算,就是用检测框与标记框的交集面积,处于两个框的并集面积。这个值的计算结果当然是在0-1之间,0表示检测结果与真实的标记框完全无关,检测完全错误,而1则表示检测框和标记框完全重合,对于算法的评估而言,这个值当然是越高越好。一般使用IoU=0.5来作为判断识别率的基准,大于这个阈值表示是有效的检测,否则是无效的检测。 在理解以上IoU概念的基础上,对一张图片中的多个物体进行目标检测,就可能存在多种检测结果: !image.png - TP(True Positive):算法准确的检测到了图片中的物体,并且两个检测框的IoU重合度大于0.5,因此是一个正确的预测。 - FP(False Positive):算法检测出来的检测框,与该图片所有物体的标记框的重合度都小于0.5,最典型的就是把背景识别成了物体,因此是一种误检的情况。 - TN(True Negative):本身是背景,算法也没有输出对应的检测框,因此是正常现象,在目标检测的指标计算中不需要考虑。 - FN(False Negative):本来需要算法检测出来的物体,算法没有检测出来,所以相当于是漏检的情况。 以上检测结果的分类整理成表格就是: !image.png 召回率与准确率 准确率:Precision。召回率:Recall。 有了以上对于IoU以及目标检测算法的各种不同检测结果的类型的理解,关于目标检测算法执行准确率和召回率的概念及其计算就比较简单了。 所谓的准确率,表示的就是:目标检测算法所输出的检测结果中,其类别判断和位置检测(IoU>0.5)均正确的检测所占的比例。准确率的计算公式如下图所示: !image.png 而所谓的召回率,则表示的是:目标检测算法对图片中的物体进行的检测,把多少个物体正确地检测(类别判断正确,且IoU>0.5)出来了。召回率的计算公式如下图所示: !image.png 以上图中的茶杯的检测为例,准确率表示的就是,算法输出的茶杯检测结果,真的是茶杯的情况所占的比例。而召回率则表示的是,图片中所有的茶杯,被算法准确检测出来所占的比例。 AP与mAP AP:Average Precision,表示某个类别的检测精度。mAP:mean Average Precision,表示所有类别的平均检测精度。 下面以一个例子来更详细地解释说明AP的计算过程。 以某个数据集进行小狗目标的检测为例。数据集中真实标注的小狗目标有8个,分别对应于GT1-GT8(这里的GT表示Grounded Truth的意思,也就是通过手动标注出来的真实的小狗目标所在的位置)。而通过算法检测到的小狗目标及其位置有10个,使用BB1-BB10来表示(BB表示检测算法检测到的每个小狗目标的Bounding Box)。 使用算法对数据集中小狗目标的检测结果,部分检测位置的Bounding Box只检测到小狗的头或者脚,也就是说IoU很低(例如BB3, BB4, BB5, BB7, BB8这个检测输出的IoU均比较低),而且两个真实的小狗目标GT6和GT7没有能够检测到(FN=(GT7, GT8)),也就是说这两个真实目标漏检了。基于以上信息整理目标检测算法的执行结果如下图所示:需要注意的是,目标检测算法输出的每个检测结果,不仅包含这个检测结果对应的检测类别,Bounding Box的坐标信息,还有一个检测的置信度(Confidence),也就是这个检测目标正确的概率。 !image.png 从上图可以看到,对于一个真实的待检小狗目标,检测算法可能输出多个独立的检测结果与之对应,例如BB1和BB3对应的都是GT1。而一般情况下,只有在IoU>0.5的情况下,我们才会认为算法输出的检测结果是正确的TN,因此对以上算法检测所输出的10个检测结果BB1-BB10进行IoU判断如下: !image.png 然后按照流程,基于检测结果的置信度(即上图中属于狗的概率)对其进行排序: !image.png 然后按照以上排序,在不同的rank上计算各自的准确率Precision和召回率Recall。 - 对于Rank1而言,其准确率=(>=rank1的TP数量)/(>=rank1的TP+FP的总数量)=1/1=1,其召回率=(>=rank1的TP数量)/(TP的总数量)=1/8=0.125。 - 对于Rank2而言,其准确率=(>=rank2的TP数量)/(>=rank2的TP+FP的总数量)=2/2=1,其召回率=(>=rank2的TP数量)/(TP的总数量)=2/8=0.25。 - 对于Rank3而言,其准确率=(>=rank3的TP数量)/(>=rank3的TP+FP的总数量)=3/3=1,其召回率=(>=rank3的TP数量)/(TP的总数量)=3/8=0.375。 - 对于Rank4而言,其准确率=(>=rank4的TP数量)/(>=rank4的TP+FP的总数量)=3/4=0.75,其召回率=(>=rank4的TP数量)/(TP的总数量)=3/8=0.375。 - 以此类推,得到rank5的准确率=4/5=0.8,其召回率=4/8=0.5。 - rank6的准确率=5/6=0.833,其召回率=5/8=0.625。 - rank7的准确率=5/7=0.714,其召回率=5/8=0.625。 - rank8的准确率=5/8=0.625,其召回率=5/8=0.625。 - rank9的准确率=5/9=0.556,其召回率=5/8=0.625。 - rank10的准确率=5/10=0.5,其召回率=5/8=0.625。 因此,以上根据目标检测算法输出的10个检测结果,得到10组准确率和召回率的数据如下: !image.png 根据10组(Precision,Recall)就可以画出目标检测算法输出以上结果对应的P-R图: !image.png 所谓的AP指标计算上的定义,就是上面P-R中标记的蓝色P-R曲线下的面积或者积分。因为Precision和Recall指标都是在0-1之间,所以以上计算出来的AP指标当然也是在0-1之间。 !image.png P-R曲线面积或者积分的计算比较复杂,所以可以采用上图提供的两个离散序列公式来计算AP指标。 第一个公式中,P(k) 是第k个rank的准确度,而 Δr(k) 是指第k个rank的召回率与第k-1个rank的召回率的差值,因此按照该公式计算AP指标就是: 第二个公式中,P(k) 是第k个rank的准确度,而 rel(k) 的定义则是,在第k个rank为有效检测TP时, rel(k) 为1,否则为0。number of relevant documents表示总的TP个数,这是是8个(GT1-GT8)。因此基于该公式计算AP指标就是: 所以可以看到,以上的两个公式虽然算式不同,但是最终的结果殊途同归,最后计算出来的AP值都是0.579。 以上AP的计算说完了,那么mAP的计算就比较简单了。上面所进行AP的计算,只是针对小狗这个类别计算出来的AP,一般情况下目标检测算法可以输出多个不同类别的检测结果,例如在COCO数据集中就包含了80个类别的标注信息,那么一个目标检测算法的mAP指标,就是先独立的计算它所支持的每个类别的检测AP指标,然后再把所有的AP值加起来求平均值就是整个算法对所有类别检测性能的mAP指标。 !image.png 参考资料 - 《深度学习之Pytorch物体检测实战》1.2 - Yy's Program: 影像辨識常見的IOU、AP、mAP是什麼意思? - Learning Model :什麼是AP/mAP/IoU?[轉錄] | by Ryan Lu | AI反斗城 | Medium
短红外(SWIR)传感器的工作原理与应用总结
本文简要总结了基于短波红外光频段成像的SWIR传感器及其成像系统的技术概念以及在工业和生活中的常见应用,为理解和在实际产品中应用该技术做好基础。 SWIR技术简介 SWIR:Short Wave InfraRed Light,短波红外光。波长范围通常在0.9-1.7um波段(也有一种说法是0.9-2.5um波段)。 下图是红外光在频谱上所在的波段。总的来说,红外光波段可以分为SWIR短红外、MWIR中红外、LWIR远红外这几个部分。各个部分对应的波长范围大致如下图所示。 !image.png 从曝光成像的工作原理上讲,SWIR传感器与我们常见的可见光谱的图像传感器的工作机理类似,都依赖于被拍摄物体材料的反射特性:外部光照中所包含的光子要么被物体反射,要么被物体吸收,从而产生高分辨率图像所需的对比度和阴影。 - 这一点与MWIR和LWIR波段的成像原理差异很大,MWIR和LWIR波段的成像依赖于物体本身的黑体辐射,辐射量与温度相关。_因此,可见光和SWIR的成像要依赖于外部的光照情况,外部光照照射到物体上被反射后进入镜头成像,因此其成像不是全天候的,晚上一般需要额外补光;而MWIR和NWIR成像依赖于物体本身的黑体辐射,因此可支持全天候24h成像。_ 因此,SWIR相机所产生的图像,在灵敏度和细节上与可见光相当,具有鲜明的阴影和高对比度。当然,SWIR的成像是单色的。 SWIR传感器的工艺及其限制 常见的可见光的图像传感器都是基于标准硅工艺生产的,因为硅元素的吸收系数在1100nm波长附近迅速下降,因此基于硅工艺的光传感器的实际有效检测的上限一般为1000nm。也就是说,硅对1000nm以上的光子吸收能力极弱,导致在该波长段的信号响应几乎为0,因此硅工艺不适合用于进行SWIR成像。 SWIR成像传感器一般采用InGaAs工艺,其对光子的探测波长上限为约1700nm,因此InGaAs传感器可以有效的吸收并且转换900-1700nm范围内的光子,是SWIR成像领域的主流选择。 InGaAs传感器的问题则在于: - InGaAs不能直接在硅晶圆上生长,材料昂贵,工艺复杂且良率低,导致传感器的生产成本和价格均很高。 - InGaAs传感器的像素尺寸缩小以后会影响图像质量,难以做到CMOS一样的高集成度和大阵列。 SWIR传感器的典型应用 夜视成像 夜间的图像监控对于普通的可见光相机而言始终是个难点。其主要的原因是夜里并非没有光线,而是处于可见光频段的光线能量太弱,进入可见光图像传感器的光子太少,不得不通过外部补光以及提升增益(图像质量变差)、增大pixel size和lens光圈(成本太高)的方式缓解问题。而在900-1700nm频段的短波红外光频段,大气辉光(nightglow)、星光和1.5 µm激光反射等仍然充足,SWIR 传感器(InGaAs)可以把这些人眼看不见的光转成高分辨率图像。 因此在夜视成像领域,SWIR相比普通的可见光相机而言,图像亮度要比可见光高5-7倍;而相比工作在LWIR频段的热成像仪而言,图像的分辨率又要高很多。 以下左图为可见光相机的成像,右图为相同环境下SWIR相机的成像: !image.png 水果水分/农产品拣选 水对900-1700nm频段的光线有着比较强的吸收特性,在1.45µm最强,1.95µm次之。一般的农产品和水70%都是水,含水量越高的情况下,该物体对于SWIR频段光线的反射率越低,呈现在SWIR图像中就越黑。而农产品和水果的任何生理变化(成熟、碰伤、腐烂、糖积累)都会改变其内部的水分分布或糖分浓度,于是在SWIR的图像里就会出现肉眼看不见的明暗反差。 !image.png 穿透雾霾成像 在雾霾天气的情况下,雾霾的颗粒直径普遍在0.1-1um之间,该范围的雾霾颗粒对于可见光的反射最大,而对于SWIR波段的散射要小很多,因此更多SWIR频段的光线可以透射雾霾颗粒,在SWIR相机中成像的图像白雾层就会大幅减薄。因此,在浓雾、雾霾等天气状况中,使用SWIR成像系统在边境、机场、海岸等监控领域中,其成像比可见光相机要清晰很多。 !image.png 高温检测 当物体的温度超过140摄氏度时,会越来越多地向外发射红外辐射,这些辐射的红外光可以通过SWIR技术检测到。当物体越热的时候,它发出的红外辐射就越多,物体在图像中就越亮。这就意味着可以使用SWIR技术在工业监测等领域中对温度检测提供竞争优势,因为它可以实现材料和产品的非接触式温度监测。这在传统温度测量方法不切实际或危险的环境中特别有用。 例如下图是电烙铁在400摄氏度的情况下,在普通的可见光相机(左图)以及SWIR相机(右图)下的对比图片。 !image.png 参考资料 - What is SWIR? | Edmund Optics - What is SWIR? | SWIR Vision Systems - Understanding SWIR: Applications and Benefits- Oxford Instruments - Clear Align Knowledge Center-Optical Engineering Insights & Resources || Why SWIR is Ideal for Border Surveillance & Maritime Imaging
CNN经典网络模型架构学习之GoogleNet
本文对经典卷积神经网络存在的问题,以及计算机视觉图像识别领域经典的GoogLeNet架构设计的相关知识点进行了完整和详细的总结。 AlexNet和VGGNet存在的问题 在CNN经典网络模型架构学习之AlexNet和CNN经典网络模型架构学习之VGGNet两篇笔记中,分别总结了经典CNN网络中的AlexNet和VGGNet两种模型的架构和实现。 相对而言,AlexNet的层次和参数都比较少,这也就限制了该网络从数据中提取和学习复杂模式的能力,最终的识别和检测效率不高。 VGGNet加大了CNN神经网络的深度,参数层达到了16层和19层,但是因为深度而导致的其他问题也就应运而生: - 首先是梯度消失问题。众所周知,在神经网络的训练过程中,通过损失函数来评估模型的运行效果,根据损失值使用反向传递法+梯度下降法从输出层向前一层层更新其运行参数,通过这种方式来实现最终损失函数输出值的降低。但是,在网络深度加大的情况下,相同的损失值在反向向前一层传递的过程中会越来越小,最终导致网络中的参数(尤其是前半部分的参数)在训练中很难得到有效的更新。 - 其次是深度模型对算力要求过高。 以VGG16网络模型为例,其参数高达138M,模型参数大小超过500MB,模型的训练和推理所需要的算力都比较高。 GoogLeNet的架构设计,对传统的CNN网络架构进行了重构,来尝试解决以上问题,并得到了较好的应用效果。GoogLeNet,也称为Inception-v1,首次在2014年提出,在2014年的ILSVRC竞赛中得到了第一名,Top-5 Error只有6.67%。_更为难能可贵的是,GoogLeNet的参数只有6.8M,比AlexNet少9倍,比VGG16更是少了20倍_。 GoogleNet的最大创新点是引入了Inception模块,这也是GoogLeNet同样被称为InceptionNet的原因所在。 Inception Module Inception模块是一种允许在多个尺度上并行处理数据的构建块,这使得网络能够比以前经典卷积神经网络架构更有效地捕获不同尺度的特征。 一个Inception模块通常由多个卷积层组成,每个卷积层使用不同的卷积核尺寸。而且不同于之前的网络模型,Inception Module中的多个卷积层以并行的方式工作,因此对于输入的同一张特征图,网络可以使用不同尺寸的卷积核进行计算。这些卷积层计算完成后,其输出结果拼接在一起,然后传递给一个池化层进行处理。以上就是Inception模块的总体设计理念。 从Inception的结构上看,GoogLeNet提出的Inception Module可以分为两种类型:Native类型和降维类型。 !image.png 两种Inception Module的共同特征是:Inception Module从前一层特征图得到的输入数据,并行进行1x1卷积、3x3卷积、5x5卷积以及3x3的最大池化处理,以上四个部分的处理结果拼接在一起,做为整个Inception的输出。而其不同点则在于:_降维版本的Inception Module在3x3卷积、5x5卷积之前,以及3x3最大池化之后分别增加一个一个1x1的卷积操作。_ 其中: - 1×1 卷积块用于在保持输入特征图分辨率不变的情况下,在特征图的像素级上捕捉局部细节。 - 3×3 卷积块从输入的特征图中捕捉中等范围特征。 - 5×5 卷积块则用于捕捉更大范围的特征。 - 独立的3×3最大池化块用于保留原始特征的显著响应(如边缘、纹理)。 如前所述,native模块和降维模块的差异,在于后者增加了三个1x1的卷积操作,分别位于3x3卷积和5x5卷积之前,以及3x3最大池化之后。_放在3x3卷积和5x5卷积操作之前的那两个1x1卷积操作,其目的是降低计算的复杂度和参数量;而放在3x3最大池化之后的1x1卷积操作,则用于控制3x3最大池化输出的通道数(否则池化后的通道数与输入的通道数相同,总的通道数就太多了)。无论如何,以上四条路径输出的特征图分辨率相同,这样后续四条并行处理路径输出的特征图才能方便的拼接在一起。_ > 由此可见,在降维版本的inception module中,独立路径中的1x1卷积操作,与其他路径中额外增加的1x1卷积操作的作用是完全不同的。 1x1卷积如何降低计算量? 在降维Inception模块中的3x3以及5x5卷积操作之前,增加的1x1卷积的目的主要是用于降低参数量和计算量。 以下图为例,在不使用1x1卷积的情况下,从14x14x480到14x14x48的特征图转换,使用5x5卷积的情况下,其计算量达到了:_(14×14×480)×(5×5)×48 = 112.9M_。 !image.png 而在两个特征图中间增加一个1x1卷积层,如下图所示,其计算量大幅度下降: !image.png 其中1x1卷积的计算量为:(14x14x480)x(1x1)x16=1.5M,5x5卷积的计算量则为:(14x14x16)x(5x5)x48=3.8M。_两个加起来也只有5.3M,只有不增加1x1卷积计算的1/20!_ Inception模块如何实现输出拼接? 如上所述,Inception模块对于输入数据而言,有四条独立的处理路径。输入数据经过这四条独立的处理路径处理以后,在Inception模块的输出部分要拼接在一起。四条路径的处理结果要进行拼接,首要的条件也就是各个路径输出特征图的分辨率要相同。 因此,四个独立通道在设计时已经统一设计为stride=1并且配好了相应的padding,来确保在相同输出数据维度的情况下,各个通道的输出数据的分辨率也是相同的: - 1x1卷积路径:padding=0 - 3x3卷积路径:padding=1 - 5x5卷积路径:padding=2 - 3x3最大池化路径:padding=1 !image.png 在以上设置的情况下,可以保证四个通道对相同输入数据处理后,其输出特征图的分辨率相同,只不过各个通道的通道数(也就是各个通道的特征图数量)不同。四个通道输出特征图的分辨率相同的情况下,对于四通道输出的拼接就比较简单了:只需要把四个通道输出的特征图并排堆积起来就好了。 以GoogLeNet(Inception V1)论文中的第一个Inception模块(3a)为例进行解释。前一层的输入张量形状为,192x28x28,由前面的卷积+池化层处理后输出。 在Inception模块的四条路径中分别进行处理: - 1x1卷积,输出64通道28x28分辨率的特征图(64x28x28) - 3x3卷积,先通过1x1卷积降维到96通道(96x28x28),然后通过3x3卷积+padding为1输出128通道(128x28x28) - 5x5卷积,先通过1x1卷积降维到16通道(16x28x28),然后通过5x5卷积+padding为2输出32通道(32x28x28) - 3x3最大池化,先进行3x3最大池化(padding=1)继续输出192通道(192x28x28),然后通过1x1卷积把通道数降低到32通道(32x28x28) 最后把以上四个独立流程的输出拼接在一起,总共就得到了64+128+32+32=256通道28x28的特征图作为整个inception模块的输出。 全局平均池化 在传统的卷积神经网络架构中,使用连续的全连接层基于卷积层提取出来的特征数据,对图像进行分类操作。全连接层存在的最大问题就是参数太多,过拟合问题比较严重。针对这个问题,GoogLeNet采取了与Networ in Network相同的做法,使用全局平均池化的操作来代替全连接层,既解决了传统模型参数太多和过拟合的问题,而且从实际数据的测试结果来看,其分类的准确率也有了比较明显的提升。 下图是输入特征向量相同的情况下,全连接层与全局平均池化层不同的计算逻辑。有关全局平均池化更详细的内容可参考CNN经典网络模型架构学习之NiN。 !image.png Auxiliary Classifier GoogLeNet总共有22层,在网络深度较深的情况下,通过反向梯度传递和计算的过程中,梯度在反向传递的中间层逐级递减,最终导致梯度消失以致网络前半部分层的参数无法得到有效更新的问题。 GoogLeNet通过引入一个Auxiliary Classifier来尝试解决以上问题。Auxiliary Classifier的思路是:在网络的中间部分挂一个也能够进行分类操作的小网络(Auxiliary Classifier),这个小网络基于前面部分的特征图数据执行分类操作,得到自己的损失函数值。在进行模型训练的过程中,把这个损失值加到模型最终输出的损失值上,以增大梯度信号,缓解梯度消失的作用。 Auxiliary Classifier仅用于训练过程,在训练完成的推理过程中只保留主干网络的输出,因此不会影响推理速度。 在GoogLeNet的网络架构中,分别在4a和4d这两个inception module后面增加一个Auxiliary Classifier(可参考后续GoogLeNet的网络整体结构部分)。_每个Auxiliary Classifier的结构如下:_ - 输入为以上两个Inception Module所输出的特征图,例如512通道14x14分辨率的特征图 - 5x5平均池化:对输入的特征图首先进行5x5平均池化操作,stride=3,得到512通道4x4分辨率的特征图 - 1x1卷积:通过1x1卷积把通道数从512降低为128,输出128通道4x4分辨率的特征图 - 展平以上特征图以后。连接到一个1024神经元的全连接层,激活函数为ReLU - 增加一个Dropout操作,dropout比例为0.7 - 连接到一个1000神经元的全连接层,对应ImageNet数据集的1000个类别。 - 1000个神经元的乘加输出,通过softmax操作得到1000维的预测向量。 以上Auxiliary Classifier的预测输出与标签值对比,得到这个Auxiliary Classifier的损失值。把网络中两个Auxiliary Classifier输出的损失值分别乘以权重0.3,增加到网络主干网络分类输出的损失值,得到整个网络的损失值: 在进行网络参数训练的过程中,会把整个TotalLoss作为其损失值反向传递以更新网络参数。 GoogLeNet的整体结构 有了以上信息储备,理解GoogLeNet网络的整体架构相对就比较容易了: !image.png 从总体架构上可以看到: - GoogLeNet的开头部分通过连续的卷积和池化操作实现输入图像分辨率的降低。 - 然后通过连续9个inception module不断提取图像特征,9个inception module分为3段(2+5+2)。每个inception段内的连续module直接连接,段之间通过一个3x3的最大池化进行连接。 - 最后一个inception module的输出再通过全局平均池化+全连接层实现最终的图像分类操作。 - 此外,在inception 4a和4d的输出上再各自通过一个Auxiliary Classifier得到用于辅助训练过程的阶段性损失值。 GoogLeNet中各层的数据维度以及参数数量等信息如下表所示: !image.png 参考资料 - GoogLeNet: A Deep Dive into Google’s Neural Network Technology | by Siddhesh Bangar | Medium - Neutrino's Blog: GoogLeNet 簡介與小實驗 - 7.4. 含并行连结的网络(GoogLeNet) — 动手学深度学习 2.0.0 documentation - Understanding GoogLeNet Model - CNN Architecture - GeeksforGeeks - GoogLeNet: Revolutionizing Deep Learning with Inception - Inception-v1 (GoogLeNet) — Winner of ILSVRC 2014 (Image Classification) | by Moris | Computer Vision Note | Medium - 深度学习经典网络解析:6.GoogLeNet-腾讯云开发者社区-腾讯云
CNN经典网络模型架构学习之NiN
本文总结了卷积神经网络经典模型中的NiN(Network in Network)的设计理念、整体网络架构和具体的网络实现细节。 LeNet、AlexNet以及VGGNet这三种卷积神经网络模型的设计模式都是相同的:通过一系列的卷积层和池化层的组合进行特征提取,然后把提取到的特征数据展平(Flatten)后,送入一系列的全连接层进行分类操作,最终输出图像识别的概率。 以上这种经典的卷积神经网络设计模式存在两个主要的设计挑战: - 基于特征数据进行图像分类任务的全连接层所包含的参数数量太多了。例如,在VGG16网络中,参数数量高达138MB,模型参数所占据的存储空间也超过了500MB。 - 无法在网络的前半段添加全连接层来增加非线性程度,这样做会破坏空间结构,而且需要更多的参数和内存。 针对以上两个网络结构设计上的问题,2013年由National University of Singapore的Min Lin所发表的Network in Network(简称NiN),对经典的卷积神经网络的架构设计理念提供了新的设计思路。 NiN架构在传统CNN卷积网络的基础上最大的两个创新是MLP卷积层和全局平均池化层。 MLP卷积层 传统的卷积层的卷积计算逻辑在详细解释卷积神经网络中的卷积与池化计算一文中已经有非常详细的描述,在此不再赘述,仅以一个卷积计算的动图来进行解释: !CNN%E5%8D%B7%E7%A7%AF%E8%AE%A1%E7%AE%97%E5%8A%A8%E5%9B%BE.gif 总结起来,传统的卷积层计算公式如下图所示,(i,j) 是输入特征图中像素位置的索引,x_{i,j} 表示对应位置的像素,W 为卷积核的参数。那么卷积计算实际上就是 (i,j) 位置的像素及其周边像素与卷积核对应位置的权重之间的乘加结果,再通过ReLU激活函数进行处理,得到卷积计算的特征图。 !image.png 在NiN网络的实现中,卷积计算按照MLP Block的方式来进行组织。一个MLP Block的典型结构如下图所示: !image.png 对于每一个MLP Block而言,其输入是原始的3通道RGB图像或者前一个MLP Block输出的多张特征图。每个MLB Block的内部包含有三个连续的卷积层,每一层的输入都是前一层的输出。其中第一个卷积层的卷积计算与普通的卷积计算别无二致,而后面的两个卷积层则是1x1卷积层,1x1的卷积计算仍然是计算特征图像素值与权重的乘加,然后使用ReLU激活函数进行非线性处理。 以下的代码解释了对于每个MLP Block的结构和计算逻辑: > 每个MLP Block包含有3个卷积层,一个普通的卷积层+ReLU激活,再加上两个连续的1x1卷积层+ReLU激活。在网络架构上,一般每个MLP Block后面再跟一个最大池化层。 全局平均池化层 传统的卷积神经网络架构中,一般使用多个全连接层来实现特征分类的功能,其做法是把最后一个卷积层产生的特征图展平(Flatten)为一维向量,经过连续多个全连接层,最后使用一个softmax层进行逻辑回归分类。这种方式存在的主要问题是:全连接层的参数太多,以及多个全连接层造成的过拟合问题。 NiN网络使用全局平均池化的操作来代替全连接层,以尝试解决经典卷积神经网络后半部分全连接层的参数过多和过拟合的问题。全局平均池化操作具体的做法是最后一层卷积层输出特征图的数量,与分类类别的数量相同(例如对于ImageNet数据集就是1000个,对于MNIST数据集则是10个)。然后针对每张特征图取其平均值以后再输出成一个向量,对这个向量加上softmax操作(softmax操作的计算流程可以参考Softmax分类器的计算流程详细总结),最终输出各个类别的识别概率。 全局平均池化操作的流程如下图所示: !image.png 以ImageNet数据集(该数据集的图像分类结果有1000个类别)为例,全局平均池化层从其前面的MLP卷积层得到1000张特征图,那么在全局平均池化的计算中,就会对每一张特征图进行平均计算得到其平均值,最终得到由1000个平均值所组成的向量,然后对这个向量执行softmax操作,得到每个类别的识别概率输出。 > 可以看到,以上的全局平均池化层的计算与普通的平均池化的计算逻辑是类似的,因此完全不需要参数,这样就极大程度上减少了模型的参数数量(实际上经典卷积神经网络中的大部分参数都来自于全连接层),也可以避免传统的全连接层存在的过拟合问题。 NiN的网络架构总结 NiN网络的总体结构如下图所示。图像输入仍然是224x224分辨率的RGB三通道图像,经过连续四个MLP Block的卷积处理,最后一个MLP Block输出1000张6x6尺寸的特征图,把这个特征图经过全局平均池化层的平均计算以及softmax激活后输出1000个类别的识别概率。 !image.png 可结合下图对以上NiB架构图中各层的特征图尺寸和计算类型进行理解。尽管看起来NiN网络的层数比VGG网络多了不少,但是因为去掉了全连接层,NiN网络的参数数量比VGG少了很多。 !image.png 基于以上定义的nin_block结构实现的完整NiN网络的实现代码如下: 参考资料 - 8.3. Network in Network (NiN) — Dive into Deep Learning 1.0.3 documentation - 卷积神经网络之-NiN 网络(Network In Network)-腾讯云开发者社区-腾讯云 - Review: Network In Network. 這篇論文是由National University of… | by Fan | Medium
CNN经典网络模型架构学习之VGGNet
本文对计算机视觉图像识别领域经典的VGGNet模型的组成架构以及在Pytorch中的实现进行了详细的总结。 VGGNet的网络架构简介 VGG:Visual Geometry Group。VGGNet最初的设计理念是通过加大卷积神经网络的深度,来提升模型的工作性能指标。VGGNet在2014年的ImageNet的图像识别和分类竞赛(ILSVRC)中得到了第二名(GoogleNet是当年竞赛的第一名),top-5 accuracy指标(模型预测出来的概率最高的前5个类别中,是否包含了真实的标签)达到了92.7%,在后续的一些其他模型中,VGGNet的网络结构也往往被用于backbone部分进行图像的特征识别。 VGGNet的网络架构中比较典型的VGG16,VGG19以及VGG34模型,其中的数字表示其模型架构分别包含有16个、19个以及34个参数层(即卷积层和全连接层)。 下图是VGG16的网络架构图: !image.png - 以上VGG16的整个网络架构中,包含了13个卷积层,5个池化层,以及3个全连接层,其中的参数层(即卷积层和全连接层)共计16个。 - 模型的输入的分辨率为224x224的RGB三通道图像数据,最终的输出为针对1000个图像分类类别的预测概率(因为VGG16模型的设计是对ImageNet数据集进行预测,该数据集有1000个分类)。 - 从整个网络架构的设计上讲,仍然是标准的卷积神经网络。整个网络结构分为两个部分:前半部分是卷积层和池化层组成的图像特征提取部分,后半部分则是由全连接层组成的图像分类部分。因此,网络结构与CNN经典网络模型架构学习之LeNet以及CNN经典网络模型架构学习之AlexNet所总结的LeNet以及AlexNet没有本质上的差别,只不过层次更多而已。但因为层次相比较LeNet和AlexNet的层数加深了很多,VGG16的参数数量达到了138M。 VGG19 相比 VGG16 多了 3 个卷积层,在以上的conv3、conv4、conv5部分各加了一个卷积层,其余部分(包括卷积核尺寸、通道数、池化策略、全连接层结构)完全相同。 在VGGNet的原始论文中,作者共提供了从A到E共6种网络配置。其中VGG16对应的是配置D,而VGG19对应的则是配置E。 !image.png 从上表可以看到,A-E这6种配置的网络架构基本相同,差异只在于各个卷积层的数量不同而已。 VGG16各网络层次参数配置 下图为VGG16网络架构中各个层次的超参数设置: !image.png - 可以看到,以上VGG16网络结构的各个层次中,conv1、conv2、conv3、conv4/conv5部分的卷积核数量分别为64、128、256、512个,各个卷积区使用的卷积核的数量在每一层加倍,这是设计VGG16网络架构的一个重要原则。 - 所有卷积层的卷积核大小都是3x3(这一点与AlexNet所使用的更大尺寸的卷积核形成了鲜明的对比),卷积层的步进stride全部为1;所有池化层均为2x2最大池化,池化步进stride全部为2。 - 激活函数方面,除了最后输出层使用多分类的softmax激活函数以外,其他所有的卷积层和全连接层的激活函数均为ReLU。 - 最后的三个全连接层部分,前两个全连接层均有4096个神经元,最后的输出层对应ImageNet数据集的1000个类别的识别概率,包含有1000个神经元。 VGGNet的Pytorch实现 VGG16网络结构基于Pytorch框架的代码实现如下所示: 参考资料 - Understanding VGG: The Backbone of Image Recognition - VGG-Net Architecture Explained. The company Visual Geometry Group… | by Siddhesh Bangar | Medium - VGGNet - HackMD
Softmax分类器的计算流程详细总结
Softmax激活函数一般用于多分类问题的分类器实现,本文详细介绍和总结了基于Softmax激活函数以及交叉熵损失函数来实现神经网络多分类器的完整计算流程。 实际的人工智能项目,经常会遇到多分类问题,最典型的就是基于MNIST手写数字识别数据集,对手写的0-9总共10个手写数字进行识别和分类,以及基于ImageNet的图片数据集,对日常生活中看到的1000个物体进行分类。在人工智能的机器学习领域中,最常用的多分类器的实现就是Softmax分类器。 Softmax分类器的计算流程详细总结-Softmax多分类器.png Softmax激活函数 对于基于Softmax实现的深度神经网络的多分类应用而言,网络最后一层的全连接神经网络的神经元个数就对应了该网络实现分类操作的类别数量。那么Softmax的输入就是这些神经元的输出(也就是所谓的logits),Softmax的输出则是不同类别分类判断的概率。 以下详细解释Softmax操作的计算流程。假设数组 a 中有 n 个元素: 那么针对这个数组 a 进行的Softmax计算的流程如下。首先,对 a 中的每个元素取以e为底数的幂,得到一个新的数组 t : 然后把 t 数组中所有元素相加得到 s: 最后,把数组 t 中的每一个元素除以以上计算出来的 s ,得到一个新的数组就是针对 a 的softmax的计算结果: 因为 s 是 t 数组所有元素的和,所以以上softmax的计算结果中所有元素的和就是1,每个元素对应于多分类识别输出对应的该类别的识别概率。 因此Softmax计算的流程如下图所示: !image.png Softmax计算流程在Python中的实现代码如下所示: One-Hot编码 One-Hot编码,又称为独热编码,在多分类应用中,只用0和1两个数字来表示分类标签对应的概率。 以dog、cat、bird三种分类情况为例,这三种类别在标签数据上,可以分别使用(1,0,1),(0,1,0),(0,0,1)来表示: !image.png 交叉熵损失函数 在深度网络多分类器应用的实现上,一般是在最后一个全连接层采用Softmax激活函数对该层所有神经元的原始输出进行处理,得到每个类别对应的分类概率,而这类应用一般采用的损失函数则是交叉熵损失函数。 交叉熵损失函数的表达式如下图所示: !image.png 其中的 p(x) 表示以One-hot编码表示的训练样本数据对应一维向量,其中只有正确分类对应的元素为1,其他分类对应的元素均为0;q(x) 则是深度网络模型的输出经过Softmax处理后输出的一维向量,其中的各个元素对应了模型预测出来的各个分类的可能性。 所以交叉熵损失函数的计算,本质上就是对训练样本标记的One-Hot分类结果,与模型使用相同样本推理计算出来的各个类别的分类预测结果之间进行比对,判断预测输出的正确分类结果的可能性有多接近1,预测输出的正确分类结果越接近1,损失函数越小。 交叉熵函数的Python代码实现如下: 可以看到,预测输出结果的正确分类2对应的可能性越高(0.8 vs 0.6),交叉熵损失函数的计算结果越小。 Softmax分类器的实现 > 多分类应用:最后一个全连接层的输出使用Softmax激活处理,训练样本的标签采用One-Hot Encoding进行编码,损失函数采用交叉熵Cross Entropy。 下图总结了深度神经网络基于Softmax激活函数和交叉熵损失函数实现多分类器的计算流程。 !image.png - 深度神经网络的最后一个全连接层,从前一个全连接层接收输入的特征变量 x_m ,与最后一层的权重系数 w_{m,k} 以及偏置变量 b_k 进行乘加操作,得到最后一层各个神经元的净输出。 - 最后一层神经元的净输出,作为一个完整的一维向量,执行Softmax操作,输出各个分类推理输出的可能性预测列表 t_k 。 - 深度神经网络输出的多分类预测输出 t_k 与以One-Hot encoding模式编码的样本标签进行比较,使用交叉熵(Cross Entropy)损失函数计算损失。 - 根据交叉熵损失函数的输出反向传播调整整个网络的各级参数。 总结起来,Softmax激活函数在计算流程上,与其他激活函数(如Sigmoid,Tanh,ReLU等)相比,最大的区别是:其他的激活函数都是对每个神经元的乘加输出进行非线性变换,而Softmax激活函数则是对最后一层所有神经元的乘加输出进行的计算。 参考资料 - 《Python深度学习和项目实战》,第三章 Softmax多分类器 - 使用 TensorFlow 學習 Softmax 回歸 (Softmax Regression) | by Leo Chiu | 手寫筆記 | Medium - Cross Entropy Loss: Intro, Applications, Code
CNN经典网络模型架构学习之AlexNet
本文对计算机视觉图像识别领域经典的AlexNet模型的组成架构以及在Pytorch中的实现进行了详细的总结。 在CNN经典网络模型架构学习之LeNet一文中,对Yann LeCun针对手写数字识别的LeNet5网络模型的结构进行了总结。接下来,继续学习计算机视觉领域中的那些经典模型的框架,本文总结了在ImageNet图像识别竞赛中脱颖而出的AlexNet。 AlexNet历史简介 在2012年的ImageNet图像识别竞赛( ImageNet Large Scale Visual Recognition Challenge ,ILSVRC)中,由Alex Krizhevsky, Ilya Sutskever和Geoffrey E. Hinton所提出的AlexNet赢得了冠军。在该竞赛最重要的Top-5 Error Rate指标上,AlexNet取得了断崖式的领先,相比第二名足足提高了10个百分点: !image.png 正是因为AlexNet在该次竞赛中的卓越表现,开启了深度学习这种方式在人工智能计算机视觉领域的研究热潮。 AlexNet的网络架构 AlexNet的网络架构图如下图所示: !image.png 由上图可以看到,AlexNet的整体结构与CNN经典网络模型架构学习之LeNet所描述的LeNet-5网络架构非常类似,整体上可以分为两个部分: - 图像特征提取部分:包含从输入层到最后一个最大池化层,这部分的输出是6x6x256维度的图像特征向量。 - 分类部分:包含最后的三个全连接层。 AlexNet网络的输入是RGB三通道227x227分辨率的图片,输出则是通过输出层的1000个神经元的SoftMax激活函数所输出的1000个分类的概率。之所以是1000个分类,主要是因为AlexNet设计的初衷就是为了参加ImageNet的图像识别竞赛,而ImageNet数据集中包含有1000个图像分类。 AlexNet的总体网络结构总共包含有五个卷积层,三个最大池化层,三个全连接层。 - 输入数据为RGB三通道227x227分辨率的彩色图像数据。 - 第一个卷积层包含有96个卷积核,卷积核为11x11x3的立体卷积核,步进Stride为4,激活函数为ReLU,最终产生96张55x55分辨率的特征图。 - 第一个池化层采用3x3,步进Stride=2的最大池化操作,输出96张27x27分辨率的特征图。 - 第二个卷积层包含有256个卷积核,卷积核尺寸为5x5x96,步进为1,padding为2,激活函数为ReLU,最终产生256张27x27分辨率的特征图。 - 第二个池化层采用3x3,步进Stride=2的最大池化操作,输出256张13x13分辨率的特征图。 - 第三个卷积层包含有384个卷积核,卷积核尺寸为3x3x256,步长为1,padding为1,激活函数为ReLU,最终产生384张13x13分辨率的特征图。 - 第四个卷积层包含有384个卷积核,卷积核尺寸为3x3x384,步长为1,padding为1,激活函数为ReLU,最终产生384张13x13分辨率的特征图。 - 第五个卷积层包含有256个卷积核,卷积核尺寸为3x3x384,步长为1,padding为1,激活函数为ReLU,最终产生256张13x13分辨率的特征图。 - 第三个池化层采用3x3,步进Stride=2的最大池化操作,输出256张6x6分辨率的特征图。 - 以上就是AlexNet的特征提取部分,最后一个池化层进行展平操作为6x6x256个元素的一维向量,最后分类网络层第一个全连接层的输入。 - 第一个全连接层有6x6x256共计9216个输入,有4096个神经元输出,激活函数为ReLU。 - 第二个全连接层接受4096个输入,有4096个神经元输出,激活函数为ReLU。 - 最后一个全连接层有1000个神经元输出,对应于ImageNet数据集的1000个识别分类的概率。 整个网络总的参数数量达到了6000万个,主要集中在最后的三个全连接层:9216x4096+4096x4096+4096x1000=59621952,可见全三个全连接层占去了所有参数总量的绝大多数。 整个网络结构各层数据的维度如下总结: !image.png AlexNet的双层架构实现 另外,从部分资料上看到的AlexNet的架构图如下所示: !image.png 可以看到,以上架构图把整个网络分为完全相同的上下两个部分,输入图像同时输入上下两个子网络,最后在输出层汇合。这个架构图实际上是AlexNet原始实现的架构图,因为当时的GPU配置和处理能力相对较低,如果使用一块GPU进行AlexNet+ImageNet数据集的训练的话,速度会非常慢。所以Alex把网络分为上下两个部分,两个子网络分别在两块显卡上并行运行,最后在输出层合并输出结果,这样可以大大加快训练和推理的速度。 但无论如何,从网络层次和结构设计的本质上,以上的这种上下两个子网络的结构与AlexNet网络的标准网络结构并没有区别。 Alexnet的特点总结 激活函数 在AlexNet的网络架构设计中,激活函数由LeNet-5的Sigmoid变成了ReLU,这一修改可以解决在神经网络的层数过深或者梯度过小的情况下,Sigmoid激活函数所存在的梯度消失问题。同时,ReLU相比Sigmoid和Tanh等激活函数,还有着收敛速度更快、训练效率更高以及计算更为简单等优点。 以下是AlexNet论文中所演示在在CIFAR-10数据集上,ReLU相比Tanh激活函数在训练收敛速度上的巨大优势: !image.png 最大池化 AlexNet与LeNet5另外一个明显的不同,是使用最大池化层代替了LeNet5所使用的平均池化层。 AlexNet所采用的3x3,stride=2的最大池化层,与LeNet5的2x2平均池化相比,更能够保留重要特征,并且因为stride
CNN经典网络模型架构学习之LeNet
本文以用于进行手写数字识别功能的LeNet为例,分析该网络的结构以及典型的卷积神经网络的整体架构,对用于进行图像识别和处理的卷积神经网络建立初步认识。 在卷积神经网络CNN的架构解析入门一文中简单的总结了典型的卷积神经网络的结构和组成,本文以一个非常经典的、用于进行手写数字识别的LeNet-5网络为例,更为详细的解释卷积神经网络的结构和运行流程。 LeNet简介 LeNet是最早发布的卷积神经网络之一,也是架构最简单的卷积网络,非常适合作为入门网络结构用于建立卷积神经网络架构设计理论和运行流程的理解基础。 LeNet模型是由贝尔实验室的研究员Yann LeCun在1989年首次提出并不断优化,其设计和应用的目的是用于识别手写数字(也就是对所谓的MNIST数据集进行的训练和识别)。 LeNet被广泛用于美国的邮政服务和自动取款机(ATM)机中,帮助识别处理手写的邮政编码数字和支票上的数字。 时至今日,一些自动取款机仍在运行Yann LeCun和他的同事Leon Bottou在上世纪90年代写的代码! !image.png LeNet的官网地址:MNIST Demos on Yann LeCun's website LeNet的网络架构说明 下图是LeNet的网络架构图: !image.png 总体上看,以上的网络架构像所有的卷积神经网络一样,由两个部分组成: - 特征提取层:包含两个卷积层+池化层(也就是上图中的汇聚层)的组合。 - 分类层:包含三个全连接层。 每个卷积块中的基本单元是一个卷积层、一个sigmoid激活函数和平均池化层。特征提取层的最后一个池化层的输出是16通道的5x5特征图,该特征图通过展平操作(Flatten)为16x5x5个元素的一维向量,这个一维向量在输入到全连接层执行分类任务,最后一个全连接层有10个神经元,对应0-9共10个数字的识别概率。 LeNet网络各层结构和参数量的详细信息总结如下: - 输入数据为灰度28x28分辨率的图像,实际上也就是一个28x28的二维数组,只有灰度通道。 - 卷积层C1包含6个5x5x1的卷积核,padding为2,所以卷积层的输出为6张28x28分辨率的特征图,卷积计算结果的激活函数为Sigmoid。 - 该层的参数数量就是6个5x5x1卷积核的权重和偏置,也就是6x(5x5x1+1)。 - 池化层S2采用2x2的平均池化操作,对卷积层C1的6通道28x28分辨率特征图进行池化计算,输出为6通道14x14分辨率的池化后特征图。 - 卷积层C3包含16个5x5x6的立体卷积核,padding为0,所以卷积层C3的输出为16张10x10分辨率的特征图,卷积计算结果的激活函数同样为Sigmoid。 - 该层的参数数量就是16个5x5x6卷积核的权重和偏置,也就是16x(5x5x6+1)。 - 池化层S4仍然采用2x2的平均池化操作,对卷积层C3的16通道10x10分辨率特征图进行池化计算,输出为16通道5x5分辨率的池化后特征图。 - 第一个全连接层F5的输入为池化层S4输出特征图的一维展平向量,因此输入数据是一个5x5x16的一维向量,F5全连接层有120个神经元,激活函数仍然是Sigmoid。 - 该层的参数数量就是120个神经元的输入权重和偏置,也就是120x(5x5x16+1)。 - 第二个全连接层F6的输入为F5的120个神经元的输出,F6全连接层有84个神经元,激活函数为Sigmoid。 - 该层的参数数量就是84个神经元的输入权重和偏置,也就是84x(120+1)。 - 最后的输出层有10个神经元,各个神经元的输出对应于数字0-9的识别概率的大小。 - 该层的参数数量就是10个神经元的输入权重和偏置,也就是10x(84+1)。 以下是LeNet在前向计算过程中各个层的输出向量的维度总结: > 对于以上LeNet的网络结构而言,需要注意: > - 以上的网络结构图中,共包含7层:两个卷积层,两个池化层,三个全连接层。但是实际上一般意义上的LeNet指的是LeNet5,这个数字5表示整个网络中包含参数的层数(即两个卷积层+三个全连接层)。 > - 实际的卷积神经网络的实现中,卷积层的激活函数使用ReLU,池化层采用最大池化方式,在网络的实际表现中性能更好。但是无论是ReLU还是最大池化,在上世纪八九十年代均未出现。所以在原始的LeNet5架构中,卷积层的激活函数采用经典的Sigmoid,池化层则采用平均池化。 > LeNet的PyTorch实现 基于以上介绍的LeNet5模型的网络架构,在PyTorch框架下的该网络实现代码如下: 以上网络实现后导出为Onnx模型文件,在netron.app中的网络架构图如下所示: !image.png 参考资料 - 6.6. 卷积神经网络(LeNet) — 动手学深度学习 2.0.0 documentation - MNIST Demos on Yann LeCun's website
一文总结YOLOv5模型的自定义训练、测试与模型导出的全过程
本文详细总结了基于用户自己指定的训练数据集,对训练数据集及其标注按照YOLO的格式进行预处理,然后对YOLOv5模型进行训练、测试以及ONNX导出等的完整流程。 YOLOv5模型的下载和测试 要对YOLOv5模型进行自定义的训练和部署,首先要做的当然就是下载YOLOv5的源代码。在Github上搜索YOLOv5找到Ultralytics的源代码仓库:ultralytics/yolov5: YOLOv5 🚀 in PyTorch > ONNX > CoreML > TFLite 。 可以看到尽管YOLOv5是比较早期的模型了,但是其开发和维护并没有停止,一直到现在仍然在持续更新中: !image.png 通过Git Clone或者直接使用HTTPS下载最新版本的代码到本地。 下载下来以后,可以先使用默认训练好的模型调用其中的脚本进行一些测试。对于YOLOv5模型的基本测试使用而言,主要用到其中的三个脚本文件:trian.py(训练)、detect.py(新样本数据推理)、export.py(模型导出)。 train.py的主要调用参数: - -weights : 初始权重文件路径,默认为 yolov5s.pt (官方基于COCO数据集预训练好的参数文件,首次使用时会自动下载),用于加载预训练模型 - -cfg : 模型配置文件 (model.yaml) 路径,定义网络结构。默认的模型配置文件在models目录下。 - -data:训练数据集配置文件。默认的数据集配置文件在data目录下。 - -batch-size:训练过程中每个mini batch的数量,一般是8或者16 - -epochs:训练的轮次数量 - -device : 指定 CUDA 设备,如 0 或 0,1,2,3 或 cpu 基于以上weights和cfg参数的设置情况,对于模型的训练可以分为以下情况: - 基于YOLO官方提供的预训练模型参数进行训练:此时就只需要通过weights参数传递预训练模型的pt文件即可,其中已经包含了模型的配置信息。 - 基于YOLO模型从头开始训练:将 weights 参数设为空字符串,并提供 cfg 参数设置模型配置。 - 如果同时在命令中提供了 cfg 和 weights 参数,则会优先使用 cfg 定义的模型结构,并尝试加载 weights 中的权重参数(如果结构匹配)。 detect.py的主要调用参数: - -weights : 指定模型的权重文件路径,默认为 yolov5s.pt 。 - -source : 推理数据的输入源路径,可以是单张图片、视频文件、目录、URL(rtsp、rtmp等)、摄像头索引(0)、屏幕(screen)等。 - -device : 运行设备,可指定为 cpu 或GPU索引(如 0,1 ),默认为自动选择。 - -classes : 指定要检测的类别索引列表,如 --class 0 2 3 ,默认为 None (检测所有类别)。 - -project : 推理结果保存的项目目录,默认为 runs/detect。 - -name : 实验名称(用于创建子目录),默认为 exp。 - -conf-thres:置信度阈值。只有识别的置信度大于该阈值才会输出结果并标记出来。 export.py的主要调用参数: - -data : 模型训练所使用的数据集配置YAML文件路径,默认为 data/coco128.yaml ,用于提供类别信息等元数据。 - -weights : 要导出的模型权重文件路径。 - -batch-size : 批处理大小,默认为 1。 - -include : 指定要导出的模型格式列表,默认为 torchscript ,支持的格式包括: - torchscript : PyTorch的TorchScript格式 - onnx : ONNX格式 - openvino : Intel OpenVINO格式 - engine : NVIDIA TensorRT格式 - coreml : Apple CoreML格式 - saved_model : TensorFlow SavedModel格式 - pb : TensorFlow GraphDef格式 - tflite : TensorFlow Lite格式 - edgetpu : TensorFlow Edge TPU格式 - tfjs : TensorFlow.js格式 - paddle : PaddlePaddle格式 YOLOv5源代码目录中的data子目录里面,包含了多个标准图像数据集的配置文件,可以先使用这些标准数据集及其配置文件测试YOLOv5模型的训练流程(此处使用coco128数据集): > 每次调用以上脚本进行的训练流程,都会在run/train下创建一个exp目录,其中包含有训练过程中所生成的各种中间文件。训练完成后,生成的权重参数文件就是这个目录下的weights/best.pt文件。 同样的,可以使用以下命令对Yolov5源代码中自带的图片,使用detect.py进行推理测试: 以上脚本会对data/images下的所有图片进行推理,推理生成的标注图片在runs/detect/exp目录下。 !image.png 训练数据集的准备 前面对Yolo模型的基本使用做了简单的测试。接下来,就是准备要准备自定义的数据集进行模型的训练了。 本文以口罩检测作为学习案例,网络上有大量的这类公共数据集可用,因此可以直接首先搜索可以满足训练需求的公共数据集。 - 网站kaggle,Roboflow,Huggingface等提供了大量的公开数据集,可以根据自己的需求在这些网站上搜索。 本文以Kaggle上的Face Mask Detection数据集对Yolov5模型进行训练:Face Mask Detection。该数据集对图片中的人是否戴口罩进行检测,整个数据集共853张图片,检测结果有三种:未戴口罩,戴口罩,未正确戴口罩。标注格式为Pascal VOC格式。 !image.png Kaggle上的Face Mask Detection数据集下载后,需要首先对其图片及其标注信息进行预处理,预处理为Yolo模型所需要的格式。对于Face Mask Detection数据集而言,要做的预处理包括: - 把该数据集所采用的Pascal VOC标注格式转换为Yolo格式。 - 把该数据集中的图片和标注集以85:10:5的比例切分为训练集、验证集、测试集三个部分。 - 按照Yolo模型训练所需要的训练数据集目录要求分别保存在train、valid、test三个子目录中。 - 准备该数据集用于Yolo训练的配置描述文件FaceMask.yaml。 Pascal VOC是一种常用的目标检测类型的标注格式,与Yolo模型训练所要求的标注格式大相迥异,所以我专门写了一个voc_to_yolo.py的脚本用于实现以上预处理流程的第1-3步:标注格式转换、数据切分、yolo训练目录结构建立。使用该脚本就可以实现从Pascal VOC数据集到Yolo训练数据集的转换: 下图是Face Mask数据集转换前后的目录结构示意图。 - 转换前的原始数据集中,所有的图片在images目录下,所有的Pascal VOC标注格式的标注信息在annotations目录下。 - 转换后的完整yolo数据集在yolo目录下,其中包含有test、train、valid三个子目录,分别对应测试、训练和验证数据集,其下又包含各自的图片文件子目录和Yolo标注文件子目录。 !image.png 基于以上已经准备好的Yolo格式的训练数据集,整理与之对应的数据集描述配置文件FaceMask.yaml如下。后续在训练过程需要使用该文件指定训练数据集的路径、识别和检测类型名称数量等信息。 模型训练和测试 基于以上预处理好的数据集在Yolov5预训练模型上进行训练: 在CPU上进行训练的时间比较长,不到1000张图片,在我的Thinkpad X260笔记本上训练的时间超过了一天。训练完成后生成的模型参数文件在runs\train\exp9\weights目录下的best.pt文件。 使用以上训练生成的模型参数文件对前一阶段分割出来的测试数据集进行测试: 以上脚本会对datasets\FaceMask\yolo\test\images\所指定的测试数据集中的所有图片进行推理,推理结果保存在runs/detect下的一个新建exp目录中,置信度大于0.5的识别结果会画框标记出来是否有正确的戴口罩。 !image.png 模型的ONNX导出 接下来就可以使用Yolov5源代码目录中的export.py,把前一步骤训练出来的best.pt参数权重文件导出为onnx标准模型文件,在onnxruntime等标准化的环境中进行部署了: 以上脚本执行后就会在best.pt相同路径下生成一个best.onnx文件,这就是模型导出的ONNX文件了。 参考资料 - ultralytics/yolov5: YOLOv5 🚀 in PyTorch > ONNX > CoreML > TFLite 。 - Face Mask Detection