Press "Enter" to skip to content

卷积神经网络(CNNs)中的空洞卷积全面指南

介绍

在计算机视觉领域中,卷积神经网络(CNN)已经重新定义了图像分析和理解的领域。这些强大的网络已经在图像分类、物体检测和语义分割等任务中取得了突破。它们为医疗保健、自动驾驶等领域的各种应用奠定了基础。

然而,随着对更具上下文感知和稳健模型的需求不断增长,传统的卷积层在捕捉广泛的上下文信息方面面临限制。这导致了对能够提高网络理解更广泛上下文能力的创新技术的需求,而不会显著增加计算复杂性。

介绍扩张卷积(Atrous Convolution),这是一种颠覆卷积神经网络中常规规则的突破性方法。扩张卷积,也被称为空洞卷积,通过在深度学习领域引入新的维度,使网络能够在不显著增加计算成本或参数的情况下捕捉更广泛的上下文。

学习目标

  • 了解卷积神经网络的基本知识,以及它们如何处理视觉数据来理解图像。
  • 了解扩张卷积如何改进传统卷积方法,从而在图像中捕捉更大的上下文。
  • 探索使用扩张卷积的知名CNN架构,例如DeepLab和WaveNet,以了解它如何提高它们的性能。
  • 通过实际示例和代码片段,获得对扩张卷积在CNN中应用的实际理解。

本文是Data Science Blogathon的一部分。

理解卷积神经网络:它的工作原理

卷积神经网络(CNN)是一类主要用于分析图像和视频等视觉数据的深度神经网络。它们受到人类视觉系统的启发,在涉及视觉数据的模式识别任务中非常有效。以下是详情:

  1. 卷积层:CNN由多个层组成,其中卷积层是核心。这些层使用卷积运算将可学习的滤波器应用于输入数据,从图像中提取各种特征。
  2. 汇聚层:在卷积之后,通常会使用汇聚层来减小空间维度,压缩卷积层学到的信息。常见的汇聚操作包括最大汇聚或平均汇聚,它们减小表示的大小同时保留关键信息。
  3. 激活函数:在卷积和汇聚层之后使用非线性激活函数(例如ReLU)来引入非线性,让网络能够学习数据中的复杂模式和关系。
  4. 全连接层:在CNN末尾,通常使用全连接层。这些层整合前面层提取的特征,并执行分类或回归任务。
  5. 逐点卷积:逐点卷积,也被称为1×1卷积,是CNN中用于降低维度和特征组合的技术。它涉及将1×1滤波器应用于输入数据,有效减少输入通道数,并允许跨通道组合特征。逐点卷积通常与其他卷积操作一起使用,以增强网络捕捉数据中的复杂模式和关系的能力。
  6. 可学习参数:CNN依赖于在训练过程中更新的可学习参数(权重和偏置)。训练过程包括前向传播,其中输入数据通过网络,以及反向传播,根据网络的性能调整参数。

从扩张卷积开始

扩张卷积,也被称为空洞卷积,是一种引入了参数扩张率的卷积操作。与常规卷积将滤波器应用于相邻像素不同,扩张卷积通过在它们之间引入间隙来分散滤波器的参数,由扩张率来控制。这个过程扩大了滤波器的感受野,而不增加参数的数量。简单来说,它允许网络在不增加复杂性的情况下从输入数据中捕获更广泛的上下文。

扩张率决定了卷积的每一步之间跳过多少像素。1的扩张率表示常规卷积,而较高的扩张率跳过更多的像素。这个扩大的感受野能够捕获更大的上下文信息,而不增加计算成本,使网络能够高效地捕获局部细节和全局上下文。

本质上,扩张卷积有助于将更广泛的上下文信息整合到卷积神经网络中,从而更好地对数据中的大规模模式进行建模。它通常用于需要关注不同尺度上的背景信息的应用,例如计算机视觉中的语义分割或自然语言处理任务中处理序列。

多尺度特征学习中的扩张卷积

扩张卷积,也被称为空洞卷积,已经在神经网络中的多尺度特征学习中起到了关键作用。以下是关于它们在实现多尺度特征学习方面的关键要点:

  1. 上下文扩展:扩张卷积允许网络在不显著增加参数的情况下从更广泛的上下文中获取信息。通过在滤波器中引入间隙,感受野在不增加计算负载的情况下扩大。
  2. 可变的感受野:使用大于1的扩张率,这些卷积可以创建“多尺度”效果。它们使网络能够同时处理不同尺度或颗粒度的输入数据,在同一层中捕获细节和粗糙细节。
  3. 分级特征提取:可以调整扩张率在网络层之间进行调节,以创建分级特征提取机制。具有较小扩张率的较低层专注于细节,而具有较大扩张率的较高层捕获更广泛的上下文。
  4. 高效的信息融合:扩张卷积有效地促进了不同尺度之间信息的融合。它们提供了一种结合来自不同感受野的特征的机制,增强了网络对数据中复杂模式的理解。
  5. 在分割和识别中的应用:在图像分割或语音识别等任务中,扩张卷积被用来通过使网络学习多尺度表示来提高性能,从而实现更准确的预测。

扩张卷积和常规卷积的结构

输入图像(矩形)    |    |常规卷积(方框)    -内核大小:固定内核    -滑动策略:在输入特征图上滑动    -步幅:通常为1    -输出特征图:尺寸减小    扩张(空洞)卷积(方框)    -内核大小:带间隙的固定内核(由扩张率控制)    -滑动策略:间隔元素,增加感受野    -步幅:由扩张率控制    -输出特征图:保持输入尺寸,扩大感受野

常规卷积和扩张(空洞)卷积的比较

方面 常规卷积 扩张(空洞)卷积
滤波器应用 将滤波器应用于连续的输入数据区域 在滤波器元素之间引入间隙(孔)
内核大小 固定的内核大小 固定的内核大小,但带有间隙(由扩张率控制)
滑动策略 在输入特征图上滑动 间隔元素允许扩大感受野
步幅 通常为1 通过扩张率控制的增加的有效步幅
输出特征图尺寸 由卷积导致的尺寸减小 保持输入尺寸,同时增加感受野
感受野 有限的有效感受野 扩大的有效感受野
上下文信息捕获 有限的上下文捕获 增强了捕获更广泛上下文的能力

空洞卷积的应用

  • 空洞卷积通过扩大感受野,提高速度,而不增加参数。
  • 它们可以在特定的输入区域上进行选择性聚焦,提高特征提取效率。
  • 与使用更大卷积核的传统卷积相比,计算复杂度减少。
  • 适用于实时视频处理和处理大规模图像数据集。

探索知名架构

DeepLab [REF 1]

DeepLab是一系列用于语义图像分割的卷积神经网络架构。它以使用空洞卷积(也称为扩张卷积)和空洞空间金字塔池化(ASPP)来捕捉图像中的多尺度上下文信息而闻名,从而实现像素级别的精确分割。

以下是DeepLab的概述:

  • DeepLab专注于通过为每个像素分配一个标签来将图像划分为有意义的区域,从而帮助理解图像中的详细上下文。
  • DeepLab使用的空洞卷积扩展了网络的感受野,同时保持了分辨率。这使得DeepLab能够在多个尺度上捕捉上下文,实现全面的信息收集,而不会显著增加计算成本。
  • DeepLab使用的空洞空间金字塔池化(ASPP)是一种有效地收集多尺度信息的特征。它使用不同膨胀率的并行空洞卷积来捕捉多尺度的上下文,并有效地融合信息。
  • DeepLab的架构,专注于多尺度上下文和精确分割,已在各种语义分割挑战中取得了最先进的性能,展示出在分割任务中的高准确性。

代码:

import tensorflow as tffrom tensorflow.keras import Sequentialfrom tensorflow.keras.layers import Conv2D, MaxPooling2D, Conv2DTransposedef create_DeepLab_model(input_shape, num_classes):    model = Sequential([        Conv2D(64, (3, 3), activation='relu', padding='same', input_shape=input_shape),        Conv2D(64, (3, 3), activation='relu', padding='same'),        MaxPooling2D(pool_size=(2, 2)),                Conv2D(128, (3, 3), activation='relu', padding='same'),        Conv2D(128, (3, 3), activation='relu', padding='same'),        MaxPooling2D(pool_size=(2, 2)),                # Add more convolutional layers as needed                Conv2DTranspose(64, (3, 3), strides=(2, 2), padding='same', activation='relu'),        Conv2D(num_classes, (1, 1), activation='softmax', padding='valid')    ])    return model# Define input shape and number of classesinput_shape = (256, 256, 3)  # Example input shapenum_classes = 21  # Example number of classes# Create the DeepLab modeldeeplab_model = create_DeepLab_model(input_shape, num_classes)# Compile the model (you might want to adjust the optimizer and loss function based on your task)deeplab_model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])# Print model summarydeeplab_model.summary()

全卷积网络(FCNs)[REF 2]

  • 全卷积网络(FCNs)与空间保留:FCNs用1×1卷积来取代全连接层,对于保持空间信息,特别是在分割等任务中,非常重要。
  • 编码器结构:编码器通常基于VGG,通过转换将全连接层转换为卷积层,以保留空间细节和与图像的连接性。
  • 空洞卷积集成:空洞卷积在FCNs中至关重要。它们使网络能够在不显著增加参数或丢失空间分辨率的情况下捕捉多尺度信息。
  • 语义分割:空洞卷积在捕捉多尺度的上下文信息方面起到了关键作用,使网络能够理解同一图像中不同大小和比例的对象。
  • 解码器的作用:解码器网络通过反卷积层将特征映射上采样到原始图像大小。空洞卷积确保上采样过程保留来自编码器的关键空间细节。
  • 提高准确性:通过融合空洞卷积,FCNs在语义分割任务中实现了精度的提高,有效地捕捉上下文并保持多尺度的空间信息。

代码:

import tensorflow as tf# 定义扩张卷积层函数def atrous_conv_layer(inputs, filters, kernel_size, rate):    return tf.keras.layers.Conv2D(filters=filters, kernel_size=kernel_size,     dilation_rate=rate, padding='same', activation='relu')(inputs)# 采用扩张卷积的例子FCN架构def FCN_with_AtrousConv(input_shape, num_classes):    inputs = tf.keras.layers.Input(shape=input_shape)    # 编码器(VGG风格)    conv1 = tf.keras.layers.Conv2D(64, (3, 3), activation='relu', padding='same')(inputs)    conv2 = tf.keras.layers.Conv2D(64, (3, 3), activation='relu', padding='same')(conv1)    # 扩张卷积层    atrous_conv1 = atrous_conv_layer(conv2, 128, (3, 3), rate=2)    atrous_conv2 = atrous_conv_layer(atrous_conv1, 128, (3, 3), rate=4)    # 根据需要添加更多的扩张卷积层...    # 解码器(转置卷积)    upsample = tf.keras.layers.Conv2DTranspose(64, (3, 3), strides=(2, 2), padding='same')    (atrous_conv2)    output = tf.keras.layers.Conv2D(num_classes, (1, 1), activation='softmax')(upsample)    model = tf.keras.models.Model(inputs=inputs, outputs=output)    return model# 定义输入形状和类的数量input_shape = (256, 256, 3)  # 示例输入形状num_classes = 10  # 示例类的数量# 创建一个带有扩张卷积的FCN模型model = FCN_with_AtrousConv(input_shape, num_classes)# 编译模型model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])# 显示模型概要model.summary()

LinkNet [REF 3]

LinkNet是一种先进的图像分割架构,将其设计的高效性与扩张卷积(也称为膨胀卷积)的强大之处相结合。它利用跳跃连接来增强信息流,并准确地对图像进行分割。

  • 高效的图像分割:LinkNet通过采用扩张卷积技术高效地对图像进行分割,这种技术能够扩大感受野而不会使参数过多增加。
  • 扩张卷积的整合:利用扩张卷积,LinkNet能够有效地捕获上下文信息,同时保持计算要求的可管理性。
  • 跳跃连接以改善信息流动:LinkNet的跳跃连接有助于更好地在网络中进行信息流动,通过整合不同网络深度的特征,实现更精确的分割。
  • 优化设计:该架构经过优化,可以在计算效率和准确的图像分割之间取得平衡,使其适用于各种分割任务。
  • 可扩展的架构:LinkNet的设计可以扩展,使其能够高效且准确地处理各种复杂度的分割任务。

代码:

import torchimport torch.nn as nnimport torch.nn.functional as Fclass ConvBlock(nn.Module):    def __init__(self, in_channels, out_channels, kernel_size=3, stride=1, padding=1):        super(ConvBlock, self).__init__()        self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=kernel_size,         stride=stride, padding=padding)        self.bn = nn.BatchNorm2d(out_channels)        self.relu = nn.ReLU(inplace=True)    def forward(self, x):        x = self.conv(x)        x = self.bn(x)        x = self.relu(x)        return xclass DecoderBlock(nn.Module):    def __init__(self, in_channels, out_channels):        super(DecoderBlock, self).__init__()        self.conv1 = ConvBlock(in_channels, in_channels // 4, kernel_size=1, stride=1, padding=0)        self.deconv = nn.ConvTranspose2d(in_channels // 4, out_channels, kernel_size=4,         stride=2, padding=1)        self.conv2 = ConvBlock(out_channels, out_channels)    def forward(self, x, skip):        x = F.interpolate(x, scale_factor=2, mode='nearest')        x = self.conv1(x)        x = self.deconv(x)        x = self.conv2(x)        if skip is not None:            x += skip        return xclass LinkNet(nn.Module):    def __init__(self, num_classes=21):        super(LinkNet, self).__init__()        # 编码器        self.encoder = nn.Sequential(            ConvBlock(3, 64),            nn.MaxPool2d(2),            ConvBlock(64, 128),            nn.MaxPool2d(2),            ConvBlock(128, 256),            nn.MaxPool2d(2),            ConvBlock(256, 512),            nn.MaxPool2d(2)        )        # 解码器        self.decoder = nn.Sequential(            DecoderBlock(512, 256),            DecoderBlock(256, 128),            DecoderBlock(128, 64),            DecoderBlock(64, 32)        )        # 最终预测        self.final_conv = nn.Conv2d(32, num_classes, kernel_size=1)    def forward(self, x):        skips = []        for module in self.encoder:            x = module(x)            skips.append(x.clone())        skips = skips[::-1]  # 反转以供解码器使用        for i, module in enumerate(self.decoder):            x = module(x, skips[i])        x = self.final_conv(x)        return x# 示例用法:input_tensor = torch.randn(1, 3, 224, 224)  # 示例输入张量形状model = LinkNet(num_classes=10)  # 示例类的数量output = model(input_tensor)print(output.shape)  # 示例输出形状

InstanceFCN [参考 4]

这种方法将全卷积网络(FCNs)应用于实例感知语义分割,FCNs在语义分割方面非常有效。与原始的FCN不同,原始的FCN中,每个输出像素是一个对象类别的分类器,而在InstanceFCN中,每个输出像素是相对于实例的位置的分类器。例如,在得分图中,每个像素是一个判断它是否属于实例的“右侧”的分类器。

InstanceFCN的工作原理

在输入图像上应用FCN生成个得分图,每个得分图对应于一种特定的相对位置。这些被称为实例敏感的得分图。为了从这些得分图中生成对象实例,使用大小为m×m的滑动窗口。将m×m窗口分成相应的k²,m ⁄ k × m ⁄ k维窗口,对应于个相对位置。输出的m ⁄ k × m ⁄ k子窗口直接从相应得分图中的相同子窗口复制值。根据它们的相对位置,将个子窗口组合在一起,组装成一个m×m的分割结果。例如,在上图中,输出的#1子窗口直接从#1实例感知得分图m ⁄ k × m ⁄ k子窗口的左上角m×m窗口复制过来。这被称为实例组装模块。

InstanceFCN架构

架构包括在输入图像上应用VGG-16完全卷积,输出特征图上有两个完全卷积分支。其中一个用于估计段的实例(如上所述),另一个用于对实例进行评分。

这个架构的某些部分使用孔卷积,在滤波器中引入空隙,用于扩大网络的视野并捕捉更多的上下文信息。

对于第一个分支,使用1×1 512-d conv.层,后面跟一个3×3 conv.层,生成一组个实例敏感的得分图。使用组装模块(如上所述)来预测m×m(= 21)的分割掩模。第二个分支包括一个3×3 512-d conv.层,后面跟一个1×1 conv.层。该1×1 conv.层是一个逐像素逻辑回归,用于对以该像素为中心的m×m滑动窗口分类为实例/非实例。因此,分支的输出是一个 objectness(物体存在)得分图,其中一个得分对应一个生成一个实例的滑动窗口。因此,这种方法对于不同的对象类别都是盲目的。

代码:

from tensorflow.keras.models import Modelfrom tensorflow.keras.layers import Input, Conv2D, concatenate# 定义孔卷积层def atrous_conv_layer(input_layer, filters, kernel_size, dilation_rate):    return Conv2D(filters=filters, kernel_size=kernel_size,     dilation_rate=dilation_rate, padding='same', activation='relu')(input_layer)# 定义InstanceFCN模型def InstanceFCN(input_shape):    inputs = Input(shape=input_shape)        # 在这里定义类似VGG-16的完全卷积层    conv1 = Conv2D(64, (3, 3), activation='relu', padding='same')(inputs)    conv2 = Conv2D(64, (3, 3), activation='relu', padding='same')(conv1)        # 孔卷积层    atrous_conv = atrous_conv_layer(conv2, filters=128, kernel_size=(3, 3),     dilation_rate=(2, 2))    # 更多的卷积层和用于打分和实例估计的分支    # 用于打分和实例估计的输出层    score_output = Conv2D(num_classes, (1, 1), activation='softmax')(... )      # 你的打分输出    instance_output = Conv2D(num_instances, (1, 1), activation='sigmoid')(... )      # 你的实例输出    return Model(inputs=inputs, outputs=[score_output, instance_output])# 使用方法:model = InstanceFCN(input_shape=(256, 256, 3))  # 输入形状的示例model.summary()  # 查看模型摘要

全卷积实例感知语义分割 (FCIS)

全卷积实例感知语义分割 (FCIS) 是由IntanceFCN方法构建而成的。 InstanceFCN只能预测固定的m×m的维度掩码,并且无法将对象分类到不同的类别中。 FCIS通过预测不同维度的掩码以及预测不同的对象类别来解决了这些问题。

联合掩码预测和分类

给定RoI,像素级别的得分图通过上述的InstanceFCN的组装操作产生。对于ROI中的每个像素,有两个任务(因此,产生两个得分图):

  1. 检测:它是否属于对象边界框中的一个相对位置
  2. 分割:它是否位于对象实例的边界内部

基于此,出现了三种情况:

  1. 内部得分高而外部得分低:检测+,分割+
  2. 内部得分低而外部得分高:检测+,分割-
  3. 两个得分都很低:检测-,分割-

对于检测,最大操作用于区分情况1和2(检测+)与情况3(检测-)。整个ROI的检测评分是通过对所有像素的可能性进行平均池化,然后通过所有类别进行softmax操作得到的。对于分割,softmax用于区分情况1(分割+)和其余情况(分割-)。ROI的前景掩码是每个类别的逐像素分割分数的并集。

使用ResNet来完全卷积地从输入图像中提取特征。在conv4层之上添加了一个RPN来生成ROI。使用1×1卷积层生成来自conv5特征图的2k² × C+1得分图(C对象类别,一个背景类别,每个类别的两组k²得分图)。对于具有最高分类得分的类别,对RoI进行分类。为了获取前景掩码,获取与待考虑的RoI的交并比得分大于0.5的所有RoI。按照像素基础加权其分类得分,获得该类别的平均掩码,然后进行二值化。

结论

空洞卷积通过解决在不损失计算效率的情况下捕获上下文信息的挑战,改变了语义分割。这些空洞卷积的设计目的在于扩展感受野同时保持空间分辨率。它们已经成为现代架构(如DeepLab、LinkNet等)中的重要组成部分。

空洞卷积能够捕获多尺度特征并提高上下文理解的能力,使其在先进的分割模型中被广泛采用。随着研究的进展,空洞卷积与其他技术的整合有望在实现精确、高效和具有上下文丰富的语义分割方面取得进一步的进展。

要点

  • 卷积神经网络中的空洞卷积帮助我们在不失去细节的情况下,以不同的尺度观察复杂图像。
  • 它们使图像清晰并保持细节,从而更容易识别图像的每个部分。
  • 它们无缝集成到DeepLab、LinkNet等架构中,提高了在不同领域准确分割对象的效果。

常见问题

此文章中显示的媒体不归Analytics Vidhya所有,仅供作者自行决定使用。

Leave a Reply

Your email address will not be published. Required fields are marked *