基于多尺度动态卷积的图像分类


✨✨ 欢迎大家来访Srlua的博文(づ ̄3 ̄)づ╭❤~✨✨

🌟🌟 欢迎各位亲爱的读者,感谢你们抽出宝贵的时间来阅读我的文章。

我是Srlua小谢,在这里我会分享我的知识和经验。🎥

希望在这里,我们能一起探索IT世界的奥妙,提升我们的技能。🔮

记得先点赞👍后阅读哦~ 👏👏

📘📚 所属专栏:传知代码论文复现

欢迎访问我的主页:Srlua小谢 获取更多信息和资源。✨✨🌙🌙

​​

​​

目录

概述

效果可视化

模型原理解读

动态卷积

多尺度特征融合网络

自适应损失函数

模型整体结构

数据集简介

实验结果

实现过程

参考文献


 本文所有资源均可在该地址处获取。

概述

在计算机视觉领域,图像分类是非常重要的任务之一。近年来,深度学习的兴起极大提升了图像分类的精度和效率。本文将介绍一种基于动态卷积网络(Dynamic Convolutional Networks)、多尺度特征融合网络(Multi-scale Feature Fusion Networks)和自适应损失函数(Adaptive Loss Functions)的智能图像分类模型,采用了PyTorch框架进行实现,并通过PyQt构建了简洁的用户图像分类界面。该模型能够处理多分类任务,并且提供了良好的可扩展性和轻量化设计,使其适用于多种不同的图像分类场景。

效果可视化

模型原理解读

动态卷积

传统卷积网络通常使用固定的卷积核,而动态卷积则是通过引入多个可学习的卷积核动态选择不同的卷积核进行操作。这样可以在不同的输入图像上实现不同的卷积操作,从而提高模型的表达能力。通过加入Attention模块,能对输入图像的不同特征进行加权处理,进一步增强了网络对特征的自适应能力。

常规的卷积层使用单个静态卷积核,应用于所有输入样本。而动态卷积层则通过注意力机制动态加权n个卷积核的线性组合,使得卷积操作依赖于输入样本。动态卷积操作可以定义为:
 


其中动态卷积的线性组合可以用这个图表示:


在 ODConv 中,对于卷积核 WiWi​:

  1. αsiαsi​​ 为 k ×× k 空间位置的每个卷积参数(每个滤波器)分配不同的注意力标量;下图a
  2. αciαci​​ 为每个卷积滤波器 WimWim​ 的 cincin​ 个通道分配不同的注意力标量;下图b
  3. αfiαfi​​ 为 coutcout​ 个卷积滤波器分配不同的注意力标量;下图c
  4. αwiαwi​​ 为整个卷积核分配一个注意力标量。下图d

在下图中,展示了将这四种类型的注意力逐步乘以 nn 个卷积核的过程。原则上,这四种类型的注意力是相互补充的,通过按位置、通道、滤波器和卷积核的顺序逐步将它们乘以卷积核 WiWi​,使卷积操作在所有空间位置、所有输入通道、所有卷积核中都不同,针对输入 xx 捕获丰富的上下文信息,从而提供性能保证。


原则上来讲,这四种类型的注意力是互补的,通过渐进式对卷积沿位置、通道、滤波器以及核等维度乘以不同的注意力将使得卷积操作对于输入存在各个维度的差异性,提供更好的性能以捕获丰富上下文信息。因此,ODCOnv可以大幅提升卷积的特征提取能力;更重要的是,采用更少卷积核的ODConv可以取得更优的性能。
代码实现

class ODConv2d(nn.Module):
    def __init__(self, in_planes, out_planes, kernel_size, stride=1, padding=0, dilation=1, groups=1,
                 reduction=0.0625, kernel_num=4):
        super(ODConv2d, self).__init__()
        self.in_planes = in_planes
        self.out_planes = out_planes
        self.kernel_size = kernel_size
        self.stride = stride
        self.padding = padding
        self.dilation = dilation
        self.groups = groups
        self.kernel_num = kernel_num
        self.attention = Attention(in_planes, out_planes, kernel_size, groups=groups,
                                   reduction=reduction, kernel_num=kernel_num)
        self.weight = nn.Parameter(torch.randn(kernel_num, out_planes, in_planes//groups, kernel_size, kernel_size),
                                   requires_grad=True)
        self._initialize_weights()
 
        if self.kernel_size == 1 and self.kernel_num == 1:
            self._forward_impl = self._forward_impl_pw1x
        else:
            self._forward_impl = self._forward_impl_common
 
    def _initialize_weights(self):
        for i in range(self.kernel_num):
            nn.init.kaiming_normal_(self.weight[i], mode='fan_out', nonlinearity='relu')
 
    def update_temperature(self, temperature):
        self.attention.update_temperature(temperature)
 
    def _forward_impl_common(self, x):
        # Multiplying channel attention (or filter attention) to weights and feature maps are equivalent,
        # while we observe that when using the latter method the models will run faster with less gpu memory cost.
        channel_attention, filter_attention, spatial_attention, kernel_attention = self.attention(x)
        batch_size, in_planes, height, width = x.size()
        x = x * channel_attention
        x = x.reshape(1, -1, height, width)
        aggregate_weight = spatial_attention * kernel_attention * self.weight.unsqueeze(dim=0)
        aggregate_weight = torch.sum(aggregate_weight, dim=1).view(
            [-1, self.in_planes // self.groups, self.kernel_size, self.kernel_size])
        output = F.conv2d(x, weight=aggregate_weight, bias=None, stride=self.stride, padding=self.padding,
                          dilation=self.dilation, groups=self.groups * batch_size)
        output = output.view(batch_size, self.out_planes, output.size(-2), output.size(-1))
        output = output * filter_attention
        return output
 
    def _forward_impl_pw1x(self, x):
        channel_attention, filter_attention, spatial_attention, kernel_attention = self.attention(x)
        x = x * channel_attention
        output = F.conv2d(x, weight=self.weight.squeeze(dim=0), bias=None, stride=self.stride, padding=self.padding,
                          dilation=self.dilation, groups=self.groups)
        output = output * filter_attention
        return output
 
    def forward(self, x):
        return self._forward_impl(x)

多尺度特征融合网络

多尺度特征是指从图像中提取不同尺度、不同分辨率下的特征。这些特征可以捕捉图像中的局部细节信息(如纹理、边缘等)和全局结构信息(如物体形状和轮廓)。传统的卷积神经网络(CNN)一般通过逐层下采样提取深层特征,但在这个过程中,高层的语义信息虽然丰富,却丢失了低层的细节信息。多尺度特征融合通过结合不同层次的特征,弥补了这一不足。


如上图所示,在本文的网络设计中,多尺度特征融合通过以下几个步骤实现:

特征提取模块:模型通过不同的卷积核(例如3x3、5x5、7x7)对输入图像进行多层次的卷积操作,提取出不同尺度的特征。

特征拼接与加权融合:在融合阶段,来自不同卷积层的特征图会进行拼接或加权求和,确保网络能够根据不同的任务需求自适应地调整特征权重。例如,在分类任务中,局部信息可能对小物体的识别更有帮助,而全局信息则适用于大物体的分类。
代码实现

class MultiScaleFeatureFusion(nn.Module):
    def __init__(self, in_channels, out_channels):
        super(MultiScaleFeatureFusion, self).__init__()
        self.conv1x1 = nn.Conv2d(in_channels, out_channels, kernel_size=1)
        self.conv3x3 = nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1)
        self.conv5x5 = nn.Conv2d(in_channels, out_channels, kernel_size=5, padding=2)
        self.conv7x7 = nn.Conv2d(in_channels, out_channels, kernel_size=7, padding=3)

    def forward(self, x):
        out1 = self.conv1x1(x)
        out2 = self.conv3x3(x)
        out3 = self.conv5x5(x)
        out4 = self.conv7x7(x)
        return out1 + out2 + out3 + out4  # 多尺度特征融合

自适应损失函数

在深度学习的图像分类任务中,损失函数的选择直接影响模型的训练效果。本文所设计的网络引入了自适应损失函数(Adaptive Loss Functions),这是提升分类性能的重要创新之一。传统的损失函数通常具有固定的形式和权重,不能根据数据分布和训练阶段的不同自动调整。而自适应损失函数通过动态调整损失权重和形式,能够更有效地优化模型,提升其对复杂问题的学习能力。
代码实现

class AdaptiveLoss(nn.Module):
    def __init__(self, alpha=0.25, gamma=2.0, balance_factor=0.999):
        super(AdaptiveLoss, self).__init__()
        self.alpha = alpha
        self.gamma = gamma
        self.balance_factor = balance_factor
    
    def forward(self, logits, targets):
        # 计算交叉熵损失
        ce_loss = F.cross_entropy(logits, targets, reduction='none')

模型整体结构

本文使用的模型整体结构如下图所示:

数据集简介

德国交通标志识别基准(GTSRB)包含43类交通标志,分为39,209个训练图像12,630个测试图像。图像具有不同的光线条件和丰富的背景。如下图所示:

实验结果

在经过动态卷积和多尺度特征提取以及自适应损失函数后在验证集上能够取得0.944的准确率。


其loss曲线和准确率曲线如下图所示:


并且本文与其他文章结果进行了比较:

模型准确率差异
ASSC[1]82.8%+11.6%
DAN[2]91.1%+3.3%
SRDA[3]93.6%+0.8%
OURS94.4%-

混淆矩阵结果

实现过程

版本

PyQt5                     5.15.11
seaborn                   0.13.2
torch                     2.4.0
PyQt5-Qt5                 5.15.2
numpy                     1.26.4
pandas                    1.5.0

  1. 首先对模型进行训练,保存最佳模型
python main.py

  1. 加载最佳模型进行可视化预测
python predict_gui.py

参考文献

[1] Haeusser, Philip, et al. “Associative domain adaptation.” Proceedings of the IEEE international conference on computer vision. 2017.
[2] Long, Mingsheng, et al. “Learning transferable features with deep adaptation networks.” International conference on machine learning. PMLR, 2015.
[3] Cai, Guanyu, et al. “Learning smooth representation for unsupervised domain adaptation.” IEEE Transactions on Neural Networks and Learning Systems 34.8 (2021): 4181-4195.
[4] Li, Chao, Aojun Zhou, and Anbang Yao. “Omni-dimensional dynamic convolution.” arXiv preprint arXiv:2209.07947 (2022).

​​

### 多尺度卷积神经网络在图像分类中的应用 多尺度卷积神经网络(Multi-scale Convolutional Neural Network, Multi-scale CNN)是一种通过不同大小的卷积核或多分支架构来捕捉图像中多种尺度特征的技术。这种方法能够有效提升模型对目标物体形状变化、尺寸差异以及背景干扰等问题的鲁棒性。 #### 1. 多尺度卷积的核心原理 多尺度卷积通常利用多个不同大小的卷积核在同一层上并行操作,从而捕获图像的不同细节层次。例如,在某些经典框架中,会采用 \(3 \times 3\)、\(5 \times 5\) 和 \(7 \times 7\) 的卷积核组合[^2]。这些卷积核分别对应于细粒度边缘检测、中间尺度纹理分析和大范围空间关系建模。此外,为了进一步降低计算成本,部分研究引入了权值共享机制,使得同一组权重可以在不同的子区域重复使用[^3]。 #### 2. 实现方法概述 以下是几种常见的多尺度卷积实现方式: - **Inception 模块**: Google 提出的一种典型设计思路,它在一个单独的层内集成了若干个平行路径,每条路径包含特定尺寸的卷积运算 (如 \(1 \times 1\), \(3 \times 3\), 或者池化)[^1]。最终将各分支的结果沿通道维度拼接起来作为下一层输入。 - **Dilated/Atrous Convolutions**: 扩张卷积允许扩大感受野而无需增加额外参数数量。具体而言,就是在标准滑动窗口之间插入空洞间隙,形成稀疏采样模式。这种方式特别适合处理高分辨率遥感影像或者医学扫描数据等领域内的大规模场景理解任务。 - **Pyramid Pooling Module**: PSPNet 中提出的金字塔池化策略先通过对原始图片执行全局最大/平均汇聚得到固定长度向量表示;然后再将其重新插值得到原图大小并与初始特征图叠加融合在一起。这样既保留了低级像素级别信息又兼顾到了高级语义概念描述能力。 #### 3. MATLAB 示例代码片段 下面给出一段简单的基于MATLAB平台构建基础版multi-scale cnn用于水果类别预测的例子: ```matlab layers = [ imageInputLayer([32 32 3]) % Scale 1: Small Kernel Size convolution2dLayer(3,64,'Padding','same') batchNormalizationLayer reluLayer maxPooling2dLayer(2,'Stride',2) % Scale 2: Medium Kernel Size convolution2dLayer(5,128,'Padding','same') batchNormalizationLayer reluLayer maxPooling2dLayer(2,'Stride',2) % Scale 3: Large Kernel Size convolution2dLayer(7,256,'Padding','same') batchNormalizationLayer reluLayer fullyConnectedLayer(10) % Assuming there are 10 classes of fruits. softmaxLayer classificationLayer]; ``` 此脚本定义了一个小型化的三层结构,其中每一层代表一种独立的空间变换视角。最后一节则负责把前面提取出来的抽象表征转换成具体的概率分布形式以便后续决策判断之需。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值