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

news2024/11/26 2:24:28

目录

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_out
        return 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 1

        self.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.coloradmin.cn/o/2236426.html

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

相关文章

【HarmonyOS Next】数据本地存储:@ohos.data.preferences

【HarmonyOS Next】数据本地存储:ohos.data.preferences 在开发现代应用程序时,数据存储是一个至关重要的过程。应用程序为了保持某些用户设置、应用状态以及其他小量数据信息通常需要一个可靠的本地存储解决方案。在 HarmonyOS Next 环境下&#xff0c…

【从零开始的LeetCode-算法】3255. 长度为 K 的子数组的能量值 II

给你一个长度为 n 的整数数组 nums 和一个正整数 k 。 一个数组的 能量值 定义为: 如果 所有 元素都是依次 连续 且 上升 的,那么能量值为 最大 的元素。否则为 -1 。 你需要求出 nums 中所有长度为 k 的 子数组 的能量值。 请你返回一个长度为 n - …

C++ 参数传递 笔记

目录 1、输入参数的传递方式-选择传值还是传引用? 处理用户信息 处理坐标 处理配置 处理ID 2、对于需要修改的参数,使用非const引用传递 有趣的例外:警惕表象的迷惑 需要警惕的陷阱 “糟糕”的update方法: “完美”的set_name与set…

爬虫策略规避:Python爬虫的浏览器自动化

网络爬虫作为一种自动化获取网页数据的技术,被广泛应用于数据挖掘、市场分析、竞争情报等领域。然而,随着反爬虫技术的不断进步,简单的爬虫程序往往难以突破网站的反爬虫策略。因此,采用更高级的爬虫策略,如浏览器自动…

信号-3-信号处理、可重入函数与`volatile`关键字总结

信号处理是操作系统中的一个重要机制,它允许进程在运行期间响应外部事件,并作出相应的处理。为了处理信号,程序员需要理解如何设置信号处理器,如何管理信号的屏蔽与阻塞,以及信号的递送机制。本文将结合操作系统中的信…

深度学习-图像评分实验(TensorFlow框架运用、读取处理图片、模型建构)

目录 0、实验准备 ①实验环境 ②需要下载的安装包 ③注意事项(很关键,否则后面内容看不懂) ④容易出现的问题 1、查看数据并读取数据。 2、PIL库里的Image包进行读取(.resize更改图片尺寸,并将原始数据归一化处…

【Linux系统】—— 基本指令(二)

【Linux系统】—— 基本指令(二) 1 「alias」命令1.1 「ll」命令1.2 「alias」命令 2 「rmdir」指令与「rm」指令2.1 「rmdir」2.2 「rm」2.2.1 「rm」 删除普通文件2.2.2 「rm」 删除目录2.2.3 『 * 』 通配符 3 「man」 指令4 「cp」 指令4.1 拷贝普通…

面向对象技术简述(含设计模式)

6.9.2 面向对象技术 面向对象 对象 分类 继承 通过消息的通信 面向对象 对象 分类 继承 通过消息的通信 面向对象对象分类继承通过消息的通信其中包括: 对象 运行的实体;既包含属性/数据,又包含方法/行为/操作数据的函数;…

【信号处理】基于联合图像表示的深度学习卷积神经网络

Combined Signal Representations for Modulation Classification Using Deep Learning: Ambiguity Function, Constellation Diagram, and Eye Diagram 信号表示 Ambiguity Function(AF) 模糊函数描述了信号的两个维度(dimensions):延迟(delay)和多普勒(Doppler)。 …

【C++练习】两个实型数的加法运算

题目: 编写一个C程序,实现两个实型数的加法运算并输出结果。 要求: 定义一个函数 dadd,该函数接收两个 double 类型的参数,并返回它们的和。在 main 函数中,提示用户输入两个实型数(double 类…

【开源免费】基于SpringBoot+Vue.JS周边产品销售网站(JAVA毕业设计)

博主说明:本文项目编号 T 061 ,文末自助获取源码 \color{red}{T061,文末自助获取源码} T061,文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析…

Sql面试题二:请查询出用户连续三天登录的所有数据记录

问题: 现有用户登录记录表,请查询出用户连续三天登录的所有数据记录 id dt 1 2024-04-25 1 2024-04-26 1 2024-04-27 1 2024-04-28 1 2024-04-30 1 2024-05-01 1 2024-05-02 1 2024-05-04 1 2024-05-05 2 2…

科研绘图系列:R语言分组堆积图(grouped stacked barplot)

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍加载R包准备画图主题数据链接导入数据画图数据准备图例图1图2合并图系统信息介绍 分组堆积图(Grouped Stacked Bar Chart)是一种数据可视化图表,它结合了分组柱状图和堆积柱状图…

世界技能竞赛大数据应用开发环境1:1还原

集群情况 模块A搭建环境,在容器中搭建大数据平台 Pc机,安装安装比赛需要软件 模块B中使用idea快速开发完成数据处理 模块E包含了接口数据,使用vs code快速搭建vue数据可视化

【网络协议大花园】应用层 http协议的使用小技巧,用好了都不用加班,效率翻两倍(下篇)

本篇会加入个人的所谓鱼式疯言 ❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言 而是理解过并总结出来通俗易懂的大白话, 小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的. 🤭🤭🤭可能说的不是那么严谨.但小编初心是能让更多人…

SpringBoot源码解析(一)

SpringBoot自动装配原理 SpringBootApplication注解 我们在使用SpringBoot时,通常使用的是SpringBootApplication这个注解,比如: 而这个注解的定义为下图,可以发现这个注解上有另外三个注解:SpringBootConfiguration…

流类库与输入输出

来源:《C语言程序设计》 像C语言一样,C语言也没有输入输出语句。 但C标准库中有一个面向对象的输入输出软件包,即I/O流类库。 流是I/O流类的中心概念。 ------ I/O流类库是C语言中I/O函数在面向对象的程序设计方法中的一个替换产品。 -…

k8s图形化显示(KRM)

在master节点 kubectl get po -n kube-system 这个命令会列出 kube-system 命名空间中的所有 Pod 的状态和相关信息,比如名称、状态、重启次数等。 systemctl status kubelet #查看kubelet状态 yum install git #下载git命令 git clone https://gitee.com/duk…

理解鸿蒙app 开发中的 context

是什么 Context是应用中对象的上下文,其提供了应用的一些基础信息,例如resourceManager(资源管理)、applicationInfo(当前应用信息)、dir(应用文件路径)、area(文件分区…

ML1:sklearn env

sklearn: 中文参考: https://scikit-learn.cn/stable/modules/linear_model.html#ordinary-least-squares https://scikit-learn.org.cn/view/4.html ——》为主,不懂地方参考上面中文以及下面英文 英文参考: https://scikit…