深度学习笔记(十二):普通卷积、深度可分离卷积、空间可分离卷积代码

简介: 本文探讨了深度可分离卷积和空间可分离卷积,通过代码示例展示了它们在降低计算复杂性和提高效率方面的优势。

1. 摘要🎄

本文介绍了深度可分离卷积和空间可分离卷积的概念及其在计算复杂性和效率上的优势。深度可分离卷积通过通道内卷积和1x1卷积减少参数量,而空间可分离卷积将3x3卷积分解为3x1和1x3卷积以降低计算复杂性。代码示例展示了这两种卷积在实际网络结构中的应用,并通过比较计算量表明深度可分离卷积具有更高的效率。

2. 定义🎄

空间可分离卷积:空间可分离卷积是一种将传统卷积操作分解为两个更小操作的方法,通常分为逐行卷积和逐列卷积两个步骤。首先,使用一维卷积核对输入特征图的每一行进行卷积,生成中间特征图;然后,对中间特征图的每一列进行卷积,得到最终输出特征图。这种卷积方式可以减少计算量和参数数量,但并非所有的卷积核都适合进行空间上的分离,因此在深度学习中的应用不如深度可分离卷积广泛。 最常见的情况是将3x3的卷积核划分为3x1和1x3的卷积核,如下所示:
在这里插入图片描述
现在,我们不是用9次乘法进行一次卷积,而是进行两次卷积,每次3次乘法(总共6次),以达到相同的效果。 乘法较少,计算复杂性下降,网络运行速度更快。

import torch
import torch.nn as nn

class SpatiallySeparableConv2d(nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size, stride=1, padding=0):
        super(SpatiallySeparableConv2d, self).__init__()
        # 检查卷积核大小是否为奇数
        assert kernel_size % 2 == 1, "Kernel size must be odd for spatially separable convolution"

        self.depthwise_row_conv = nn.Conv2d(in_channels, in_channels, kernel_size=(kernel_size, 1),
                                            stride=(stride, 1), padding=((padding//2), 0), groups=in_channels)
        self.depthwise_col_conv = nn.Conv2d(in_channels, out_channels, kernel_size=(1, kernel_size),
                                            stride=(1, stride), padding=(0, (padding//2)), groups=in_channels)

    def forward(self, x):
        x = self.depthwise_row_conv(x)
        x = self.depthwise_col_conv(x)
        return x

# 示例使用
input_tensor = torch.randn(1, 3, 32, 32)  # (batch_size, channels, height, width)
conv = SpatiallySeparableConv2d(in_channels=3, out_channels=8, kernel_size=3, stride=1, padding=1)
output = conv(input_tensor)

print(output.shape)  # 输出的形状

深度可分离卷积:深度可分离卷积(Depthwise Separable Convolution)是一种高效的卷积操作,广泛应用于轻量级神经网络中,如MobileNet和Xception。它将标准卷积操作分解为两个较小的操作:深度卷积(Depthwise Convolution)和逐点卷积(Pointwise Convolution)。

  1. 深度卷积:在这一步中,每个输入通道独立地应用一个卷积核,这样只捕获空间特征而不混合通道信息。

  2. 逐点卷积:此步骤使用1x1的卷积核对深度卷积的输出进行卷积,目的是组合来自不同通道的特征。

这种分解方法显著减少了计算量和模型参数,同时保持了网络的性能。深度可分离卷积特别适合于计算资源有限的环境,如移动设备和嵌入式系统,深度可分离卷积步骤如下图所示。
在这里插入图片描述

import torch
import torch.nn as nn

class DepthwiseSeparableConv2d(nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size, stride=1, padding=0):
        super(DepthwiseSeparableConv2d, self).__init__()
        self.depthwise = nn.Conv2d(
            in_channels, in_channels, 
            kernel_size=kernel_size, 
            stride=stride, 
            padding=padding, 
            groups=in_channels
        )
        self.pointwise = nn.Conv2d(
            in_channels, out_channels, 
            kernel_size=1, 
            stride=1, 
            padding=0
        )

    def forward(self, x):
        x = self.depthwise(x)
        x = self.pointwise(x)
        return x

# 示例使用
input_tensor = torch.randn(1, 3, 32, 32)  # (batch_size, channels, height, width)
dconv = DepthwiseSeparableConv2d(in_channels=3, out_channels=8, kernel_size=3, stride=1, padding=1)
output = dconv(input_tensor)

print(output.shape)  # 输出的形状

3. 具体代码分析🎄

import torch.nn as nn
from Module.activation import act_layers

class ConvBNReLU(nn.Sequential):
    def __init__(self,i,o,k,s,p,dilation=(1,1),groups=1,bias=False,activation='ReLU'):
        super(ConvBNReLU, self).__init__()

        self.CBA = nn.Sequential(
            nn.Conv2d(i,o,kernel_size=k,stride=s,padding=p,dilation=dilation,groups=groups,bias=bias),
            nn.BatchNorm2d(o),
            act_layers(activation)
        )
    def forward(self, input):
        x = self.CBA(input)
        return x

class Param(nn.Module):
    def __init__(self,activation='ReLU'):
        super(Param, self).__init__()
        self.conv1 = nn.Sequential(
            nn.Conv2d(3, 24, kernel_size=3, stride=2, padding=1, bias=False),
            nn.BatchNorm2d(24),
            act_layers(activation)
        )
        # 普通卷积
        self.conv2 = nn.Sequential(
            nn.Conv2d(24, 24, kernel_size=3, stride=1, padding=1, bias=False),
            nn.BatchNorm2d(24),
            act_layers(activation)
        )
        # 深度可分离
        self.conv3 = nn.Sequential(
            self.depthwise_conv(24, 24, kernel_s=3, stride=1, padding=1),
            nn.Conv2d(24, 24, 1),
            nn.BatchNorm2d(24),
            act_layers(activation)
        )
        # 空间可分离
        self.D3x1_D1x3 = nn.Sequential(
            ConvBNReLU(24,24,(3,1),1,p=(1,0),dilation=(1,1),groups=1),
            ConvBNReLU(24,24,(1,3),1,p=(0,1),dilation=(1,1),groups=1)
        )

    @staticmethod
    def depthwise_conv(input_c: int,
                       output_c: int,
                       kernel_s: int,
                       stride: int = 1,
                       padding: int = 0,
                       bias: bool = False) -> nn.Conv2d:
        return nn.Conv2d(in_channels=input_c, out_channels=output_c, kernel_size=kernel_s,
                         stride=stride, padding=padding, bias=bias, groups=input_c)

    def forward(self, x):
        x = self.conv1(x)
        # 普通卷积 258.55M 5.93k
        x = self.conv2(x)
        # 深度可分离 69.57M 1.56K
        x = self.conv3(x)
        # 空间可分离 186.9M 4.25K
        x = self.D3x1_D1x3(x)

        return x

很明显深度可分离卷积参数量和计算复杂度都最小。

目录
相关文章
|
2天前
|
编解码 Java 程序员
写代码还有专业的编程显示器?
写代码已经十个年头了, 一直都是习惯直接用一台Mac电脑写代码 偶尔接一个显示器, 但是可能因为公司配的显示器不怎么样, 还要接转接头 搞得桌面杂乱无章,分辨率也低,感觉屏幕还是Mac自带的看着舒服
|
4天前
|
存储 缓存 关系型数据库
MySQL事务日志-Redo Log工作原理分析
事务的隔离性和原子性分别通过锁和事务日志实现,而持久性则依赖于事务日志中的`Redo Log`。在MySQL中,`Redo Log`确保已提交事务的数据能持久保存,即使系统崩溃也能通过重做日志恢复数据。其工作原理是记录数据在内存中的更改,待事务提交时写入磁盘。此外,`Redo Log`采用简单的物理日志格式和高效的顺序IO,确保快速提交。通过不同的落盘策略,可在性能和安全性之间做出权衡。
1540 5
|
1月前
|
弹性计算 人工智能 架构师
阿里云携手Altair共拓云上工业仿真新机遇
2024年9月12日,「2024 Altair 技术大会杭州站」成功召开,阿里云弹性计算产品运营与生态负责人何川,与Altair中国技术总监赵阳在会上联合发布了最新的“云上CAE一体机”。
阿里云携手Altair共拓云上工业仿真新机遇
|
7天前
|
人工智能 Rust Java
10月更文挑战赛火热启动,坚持热爱坚持创作!
开发者社区10月更文挑战,寻找热爱技术内容创作的你,欢迎来创作!
581 22
|
4天前
|
存储 SQL 关系型数据库
彻底搞懂InnoDB的MVCC多版本并发控制
本文详细介绍了InnoDB存储引擎中的两种并发控制方法:MVCC(多版本并发控制)和LBCC(基于锁的并发控制)。MVCC通过记录版本信息和使用快照读取机制,实现了高并发下的读写操作,而LBCC则通过加锁机制控制并发访问。文章深入探讨了MVCC的工作原理,包括插入、删除、修改流程及查询过程中的快照读取机制。通过多个案例演示了不同隔离级别下MVCC的具体表现,并解释了事务ID的分配和管理方式。最后,对比了四种隔离级别的性能特点,帮助读者理解如何根据具体需求选择合适的隔离级别以优化数据库性能。
201 3
|
10天前
|
JSON 自然语言处理 数据管理
阿里云百炼产品月刊【2024年9月】
阿里云百炼产品月刊【2024年9月】,涵盖本月产品和功能发布、活动,应用实践等内容,帮助您快速了解阿里云百炼产品的最新动态。
阿里云百炼产品月刊【2024年9月】
|
11天前
|
Linux 虚拟化 开发者
一键将CentOs的yum源更换为国内阿里yum源
一键将CentOs的yum源更换为国内阿里yum源
580 5
|
23天前
|
存储 关系型数据库 分布式数据库
GraphRAG:基于PolarDB+通义千问+LangChain的知识图谱+大模型最佳实践
本文介绍了如何使用PolarDB、通义千问和LangChain搭建GraphRAG系统,结合知识图谱和向量检索提升问答质量。通过实例展示了单独使用向量检索和图检索的局限性,并通过图+向量联合搜索增强了问答准确性。PolarDB支持AGE图引擎和pgvector插件,实现图数据和向量数据的统一存储与检索,提升了RAG系统的性能和效果。
|
7天前
|
XML 安全 Java
【Maven】依赖管理,Maven仓库,Maven核心功能
【Maven】依赖管理,Maven仓库,Maven核心功能
233 3
|
9天前
|
存储 人工智能 搜索推荐
数据治理,是时候打破刻板印象了
瓴羊智能数据建设与治理产品Datapin全面升级,可演进扩展的数据架构体系为企业数据治理预留发展空间,推出敏捷版用以解决企业数据量不大但需构建数据的场景问题,基于大模型打造的DataAgent更是为企业用好数据资产提供了便利。
327 2