前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >深度学习Pytorch检测实战 - Notes - 第6章 单阶经典检测器:YOLO

深度学习Pytorch检测实战 - Notes - 第6章 单阶经典检测器:YOLO

原创
作者头像
肉松
修改2020-08-27 15:07:55
7260
修改2020-08-27 15:07:55
举报

6.1 无锚框预测:YOLO v1

相比起Faster RCNN的两阶结构,2015年诞生的YOLO v1创造性地使用一阶结构完成了物体检测任务,直接预测物体的类别与位置,没有RPN网络,也没有类似于Anchor的预选框,因此速度很快。

6.1.1 网络结构

与其他物体检测算法一样,YOLO v1首先利用卷积神经网络进行了特征提取,具体结构如图6.1所示,该结构与GoogLeNet模型有些类似。

在该结构中,输出图像的尺寸固定为448×448,经过24个卷积层与两个全连接层后,最后输出的特征图大小为7×7×30。

关于YOLO v1的网络结构,有以下3个细节:

  • 在3×3的卷积后通常会接一个通道数更低的1×1卷积,这种方式既降低了计算量,同时也提升了模型的非线性能力。
  • 除了最后一层使用了线性激活函数外,其余层的激活函数为LeakyReLU。
  • 在训练中使用了Dropout与数据增强的方法来防止过拟合。
图6.1 YOLO v1网络结构
图6.1 YOLO v1网络结构

6.1.2 特征图的意义

YOLO v1的网络结构并无太多创新之处,其精髓主要在最后7×7×30大小的特征图中。如图6.2所示,YOLO v1将输入图像划分成7×7的区域,每一个区域对应于最后特征图上的一个点,该点的通道数为30,代表了预测的30个特征。

YOLO v1在每一个区域内预测两个边框,如图6.2中的预测框A与B,这样整个图上一共预测7×7×2=98个框,这些边框大小与位置各不相同,基本可以覆盖整个图上可能出现的物体。

YOLO v1检测原理图
YOLO v1检测原理图

如果一个物体的中心点落在了某个区域内,则该区域就负责检测该物体。图6.2中真实物体框的中心点在当前区域内,该区域就负责检测该物体,具体是将该区域的两个框与真实物体框进行匹配,IoU更大的框负责回归该真实物体框,在此A框更接近真实物体。最终的预测特征由类别概率、边框的置信度及边框的位置组成。

  • 类别概率:由于PASCAL VOC数据集一共有20个物体类别,因此这里预测的是边框属于哪一个类别。
  • 置信度:表示该区域内是否包含物体的概率,类似于Faster RCNN中是前景还是背景。由于有两个边框,因此会存在两个置信度预测值。
  • 边框位置:对每一个边框需要预测其中心坐标及宽、高这4个量,两个边框共计8个预测值。
预测特征的30维通道含义
预测特征的30维通道含义

这里有以下3点值得注意的细节:

  • YOLO v1并没有先验框,而是直接在每个区域预测框的大小与位置,是一个回归问题。这样做能够成功检测的原因在于,区域本身就包含了一定的位置信息,另外被检测物体的尺度在一个可以回归的范围内。
  • 从图6.3中可以看出,一个区域内的两个边框共用一个类别预测,在训练时会选取与物体IoU更大的一个边框,在测试时会选取置信度更高的一个边框,另一个会被舍弃,因此整张图最多检测出49个物体。
  • YOLO v1采用了物体类别与置信度分开的预测方法,这点与Faster RCNN不同。Faster RCNN将背景也当做了一个类别,共计21种,在类别预测中包含了置信度的预测。

6.1.3 损失计算

通过卷积网络得到每个边框的预测值后,为了进一步计算网络训练的损失,还需要确定每一个边框是对应着真实物体还是背景框,即区分开正、负样本。YOLO v1在确定正负样本时,有以下两个原则:

  • 当一个真实物体的中心点落在了某个区域内时,该区域就负责检测该物体。具体做法是将与该真实物体有最大IoU的边框设为正样本,这个区域的类别真值为该真实物体的类别,该边框的置信度真值为1。
  • 除了上述被赋予正样本的边框,其余边框都为负样本。负样本没有类别损失与边框位置损失,只有置信度损失,其真值为0。

YOLO v1的损失一共由5部分组成,均使用了均方差损失,

公式中i代表第几个区域,一共有S2个区域,在此为49;j代表某个区域的第几个预测边框,一共有B个预测框,在此为2;obj代表该框对应了真实物体;noobj代表该框没有对应真实物体。这5项损失的意义如下:

  • 第一项为正样本中心点坐标的损失。λcoord的目的是为了调节位置损失的权重,YOLO v1设置λcoord为5,调高了位置损失的权重。
  • 第二项为正样本宽高的损失。由于宽高差值受物体尺度的影响,因此这里先对宽高进行了平方根处理,在一定程度上降低对尺度的敏感,强化了小物体的损失权重。
  • 第三、四项分别为正样本与负样本的置信度损失,正样本置信度真值为1,负样本置信度为0。λnoobj默认为0.5,目的是调低负样本置信度损失的权重。
  • 最后一项为正样本的类别损失。

总体上,YOLO v1利用了回归的思想,使用轻量化的一阶网络同时完成了物体的定位与分类,处理速度极快,可以达到45 FPS,当使用更轻量的网络时甚至可以达到155 FPS。得益于其出色的处理速度,YOLOv1被广泛应用在实际的工业场景中,尤其是追求实时处理的场景。当然,YOLO v1也有一些不足之处,主要有如下3点:

  • 由于每一个区域默认只有两个边框做预测,并且只有一个类别,因此YOLO v1有着天然的检测限制。这种限制会导致模型对于小物体,以及靠得特别近的物体检测效果不好。
  • 由于没有类似于Anchor的先验框,模型对于新的或者不常见宽高比例的物体检测效果不好。另外,由于下采样率较大,边框的检测精度不高。
  • 在损失函数中,大物体的位置损失权重与小物体的位置损失权重是一样的,这会导致同等比例的位置误差,大物体的损失会比小物体大,小物体的损失在总损失中占比较小,会带来物体定位的不准确。

6.2 依赖锚框:YOLO v2

6.2.1 网络结构的改善

首先,YOLO v2对于基础网络结构进行了多种优化,提出了一个全新的网络结构,称之为DarkNet。原始的DarkNet拥有19个卷积层与5个池化层,在增加了一个Passthrough层后一共拥有22个卷积层,精度与VGGNet相当,但浮点运算量只有VGGNet的1/5左右,因此速度极快。

相比起v1版本的基础网络,DarkNet进行了以下几点改进:

  • BN层:DarkNet使用了BN层,这一点带来了2%以上的性能提升。BN层有助于解决反向传播中的梯度消失与爆炸问题,可以加速模型的收敛,同时起到一定的正则化作用。BN层的具体位置是在每一个卷积之后,激活函数LeakyReLU之前。
  • 用连续3×3卷积替代了v1版本中的7×7卷积,这样既减少了计算量,又增加了网络深度。此外,DarkNet去掉了全连接层与Dropout层。
  • Passthrough层:DarkNet还进行了深浅层特征的融合,具体方法是将浅层26×26×512的特征变换为13×13×2048,这样就可以直接与深层13×13×1024的特征进行通道拼接。这种特征融合有利于小物体的检测,也为模型带来了1%的性能提升。
  • 由于YOLO v2在每一个区域预测5个边框每个边框有25个预测值,因此最后输出的特征图通道数为125。其中,一个边框的25个预测值分别是20个类别预测、4个位置预测及1个置信度预测值。这里与v1有很大区别,v1是一个区域内的边框共享类别预测,而这里则是相互独立的类别预测值。

6.2.2 先验框的设计

YOLO v2吸收了Faster RCNN的优点,设置了一定数量的预选框,使得模型不需要直接预测物体尺度与坐标,只需要预测先验框到真实物体的偏移,降低了预测难度。

关于先验框,YOLO v2首先使用了聚类的算法来确定先验框的尺度,并且优化了后续的偏移计算方法,下面详细介绍这两部分。

先验框的设计为YOLO v2带来了7%的召回率提升。

1.聚类提取先验框尺度

Faster RCNN中预选框(即Anchor)的大小与宽高是由人手工设计的,因此很难确定设计出的一组预选框是最贴合数据集的,也就有可能为模型性能带来负面影响。

针对此问题,YOLO v2通过在训练集上聚类来获得预选框,只需要设定预选框的数量k,就可以利用聚类算法得到最适合的k个框。在聚类时,两个边框之间的距离使用式(6-2)的计算方法,即IoU越大,边框距离越近。

在衡量一组预选框的好坏时,使用真实物体与这一组预选框的平均IoU作为标准。值得一提的是,这一判断标准在手工设计预选框的方法中也可以使用。

至于预选框的数量选取,显然数量k越多,平均IoU会越大,效果会更好,但相应的也会带来计算量的提升,YOLO v2在速度与精度的权衡中选择了预选框数量为5。

2.优化偏移公式

有了先验框后,YOLO v2不再直接预测边框的位置坐标,而是预测先验框与真实物体的偏移量。在Faster RCNN中,中心坐标的偏移公式如式(6-3)所示。

公式中wa、ha、xa及ya代表Anchor的宽高与中心坐标,tx与ty是模型预测的Anchor相对于真实物体的偏移量,经过计算后得到预测的物体中心坐标x和y。

YOLO v2认为这种预测方式没有对预测偏移进行限制,导致预测的边框中心可以出现在图像的任何位置,尤其是在训练初始阶段,模型参数还相对不稳定。例如tx是1与-1时,预测的物体中心点会有两个宽度的差距。

因此,YOLO v2提出了式(6-4)所示的预测公式:

公式中参数的意义可以与图6.5结合进行理解,图中实线框代表预测框,虚线框代表先验框:

  • cx与cy代表中心点所处区域左上角的坐标,pw与ph代表了当前先验框的宽高,如图6.5中的虚线框所示。
  • σ(tx)与σ(ty)代表预测框中心点与中心点所处区域左上角坐标的距离,加上cx与cy即得到预测框的中心坐标。
  • tw与th为预测的宽高偏移量。先验框的宽高乘上指数化后的宽高偏移量,即得到预测框的宽高。
  • 公式中的σ代表Sigmoid函数,作用是将坐标偏移量化到(0,1)区间,这样得到的预测边框的中心坐标bx、by会限制在当前区域内,保证一个区域只预测中心点在该区域内的物体,有利于模型收敛。
  • YOLO v1将预测值t0作为边框的置信度,而YOLO v2则是将做Sigmoid变换后的σ(t0)作为真正的置信度预测值。
图6.5 YOLO v2预测值的含义
图6.5 YOLO v2预测值的含义

6.2.3 正、负样本与损失函数

关于正、负样本的选取,YOLO v2基本保持了之前的方法,其基本流程如下:

  1. 首先利用式(6-4),将预测的位置偏移量作用到先验框上,得到预测框的真实位置。
  2. 如果一个预测框与所有真实物体的最大IoU小于一定阈值(默认为0.6)时,该预测框视为负样本。
  3. 每一个真实物体的中心点落在了某个区域内,该区域就负责检测该物体。具体做法是将与该物体有最大IoU的预测框视为正样本。
  4. 确定了正样本与负样本后,最后是网络损失的计算。

由于利用了先验框,YOLO v2的损失函数也相应的进行了改变,公式如式(6-5)所示。

损失一共有5项组成,意义分别如下:

  • 第一项为负样本的置信度损失,公式中1max IoU<Thresh表示最大IoU小于阈值,即负样本的边框,λnoobj是负样本损失的权重,boijk为置信度σ(to)。
  • 第二项为先验框与预测框的损失,只存在于前12800次迭代中,目的是使预测框先收敛于先验框,模型更稳定。
  • 第三项为正样本的位置损失,表示筛选出的正样本,为权重。
  • 后两项分别为正样本的置信度损失与类别损失,为置信度的真值。

在计算正、负样本的过程中,虽然有些预测框的最大IoU可能小于0.6,即被赋予了负样本,但如果后续是某一个真实物体对应的最大IoU的框时,该预测框会被最终赋予成正样本,以保证recall。

有些预测框的最大IoU大于0.6,但是在一个区域内又不是与真实物体有最大IoU,这种预测框会被舍弃掉不参与损失计算,既不是正样本也不是负样本

6.2.5 工程技巧

除了模型上的改进,YOLO v2也是一个充满工程技巧的检测模型,下面从两个方面介绍其工程上的特点。

1.多尺度训练

由于移除了全连接层,因此YOLO v2可以接受任意尺寸的输入图片。在训练阶段,为了使模型对于不同尺度的物体鲁棒,YOLO v2采取了多种尺度的图片作为训练的输入。

由于下采样率为32,为了满足整除的需求,YOLO v2选取的输入尺度集合为{320,352,384,...,608},这样训练出的模型可以预测多个尺度的物体。并且,输入图片的尺度越大则精度越高,尺度越低则速度越快,因此YOLO v2多尺度训练出的模型可以适应多种不同的场景要求。

2.多阶段训练

由于物体检测数据标注成本较高,因此大多数物体检测模型都是先利用分类数据集来训练卷积层,然后再在物体检测数据集上训练。例如,YOLO v1先利用ImageNet上224×224大小的图像预训练,然后在448×448的尺度上进行物体检测的训练。这种转变使得模型要适应突变的图像尺度,增加了训练难度。

YOLO v2针对以上问题,优化了训练过程,采用如图6.6所示的训练方式,具体过程如下:

(1)利用DarkNet网络在ImageNet上预训练分类任务,图像尺度为224×224。

(2)将ImageNet图片放大到448×448,继续训练分类任务,让模型首先适应变化的尺度。

(3)去掉分类卷积层,在DarkNet上增加Passthrough层及3个卷积层,利用尺度为448×448的输入图像完成物体检测的训练。

总体上来看,YOLO v2相较于之前的版本有了质的飞跃,主要体现在吸收了其他算法的优点,使用了先验框、特征融合等方法,同时利用了多种训练技巧,使得模型在保持极快速度的同时大幅度提升了检测的精度。YOLO v2已经达到了较高的检测水平,但如果要分析其不足的话,大体有以下3点:

  • 单层特征图:虽然采用了Passthrough层来融合浅层的特征,增强多尺度检测性能,但仅仅采用一层特征图做预测,细粒度仍然不够,对小物体等检测提升有限,并且没有使用残差这种较为简单、有效的结构。
  • 受限于其整体结构,依然没有很好地解决小物体的检测问题。
  • 太工程化:YOLO v2的整体实现有较多工程化调参的过程,尤其是后续损失计算有些复杂,不是特别“优雅”,导致后续改进与扩展空间不足。

YOLO V3 论文翻译:

https://zhuanlan.zhihu.com/p/37201615

YOLO3网络结构
YOLO3网络结构
输入 - 输出
输入 - 输出

YOLO V3代码

ModuleList(

(0): Sequential( (conv_0): Conv2d(3, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False) )

(1): Sequential( (conv_1): Conv2d(32, 64, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False) ) # 第一次下采样

代码语言:python
复制
(2): Sequential((conv_2): Conv2d(64, 32, kernel_size=(1, 1), stride=(1, 1), bias=False))
(3): Sequential((conv_3): Conv2d(32, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False))
(4): Sequential((shortcut_4): EmptyLayer())

(5): Sequential( (conv_5): Conv2d(64, 128, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False) ) # 第二次下采样

代码语言:python
复制
  (6): Sequential( (conv_6): Conv2d(128, 64, kernel_size=(1, 1), stride=(1, 1), bias=False) )
  (7): Sequential((conv_7): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)  )
  (8): Sequential( (shortcut_8): EmptyLayer() )
代码语言:python
复制
  (9): Sequential( (conv_9): Conv2d(128, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)  )
  (10): Sequential(  (conv_10): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)  )
  (11): Sequential(  (shortcut_11): EmptyLayer())

(12): Sequential( (conv_12): Conv2d(128, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False) ) # 第三次下采样

代码语言:python
复制
  (13): Sequential( (conv_13): Conv2d(256, 128, kernel_size=(1, 1), stride=(1, 1), bias=False))
  (14): Sequential( (conv_14): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False) )
  (15): Sequential( (shortcut_15): EmptyLayer( )
代码语言:javascript
复制
  (16): Sequential( (conv_16): Conv2d(256, 128, kernel_size=(1, 1), stride=(1, 1), bias=False) )
  (17): Sequential( (conv_17): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False))
  (18): Sequential((shortcut_18): EmptyLayer())
代码语言:javascript
复制
  (19): Sequential( (conv_19): Conv2d(256, 128, kernel_size=(1, 1), stride=(1, 1), bias=False))
  (20): Sequential( (conv_20): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False))
  (21): Sequential(  (shortcut_21): EmptyLayer())
代码语言:javascript
复制
  (22): Sequential(   (conv_22): Conv2d(256, 128, kernel_size=(1, 1), stride=(1, 1), bias=False) )
  (23): Sequential( (conv_23): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False) )
  (24): Sequential( (shortcut_24): EmptyLayer() )
代码语言:javascript
复制
  (25): Sequential( (conv_25): Conv2d(256, 128, kernel_size=(1, 1), stride=(1, 1), bias=False) )
  (26): Sequential( (conv_26): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False) )
  (27): Sequential(  (shortcut_27): EmptyLayer() )
代码语言:javascript
复制
  (28): Sequential(  (conv_28): Conv2d(256, 128, kernel_size=(1, 1), stride=(1, 1), bias=False)  )
  (29): Sequential(   (conv_29): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)     )
  (30): Sequential( (shortcut_30): EmptyLayer())
代码语言:javascript
复制
  (31): Sequential  (conv_31): Conv2d(256, 128, kernel_size=(1, 1), stride=(1, 1), bias=False))
  (32): Sequential(    (conv_32): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)  )
  (33): Sequential(    (shortcut_33): EmptyLayer()  )
代码语言:javascript
复制
  (34): Sequential(    (conv_34): Conv2d(256, 128, kernel_size=(1, 1), stride=(1, 1), bias=False)  )
  (35): Sequential(    (conv_35): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)  )
  (36): Sequential(    (shortcut_36): EmptyLayer()  )

(37): Sequential( (conv_37): Conv2d(256, 512, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False) ) # 第四次下采样

代码语言:javascript
复制
  (38): Sequential(    (conv_38): Conv2d(512, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)  )
  (39): Sequential(    (conv_39): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)  )
  (40): Sequential(    (shortcut_40): EmptyLayer()  )
代码语言:javascript
复制
  (41): Sequential(    (conv_41): Conv2d(512, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)  )
  (42): Sequential(    (conv_42): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)  )
  (43): Sequential(    (shortcut_43): EmptyLayer()  )
代码语言:javascript
复制
  (44): Sequential(    (conv_44): Conv2d(512, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)  )
  (45): Sequential(    (conv_45): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)     )
  (46): Sequential(    (shortcut_46): EmptyLayer()  )
代码语言:javascript
复制
  (47): Sequential(    (conv_47): Conv2d(512, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)     )
  (48): Sequential(    (conv_48): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)  )
  (49): Sequential(    (shortcut_49): EmptyLayer()  )
代码语言:javascript
复制
  (50): Sequential(    (conv_50): Conv2d(512, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)  )
  (51): Sequential(    (conv_51): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)   )
  (52): Sequential(    (shortcut_52): EmptyLayer()  )
代码语言:javascript
复制
  (53): Sequential(    (conv_53): Conv2d(512, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)  )
  (54): Sequential(    (conv_54): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)  )
  (55): Sequential(    (shortcut_55): EmptyLayer(  )
代码语言:javascript
复制
  (56): Sequential(    (conv_56): Conv2d(512, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)     )
  (57): Sequential    (conv_57): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)  )
  (58): Sequential(    (shortcut_58): EmptyLayer()  )
代码语言:javascript
复制
  (59): Sequential(    (conv_59): Conv2d(512, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)    )
  (60): Sequential(    (conv_60): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)    )
  (61): Sequential(    (shortcut_61): EmptyLayer()  )

(62): Sequential( (conv_62): Conv2d(512, 1024, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False) ) # 第五次下采样

代码语言:javascript
复制
  (63): Sequential(    (conv_63): Conv2d(1024, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)   )
  (64): Sequential(    (conv_64): Conv2d(512, 1024, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)  )
  (65): Sequential(    (shortcut_65): EmptyLayer()  )
代码语言:javascript
复制
  (66): Sequential(    (conv_66): Conv2d(1024, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)   )
  (67): Sequential(  (conv_67): Conv2d(512, 1024, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)    )
  (68): Sequential(    (shortcut_68): EmptyLayer()  )
代码语言:javascript
复制
  (69): Sequential(    (conv_69): Conv2d(1024, 512, kernel_size=(1, 1), stride=(1, 1), bias=False) )
  (70): Sequential(    (conv_70): Conv2d(512, 1024, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)  )
  (71): Sequential(    (shortcut_71): EmptyLayer()  )
代码语言:javascript
复制
  (72): Sequential(    (conv_72): Conv2d(1024, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)  )
  (73): Sequential(    (conv_73): Conv2d(512, 1024, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)    )
  (74): Sequential(    (shortcut_74): EmptyLayer()  )

代码语言:javascript
复制
 (75): Sequential(    (conv_75): Conv2d(1024, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)  )
  (76): Sequential(    (conv_76): Conv2d(512, 1024, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)    )
  (77): Sequential(    (conv_77): Conv2d(1024, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)  )
  (78): Sequential(   (conv_78): Conv2d(512, 1024, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)   )
  (79): Sequential(    (conv_79): Conv2d(1024, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)  )
  (80): Sequential(    (conv_80): Conv2d(512, 1024, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)  )
  (81): Sequential(    (conv_81): Conv2d(1024, 255, kernel_size=(1, 1), stride=(1, 1))  )

(82): Sequential( (Detection_82): DetectionLayer() ) # 32倍降采样

(83): Sequential( (route_83): EmptyLayer() ) # 此处route层直接把79层处特征取过来

(84): Sequential( (conv_84): Conv2d(512, 256, kernel_size=(1, 1), stride=(1, 1), bias=False) )

(85): Sequential( (upsample_85): Upsample(scale_factor=2.0, mode=nearest) )

(86): Sequential( (route_86): EmptyLayer() ) # 此处route将85和61层的特征拼接在一起

代码语言:javascript
复制
  (87): Sequential(    (conv_87): Conv2d(768, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)  )
  (88): Sequential(    (conv_88): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)     )
  (89): Sequential(    (conv_89): Conv2d(512, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)    )
  (90): Sequential(    (conv_90): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)   )
  (91): Sequential(    (conv_91): Conv2d(512, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)  )
  (92): Sequential(    (conv_92): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)   )
  (93): Sequential(    (conv_93): Conv2d(512, 255, kernel_size=(1, 1), stride=(1, 1))  )

(94): Sequential( (Detection_94): DetectionLayer() ) # 16倍降采样

(95): Sequential( (route_95): EmptyLayer() ) # 此处route层直接把91层处特征取过来

(96): Sequential( (conv_96): Conv2d(256, 128, kernel_size=(1, 1), stride=(1, 1), bias=False) )

(97): Sequential( (upsample_97): Upsample(scale_factor=2.0, mode=nearest) )

(98): Sequential( (route_98): EmptyLayer() ) # 此处route将97层和36层特征拼接在一起

代码语言:javascript
复制
  (99): Sequential(    (conv_99): Conv2d(384, 128, kernel_size=(1, 1), stride=(1, 1), bias=False)  )
  (100): Sequential(    (conv_100): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)  )
  (101): Sequential(    (conv_101): Conv2d(256, 128, kernel_size=(1, 1), stride=(1, 1), bias=False)   )
  (102): Sequential(    (conv_102): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)  )
  (103): Sequential(    (conv_103): Conv2d(256, 128, kernel_size=(1, 1), stride=(1, 1), bias=False) ) 
 (104): Sequential(   (conv_104): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)  )
  (105): Sequential(    (conv_105): Conv2d(256, 255, kernel_size=(1, 1), stride=(1, 1))  )

(106): Sequential( (Detection_106): DetectionLayer() )) # 8倍降采样

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 6.1 无锚框预测:YOLO v1
  • 6.2 依赖锚框:YOLO v2
  • YOLO V3 论文翻译:
  • YOLO V3代码
相关产品与服务
图像识别
腾讯云图像识别基于深度学习等人工智能技术,提供车辆,物体及场景等检测和识别服务, 已上线产品子功能包含车辆识别,商品识别,宠物识别,文件封识别等,更多功能接口敬请期待。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档