【MobileNetV3】MobileNetV3网络结构详解

2023-05-16

文章目录

  • 1 MobileNetV3创新点
  • 2 block变成了什么样
    • 2.1 总体介绍
    • 2.2 SE模块理解
    • 2.3 ReLu6和hardswish激活函数理解
  • 3 网络总体结构
  • 4 代码解读
  • 5 感谢链接

在看本文前,强烈建议先看一下之前写的 MobilenetV2。

1 MobileNetV3创新点

  • bottleneck结构变了
  • 让网络更宽、更深,宽多少?深多少?采用NAS(Neural Architecture Search)搜索得到
  • 重新设计耗时层结构(针对NAS搜索的结构进行设计,咱可以不管)

2 block变成了什么样

2.1 总体介绍

参考大佬的图片进行解读,Mobilenetv2中的block如下图所示
mobilenetv2
Mobilenetv3中的block如下图所示

Mobilenetv3
可以发现,Mobilenetv3的block中加入了SE模块,更换了激活函数
SE模块下一节讲。
此处更新的激活函数在图中用NL(非线性)统一表示,因为用到的激活函数不一样,主要有hardswish、relu两种。
最后那个1x1降维投影层用的是线性激活(f(x)=x),也可以理解为没用激活。

2.2 SE模块理解

SE(Squeeze-and-Excitation) 模块类似于一个注意力模块,以在Mobilenetv3中的应用为例进行理解,如下图所示。
SE模块

2.3 ReLu6和hardswish激活函数理解

ReLu6激活函数如下图所示,相当于加了个最大值6进行限制。
relu6

hardswish激活函数如下图所示,相当于分成3段进行限制。
采用hardswish,计算速度相对较快,对量化过程友好

hardswish
hardswish图像

3 网络总体结构

作者针对不同需求,通过NAS得到两种结构,一个是MobilenetV3-Large,结构如下图:

MobilenetV3-Large
图中部分参数解释:

  • Input表示输入尺寸
  • Operator中的NBN表示不使用BN,最后的conv2d 1x1相当于全连接层的作用
  • exp size表示bottleneck中的第一层1x1卷积升维,维度升到多少(第一个bottleneck没有1x1卷积升维操作)
  • out表示bottleneck输出的channel个数
  • SE表示是否使用SE模块
  • NL表示使用何种激活函数,HS表示HardSwish,RE表示ReLu
  • s表示步长(s=2,长宽变为原来一半)

另一个是MobilenetV3-Small,结构如下图:

MobilenetV3-Small

4 代码解读

直接看代码注释即可,可运行

from typing import Callable, List, Optional

import torch
from torch import nn, Tensor
from torch.nn import functional as F
from functools import partial


# ------------------------------------------------------#
#   这个函数的目的是确保Channel个数能被8整除。
#   离它最近的8的倍数
#	很多嵌入式设备做优化时都采用这个准则
# ------------------------------------------------------#
def _make_divisible(ch, divisor=8, min_ch=None):
    if min_ch is None:
        min_ch = divisor
    # int(v + divisor / 2) // divisor * divisor:四舍五入到8
    new_ch = max(min_ch, int(ch + divisor / 2) // divisor * divisor)
    # Make sure that round down does not go down by more than 10%.
    if new_ch < 0.9 * ch:
        new_ch += divisor
    return new_ch


# -------------------------------------------------------------#
#   Conv+BN+Acti经常会用到,组在一起
# -------------------------------------------------------------#
class ConvBNActivation(nn.Sequential):
    def __init__(self,
                 in_planes: int,
                 out_planes: int,
                 kernel_size: int = 3,
                 stride: int = 1,
                 groups: int = 1,
                 norm_layer: Optional[Callable[..., nn.Module]] = None,         # 卷积后的BN层
                 activation_layer: Optional[Callable[..., nn.Module]] = None):  # 激活函数
        padding = (kernel_size - 1) // 2
        if norm_layer is None:          # 没有传入,就默认使用BN
            norm_layer = nn.BatchNorm2d
        if activation_layer is None:
            activation_layer = nn.ReLU6
        super(ConvBNActivation, self).__init__(nn.Conv2d(in_channels=in_planes,
                                                         out_channels=out_planes,
                                                         kernel_size=kernel_size,
                                                         stride=stride,
                                                         padding=padding,
                                                         groups=groups,
                                                         bias=False),           # 后面会用到BN层,故不使用bias
                                               norm_layer(out_planes),
                                               activation_layer(inplace=True))


# ------------------------------------------------------#
#   注意力模块:SE模块
#	就是两个FC层,节点个数、激活函数要注意要注意
# ------------------------------------------------------#
class SqueezeExcitation(nn.Module):
    # squeeze_factor: int = 4:第一个FC层节点个数是输入特征矩阵的1/4
    def __init__(self, input_c: int, squeeze_factor: int = 4):
        super(SqueezeExcitation, self).__init__()
        # 第一个FC层节点个数,也要是8的整数倍
        squeeze_c = _make_divisible(input_c // squeeze_factor, 8)
        # 通过卷积核大小为1x1的卷积替代FC层,作用相同
        self.fc1 = nn.Conv2d(input_c, squeeze_c, 1)
        self.fc2 = nn.Conv2d(squeeze_c, input_c, 1)

    def forward(self, x: Tensor) -> Tensor:
        # x有很多channel,通过output_size=(1, 1)实现每个channel变成1个数字
        scale = F.adaptive_avg_pool2d(x, output_size=(1, 1))
        scale = self.fc1(scale)
        scale = F.relu(scale, inplace=True)
        scale = self.fc2(scale)
        # 此处的scale就是第二个FC层输出的数据
        scale = F.hardsigmoid(scale, inplace=True)  
        return scale * x        # 和原输入相乘,得到SE模块的输出


# ------------------------------------------------------#
#   InvertedResidualConfig是参数配置文件
# ------------------------------------------------------#
class InvertedResidualConfig:
    def __init__(self,
                 input_c: int,          
                 kernel: int,
                 expanded_c: int,   # bottleneck中的第一层1x1卷积升维,维度升到多少
                 out_c: int,
                 use_se: bool,
                 activation: str,
                 stride: int,
                 width_multi: float):       # 和mobilenetv2中倍率因子相同,通过它得到每一层channels个数和基线的区别
        self.input_c = self.adjust_channels(input_c, width_multi)   # 倍率因子用在这儿了
        self.kernel = kernel
        self.expanded_c = self.adjust_channels(expanded_c, width_multi)
        self.out_c = self.adjust_channels(out_c, width_multi)
        self.use_se = use_se
        # activation == "HS",则self.use_hs==True
        self.use_hs = activation == "HS"  # whether using h-swish activation
        self.stride = stride

    # 静态方法
    @staticmethod
    def adjust_channels(channels: int, width_multi: float):
        return _make_divisible(channels * width_multi, 8)


class InvertedResidual(nn.Module):
    def __init__(self,
                 cnf: InvertedResidualConfig,       # cnf是个config文件,对应的格式就是上面介绍的InvertedResidualConfig类
                 norm_layer: Callable[..., nn.Module]):
        super(InvertedResidual, self).__init__()

        if cnf.stride not in [1, 2]:
            raise ValueError("illegal stride value.")

        # 是否使用shortcut连接
        self.use_res_connect = (cnf.stride == 1 and cnf.input_c == cnf.out_c)       

        layers: List[nn.Module] = []    # 定义一个空列表,里面元素类型为nn.module
        activation_layer = nn.Hardswish if cnf.use_hs else nn.ReLU

        # expand
        if cnf.expanded_c != cnf.input_c:       # 第一个bottleneck没有这个1x1卷积,故有这个if哦安短
            layers.append(ConvBNActivation(cnf.input_c,
                                           cnf.expanded_c,
                                           kernel_size=1,
                                           norm_layer=norm_layer,
                                           activation_layer=activation_layer))

        # depthwise
        layers.append(ConvBNActivation(cnf.expanded_c,      # 上一层1x1输出通道数为cnf.expanded_c
                                       cnf.expanded_c,
                                       kernel_size=cnf.kernel,
                                       stride=cnf.stride,
                                       groups=cnf.expanded_c,       # DW卷积
                                       norm_layer=norm_layer,
                                       activation_layer=activation_layer))

        if cnf.use_se:      # 是否使用se模块,只需要传入个input_channel
            layers.append(SqueezeExcitation(cnf.expanded_c))

        # project       降维1x1卷积层
        layers.append(ConvBNActivation(cnf.expanded_c,
                                       cnf.out_c,
                                       kernel_size=1,
                                       norm_layer=norm_layer,
                                       # nn.Identity是一个线性激活,没进行任何处理
                                       #    内部实现:直接return input
                                       activation_layer=nn.Identity))   

        self.block = nn.Sequential(*layers)
        self.out_channels = cnf.out_c
        self.is_strided = cnf.stride > 1

    def forward(self, x: Tensor) -> Tensor:
        result = self.block(x)
        if self.use_res_connect:
            result += x

        return result


# 继承来自nn.module类
class MobileNetV3(nn.Module):
    def __init__(self,
                 inverted_residual_setting: List[InvertedResidualConfig],   # 参数设置列表,列表里面每个元素类型是上面定义的那个类的形式
                 last_channel: int,         # 倒数第二层channel个数
                 num_classes: int = 1000,   # 需要分类的类别数
                 block: Optional[Callable[..., nn.Module]] = None,
                 norm_layer: Optional[Callable[..., nn.Module]] = None):
        super(MobileNetV3, self).__init__()

        if not inverted_residual_setting:
            raise ValueError("The inverted_residual_setting should not be empty.")
        elif not (isinstance(inverted_residual_setting, List) and
                  all([isinstance(s, InvertedResidualConfig) for s in inverted_residual_setting])):
            raise TypeError("The inverted_residual_setting should be List[InvertedResidualConfig]")

        if block is None:
            block = InvertedResidual

        # 将norm_layer设置为BN
        #   partial()给输入函数BN指定默认参数,简化之后的函数参数量
        if norm_layer is None:
            norm_layer = partial(nn.BatchNorm2d, eps=0.001, momentum=0.01)

        layers: List[nn.Module] = []

        # building first layer   就是普通的conv
        firstconv_output_c = inverted_residual_setting[0].input_c
        layers.append(ConvBNActivation(3,
                                       firstconv_output_c,
                                       kernel_size=3,
                                       stride=2,
                                       norm_layer=norm_layer,
                                       activation_layer=nn.Hardswish))
        # building inverted residual blocks
        for cnf in inverted_residual_setting:
            layers.append(block(cnf, norm_layer))

        # building last several layers
        lastconv_input_c = inverted_residual_setting[-1].out_c
        lastconv_output_c = 6 * lastconv_input_c            # small:96->576; Large:160->960
        layers.append(ConvBNActivation(lastconv_input_c,
                                       lastconv_output_c,
                                       kernel_size=1,
                                       norm_layer=norm_layer,
                                       activation_layer=nn.Hardswish))
        self.features = nn.Sequential(*layers)
        self.avgpool = nn.AdaptiveAvgPool2d(1)
        self.classifier = nn.Sequential(nn.Linear(lastconv_output_c, last_channel),
                                        nn.Hardswish(inplace=True),
                                        nn.Dropout(p=0.2, inplace=True),
                                        nn.Linear(last_channel, num_classes))

        # initial weights
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                nn.init.kaiming_normal_(m.weight, mode="fan_out")
                if m.bias is not None:
                    nn.init.zeros_(m.bias)
            elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)):
                nn.init.ones_(m.weight)
                nn.init.zeros_(m.bias)
            elif isinstance(m, nn.Linear):
                nn.init.normal_(m.weight, 0, 0.01)
                nn.init.zeros_(m.bias)

    def _forward_impl(self, x: Tensor) -> Tensor:
        x = self.features(x)
        x = self.avgpool(x)     # 到这后面不再需要高和宽的维度了
        x = torch.flatten(x, 1) # 故进行展平处理
        x = self.classifier(x)

        return x

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


def mobilenet_v3_large(num_classes: int = 1000,
                       reduced_tail: bool = False) -> MobileNetV3:
    """
    Constructs a large MobileNetV3 architecture from
    "Searching for MobileNetV3" <https://arxiv.org/abs/1905.02244>.

    weights_link:
    https://download.pytorch.org/models/mobilenet_v3_large-8738ca79.pth

    Args:
        num_classes (int): number of classes
        reduced_tail (bool): 需要的话, 设为True, 可以进一步减小网络
            If True, reduces the channel counts of all feature layers
            between C4 and C5 by 2. It is used to reduce the channel redundancy in the
            backbone for Detection and Segmentation.
    """
    width_multi = 1.0       # 调整channel个数,默认1.0
    bneck_conf = partial(InvertedResidualConfig, width_multi=width_multi)   # partial()给输入函数指定默认参数
    # 给类里的方法传入参数      有了上面一行,这行有必要吗?
    adjust_channels = partial(InvertedResidualConfig.adjust_channels, width_multi=width_multi)

    reduce_divider = 2 if reduced_tail else 1

    inverted_residual_setting = [
        # input_c, kernel, expanded_c, out_c, use_se, activation, stride
        bneck_conf(16, 3, 16, 16, False, "RE", 1),
        bneck_conf(16, 3, 64, 24, False, "RE", 2),  # C1
        bneck_conf(24, 3, 72, 24, False, "RE", 1),
        bneck_conf(24, 5, 72, 40, True, "RE", 2),   # C2
        bneck_conf(40, 5, 120, 40, True, "RE", 1),
        bneck_conf(40, 5, 120, 40, True, "RE", 1),
        bneck_conf(40, 3, 240, 80, False, "HS", 2),  # C3
        bneck_conf(80, 3, 200, 80, False, "HS", 1),
        bneck_conf(80, 3, 184, 80, False, "HS", 1),
        bneck_conf(80, 3, 184, 80, False, "HS", 1),
        bneck_conf(80, 3, 480, 112, True, "HS", 1),
        bneck_conf(112, 3, 672, 112, True, "HS", 1),
        bneck_conf(112, 5, 672, 160 // reduce_divider, True, "HS", 2),  # C4
        bneck_conf(160 // reduce_divider, 5, 960 // reduce_divider, 160 // reduce_divider, True, "HS", 1),
        bneck_conf(160 // reduce_divider, 5, 960 // reduce_divider, 160 // reduce_divider, True, "HS", 1),
    ]
    last_channel = adjust_channels(1280 // reduce_divider)  # C5    # 倒数第二个全连接层节点个数

    return MobileNetV3(inverted_residual_setting=inverted_residual_setting,
                       last_channel=last_channel,
                       num_classes=num_classes)


def mobilenet_v3_small(num_classes: int = 1000,
                       reduced_tail: bool = False) -> MobileNetV3:
    """
    Constructs a large MobileNetV3 architecture from
    "Searching for MobileNetV3" <https://arxiv.org/abs/1905.02244>.

    weights_link:
    https://download.pytorch.org/models/mobilenet_v3_small-047dcff4.pth

    Args:
        num_classes (int): number of classes
        reduced_tail (bool): If True, reduces the channel counts of all feature layers
            between C4 and C5 by 2. It is used to reduce the channel redundancy in the
            backbone for Detection and Segmentation.
    """
    width_multi = 1.0
    bneck_conf = partial(InvertedResidualConfig, width_multi=width_multi)
    adjust_channels = partial(InvertedResidualConfig.adjust_channels, width_multi=width_multi)

    reduce_divider = 2 if reduced_tail else 1

    inverted_residual_setting = [
        # input_c, kernel, expanded_c, out_c, use_se, activation, stride
        bneck_conf(16, 3, 16, 16, True, "RE", 2),  # C1
        bneck_conf(16, 3, 72, 24, False, "RE", 2),  # C2
        bneck_conf(24, 3, 88, 24, False, "RE", 1),
        bneck_conf(24, 5, 96, 40, True, "HS", 2),  # C3
        bneck_conf(40, 5, 240, 40, True, "HS", 1),
        bneck_conf(40, 5, 240, 40, True, "HS", 1),
        bneck_conf(40, 5, 120, 48, True, "HS", 1),
        bneck_conf(48, 5, 144, 48, True, "HS", 1),
        bneck_conf(48, 5, 288, 96 // reduce_divider, True, "HS", 2),  # C4
        bneck_conf(96 // reduce_divider, 5, 576 // reduce_divider, 96 // reduce_divider, True, "HS", 1),
        bneck_conf(96 // reduce_divider, 5, 576 // reduce_divider, 96 // reduce_divider, True, "HS", 1)
    ]
    last_channel = adjust_channels(1024 // reduce_divider)  # C5

    return MobileNetV3(inverted_residual_setting=inverted_residual_setting,
                       last_channel=last_channel,
                       num_classes=num_classes)

if __name__ == "__main__":
    model = mobilenet_v3_small()
    print(model)

    from torchsummaryX import summary
    summary(model, torch.randn(1,3,224,224))

输出:

MobileNetV3(
  (features): Sequential(
    (0): ConvBNActivation(
      (0): Conv2d(3, 16, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
      (1): BatchNorm2d(16, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)
      (2): Hardswish()
    )
    (1): InvertedResidual(
...
(classifier): Sequential(
    (0): Linear(in_features=576, out_features=1024, bias=True)
    (1): Hardswish()
    (2): Dropout(p=0.2, inplace=True)
    (3): Linear(in_features=1024, out_features=1000, bias=True)
  )
)
================================================================================================
                                           Kernel Shape       Output Shape  \
Layer
0_features.0.Conv2d_0                     [3, 16, 3, 3]  [1, 16, 112, 112]
1_features.0.BatchNorm2d_1                         [16]  [1, 16, 112, 112]
...
123_classifier.Dropout_2                      -          -
124_classifier.Linear_3                  1.025M     1.024M
------------------------------------------------------------------------------------------------
                          Totals
Total params           2.542856M
Trainable params       2.542856M
Non-trainable params         0.0
Mult-Adds             56.516456M

5 感谢链接

https://www.bilibili.com/video/BV1GK4y1p7uE/?spm_id_from=333.788
https://blog.csdn.net/m0_48742971/article/details/123438626
https://www.bilibili.com/video/BV1zT4y1P7pd/?spm_id_from=333.788
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【MobileNetV3】MobileNetV3网络结构详解 的相关文章

  • 2017阿里研发工程师C/C++实习生招聘笔试题

    1 做股票的人总会忍不住幻想 xff1a 如果知道明天怎样就好了 那么问题来了 xff0c 如果打开上帝视角 xff0c 你最好能做到怎样 xff1f 真实世界的股票交易规则太复杂 xff0c 我们这里做一些简化 首先我们假设有N个股票和M
  • http digest认证过程分析及例子

    验证过程 xff1a 步骤一 客户端向服务器申请数据 Request GET auth HTTP 1 1 r n Accept r n Host 192 168 1 15 r n Content Length 0 r n r n r n 步
  • 用IMU监测力量训练中的杠铃速度,帮助科学界和体育界评估杠杆运动学

    大家好 xff0c 惯师科技致力于分享IMU前沿科研资讯 xff0c 今天和大家分享一篇验证IMU xff08 惯性测量单元 xff09 自动获取卧推过程中杠铃速度的有效性和可靠性的论文 为验证基于IMU设备自动获取卧推运动过程中的杠铃速度
  • FPGA学习笔记(1)

    之前虽说有学习FPGA 主要是verilog xff0c 但真正的具体应用还是少 xff0c 基本是在修改师兄的代码 然后最近也一直在学习c和python xff0c 所以好久没看verilog了 本来真的不想再看的 xff0c 但工作也是
  • python pip使用

    python使用pip管理包十分详细 xff0c 这里记录常用的pip操作 xff08 windows xff09 1 查看pip版本 pip V 2 升级pip版本 方法一 xff1a pip install upgrade pip 方法
  • 华为2016笔试-扑克牌大小比较游戏 python接法

    这几天刷题 xff0c 发现该题没有python的程序 xff0c 正好在学python xff0c 尝试写了下 xff0c 没有用任何库 xff0c 写的不好 xff0c 有很多改进的地方 基于python3 7 扑克牌游戏大家应该都比较
  • C语言程序设计现代方法第四章课后习题

    第一题 include lt stdio h gt include int main void int a printf Enter a two digit number scanf s 34 d 34 amp a printf THE d
  • C语言程序设计现代方法第六章课后习题

    第一题 include lt stdio h gt include lt string gt int main void float a b 61 0 do printf 34 Enter a number 34 scanf s 34 f
  • C语言程序设计现代方法第二版,第九章课后编程习题

    第一题 include lt stdio h gt include lt string gt void selection sort int n int a int i j max 61 a 0 for i 61 0 i lt n i 43
  • C语言程序设计现代方法第二版,第10章课后编程习题

    第一题 这题10 2中的pop函数没有用 xff0c 在我的电脑里 xff08 vs2017 xff09 当把pop赋值给字符串时总是报错 xff0c 尝试了各种办法都不行 xff0c 提示是 xff1a char 和char类型不兼容 求
  • 华为2019校招笔试题之旋转方阵(C语言版、python)

    题目描述 输入一个N阶方阵 0 lt N lt 10 输出此方阵顺时针旋转M 0 lt 61 M lt 61 10000 次后的方阵 旋转举例 xff1a xff08 如下四个三阶方阵从上到下为数字围绕中心顺时针旋转 1 2 3 4 5 6
  • GPS数据包相关笔记

    一 GPS数据包类型 GPGSV xff1a 可见卫星信息 GPGLL xff1a 地理定位信息 GPRMC xff1a 推荐最小定位信息 GPVTG xff1a 地面速度信息 GPGGA xff1a GPS定位信息 GPGSA xff1a
  • C++学习困难,自学需要做到这几个方面……

    喜欢的可以转发收藏加关注哦 xff01 C 43 43 是一种静态数据类型检查的 xff0c 支持多重编程范式的通用程序设计语言 它支持过程化程序设计 数据抽象 面向对象程序设计 制作图标等等泛型程序设计等多种程序设计风格 自学编程语言难在
  • vue js时分秒计时器_Vue js框架的倒数计时器

    vue js时分秒计时器 VUE倒计时 vue count down timer This is a count down timer for Vue js framework This library supports two types
  • TCP长连接(Keepalive)

    TCP Keepalive的起源 TCP协议中有长连接和短连接之分 短连接环境下 xff0c 数据交互完毕后 xff0c 主动释放连接 xff1b 长连接的环境下 xff0c 进行一次数据交互后 xff0c 很长一段时间内无数据交互时 xf
  • 从输入一个网址到浏览器显示页面经历的全过程

    作为网络专栏的开篇导文 xff0c 本文概况介绍下经典案例 xff1a 从输入一个网址到浏览器显示页面的全过程 步骤概要介绍如下 xff1a 1 输入网址2 DNS解析获取域名对应的IP地址3 建立TCP连接4 web浏览器向web服务器发
  • 端口号是什么以及常见端口号

    端口号 具有网络功能的应用软件的标识号 注意 xff0c 端口号是不固定的 xff0c 即可以由用户手工可以分配 xff08 当然 xff0c 一般在软件编写时就已经定义 xff09 当然 xff0c 有很多应用软件有公认的默认的端口 xf
  • DNS域名解析过程

    目录 1 DNS2 域名系统DNS 的作用3 域名的层级关系4 DNS域名解析过程 递归查询迭代查询 5 高速缓存6 DNS相关面试问题 1 DNS DNS xff08 Domain Name System xff09 是域名系统的英文缩写
  • java常见面试题

    目录 基础语法 1 Java 语言的优点 xff1f 2 Java 如何实现平台无关 xff1f 3 JVM xff0c JDK 和 JRE 的区别 xff1f 4 Java 按值调用还是引用调用 xff1f 5 浅拷贝和深拷贝的区别 xf
  • 分段分页存储

    2020 4 27 在家的网课 xff0c 无聊 xff0c 记录一下分页 xff0c 分段 xff0c 段页式存储笔记 昨天刚学了分页存储 xff0c 听得我一脸懵逼 xff0c 好在课下花了很长时间才弄懂 1 分页存储管理 1 分页存储

随机推荐

  • 解压码

    BN00001 22kke BN00002 88cde BN00003 00ike BN00004 76cdb BN00005 09dbm BN00006 0mndc BN00007 cd78d BN00008 bdmf8 BN00009
  • 保险项目业务流程

    1 整个项目分为四分模块 xff1a 信息采集模块 信息验证 审批 生成合同 xff08 开单 xff09 信息采集模块 xff1a 包括购买保险产品 xff0c 客户个人信息 1 纸质文档给客户填写 xff0c 在回来录入系统 2 客户直
  • IDEA使用maven自定义archetype

    标题自定义archetype 在pom文件中添加archetype plugin span class token generics span class token punctuation lt span plugin span clas
  • 自定义Perperties文件内容读取

    新建properties文件放在resources目录下 properties文件内容 url span class token operator 61 span jdbc span class token operator span my
  • 如何使用Google TV设置Chromecast

    Justin Duino 贾斯汀 杜伊诺 Justin Duino Google changed up its streaming platform with the release of the Chromecast with Googl
  • 使用CSS中的Hover控制显示子元素或者兄弟元素

    lt DOCTYPE html gt lt html lang 61 34 en 34 gt lt head gt lt meta charset 61 34 UTF 8 34 gt lt meta name 61 34 viewport
  • maven项目中的jdbc连接步骤

    在maven项目pom xml中到入驱动包 xff08 以下是驱动包代码 xff09 lt dependencies gt lt https mvnrepository com artifact mysql mysql connector
  • executeUpdate()与executeQuery()的使用

    增 删 改 用executeUpdate xff08 xff09 返回值为int型 xff0c 表示被影响的行数 例子 查用executeQuery 返回的是一个集合 next xff08 xff09 表示 指针先下一行 xff0c 还有f
  • Access denied for user ''@'localhost' (using password: YES)错误解决方法

    远程登录被拒绝 xff0c 要改一个表数据的属性让他可以远程登录 解决方法如下 xff0c 执行命令 xff1a mysql gt use mysql mysql gt select host user from user 查看结果是不是r
  • 基于yolov5和Tesseract-OCR车牌识别项目 Linux系统上搭建运行(大概结构)

    项目大概分为两部分 xff0c 首先使用yolov5进行目标检测并截图 xff1b 然后对图片一系列的处理后使用Tesseract OCR进行字符识别 xff08 本文为简易版框架结构 xff0c 如果看完感兴趣可以在文末跳转看细节操作 x
  • ubuntu20.04使用微软Azure Kinect DK 实现三维重建demo记录

    本文仅为在ubuntu20 04实现Azure Kinect DK 三维重建demo xff0c 此文记录实现过程仅供学习 xff0c 同时为大家避坑 xff0c 文中参考大量文章已列至末尾 1 ros安装 2 安装微软 DK的sdk 3
  • 常见一面问题

    1 智能指针 常用的c 43 43 库 Standard Template Library STL Algorithms 算法 Containers 容器 Functions 函数 Iterators 迭代器 Boost 同样是大量C 43
  • ROS datatype/md5sum错误

    I got this error today Problem ERROR 1576785283 032878520 Client rostopic 21515 1576784759002 wants topic timestamp to h
  • 快速安装Pytorch和Torchvision

    文章目录 1 Linux下激活自己的虚拟环境并查看Python版本2 查看需要安装的Pytorch和Torchvision版本3 直接命令行安装3 1 如果不报错的话3 2 ERROR Could not install packages
  • 【Darknet-53】YOLOv3 backbone Darknet-53 详解

    文章目录 1 模型计算量与参数量2 Darknet 53网络3 感谢链接 1 模型计算量与参数量 模型计算量与参数量的计算方式主要有两种 xff0c 一种是使用thop库 xff0c 一种是使用torchsummaryX 使用pip ins
  • ubuntu 默认命令行_从命令行在Ubuntu上设置默认浏览器

    ubuntu 默认命令行 Ubuntu Linux has a default browser functionality that will automatically launch the correct browser when cl
  • 【DeeplabV3+】DeeplabV3+网络结构详解

    文章目录 1 常规卷积与空洞卷积的对比1 1 空洞卷积简介1 2 空洞卷积的优点 2 DeeplabV3 43 模型简介3 DeeplabV3 43 网络代码4 mobilenetv2网络代码5 感谢链接 聊DeeplabV3 43 网络前
  • 【YOLOv3 decode】YOLOv3中解码理解decode_box

    文章目录 1 解码是什么意思2 代码解读3 生成网格中心 代码详解4 按照网格格式生成先验框的宽高 代码详解5 感谢链接 1 解码是什么意思 在利用YOLOv3网络结构提取到out0 out1 out2之后 xff0c 不同尺度下每个网格点
  • 【DeeplabV3+ MIoU】DeeplabV3+计算评价指标

    文章目录 1 分割常用评价指标1 1 什么是MIoU1 2 什么是PA1 2 什么是MPA 2 根据混淆矩阵计算评价指标2 1 计算MIoU2 2 计算PA2 3 计算MPA 3 计算 MIoU 总体代码4 compute mIoU 函数
  • 【MobileNetV3】MobileNetV3网络结构详解

    文章目录 1 MobileNetV3创新点2 block变成了什么样2 1 总体介绍2 2 SE模块理解2 3 ReLu6和hardswish激活函数理解 3 网络总体结构4 代码解读5 感谢链接 在看本文前 xff0c 强烈建议先看一下之