【AI系统】GhostNet 系列

GhostNet 系列

本文主要会介绍 GhostNet 系列网络,在本文中会给大家带来卷积结构的改进方面的轻量化,以及与注意力(self-attention)模块的进行结合,部署更高效,更适合移动计算的 GhostNetV2。让读者更清楚的区别 V2 与 V1 之间的区别。

GhostNet V1 模型

GhostNet V1:提供了一个全新的 Ghost Module,旨在通过廉价操作生成更多的特征图。基于一组原始的特征图,作者应用一系列廉价的线性变换(cheap linear operations),以很小的代价生成许多能从原始特征发掘所需信息的 Ghost 特征图。该 Ghost 模块即插即用,通过堆叠 Ghost Module 得出 Ghost bottleneck,进而搭建轻量级神经网络——GhostNet。在 ImageNet 分类任务,GhostNet 在相似计算量情况下 Top-1 正确率达 75.7%,高于 MobileNetV3 的 75.2%。

Ghost Module

利用Ghost Module生成与普通卷积层相同数量的特征图,我们可以轻松地将Ghost Module替换卷积层,集成到现有设计好的神经网络结构中,以减少计算成本。第一、先通过普通的 conv 生成一些特征图。第二、对生成的特征图进行 cheap 操作生成冗余特征图,这步使用的卷积是 DW 卷积。第三将 conv 生成的特征图与 cheap 操作生成的特征图进行 concat 操作。如下图(b)所示,展示了 Ghost 模块和普通卷积的过程。

在这里插入图片描述

深度卷积神经网络通常引用由大量卷积组成的卷积神经网络,导致大量的计算成本。尽管最近的工作,例如 MobileNet 和 ShuffleNet 引入了深度卷积或混洗操作,以使用较小的卷积核(浮点运算)来构建有效的 CNN,其余 1×1 卷积层仍将占用大量内存和 FLOPs。鉴于主流 CNN 计算出的中间特征图中存在大量的冗余,作者提出减少所需的资源,即用于生成它们的卷积核。实际上,给定输入数据 X ∈ R c x h x w X∈R^{cxhxw} XRcxhxw,其中 c 是输入通道数,h 和 w 是高度,输入数据的宽度,分别用于生成 n 个特征图的任意卷积层的运算可表示为:

Y = X ∗ f + b Y=X*f+b Y=Xf+b

其中 *是卷积运算,b 是偏差项, Y ∈ R h ′ x w ′ x n Y∈R^{h'xw'xn} YRhxwxn 是具有 n 个通道的输出特征图, f ∈ R c x k x k x n f∈R^{cxkxkxn} fRcxkxkxn 是这一层中的卷积核。另外,h‘ 和 w’ 分别是输出数据的高度和宽度,kxk 分别是卷积核 f 的内核大小。在此卷积过程中,由于卷积核数量 n 和通道数 c 通常非常大(例如 256 或 512),所需的 FLOPs 数量达 n ⋅ h ′ ⋅ w ′ ⋅ c ⋅ k ⋅ k n \cdot h' \cdot w' \cdot c \cdot k \cdot k nhwckk 之多。

根据上述公式,要优化的参数数量( f f f b b b 中的参数)由输入和输出特征图的尺寸确定。如图 1 中所观察到的,卷积层的输出特征图通常包含很多冗余,并且其中一些可能彼此相似。作者指出,没有必要使用大量的 FLOP 和参数一一生成这些冗余特征图。这些原始特征图通常具有较小的大小,并由普通的卷积核生成。具体来说, m m m 个原始特征图 Y ′ ∈ R h ′ × w ′ × m Y'∈R^{h' \times w' \times m} YRh×w×m 是使用一次卷积生成的:

Y ′ = X ∗ f ′ Y'=X*f' Y=Xf

其中 f ′ ∈ R c × k × k × m f'∈R^{c \times k \times k \times m} fRc×k×k×m 是使用的卷积核, m ≤ n m\leq n mn,为简单起见,这里省略了偏差项。超参数(例如卷积核大小,stride,padding)与普通卷积中的超参数相同,以保持输出特征图的空间大小(即 h ′ h' h w ′ w' w )保持一致。为了进一步获得所需的 n n n 个特征图,作者提出对 Y ′ Y' Y 中的每个原始特征应用一系列廉价的线性运算,以生成 s 个幻影特征图:

y i j = Φ i , j ( y i ′ ) , ∀ i = 1 , . . . , m , j = 1 , . . . , s y_{ij}=Φ_{i,j}(y'_{i}),\forall i=1,...,m,j=1,...,s yij=Φi,j(yi),i=1,...,m,j=1,...,s

其中 Y i ′ Y'_{i} Yi Y ′ Y' Y 中第 i i i 个原始特征图,上述函数中的 Φ i , j Φ_{i,j} Φi,j 是第 j 个线性运算,用于生成第 jj 个特征图 y i j y_{ij} yij ,也就是说, y i ′ y'_{i} yi 可以具有一个或多个特征图 y i , j j = 1 s {y_{i,j}}^{s}_{j=1} yi,jj=1s 。最后的 Φ i , j Φ_{i,j} Φi,j 是用于保留原始特征图的恒等映射,通过操作,我们可以获得 n = m ⋯ n=m\cdots n=m 个特征图 Y = [ y 11 , y 12 , . . . , y m s ] Y=[y_{11},y_{12},...,y_{ms}] Y=[y11,y12,...,yms] 作为 Ghost module 的输出数据。注意,线性运算 Φ Φ Φ 在每个通道上运行,其计算量比普通卷积少得多。实际上,Ghost module 中可能有几种不同的线性运算。

复杂度分析

Ghost module 具有一个恒等映射和 m ⋅ ( s − 1 ) = n s ⋅ ( s − 1 ) m \cdot (s-1) = \frac{n}{s}\cdot (s-1) m(s1)=sn(s1) 个线性运算,并且每个线性运算的平均内核大小 d × d d \times d d×d。理想情况下, n ⋅ ( s − 1 ) n \cdot (s-1) n(s1) 个线性运算可以具有不同的形状和参数,但是特别是考虑到 CPU 或 GPU 的实用性,在线推理会受到阻碍。因此,作者建议在一个 Ghost 模块中采用相同大小的线性运算以高效实现 Ghost module。使用 Ghost module 升级普通卷积的理论加速比为:

r s = n ⋅ h ′ ⋅ w ′ ⋅ c ⋅ k ⋅ k n s ⋅ h ′ ⋅ w ′ ⋅ c ⋅ k ⋅ k + ( s − 1 ) ⋅ n s ⋅ h ′ ⋅ w ′ ⋅ d ⋅ d r_{s}=\frac{n\cdot h' \cdot w' \cdot c \cdot k \cdot k}{\frac{n}{s}\cdot h'\cdot w' \cdot c \cdot k \cdot k +(s-1)\cdot \frac{n}{s}\cdot h'\cdot w' \cdot d \cdot d} rs=snhwckk+(s1)snhwddnhwckk

= c ⋅ k ⋅ k 1 s ⋅ c ⋅ k ⋅ k + s − 1 s ⋅ d ⋅ d ≈ s ⋅ c s + c − 1 ≈ s =\frac{c\cdot k \cdot k}{\frac{1}{s}\cdot{c}\cdot{k}\cdot{k}+\frac{s-1}{s}\cdot d \cdot d} ≈\frac{s\cdot c}{s+c-1} ≈ s =s1ckk+ss1ddckks+c1scs

其中 d × d d \times d d×d 的幅度与 k × k k \times k k×k 相似,并且 s ≪ c s\ll c sc。同样,参数压缩比可以计算为:

r c = n ⋅ c ⋅ k ⋅ k n s ⋅ c ⋅ k ⋅ k + ( s − 1 ) ⋅ n s ⋅ d ⋅ d ≈ s ⋅ c s + c − 1 ≈ s r_{c} =\frac{n\cdot c\cdot k \cdot k}{\frac{n}{s}\cdot{c}\cdot{k}\cdot{k}+(s-1)\cdot \frac{n}{s}\cdot d \cdot d} ≈\frac{s\cdot c}{s+c-1} ≈ s rc=snckk+(s1)snddnckks+c1scs

其实 GhostNet 的方法也很简单,无外乎就是将原本的乘法变成了两个乘法相加,然后在代码实现中,其实第二个变换是用 depthwise conv 实现的。作者在文中也提到,前面的卷积使用 pointwise 效率比较高,所以网络嫣然类似一个 mobilenet 的反过来的版本,只不过 GhostNet 采用了拼接的方式,进一步减少了计算量。Ghost module 的 pytorch 代码如下:

#Ghost 模块,以普通卷积和 DW 卷积组合而成
class GhostModule(nn.Module):def __init__(self, in_channels,out_channels,s=2, kernel_size=1,stride=1, use_relu=True):super(GhostModule, self).__init__()intrinsic_channels = out_channels//sghost_channels = intrinsic_channels * (s - 1)self.primary_conv = nn.Sequential(nn.Conv2d(in_channels=in_channels, out_channels=intrinsic_channels, kernel_size=kernel_size, stride=stride,padding=kernel_size // 2, bias=False),nn.BatchNorm2d(intrinsic_channels),nn.ReLU(inplace=True) if use_relu else nn.Sequential())self.cheap_op = DW_Conv3x3BNReLU(in_channels=intrinsic_channels, out_channels=ghost_channels, stride=stride,groups=intrinsic_channels)def forward(self, x):y = self.primary_conv(x)z = self.cheap_op(y)out = torch.cat([y, z], dim=1)return out

Ghost bottleneck

Ghost bottleneck 与 ResNet 中的基本残差块(Basic Residual Block)结构相似,可以认为是将 Basic Residual Block 中的卷积操作用 Ghost Module 替换得到。

Ghost bottleneck 主要由两个堆叠的 Ghost Module 组成。第一个 Ghost Module 用于增加通道数。第二个 Ghost Module 用于减少通道数,以与 shortcut 路径匹配。然后,使用 shortcut 连接这两个 Ghost Module 的输入和输出。这里借鉴了 MobileNetV2,第二个 Ghost Module 之后不使用 ReLU 激活函数,其他层在每层之后都应用了批量归一化(BN)和 ReLU 非线性激活。作者设计了 2 种 Ghost bottleneck。如下图所示,分别对应着 stride=1 和 stride=2 的情况。Ghost bottleNeck 结构如下图所示:

在这里插入图片描述

左图中,主干通路用两 Ghost Module 串联组成,其中第一个 Ghost Module 扩大通道数,第二个 Ghost Module 将通道数降低到与输入通道数一致;残差边部分与 ResNet 一样。由于 Stride=1,因此不会对输入特征图的高和宽进行压缩,其功能为加深网络的深度。

右图中,主干通路的两个 Ghost Module 之间加入了一个 Stride=2 的 DWConv,可以将特征图高和宽进行压缩,使其大小降为输入的 1 2 \frac {1}{2} 21;在残差边部分,也会添加一个步长为 2 的 DWConv 和 1x1 的 PWConv,以保证 Add 操作可以对齐。这个模块可以用来替换其他 CNN 中的下采样层(1/2)。出于效率考虑,Ghost Module 中的所有标准卷积都用 PWConv 代替。

#Ghost 瓶颈层实现
class GhostBottleneck(nn.Module):def __init__(self, in_channels,mid_channels, out_channels , kernel_size, stride, use_se, se_kernel_size=1):super(GhostBottleneck, self).__init__()self.stride = strideself.bottleneck = nn.Sequential(GhostModule(in_channels=in_channels,out_channels=mid_channels,kernel_size=1,use_relu=True),DW_Conv3x3BNReLU(in_channels=mid_channels, out_channels=mid_channels, stride=stride,groups=mid_channels) if self.stride>1 else nn.Sequential(),SqueezeAndExcite(mid_channels,mid_channels,se_kernel_size) if use_se else nn.Sequential(),GhostModule(in_channels=mid_channels, out_channels=out_channels, kernel_size=1, use_relu=False))if self.stride>1:self.shortcut = DW_Conv3x3BNReLU(in_channels=in_channels, out_channels=out_channels, stride=stride)else:self.shortcut = nn.Conv2d(in_channels=in_channels, out_channels=out_channels, kernel_size=1, stride=1)def forward(self, x):out = self.bottleneck(x)residual = self.shortcut(x)out += residualreturn out

网络结构

GhostNet 主要由一堆 Ghost bottleneck 组成,其中 Ghost bottleneck 以 Ghost 模块为构建基础;

第一层是具有 16 个卷积核的标准卷积层,然后是一系列 Ghost bottleneck,通道逐渐增加。这些 Ghost bottleneck 根据其输入特征图的大小分为不同的阶段;除了每个阶段的最后一个 Ghost bottleneck 是 stride = 2,其他所有 Ghost bottleneck 都以 stride = 1 进行应用;

最后,利用全局平均池和卷积层将特征图转换为 1280 维特征向量以进行最终分类。SE 模块也用在了某些 Ghost bottleneck 中的残留层;

与 MobileNetV3 相比,这里用 ReLU 换掉了 Hard-swish 激活函数。尽管进一步的超参数调整或基于自动架构搜索的 Ghost 模块将进一步提高性能;

GhostNet V2 模型

GhostNet V2:GhostV2 的主要工作就是在 Ghost module 的基础上,添加了一个改进的注意力块。文中称为解耦全连接注意力机制 DFC(Decouplod fully connected)。它不仅可以在普通硬件上快速执行,还可以捕获远程像素之间的依赖关系。大量的实验表明,GhostNetV2 优于现有的体系结构。例如,它在具有 167M FLOPs 的 ImageNet 上实现了 75.3%的 top-1 精度,显著高于 GhostNetV1 (74.5%),但计算成本相似。

DFC 模块

虽然自注意力操作可以很好地建模长距离依赖,但是部署效率低。相比自注意力机制,具有固定权重的 FC 层更简单,更容易实现,也可以用于生成具有全局感受野的 attention maps。

给定特征图 Z ∈ R H × W × C Z ∈ R ^{H \times W\times C} ZRH×W×C,它可以看作 hw 的 tokens,记作 z i ∈ R C z_{i}\in R^{C} ziRC,也就是 Z = z 11 , z 12 , . . . , z h w Z={z_{11},z_{12},...,z_{hw}} Z=z11,z12,...,zhw。FC 层生成 attention map 的公式表达如下:

a h w = ∑ h ′ , w ′ F h , w , h ′ , w ′ ⊙ z h ′ , w ′ (1) a_{hw} = \sum_{h',w'} F_{h,w,h',w'}\odot z_{h',w'}\tag{1} ahw=h,wFh,w,h,wzh,w(1)

其中, ⊙ \odot 表示 element-wise multiplication,F 是 FC 层中可学习的权重, A = a 11 , a 12 , . . . , a H W A={a_{11},a_{12},...,a_{HW}} A=a11,a12,...,aHW。根据上述公式,将所有 tokens 与可学习的权重聚合在一起以提取全局信息,该过程比经典的自注意力简单的多。然而,该过程的计算复杂度仍然是二次方,特征图的大小为 $ \mathcal{O}({H{2}W{2}})$,这在实际情况下是不可接受的,特别是当输入的图像是高分辨率时。

例如,对于 4 层的 GhostNet 网络的特征图具有 3136 ( 56 × 56 ) (56 \times 56) (56×56) 个 tokens,这使得计算变得 attention maps 异常复杂。实际上,CNN 中的特征图通常是低秩的,不需要将不同空间位置的所有输入和输出的 tokens 密集地连接起来。特征的 2D 尺寸很自然地提供一个视角,以减少 FC 层的计算量,也就是根据上述公式分解为两个 FC 层,分别沿水平方向和垂直方向聚合特征,其公式表达如下:

a h w ′ = ∑ h ′ = 1 H F h , h ′ w H ⊙ z h ′ w , h = 1 , 2 , . . . , H , w = 1 , 2 , . . . , W (2) a'_{hw} =\sum_{h'=1}^{H}F^{H}_{h,h'w}\odot z_{h'w},h=1,2,...,H,w=1,2,...,W \tag{2} ahw=h=1HFh,hwHzhw,h=1,2,...,H,w=1,2,...,W(2)

a h w = ∑ w ′ = 1 W F w , h w ′ W ⊙ z h ′ w , h = 1 , 2 , . . . , H , w = 1 , 2 , . . . , W (3) a_{hw} =\sum_{w'=1}^{W}F^{W}_{w,hw'}\odot z_{h'w},h=1,2,...,H,w=1,2,...,W \tag{3} ahw=w=1WFw,hwWzhw,h=1,2,...,H,w=1,2,...,W(3)

其中, F H F^{H} FH F W F^{W} FW 是变换的权重。输入原始特征 Z,并依次应用公式(2)和公式(3),分别提取沿两个方向的长距离依赖关系。作者将此操作称为解耦全连接注意力(decoupled fully connected attention,DFC attention),其信息流如下图所示:

在这里插入图片描述

由于水平和垂直方向变换的解耦,注意力模块的计算复杂度可以降低到 O ( H 2 W + H W 2 ) \mathcal{O}(H^{2}W+HW^{2}) O(H2W+HW2) 对于 full attention (公式 1),正方形区域内的所有 patches 直接参与被聚合 patch 的计算。在 DFC attention 中,一个 patch 直接由其垂直方向和水平方向的 patch 进行聚合,而其他 patch 参与垂直线/水平线上的 patch 的生成,与被聚合的 token 有间接关系。因此,一个 patch 的计算也涉及到正方形区域的所有 patchs。

公式(2)和公式(3)是 DFC attention 的一般表示,分别沿着水平和垂直方向聚合像素。通过共享部分变换权重,可以方便地使用卷积操作实现,省去了影响实际推理速度的耗时张量的 reshape 操作和 transpose 操作。为了处理不同分辨率的输入图像,卷积核的大小可以与特征图的大小进行解耦,也就是在输入特征上依次进行两个大小为 1 × K H 1 \times K_{H} 1×KH 和 $ K_{W} \times 1$ 的 DWConv 操作。当用卷积操作时,DFC attention 理论上的计算复杂度为 O ( K H H W + K W H W ) \mathcal{O}(K_{H}HW+K_{W}HW) O(KHHW+KWHW)。这种策略得到了 TFLite 和 ONNX 等工具的良好支持,可以在移动设备上进行快速推理。

class GhostModuleV2(nn.Module):def __init__(self, inp, oup, kernel_size=1, ratio=2, dw_size=3, stride=1, relu=True,mode=None,args=None):super(GhostModuleV2, self).__init__()self.mode=modeself.gate_fn=nn.Sigmoid()if self.mode in ['original']:self.oup = oupinit_channels = math.ceil(oup / ratio) new_channels = init_channels*(ratio-1)self.primary_conv = nn.Sequential(  nn.Conv2d(inp, init_channels, kernel_size, stride, kernel_size//2, bias=False),nn.BatchNorm2d(init_channels),nn.ReLU(inplace=True) if relu else nn.Sequential(),)self.cheap_operation = nn.Sequential(nn.Conv2d(init_channels, new_channels, dw_size, 1, dw_size//2, groups=init_channels, bias=False),nn.BatchNorm2d(new_channels),nn.ReLU(inplace=True) if relu else nn.Sequential(),)elif self.mode in ['attn']: self.oup = oupinit_channels = math.ceil(oup / ratio) new_channels = init_channels*(ratio-1)self.primary_conv = nn.Sequential(  nn.Conv2d(inp, init_channels, kernel_size, stride, kernel_size//2, bias=False),nn.BatchNorm2d(init_channels),nn.ReLU(inplace=True) if relu else nn.Sequential(),)self.cheap_operation = nn.Sequential(nn.Conv2d(init_channels, new_channels, dw_size, 1, dw_size//2, groups=init_channels, bias=False),nn.BatchNorm2d(new_channels),nn.ReLU(inplace=True) if relu else nn.Sequential(),) self.short_conv = nn.Sequential( nn.Conv2d(inp, oup, kernel_size, stride, kernel_size//2, bias=False),nn.BatchNorm2d(oup),nn.Conv2d(oup, oup, kernel_size=(1,5), stride=1, padding=(0,2), groups=oup,bias=False),nn.BatchNorm2d(oup),nn.Conv2d(oup, oup, kernel_size=(5,1), stride=1, padding=(2,0), groups=oup,bias=False),nn.BatchNorm2d(oup),) def forward(self, x):if self.mode in ['original']:x1 = self.primary_conv(x)x2 = self.cheap_operation(x1)out = torch.cat([x1,x2], dim=1)return out[:,:self.oup,:,:]         elif self.mode in ['attn']:  res=self.short_conv(F.avg_pool2d(x,kernel_size=2,stride=2))  x1 = self.primary_conv(x)x2 = self.cheap_operation(x1)out = torch.cat([x1,x2], dim=1)return out[:,:self.oup,:,:]*F.interpolate(self.gate_fn(res),size=(out.shape[-2],out.shape[-1]),mode='nearest') 

增强 Ghost 模块

Ghost Module 中只有 m 个特征与其他像素交互,这影响了 Ghost Module 提取空间信息(spatial information)的能力。因此,作者使用 DFC attention 来增强 Ghost Module 的输出特征 Y ,从而来捕获不同空间像素之间的长距离依赖关系。输入特征 X ∈ R h × w × c X \in R^{h \times w \times c} XRh×w×c 被送入两个分支,一个是 Ghost Module 分支,用于输出特征 Y,另一个是 DFC attention Module 分支,用于生成 attention map,记作 A A A

回想一下,在经典的自注意力中,线性变换层将输入特征图转换为计算 attention maps 的 query 和 key。类似的,作者实现一个 1 × 1 1 \times 1 1×1 的卷积操作,将 Ghost Module 分支的输入 X X X 转换为 DFC module 分支的输入 Z Z Z。两个分支输出的乘积,即为最终输出 O ∈ R H × W × C O\in {R}^{H \times W\times C} ORH×W×C 可以表示为:

KaTeX parse error: Can't use function '$' in math mode at position 2: $̲\mathcal{O} = S…

其中, ⊙ \odot 表示 element-wise multiplication, A A A 是 attention map,Sigmoid 是归一化函数以缩放到 ( 0 , 1 ) 范围。$ \mathcal{V}()$ 表示 Ghost Module,$X $ 为输入特征。则信息聚合过程如下图所示:

在这里插入图片描述

使用相同的输入特征,Ghost Module 和 DFC attention 是两个从不同角度提取信息的并行分支。输出特征是它们逐元素的信息,其中包含来自 Ghost Module 的特性和 DFC attention 的信息。每个 attention value 涉及到大范围的 patches,以便输出的特征可以包含这些 patches 的信息。

模型结构实现

为了减小 DFC attention 模块所消耗的计算量,本文对 DFC 这条支路上的特征进行下采样,在更小的特征图上执行一系列变换。同时,本文发现,对一个逆 bottleneck 结构而言,增强“expressiveness”(bottleneck 中间层)比“capacity”(bottleneck 输出层)更加有效,因此在 GhostNetV2 只对中间特征做了增强。GhostNetV2 的 bottleneck 如下图所示。

在这里插入图片描述

class GhostBottleneckV2(nn.Module): def __init__(self, in_chs, mid_chs, out_chs, dw_kernel_size=3,stride=1, act_layer=nn.ReLU, se_ratio=0.,layer_id=None,args=None):super(GhostBottleneckV2, self).__init__()has_se = se_ratio is not None and se_ratio > 0.self.stride = stride# Point-wise expansionif layer_id<=1:self.ghost1 = GhostModuleV2(in_chs, mid_chs, relu=True,mode='original',args=args)else:self.ghost1 = GhostModuleV2(in_chs, mid_chs, relu=True,mode='attn',args=args) # Depth-wise convolutionif self.stride > 1:self.conv_dw = nn.Conv2d(mid_chs, mid_chs, dw_kernel_size, stride=stride,padding=(dw_kernel_size-1)//2,groups=mid_chs, bias=False)self.bn_dw = nn.BatchNorm2d(mid_chs)# Squeeze-and-excitationif has_se:self.se = SqueezeExcite(mid_chs, se_ratio=se_ratio)else:self.se = Noneself.ghost2 = GhostModuleV2(mid_chs, out_chs, relu=False,mode='original',args=args)# shortcutif (in_chs == out_chs and self.stride == 1):self.shortcut = nn.Sequential()else:self.shortcut = nn.Sequential(nn.Conv2d(in_chs, in_chs, dw_kernel_size, stride=stride,padding=(dw_kernel_size-1)//2, groups=in_chs, bias=False),nn.BatchNorm2d(in_chs),nn.Conv2d(in_chs, out_chs, 1, stride=1, padding=0, bias=False),nn.BatchNorm2d(out_chs),)def forward(self, x):residual = xx = self.ghost1(x)if self.stride > 1:x = self.conv_dw(x)x = self.bn_dw(x)if self.se is not None:x = self.se(x)x = self.ghost2(x)x += self.shortcut(residual)return x

如果您想了解更多AI知识,与AI专业人士交流,请立即访问昇腾社区官方网站https://www.hiascend.com/或者深入研读《AI系统:原理与架构》一书,这里汇聚了海量的AI学习资源和实践课程,为您的AI技术成长提供强劲动力。不仅如此,您还有机会投身于全国昇腾AI创新大赛和昇腾AI开发者创享日等盛事,发现AI世界的无限奥秘~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/888682.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

YOLOv8改进,YOLOv8引入CARAFE轻量级通用上采样算子,助力模型涨点

摘要 CARAFE模块的设计目的是在不增加计算复杂度的情况下,提升特征图的质量,特别是在视频超分辨率任务中,提升图像质量和细节。CARAFE结合了上下文感知机制和聚合特征的能力,通过动态的上下文注意力机制来提升细节恢复的效果。 理论介绍 传统的卷积操作通常依赖于局部区域…

大型制造企业IT蓝图、信息化系统技术架构规划与实施路线方案

关注 获取ppt​​​​​​全文&#xff0c;请关注作者

HTTP 长连接(HTTP Persistent Connection)简介

HTTP长连接怎么看&#xff1f; HTTP 长连接&#xff08;HTTP Persistent Connection&#xff09;简介 HTTP 长连接&#xff08;Persistent Connection&#xff09;是 HTTP/1.1 的一个重要特性&#xff0c;它允许在一个 TCP 连接上发送多个 HTTP 请求和响应&#xff0c;而无需为…

001集—— 创建一个WPF项目 ——WPF应用程序入门 C#

本例为一个WPF应用&#xff08;.NET FrameWork&#xff09;。 首先创建一个项目 双击xaml文件 双击xaml文件进入如下界面&#xff0c;开始编写代码。 效果如下&#xff1a; 付代码&#xff1a; <Window x:Class"WpfDemoFW.MainWindow"xmlns"http://schema…

微信小程序配置less并使用

1.在VScode中下载Less插件 2.在微信小程序中依次点击如下按钮 选择 从已解压的扩展文件夹安装… 3.选中刚在vscode中下载安装的插件文件 如果没有修改过插件的安装目录&#xff0c;一般是在c盘下C:\用户\用户名.vscode\extensions\mrcrowl.easy-less-2.0.2 我的路径是&#xf…

Vue网页屏保

Vue网页屏保 在vue项目中&#xff0c;如果项目长时间未操作需要弹出屏幕保护程序&#xff0c;以下为网页屏保效果&#xff0c;看板内容为连接的资源。 屏保组件 <template><div v-if"isActive" class"screensaver" click"disableScreens…

【SpringBoot】使用IDEA创建SpringBoot项目

1、使用SpringBoot脚手架创建 我们使用SpringBoot的脚手架Spring Initializr创建&#xff0c;如图所示&#xff1a; 2、选择SpringBoot版本 最开始做项目时候&#xff0c;组长说创建一个 springboot 2.5.4 的项目&#xff0c;mysql使用 5.6.X &#xff0c;maven使用是3.6.X…

如何在鸿蒙API9和x86模拟器中使用MQTT

目录 引言 安装MQTT软件包 避免MQTT软件包自动升级 程序的编写 运行测试 结语 引言 虽然我的课主要是OpenHarmony南向开发的&#xff0c;但是结课时有个同学说他在写鸿蒙APP时无法将MQTT库加入到设备中&#xff0c;希望我帮忙看看。由于他没有鸿蒙的真机&#xff0c;只能…

保姆级教程用vite创建vue3项目并初始化添加PrimeVue UI踩坑实录

文章目录 一、什么是PrimeVue二、详细教程1.添加PrimeVue2.配置main.js3.添加自动引入4.配置vite.config.js5.创建测试页面 一、什么是PrimeVue PrimeVue 是一个用于 Vue.js 3.x 开发的一款高质量、广受欢迎的 Web UI 组件库。 官网地址&#xff1a;https://primevue.org/ 二、…

QT的ui界面显示不全问题(适应高分辨率屏幕)

//自动适应高分辨率 QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);一、问题 电脑分辨率高&#xff0c;默认情况下&#xff0c;打开QT的ui界面&#xff0c;显示不全按钮内容 二、解决方案 如果自己的电脑分辨率较高&#xff0c;可以尝试以下方案&#xff1a;自…

超级详细,如何手动安装python第三方库?

文章目录 1&#xff0c;python第三方库安装包有3种类型2&#xff0c;python第三方库安装包whl文件如何安装&#xff1f;3&#xff0c;python第三方库安装包zip和tar.gz文件如何安装&#xff1f;4&#xff0c; python第三方库安装包exe文件如何安装&#xff1f; 手动安装第三方库…

Alibaba EasyExcel 导入导出全家桶

一、阿里巴巴EasyExcel的优势 首先说下EasyExcel相对 Apache poi的优势&#xff1a; EasyExcel也是阿里研发在poi基础上做了封装&#xff0c;改进产物。它替开发者做了注解列表解析&#xff0c;表格填充等一系列代码编写工作&#xff0c;并将此抽象成通用和可扩展的框架。相对p…

什么叫自动获得ip地址?自动获得的ip地址怎么设置

在数字化时代&#xff0c;网络连接已成为我们日常生活和工作中不可或缺的一部分。然而&#xff0c;对于非技术用户而言&#xff0c;复杂的网络配置常常令人感到困惑。幸运的是&#xff0c;自动获得IP地址技术的出现&#xff0c;极大地简化了网络配置过程。本文将详细介绍自动获…

流媒体之linux下离线部署FFmpeg 和 SRS

前言 用户对网络做了限制&#xff0c;只能访问指定的网址&#xff0c;和没网没啥区别&#xff0c;导致无法连接外网&#xff0c;无法获取安装包&#xff0c;还有一些编译需要的开源工具 用户需要用平台查看库房的海康摄像头实时监控&#xff0c;只能在库房里一台纯净的ubantu…

数字时代的文化宝库:存储技术与精神生活

文章目录 1. 文学经典的数字传承2. 音乐的无限可能3. 影视艺术的数字化存储4. 结语 数字时代的文化宝库&#xff1a;存储技术与精神生活 在数字化的浪潮中&#xff0c;存储技术如同一座桥梁&#xff0c;连接着过去与未来&#xff0c;承载着人类文明的瑰宝。随着存储容量的不断增…

渗透测试之Web基础之Linux病毒编写——泷羽sec

声明&#xff1a; 学习视频来自B站UP主泷羽sec,如涉及侵权马上删除文章。本文只涉及学习内容,其他的都与本人无关,切莫逾越法律红线,否则后果自负 泷羽sec的个人空间-泷羽sec个人主页-哔哩哔哩视频 (bilibili.com)https://space.bilibili.com/350329294 导读&#xff1a; 时刻…

基于神经网络的弹弹堂类游戏弹道快速预测

目录 一、 目的... 1 1.1 输入与输出.... 1 1.2 隐网络架构设计.... 1 1.3 激活函数与损失函数.... 1 二、 训练... 2 2.1 数据加载与预处理.... 2 2.2 训练过程.... 2 2.3 训练参数与设置.... 2 三、 测试与分析... 2 3.1 性能对比.... 2 3.2 训练过程差异.... 3 四、…

Xlsxwriter生成Excel文件时TypeError异常处理

在使用 XlsxWriter 生成 Excel 文件时&#xff0c;如果遇到 TypeError&#xff0c;通常是因为尝试写入的值或格式与 XlsxWriter 的限制或要求不兼容。 1、问题背景 在使用 Xlsxwriter 库生成 Excel 文件时&#xff0c;出现 TypeError: “expected string or buffer” 异常。此…

MATLAB期末复习笔记(下)

目录 五、数据和函数的可视化 1.MATLAB的可视化对象 2.二维图形的绘制 3.图形标识 4.多子图绘图 5.直方图的绘制 &#xff08;1&#xff09;分类 &#xff08;2&#xff09;垂直累计式 &#xff08;3&#xff09;垂直分组式 &#xff08;4&#xff09;水平分组式 &…

操作系统学习

问题&#xff1a; 因为想用傲梅来给系统盘扩容&#xff0c;导致无法进入操作系统&#xff0c;报错如下&#xff1a; 无法加载应用程序或操作系统&#xff0c;原因是所需文件丢失或包含错误. 文件:Windowslsystem32lwinload.efi错误代码: 0xc000007b 你需要使用恢复工具。如果…