首页 > 其他分享 >ENet——实时语义分割的深度神经网络架构与代码实现

ENet——实时语义分割的深度神经网络架构与代码实现

时间:2024-04-03 12:30:42浏览次数:20  
标签:ENet nn 卷积 self 语义 relu 神经网络 128 RegularBottleneck

概述

在移动设备上执行实时像素级分割任务具有重要意义。现有的基于分割的深度神经网络需要大量的浮点运算,并且通常需要较长时间才能投入使用。本文提出的ENet架构旨在减少潜在的计算负担。ENet在保持或提高分割精度的同时,相比现有的分割网络,速度提升了18倍,参数量减少了79倍。
在这里插入图片描述
论文地址:https://arxiv.org/abs/1606.02147

介绍

随着增强现实设备、智能家居设备和自动驾驶技术的兴起,将语义分割算法移植到性能较低的移动设备上变得尤为迫切。语义分割算法对图像中的每个像素进行分类标记。近期,大规模数据集的可用性以及强大的计算资源(如GPU和TPU)的出现,推动了卷积神经网络在超越传统计算机视觉算法方面取得了显著进展。尽管卷积网络在分类和识别任务上取得了良好的效果,但在进行像素级分割时,往往产生粗糙的空间结果。因此,通常需要将其他算法(如基于颜色的分割、条件随机场等)与之结合,以增强分割结果。

为了实现图像的空间分类和精细分割,已经出现了如SegNet、FCN等网络结构,这些结构通常基于VGG-16等大型多分类网络。然而,这些网络由于参数量大和推理时间长,不适用于要求图像处理速度超过10fps的移动设备或电池供电的应用设备。

本文提出的网络结构旨在实现快速推理和高准确率的分割。

相关工作

语义分割在图像理解和目标检测中扮演着关键角色,尤其在增强现实和自动驾驶中,其实时性要求极高。当前的计算机视觉应用普遍采用深度神经网络,其中场景分析较好的卷积网络采用编码-解码结构,受自编码器启发。SegNet中的编码-解码结构得到了改进,编码部分类似于VGG的卷积网络用于分类,解码部分主要用于上采样。但这些网络的参数量大,导致推理时间长。SegNet通过移除VGG16的全连接层来减少浮点运算和内存占用,但其轻量级网络仍无法实现实时分割。

其他结构采用简单的分类器后接CRF作为后处理步骤,但这些复杂的后处理操作常常无法准确标记图像中的小物体。CNN结合RNN可以提高准确率,但无法解决速度问题。RNN可作为后处理手段与其他技术结合使用。

网络结构

在这里插入图片描述

ENet网络结构参考了ResNet,描述为一个主分支和一个带有卷积核的附加分支,最后通过像素级相加进行融合。每个block包含三个卷积层:一个1x1的映射用于维度减少,一个主卷积层,一个1x1的扩张。在这些层之间穿插批量归一化(BN)层和PReLU层,定义为bottleneck模型。如果bottleneck进行下采样,则在主分支上添加最大池化层,并将第一个1x1的映射替换为2x2、步长为2的卷积,对激活值进行padding以匹配feature map尺寸。卷积核大小为3x3,类型包括普通卷积、空洞卷积和转置卷积,有时用1x5或5x1的非对称卷积替换。为进行正则化,在bottleneck2.0之前使用p=0.01,其他条件下使用p=0.1。

ENet的初始部分包含一个单独的block,第一阶段包含五个bottleneck部分。第二、三阶段结构相同,但第三阶段开始时没有下采样过程。前三个阶段为编码阶段,第四、五阶段为解码阶段。为减少内核调用和内存占用,网络未使用偏差项。在每个卷积层和pReLU层之间添加BN层。在解码网络部分,最大池化层被最大上采样层代替,padding被无偏差项的空间卷积替换。ENet在最后一个上采样过程中未使用最大池化索引,因为输入图像的通道数为3,而输出通道数为类别数。最终,使用全卷积模型作为网络的最后部分,占用部分解码网络的处理时间。
在这里插入图片描述

设计选择

Feature map尺寸:在语义分割中,对图像进行下采样存在两个缺点:一是分辨率减少导致空间位置信息损失,如边界信息;二是全像素级分割要求输出与输入尺寸相同,意味着下采样后必须进行同等程度的上采样,增加了模型大小和计算资源。为解决第一个问题,ENet采用SegNet的方式,保留最大池化过程中最大值的索引,以在解码网络中生成稀疏的上采样maps。考虑到内存需求,避免过度下采样,以免影响分割准确率。

下采样的优点:下采样后的图像进行卷积操作具有较大的感受野,有助于获取更多上下文信息,有利于不同类别的区分。研究发现使用空洞卷积效果更佳。

Early downsampling:为实现良好的分割效果和实时操作,需处理大尺寸输入图像,这非常消耗资源。ENet的前两个block大幅减小输入尺寸,同时只使用部分feature map。由于可视化信息具有高度空间冗余,可以压缩为更有效的表达形式。网络初始部分作为特征提取和预处理输入。

解码尺寸大小:SegNet具有高度对称的网络结构,而ENet是非对称的,包含较大的编码层和较小的解码网络。编码层类似于原始分类网络,处理较小数据并进行信息处理和滤波,解码网络对编码网络输出进行上采样,微调细节。

非线性操作:研究发现,去除网络初始层中的大部分ReLU层可提升分割效果,认为网络深度不足。随后,将所有ReLU替换为PReLUs,为每张feature map增加额外参数。

信息保留的维度变化:下采样是必要的,但剧烈维度衰减不利于信息流动。为解决这一问题,ENet在池化层后接卷积层以增加维度,进而增加计算资源。将池化和卷积操作并行执行,然后进行拼接。在ResNet结构中,下采样时第一个1x1映射使用步长为2的卷积,丢弃了约75%的输入信息。将卷积核增至2x2有助于信息保留。

分解卷积核:二维卷积可分解为两个一维卷积核(nxn -> nx1, 1xn)。ENet使用5x1, 1x5的非对称卷积,减小过拟合风险,增加感受野。卷积核分解还减少了参数量,加上非线性处理,使计算功能更丰富。

空洞卷积:ENet将bottleneck中的卷积层替换为空洞卷积并进行串联,增大感受野,提高分割的IOU。

正则化:现有分割数据集有限,网络训练易过拟合。ENet采用空间Dropout进行处理。

代码PyTorch实现

initial block

class InitialBlock(nn.Module):

def __init__(self,in_channels,out_channels):

super(InitialBlock, self).__init__()

self.conv = nn.Conv2d(in_channels, out_channels-in_channels, kernel_size=3, stride=2,padding=1, bias=False)

self.pool = nn.MaxPool2d(kernel_size=3,stride=2,padding=1)

self.bn = nn.BatchNorm2d(out_channels)

self.relu = nn.PReLU()

def forward(self, x):

return self.relu(self.bn(torch.cat([self.conv(x),self.pool(x)],dim=1)))

bottleneck module

class RegularBottleneck(nn.Module):

def __init__(self,in_places,places, stride=1, expansion = 4,dilation=1,is_relu=False,asymmetric=False,p=0.01):

super(RegularBottleneck, self).__init__()

mid_channels = in_places // expansion        self.bottleneck = nn.Sequential(

Conv1x1BNReLU(in_places, mid_channels, False),

AsymmetricConv(mid_channels, 1, is_relu) if asymmetric else Conv3x3BNReLU(mid_channels, mid_channels, 1,dilation, is_relu),

Conv1x1BNReLU(mid_channels, places,is_relu),

nn.Dropout2d(p=p)

)

self.relu = nn.ReLU(inplace=True) if is_relu else nn.PReLU()

def forward(self, x):

residual = x        out = self.bottleneck(x)

out += residual        out = self.relu(out)

return outclass DownBottleneck(nn.Module):

def __init__(self,in_places,places, stride=2, expansion = 4,is_relu=False,p=0.01):

super(DownBottleneck, self).__init__()

mid_channels = in_places // expansion        self.bottleneck = nn.Sequential(

Conv2x2BNReLU(in_places, mid_channels, is_relu),

Conv3x3BNReLU(mid_channels, mid_channels, 1, 1, is_relu),

Conv1x1BNReLU(mid_channels, places,is_relu),

nn.Dropout2d(p=p)

)

self.downsample = nn.MaxPool2d(3,stride=stride,padding=1,return_indices=True)

self.relu = nn.ReLU(inplace=True) if is_relu else nn.PReLU()

def forward(self, x):

out = self.bottleneck(x)

residual,indices = self.downsample(x)

n, ch, h, w = out.size()

ch_res = residual.size()[1]

padding = torch.zeros(n, ch - ch_res, h, w)

residual = torch.cat((residual, padding), 1)

out += residual        out = self.relu(out)

return out, indicesclass UpBottleneck(nn.Module):

def __init__(self,in_places,places, stride=2, expansion = 4,is_relu=True,p=0.01):

super(UpBottleneck, self).__init__()

mid_channels = in_places // expansion        self.bottleneck = nn.Sequential(

Conv1x1BNReLU(in_places,mid_channels,is_relu),

TransposeConv3x3BNReLU(mid_channels,mid_channels,stride,is_relu),

Conv1x1BNReLU(mid_channels,places,is_relu),

nn.Dropout2d(p=p)

)

self.upsample_conv = Conv1x1BN(in_places, places)

self.upsample_unpool = nn.MaxUnpool2d(kernel_size=2)

self.relu = nn.ReLU(inplace=True) if is_relu else nn.PReLU()

def forward(self, x, indices):

out = self.bottleneck(x)

residual = self.upsample_conv(x)

residual = self.upsample_unpool(residual,indices)

out += residual        out = self.relu(out)

return

architecture

class ENet(nn.Module):

def __init__(self, num_classes):

super(ENet, self).__init__()

self.initialBlock = InitialBlock(3,16)

self.stage1_1 = DownBottleneck(16, 64, 2)

self.stage1_2 = nn.Sequential(

RegularBottleneck(64, 64, 1),

RegularBottleneck(64, 64, 1),

RegularBottleneck(64, 64, 1),

RegularBottleneck(64, 64, 1),

)

self.stage2_1 = DownBottleneck(64, 128, 2)

self.stage2_2 = nn.Sequential(

RegularBottleneck(128, 128, 1),

RegularBottleneck(128, 128, 1, dilation=2),

RegularBottleneck(128, 128, 1, asymmetric=True),

RegularBottleneck(128, 128, 1, dilation=4),

RegularBottleneck(128, 128, 1),

RegularBottleneck(128, 128, 1, dilation=8),

RegularBottleneck(128, 128, 1, asymmetric=True),

RegularBottleneck(128, 128, 1, dilation=16),

)

self.stage3 = nn.Sequential(

RegularBottleneck(128, 128, 1),

RegularBottleneck(128, 128, 1, dilation=2),

RegularBottleneck(128, 128, 1, asymmetric=True),

RegularBottleneck(128, 128, 1, dilation=4),

RegularBottleneck(128, 128, 1),

RegularBottleneck(128, 128, 1, dilation=8),

RegularBottleneck(128, 128, 1, asymmetric=True),

RegularBottleneck(128, 128, 1, dilation=16),

)

self.stage4_1 = UpBottleneck(128, 64, 2, is_relu=True)

self.stage4_2 = nn.Sequential(

RegularBottleneck(64, 64, 1, is_relu=True),

RegularBottleneck(64, 64, 1, is_relu=True),

)

self.stage5_1 = UpBottleneck(64, 16, 2, is_relu=True)

self.stage5_2 = RegularBottleneck(16, 16, 1, is_relu=True)

self.final_conv = nn.ConvTranspose2d(in_channels=16, out_channels=num_classes, kernel_size=3, stride=2, padding=1,

output_padding=1, bias=False)

def forward(self, x):

x = self.initialBlock(x)

x,indices1 = self.stage1_1(x)

x = self.stage1_2(x)

x, indices2 = self.stage2_1(x)

x = self.stage2_2(x)

x = self.stage3(x)

x = self.stage4_1(x, indices2)

x = self.stage4_2(x)

x = self.stage5_1(x, indices1)

x = self.stage5_2(x)

out = self.final_conv(x)

return

标签:ENet,nn,卷积,self,语义,relu,神经网络,128,RegularBottleneck
From: https://blog.csdn.net/matt45m/article/details/137223054

相关文章

  • 深度学习-卷积神经网络--MT CNN-人脸检测-64
    目录1.MTCNN-的原理2.损失函数4.升华Paper地址:https://kpzhang93.github.io/MTCNN_face_detection_alignment/github链接:https://github.com/kpzhang93/MTCNN_face_detection_alignment1.MTCNN-的原理图像金字塔对图片进行Resize操作,将原始图像缩放成不同的尺度,生......
  • Machine Learning机器学习之文本分析的词法分析、句法分析、语义分析(详细讲解)
    目录前言词法分析:词义消歧:句法分析:语义分析:文本分析应用1、文本分类:设计过程:代码实现:完整代码: 2、情感分析:总结博主介绍:✌专注于前后端、机器学习、人工智能应用领域开发的优质创作者、秉着互联网精神开源贡献精神,答疑解惑、坚持优质作品共享。本人是掘金/腾讯......
  • 机器学习——卷积神经网络中的其他类型
    机器学习——卷积神经网络中的其他类型卷积神经网络(ConvolutionalNeuralNetworks,CNNs)是深度学习领域中最重要的技术之一,它在图像处理、语音识别、自然语言处理等领域取得了巨大成功。在CNN中,卷积层是最核心的组成部分之一,而卷积操作又有许多不同类型,本文将重点介绍其中......
  • 深度学习-卷积神经网络--Mask RCNN-62
    目录1.总体网络结构2.MaskRCNN细节3.loss4.预测参考链接:https://blog.csdn.net/qq_47233366/article/details/131326554?ops_request_misc=%25257B%252522request%25255Fid%252522%25253A%252522171196013016800213023649%252522%25252C%252522scm%252522%25253A%252522201......
  • 论文阅读:图神经网络应用于知识图谱推理的研究综述
    论文链接:图神经网络应用于知识图谱推理的研究综述一、知识推理研究进展(1)知识图谱以节点和边的图结构存储数据,GNN可以有效整合知识图谱结构特征及属性特征,通过节点的领域信息聚合并更新节点,利用其强大的信息传播能力学习数据间的语义关系和潜在信息,使其可以很好地学习知识推理......
  • 基于神经网络的心脏健康监测计算机毕设+完整代码+数据
        ......
  • 神经网络与深度学习课程总结一
    线性回归定义与基本概念:线性回归用于确定变量间相互依赖的定量关系,是一种统计分析方法。以房屋面积与销售价格的关系为例,通过拟合一条直线(模型)来预测未知面积的房屋价格。数学模型:模型表示为\(y=h_{\theta}(x)=\theta^Tx+\theta_0\),其中\(x\)和\(y\)分别是输入和输......
  • 故障诊断模型 | 基于LSTM长短期记忆神经网络的滚动轴承故障诊断(Pytorch)
    概述LSTM(LongShort-TermMemory)是一种常用的循环神经网络(RNN),在时间序列数据处理任务中表现优秀,可用于滚动轴承故障诊断。滚动轴承故障通常会导致振动信号的变化,这些振动信号可以被视为时间序列数据。LSTM能够捕捉时间序列之间的依赖关系,从而对滚动轴承的故障进行诊断。......
  • 深度学习理论基础(二)神经网络基础篇
    目录一、基础知识点Ⅰ参数部分Ⅱ模型部分二、普通神经网络模型搭建1.准备数据集2.划分数据集3.搭建模型4.训练网络5.测试网络6.保存与导入模型  神经网络通过学习大量样本的输入与输出特征之间的关系,以拟合出输入与输出之间的方程,学习完成后,只给它输入特......
  • 毕业设计:基于深度学习的厨房穿戴识别系统 卷积神经网络
    目录前言一、课题背景与意义二、设计思路2.1.图像分类2.2.目标检测三、模型训练3.1实验环境3.2结果分析最后前言 ......