yolov5修改骨干网络-使用自己搭建的网络-以efficientnetv2为例

news2024/11/24 13:32:02

yolov5修改骨干网络–原网络说明
yolov5修改骨干网络-使用pytorch自带的网络-以Mobilenet和efficientnet为例
yolov5修改骨干网络-使用自己搭建的网络-以efficientnetv2为例

在这里插入图片描述

  • 增加网络的深度depth能够得到更加丰富、复杂的特征并且能够很好的应用到其它任务中。但网络的深度过深会面临梯度消失,训练困难的问题。
  • 增加网络的width能够获得更高细粒度的特征并且也更容易训练,但对于width很大而深度较浅的网络往往很难学习到更深层次的特征。
  • 增加输入网络的图像分辨率能够潜在得获得更高细粒度的特征模板,但对于非常高的输入分辨率,准确率的增益也会减小。但大分辨率图像会增加计算量。

efficientnet则是通过NAS搜索,同时增加width、depth以及resolution,使网络结构达到最优。

下表为EfficientNet-B0的网络框架(B1-B7就是在B0的基础上修改Resolution,Channels以及Layers),可以看出网络总共分成了9个Stage。

第一个Stage是一个卷积核大小为3x3,stride为2的普通卷积层(包含BN和Swish激活函数);
Stage2~Stage8都是在重复堆叠MBConv结构(Layers表示该Stage重复MBConv结构多少次),Stage9由一个普通的1x1的卷积层 + 平均池化层 + 全连接层组成。

MBConv后的1或6就是倍率因子n,即MBConv中第一个1x1的卷积层会将输入特征矩阵的channels扩充为n倍,其中k3x3或k5x5表示MBConv中Depthwise Conv所采用的卷积核大小。Channels表示通过该Stage后输出特征矩阵的Channels。

在这里插入图片描述


MBConv结构如下:
在这里插入图片描述
MBConv主要由一个 1x1 的卷积进行升维 (它的卷积核个数是输入特征矩阵channel的n倍, n ∈ { 1 , 6 } n \in \left\{1, 6\right\} n{1,6},当n=1时,不升维),一个kxk的Depthwise Conv卷积,k主要有3x3和5x5两种情况,一个SE模块,然后接一个1x1的普通卷积进行降维作用,再加一个Droupout,最后再进行特征图融合。

仅当输入MBConv结构的特征矩阵与输出的特征矩阵shape相同时shortcut连接才存在(代码中可通过stride== 1 and inputc_channels==output_channels条件来判断)


SE模块,由一个全局平均池化,两个全连接层组成。
在这里插入图片描述

假设输入图像H×W×C,第一个全连接层的节点个数是输入该MBConv特征矩阵 channels 乘SERadio,一般SERadio为 0.25,所以channe为 C 4 \frac{C}{4} 4C ,然后是Swish激活函数。

第二个全连接层的节点个数等于Depthwise Conv层输出的特征矩阵 channels,即 C C C,且使用Sigmoid激活函数,这样就拉伸成了1×1×C,然后再与原图像相乘,将每个通道赋予权重。这样就实现了注意力。

class SqueezeExcite_efficientv2(nn.Module):
    def __init__(self, c1, c2, se_ratio=0.25, act_layer=nn.ReLU):
        super().__init__()
        self.gate_fn = nn.Sigmoid()
        reduced_chs = int(c1 * se_ratio)
        self.avg_pool = nn.AdaptiveAvgPool2d(1)
        self.conv_reduce = nn.Conv2d(c1, reduced_chs, 1, bias=True)
        self.act1 = act_layer(inplace=True)
        self.conv_expand = nn.Conv2d(reduced_chs, c2, 1, bias=True)

    def forward(self, x):
        # 先全局平均池化
        x_se = self.avg_pool(x)
        # 再全连接(这里是用的1x1卷积,效果与全连接一样,但速度快)
        x_se = self.conv_reduce(x_se)
        # ReLU激活
        x_se = self.act1(x_se)
        # 再全连接
        x_se = self.conv_expand(x_se)
        # sigmoid激活
        x_se = self.gate_fn(x_se)
        # 将x_se 维度扩展为和x一样的维度 
        x = x * (x_se.expand_as(x))
        return x

Dropout层在源码实现中只有使用shortcut的时候才有Dropout层。

EfficientNetV1在训练图像的尺寸很大时,训练速度非常慢,而且非常吃显存。

在网络浅层中使用Depthwise convolutions速度会很慢。虽然Depthwise convolutions结构相比普通卷积拥有更少的参数以及更小的FLOPs,但通常无法充分利用现有的一些加速器,于是有人提出了Fused-MBConv结构去更好的利用移动端或服务端的加速器。

Fused-MBConv结构也非常简单,即将原来的MBConv结构主分支中的 conv1x1和depthwise conv3x3替换成一个普通的conv3x3,如图所示。

在这里插入图片描述

EfficientNetV2网络框架相比与EfficientNetV1,主要有以下不同:

  1. EfficientNetV2中除了使用到MBConv模块外,还使用了Fused-MBConv模块(主要是在网络浅层中使用)。
  2. EfficientNetV2使用较小的expansion ratio(MBConv中第一个expand conv1x1或者Fused-MBConv中第一个expand conv3x3)比如4,在EfficientNetV1中基本都是6. 这样的好处是能够减少内存访问开销。
  3. EfficientNetV2中更偏向使用更小(3x3)的kernel_size,在EfficientNetV1中使用了很多5x5的kernel_size。通过下表可以看到使用的kernel_size全是3x3的,由于3x3的感受野是要比5x5小的,所以需要堆叠更多的层结构以增加感受野。
  4. 移除了EfficientNetV1中最后一个步距为1的stage,就是EfficientNetV1中的stage8,可能是因为它的参数数量过多并且内存访问开销过大。

在这里插入图片描述

Conv3x3就是普通的3x3卷积 + 激活函数(SiLU)+ BN

Fused-MBConv 模块模块名称后跟的1,4表示expansion ratio,k3x3表示kenel_size为3x3,注意当expansion ratio等于1时是没有expand conv的,还有这里是没有使用到SE结构的(原论文图中有SE)。

当stride=1且输入输出channel相等时才有shortcut连接。

当有shortcut连接时才有Dropout层,而且这里的Dropout层是Stochastic Depth,即会随机丢掉整个block的主分支(只剩捷径分支,相当于直接跳过了这个block)也可以理解为减少了网络的深度。

在这里插入图片描述

MBConv模块和EfficientNetV1中是一样的,其中模块名称后跟的4,6表示expansion ratio,SE0.25表示使用了SE模块,0.25表示SE模块中第一个全连接层的节点个数是输入该MBConv模块特征矩阵channels的 1 4 \frac{1}{4} 41

注意当stride=1且输入输出Channels相等时才有shortcut连接。同样这里的Dropout层是Stochastic Depth。

在这里插入图片描述
Stride就是步距,注意每个Stage中会重复堆叠Operator模块多次,只有第一个Opertator模块的步距是按照表格中Stride来设置的,其他的默认都是1。 #Channels表示该Stage输出的特征矩阵的Channels,Layers表示该Stage重复堆叠Operator的次数。


网络代码

在这里插入图片描述
根据这个结构图进行代码编写,首先是一个步长为2的3x3矩阵,输出channel为24,后面当然也是有bn+激活的。这里先写一个base,通过修改yaml文件对其操作。

这一行的yaml参数应该如下:[-1, 1, stem, [24, 3, 2]],

class stem(nn.Module):
    def __init__(self, c1, c2, kernel_size=3, stride=1, groups=1):
        super().__init__()
        # kernel_size为3时,padding 为1,kernel为1时,padding为0
        padding = (kernel_size - 1) // 2
        # 由于要加bn层,所以不加偏置
        self.conv = nn.Conv2d(c1, c2, kernel_size, stride, padding=padding, groups=groups, bias=False)
        self.bn = nn.BatchNorm2d(c2, eps=1e-3, momentum=0.1)
        self.act = nn.SiLU(inplace=True)

    def forward(self, x):
        # print(x.shape)
        x = self.conv(x)
        x = self.bn(x)
        x = self.act(x)
        return x

然后是FusedMBConv,根据这个流程图编写:

在这里插入图片描述
注意,FusedMBConv是没有SE模块的,虽然上面画了SE。

Fused-MBConv1 后面这个1表示expansion=1,不升维;若不等于1,则升维到原维度的n倍;

后面layers=2表示使用两次这个bolck,所以第一个Fused-MBConv1, k3x3的yaml参数应为[-1, 2, FusedMBConv, [24, 3, 1, 1, 0]]

[24:out_channer, 3:kernel_size, 1:stride,1:expansion, 0:se_ration]

# Fused-MBConv 将 MBConv 中的 depthwise conv3×3 和扩展 conv1×1 替换为单个常规 conv3×3。
class FusedMBConv(nn.Module):
    def __init__(self, c1, c2, k=3, s=1, expansion=1, se_ration=0, dropout_rate=0.2, drop_connect_rate=0.2):
        super().__init__()
        # 当stride=1且输入输出Channels相等时才有shortcut连接,只有使用shortcut时,才用dropout
        self.has_shortcut = (s == 1 and c1 == c2)  # 只要是步长为1并且输入输出特征图大小相等,就是True 就可以使用到残差结构连接
        # expansion是为了先升维,再卷积,再降维,再残差
        self.has_expansion = expansion != 1  # expansion==1 为false expansion不为1时,输出特征图维度就为expansion*c1,k倍的c1,扩展维度
        expanded_c = c1 * expansion
        if self.has_expansion:
            self.expansion_conv = stem(c1, expanded_c, kernel_size=k, stride=s)
            self.project_conv = stem(expanded_c, c2, kernel_size=1, stride=1)
        else:
            self.project_conv = stem(c1, c2, kernel_size=k, stride=s)

        self.drop_connect_rate = drop_connect_rate
        if self.has_shortcut and drop_connect_rate > 0:
            self.dropout = DropPath(drop_connect_rate)

    def forward(self, x):
        if self.has_expansion:
            result = self.expansion_conv(x)
            result = self.project_conv(result)
        else:
            result = self.project_conv(x)
        if self.has_shortcut:
            if self.drop_connect_rate > 0:
                result = self.dropout(result)
            result += x

        return result

stage2: Fused-MBConv4, k3x3 2 48 4 表示用kernelsize=3的卷积核,先升维4倍,outchannel=48,重复四次,注意stride=2只有在第一次重复时才有,后面三次的stride都是1,所以yaml应该写为:
第一个的stride为2
[-1, 1, FusedMBConv, [48, 3, 2, 4, 0]]
后面三个的stride为1
[-1, 3, FusedMBConv, [48, 3, 1, 4, 0]]

同理stage 3 Fused-MBConv4, k3x3 2 64 4

   [-1, 1, FusedMBConv, [64, 3, 2, 4, 0]], 
   [-1, 3, FusedMBConv, [64, 3, 1, 4, 0]],

然后是stage 4 MBConv4, k3x3, SE0.25 2 128 6 表示6个MBConv模块,第一次用kernel size=3的卷积核升维四倍,SERadio为0.25,第一次的stride为2,后三次为1,输出channel为128。
yaml参数就应该为:

   [-1, 1, MBConv, [128, 3, 2, 4, 0.25]], # 先用步长为2的卷积
   [-1, 5, MBConv, [128, 3, 1, 4, 0.25]], # 后面5个block用步长为1的卷积
class MBConv(nn.Module):
    def __init__(self, c1, c2, k=3, s=1, expansion=1, se_ration=0, dropout_rate=0.2, drop_connect_rate=0.2):
        super().__init__()
        self.has_shortcut = (s == 1 and c1 == c2)
        expanded_c = c1 * expansion
        self.expansion_conv = stem(c1, expanded_c, kernel_size=1, stride=1)
        self.dw_conv = stem(expanded_c, expanded_c, kernel_size=k, stride=s, groups=expanded_c)
        self.se = SqueezeExcite_efficientv2(expanded_c, expanded_c, se_ration) if se_ration > 0 else nn.Identity()
        self.project_conv = stem(expanded_c, c2, kernel_size=1, stride=1)
        self.drop_connect_rate = drop_connect_rate
        if self.has_shortcut and drop_connect_rate > 0:
            self.dropout = DropPath(drop_connect_rate)

    def forward(self, x):
        # 先用1x1的卷积增加升维
        result = self.expansion_conv(x)
        # 再用一般的卷积特征提取
        result = self.dw_conv(result)
        # 添加se模块
        result = self.se(result)
        # 再用1x1的卷积降维
        result = self.project_conv(result)
        # 如果使用shortcut连接,则加入dropout操作
        if self.has_shortcut:
            if self.drop_connect_rate > 0:
                result = self.dropout(result)
            # shortcut就是到残差结构,输入输入的channel大小相等,这样就能相加了
            result += x

        return result

同理stage5和stage6的参数分别为:

   [-1, 1, MBConv, [160, 3, 2, 6, 0.25]], 
   [-1, 8, MBConv, [160, 3, 1, 6, 0.25]], 

   [-1, 1, MBConv, [256, 3, 2, 4, 0.25]], 
   [-1, 14, MBConv, [256, 3, 1, 4, 0.25]], 

注意,我们不需要stage7,因为我们只需要进行特征提取,不需要进行分类
在这里插入图片描述

然后是修改concat连接的位置:

下面注释中很清晰的写了特征图大小变化,以及为什么要和那一层连接。默认输入图片尺寸为640*640

# YOLOv5 🚀 by Ultralytics, GPL-3.0 license

# Parameters
nc: 80  # number of classes
depth_multiple: 1.0  # model depth multiple
width_multiple: 1.0  # layer channel multiple
anchors:
  - [10,13, 16,30, 33,23]  # P3/8
  - [30,61, 62,45, 59,119]  # P4/16
  - [116,90, 156,198, 373,326]  # P5/32

# YOLOv5 v6.0 backbone
backbone:
  [[-1, 1, stem, [24, 3, 2]],  # 0-P1/2 efficientnetv2 一开始是Stem = 普通的卷积+bn+激活  640*640*3 --> 320*320*24
#                    # [out_channel,kernel_size,stride,expansion,se_ration]
   [-1, 2, FusedMBConv, [24, 3, 1, 1, 0]], # 1 2个FusedMBConv=3*3conv+se+1*1conv   320*320*24-->320*320*24

   [-1, 1, FusedMBConv, [48, 3, 2, 4, 0]], # 2 这里strid2=2,特征图尺寸缩小一半,expansion=4输出特征图的深度变为原来的4倍 320*320*24-->160*160*48
   [-1, 3, FusedMBConv, [48, 3, 1, 4, 0]], # 3 三个FusedMBConv

   [-1, 1, FusedMBConv, [64, 3, 2, 4, 0]], # 4 160*160*48-->80*80*64
   [-1, 3, FusedMBConv, [64, 3, 1, 4, 0]], # 5

   [-1, 1, MBConv, [128, 3, 2, 4, 0.25]], # 6  这里strid2=2,特征图尺寸缩小一半, 40*40*128
   [-1, 5, MBConv, [128, 3, 1, 4, 0.25]], # 7

   [-1, 1, MBConv, [160, 3, 2, 6, 0.25]], # 8 这里 strid2=2,特征图尺寸缩小一半,20*20*160
   [-1, 8, MBConv, [160, 3, 1, 6, 0.25]], # 9

   [-1, 1, MBConv, [256, 3, 2, 4, 0.25]], # 10 这里strid2=2,特征图尺寸缩小一半,10*10*160
   [-1, 14, MBConv, [256, 3, 1, 4, 0.25]], # 11

   [-1, 1, SPPF, [1024, 5]], #12
  ]
# YOLOv5 v6.0 head
head:
  [[-1, 1, Conv, [512, 1, 1]], # 13  10*10
   [-1, 1, nn.Upsample, [None, 2, 'nearest']], # 14  20*20
   [[-1, 9], 1, Concat, [1]],  # 15 cat backbone P4 15  这里特征图大小为20*20,所以应该和9号连接
   [-1, 3, C3, [512, False]],  # 16 20*20

   [-1, 1, Conv, [256, 1, 1]], #17  20*20
   [-1, 1, nn.Upsample, [None, 2, 'nearest']], #18 40*40
   [[-1, 7], 1, Concat, [1]],  # cat backbone P3 19  7号特征图大小也是40*40
   [-1, 3, C3, [256, False]],  # 20 (P3/8-small)

   [-1, 1, Conv, [256, 3, 2]],  #21  卷积步长为2,所以特征图尺寸缩小,为 20*20
   [[-1, 17], 1, Concat, [1]],  # cat head P4  17层的特征图也是20*20
   [-1, 3, C3, [512, False]],  # 23 (P4/16-medium) 

   [-1, 1, Conv, [512, 3, 2]],  # 24  10*10 
   [[-1, 13], 1, Concat, [1]],  # cat head P5  13层的特征图大小就是10*10
   [-1, 3, C3, [1024, False]],  # 26 (P5/32-large)

   [[20, 23, 26], 1, Detect, [nc, anchors]],  # Detect(P3, P4, P5)
  ]

然后是修改yolo.py,这边很好改,后面加上stem, FusedMBConv, MBConv

if m in [Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, SPPF....
stem, FusedMBConv, MBConv]

common.py中应该添加的efficientnet代码如下:

# ------------------------------efficientnetv2--------------------------------------

class stem(nn.Module):
    def __init__(self, c1, c2, kernel_size=3, stride=1, groups=1):
        super().__init__()
        # kernel_size为3时,padding 为1,kernel为1时,padding为0
        padding = (kernel_size - 1) // 2
        # 由于要加bn层,所以不加偏置
        self.conv = nn.Conv2d(c1, c2, kernel_size, stride, padding=padding, groups=groups, bias=False)
        self.bn = nn.BatchNorm2d(c2, eps=1e-3, momentum=0.1)
        self.act = nn.SiLU(inplace=True)

    def forward(self, x):
        # print(x.shape)
        x = self.conv(x)
        x = self.bn(x)
        x = self.act(x)
        return x


def drop_path(x, drop_prob: float = 0., training: bool = False):
    if drop_prob == 0. or not training:
        return x
    keep_prob = 1 - drop_prob
    shape = (x.shape[0],) + (1,) * (x.ndim - 1)
    random_tensor = keep_prob + torch.rand(shape, dtype=x.dtype, device=x.device)
    random_tensor.floor_()  # binarize

    output = x.div(keep_prob) * random_tensor
    return output


class DropPath(nn.Module):
    def __init__(self, drop_prob=None):
        super(DropPath, self).__init__()
        self.drop_prob = drop_prob

    def forward(self, x):
        return drop_path(x, self.drop_prob, self.training)


class SqueezeExcite_efficientv2(nn.Module):
    def __init__(self, c1, c2, se_ratio=0.25, act_layer=nn.ReLU):
        super().__init__()
        self.gate_fn = nn.Sigmoid()
        reduced_chs = int(c1 * se_ratio)
        self.avg_pool = nn.AdaptiveAvgPool2d(1)
        self.conv_reduce = nn.Conv2d(c1, reduced_chs, 1, bias=True)
        self.act1 = act_layer(inplace=True)
        self.conv_expand = nn.Conv2d(reduced_chs, c2, 1, bias=True)

    def forward(self, x):
        # 先全局平均池化
        x_se = self.avg_pool(x)
        # 再全连接(这里是用的1x1卷积,效果与全连接一样,但速度快)
        x_se = self.conv_reduce(x_se)
        # ReLU激活
        x_se = self.act1(x_se)
        # 再全连接
        x_se = self.conv_expand(x_se)
        # sigmoid激活
        x_se = self.gate_fn(x_se)
        # 将x_se 维度扩展为和x一样的维度
        x = x * (x_se.expand_as(x))
        return x

# Fused-MBConv 将 MBConv 中的 depthwise conv3×3 和扩展 conv1×1 替换为单个常规 conv3×3。
class FusedMBConv(nn.Module):
    def __init__(self, c1, c2, k=3, s=1, expansion=1, se_ration=0, dropout_rate=0.2, drop_connect_rate=0.2):
        super().__init__()
        # shorcut 是指到残差结构 expansion是为了先升维,再卷积,再降维,再残差
        self.has_shortcut = (s == 1 and c1 == c2)  # 只要是步长为1并且输入输出特征图大小相等,就是True 就可以使用到残差结构连接
        self.has_expansion = expansion != 1  # expansion==1 为false expansion不为1时,输出特征图维度就为expansion*c1,k倍的c1,扩展维度
        expanded_c = c1 * expansion

        if self.has_expansion:
            self.expansion_conv = stem(c1, expanded_c, kernel_size=k, stride=s)
            self.project_conv = stem(expanded_c, c2, kernel_size=1, stride=1)
        else:
            self.project_conv = stem(c1, c2, kernel_size=k, stride=s)

        self.drop_connect_rate = drop_connect_rate
        if self.has_shortcut and drop_connect_rate > 0:
            self.dropout = DropPath(drop_connect_rate)

    def forward(self, x):
        if self.has_expansion:
            result = self.expansion_conv(x)
            result = self.project_conv(result)
        else:
            result = self.project_conv(x)
        if self.has_shortcut:
            if self.drop_connect_rate > 0:
                result = self.dropout(result)
            result += x

        return result


class MBConv(nn.Module):
    def __init__(self, c1, c2, k=3, s=1, expansion=1, se_ration=0, dropout_rate=0.2, drop_connect_rate=0.2):
        super().__init__()
        self.has_shortcut = (s == 1 and c1 == c2)
        expanded_c = c1 * expansion
        self.expansion_conv = stem(c1, expanded_c, kernel_size=1, stride=1)
        self.dw_conv = stem(expanded_c, expanded_c, kernel_size=k, stride=s, groups=expanded_c)
        self.se = SqueezeExcite_efficientv2(expanded_c, expanded_c, se_ration) if se_ration > 0 else nn.Identity()
        self.project_conv = stem(expanded_c, c2, kernel_size=1, stride=1)
        self.drop_connect_rate = drop_connect_rate
        if self.has_shortcut and drop_connect_rate > 0:
            self.dropout = DropPath(drop_connect_rate)

    def forward(self, x):
        # 先用1x1的卷积增加升维
        result = self.expansion_conv(x)
        # 再用一般的卷积特征提取
        result = self.dw_conv(result)
        # 添加se模块
        result = self.se(result)
        # 再用1x1的卷积降维
        result = self.project_conv(result)
        # 如果使用shortcut连接,则加入dropout操作
        if self.has_shortcut:
            if self.drop_connect_rate > 0:
                result = self.dropout(result)
            # shortcut就是到残差结构,输入输入的channel大小相等,这样就能相加了
            result += x

        return result

# ------------------------------efficientnetv2--------------------------------------

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

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

相关文章

全面适配 Android12

本文目录 背景技术分析实战总结与展望 背景 2021 年 10 月 5 日 Google 发布 Android12 操作系统,安全性和隐私性大幅提升,各手机厂家陆续更新 Android12 操作系统。 2022 年随着各大 APP 应用市场推动 Android12 适配工作,开发者积极响应…

应用性能监控管理工具

应用程序性能监控 Application Manager 的应用程序性能监控(APM Insight) 使应用程序开发人员和 DevOps 工程师能够了解应用程序性能,并帮助他们在问题影响最终用户之前对其进行故障排除。在应用程序性能问题影响收入之前监控、查明并解决它…

计算机毕设Python+Vue校园社团管理系统(程序+LW+部署)

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

PiL测试实战(下)| PiL阶段的闭环测试

前言 上篇我们介绍了单元级软件的PiL测试,对于集成级的PiL测试,其流程和单元阶段基本一致。然而,对于一些带有反馈控制逻辑的集成测试(如电机控制器MCU),PiL阶段会将控制算法(Controller Model…

HeidiSQL连接MySQL失败

HeidiSQL连接MySQL失败故障现象解决方案方案一方案二故障现象 在使用非本地盘的位置上的Heidi SQL工具,远程连接MySQL,发现连接失败,错误的原因是“plugin caching_sha2_password.dll could not be loaded”的解决办法。 解决方案 我们可…

Linux进度条小程序与git

gitLinux进度条小程序缓冲区问题回车换行倒计时小程序进度条程序git什么是gitgit的发展史git的基本操作创建仓库与本地仓库建立联系Linux中git提交代码的三板斧git基础指令Linux进度条小程序 缓冲区问题 编译运行后发现延迟了两秒才出现数字,我们都知道程序中的代码…

83-137-springcloud-stream-nacos-sentinel

83-137-springcloud-stream-nacos-sentinel: Stream 常见MQ(消息中间件):ActiveMQ,RabbitMQ,RocketMQ,Kafka Cloud Stream:屏蔽底层消息中间件的差异,降低切换成本,统一消息的编程…

WSL_02 WSL配置强大的 zsh

文章目录1 ZSH简介2 安装zsh2.1 准备阶段2 基础安装3 zsh更换主题3.1 使用vscode 打开 .zshrc4 自定义支持插件4.1 修改配置5 安装第三方插件autosuggestion5. 1 下载参考1 ZSH简介 zsh是Linux命令行界面,可以为帮助我们自定义配置命令行窗口,并且具有许…

vue引入iconfont/引入svg原理

前言 本文撰写的初衷是为了向组内成员推行使用svg sprites的方式管理项目的图标,由于实际工作中很多项目仍然采用font class的方式,这样不自觉带来一个痛点. 当项目一期开发完毕后,过段时间进入到项目二期。新增的开发需求不可避免的会增加新的图标,而font class需要全量打包…

Redis数据结构及命令详解

个人博客地址: http://xiaohe-blog.top/ 文章目录0. 简述1. 通用命令1.1 keys1.2 del1.3 type1.4 exists1.5 expire1.6 ttl2. string 类型2.1 set2.2 get2.3 mset2.4 mget2.5 setnx2.6 setex2.4 incr2.5 incrby2.6 incrbyfloat3. hash 类型3.1 hset3.2 hget3.3 hmse…

互联网时代,云计算的6大特征

1 云计算的定义 云计算是目前业内的热点概念,它以开放的标准和服务为基础,以互联网为中心,提供安全、快速、便捷的数据存储和网络计算服务,让互联网这片“云”上的各种计算机共同组成数个庞大的数据中心及计算中心。它可以被看成…

Observability:我们该选 Beats 还是 Elastic Agents 来采集数据?

除了 Logstash 之外,Elastic 提供了两种主要的方式来向 Elasticsearch 发送数据: 我们可以选择直接把数据从 Beats 发送至 Elasticsearch。当然我们也可以通过 Logstash 更进一步处理再发送至 Elasticsearch。 另外一种方式是使用 Elastic Agents 来发送…

[附源码]Nodejs计算机毕业设计基于的二手车交易平台Express(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置: Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术: Express框架 Node.js Vue 等等组成,B/S模式 Vscode管理前后端分…

[附源码]Python计算机毕业设计Django课室预约系统

项目运行 环境配置: Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术: django python Vue 等等组成,B/S模式 pychram管理等等。 环境需要 1.运行环境:最好是python3.7.7,…

Jmeter简单入门

背景 我们项目中一般测试接口都是用vscode中的REST Client插件(推荐好用)或者的话postman(适合写一些脚本和文件的上传) 但是他们都有一个不太行的功能,那就是多线程并发测试,其他市面上的什么apipost也都是不支持,网…

带你在Ubuntu 18.04上编译Linux内核

【推荐阅读】 一文了解Linux上TCP的几个内核参数调优 一文剖析Linux内核中内存管理 分析linux启动内核源码 一、环境说明 编译环境我选择了Ubuntu 18.04的虚拟机,内核截止2018-10-14最新版为4.18.14,笔者即将编译这个版本。 请确保磁盘空间足够&am…

Phoenix 对 Hbase 中表的映射

目录1)表的关系2)Hbase中创建表 test3)视图映射4)表映射数字类型说明1)表的关系 默认情况下, HBase 中已存在的表,通过 Phoenix 是不可见的。 如果要在 Phoenix 中操作 HBase 中已存在的表&…

java计算机毕业设计基于安卓Android的车位服务管理APP

项目介绍 网络的广泛应用给生活带来了十分的便利。所以把车位服务管理与现在网络相结合,利用java技术建设车位服务管理APP,实现车位服务管理的信息化。则对于进一步提高车位服务管理发展,丰富车位服务管理经验能起到不少的促进作用。 车位服务管理APP能够通过互联网得到广泛的、…

Python 爬虫库 urllib 使用详解!

一、Python urllib库 Python urllib 库用于操作网页 URL,并对网页的内容进行抓取处理。 Python3 的 urllib。 urllib 包 包含以下几个模块: urllib.request - 打开和读取 URL。 urllib.error - 包含 urllib.request 抛出的异常。 urllib.parse - 解析 …

自学了半个月python,感觉没用,怎么办?

本人从零基础开始学习python,已有两年之久,虽然一路上磕磕绊绊,但学习了一段时间之后,日常很多繁琐的工作,在python的助力下确实得到了很好的解决,工作效率也大大提高。 回到问题上来,自学了半…