前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >工程必备!轻量级网络面试题!!

工程必备!轻量级网络面试题!!

作者头像
灿视学长
发布2021-07-07 10:33:21
3700
发布2021-07-07 10:33:21
举报
文章被收录于专栏:灿视学长灿视学长

大家好,我是灿视,祝大家端午节快乐!

今天我们继续肝一道面试题,我们一起,要在假期偷偷变强哈。

说到轻量级网络,那么肯定要说的就是

ShuffleNet

网络系列。这不,粉丝前两天面试的时候,就被问到了

ShuffleNet

的网络。那么我们今天,回顾下其中的考点与重点呀~

看文章前,可以先关注下我们。

专注于分享最优质的计算机视觉面经,持续关注AI在互联网与银行等单位中的工作机会。

ShuffleNet

系列算法之

V1

简介

ShuffleNet
V1

Face++

2017

年提出的轻量级深层神经网络。在

ImageNet

竞赛和

MS
COCO

竞赛中均表现了比其他移动端先进网络更优越的性能。

主要有以下两个亮点:

  • 提出
pointwise
group
convolution

来降低

PW

卷积(也即是 1*1 卷积)的计算复杂度。

  • 提出
channel
shuffle

来改善跨特征通道的信息流动。

PointWise
Group
Convolution

先简单介绍一下

PointWise
Group
Convolution

(组卷积)的概念,如下图

1

所示,左边为常见的普通卷积运算,输出的每一个维度的特征都需要输入特征的每一个维度经过计算获得,但这样的计算量会比较大。因而在

Alexnet

ResNeXt

等网络中采用了

group
convolution

,在输入特征图的通道方向执行分组操作得到最后的输入特征,如图

1

中左边所示。

PointWise
Group
Convolution

只是

group
convolution

的一种特殊形式,特殊的地方在于它的卷积核的核大小为

1

*

1

1

左边为普通卷积 右边为组卷积

那么为什么

ShuffleNet

网络要使用逐点组卷积呢?

其实是由于

group
convolution

本身的问题导致的,我们知道使用

group
convolution

的网络有很多,如

Xception

MobileNet

ResNeXt

等。

Xception

等模型采用了

depthwise
convolution

,这是一种比较特殊的

group
convolution

,此时分组数恰好等于通道数,意味着每个组只有一个特征图。这些网络存在一个很大的弊端是采用了密集的

1

x

1

pointwise
convolution

,在

ResNeXt

模型中

1

x

1
pointwise
convolution

基本上占据了

93.4

%的乘加运算。那么在

ShuffleNet

自然而然就提出了

pointwise
group
convolution

来降低网络中

1

×

1
pointwise
convolution

的计算量。

在原论文中作者也给出了

ResNet

ResNeXt

ShuffleNet

这三种模型中的一个

bottleneck

的计算量对比,从下面的计算公式可知

ShuffleNet

的计算量确实是最小的。下图

2

ResNet

的一个残差块,图

3

分别为

ResNeXt

(将图中

3

×

3

DWConv

换成

3

×

3

GConv

)和

ShuffleNet

bottleneck

ResNet: hw(1×1×c×m) + hw(3×3×m×m) + hw(1×1×c×m) = hw(2cm+9m^2)
ResNeXt: hw(1×1×c×m) + hw(3×3×m×m)/g + hw(1×1×c×m) = hw(2cm+9m^2/g)
ShuffleNet: hw(1×1×c×m)/g + hw(3×3×m) + hw(1×1×c×m)/g = hw(2cm/g+9m)

2
ResNet

的残差块

3

左为

ResNeXt

右为

ShuffleNet

由上可知,虽然

pointwise
group
convolution

可以降低计算量,但是如果多个组卷积堆叠在一起,会产生一个副作用:某个通道的输出结果,仅来自于一小部分输入通道,这个副作用会导致在组与组之间信息流动的阻塞,以及表达能力的弱化。那么我们如何解决这个问题呢?这用到了本文的第二个创新点—

channel
shuffle

channel
shuffle

为达到特征之间通信目的,作者提出了

channel
shuffle

。如图

4

-

a

为正常采用组卷积提取出来的特征(相同颜色的通道表示是在同一个

Group

)。图

4

-

b

就是采用

channel
shuffle

思想对

group
convolution

之后的特征图进行“重组”,这样可以保证接下了采用的

group
convolution

其输入来自不同的组,因此信息可以在不同组之间流转。图

4

-

c

进一步的展示了这一过程并随机,其实是“均匀地打乱”。在程序上实现

channel
shuffle

是非常容易的:假定将输入层分为

g

组,总通道数为

g

×

n

,首先将通道那个维度拆分为

(g,n)

两个维度,然后将这两个维度转置变成

(n,g)

,最后重新

reshape

成一个维度

g

×

n

。仅需要简单的维度操作和转置就可以实现均匀的

shuffle

。采用

channel
shuffle

之后就可以充分发挥

group convolution

的优点,完美的避开其缺点啦。

4
channel
shuffle

Pytorch

代码如下:

def shuffle_channels(x, groups):
    """shuffle channels of a 4-D Tensor"""
    batch_size, channels, height, width = x.size()
    assert channels % groups == 0
    channels_per_group = channels // groups
    # split into groups
    x = x.view(batch_size, groups, channels_per_group,
               height, width)
    # transpose 1, 2 axis
    x = x.transpose(1, 2).contiguous()
    # reshape into orignal
    x = x.view(batch_size, channels, height, width)
    return x

ShuffleNet

细节

1、
ShuffleNet
unit
ShuffleNet

的基本单元是在一个残差单元的基础上采用上面的设计理念改进而成的。

5

上图

5

-

a

所示为一个包含 3 层的残差单元:首先是

1

x

1

卷积,然后是

3

x

3

depthwise
convolution

,这里的

3

x

3

卷积是瓶颈层(

bottleneck

),紧接着是

1

x

1

卷积,最后是一个

add

连接,将输入直接加到输出上。

现在,进行如下的改进:将密集的

1

×

1

卷积替换成

1

×

1

group
convolution

,不过在第一个

1

×

1

卷积之后增加了一个

channel
shuffle

操作。另外

3

×

3

depthwise
convolution

之后没有使用 ReLU 激活函数。需要注意的是,这里的

stride

=

1

。改进之后如图

5

-

b

所示。

对于残差单元,如果

stride

=

1

时,此时输入与输出

shape

一致可以直接相加,而当

stride

=

2

时,通道数增加,而特征图大小减小,此时输入与输出不匹配。为了解决这个问题在

ShuffleNet

中,对原输入采用

stride

=

2

3

x

3
avg
pool

,这样得到和输出一样大小的特征图,然后将得到特征图与输出进行连接(

concat

),而不是相加。这样做的目的主要是降低计算量与参数大小,如图

5

-

c

所示。

stride

=

1

stride

=

2

下的

ShuffleNet
unit

代码如下:

# stride$=1
class ShuffleNetUnitA(nn.Module):
    """ShuffleNet unit for stride=1"""
    def __init__(self, in_channels, out_channels, groups=3):
        super(ShuffleNetUnitA, self).__init__()
        assert in_channels == out_channels
        assert out_channels % 4 == 0
        bottleneck_channels = out_channels // 4
        self.groups = groups
        self.group_conv1 = nn.Conv2d(in_channels, bottleneck_channels,
                                        1, groups=groups, stride=1)
        self.bn2 = nn.BatchNorm2d(bottleneck_channels)
        self.depthwise_conv3 = nn.Conv2d(bottleneck_channels,
                                         bottleneck_channels,
                                         3, padding=1, stride=1,
                                         groups=bottleneck_channels)
        self.bn4 = nn.BatchNorm2d(bottleneck_channels)
        self.group_conv5 = nn.Conv2d(bottleneck_channels, out_channels,
                                     1, stride=1, groups=groups)
        self.bn6 = nn.BatchNorm2d(out_channels)

    def forward(self, x):
        out = self.group_conv1(x)
        out = F.relu(self.bn2(out))
        out = shuffle_channels(out, groups=self.groups)
        out = self.depthwise_conv3(out)
        out = self.bn4(out)
        out = self.group_conv5(out)
        out = self.bn6(out)
        out = F.relu(x + out)
        return out

# -----------------------------------------------------------
# stride$=1
class ShuffleNetUnitB(nn.Module):
    """ShuffleNet unit for stride=2"""
    def __init__(self, in_channels, out_channels, groups=3):
        super(ShuffleNetUnitB, self).__init__()
        out_channels -= in_channels
        assert out_channels % 4 == 0
        bottleneck_channels = out_channels // 4
        self.groups = groups
        self.group_conv1 = nn.Conv2d(in_channels, bottleneck_channels,
                                     1, groups=groups, stride=1)
        self.bn2 = nn.BatchNorm2d(bottleneck_channels)
        self.depthwise_conv3 = nn.Conv2d(bottleneck_channels,
                                         bottleneck_channels,
                                         3, padding=1, stride=2,
                                         groups=bottleneck_channels)
        self.bn4 = nn.BatchNorm2d(bottleneck_channels)
        self.group_conv5 = nn.Conv2d(bottleneck_channels, out_channels,
                                     1, stride=1, groups=groups)
        self.bn6 = nn.BatchNorm2d(out_channels)

    def forward(self, x):
        out = self.group_conv1(x)
        out = F.relu(self.bn2(out))
        out = shuffle_channels(out, groups=self.groups)
        out = self.depthwise_conv3(out)
        out = self.bn4(out)
        out = self.group_conv5(out)
        out = self.bn6(out)
        x = F.avg_pool2d(x, 3, stride=2, padding=1)
        out = F.relu(torch.cat([x, out], dim=1))
        return out
        
2、
ShuffleNet

整体网络结构

6
ShuffleNet

整体网络结构

ShuffleNet

的整体网络结构如图

6

所示。首先是普通的

3

x

3

的卷积和

max
pool

。然后是三个

stage

,每个

stage

都是重复堆积若干

ShuffleNet
unit

。对于每个

stage

,第一个

ShuffleNet
unit

stride

=

2

,这样特征图

width

height

各降低一半,而通道数增加一倍。

后面的

ShuffleNet
unit

都是

stride

=

1

,特征图和通道数都保持不变。其中

g

控制了

group
convolution

中的分组数,分组越多,在相同计算资源下,可以使用更多的通道数,所以

g

越大时,采用了更多的卷积核。当完成三个

stage

后,采用

global
pool

将特征图大小降为

1

×

1

,最后是输出类别预测值的全连接层。

3、实验结果

作者做了大量的对比实验来证明

ShuffleNet

的优秀性能,这里给出一部分实验结果。

7

给出了采用不同的

g

值的

ShuffleNet
V1

ImageNet

上的表现结果。可以看到基本上当

g

越大时,错误率越低,这是因为采用更多的分组后,在相同的计算约束下可以使用更多的通道数,或者说特征图数量增加,网络的特征提取能力增强,网络性能得到提升。注意

Shuffle

是基准模型,而

0.5

× 和

0.25

× 表示的是在基准模型上将通道数缩小为原来的

0.5

0.25

7

不同的

g

值的

ShuffleNet

的表现结果

除此之外,作者还对比了不采用

channle
shuffle

和采用之后的网络性能对比,如下图

8

所示。可以清楚的看到,采用

channle
shuffle

之后,网络性能更好,从而证明

channle
shuffle

的有效性。

8

不采用

channle
shuffle

和采用之后的网络性能对比

作者也对比了

ShuffleNet

MobileNet

的计算量和精度,如下图

9

所示。可以看到

ShuffleNet

不仅计算复杂度更低,而且精度更好。

9
ShuffleNet

MobileNet

的计算量和精度对比

其他一些实验对比结果大家可以阅读原论文获取。原论文链接放在了引用中,大家自提哈。

总结

ShuffleNet

针对现大多数模型采用的逐点卷积存在的问题,提出了

pointwise
group
convolution

channel
shuffle

的处理方法,并基于这两个操作提出了一个

ShuffleNet
unit

,最后在多个竞赛中证明了这个网络的效率和精度。

ShuffleNet

系列算法之

V2

简介

ShuffleNet

-

V2

,它是由旷视提出的

V1

升级版本,能够在同等复杂度下,比

ShuffleNet

-

V1

MobileNet

-

v2

更准确。

主要有以下一些亮点:

  • 提出了四个高效网络设计指南
G1

G2

G3

G4
  • 针对
ShuffleNet

-

V1

的两种

unit

做了升级

论文前期实验

ShuffleNet

-

V2

这篇论文中,作者先是做了两个实验来抛砖引玉,为下文提出的四个高效网络设计指南以及创新点埋下伏笔。

1、网络执行效率准则

目前衡量模型复杂度的一个通用指标是

FLOPs

,具体指的是

multiply-add

数量。在论文中作者一上来先提出了一个问题:

是不是准确率和

FLOPs

(浮点数计算的数量)就可以代表一个网络模型的性能呢?

为此他们做了如下的实验:比较了分别以

FLOPs

Accuracy

为变量下不同平台下各个模型的推理时间。实验结果如下图

1

所示。

1

从图中我们可以看出:

a

、在不同平台下同一个模型的推理速度是不同的;

b

相同精度或相同

FLOPs

下的模型推理时间是不同的。

作者经过分析后,认为出现这种情况的原因主要有:

  • 对推理速度影响较大的因素,但没有影响到
FLOPs

。例如:内存访问成本

MAC

(

memory
access
cost

)和并行度(

degree
of
parallelism

)。

  • 运行平台不同。不同的运行平台,针对卷积等操作有一定的优化,例如
cudnn

等。

据此作者提出了

2

个网络执行效率对比的准则:论文也是按照以下这两个准则,对多种网络(包括

shufflenetv2

)进行评估。

(1)使用直接度量方式如速度代替 FLOPs。

(2)在同一环境平台上进行评估。

2、模型推理耗时

如下图

2

所示,作者分别在

GPU

CPU

上对

ShuffleNet

-

V1

MobileNet

-

V2

的推理时间进行了测试。从图中可以看出,整个推理时间被分解用于不同的操作。处理器在运算的时候,不光只是进行卷积运算,也在进行其他的运算,特别是在

GPU

上,卷积运算只占了运算时间的一半左右。作者将卷积部分认为是

FLOPs

操作。虽然这部分消耗的时间最多,但其他操作包括数据

IO

shuffle

和逐元素操作(

Elemwise

ReLU

等)也占用了相当多的时间。因此,再次确认了模型只使用

FLOPs

指标对实际运行时间的估计是不够准确的。

2
ShuffleNet

-

V1

MobileNet

-

V2

GPU

CPU

上的推理时间占比

四个高效网络设计指南

综上两个实验,作者提出了四个高效网络设计指南

G1

G2

G3

G4

。下面让我们一起来看看这四个东东都是什么吧。

G1

:

Equal
channel
width
minimizes
memory
access
cost
G1

的意思为:卷积的输入输出具有相同

channel

的时候,内存消耗是最小的。作者以

1

×

1
PW

卷积为例,假设输入和输出的特征通道数分别为

c_1

c_2

,特征图的大小为

h

×

w

,则

1

×

1
PW

卷积的

FLOPs

为:

B=(hwc_1*1*1*c_2)=hwc_1c_2

对应的 MAC(

memory
access
cost

)为:

MAC=hwc_1+hwc_2+1*1*c_1*c_2=hw(c_1+c_2)+c_1c_2

并且我们知道以下均值不等式:

c_1+c_2 ≥ 2\sqrt{c_1c_2}

最后整理一下上面的式子可以知道:

MAC≥2\sqrt{hwB}+\frac{B}{hw}

那么在相同

FLOPs

即当

B

不变的时候,只有当

c1

=

c2

的时候,

MAC

才能最小。如下图

3

所示,作者也做了一系列的实验,从图中可看出,只有当

c1

=

c2

的时候,在

GPU

或者

CPU

下的推理速度是最快的。

3

不同输入和输出下的推理速度


G2

Excessive
group
convolution
increases
MAC
G2

意思为:过多的分组卷积操作会增大

MAC

,从而使模型速度变慢。和前面同理,

g

为分组的数量,带

group

操作的

1

×

1

卷积的

FLOPs

为:

B=hw(c_1*1*1*c_2)/g=hwc_1c_2/g

MAC

值为:

MAC=hw(c_1+c_2)+\frac{c_1c_2}{g}=hwc_1+\frac{Gg}{c_1}+\frac{B}{hw}

可以看出,在

B

不变时,

g

越大,

MAC

也越大。如下图

4

所示,作者也做了实验对比,从图可以看出随着

g

越大,在

GPU

CPU

的推理速度也越慢。

4

不同

g

值下

GPU

CPU

的推理速度


G3

Network
fragmentation
reduces
degree
of
parallelism
G3

的意思是网络内部分支操作会降低并行度。作者认为,模型中的网络结构太复杂(分支和基本单元过多)会降低网络的并行程度,模型速度越慢。文章用了一个词:

fragment

,翻译过来就是分裂的意思,可以简单理解为网络的单元或者支路数量。

为了研究

fragment

对模型速度的影响,作者做了第四个实验。如图

5

所示,

1

-

fragment

-

series

表示单个卷积层;

2

-

fragment

-

series

表示一个

block

中有

2

个卷积层串行,也就是简单的叠加;

4

-

fragment

-

parallel

表示一个

block

中有

4

个卷积层并行,类似

Inception

的整体设计。图

6

为测试结果,可以看出在相同

FLOPs

的情况下,单卷积层(

1

-

fragment

)的速度最快。

5

6

不同分支结构下

GPU

CPU

下的推理速度


G4

Element

-

wise
operations
are
non

-

negligible
G4

的意思为:

Element

-

wise

操作不能被忽略。如图

2

所示,

IO

操作例如数据拷贝虽然

FLOPs

非常低,但是带来的时间消耗还是非常明显的,尤其是在

GPU

上。元素操作操作虽然基本上不增加

FLOPs

,但是所带来的时间消耗占比却不可忽视。于是作者做了一个实验,采用的是

Resnet50

的 bottleneck,除去跨层链接

shortcut

ReLU

之后测试其推理速度如下图

7

所示,在

GPU

ARM

结构上都获得了接近

20

% 的提速。

7
shortcut

ReLU

的推理速度

ShuffleNet

-

V2

设计

终于到了最后的部分了!这一部分,作者根据之前所提出的设计指南,在

Shufflenet

-

V1

的基础上进行修改,得到了

ShuffleNet

-

V2

1、
ShuffleNet

-

V2

unit

升级

作者在遵循 G1-G4 的设计准则的条件下,对于

ShuffleNet

-

V1

unit

进行了改进,如下图

8

所示为

ShuffleNet

-

V1

V2

unit

对比。图

8

-

a

和图

8

-

b

分别为

ShuffleNet

-

V1

stride

=

1

stride

=

1

unit

,图

8

-

c

和图

8

-

d

分别为对应的改进版。

8

作者分析了原

ShuffleNet

-

V1

中违背

G1

-

G4

的一些结构:

1、图

8

-

a

中的逐点组卷积增加了

MAC

违背了

G2

2、图

8

-

a

8

-

b

中过多的分组违背了

G3

3、图

8

-

a

8

-

b

中卷积输入和输出不相等违背了

G1

;

4、图

8

-

a

中使用了

add

操作违背了

G4

;

针对于以上问题,作者在

ShuffleNet

-

V2

中做了以下改进:

1、对于

stride

=

1

的模块来说,如图

8

-

c

,在每个单元的开始,通过

Channel
split

c

特征通道的输入被分为两支,分别为

c

c'

c'

个通道。按照准则

G3

,一个分支的结构仍然保持不变,另一个分支由三个卷积组成,为了满足

G1

,令输入和输出通道相同。与

ShuffleNet

-

V1

不同的是,两个

1

×

1

卷积不再是组卷积(

GConv

)(遵循

G2

),因为

Channel
Split

分割操作已经产生了两个组。

2、卷积之后,把两个分支拼接(

Concat

)起来,避免使用

Add

操作(遵循

G4

),从而通道数量保持不变 (遵循

G1

)。然后进行与

ShuffleNet

-

V1

相同的

Channel
Shuffle

操作来保证两个分支间能进行信息交流(将 shuffle 移到了 concat 之后遵循

G3

)。

3、对于

stride

=

2

的模块来说,如图

8

-

d

,使用一个

3

×

3

的 DW 卷积和

1

×

1

的卷积来替代

V1

当中的平均池化操作。也将原来的

1

×

1

组卷积换成了普通的

1

×

1

卷积(遵循

G2

)。

如下所示为

pytorch

版本

ShuffleNet

-

V2

的结构单元代码:

def channel_shuffle(x: Tensor, groups: int) -> Tensor:

    batch_size, num_channels, height, width = x.size()
    channels_per_group = num_channels // groups

    # reshape
    # [batch_size, num_channels, height, width] -> [batch_size, groups, channels_per_group, height, width]
    x = x.view(batch_size, groups, channels_per_group, height, width)

    x = torch.transpose(x, 1, 2).contiguous()

    # flatten
    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
        # 当stride为1时,input_channel应该是branch_features的两倍
        # python中 '<<' 是位运算,可理解为计算×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.branch2(x2)), dim=1)
        else:
            out = torch.cat((self.branch1(x), self.branch2(x)), dim=1)

        out = channel_shuffle(out, 2)

        return out
2、
ShuffleNet

-

V2

的整体网络结构

9
ShuffleNet

-

V2

的整体网络结构

ShuffleNet

-

V2

的整体网络结构如图 9 所示。基本上延续了和

V1

相似的结构,每个

stage

都包含了若干

stride

=

1

stride

=

2

的模块,需要主要的是,每经过一个

stage

通道数都会增加一倍的原因是由于

stride

=

2

的模块(图

8

-

d

)两个分支的通道数都等于输入通道,再经过

concat

之后输出通道自然增加两倍。

2、
ShuffleNet

-

V2

实验结果

9
ShuffleNet

-

V2

的实验结果

如图

9

所示为

ShuffleNet

-

V2

的实验结果,作者比较了

ShuffleNet

-

V2

MobileNet

系列、

DenseNet

Xception

等网络在

GPU

CPU

下的推理速度和精度。从图中可知,

ShuffleNet

-

V2

在精度和推理速度上都是更加杰出的。

总结

1、

ShuffleNet

-

V2

完善了网络性能对比的准则,以

FLOPs

、推理速度和平台这三个因素来综合评价网络的性能。

2、提出了四个高效网络设计指南,并据此设计了

ShuffleNet

-

V2

中的结构单元。

引用

  • https://arxiv.org/pdf/1807.11164.pdf
  • https://www.jianshu.com/p/c5db1f98353f
  • https://zhuanlan.zhihu.com/p/67009992
  • https://zhuanlan.zhihu.com/p/48261931
  • https://blog.csdn.net/weixin_44474718/article/details/91041343
  • https://blog.csdn.net/weixin_43624538/article/details/86155936
  • https://arxiv.org/abs/1707.01083
  • https://zhuanlan.zhihu.com/p/32304419
  • https://www.jianshu.com/p/c5db1f98353f
  • https://www.cnblogs.com/hellcat/p/10318630.html
  • https://blog.csdn.net/weixin_43624538/article/details/86155936
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-06-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 灿视学长 微信公众号,前往查看

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

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 简介
    • 1、
      • 2、
        • 3、实验结果
        • 总结
        • 简介
        • 论文前期实验
          • 1、网络执行效率准则
            • 2、模型推理耗时
            • 四个高效网络设计指南
              • 1、
                • 2、
                  • 2、
                  • 总结
                  • 引用
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档