【论文笔记】FasterNet:Run, Don’t Walk: Chasing Higher FLOPS for Faster Neural Networks

这篇具有很好参考价值的文章主要介绍了【论文笔记】FasterNet:Run, Don’t Walk: Chasing Higher FLOPS for Faster Neural Networks。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

【论文笔记】FasterNet:Run, Don’t Walk: Chasing Higher FLOPS for Faster Neural Networks,论文,论文阅读,深度学习,神经网络
为了设计快速神经网络,许多工作都集中在减少浮点运算(FLOPs)的数量上。然而,作者观察到FLOPs的这种减少不一定会带来延迟的类似程度的减少。这主要源于每秒低浮点运算(FLOPS)效率低下。

为了实现更快的网络,作者重新回顾了FLOPs的运算符,并证明了如此低的FLOPS主要是由于运算符的频繁内存访问,尤其是深度卷积。因此,本文提出了一种新的partial convolution(PConv),通过同时减少冗余计算和内存访问可以更有效地提取空间特征。

基于PConv进一步提出FasterNet,这是一个新的神经网络家族,它在广泛的设备上实现了比其他网络高得多的运行速度,而不影响各种视觉任务的准确性。例如,在ImageNet-1k上小型FasterNet-T0在GPU、CPU和ARM处理器上分别比MobileVitXXS快3.1倍、3.1倍和2.5倍,同时准确度提高2.9%。

大模型FasterNet-L实现了令人印象深刻的83.5%的TOP-1精度,与Swin-B不相上下,同时GPU上的推理吞吐量提高了49%,CPU上的计算时间也节省了42%。

论文链接🔗:Run, Don’t Walk: Chasing Higher FLOPS for Faster Neural Networks


1. 介绍

在提升快速性上,研究人员和从业者通常是倾向于设计具有成本效益的快速神经网络,降低计算复杂度,这一点主要通过浮点运算(FLOPs)来衡量。FLOPs是floating point of operations的缩写,是浮点运算次数,可以用来衡量算法/模型复杂度。

MobileNet、ShuffleNet和GhostNet等利用深度卷积(DWConv)和/或组卷积(GConv)来提取空间特征。然而,在减少FLOPs的过程中,算子经常会受到内存访问增加的副作用的影响。

除了上述纯卷积神经网络(CNNs)之外,人们对使视觉Transformer(ViTs)和多层感知器(MLP)架构更小更快也越来越感兴趣。例如,MobileViT和MobileFormer通过将DWConv与改进的注意力机制相结合,降低了计算复杂性。然而,它们仍然受到DWConv的上述问题的困扰,并且还需要修改的注意力机制的专用硬件支持。使用先进但耗时的标准化和激活层也可能限制其在设备上的速度。

所以FLOPs的减少不一定会导致类似水平的延迟 (Latency) 减少。这主要是由于每秒浮点运算数量 (Floating-Point OPerations per Second) 较低。根据公式:
【论文笔记】FasterNet:Run, Don’t Walk: Chasing Higher FLOPS for Faster Neural Networks,论文,论文阅读,深度学习,神经网络
其中FLOPS是每秒浮点运算的缩写,这个值越高,说明硬件性能越好。
【论文笔记】FasterNet:Run, Don’t Walk: Chasing Higher FLOPS for Faster Neural Networks,论文,论文阅读,深度学习,神经网络
上图结果表明,许多现有神经网络的FLOPS较低,其FLOPS通常低于流行的ResNet50。由于FLOPS如此之低,这些“快速”的神经网络实际上不够快。它们的FLOPs减少不能转化为延迟的确切减少量。在某些情况下,没有任何改善,甚至会导致更糟的延迟。例如,CycleMLP-B1具有ResNet50的一半FLOPs,但运行速度较慢(即CycleMLPB1与ResNet50:111.9ms与69.4ms)。


为了实现更快的网络,本文重新审视了流行的算子,并证明了较低的 FLOPS 主要是由于算子的频繁内存访问,尤其是 Depth-wise Convolution。

本文旨在通过开发一种简单、快速、有效的运算符来消除这种差异,该运算符可以在减少FLOPs的情况下保持高FLOPS。具体来本文旨在通过开发一种简单、快速、有效的运算符来消除这种差异,该运算符可以在减少FLOPs的情况下保持高FLOPS。


2. 简单介绍以下深度可分离卷积

深度可分离卷积(Depthwise Separable Convolution)是指将卷积操作分解为深度卷积和逐点卷积两步操作的卷积操作。它在卷积神经网络中被广泛应用,可以用来减少模型参数数量、计算量和提高网络效果等作用。

深度可分离卷积的实现方式是,在原来的传统卷积基础上,将卷积分成两步操作:

  1. 深度卷积(Depthwise Convolution):在每个输入通道内分别进行一个卷积操作,不改变通道数
  2. 逐点卷积(Pointwise Convolution):使用1x1卷积核在深度方向上进行卷积,对输出通道进行混合和重新组合。(感觉就是1x1卷积,换了个说法而已)

相比传统卷积,深度可分离卷积具有计算量更小、模型参数更少、性能优越等优点。在移动端等计算资源受限的场景中,深度可分离卷积可以帮助提高神经网络模型的效率和性能。同时,深度可分离卷积还可以应用于目标检测、图像分割和自然语言处理等领域。Mobilenet中使用了大量的深度可分离卷积来代替传统卷积。

DWConv把Conv的计算量从 h × w × k 2 × c 2 h \times w \times k^{2} \times c^{2} h×w×k2×c2缩小到了 h × w × k 2 × c h \times w \times k^{2} \times c h×w×k2×c

虽然 DWConv 可以有效地降低 FLOPs,但它不能简单地用来取代常规的 Conv,因为会导致严重的精度下降。所以说 DWConv 通常会跟随 Pointwise Convolution (PWConv)。因此在实践中, DWConv的通道数 c (或网络宽度) 增加到c以补偿精度下降。一般在实践中 DWConv 的通道数会变宽,以补偿精度的下降 (比如 MobileNet V2 中变为了6倍宽)。但是这会带来更高的内存访问,降低整体计算速度,尤其是对于 I/O-bound 设备。

注意,这里所说的DWConv,其实就包括了深度卷积和逐点卷积。


3. PConv

3.1 部分卷积PConv的设计

本文给出的解决方案部分卷积 (Partial Convolution, PConv) 的出发点是卷积神经网络特征的冗余性。如下图所示是在预训练的 ResNet50 的中间层中可视化特征图,左上角的图像是输入,特征图在不同通道之间具有很高的相似性
【论文笔记】FasterNet:Run, Don’t Walk: Chasing Higher FLOPS for Faster Neural Networks,论文,论文阅读,深度学习,神经网络
部分卷积设计的目的是同时减小内存访问和计算冗余,其和常规卷积,DWConv 的区别如下图所示。
【论文笔记】FasterNet:Run, Don’t Walk: Chasing Higher FLOPS for Faster Neural Networks,论文,论文阅读,深度学习,神经网络
工作原理如下图所示。
【论文笔记】FasterNet:Run, Don’t Walk: Chasing Higher FLOPS for Faster Neural Networks,论文,论文阅读,深度学习,神经网络

以下会涉及参数量的计算,可以先看下这篇文章:神经网络参数量,计算量FLOPS,内存访问量MAC

PConv 对部分输入通道应用常规的 Conv 来进行空间特征提取,而对其余通道保持不变。对于连续或规则的内存访问,将第一个或最后一个连续的 c p c_{p} cp通道视为整个特征图的代表进行计算。在不丧失一般性的情况下认为输入和输出特征图具有相同数量的通道。因此

  • PConv的FLOPs h × w × k 2 × c p 2 . h \times w \times k^{2} \times c_{p}^{2} . h×w×k2×cp2.
    其中,h和w是特征图的宽和高,k是卷积和的大小, c p c_{p} cp是常规卷积作用的通道数,相当于之前普通卷积的 c i n c_{in} cin变成了 c p c_{p} cp
    在实际实现时一般 r = c p c = 1 4 r=\frac{c_{p}}{c}=\frac{1}{4} r=ccp=41。所以,PConv的FLOPs只有常规卷积的1/16。
  • PConv的内存访问情况: h × w × 2 c p + k 2 × c p 2 ≈ h × w × 2 c p h \times w \times 2 c_{p}+k^{2} \times c_{p}^{2} \approx h \times w \times 2 c_{p} h×w×2cp+k2×cp2h×w×2cp
    其中,h和w是特征图的宽和高,k是卷积和的大小, c p c_{p} cp是常规卷积作用的通道数。PConv的内存访问量仅仅是常规卷积的1/4,所以无需进行内存的访问。

3.2 PConv 之后的 Point-Wise Convolution

为了充分有效地利用来自所有通道的信息,作者进一步在 PConv 之后增加了 Point-Wise Convolution (PWConv),没错就是DWConv之后的那个东西,一般是用来升维的。如下图所示,在输入特征图上的有效感受野一起看起来像一个 T 型的 Conv,和常规 Conv 相比,它更关注中心位置。
【论文笔记】FasterNet:Run, Don’t Walk: Chasing Higher FLOPS for Faster Neural Networks,论文,论文阅读,深度学习,神经网络

  • T型的Conv的FLOPs h × w × ( k 2 × c p × c + c × ( c − c p ) ) h \times w \times\left(k^{2} \times c_{p} \times c+c \times\left(c-c_{p}\right)\right) h×w×(k2×cp×c+c×(ccp))
  • 解耦成PConv和PWConv的FLOPs h × w × ( k 2 × c p 2 + c × c p ) h \times w \times\left(k^{2} \times c_{p}^{2}+c \times c_{p}\right) h×w×(k2×cp2+c×cp)

很明显,解耦后的计算量更小。

3.3 PConv的代码

class PConv(nn.Module):
    """ Partial convolution (PConv).
    """
    def __init__(self,
                 dim: int,
                 n_div: int,
                 forward: str = "split_cat",
                 kernel_size: int = 3) -> None:
        """ Construct a PConv layer.

        :param dim: Number of input/output channels
        :param n_div: Reciprocal of the partial ratio.
        :param forward: Forward type, can be either 'split_cat' or 'slicing'.
        :param kernel_size: Kernel size.
        """
        super().__init__()
        self.dim_conv = dim // n_div
        self.dim_untouched = dim - self.dim_conv

        self.conv = nn.Conv2d(
            self.dim_conv,
            self.dim_conv,
            kernel_size,
            stride=1,
            padding=(kernel_size - 1) // 2,
            bias=False
        )

        if forward == "slicing":
            self.forward = self.forward_slicing
        elif forward == "split_cat":
            self.forward = self.forward_split_cat
        else:
            raise NotImplementedError

    def forward_slicing(self, x: Tensor) -> Tensor:
        """ Apply forward pass for inference. """
        x[:, :self.dim_conv, :, :] = self.conv(x[:, :self.dim_conv, :, :])

        return x

    def forward_split_cat(self, x: Tensor) -> Tensor:
        """ Apply forward pass for training. """
        x1, x2 = torch.split(x, [self.dim_conv, self.dim_untouched], dim=1)
        x1 = self.conv(x1)
        x = torch.cat((x1, x2), 1)

        return x

注意下forward_slicing中的卷积操作,我一开始还在想要怎么做到部分卷积,没想到就是切片,还是蛮有意思的。

另外,通过代码forward_split_cat可以看到,训练阶段的PConv只是进行了部分卷积,没有进行PW卷积。

4. 基于PConv的视觉骨干模型 FasterNet

4.1 实现细节

鉴于新型PConv和现成的PWConv作为主要的算子,进一步提出FasterNet,这是一个新的神经网络家族,运行速度非常快,对许多视觉任务非常有效。作者的目标是使体系结构尽可能简单,使其总体上对硬件友好。
【论文笔记】FasterNet:Run, Don’t Walk: Chasing Higher FLOPS for Faster Neural Networks,论文,论文阅读,深度学习,神经网络
如上图所示,他有4个Stages,Stage1之前通过了Embedding层(一个常规的4x4卷积,步长为4,相当于将宽高缩小为了1/4),其他的Stage之前使用Merging层(常规个2x2卷积,步长为2,也是起下采样作用),每个 Stage 都由一些 FasterNet 块堆叠而成。

这里注意下几个细节。

  • 作者观察到,最后两个Stage中的块消耗更少的内存访问,并且具有更高的FLOPS,因此,作者在最后2个 Stage放置了更多的 FasterNet 块,并相应地将更多的计算分配到最后2个 Stage。
  • 每个 FasterNet 块都是由1个 PConv 和后续的两个 1×1 的 Point-wise Convolution 构成的。这三者构成了一个倒残差的架构,中间层的通道数量更多,并放置了一个 Shortcut 连接以重用输入特征。

可以发现,FasterNet Block是不会改变图像大小的,只有Merging才会进行下采样。

4.2 Normalization 层和激活函数的使用

Normalization 层和激活函数神经网络而言是必不可少的,但是如果在整个网络中过度使用这些层,就有可能会限制特征的多样性,从而损害网络的性能,还可能会降低整体计算速度。所以作者只把它们放在每个中间层的 PWConv 之后,以保持特征多样性并获得更低的 Latency。

FasterNet 使用 BN 来代替 LN 等。BN 的好处是它可以通过结构重参数化的方式合并到相邻的 Conv 层中,以便更快地推断。

对于激活函数,考虑到运行时间和有效性,作者经验性地选择 GELU 作为较小的 FasterNet 变体,ReLU 作为较大的 FasterNet 变体。

为了在不同的计算预算下服务于广泛的应用程序,作者提供了 FasterNetT0/1/2,FasterNet-S,FasterNet-M,和 FasterNet-L。

4.3 代码实现

# PConv
class Partial_conv3(nn.Module):
    def __init__(self, dim, n_div, forward):
        super().__init__()
        self.dim_conv3 = dim // n_div
        self.dim_untouched = dim - self.dim_conv3
        self.partial_conv3 = nn.Conv2d(self.dim_conv3, self.dim_conv3, 3, 1, 1, bias=False)
 
        if forward == 'slicing':
            self.forward = self.forward_slicing
        elif forward == 'split_cat':
            self.forward = self.forward_split_cat
        else:
            raise NotImplementedError
 
    def forward_slicing(self, x):
        # only for inference
        x = x.clone()  # !!! Keep the original input intact for the residual connection later
        x[:, :self.dim_conv3, :, :] = self.partial_conv3(x[:, :self.dim_conv3, :, :])
 
        return x
 
    def forward_split_cat(self, x):
        # for training/inference
        x1, x2 = torch.split(x, [self.dim_conv3, self.dim_untouched], dim=1)
        x1 = self.partial_conv3(x1)
        x = torch.cat((x1, x2), 1)
        return x
 
 
class MLPBlock(nn.Module):
    def __init__(self,
                 dim,
                 n_div,
                 mlp_ratio,
                 drop_path,
                 layer_scale_init_value,
                 act_layer,
                 norm_layer,
                 pconv_fw_type
                 ):
 
        super().__init__()
        self.dim = dim
        self.mlp_ratio = mlp_ratio
        self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()
        self.n_div = n_div
 
        mlp_hidden_dim = int(dim * mlp_ratio)
 
        mlp_layer = [
            nn.Conv2d(dim, mlp_hidden_dim, 1, bias=False),
            norm_layer(mlp_hidden_dim),
            act_layer(),
            nn.Conv2d(mlp_hidden_dim, dim, 1, bias=False)
        ]
 
        self.mlp = nn.Sequential(*mlp_layer)
 
        self.spatial_mixing = Partial_conv3(
            dim,
            n_div,
            pconv_fw_type
        )
 
        if layer_scale_init_value > 0:
            self.layer_scale = nn.Parameter(layer_scale_init_value * torch.ones((dim)), requires_grad=True)
            self.forward = self.forward_layer_scale
        else:
            self.forward = self.forward
 
    def forward(self, x):
        shortcut = x
        x = self.spatial_mixing(x)
        x = shortcut + self.drop_path(self.mlp(x))
        return x
 
    def forward_layer_scale(self, x):
        shortcut = x
        x = self.spatial_mixing(x)
        x = shortcut + self.drop_path(
            self.layer_scale.unsqueeze(-1).unsqueeze(-1) * self.mlp(x))
        return x
 
  # FasterNet基础模块
class BasicStage(nn.Module):
    def __init__(self,
                 dim,
                 depth=1,
                 n_div=4,
                 mlp_ratio=2,
                 # drop_path=[0.0],
                 layer_scale_init_value=0,
                 norm_layer=nn.BatchNorm2d,
                 act_layer=nn.ReLU,
                 pconv_fw_type='split_cat'
                 ):
        super().__init__()
        dpr = [x.item()
               for x in torch.linspace(0, 0.0, sum([1, 2, 8, 2]))]
        blocks_list = [
            MLPBlock(
                dim=dim,
                n_div=n_div,
                mlp_ratio=mlp_ratio,
                drop_path=dpr[i],
                layer_scale_init_value=layer_scale_init_value,
                norm_layer=norm_layer,
                act_layer=act_layer,
                pconv_fw_type=pconv_fw_type
            )
            for i in range(depth)
        ]
 
        self.blocks = nn.Sequential(*blocks_list)
 
    def forward(self, x):
        x = self.blocks(x)
        return x
 
 # 最开始的下采样
class PatchEmbed(nn.Module):
 
    def __init__(self, in_chans, embed_dim, patch_size, patch_stride, norm_layer):
        super().__init__()
        self.proj = nn.Conv2d(in_chans, embed_dim, kernel_size=patch_size, stride=patch_stride, bias=False)
        if norm_layer is not None:
            self.norm = norm_layer(embed_dim)
        else:
            self.norm = nn.Identity()
 
    def forward(self, x):
        x = self.norm(self.proj(x))
        return x
 
    def fuseforward(self, x):
        x = self.proj(x)
        return x
 
 # 后面的下采样
class PatchMerging(nn.Module):
 
    def __init__(self, dim, out_dim, k, patch_stride2, norm_layer=nn.BatchNorm2d):
        super().__init__()
        self.reduction = nn.Conv2d(dim, out_dim, kernel_size=k, stride=patch_stride2, bias=False)
        if norm_layer is not None:
            self.norm = norm_layer(out_dim)
        else:
            self.norm = nn.Identity()
 
    def forward(self, x):
        x = self.norm(self.reduction(x))
        return x
 
    def fuseforward(self, x):
        x = self.reduction(x)
        return x

5. PConv具有更高的FLOPS

作者在3种不同设备上测量 Latency (Batch Size=1) 和 Throughput (Batch Size=32),GPU (2080Ti), CPU (Intel i9-9900X, using a single thread), 和 ARM。

本小节作者展示了 PConv 速度更快,更好地利用了设备上的计算能力。比如将10层 PConv 堆起来,然后测量GPU、CPU 和 ARM 处理器上的 FLOPs 和延迟/吞吐量所示。
【论文笔记】FasterNet:Run, Don’t Walk: Chasing Higher FLOPS for Faster Neural Networks,论文,论文阅读,深度学习,神经网络
PConv 的 FLOPs 只有普通 Conv 的 1/16,在 GPU、CPU 和 ARM 上分别比 DWConv 高14倍、6.5倍和22.7倍。常规的 Conv 拥有最高的 FLOPS,因为它已经不断优化了多年。GConv 和 DWConv 尽管显著降低了 FLOPs,但 FLOPS 却急剧下降。此外,它们倾向于增加通道数量以弥补性能下降,但是这会增加它们的延迟。

6. 总结

为了实现更快的网络,本文重新审视了流行的算子,并证明了较低的 FLOPS 主要是由于算子的频繁内存访问,尤其是 Depth-wise Convolution。本文提出了一种新的部分卷积 (Partial Convolution, PConv),通过同时减少冗余计算和内存访问,可以更有效地提取空间特征。在 PConv 的基础上,作者进一步提出了 FasterNet,一种新的神经网络家族,在各种设备上的运行速度远高于其他网络。

Reference

通用 Vision Backbone 超详细解读 (二十二):FasterNet:追求更快的神经网络
CVPR2023|不好意思我要加速度了!FasterNet:更高FLOPS是更快更强的底气
yolov5增加fasternet结构文章来源地址https://www.toymoban.com/news/detail-730060.html

到了这里,关于【论文笔记】FasterNet:Run, Don’t Walk: Chasing Higher FLOPS for Faster Neural Networks的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Don’t Hold My Data Hostage – A Case For Client Protocol Redesign 论文阅读 & Apache IoTDB TsBlock 对比

    Don’t Hold My Data Hostage – A Case For Client Protocol Redesign 是 VLDB 2017 的一篇论文,主要着眼于数据库客户端协议的设计。本文主要是个人对论文的一些理解,以及结合自己较熟悉的开源时序数据库 Apache IoTDB 进行了一些对比分析。如果有谬误之处,欢迎留言指正~ 将大量级数据从

    2024年02月12日
    浏览(50)
  • HDLBits刷题笔记8:Circuits.Sequential Logic.Latches and Flip-Flops

    建立一个8bit的D触发器 建立一个8bit的D触发器,带同步高电平复位 建立一个下降沿触发的8bit的D触发器,带同步高电平复位,复位时,将触发器的值设置为 0x34 建立一个8bit的D触发器,带异步高电平复位 建立一个16bit的D触发器,带2bit的字节使能 byteena[1:0] ,带同步低电平复位

    2024年02月12日
    浏览(36)
  • verilog 学习笔记 —— 时序逻辑 Sequential Logics (Latches and Flip-Flops 锁存器和触发器)

    1. D flip-flop D触发器 2. D flip-flop  D触发器 3. DFF with reset  带复位的D触发器  4. 带复位值的D触发器 5. DFF with asynchronous reset 带异步复位功能的 D触发器 6. DFF with byte enable   带位启动的触发器 7. D Latch  D锁存器 8. DFF  9. DFF   10. DFF+gate   11. Mux and DFF   12. DFFs and gates   13

    2024年02月04日
    浏览(58)
  • FasterNet实战:使用FasterNet实现图像分类任务(二)

    在上一篇文章中完成了前期的准备工作,见链接: FasterNet实战:使用FasterNet实现图像分类任务(一) 这篇主要是讲解如何训练和测试 完成上面的步骤后,就开始train脚本的编写,新建train.py 在train.py导入 os.environ[‘CUDA_VISIBLE_DEVICES’]=“0,1” 选择显卡,index从0开始,比如一台

    2024年02月01日
    浏览(39)
  • GPT-4开源平替miniGPT-4来了,仅需23G显存单机可run,附论文、项目代码地址

    来源 | 新智元  微信号:AI-era 先是ChatGPT的发布给世界带来了一点小小的NLP震撼,随后发布的GPT-4更是破圈计算机视觉,展现了非凡的多模态能力。 不光能读懂人类的梗,给个手绘草图甚至可以直接写出网站的代码,彻底颠覆了对语言模型、视觉模型能力边界的认知。 GPT-

    2024年02月01日
    浏览(41)
  • FasterNet

    更高FLOPS才是更快更强的底气,作者重新审视了现有的操作符,特别是DWConv的计算速度——FLOPS。作者发现导致低FLOPS问题的主要原因是频繁的内存访问。然后,作者提出了PConv作为一种竞争性替代方案,它减少了计算冗余以及内存访问的数量。 论文链接:https://paperswithcode.com

    2023年04月20日
    浏览(15)
  • int8,FLOPS,FLOPs,TOPS 等具体含义

    算力的计量单位FLOPS(Floating-point operations per second),FLOPS表示每秒浮点的运算次数。具体使用时,FLOPS前面还会有一个字母常量,例如TFLOPS、PFLOPS。这个字母T、P代表次数,T代表每秒一万亿次,P代表每秒一千万亿次。 除了运算次数,衡量算力水平时还要看算力精度。例如,

    2024年02月04日
    浏览(33)
  • Random Walk算法详解(附python代码)

            一维随机游走问题:设一个质点(随机游走者)沿着一条直线运动,单位时间内只能运动一个单位长度,且只能停留在该直线上的整数点,假设在时刻t,该质点位于直线上的点i,那么在时刻t +1,该质点的位置有三种可能: ①以p 的概率跳到整数点i-1 ②或以q的概率

    2024年02月01日
    浏览(38)
  • python遍历目录(文件夹)os.walk

    打印:

    2024年02月08日
    浏览(40)
  • 【计算机视觉】GFLOPs、FLOPS和FLOPs的区别和联系(含代码示例)

    这三个概念其实都差不多,都涉及浮点运算,但是还是有一些小的不同之处,下面简单总结一下: GFLOPS 就是 Giga Floating-point Operations Per Second,即每秒10亿次的浮点运算数,常作为GPU性能参数但不一定代表GPU的实际表现,因为还要考虑具体如何拆分多边形和像素、以及纹理填充,理

    2024年02月03日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包