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)
相关推荐
JaneZJW24 分钟前
江科大STM32入门——UART通信笔记总结
笔记·stm32·单片机·嵌入式
Heavydrink30 分钟前
Spring学习笔记2
笔记·学习·spring
霜雪殇璃44 分钟前
c++对结构体的扩充以及类的介绍
开发语言·c++·笔记·学习
YunB西风英1 小时前
(STM32笔记)十二、DMA的基础知识与用法 第三部分
笔记·stm32·单片机·嵌入式硬件·dma·嵌入式
Fz@1 小时前
AD与嘉立创的集成库整理
笔记·学习
小高Baby@2 小时前
网络授时笔记
开发语言·笔记·学习·php
星迹日2 小时前
数据结构:LinkedList与链表—无头单向链表(一)
java·数据结构·经验分享·笔记·链表·单向链表
zhencon-com2 小时前
如何用Python编程实现自动整理XML发票文件
xml·经验分享·笔记·娱乐·媒体·教育电商·政务
一棵开花的树,枝芽无限靠近你2 小时前
【PPTist】插入形状、插入图片、插入图表
前端·笔记·学习·编辑器·ppt·pptist
bachelores2 小时前
数据结构-排序
数据结构·算法·排序算法