第十章 ShuffleNetv2网络详解

系列文章目录


第一章 AlexNet网络详解

第二章 VGG网络详解

第三章 GoogLeNet网络详解 

第四章 ResNet网络详解 

第五章 ResNeXt网络详解 

第六章 MobileNetv1网络详解 

第七章 MobileNetv2网络详解 

第八章 MobileNetv3网络详解 

第九章 ShuffleNetv1网络详解 

第十章 ShuffleNetv2网络详解 

第十一章 EfficientNetv1网络详解 

第十二章 EfficientNetv2网络详解 

第十三章 Transformer注意力机制

第十四章 Vision Transformer网络详解 

第十五章 Swin-Transformer网络详解 

第十六章 ConvNeXt网络详解 

第十七章 RepVGG网络详解 

第十八章 MobileViT网络详解 


文章目录

  •  ShuffleNetv2网络详解
  • 0. 前言
  • 1. 摘要
  • 2.   ShuffleNetv2网络详解网络架构
    • 1.  ShuffleNetv2_Model.py(pytorch实现)
    • 2.
  • 总结


0、前言

1.这篇论文提出了一种基于直接度量的神经网络架构设计方法,并展示了其实验结果和指导性指南。

2.本文的研究背景是当前神经网络架构设计大多是以FLOPs复杂度为导向,而缺乏对速度等直接指标的综合考虑。

3.本文的主要论点是应该通过在目标平台上对直接指标进行全面综合评估,并在此基础上制定优化网络架构的指导性方法。

4.以往的研究大多使用FLOPs作为神经网络架构设计的优化目标,而这种方法忽略了其他因素对实际速度的影响,导致了速度与精度无法同时提高的问题。

5.本文提出了一种基于直接度量的神经网络架构设计方法,通过在目标平台上综合评估速度等直接指标来引导架构的设计,从而实现更高的速度与精度综合表现。

6.实验结果表明,作者提出的网络模型(ShuffleNet V2)在速度和精度平衡方面都达到了最先进的表现,本研究的贡献是提供了一种更全面的指导优化网络架构的方法。但本文的主要局限在于实验数据集的规模较小,未来仍需要更多的实验和验证来证明这种方法的适用性。

深度卷积神经网络(CNN)的架构已经演变了多年,变得更加精确和更快速。自AlexNet里程碑式的工作以来[1],通过新颖的结构,包括VGG [2],GoogLeNet [3],ResNet [4,5],DenseNet [6],ResNeXt [7],SE-Net [8]和自动神经架构搜索 [9,10,11],ImageNet分类准确性已显着提高。除了准确性,计算复杂度是另一个重要的考虑因素。现实任务通常旨在在给定目标平台(例如硬件)和应用场景(例如自动驾驶需要低延迟)的限制的计算预算下获得最佳准确性。这激发了一系列工作,以轻量级架构设计和更好的速度-准确度权衡为目标,包括Xception [12],MobileNet [13],MobileNet V2 [14],ShuffleNet [15]和CondenseNet [16],等等。这些工作中的分组卷积和深度卷积至关重要。为了衡量计算复杂度,广泛使用的度量标准是浮点运算数或FLOPs [1]。然而,FLOPs是一种间接度量标准。它是我们真正关心的直接度量标准(如速度或延迟)的近似,但通常不等价于它。这种差异已经得到注意。

在之前的研究中,例如MobileNet v2 [14]比NASNET-A [9]快得多,但它们具有可比较的FLOPs。图1(c)(d)进一步证明了此现象,表明具有类似FLOPs的网络速度不同。因此,仅使用FLOPs作为计算复杂度指标是不够的,可能会导致次优设计。间接指标(FLOPs)与直接指标(速度)之间的差异可以归因于两个主要原因。首先,FLOPs未考虑影响速度的几个重要因素之一。其中一个因素是内存访问成本(MAC)。这种成本在某些操作,如组卷积中占据了很大一部分运行时间。在具有强大计算能力的设备上,如GPU,这可能成为瓶颈。在网络架构设计过程中,不应简单忽略此成本。另一个因素是并行度。具有高并行度的模型可以比具有低并行度的模型更快,前提是它们具有相同的FLOPs。其次,对于具有相同FLOPs的操作,在不同平台上的运行时间可能不同。例如,张量分解广泛用于早期的一些研究中,以加速矩阵乘法。然而,最近的一份研究[19]发现,在GPU上,[22]中的分解甚至比不做分解的1 × 1卷积还要慢,尽管它将FLOPs降低了75%。我们对这个问题进行了调查,并发现这是因为最新的CUDNN [23]库是专门针对3×3的卷积进行优化的。我们不能确定3×3卷积比1×1卷积慢9倍。

通过这些观察,我们提出在进行有效的网络架构设计时应考虑两个原则。首先,应使用直接指标(例如速度)而不是间接指标(例如FLOPs)。其次,这种指标应在目标平台上进行评估。在本文中,我们遵循这两个原则,并提出了一个更有效的网络架构。在第2节中,我们首先分析了两个代表性的最新网络(15,14)的运行时性能。然后,我们推导出了四条有效网络设计准则,超越了仅考虑FLOPs的范畴。虽然这些准则与平台无关,但我们进行了一系列受控实验,在GPU和ARM两个不同的平台上进行了验证,通过专门的代码优化,确保我们的结论在最新技术上。根据这些准则,在第3节中,我们设计了一个新的网络结构。由于它受ShuffleNet(15)的启发,因此被称为ShuffleNet V2。通过第4节中的综合验证实验,它在两个平台上都比以前的网络更快,更准确。图1(a)(b)提供了比较的概述。例如,给定40M FLOPs的计算复杂度预算,ShuffleNet V2比ShuffleNet V1和MobileNet V2分别更准确3.5%和3.7%。

(图1:在四个网络架构和两个硬件平台上,使用四个不同计算复杂度级别来衡量准确度(ImageNet验证集分类)、速度和FLOPs(参见正文)。(a、c)GPU结果,batchsize = 8。(b、d)ARM结果,batchsize = 1。最佳表现算法,即我们提出的ShuffleNet v2,在所有情况下都处于右上角区域)

1、摘要

目前,神经网络架构设计主要由计算复杂度间接指导,即FLOPs。然而,直接指标,例如速度,还依赖其他因素,如存储器访问成本和平台特性。因此,本文提出在目标平台上评估直接指标,而不仅考虑FLOPs。根据一系列控制实验,本文得出了几个有效网络设计的实用指南。因此,我们提出了一种新的架构,称为ShuffleNet V2。综合消融实验证明我们的模型在速度和准确度的权衡方面是最先进的。关键词:CNN架构设计,效率,实用性

2、ShuffleNetv2网络详解网络架构

3.正文分析

 网络设计高效实践指南。我们的研究是在两个广泛采用的硬件上进行的,该硬件具有行业级别的CNN库优化。我们注意到我们的CNN库比大多数开源库更有效率。因此,我们确保我们的观察和结论在工业实践中具有可靠性和重要性。{GPU.使用单个NVIDIA GeForce GTX 1080Ti。卷积库为CUDNN 7.0 [23]。我们还激活了CUDNN的基准测试功能,分别选择不同的卷积最快算法。{ARM.使用高度优化的基于Neon的实现的Qualcomm Snapdragon 810。评估仅使用一个线程。

其他设置包括: 打开完整的优化选项(例如,使用张量融合来减少小操作的开销).输入图像大小为224 ×224。每个网络都是随机初始化并评估100次。平均运行时间被使用。为了开始我们的研究,我们分析了两个最先进的网络,ShuffleNet V1 [15]和MobileNet V2 [14]的运行时间性能。它们都非常高效和准确地完成ImageNet分类任务,并且广泛用于低端设备,如手机。尽管我们只分析了这两个网络,但我们注意到它们代表了当前的趋势。它们的核心都是分组卷积和深度卷积,这也是其他最先进网络的关键组成部分,比如ResNeXt [7]、Xception [12]、MobileNet [13]和CondenseNet [16]。总体运行时间被分解为不同的操作,如图2所示。我们注意到FLOPs指标只考虑了卷积部分。尽管这部分消耗了大部分时间,但数据I/O、数据洗牌和元素操作(AddTensor、ReLU等)等其他操作也占据了相当数量的时间。因此,FLOPs不是一个足够准确的实际运行时间估计。基于这一观察,我们从几个不同方面对运行时(或速度)进行了详细分析,并得出了几个对于有效的网络架构设计的实用指南:G1)等通道宽度最小化存储器访问成本(MAC)。现代网络通常采用深度可分离卷积[12,13,15,14],其中逐点卷积(即1×1卷积)占据了大部分的复杂度[15]。我们研究了1×1卷积的卷积核形状。形状由两个参数指定:输入通道数c1和输出通道数c2。设h和w为特征图的空间大小,1×1卷积的FLOPs为B=hwc1c2。为了简化起见,我们假定运算设备中的缓存足够大,可以存储整个特征图。

(图2:ShuffleNet v1 [15](1×,g = 3)和MobileNet v2 [14](1×)两个代表性先进网络架构的运行时间分解。) 

因此,MAC具有由FLOPs给出的下限。当输入和输出通道数量相同时,它达到下限。这个结论是理论上的。在实践中,许多设备上的缓存通常不够大。另外,现代计算库通常采用复杂的阻塞策略来充分利用缓存机制[24]。因此,真正的MAC可能会偏离理论值。为了验证上述结论,进行如下实验。通过重复堆叠10个构建块来构建基准网络。每个块都包含两个卷积层。第一个包含c1个输入通道和c2个输出通道,第二个则相反。表1报告了固定总FLOPs时,通过改变c1:c2比例而获得的运行速度。很明显,当c1:c2接近1:1时,MAC变小,网络评估速度更快。G2)过多的分组卷积会增加MAC。分组卷积是现代网络架构的核心[7,15,25,26,27,28]。通过将所有通道之间的密集卷积变成稀疏卷积(仅在通道组内),可以减少计算复杂性(FLOPs)。一方面,它允许在固定FLOPs下使用更多通道,并增加网络容量(从而获得更好的准确性)。另一方面,增加通道数会导致MAC增加。形式上,按照G1和Eq.1中的符号,1×1分组卷积的MAC和FLOPs之间的关系为MAC = hw(c1 + c2) + c1c2 g = hwc1 + Bgc1 + Bhw; (2)其中g是组数,B = hwc1c2 / g是FLOPs。很容易看出,在给定固定输入形状c1×h×w和计算成本B的情况下,MAC随着g的增长而增加。为了研究实践中的影响,通过堆叠10个点卷积分组卷积层来构建基准网络。表2报告了使用分组卷积的运行速度。

在固定总算力的情况下,使用不同的组数是有差异的。很明显,使用一个大的组数会显著降低运行速度。例如,在GPU上使用8个组比使用1个组(标准密集卷积)慢了两倍以上,在ARM上慢了多达30%。这主要是由于增加了乘加运算。我们指出,我们的实现经过了特殊优化,比逐个组计算卷积要快得多。因此,我们建议应根据目标平台和任务精心选择组数。仅仅因为这可能使得可以使用更多的通道而使用大的组数是不明智的,因为准确性增加的好处很容易被迅速增加的计算成本所抵消。G3)网络分段降低了并行度。在GoogLeNet系列[29,30,3,31]和自动生成的体系结构[9,11,10]中,在每个网络块中广泛采用了“多路径”结构。使用许多小的运算符(这里称为“分段运算符”)而不是少量的大运算符。例如,在NASNET-A[9]中,分段运算符的数量(即一个构建块中的单个卷积或池操作的数量)为13。相比之下,在像ResNet [4]这样的常规结构中,这个数字是2或3。

尽管这种分段结构已被证明对准确性有益,但它可能会降低效率,因为它对于GPU等具有强大并行计算能力的设备来说是不友好的。它还引入了额外的开销,例如内核启动和同步。

表1: Guideline 1的验证实验。测试了四种不同的输入/输出通道比率(c1和c2),在这四种比率下,通过改变通道数量固定了总FLOPs。输入图像大小为56×56。

Table 1:Validation experiment for Guideline 1.Four different ratios of number of input/output channels (c1 and c2)are tested,while the total FLOPs under the four ratios is fixed by varying the number of channels.Input image size is 56 ×56

GPU(Batches/.sec)

ARM(Images/sec.)

c1:c2

(c1,c2) for ×1

×1

×2

×4

(c1,c2) for ×1

×1

×2

×4

1:1

(128,128)

1480

723

232

(32,32)

76.2

21.7

5.3

1:2

(90,180)

1296

586

206

(22,44)

72.9

20.5

5.1

1:6

(52,312)

876

489

189

(13,78)

69.1

17.9

4.6

1:12

(36,432)

748

392

163

(9,108)

57.6

15.1

4.4

该表格展示了针对Guideline 1进行的验证实验结果,其中测试了四种不同的输入/输出通道比率(c1和c2),并在保持总FLOPs不变的情况下通过调整通道数量来实现。具体参数解释如下:

GPU (Batches/sec.):使用GPU进行计算时,每秒钟可以处理的batch数。

ARM (Images/sec.):使用ARM处理器进行计算时,每秒钟可以处理的图像数。

c1:c2 (c1,c2) for ×1 ×1 ×2 ×4:输入/输出通道比率,其中c1表示输入通道数,c2表示输出通道数,后面的×1 ×1 ×2 ×4表示四种不同的通道倍增方式。

(c1,c2) for ×1 ×1 ×2 ×4:在不同的通道倍增方式下,通过调整通道数量得到的总FLOPs,其中输入图像大小为56x56。

从表格中可以提取以下信息:

随着输入/输出通道比率的变化,GPU和ARM的处理速度都会发生变化。

在相同的输入/输出通道比率下,GPU的处理速度明显高于ARM,这可能是由于GPU在并行计算方面的优势。

随着通道数量的增加,GPU和ARM的处理速度都会降低,这是由于计算复杂度的增加。

在不同的通道倍增方式下,总FLOPs保持不变,但GPU和ARM的处理速度会发生变化,这是由于不同的通道倍增方式会影响计算的瓶颈。

总的来说,该表格展示了在Guideline 1下进行的验证实验,突出了输入/输出通道比率、通道数量和通道倍增方式对计算速度的影响。

表2:指南2的验证实验。测试了4个不同的组数g,而总FLOPs在这四个值下是通过改变总通道数c来保持固定的。输入图像尺寸为56 ×56。

Table 2:Validation experiment for Guideline 2.Four values of group number g are tested,while the total FLOPs under the four values is fixed by varying the total channel number c.Input image size is 56 ×56.

GPU(Batches/.sec)

ARM(Images/sec.)

g

c for ×1

×1

×2

×4

c for ×1

×1

×2

×4

1

128

2451

1289

437

64

40.0

10.2

2.3

2

180

1725

873

341

90

35.0

9.5

2.2

4

256

1026

644

338

128

32.9

8.7

2.1

8

360

634

455

230

180

27.8

7.5

1.8

该表格展示了针对Guideline 2进行的验证实验结果,其中测试了四种不同的分组数量g,并在保持总FLOPs不变的情况下通过调整通道数量来实现。具体参数解释如下:

GPU (Batches/sec.):使用GPU进行计算时,每秒钟可以处理的batch数。

CPU (Images/sec.):使用CPU进行计算时,每秒钟可以处理的图像数。

g:分组数量。

c for ×1 ×1 ×2 ×4:在不同的通道倍增方式下,通过调整通道数量得到的总FLOPs,其中输入图像大小为56x56。

从表格中可以提取以下信息:

随着分组数量g的增加,GPU和CPU的处理速度都会发生变化。

在相同的分组数量下,GPU的处理速度明显高于CPU,这可能是由于GPU在并行计算方面的优势。

随着通道数量的增加,GPU和CPU的处理速度都会降低,这是由于计算复杂度的增加。

在不同的通道倍增方式下,总FLOPs保持不变,但GPU和CPU的处理速度会发生变化,这是由于不同的通道倍增方式会影响计算的瓶颈。

总的来说,该表格展示了在Guideline 2下进行的验证实验,突出了分组数量、通道数量和通道倍增方式对计算速度的影响。

表3:指南3.c的验证实验表示单个片段的通道数。其他分段结构的通道数将根据FLOPs进行调整,以保持与单个片段相同。输入图像尺寸为56×56

Table 3:Validation experiment for Guideline 3.c denotes the number of channels for 1-fragment.The channel number in other fragmented structures is adjusted so that the FLOPs is the same as 1-fragment.Input image size is 56 ×56

GPU(Batches/.sec)

ARM(Images/sec.)

c=128

c=256

c=512

c=64

c=128

c=256

1-fragment

2446

1274

434

40.2

10.1

2.3

2-fragment-series

1790

909

336

38.6

10.1

2.2

4-fragment-series

752

745

349

38.4

10.1

2.3

2-fragment-parallel

1537

803

320

33.4

9.1

2.2

4-fragment- parallel

691

572

292

35.0

8.4

2.1

该表格展示了针对Guideline 3进行的验证实验结果,其中测试了不同的分片结构和通道数量,并通过调整通道数量使得总FLOPs相同。具体参数解释如下:

GPU(Batches/sec.):使用GPU进行计算时,每秒钟可以处理的batch数。

CPU (Images/sec.):使用CPU进行计算时,每秒钟可以处理的图像数。

c=128 c=256 c=512:不同的通道数量。

1-fragment:单片结构。

2-fragment-series:双片结构,串行连接。

4-fragment-series:四片结构,串行连接。

2-fragment-parallel:双片结构,并行连接。

4-fragment-parallel:四片结构,并行连接。

从表格中可以提取以下信息:

不同的分片结构和通道数量会对GPU和CPU的处理速度产生影响。

在相同的通道数量下,GPU的处理速度明显高于CPU,这可能是由于GPU在并行计算方面的优势。

不同的分片结构会影响计算的瓶颈,从而影响GPU和CPU的处理速度。

并行连接的分片结构相对于串行连接的分片结构具有更好的计算性能。

总的来说,该表格展示了在Guideline 3下进行的验证实验,突出了分片结构和通道数量对计算速度的影响。

表格4: Guideline 4 的验证实验。ReLU和Shortcut操作分别从“瓶颈”单元[4]中移除。c是单元中的通道数。该单元被重复堆叠了10次以基准测试速度。

Table 4:Validation experiment for Guideline 4.The ReLU and shortcut operations are removed from the \bottleneck"unit [4],separately.c is the number of channels in unit.The unit is stacked repeatedly for 10 times to benchmark the speed.

GPU(Batches/.sec)

ARM(Images/sec.)

RELU

short-cut

c=32

c=64

c=128

c=32

c=64

c=128

yes

yes

2427

2066

1436

56.7

16.9

5.0

yes

no

2647

2256

1735

61.9

18.8

5.2

no

yes

2672

2121

1458

57.3

18.2

5.1

no

no

2842

2376

1782

66.3

20.2

5.4

该表格展示了针对Guideline 4进行的验证实验结果,其中测试了不同的“bottleneck”单元中是否存在ReLU和shortcut操作,并且使用不同的通道数量进行堆叠。具体参数解释如下:

GPU (Batches/sec.):使用GPU进行计算时,每秒钟可以处理的batch数。

CPU (Images/sec.):使用CPU进行计算时,每秒钟可以处理的图像数。

ReLU:是否在“bottleneck”单元中加入ReLU操作。

shortcut:是否在“bottleneck”单元中加入shortcut操作。

c=32 c=64 c=128:不同的通道数量。

从表格中可以提取以下信息:

在不同的通道数量下,加入ReLU和shortcut操作会对GPU和CPU的处理速度产生影响。

在相同的ReLU和shortcut设置下,GPU的处理速度明显高于CPU,这可能是由于GPU在并行计算方面的优势。

在相同的通道数量下,加入ReLU和shortcut操作会提高计算的瓶颈,从而影响GPU和CPU的处理速度。

不加入ReLU和shortcut操作的“bottleneck”单元具有更快的计算速度。

总的来说,该表格展示了在Guideline 4下进行的验证实验,突出了ReLU和shortcut操作以及通道数量对计算速度的影响。

(图3:ShuffleNet v1 [15]和本文的构建块。(a)基本ShuffleNet单元;(b)用于空间下采样(2×)的ShuffleNet单元;(c)我们的基本单元;(d)我们的用于空间下采样(2×)的单元。DWConv:深度可分离卷积。GConv:组卷积。)


 为了量化网络碎片化如何影响效率,我们评估了一系列具有不同碎片化程度的网络块。具体来说,每个构建块由1到4个1×1卷积组成,这些卷积按顺序或并行排列。附录中说明了这些块的结构。每个块重复堆叠10次。表3中的结果显示,碎片化显著降低了GPU的速度,例如4个碎片的结构比1个碎片慢3倍。在ARM上,速度降低相对较小。G4)成分操作是不可忽略的。如图2所示,在轻量级模型(如[15,14])中,成分操作占用了相当数量的时间,特别是在GPU上。在这里,成分运算符包括ReLU、AddTensor、AddBias等。它们的FLOP很小,但相对较重的MAC。特别地,我们还将深度卷积[12,13,14,15]视为成分运算符,因为它也具有高的MAC/FLOPs比值。为了验证,我们在ResNet [4]的"瓶颈"单元中进行了实验(1×1卷积,然后是3×3卷积,然后是1×1卷积,带ReLU和快捷连接)。分别去除了ReLU和快捷操作,不同变体的运行时间在表4中报告。我们观察到,在ReLU和快捷操作被移除后,GPU和ARM都获得了约20%的加速。结论和讨论基于上述指南和经验研究,我们得出结论,高效的网络架构应该1)使用"平衡化"卷积(相等的通道宽度);2)意识到使用组卷积的成本;3)降低碎片化程度;以及4)减少成分运算。这些理想的属性取决于平台特征(如内存处理和代码优化),这些特征超出了理论FLOPs。它们应该纳入实际网络设计的考虑。

轻量级神经网络结构的最新进展[15,13,14,9,11,10,12]主要基于FLOPs指标,而不考虑上述特性。例如,ShuffleNet v1 [15]严重依赖于组卷积(针对G2)和类似瓶颈的构建块(针对G1)。MobileNet v2 [14]使用反转瓶颈结构,违反了G1。它使用深度卷积和ReLUs在“厚”特征图上,违反了G4。自动生成的结构[9,11,10]高度分散,违反了G3。

表格5:ShuffleNet v2的整体架构,针对四个不同的复杂度级别。

Table 5:Overall architecture of ShuffleNet v2,for four different levels of complexities.

Layer

Output size

KSize

Stride

Repeat

Output Channels

0.5×

1.5×

Image

224×224

3

3

3

3

Conv1

MaxPool

112×112

56×56

3×3

3×3

2

2

1

24

24

24

24

Stage2

28×28

28×28

2

1

1

3

48

116

176

244

Stage3

14×14

14×14

2

1

1

7

96

232

352

488

Stage4

7×7

7×7

2

1

1

3

192

464

704

976

Conv5

7×7

1×1

1

1

1024

1024

1024

2048

GlobalPool

1×1

7×7

FC

1000

1000

1000

1000

FLOPs

41M

146M

299M

591M

#of Weights

1.4M

2.3M

3.5M

7.4M

该表格展示了ShuffleNet v2的整体架构,其中包含了四个不同复杂度级别的结构以及相应的计算量和权重数量。具体参数解释如下:

Layer:每一层的名称。

Output size:输出特征图的大小。

KSize:卷积核大小。

Stride:步长。

Repeat:重复次数。

Output channels:输出通道数。

FLOPs:每秒钟的浮点运算次数。

#of Weights:模型中的权重数量。

从表格中可以提取以下信息:

ShuffleNet v2采用了一种新的结构设计,即“逐通道组卷积”和“通道重排”,在保证精度的同时大幅度减小了计算量和参数数量。

ShuffleNet v2的复杂度可以根据重复次数和输出通道数进行不同级别的调整,从而满足不同的应用场景。

ShuffleNet v2的最终输出经过全局池化和全连接层,得到1000个类别的预测结果。

该表格还提到了MobileNet v2和自动生成的结构,MobileNet v2采用了不符合Guideline 1的反向瓶颈结构,而自动生成的结构则存在高度碎片化违反Guideline 3的问题。

总的来说,该表格展示了ShuffleNet v2的整体架构以及对Guideline的遵循情况,突出了计算量和参数数量的控制以及新型结构的设计思想。

ShuffleNet V2是一种高效的网络架构,广泛应用于移动设备等低端设备。它是我们工作的灵感来源,因此首先对ShuffleNet V1进行了回顾和分析。根据文献[15],轻量级网络的主要挑战是在给定的计算预算(FLOPs)下只能负担得起有限数量的特征通道。为了在不显著增加FLOPs的情况下增加通道数,文献[15]采用了两个技术:点卷积组和瓶颈式结构。然后引入了“通道混洗”操作,以实现不同通道组之间的信息通信并提高准确性。建筑块如图3(a)(b)所示。正如第2节中讨论的那样,点卷积组和瓶颈结构都增加了MAC(G1和G2)。这种成本是不可忽视的,尤其是对于轻量级模型来说。此外,使用过多的组违反了G3。快捷连接中的逐元素“添加”操作也是不可取的(G4)。因此,为了实现高模型容量和效率,关键问题是如何在既没有密集卷积也没有太多组的情况下维持大量且同样宽的通道。

频道分裂和ShuffleNet V2为了实现上述目的,我们引入了一个简单的运算符,称为频道分裂。如图3(c)所示,在每个单元开始时,输入的c个特征通道被拆分成两个分支,分别具有c-c0和c0个通道。沿着G3,一个分支保留为身份。另一支由具有相同输入和输出通道的三个卷积组成,以满足G1。两个1×1卷积不再是组内卷积,不同于[15]。这部分是为了遵循G2,并且部分上已经分裂了两个组。卷积之后,两个分支被串联起来,所以通道数保持不变(G1)。然后使用与[15]相同的“通道混洗”操作,在两个分支之间启用信息通信。混洗后,下一个单元开始。请注意,ShuffleNet v1 [15]中的“添加”操作不再存在。元素级操作如ReLU和深度卷积仅存在于一个分支中。此外,“连结”,“通道混洗”和“通道分裂”三个连续的元素级操作被合并成单个元素级操作。根据G4,这些更改是有益的。对于空间下采样,该单元略有修改,如图3(d)所示。删除了频道分裂运算符。因此,输出通道数翻倍。所提出的构建块(c)(d),以及生成的网络,称为ShuffleNet V2。基于以上分析,我们得出结论,此设计架构高效,因为它遵循所有指南。重复堆叠构建块以构造整个网络。为简单起见,我们设置c0=c=2。整个网络结构类似于ShuffleNet v1 [15],并在表5中总结。只有一个区别:在全局平均池化之前,增加了一个附加的1×1卷积层来混合特征,这在ShuffleNet v1中不存在。与[15]类似,每个块中的通道数被缩放以生成网络。

ShuffleNet v2的网络精度分析不仅高效,而且准确。有两个主要原因。首先,每个构建块中的高效率使得可以使用更多的特征通道和更大的网络容量。其次,在每个块中,一半的特征通道(当c0=c=2时)直接通过块并加入下一个块。这可以被视为一种特征重用,在与DenseNet [6]和CondenseNet [16]类似的精神中。在DenseNet [6]中,为了分析特征重用模式,将层之间的权重的l1范数绘制出来,如图4(a)所示。很明显,相邻层之间的连接比其他连接更强。这意味着所有层之间的密集连接可能会引入冗余。最近的CondenseNet [16]也支持该观点。在ShuffleNet v2中,很容易证明第i个和(i+j)个构建块之间的“直接连接”通道数量为rjc,其中r =(1-c0)/c。换句话说,特征重用的量随着两个块之间的距离的指数衰减。在远程块之间,特征重用变得更加弱。图4(b)绘制了与(a)类似的可视化,其中r = 0.5。请注意,(b)中的模式类似于(a)。

因此,ShuffleNet V2的结构通过设计实现了这种特征重用模式。它与DenseNet [6]具有类似的高准确性的特征重用优势,但正如之前分析的那样,它要更有效。这在实验和表8中得到了验证。

(图4:稠密块网络和ShuffleNet V2中特征重用模式的说明。(a)(由[6]提供)模型卷积层中滤波器权重的平均绝对值。像素(s;l)的颜色编码了连接层s和l的权重的平均L1范数。(b)像素(s;l)的颜色表示直接连接ShuffleNet v2块s到块l的通道数。所有像素值都归一化到[0;1]范围内) 

我们的消融实验在ImageNet 2012分类数据集[32,33]上进行。按照惯例[15,13,14],我们比较的所有网络都有四个计算复杂度级别,即约40、140、300和500+MFLOPs。这样的复杂度在移动场景中很常见。其他超参数和协议与ShuffleNet v1 [15]完全一样。我们与以下网络架构进行比较[12,14,6,15]:{ShuffleNet v1 [15]。在[15]中,比较了一系列的组数g。建议使用g =3具有更好的精度和速度之间的平衡。这也符合我们的观察。在这项工作中,我们主要使用g =3。{MobileNet v2 [14]。它比MobileNet v1 [13]更好。为了全面比较,我们报告原始论文[14]和我们的重新实现的准确性,因为[14]中的一些结果不可用。{Xception [12]。原始Xception模型[12]非常大(FLOPs>2G),超出了我们的比较范围。最近的工作[34]提出了一种修改的轻量级Xception结构,显示出更好的精度和效率之间的平衡。因此,我们与这个变种进行比较。{DenseNet [6]。原始工作[6]只报告了大型模型(FLOPs>2G)的结果。为了直接比较,我们按照表5中的架构设置对其进行了重新实现,其中第2-4阶段的构建块由DenseNet块组成。我们调整通道数量以满足不同的目标复杂度。表8总结了所有结果。我们从不同的角度分析这些结果。

最后,图1(a)(b)总结了准确性与速度之间的结果,即直接度量。我们得出结论,在GPU和ARM上,ShuffleNet v2在准确性和速度方面都表现最佳。与其他方法的兼容性。ShuffleNet v2可以与其他技术相结合,以进一步提高性能。当配备Squeeze-and-excitation(SE)模块[8]时,ShuffleNet v2的分类精度可以在速度损失的条件下提高0.5%。块结构如附录图2(b)所示。结果显示在表8的底部部分。大模型的泛化性。尽管我们的主要剖析是针对轻量级场景进行的,但ShuffleNet v2可用于大型模型(例如,FLOP≥2G)。表6比较了由50层ShuffleNet v2(详细信息见附录)与ShuffleNet v1 [15]和ResNet-50 [4]相对应的模型。在2.3GFLOPs下,ShuffleNet v2仍然优于ShuffleNet v1,比ResNet-50少40%的FLOPs。对于非常深的ShuffleNet v2(例如100层以上),为了使训练更快地收敛,我们通过添加一个残差路径轻微修改了基本的ShuffleNet v2单元(详细信息见附录)。表6呈现了一个配备SE [8]组件的164层ShuffleNet v2模型(详细信息见附录)。它获得了比以前的最先进模型[8]更优秀的准确性,但FLOPs更少。物体检测为了评估通用性,我们还测试了COCO物体检测[38]任务。我们使用最先进的轻量级检测器{Light-Head RCNN [34]作为我们的框架,并遵循相同的训练和测试协议。仅用我们的骨干网络替换了原来的模型。模型预先在ImageNet上进行了预训练,然后在检测任务上进行了微调。为了训练,我们使用COCO中的train + val集,除了minival集的5000个图像,使用minival集进行测试。准确度度量为COCO标准mmAP,即在0.5到0.95的框IoU阈值下的平均mAP。ShuffleNet v2与其他三种轻量级模型(Xception [12,34]、ShuffleNet v1 [15]和MobileNet v2 [14])在四个复杂度级别上进行比较。表7的结果显示,ShuffleNet v2表现最佳。

相比检测结果(表7)与分类结果(表8),有趣的是,在分类中,准确性排名为ShuffleNet v2≥MobileNet v2> ShuffeNet v1> Xception,而在检测中,排名变为ShuffleNet v2> Xception ≥ ShuffleNet v1≥ MobileNet v2。这表明Xception在检测任务上表现良好。这可能是因为Xception构建块的感受野比其他对应物更大(7比3)。受此启发,我们还通过在每个构建块的第一个点卷积之前引入一个额外的3×3深度卷积来扩大ShuffleNet v2的感受野。该变体称为ShuffleNet v2 *。只需要很少的额外FLOP,它可以进一步提高准确性。

我们还在GPU上对运行时间进行基准测试。为了公平比较,批处理大小设置为4,以确保充分利用GPU。由于数据复制(分辨率高达800×1200)和其他特定于检测的操作(如PSRoI池化[34])的开销,不同模型之间的速度差距小于分类的差距。尽管如此,ShuffleNet v2仍然优于其他模型,例如比ShuffleNet v1快约40%,比MobileNet v2快约16%。此外,变体ShuffleNet v2 *具有最佳的准确性,并且仍然比其他方法更快。这引发了一个实际的问题:如何增加接受场的大小?这对于高分辨率图像的目标检测至关重要[39]。我们将来会研究这个话题。

表8:对比几种网络架构的分类误差(验证集,单中心裁剪)和速度,在两个平台和四个计算复杂性水平上的结果。为了更好地比较,结果按复杂性水平分组。GPU批量大小为8,ARM为1。图像大小为224×224,除外[*]160×160和[**]192×192。由于目前缺乏高效实现,我们不提供CondenseNets [16]的速度测量。

 Table 8:Comparison of several network architectures over classification error (on valida tion set,single center crop)and speed,on two platforms and four levels of computation complexity.Results are grouped by complexity levels for better comparison.The batch size is 8 for GPU and 1 for ARM.The image size is 224 ×224 except:[*]160 ×160 and [**]192 ×192.We do not provide speed measurements for CondenseNets [16]due to lack of efficient implementation currently.

FLOPS:全大写,指每秒浮点运算次数,可以理解为计算的速度,是衡量硬件性能的一个指标。(硬件)

FLOPs:s小写,指浮点运算,理解为计算量,可以衡量算法/模型的复杂度(模型)

在论文中常用FLOPs(1 FLOPs = 10^9 FLOPs)

论文亮点:

1.计算复杂度不能只看FLOPs

直接看speed

MAC:memory access cost 内存访问成本

Degree of parallelism 并行等级

Platform 平台

2. 提出4条网络设计准则(guide line)

G1: Equal channel width minimizes memory access cost(MAC)

G2: Excessive group convolution increases MAC

G3: Network fragmentation reduces degree of parallesim

G4: Element-wise operations are non-negligible

G1:Equal channel width minimizes memory acces cost(MAC)

当卷积层的输入特征矩阵与输出特征矩阵channel相等时MAC最小(保持FLOPs 不变时)c1=c2时推理速度最大

MAC > 2*sqrt(hwB) + B/(hw)   B = hwc1c2 (FLOPs)

MAC = hw(c1+c2)+c1c2  (c1+c2)/2 >= sqrt(c1c2)

输入消耗:hwc1

输出消耗:hwc2

MAC >= 2hw*sqrt(c1c2)+c1c2>=2*sqrt(hwB)+B/(hw)  B=hwc1c2

G2: Excessive group convolution increases MAC

Gconvgroups增大时(保持FLOPs不变时),MAC也会增大

MAC = hw(c1+c2)+(c1c2)/g=hwc1+Bg/c1+B/hw (B=hwc1c2/g) FLOPs

G3: Network fragmentation reduces degree of parallesim

网络的碎片化程度越高,速度越慢

G4: Element-wise operations are non-negligible

Element-wise操作带来的影响是不可护士的(Element-wise操作包括ReLU,AddTensor,AddBia等操作)

3.提出新的block设计

使用平衡的convolution,c1=c2,不要一味扩大group的值,降低网络的复杂度(不要使用过多的分支),尽可能减少使用Element-wise操作

1.ShuffleNetv2.py(pytorch实现)

from typing import List, Callable
import torch
from torch import Tensor
import torch.nn as nn

def channel_shuffle(x:Tensor, groups:int) -> Tensor:
    batch_size, num_channels, height, width = x.size()
    channel_per_group = num_channels // groups
    x = x.view(batch_size, groups, channel_per_group, height, width)
    x = torch.transpose(x, 1, 2).contiguous()
    x = x.view(batch_size, -1, height, width)
    return x

class InvertedResidual(nn.Module):
    def __init__(self, input_c: int, output_c:int, stride:int):
        super(InvertedResidual, self).__init__()
        if stride not in [1, 2]:
            raise ValueError("illegal stride value.")
        self.stride = stride
        assert output_c % 2 == 0
        branch_features = output_c // 2
        assert (self.stride != 1) or (input_c == branch_features << 1)
        if self.stride == 2:
            self.branch1 = nn.Sequential(
                self.depthwise_conv(input_c, input_c, kernel_s=3, stride=self.stride, padding=1),
                nn.BatchNorm2d(input_c),
                nn.Conv2d(input_c, branch_features, kernel_size=1, stride=1, padding=0, bias=False),
                nn.BatchNorm2d(branch_features),
                nn.ReLU(inplace=True)
            )
        else:
            self.branch1 = nn.Sequential()
        self.branch2 = nn.Sequential(
            nn.Conv2d(input_c if self.stride > 1 else branch_features, branch_features, kernel_size=1,
                      stride=1, padding=0, bias=False),
            nn.BatchNorm2d(branch_features),
            nn.ReLU(inplace=True),
            self.depthwise_conv(branch_features, branch_features, kernel_s=3, stride=self.stride, padding=1),
            nn.BatchNorm2d(branch_features),
            nn.Conv2d(branch_features, branch_features, kernel_size=1, stride=1, padding=0, bias=False),
            nn.BatchNorm2d(branch_features),
            nn.ReLU(inplace=True)
        )

    @staticmethod
    def depthwise_conv(input_c: int,
                        output_c:int,
                        kernel_s:int,
                        stride:int=1,
                        padding:int=0,
                        bias:bool=False) -> nn.Conv2d:
        return nn.Conv2d(in_channels=input_c, out_channels=output_c, kernel_size=kernel_s,
                            stride=stride, padding=padding, bias=bias, groups=input_c)

    def forward(self, x: Tensor) -> Tensor:
        if self.stride == 1:
            x1, x2 = x.chunk(2, dim=1)
            out = torch.cat((x1, self.branch1(x), self.branch2(x)), dim=1)
        else:
            out = torch.cat((self.branch1(x), self.branch2(x)), dim=1)
        out = channel_shuffle(out, 2)
        return out

class ShuffleNetV2(nn.Module):
    def __int__(self,
                stages_repeats: List[int],
                stages_out_channels: List[int],
                num_classes:int=1000,
                inverted_residual: Callable[..., nn.Module] = InvertedResidual):
        super(ShuffleNetV2, self).__init__()
        if len(stages_repeats) != 3:
            raise ValueError("expected stages_repeats as list of 3 positive ints")
        if len(stages_out_channels) != 5:
            raise ValueError("expected stage_out_channels as list of 5 positive ints")
        self._stage_out_channels = stages_out_channels
        input_channels=3,
        output_channels = self._stage_out_channels[0]
        self.conv1 = nn.Sequential(
            nn.Conv2d(input_channels, output_channels, kernel_size=3, stride=2, padding=1, bias=False),
            nn.BatchNorm2d(output_channels),
            nn.ReLU(inplace=True)
        )
        input_channels = output_channels
        self.maxpoool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
        self.stage2:nn.Sequential
        self.stage3:nn.Sequential
        self.stage4:nn.Sequential
        stages_names = ["stage{}".format(i) for i in [2, 3, 4]]
        for name, repeats, output_channels in zip(stages_names, stages_repeats, stages_out_channels[1:]):
            seq = [inverted_residual(input_channels, output_channels, 2)]
            for i in range(repeats - 1):
                seq.append(inverted_residual(output_channels, output_channels, 1))
            setattr(self, name, nn.Sequential(*seq))
            input_channels = output_channels
        output_channels = self._stage_out_channels[-1]
        self.conv5 = nn.Sequential(
            nn.Conv2d(input_channels, output_channels, kernel_size=1, stride=1, padding=0, bias=False),
            nn.BatchNorm2d(output_channels),
            nn.ReLU(inplace=True)
        )
        self.fc = nn.Linear(output_channels, num_classes)

    def _forward_impl(self, x:Tensor) -> Tensor:
        x = self.conv1(x)
        x = self.maxpoool(x)
        x = self.stage2(x)
        x = self.stage3(x)
        x = self.stage4(x)
        x = self.conv5(x)
        x = x.mean([2, 3])
        x = self.fc(x)
        return x
    def forward(self, x:Tensor) -> Tensor:
        return self._forward_impl(x)

def shufflenet_v2_x0_5(num_classes=1000):
    model = ShuffleNetV2(stages_repeats=[4, 8, 4],
                         stages_out_channels=[24, 48, 96, 192, 1024],
                         num_classes=num_classes)
    return model

def shufflenet_v2_x1_0(num_classes=1000):
    model = ShuffleNetV2(stages_repeats=[4, 8, 4],
                         stages_out_channels=[24, 116, 232, 464, 1024],
                         num_classes=num_classes)
    return model

def shufflenet_v2_x1_5(num_classes=1000):
    model = ShuffleNetV2(stages_repeats=[4, 8, 4],
                         stages_out_channels=[24, 176, 352, 704, 1024],
                         num_classes=num_classes)
    return model

def shufflenet_v2_x2_0(num_classes=1000):
    model = ShuffleNetV2(stages_repeats=[4, 8, 4],
                         stages_out_channels=[24, 244, 488, 976, 2048],
                         num_classes=num_classes)
    return model

总结

我们提议网络架构设计应该考虑直接指标,比如速度,而不是间接指标,比如FLOPs。我们提出了实用指南和一种新型架构,ShuffleNet v2。全面实验验证了我们的新模型的有效性。我们希望这项工作能激发未来的网络架构设计工作,使其能够平台意识并更具实际意义。

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ShuffleNet V2是一种用于高效卷积神经网络(CNN)架构设计的实用准则。它的网络结构通过引入一些新特性来改进ShuffleNet V1的缺点。\[2\] ShuffleNet V2的基本单元块分为两种类型:a和b是ShuffleNet V1的基本单元块,c和d是ShuffleNet V2的基本单元块。ShuffleNet V1的缺点包括使用了过多的group、depthwise convolution和瓶颈结构增加了MAC,并且跨层连接中的element-wise Add操作也可以进行优化。为了解决这些问题,ShuffleNet V2引入了几种新特性。\[2\] 与分类结果相比,ShuffleNet V2在检测任务中表现更好。这可能是因为ShuffleNet V2引入了一个额外的3×3深度卷积来扩大感受野,从而提高了准确性。这个变体被称为ShuffleNet V2*,它只需要很少的额外FLOP就可以进一步提高准确性。\[3\] 总的来说,ShuffleNet V2通过改进网络结构和引入新特性,提高了CNN的效率和准确性。 #### 引用[.reference_title] - *1* *2* [shufflenet v2网络详解](https://blog.csdn.net/qq_35741782/article/details/107513899)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [第十章 ShuffleNetv2网络详解](https://blog.csdn.net/ADICDFHL/article/details/131338619)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值