深入浅出之DarkNet网络

2024-07-06

一、VGG网络

深入浅出之VGGNet网络-CSDN博客文章浏览阅读375次,点赞2次,收藏2次。VGGNet(Visual Geometry Group Network)是一种深度卷积神经网络,由牛津大学计算机视觉组(Visual Geometry Group)的研究团队于2014年提出。VGGNet在当时的ImageNet图像识别挑战中取得了优异的表现,并成为了深度学习和计算机视觉领域中的经典模型之一。以下是对VGGNet的详细解析:VGGNet提供了多种网络结构,如VGG-11、VGG-13、VGG-16和VGG-19等,这些网络结构的基本架构相似,但卷积核的数量和深度有所不同。以VGG-16为例_vggnethttps://blog.csdn.net/a8039974/article/details/141906452https://blog.csdn.net/a8039974/article/details/141906452

VGGNet各级别网络结构图

VGG16包含了16个隐藏层(13个卷积层+3个全连接层),如图中的D列所示

VGG19包含了19个隐藏层(16个卷积层+3个全连接层),如图中的E列所示

VGG网络的结构非常一致,从头到尾全部使用的是3x3的卷积核和2x2的池化核

二、NIN网络

深入浅出之NIN网络-CSDN博客文章浏览阅读1.2k次,点赞27次,收藏11次。NIN网络由加州大学伯克利分校的研究团队提出,并在《Network In Network》论文中进行了详细阐述。该论文发表于ICLR-2014,NIN以一种全新的角度审视了卷积神经网络中的卷积核设计,通过引入子网络结构代替纯卷积中的线性映射部分,从而提高了网络的表达能力和非线性特性。_nin网络https://blog.csdn.net/a8039974/article/details/143110885https://blog.csdn.net/a8039974/article/details/143110885NiN块以一个普通卷积层开始,后面是两个1×1的卷积层。这两个1×1卷积层充当带有ReLU激活函数的逐像素全连接层。 第一层的卷积窗口形状通常由用户设置。 随后的卷积窗口形状固定为1×1。

三、Darknet 19

3.1 概述

Darknet-19 是Joseph Redmon 于2016年提出的。 Darknet-19 是 YOLO v2 的 backbone。Darknet-19 总共有 19 层 conv 层, 5 个 maxpooling 层。Darknet-19 吸收了 VGG16, NIN 等网络的优点,网络结构小巧,但是性能强悍。

提出背景:

Darknet19是YOLOv2目标检测算法中的骨干网络,由Joseph Redmon于2016年提出。它旨在通过紧凑的网络结构实现高效的目标检测性能。

主要贡献:

Darknet19结合了VGG16和NIN的优点,设计了一个轻量级的卷积神经网络,用于目标检测任务。它在保持与ResNet相当分类精度的同时,提供了更快的计算速度。

特点:

结构紧凑,参数少,计算效率高。

融合了多种网络结构的优点,如VGG的卷积核大小和NIN的1x1卷积核。

在计算速度和精度之间取得了良好的平衡。

优缺点:

优点:计算速度快,模型参数少,易于部署。

缺点:随着更复杂的网络结构出现,Darknet19的表达能力可能受限,特别是在处理更复杂场景或更高精度要求的任务时。

应用场景:

Darknet19广泛应用于目标检测任务,特别是在实时性要求较高的场景,如自动驾驶、视频监控等领域。同时,它也可以用于图像分类等任务。

3.2 网络结构:

Darknet19包含19个卷积层,5个最大池化层,无全连接层,使用了Avgpool。卷积层主要使用3x3的卷积核,部分层使用1x1卷积核进行特征降维。

实际输入为416 ∗ 416 416*416416∗416

没有FC层,5次降采样(MaxPool),19个卷积层

使用Batch Normilazation来让训练更稳定,加速收敛,使model规范化。

使用Global Average Pooling

YOLOV2网络结构

3.3 darknet 19相对VGG优势

Darknet-19相对于VGG的优势主要体现在以下几个方面:

1. 网络结构的简洁性与高效性

Darknet-19:网络结构相对简洁,主要由卷积层、池化层和批量归一化层组成,没有VGG中那么多的全连接层。这种设计使得Darknet-19在保持高性能的同时,减少了计算量和参数数量,提高了计算效率。

VGG:虽然VGG网络在图像分类等任务中表现出色,但其网络结构相对较深且复杂,包含多个全连接层,这在一定程度上增加了计算负担和参数数量。

2. 参数量与计算量

Darknet-19:通过精心设计的网络结构和参数配置,Darknet-19在保持高性能的同时,显著减少了参数量和计算量。这使得Darknet-19在资源受限的环境下(如移动设备或嵌入式系统)具有更好的应用前景。

VGG:虽然VGG通过堆叠多个小卷积核(如3x3)来减少参数数量并降低过拟合风险,但其整体参数量和计算量仍然相对较大。

3. 训练与收敛速度

Darknet-19:由于其简洁的网络结构和较少的参数量,Darknet-19在训练过程中通常具有较快的收敛速度。这意味着在相同的时间内,Darknet-19可以完成更多的训练迭代,从而更快地达到或接近最优性能。

VGG:虽然VGG也能够在训练过程中逐渐收敛并达到较高的性能水平,但由于其网络结构的复杂性和较大的参数量,其收敛速度可能相对较慢。

4. 泛化能力与适应性

Darknet-19:由于其简洁而高效的网络设计,Darknet-19在多个数据集和任务上均表现出良好的泛化能力和适应性。这使得Darknet-19能够广泛应用于各种计算机视觉任务中。

VGG:VGG同样具有较强的泛化能力和适应性,但其相对复杂的网络结构可能在一定程度上限制了其在某些特定场景下的应用。

5. 应用场景

Darknet-19:由于其高效性和简洁性,Darknet-19特别适用于对计算资源和存储资源有严格限制的应用场景,如移动设备、嵌入式系统以及实时图像处理等。

VGG:VGG则更适用于对计算资源和存储资源要求相对宽松的应用场景,如高性能计算集群、数据中心等。

综上所述,Darknet-19相对于VGG的优势主要体现在网络结构的简洁性与高效性、参数量与计算量的减少、训练与收敛速度的加快以及泛化能力与适应性的提升等方面。这些优势使得Darknet-19在资源受限的环境下具有更好的应用前景和竞争力。

3.4 darknet-19和vgg-16哪个更优

Darknet-19和VGG-16各有其优势和适用场景,无法简单地判断哪个更优,而是需要根据具体的应用需求和资源限制来选择。以下是对两者优缺点的详细比较:

Darknet-19的优势:

网络结构简洁高效:Darknet-19的网络结构相对简洁,主要由卷积层、池化层和批量归一化层组成,没有复杂的全连接层,这减少了计算量和参数数量,提高了计算效率。

计算速度快:由于其简洁的网络结构和较少的参数量,Darknet-19在处理图像时的速度通常比VGG-16更快。例如,在处理一张图片时,Darknet-19可能比VGG-16快6倍左右。

训练收敛快:较少的参数和计算量使得Darknet-19在训练过程中通常具有较快的收敛速度,能够更快地达到或接近最优性能。

适用于资源受限环境:由于其高效性,Darknet-19特别适用于对计算资源和存储资源有严格限制的应用场景,如移动设备、嵌入式系统等。

VGG-16的优势:

性能稳定:VGG-16作为一种经典的卷积神经网络架构,经过长时间的验证和优化,其性能相对稳定可靠。

准确率高:在多个基准测试上,VGG-16都表现出了较高的准确率,尤其是在图像分类等任务中。

可扩展性强:VGG-16的网络结构具有一定的可扩展性,可以通过增加卷积层或全连接层等方式来进一步提升性能。

适用于复杂任务:由于其较深的网络结构和强大的特征提取能力,VGG-16适用于处理更复杂的计算机视觉任务。

综合考虑:

如果应用场景对计算速度和资源限制有较高要求,且对准确率的要求不是极端严格,那么Darknet-19可能是一个更好的选择。

如果应用场景对准确率有较高要求,且计算资源和存储资源相对充足,那么VGG-16可能更适合。

总之,Darknet-19和VGG-16各有千秋,选择哪个更优取决于具体的应用需求和资源限制。在实际应用中,可以根据具体情况进行权衡和选择。

3.5 pytorch实现

class DarkNet19(nn.Module):

"""DarkNet19 """

def __init__(self, num_classes: int = 1000, init_weight: bool = True) -> None:

super().__init__()

if init_weight:

self.apply(_initialize_weights)

self.features = nn.Sequential(

Conv(in_channels=3, out_channels=32, kernel_size=3),

nn.MaxPool2d(kernel_size=2, stride=2),

Conv(in_channels=32, out_channels=64, kernel_size=3),

nn.MaxPool2d(kernel_size=2, stride=2),

Conv(in_channels=64, out_channels=128, kernel_size=3),

Conv(in_channels=128, out_channels=64, kernel_size=1),

Conv(in_channels=64, out_channels=128, kernel_size=3),

nn.MaxPool2d(kernel_size=2, stride=2),

Conv(in_channels=128, out_channels=256, kernel_size=3),

Conv(in_channels=256, out_channels=128, kernel_size=1),

Conv(in_channels=128, out_channels=256, kernel_size=3),

nn.MaxPool2d(kernel_size=2, stride=2),

Conv(in_channels=256, out_channels=512, kernel_size=3),

Conv(in_channels=512, out_channels=256, kernel_size=1),

Conv(in_channels=256, out_channels=512, kernel_size=3),

Conv(in_channels=512, out_channels=256, kernel_size=1),

Conv(in_channels=256, out_channels=512, kernel_size=3),

nn.MaxPool2d(kernel_size=2, stride=2),

Conv(in_channels=512, out_channels=1024, kernel_size=3),

Conv(in_channels=1024, out_channels=512, kernel_size=1),

Conv(in_channels=512, out_channels=1024, kernel_size=3),

Conv(in_channels=1024, out_channels=512, kernel_size=1),

Conv(in_channels=512, out_channels=1024, kernel_size=3),

)

self.classifier = nn.Sequential(

*self.features,

Conv(in_channels=1024, out_channels=num_classes, kernel_size=1),

GlobalAvgPool2d()

)

def forward(self, x: torch.Tensor) -> torch.Tensor:

out = self.classifier(x)

return out

四、Darkent 53

4.1、 概述

1、提出背景与时间

Darknet53是在深度学习,尤其是卷积神经网络(CNN)快速发展的背景下提出的。随着计算机视觉任务的复杂度和精度要求不断提高,传统的网络结构已经难以满足需求。为了提升目标检测和分类等任务的性能,Joseph Redmon在2018年的论文《YOLOv3: An Incremental Improvement》中提出了Darknet53网络结构,作为YOLOv3目标检测算法的核心网络。

2、作者

Darknet53的作者是Joseph Redmon,他是一位在深度学习领域具有显著贡献的研究者,特别是在目标检测领域。同时,也有说法认为Darknet53是由Joseph Redmon和Ali Farhadi共同提出的,但通常认为Joseph Redmon是主要的贡献者。

3、主要贡献

Darknet53的主要贡献在于其高效的网络结构和强大的特征提取能力。它采用了残差连接和跨层连接等技术,提高了网络的稳定性和准确性。同时,Darknet53的网络结构相对简洁,参数量较少,计算效率高,使得它在目标检测和图像分类等任务中表现出色。

4、特点

高效性:Darknet53采用残差连接和跨层连接等技术,提高了网络的计算效率和收敛速度。

强大的特征提取能力:通过堆叠多个卷积层和残差块,Darknet53能够提取到更高级别的图像特征。

参数量少:相比其他深度神经网络框架,Darknet53的参数量较少,使得模型更快、更容易训练和优化。

可扩展性:使用残差结构,可以轻松地增加更多的卷积层来提高网络的性能。

5、优缺点

优点:

高效性:计算速度快,推理效率高。

强大的特征提取能力:能够提取到丰富的图像特征。

参数量少:模型较小,易于训练和部署。

缺点:

对于某些极端复杂或特殊的任务,可能需要更深的网络结构或更复杂的模型来进一步提升性能。

6、应用场景

Darknet53因其高效性和强大的特征提取能力,被广泛应用于计算机视觉领域的各种任务中,包括但不限于:

图像分类:对图像中的物体进行分类。

目标检测:在图像中检测和定位多个目标。

人脸识别:通过图像进行人脸识别和身份验证。

自动驾驶:在自动驾驶汽车中进行道路识别、车辆检测等任务。

总之,Darknet53作为一种高效的卷积神经网络架构,在计算机视觉领域具有广泛的应用前景和重要的研究价值。

4.2、网络结构

Darknet53的网络结构主要由卷积层、残差块和池化层组成。具体来说,它包括53个卷积层(但通常说法是有52个卷积层和1个输出层,共53层)和5个最大池化层。网络被划分为前段、中段和后段三部分。前段主要由卷积层和最大池化层组成,用于提取图像的初步特征;中段主要由残差块组成,通过残差连接增强特征提取能力并加速收敛;后段则通过全局平均池化层和全连接层输出最终的预测结果。

yolo v3用于提取特征的backbone是Darknet-53,他借鉴了yolo v2中的网络(Darknet-19)结构,在名字上我们也可以窥出端倪。不同于Darknet-19的是,Darknet-53引入了大量的残差结构,并且使用步长为2,卷积核大小为3×3卷积层Conv2D代替池化层Maxpooling2D。通过在ImageNet上的分类表现,Darknet-53经过以上改造在保证准确率的同时极大地提升了网络的运行速度,证明了Darknet-53在特征提取能力上的有效性。

YOLOV3网络结构

图1中为Darknet-53的网络结构图。从图1中可以看出,网络中堆叠了大量的残差结构Residual,而且每两个残差结构之间插着一个步长为2,卷积核大小为3×3卷积层,用于完成下采样的操作。在源码中,Darknet-53网络的输入尺寸是416416,最后卷积层输出的特征图尺寸为1313,通道数为1024。如果是分类任务,最后一个残差结构之后接入全局池化层Global Avgpool,1000个神经元的全连接层Connected,以及一个激活函数层Softmax。但是,在YOLO v3中,Darknet-53只用于提取特征,所以没有最后的这三层,只是输出了三种不同尺寸的特征图(13 * 13、26 * 26、52 * 52)。

图2中展示了Darknet-53中堆叠的残差单元的结构图。其中Input和Output分别是残差单元的输入和输出,In_channels是输入的通道数,h,w分别为输入的高和宽。

从图2中可以看到,输入首先经过一个1×1的卷积层Conv(1×1,stride=1)将通道数降低一半 ,然后进入一个3×3的卷积层Conv(3×3,stride=1)进行特征提取,这时通道数又恢复为In_channels。最后3×3卷积的输出与经过Shorcut传递过来的输入Input相加得到最终的Output(此时3×3卷积的输出与Input的形状(In_channels,h,w)相同,可以直接相加)。我们看到,经过Residual运算之后,输入的特征图形状保持不变。

从图1中我们可以看到,Darknet-53中总共有6个单独的卷积层和23个Residual,每个Residual包含2个卷积层(一个1×1,一个3×3),所以Darknet-53中共有52层卷积,可为什么叫做Darknet-53呢?因为Darknet-53在YOLO v3中,前52层只用作特征提取,最后一层是用于输出预测值的,故加上输出那一层称为Darknet-53。

网络结构设计理念 Darknet-53在Darknet-19的基础上增加了大量的残差结构Residual,并且使用步长为2,卷积核大小为3×3卷积层Conv2D代替池化层Maxpooling2D。作者为什么要做这两点改进呢?

残差结构 首先,加入残差结构Residual的目的是为了增加网络的深度,用于支持网络提取更高级别的语义特征,同时残差的结构可以帮助我们避免梯度的消失或爆炸。因为残差的物理结构,反映到反向梯度传播中,可以使得梯度传递到前面很远的网络层中,削弱反向求导的链式反应。 其次,我们看到残差结构单元里边输入首先会经过一个1×1的卷积层将输入通道降低一半,然后再进行3×3的卷积,这在相当程度上帮助网络减少了计算量,使得网络的运行速度更快,效率更高。

步长为2的卷积替换池化层 从作用上来说,步长为2的卷积替换池化层都可以完成下采样的工作,但其实现在的神经网络中,池化层已经比较少了,大家都开始尝试其他的下采样方法,比如步长为2的卷积。那么为什么要这样替换呢?参考CNN为什么不需要池化层下采样了?. 对于池化层和步长为2的卷积层来说,个人的理解是这样的,池化层是一种先验的下采样方式,即人为的确定好下采样的规则(选取覆盖范围内最大的那个值,默认最大值包含的信息是最多的);而对于步长为2的卷积层来说,其参数是通过学习得到的,采样的规则是不确定的,这种不确定性会增加网络的学习能力。

网络性能评估

图3. 不同backbone的性能对比 不同backbone进行比较的前提是每个网络都使用相同的设置进行训练,并以 256×256 的单裁剪精度进行测试。 运行时间(FPS)是在 Titan X 上以 256 × 256 的分辨率测量的。因此,从图3中,我们可以看出Darknet-53 的性能与最先进的分类器相当,但浮点运算更少,速度更快。Darknet-53比ResNet-101好,快1.5倍。Darknet-53 的性能与 ResNet-152相似,速度快2倍 Darknet-53 还实现了每秒最高测量浮点运算。 这意味着网络结构更好地利用了 GPU,使其评估效率更高,从而更快。 这主要是因为 ResNet 的层太多并且效率不高。

更多残差结构知识详见:

深入浅出之Bottleneck层、Res unit和ResX模块(YOLO)-CSDN博客文章浏览阅读726次,点赞8次,收藏13次。在YOLO系列算法中,Res unit(残差单元)和ResX是两个重要的组件,它们在网络结构中扮演着关键角色。以下是对这两个组件的详细解释:Res unit是借鉴了ResNet(残差网络)中的残差结构,旨在解决深层网络训练中的梯度消失或梯度爆炸问题,使网络能够构建得更深。在YOLO系列中,Res unit允许网络在增加深度的同时,保持较好的训练效果和性能。特点:ResX是YOLO系列中的一个大组件,它由一个CBL(Conv+Bn+Leaky_relu)和X个残差组件(Res unit)构成。在YOLOv3等https://blog.csdn.net/a8039974/article/details/142349866https://blog.csdn.net/a8039974/article/details/142349866

深入浅出之Resnet网络-CSDN博客文章浏览阅读4k次,点赞13次,收藏35次。ResNet(Residual Network,残差网络)是一种由微软亚洲研究院提出的深度神经网络结构,其核心在于通过残差连接(residual connections)解决了深层网络训练中的梯度消失和梯度爆炸问题,使得网络可以训练得更深,性能更强。_resnethttps://blog.csdn.net/a8039974/article/details/142202414https://blog.csdn.net/a8039974/article/details/142202414

4.3、 pytorch实现

版本一:

import math

from collections import OrderedDict

import torch.nn as nn

#---------------------------------------------------------------------#

# 残差结构

# 利用一个1x1卷积下降通道数,然后利用一个3x3卷积提取特征并且上升通道数

# 最后接上一个残差边

#---------------------------------------------------------------------#

class BasicBlock(nn.Module):

def __init__(self, inplanes, planes):

super(BasicBlock, self).__init__()

self.conv1 = nn.Conv2d(inplanes, planes[0], kernel_size=1, stride=1, padding=0, bias=False)

self.bn1 = nn.BatchNorm2d(planes[0])

self.relu1 = nn.LeakyReLU(0.1)

self.conv2 = nn.Conv2d(planes[0], planes[1], kernel_size=3, stride=1, padding=1, bias=False)

self.bn2 = nn.BatchNorm2d(planes[1])

self.relu2 = nn.LeakyReLU(0.1)

def forward(self, x):

residual = x

out = self.conv1(x)

out = self.bn1(out)

out = self.relu1(out)

out = self.conv2(out)

out = self.bn2(out)

out = self.relu2(out)

out += residual

return out

class DarkNet(nn.Module):

def __init__(self, layers):

super(DarkNet, self).__init__()

self.inplanes = 32

# 416,416,3 -> 416,416,32

self.conv1 = nn.Conv2d(3, self.inplanes, kernel_size=3, stride=1, padding=1, bias=False)

self.bn1 = nn.BatchNorm2d(self.inplanes)

self.relu1 = nn.LeakyReLU(0.1)

# 416,416,32 -> 208,208,64

self.layer1 = self._make_layer([32, 64], layers[0])

# 208,208,64 -> 104,104,128

self.layer2 = self._make_layer([64, 128], layers[1])

# 104,104,128 -> 52,52,256

self.layer3 = self._make_layer([128, 256], layers[2])

# 52,52,256 -> 26,26,512

self.layer4 = self._make_layer([256, 512], layers[3])

# 26,26,512 -> 13,13,1024

self.layer5 = self._make_layer([512, 1024], layers[4])

self.layers_out_filters = [64, 128, 256, 512, 1024]

# 进行权值初始化

for m in self.modules():

if isinstance(m, nn.Conv2d):

n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels

m.weight.data.normal_(0, math.sqrt(2. / n))

elif isinstance(m, nn.BatchNorm2d):

m.weight.data.fill_(1)

m.bias.data.zero_()

#---------------------------------------------------------------------#

# 在每一个layer里面,首先利用一个步长为2的3x3卷积进行下采样

# 然后进行残差结构的堆叠

#---------------------------------------------------------------------#

def _make_layer(self, planes, blocks):

layers = []

# 下采样,步长为2,卷积核大小为3

layers.append(("ds_conv", nn.Conv2d(self.inplanes, planes[1], kernel_size=3, stride=2, padding=1, bias=False)))

layers.append(("ds_bn", nn.BatchNorm2d(planes[1])))

layers.append(("ds_relu", nn.LeakyReLU(0.1)))

# 加入残差结构

self.inplanes = planes[1]

for i in range(0, blocks):

layers.append(("residual_{}".format(i), BasicBlock(self.inplanes, planes)))

return nn.Sequential(OrderedDict(layers))

def forward(self, x):

x = self.conv1(x)

x = self.bn1(x)

x = self.relu1(x)

x = self.layer1(x)

x = self.layer2(x)

out3 = self.layer3(x)

out4 = self.layer4(out3)

out5 = self.layer5(out4)

return out3, out4, out5

def darknet53():

model = DarkNet([1, 2, 8, 8, 4])

return model

版本二:

import torch

import torch.nn as nn

from torch.nn import modules

from torch.utils.data import DataLoader

from torchvision.datasets import CIFAR10

from torchvision.transforms import transforms

from torch.autograd import Variable

class ConvBnLeaky(modules.Module):

def __init__(self,in_it,out_it,kernels,padding = 0,strides = 1):

super(ConvBnLeaky, self).__init__()

self.convs = nn.Sequential(

nn.Conv2d(in_it,out_it,kernels,padding=padding,stride=strides),

nn.BatchNorm2d(out_it),

nn.LeakyReLU(0.1,True)

)

def forward(self,x):

x = self.convs(x)

return x

pass

class Resnet_Block(modules.Module):

def __init__(self,ch,num_block = 1):

super(Resnet_Block, self).__init__()

self.module_list = modules.ModuleList()

for _ in range(num_block):

resblock = nn.Sequential(

ConvBnLeaky(ch,ch // 2,1),

ConvBnLeaky(ch // 2,ch,kernels=3,padding=1)

)

self.module_list.append(resblock)

def forward(self,x):

for i in self.module_list:

x = i(x) + x

return x

class Darknet_53(modules.Module):

def __init__(self,num_classes = 10):

super(Darknet_53, self).__init__()

self.later_1 = nn.Sequential(

ConvBnLeaky(3,32,3,padding=1),

ConvBnLeaky(32,64,3,padding=1,strides=2),

Resnet_Block(64,1)

)

self.later_2 = nn.Sequential(

ConvBnLeaky(64, 128, 3, padding=1,strides=2),

Resnet_Block(128, 2)

)

self.later_3 = nn.Sequential(

ConvBnLeaky(128, 256, 3, padding=1, strides=2),

Resnet_Block(256, 8)

)

self.later_4 = nn.Sequential(

ConvBnLeaky(256, 512, 3, padding=1, strides=2),

Resnet_Block(512, 8)

)

self.later_5 = nn.Sequential(

ConvBnLeaky(512, 1024, 3, padding=1, strides=2),

Resnet_Block(1024, 4)

)

self.pool = nn.AdaptiveAvgPool2d((1,1))

self.fc = nn.Linear(1024,num_classes)

def forward(self,x):

x = self.later_1(x)

x = self.later_2(x)

x = self.later_3(x)

x = self.later_4(x)

x = self.later_5(x)

x = self.pool(x)

x = torch.squeeze(x)

x = self.fc(x)

return x

def main():

Root_file = 'cifar'

train_data = CIFAR10(Root_file,train=True,transform = transforms.ToTensor())

data = DataLoader(train_data,batch_size=64,shuffle=True)

device = torch.device('cuda')

net = Darknet_53().to(device)

print(net)

Cross = nn.CrossEntropyLoss().to(device)

optimizer = torch.optim.Adam(net.parameters(),0.001)

for epoch in range(10):

for img,label in data:

img = Variable(img).to(device)

label = Variable(label).to(device)

output = net.forward(img)

loss = Cross(output,label)

loss.backward()

optimizer.zero_grad()

optimizer.step()

pre = torch.argmax(output,1)

num = (pre == label).sum().item()

acc = num / img.shape[0]

loss_val = loss.item()

print("epoch:",epoch)

print("acc:",acc)

print("loss:",loss_val)

pass

if __name__ == '__main__':

main()

五、CSPNet

深入浅出之CSPNet网络-CSDN博客文章浏览阅读2.6k次,点赞14次,收藏43次。CSPNet(Cross Stage Partial Network)的提出背景主要源于对现有计算机视觉模型的分析和挑战。在计算资源受限的情况下,轻量级神经网络模型越来越受到关注,但这类模型在轻量化的同时往往会牺牲模型的准确性。此外,现有的模型在推断过程中存在计算瓶颈和内存开销较大的问题,这限制了模型在嵌入式设备和边缘计算平台上的应用。CSPNet旨在解决这些问题,通过优化网络结构和计算流程,提高轻量级模型的学习能力,以在保持较高准确性的同时实现轻量化。_cspnethttps://blog.csdn.net/a8039974/article/details/142242325

CSPNet(Cross Stage Partial Network)的提出背景主要源于对现有计算机视觉模型的分析和挑战。在计算资源受限的情况下,轻量级神经网络模型越来越受到关注,但这类模型在轻量化的同时往往会牺牲模型的准确性。此外,现有的模型在推断过程中存在计算瓶颈和内存开销较大的问题,这限制了模型在嵌入式设备和边缘计算平台上的应用。CSPNet旨在解决这些问题,通过优化网络结构和计算流程,提高轻量级模型的学习能力,以在保持较高准确性的同时实现轻量化。

六、CSPDarknet53

6.1 概述

1. 提出背景与时间

CSPDarknet53是在Darknet53的基础上进一步优化而来的一种深度卷积神经网络模型,旨在提升图像识别和分类任务的性能。Darknet53由Joseph Redmon等人于2018年提出,主要用于高效的对象检测和图像分类。CSPDarknet53作为Darknet53的改进版本,通过引入CSP(Cross Stage Partial Connections)结构,进一步提高了模型的准确性和效率。

5. 作者

CSPDarknet53的主要贡献者包括AlexeyAB等研究人员,他们在Darknet53的基础上进行了改进和创新,提出了这一新的网络结构。

3. 主要贡献

引入CSP结构:通过跨阶段的部分连接,提高了模型的稳定性和泛化能力,减少了计算冗余。

提升性能:在不损失检测精度的前提下,提升了模型对特征提取的能力,从而提高了检测速度和准确性。

降低计算损耗:减少了模型的参数数量和FLOPs(floating point operations),使得模型在配置简单的CPU上也能实现较好的性能。

4. 特点

高效性:通过CSP结构减少了计算冗余,提高了模型的推理速度。

鲁棒性:在多个目标检测和实例分割任务中表现出较强的鲁棒性,能够应对复杂多变的场景。

灵活性:网络架构灵活,可以根据具体任务需求进行调整和优化。

5 优缺点

优点:

提升了模型对特征提取的能力,提高了检测速度和准确性。降低了模型的计算损耗,适用于配置简单的硬件环境。具有较强的鲁棒性和稳定性,能够应对复杂场景。

缺点:

相比其他更复杂的网络结构,可能在某些极端场景下精度略有不足。引入CSP结构后,模型的计算量和参数量虽然有所减少,但仍需要较大的计算资源。

6. 应用场景

CSPDarknet53因其优异的性能被广泛应用于图像识别、目标检测、人脸识别等计算机视觉任务中。例如,在智能监控、工业自动化、无人驾驶等领域中,CSPDarknet53能够准确地识别并分类各种场景中的物体和目标,为实际应用提供强有力的支持。此外,CSPDarknet53还常被用作深度学习模型的主干网络,与其他网络结构结合使用以进一步提升性能。

6.2. 网络结构

CSPDarknet53网络包含53个卷积层和1个全连接层。其网络结构主要由卷积层、残差块和池化层组成,通过CSP结构将输入的特征数据分为两部分,一部分进行残差卷积,另一部分保持原样,最后通过拼接操作合并两部分特征。这种结构使得网络能够在不同层次的特征图中提取更丰富的信息。

CSP-DarkNet和CSP-ResNe(X)t的整体思路是差不多的,沿用网络的滤波器尺寸和整体结构,在每组Residual block加上一个Cross Stage Partial结构。并且,CSP-DarkNet中也取消了Bottleneck的结构,减少了参数使其更容易训练。

YOLOV4网络结构

YOLOV5网络结构

更多相关知识请参考:

深入浅出之CSPNet网络-CSDN博客文章浏览阅读1.3k次,点赞14次,收藏30次。CSPNet(Cross Stage Partial Network)的提出背景主要源于对现有计算机视觉模型的分析和挑战。在计算资源受限的情况下,轻量级神经网络模型越来越受到关注,但这类模型在轻量化的同时往往会牺牲模型的准确性。此外,现有的模型在推断过程中存在计算瓶颈和内存开销较大的问题,这限制了模型在嵌入式设备和边缘计算平台上的应用。CSPNet旨在解决这些问题,通过优化网络结构和计算流程,提高轻量级模型的学习能力,以在保持较高准确性的同时实现轻量化。_cspnethttps://blog.csdn.net/a8039974/article/details/142242325https://blog.csdn.net/a8039974/article/details/142242325深入浅出之SPP、SPPF、SPPCSPC与ASPP模块(YOLO)-CSDN博客文章浏览阅读1.4k次,点赞9次,收藏25次。YOLOv4中的SPP模块是一个重要的组成部分,它通过融合不同尺度大小的特征图来增强网络的特征提取能力。SPP的引入使得YOLOv4能够更好地适应不同大小的输入图像,并提取出更加丰富的特征信息,从而提高目标检测的精度和泛化能力。_sppfhttps://blog.csdn.net/a8039974/article/details/142339986https://blog.csdn.net/a8039974/article/details/142339986深入浅出之CSPBlock模块(YOLO)-CSDN博客文章浏览阅读991次,点赞23次,收藏17次。YOLO CSPX模块是YOLO系列算法中的一个重要组成部分,它通过跨阶段部分连接的方式减少了计算量,同时保证了模型的准确率。在YOLOv4及后续版本中,CSPX模块被广泛应用于主干网络和Neck结构中,为模型提供了强大的特征提取和融合能力。https://blog.csdn.net/a8039974/article/details/142350637https://blog.csdn.net/a8039974/article/details/142350637

6.3 PyTorch实现

这个复现包括了全局池化和全连接层,YOLOv4中使用CSP-DarkNet只使用之前的卷积层用作特征提取。

Mish激活函数和BN_CONV_Mish结构

class Mish(nn.Module):

def __init__(self):

super(Mish, self).__init__()

def forward(self, x):

return x * torch.tanh(F.softplus(x))

class BN_Conv_Mish(nn.Module):

def __init__(self, in_channels, out_channels, kernel_size, stride, padding, dilation=1, groups=1, bias=False):

super(BN_Conv_Mish, self).__init__()

self.conv = nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding, dilation=dilation,

groups=groups, bias=bias)

self.bn = nn.BatchNorm2d(out_channels)

def forward(self, x):

out = self.bn(self.conv(x))

return Mish()(out)

Basic block

使用的是残差结构,要注意的是:按照residual block的一贯思路,shortcut之前的最后一层卷积使用线性激活(不适使用激活函数)。

class ResidualBlock(nn.Module):

"""

basic residual block for CSP-Darknet

"""

def __init__(self, chnls, inner_chnnls=None):

super(ResidualBlock, self).__init__()

if inner_chnnls is None:

inner_chnnls = chnls

self.conv1 = BN_Conv_Mish(chnls, inner_chnnls, 1, 1, 0) # always use samepadding

self.conv2 = nn.Conv2d(inner_chnnls, chnls, 3, 1, 1, bias=False)

self.bn = nn.BatchNorm2d(chnls)

def forward(self, x):

out = self.conv1(x)

out = self.conv2(out)

out = self.bn(out) + x

return Mish()(out)

CSP-DarkNet

按照上图的结构实现CSP结构并搭建网络。需要注意的是,第一个CSP结构和后面的有略微差别:

class CSPFirst(nn.Module):

"""

First CSP Stage

"""

def __init__(self, in_chnnls, out_chnls):

super(CSPFirst, self).__init__()

self.dsample = BN_Conv_Mish(in_chnnls, out_chnls, 3, 2, 1) # same padding

self.trans_0 = BN_Conv_Mish(out_chnls, out_chnls, 1, 1, 0)

self.trans_1 = BN_Conv_Mish(out_chnls, out_chnls, 1, 1, 0)

self.block = ResidualBlock(out_chnls, out_chnls//2)

self.trans_cat = BN_Conv_Mish(2*out_chnls, out_chnls, 1, 1, 0)

def forward(self, x):

x = self.dsample(x)

out_0 = self.trans_0(x)

out_1 = self.trans_1(x)

out_1 = self.block(out_1)

out = torch.cat((out_0, out_1), 1)

out = self.trans_cat(out)

return out

class CSPStem(nn.Module):

"""

CSP structures including downsampling

"""

def __init__(self, in_chnls, out_chnls, num_block):

super(CSPStem, self).__init__()

self.dsample = BN_Conv_Mish(in_chnls, out_chnls, 3, 2, 1)

self.trans_0 = BN_Conv_Mish(out_chnls, out_chnls//2, 1, 1, 0)

self.trans_1 = BN_Conv_Mish(out_chnls, out_chnls//2, 1, 1, 0)

self.blocks = nn.Sequential(*[ResidualBlock(out_chnls//2) for _ in range(num_block)])

self.trans_cat = BN_Conv_Mish(out_chnls, out_chnls, 1, 1, 0)

def forward(self, x):

x = self.dsample(x)

out_0 = self.trans_0(x)

out_1 = self.trans_1(x)

out_1 = self.blocks(out_1)

out = torch.cat((out_0, out_1), 1)

out = self.trans_cat(out)

return out

class CSP_DarkNet(nn.Module):

"""

CSP-DarkNet

"""

def __init__(self, num_blocks: object, num_classes=1000) -> object:

super(CSP_DarkNet, self).__init__()

chnls = [64, 128, 256, 512, 1024]

self.conv0 = BN_Conv_Mish(3, 32, 3, 1, 1) # same padding

self.neck = CSPFirst(32, chnls[0])

self.body = nn.Sequential(

*[CSPStem(chnls[i], chnls[i+1], num_blocks[i]) for i in range(4)])

self.global_pool = nn.AdaptiveAvgPool2d((1, 1))

self.fc = nn.Linear(chnls[4], num_classes)

def forward(self, x):

out = self.conv0(x)

out = self.neck(out)

out = self.body(out)

out = self.global_pool(out)

out = out.view(out.size(0), -1)

out = self.fc(out)

return F.softmax(out)

def csp_darknet_53(num_classes=1000):

return CSP_DarkNet([2, 8, 8, 4], num_classes)

测试网络结构

net = csp_darknet_53()

summary(net, (3, 256, 256))

参考:

YOLOv4特征提取网络——CSPDarkNet结构解析及PyTorch实现