24/11/3 算法笔记 空洞卷积

什么是空洞卷积

上图展示了空洞卷积,其卷积核大小为3×3,步长s=1,r=2。你或许会问了,这个r是什么呢,其实啊,这个r正是普通卷积和空洞卷积的差别所在,我们称之为膨胀因子。当r=1时,表示卷积核各元素之前没有空隙,即相邻两个元素间位置相差1,此时其实就是我们正常的卷积,所以广义上说,普通的卷积是一种特殊的空洞卷积;当r=2时,表示卷积核各元素之前有一个空隙,即相邻两个元素间位置相差2,此时就是我们上图中的卷积核。

定义

空洞卷积是一种卷积操作,其中卷积核中间带有一些洞,跳过一些元素进行卷积。这种操作使得卷积核可以在不增加参数量的前提下扩大其感受野。

原理

在传统的卷积操作中,滤波器的每个元素都与输入的相应位置进行相乘,然后求和。而在空洞卷积中,滤波器的元素之间有一定的间隔,也就是所谓的空洞。这个间隔可以是一个或多个像素。通过增加空洞的大小,空洞卷积可以有效地扩大滤波器的感受野,即滤波器能够看到输入图像更广阔的范围。

优势

  1. 扩大感受野:空洞卷积可以在不牺牲空间分辨率的情况下扩大感受野,这对于捕捉更大尺度的特征和提供更好的上下文信息非常有帮助。
  2. 获取多尺度上下文信息:当多个带有不同扩张率的空洞卷积核叠加时,不同的感受野会带来多尺度信息,这对于分割任务是非常重要的。
  3. 降低计算量:空洞卷积不需要引入额外的参数,因此可以有效地减少计算量。

缺点

  1. 网格效应:由于空洞卷积是一种稀疏的采样方式,当多个空洞卷积叠加时,有些像素根本没有被利用到,会损失信息的连续性与相关性,进而影响分割、检测等要求较高的任务。
  2. 多尺度问题:大的扩张率对于大物体分割与检测有利,但是对于小物体则有弊无利,如何处理好多尺度问题的检测,是空洞卷积设计的重点。

感受野就是特征图上的一个像素对应原图夺嫂尺寸的像素

感受野计算公式

srtide表示步长,k kk表示卷积核大小。

至于空洞卷积为什么可以增大感受野,如下图所示:

上图表示使用3×3的卷积核进行空洞卷积,r=2,很明显,此时灰色特征层的感受野为5×5。其实呢,计算空洞卷积感受野也有公式,我们这样来思考,上图是3×3的卷积核,r=2,这样构成的一个空洞卷积核(乱起的名字哈,不用在意)的尺寸就相当于是5×5大小了,这时候我们感受野的计算就相当于5×5卷积核的感受野了。

空洞卷积的缺点,有些像素没有利用到。网格效应

解决缺点:

使用不同膨胀因子的空洞卷积

这样效果就有所改善了

接下来我们用numpy拆解一下空洞卷积

import numpy as np

def dilated_convld(input_data,kernel,dilation,stride):

    """
    一维空洞卷积实现。
    
    参数:
    - input_data: 输入数据,形状为 (length, channels)
    - kernel: 卷积核,形状为 (kernel_size, channels, out_channels)
    - dilation: 空洞大小
    - stride: 步长
    
    返回:
    - 输出数据,形状为 (output_length, out_channels)
    """
# 输入数据的长度和通道数
    length, channels = input_data.shape
    # 卷积核的大小和输出通道数
    kernel_size, _, out_channels = kernel.shape
    
    # 计算输出数据的长度
    output_length = (length - dilation * (kernel_size - 1) - 1) // stride + 1
    
    # 初始化输出数据
    output_data = np.zeros((output_length, out_channels))
    
    # 空洞卷积
    for i in range(0, output_length):
        for j in range(out_channels):
            # 计算当前卷积核的起始位置
            start = i * stride
            end = start + dilation * kernel_size
            # 提取对应的输入数据片段
            input_slice = input_data[start:end:dilation, :]
            # 执行卷积操作
            output_data[i, j] = np.sum(input_slice * kernel[:, :, j], axis=(0, 1))
    
    return output_data

# 示例使用
if __name__ == "__main__":
    # 输入数据:长度为10,1个通道
    input_data = np.random.rand(10, 1)
    
    # 卷积核:大小为3,1个输入通道,1个输出通道
    kernel = np.random.rand(3, 1, 1)
    
    # 空洞大小为2,步长为1
    dilation = 2
    stride = 1
    
    # 执行空洞卷积
    output_data = dilated_conv1d(input_data, kernel, dilation, stride)
    
    print("Input Data Shape:", input_data.shape)
    print("Output Data Shape:", output_data.shape)
相关推荐
网易独家音乐人Mike Zhou7 分钟前
【卡尔曼滤波】数据预测Prediction观测器的理论推导及应用 C语言、Python实现(Kalman Filter)
c语言·python·单片机·物联网·算法·嵌入式·iot
冰帝海岸44 分钟前
01-spring security认证笔记
java·笔记·spring
小二·2 小时前
java基础面试题笔记(基础篇)
java·笔记·python
Swift社区4 小时前
LeetCode - #139 单词拆分
算法·leetcode·职场和发展
Kent_J_Truman4 小时前
greater<>() 、less<>()及运算符 < 重载在排序和堆中的使用
算法
wusong9995 小时前
mongoDB回顾笔记(一)
数据库·笔记·mongodb
猫爪笔记5 小时前
前端:HTML (学习笔记)【1】
前端·笔记·学习·html
Resurgence035 小时前
【计组笔记】习题
笔记
IT 青年5 小时前
数据结构 (1)基本概念和术语
数据结构·算法
Dong雨5 小时前
力扣hot100-->栈/单调栈
算法·leetcode·职场和发展