改进系列(3):基于ResNet网络与CBAM模块融合实现的生活垃圾分类

目录

1. ResNet介绍

2. CBAM 模块

3. resnet + cbam

3.1 添加在每个layer层后

 3.2 关于训练的建议

4. 垃圾分类实战

4.1 数据集

4.2 训练

4.3 最好的权重

4.4 推理

5. 其它


1. ResNet介绍

ResNet(残差网络)是一种深度卷积神经网络模型,由Kaiming He等人于2015年提出。它的提出解决了深度神经网络的梯度消失和梯度爆炸问题,使得深层网络的训练变得更加容易和有效。

在深度神经网络中,随着网络层数的增加,梯度在反向传播过程中逐渐变小,导致网络的训练变得困难。这是因为在传统的网络结构中,每个网络层都是通过直接逐层堆叠来进行信息的传递。当网络层数增加时,信息的传递路径变得更长,导致梯度逐渐消失。为了解决这个问题,ResNet提出了“残差学习”的概念。

ResNet引入了“残差块”(residual block)的概念,其中每个残差块包含一个跳跃连接(skip connection),将输入直接添加到输出中。这个跳跃连接允许梯度直接通过残差块传递,避免了梯度的消失问题。通过残差块的堆叠,ResNet可以构建非常深的网络,如ResNet-50、ResNet-101等。

ResNet的提出极大地促进了深度神经网络的发展。它在多个视觉任务上取得了非常好的性能,成为了目标检测、图像分类、图像分割等领域的重要基准模型。同时,ResNet的思想也影响了后续的深度神经网络架构设计,被广泛应用于各种深度学习任务中。

Resnet 太经典了,以至于后面基本上都采用了‘残差块’的结构,关于resnet网络的详细介绍,可以百度,或者参考本人之前的 博文

2. CBAM 模块

CBAM代表卷积块注意力模块。它是一种神经网络架构,增强了卷积神经网络(CNN)中的注意力机制。CBAM模块由两个注意力机制组成,即通道注意力模块(CAM)和空间注意力模块(SAM)。

通道注意力模块侧重于通过计算通道统计数据并将这些统计数据的加权和应用于每个通道来捕获通道之间的全局依赖关系。这使得网络能够强调重要渠道,抑制无关渠道。

另一方面,空间注意力模块捕捉图像中空间位置之间的依赖关系。它通过考虑每个空间位置相对于其相邻位置的重要性来计算空间注意力图。这有助于网络关注重要的空间区域,忽略信息量较小的区域。

通过结合信道注意力模块和空间注意力模块,CBAM模块使网络能够动态调整CNN内的注意力。这提高了图像分类、对象检测和语义分割等任务的性能。

python的代码实现如下:

class ChannelAttention(nn.Module):def __init__(self, in_planes, reduction=16):super(ChannelAttention, self).__init__()self.avg_pool = nn.AdaptiveAvgPool2d(1)self.max_pool = nn.AdaptiveMaxPool2d(1)self.fc1 = nn.Conv2d(in_planes, in_planes // reduction, 1, bias=False)self.relu1 = nn.ReLU()self.fc2 = nn.Conv2d(in_planes // reduction, in_planes, 1, bias=False)self.sigmoid = nn.Sigmoid()def forward(self, x):avg_out = self.fc2(self.relu1(self.fc1(self.avg_pool(x))))max_out = self.fc2(self.relu1(self.fc1(self.max_pool(x))))out = avg_out + max_outreturn self.sigmoid(out)class SpatialAttention(nn.Module):def __init__(self, kernel_size=7):super(SpatialAttention, self).__init__()assert kernel_size in (3, 7), 'kernel size must be 3 or 7'padding = 3 if kernel_size == 7 else 1self.conv1 = nn.Conv2d(2, 1, kernel_size, padding=padding, bias=False)self.sigmoid = nn.Sigmoid()def forward(self, x):avg_out = torch.mean(x, dim=1, keepdim=True)max_out, _ = torch.max(x, dim=1, keepdim=True)x = torch.cat([avg_out, max_out], dim=1)x = self.conv1(x)return self.sigmoid(x)class CBAM(nn.Module):def __init__(self, in_planes, reduction=16, kernel_size=7):super(CBAM, self).__init__()self.ca = ChannelAttention(in_planes, reduction)self.sa = SpatialAttention(kernel_size)def forward(self, x):out = x * self.ca(x)out = out * self.sa(out)return out

3. resnet + cbam

resnet不同版本的结构如下

其实都是5层的结构,不过每层的相同模块重复多少次的区别

对于浅层(18,34)的残差块,可以看到没有1*1的卷积,因为网络并不大。而后面的50、101、152因为通道数很多,导致网络参数量很大,所以使用了1*1进行降维

添加模块很简单,因为CBAM模块的输入维度和输出维度是一样的,这样就可以在resnet网络的任意位置进行添加。

就比如vgg都是3*3连续两次的卷积,就是因为通道一样,那我想要连续卷积3次,甚至4次五次也只是重复叠加就行了,就类似于这个CMAB模块

事实上,通道不一样也可以添加,不过要更改维度稍微麻烦一点罢了

3.1 添加在每个layer层后

关键代码如下

    net.layer1.add_module('cbam',CBAM(net.layer1[-1].conv2.out_channels))net.layer2.add_module('cbam',CBAM(net.layer2[-1].conv2.out_channels))net.layer3.add_module('cbam',CBAM(net.layer3[-1].conv2.out_channels))net.layer4.add_module('cbam',CBAM(net.layer4[-1].conv2.out_channels))

这里的net就是resnet18 ~ resnet152网络,如果想要在单独某个层后添加,将对应的layerx注释即可,网络仍然可以正常运行

因为CBAM模块需要知道上一层传入的通道数是多少,这里经过测试发现,不同版本resnet的不同layer的最后模块都是下面这样,那么将它取出,传给resnet就行了


    (1): BasicBlock(
      (conv1): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (relu): ReLU(inplace=True)
      (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    

添加后的网络结构如下:

 3.2 关于训练的建议

添加完模块后,网络的结构就被破坏了,这样官方的预训练模型和改进后的模型无法匹配,就没法使用,这里有两种解决办法

1. 载入模型的时候有个strick参数,设置为False采用不完全覆盖即可

2. 先载入网络的预训练权重,然后在更改网络,这里本人使用的是第二种

不过这不是重点,迁移学习的好处谁都知道。针对于不同任务,虽然特征不同,但我们可以肯定在底层的语义特征其实是类似的(边缘、亮度啥的),不同的仅仅是高级的语义特征罢了,所以没必要从头进行学习

而我们添加的模块是没有权重的,所以CBAM模块必须要重头训练,这也是为啥有人认为加了模块为什么精度还降低的原因。要么模块不适用某个数据集,要么没有训练到位

    # 是否冻结权重if args.freeze_layers:for name, para in net.named_parameters():para.requires_grad_(False)if "fc" in name:para.requires_grad_(True)if "cbam" in name:para.requires_grad_(True)

这里的cbam就是之前添加CBAM模块的名字

可以发现,冻结后的训练参数明显少了很多

4. 垃圾分类实战

下载:Resnet改进(resnet18、resnet50等)在每个layer后加入CBAM模块实战:生活垃圾识别资源-CSDN文库

Tips:项目已经封装好,参考readme的数据集摆放好就可以训练了

4.1 数据集

生活常见垃圾分类,类别如下(代码自动生成

{"0": "battery","1": "biological","2": "brown_glass","3": "cardboard","4": "clothes","5": "green_glass","6": "metal","7": "paper","8": "plastic","9": "shoes","10": "trash","11": "white_glass"
}

可视化结果:

样本量:

4.2 训练

这里把CBAM加在了每一个layer后面,想要作对比实验可以自己注释掉特定层,或者全部去掉就是最初的resnet网络,这里利用resnet18+CBAM训练了100轮。

生成的结果如下:

Namespace(model='resnet18', pretrained=True, freeze_layers=True, batch_size=8, epochs=100, optim='SGD', lr=0.001, lrf=0.0001)
Using device is:  cuda
Using dataloader workers is : 8
trainSet number is : 12415 valSet number is : 3100
model output is : 12
resnet version :  resnet18
ResNet((conv1): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)(bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(relu): ReLU(inplace=True)(maxpool): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)(layer1): Sequential((0): BasicBlock((conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(relu): ReLU(inplace=True)(conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True))(1): BasicBlock((conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(relu): ReLU(inplace=True)(conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True))(cbam): CBAM((ca): ChannelAttention((avg_pool): AdaptiveAvgPool2d(output_size=1)(max_pool): AdaptiveMaxPool2d(output_size=1)(fc1): Conv2d(64, 4, kernel_size=(1, 1), stride=(1, 1), bias=False)(relu1): ReLU()(fc2): Conv2d(4, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)(sigmoid): Sigmoid())(sa): SpatialAttention((conv1): Conv2d(2, 1, kernel_size=(7, 7), stride=(1, 1), padding=(3, 3), bias=False)(sigmoid): Sigmoid())))(layer2): Sequential((0): BasicBlock((conv1): Conv2d(64, 128, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)(bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(relu): ReLU(inplace=True)(conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(downsample): Sequential((0): Conv2d(64, 128, kernel_size=(1, 1), stride=(2, 2), bias=False)(1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)))(1): BasicBlock((conv1): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(relu): ReLU(inplace=True)(conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True))(cbam): CBAM((ca): ChannelAttention((avg_pool): AdaptiveAvgPool2d(output_size=1)(max_pool): AdaptiveMaxPool2d(output_size=1)(fc1): Conv2d(128, 8, kernel_size=(1, 1), stride=(1, 1), bias=False)(relu1): ReLU()(fc2): Conv2d(8, 128, kernel_size=(1, 1), stride=(1, 1), bias=False)(sigmoid): Sigmoid())(sa): SpatialAttention((conv1): Conv2d(2, 1, kernel_size=(7, 7), stride=(1, 1), padding=(3, 3), bias=False)(sigmoid): Sigmoid())))(layer3): Sequential((0): BasicBlock((conv1): Conv2d(128, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)(bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(relu): ReLU(inplace=True)(conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(downsample): Sequential((0): Conv2d(128, 256, kernel_size=(1, 1), stride=(2, 2), bias=False)(1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)))(1): BasicBlock((conv1): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(relu): ReLU(inplace=True)(conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True))(cbam): CBAM((ca): ChannelAttention((avg_pool): AdaptiveAvgPool2d(output_size=1)(max_pool): AdaptiveMaxPool2d(output_size=1)(fc1): Conv2d(256, 16, kernel_size=(1, 1), stride=(1, 1), bias=False)(relu1): ReLU()(fc2): Conv2d(16, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)(sigmoid): Sigmoid())(sa): SpatialAttention((conv1): Conv2d(2, 1, kernel_size=(7, 7), stride=(1, 1), padding=(3, 3), bias=False)(sigmoid): Sigmoid())))(layer4): Sequential((0): BasicBlock((conv1): Conv2d(256, 512, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)(bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(relu): ReLU(inplace=True)(conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(downsample): Sequential((0): Conv2d(256, 512, kernel_size=(1, 1), stride=(2, 2), bias=False)(1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)))(1): BasicBlock((conv1): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(relu): ReLU(inplace=True)(conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True))(cbam): CBAM((ca): ChannelAttention((avg_pool): AdaptiveAvgPool2d(output_size=1)(max_pool): AdaptiveMaxPool2d(output_size=1)(fc1): Conv2d(512, 32, kernel_size=(1, 1), stride=(1, 1), bias=False)(relu1): ReLU()(fc2): Conv2d(32, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)(sigmoid): Sigmoid())(sa): SpatialAttention((conv1): Conv2d(2, 1, kernel_size=(7, 7), stride=(1, 1), padding=(3, 3), bias=False)(sigmoid): Sigmoid())))(avgpool): AdaptiveAvgPool2d(output_size=(1, 1))(fc): Linear(in_features=512, out_features=12, bias=True)
)
Total parameters is:11.23 M
Train parameters is:50068 
Flops:1824.40 M 
use optim is :  SGD

训练日志:

    "train parameters": {"model": "resnet18","pretrained": true,"freeze_layers": true,"batch_size": 16,"epochs": 100,"optim": "SGD","lr": 0.01,"lrf": 0.001},"Datasets": {"trainSets number": 12415,"validSets number": 3100},"model": {"total parameters": 11226580.0,"train parameters": 49676,"flops": 1824400426.0},
    "epoch:99": {"train info": {"accuracy": 0.9484494563020954,"battery": {"Precision": 0.9493,"Recall": 0.9656,"Specificity": 0.9967,"F1 score": 0.9574},"biological": {"Precision": 0.9662,"Recall": 0.9797,"Specificity": 0.9977,"F1 score": 0.9729},"brown_glass": {"Precision": 0.9312,"Recall": 0.9465,"Specificity": 0.9971,"F1 score": 0.9388},"cardboard": {"Precision": 0.9516,"Recall": 0.9369,"Specificity": 0.9971,"F1 score": 0.9442},"clothes": {"Precision": 0.9852,"Recall": 0.9843,"Specificity": 0.9923,"F1 score": 0.9847},"green_glass": {"Precision": 0.9704,"Recall": 0.9762,"Specificity": 0.9987,"F1 score": 0.9733},"metal": {"Precision": 0.8776,"Recall": 0.8961,"Specificity": 0.9935,"F1 score": 0.8868},"paper": {"Precision": 0.9167,"Recall": 0.9298,"Specificity": 0.9939,"F1 score": 0.9232},"plastic": {"Precision": 0.8656,"Recall": 0.8194,"Specificity": 0.9925,"F1 score": 0.8419},"shoes": {"Precision": 0.9525,"Recall": 0.9507,"Specificity": 0.9931,"F1 score": 0.9516},"trash": {"Precision": 0.9177,"Recall": 0.9391,"Specificity": 0.996,"F1 score": 0.9283},"white_glass": {"Precision": 0.8837,"Recall": 0.8581,"Specificity": 0.9941,"F1 score": 0.8707},"mean precision": 0.9306416666666667,"mean recall": 0.9318666666666666,"mean specificity": 0.995225,"mean f1 score": 0.93115},"valid info": {"accuracy": 0.6038709677399875,"battery": {"Precision": 0.5551,"Recall": 0.6667,"Specificity": 0.9653,"F1 score": 0.6058},"biological": {"Precision": 0.7278,"Recall": 0.665,"Specificity": 0.9831,"F1 score": 0.695},"brown_glass": {"Precision": 0.5816,"Recall": 0.6777,"Specificity": 0.9802,"F1 score": 0.626},"cardboard": {"Precision": 0.5762,"Recall": 0.6798,"Specificity": 0.9695,"F1 score": 0.6237},"clothes": {"Precision": 0.7115,"Recall": 0.5859,"Specificity": 0.8757,"F1 score": 0.6426},"green_glass": {"Precision": 0.725,"Recall": 0.696,"Specificity": 0.9889,"F1 score": 0.7102},"metal": {"Precision": 0.4346,"Recall": 0.5425,"Specificity": 0.9634,"F1 score": 0.4826},"paper": {"Precision": 0.5596,"Recall": 0.581,"Specificity": 0.9668,"F1 score": 0.5701},"plastic": {"Precision": 0.4469,"Recall": 0.4624,"Specificity": 0.9662,"F1 score": 0.4545},"shoes": {"Precision": 0.5217,"Recall": 0.5772,"Specificity": 0.9227,"F1 score": 0.548},"trash": {"Precision": 0.6185,"Recall": 0.7698,"Specificity": 0.9777,"F1 score": 0.6859},"white_glass": {"Precision": 0.551,"Recall": 0.5226,"Specificity": 0.9776,"F1 score": 0.5364},"mean precision": 0.584125,"mean recall": 0.6188833333333333,"mean specificity": 0.9614250000000002,"mean f1 score": 0.5983999999999999}}

如果想要绘制pr曲线、auc啥的,根据上述的json文件绘制即可

各类曲线:

混淆矩阵:

4.3 最好的权重

训练结束后,会打印在验证集上最好的一轮结果

best epoch: 42
train performance: {"accuracy": 0.9386226339098359,"battery": {"Precision": 0.9358,"Recall": 0.9444,"Specificity": 0.9958,"F1 score": 0.9401},"biological": {"Precision": 0.9722,"Recall": 0.9746,"Specificity": 0.9981,"F1 score": 0.9734},"brown_glass": {"Precision": 0.9242,"Recall": 0.928,"Specificity": 0.9969,"F1 score": 0.9261},"cardboard": {"Precision": 0.9363,"Recall": 0.9271,"Specificity": 0.9962,"F1 score": 0.9317},"clothes": {"Precision": 0.9822,"Recall": 0.9847,"Specificity": 0.9907,"F1 score": 0.9834},"green_glass": {"Precision": 0.9473,"Recall": 0.9623,"Specificity": 0.9977,"F1 score": 0.9547},"metal": {"Precision": 0.8468,"Recall": 0.8701,"Specificity": 0.9918,"F1 score": 0.8583},"paper": {"Precision": 0.9035,"Recall": 0.9143,"Specificity": 0.9929,"F1 score": 0.9089},"plastic": {"Precision": 0.8464,"Recall": 0.7962,"Specificity": 0.9915,"F1 score": 0.8205},"shoes": {"Precision": 0.9454,"Recall": 0.9418,"Specificity": 0.9921,"F1 score": 0.9436},"trash": {"Precision": 0.9279,"Recall": 0.9229,"Specificity": 0.9966,"F1 score": 0.9254},"white_glass": {"Precision": 0.8371,"Recall": 0.8371,"Specificity": 0.9914,"F1 score": 0.8371},"mean precision": 0.9170916666666665,"mean recall": 0.9169583333333334,"mean specificity": 0.9943083333333335,"mean f1 score": 0.9169333333333333
}
valid performance: {"accuracy": 0.6090322580625516,"battery": {"Precision": 0.5484,"Recall": 0.7196,"Specificity": 0.9615,"F1 score": 0.6224},"biological": {"Precision": 0.7471,"Recall": 0.6599,"Specificity": 0.9848,"F1 score": 0.7008},"brown_glass": {"Precision": 0.6,"Recall": 0.6942,"Specificity": 0.9812,"F1 score": 0.6437},"cardboard": {"Precision": 0.581,"Recall": 0.5843,"Specificity": 0.9743,"F1 score": 0.5826},"clothes": {"Precision": 0.6558,"Recall": 0.6638,"Specificity": 0.8177,"F1 score": 0.6598},"green_glass": {"Precision": 0.7222,"Recall": 0.728,"Specificity": 0.9882,"F1 score": 0.7251},"metal": {"Precision": 0.4602,"Recall": 0.5294,"Specificity": 0.9678,"F1 score": 0.4924},"paper": {"Precision": 0.5678,"Recall": 0.5381,"Specificity": 0.9702,"F1 score": 0.5526},"plastic": {"Precision": 0.4768,"Recall": 0.4162,"Specificity": 0.973,"F1 score": 0.4444},"shoes": {"Precision": 0.5871,"Recall": 0.4608,"Specificity": 0.9527,"F1 score": 0.5163},"trash": {"Precision": 0.6243,"Recall": 0.777,"Specificity": 0.978,"F1 score": 0.6923},"white_glass": {"Precision": 0.5479,"Recall": 0.5161,"Specificity": 0.9776,"F1 score": 0.5315},"mean precision": 0.5932166666666667,"mean recall": 0.6072833333333333,"mean specificity": 0.9605833333333335,"mean f1 score": 0.5969916666666667
}

4.4 推理

推理的时候,放在指定目录即可对图片进行批推理

5. 其它

更多的CNN图像分类、语义分割关注本专栏,将持续更新

融合其他模块应该和CBAM模块差不多,思路一样的。对于不同网络,利用vgg、densenet、transformer之类的也差不多。同时语义分割的unet也是连续的3*3卷积,通道数也不变,加入CBAM模块也是类似的。

关于本项目,CBAM也可以在layer内部进行添加,不过我搜了资料,加在layer后是效果最棒的。如果想要发文章,最好多试试其他模块,然后多炼丹才好

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

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

相关文章

Linux 服务器上部署 .NET Core 应用程序,值得收藏!

在 Linux 服务器上部署 .NET Core 应用程序,标志着传统的以微软为中心的部署平台的重大转变。.NET Core 的跨平台特性允许开发人员享受 Linux 环境的性能、可靠性和安全性。本指南提供了在各种 Linux 发行版上部署 .NET Core 应用程序的全面概述,重点是使…

2024-11-01 - 统一身份认证 - OpenLdap - 中间件 - 流雨声

摘要 2024-11-01 周五 杭州 暴雨 调查问卷: https://www.wjx.cn/vm/exIBFDM.aspx# 2024年转瞬即逝,可是生活还在继续,这里有一项关于人工智能和项目管理对于效能关系的调研问卷,AI 对工作的作用和影响。问卷不采集个人信息,在此…

前端页面性能优化的常见问题与解决方案

在当今互联网高速发展的时代,前端页面的性能对于用户体验至关重要。一个加载缓慢、交互卡顿的页面很可能会导致用户流失。本文将深入探讨前端页面性能优化中常见的问题以及相应的解决方案。 一、常见问题 (一)资源加载问题 文件体积过大 …

视频播放相关的杂记

基于QT FFMPEG设计一款 RTMP协议推流、视频录制软件 实现的功能: (1)将摄像头视频流 麦克风音频流合并,并推到流媒体服务器 (2)将摄像头视频流 麦克风音频流保存到本地磁盘 基于QtFFMPEG设计一款RTM…

Pycharm,2024最新版Pycharm下载安装配置教程!

目录 1、Pycharm 简介2、Pycharm下载3、环境变量的配置4、Pycharm的使用 1、Pycharm 简介 Pycharm资料领取不收米 PyCharm是一种Python IDE(Integrated Development Environment,集成开发环境),带有一整套可以帮助用户在使用Py…

Redis9:商户查询缓存3

欢迎来到“雪碧聊技术”CSDN博客! 在这里,您将踏入一个专注于Java开发技术的知识殿堂。无论您是Java编程的初学者,还是具有一定经验的开发者,相信我的博客都能为您提供宝贵的学习资源和实用技巧。作为您的技术向导,我将…

解锁函数的魔力:Python 中的多值传递、灵活参数与无名之美

文章目录 前言📖一、多值返回📚1.1 多值返回的概念📚1.2 工作原理📚1.3 应用场景📜总结 📖二、 多种参数传递形式📚2.1 位置参数(Positional Arguments)📚2.2…

若依框架-添加测试类-最新

1、在【ruoyi-admin】的pom.xml下添加依赖 <!-- 单元测试--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-test</artifactId><scope>test</scope></dependency><dependency>…

初识网络编程TCP/IP

目录 前言相关名词解释应用层协议——HTTP传输层协议socketTCP帧头格式三次握手、四次挥手 UDPTCP的socket实现 参考博文 前言 刚碰到网络编程&#xff0c;会出现一堆协议、概念、这层次那技术的&#xff0c;头都大了&#xff0c;还是得总结总结…… 相关名词解释 ✨✨网络…

【C++课程学习】:继承(上)(详细讲解)

&#x1f381;个人主页&#xff1a;我们的五年 &#x1f50d;系列专栏&#xff1a;C课程学习 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 目录 一.继承的概念和定义 &#x1f384;继承的概念&#xff1a; &#x1f384;继承的定义&#xff1a; …

Linux笔记之pandoc实现各种文档格式间的相互转换

Linux笔记之pandoc实现各种文档格式间的相互转换 code review! 文章目录 Linux笔记之pandoc实现各种文档格式间的相互转换1.安装 Pandoc2.Word转Markdown3.markdown转html4.Pandoc 支持的一些常见格式4.1.输入格式4.2.输出格式 1.安装 Pandoc sudo apt-get install pandoc # …

封装的数字滚动组件的实现代码

效果&#xff1a; 学习啦&#xff1a; Vue 是一个渐进式框架&#xff0c;鼓励通过组件化来构建应用&#xff0c;其组件化优势&#xff1a; 代码复用&#xff1a;不同的视图和功能被封装成独立的组件&#xff0c;便于复用。易于维护&#xff1a;每个组件职责单一、耦合度低&…

Kafka面试题解答(二)

1.怎么尽可能保证 Kafka 的可靠性 kafka是可能会出现数据丢失问题的&#xff0c;Leader维护了一个动态的in-sync replica set&#xff08;ISR&#xff09;&#xff0c;意为和 Leader保持同步的FollowerLeader集合(leader&#xff1a;0&#xff0c;isr:0,1,2)。 如果Follower长…

分块——最为优雅的暴力

在信息学竞赛中&#xff0c;常常会遇到一些区间修改或区间查询的题目&#xff0c;如果直接敲暴力的话&#xff0c;时间复杂度是 O ( n m ) O(nm) O(nm) 可能会超时&#xff0c;如果写树状数组或线段树的话&#xff0c;又有一点复杂&#xff0c;不易理解&#xff0c;那么这时候…

w~视觉~合集20~SAM

我自己的原文哦~ https://blog.51cto.com/whaosoft/12500982 #SAM 今天&#xff0c;Meta发布史上首个图像分割基础模型SAM&#xff0c;将NLP领域的prompt范式引进CV&#xff0c;让模型可以通过prompt一键抠图。网友直呼&#xff1a;CV不存在了! 就在刚刚&#xff0c;Meta AI…

Halcon resistor.hedv 使用多个对焦级别提取深度

depth_from_focus * Extract depth using multiple focus levels * 使用多个对焦级别提取深度 Names : [] * 初始化一个空数组&#xff0c;用于存储图像名称 dev_close_window () * 关闭当前打开的图像窗口 for i : 1 to 10 by 1 * 循环开始&#xff0c;从1到10 …

qt QTreeWidgetItem详解

1、概述 QTreeWidgetItem 是 Qt 框架中的一个类&#xff0c;专门用于在 QTreeWidget&#xff08;一个基于项的树形视图&#xff09;中表示单个节点&#xff08;或称为项&#xff09;。QTreeWidget 继承自 QAbstractItemView&#xff0c;而 QTreeWidgetItem 则作为树中的一个节…

三.Linux用户和用户管理

前言&#xff1a;Linux系统是一个多用户多任务的分时操作系统&#xff0c;任何一个要使用资源的都必须向系统管理员申请一个账户&#xff0c;然后通过这个账户的身份进入系统。 一.此次目的 用户账号的添加、删除与修改。 用户口令的管理。 用户组的管理。 二.用户账号的添加…

SpringBoot技术栈:构建高效共享汽车系统

4系统概要设计 4.1概述 本系统采用B/S结构(Browser/Server,浏览器/服务器结构)和基于Web服务两种模式&#xff0c;是一个适用于Internet环境下的模型结构。只要用户能连上Internet,便可以在任何时间、任何地点使用。系统工作原理图如图4-1所示&#xff1a; 图4-1系统工作原理…

【笔记】扩散模型(九):Imagen 理论与实现

论文链接&#xff1a;Photorealistic Text-to-Image Diffusion Models with Deep Language Understanding 非官方实现&#xff1a;lucidrains/imagen-pytorch Imagen 是 Google Research 的文生图工作&#xff0c;这个工作并没有沿用 Stable Diffusion 的架构&#xff0c;而是级…