新型深度神经网络架构:ENet模型

news2025/5/15 6:13:02

语义分割技术能够为图像中的每个像素分配一个类别标签,这对于理解图像内容和在复杂场景中找到目标对象至关重要。在自动驾驶和增强现实等应用中,实时性是一个硬性要求,因此设计能够快速运行的卷积神经网络非常关键。
尽管深度卷积神经网络(如VGG16等)在分类和识别任务上取得了巨大成功,但它们在像素级图像标注上提供的空间结果较为粗糙。通常需要将CNN与其他算法(例如基于颜色的分割或条件随机场)级联以细化结果。许多移动或电池供电的应用需要以高于每秒10帧(fps)的速率处理图像,这对算法的运行效率提出了更高的要求。然而,现有的基于深度学习的方法往往因为参数众多和推理时间长而难以满足这一需求。

为了解决这些问题,论文提出了ENet,这是一个专为低延迟操作而设计的新型深度神经网络架构。ENet在保持相似或更高准确度的同时,显著减少了计算量、参数数量,并提高了运行速度。ENet的主要目标是在资源受限的移动设备上实现高效的语义分割,同时在高端GPU上也展现出高效的性能,以满足数据中心等场景下对大规模高分辨率图像处理的需求。

不同数据集上的ENet预测(从左到右为cityscape、CamVid和SUN):
image.png

ENet(Efficient Neural Network)

模型架构

ENet网络框架是一种专为实时语义分割任务设计的深度学习模型,它采用了高效的编码器-解码器结构,包含多个阶段,每个阶段由多个瓶颈模块(bottleneck blocks)组成。

1. 初始阶段: 这个阶段使用一个单独的卷积块,包括一个3x3的卷积层,步长为2,用于快速将输入图像下采样,减少分辨率,同时增加特征图的数量。
image.png

2. 编码器:

瓶颈模块(Bottleneck Modules):ENet的编码器由多个瓶颈模块组成,每个模块包含以下子层:

  • 1x1投影卷积:用于降维,减少特征图的数量。
  • 主卷积层:可以是3x3的常规卷积、扩张卷积或5x5的不对称卷积(由5x1和1x5的卷积组成)。
  • 1x1扩展卷积:用于升维,恢复特征图的数量。
  • 批量归一化(Batch Normalization)PReLU激活函数:在所有卷积层之后使用,以加速训练并提高模型稳定性。
  • 下采样:通过最大池化层或步长为2的卷积层实现,减少特征图的空间尺寸。

3. 重复部分: 编码器中包含重复的部分,其中不包含下采样的瓶颈模块,以进一步提取特征。

4. 解码器: 解码器同样由瓶颈模块组成,但执行的是上采样操作,逐步恢复特征图的空间尺寸。

  • 上采样模块:与编码器中的下采样相对应,使用上采样卷积层逐步增加特征图的分辨率。
  • 最大池化与最大反池化(Max Unpooling):编码器中使用最大池化减少尺寸,在解码器中使用最大反池化恢复尺寸。

5. 全卷积层:
在解码器的最后,使用一个全卷积层将特征图转换成最终的语义分割图,该层的输出通道数等于类别数。

模型特点

  • 速度快:比现有模型快18倍。
  • 计算量低:需要的浮点运算次数(FLOPs)少75倍。
  • 参数少:参数数量少79倍。
  • 精度高:提供与现有模型相似或更好的精度。

模型代码

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

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

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


实验步骤

数据集:在CamVid、Cityscapes和SUN数据集上进行测试。

评估指标:使用类平均精度(class average accuracy)和交并比(intersection-over-union, IoU)作为性能评估指标。

训练过程:首先训练编码器,然后添加解码器并训练整个网络进行上采样和像素级分类。

优化算法:使用Adam优化算法,设置学习率为5e-4,L2权重衰减为2e-4,批量大小为10。

实验结果

1.性能对比:ENet在NVIDIA Jetson TX1嵌入式系统模块和NVIDIA Titan X GPU上的性能均优于现有的SegNet模型。ENet在NVIDIA TX1上的推理速度能够达到21.1fps(640x360分辨率),显示出其在实时应用中的潜力:
image.png

2.精度:在Cityscapes数据集上,ENet在类IoU、类iIoU和类别IoU上均优于SegNet。在Cityscapes数据集上,ENet在类IoU上达到了58.3%,在iIoU上达到了34.4%,优于SegNet模型。
image.png

image.png

结论

ENet模型通过其创新的设计,在保持高精度的同时显著提高了语义分割的速度,使其适用于实时应用,尤其是在计算资源受限的移动设备上。尽管主要目标是在移动设备上运行网络,但在高端gpu(如NVIDIA Titan x)上也非常高效。这可能在需要处理大量高分辨率图像的数据中心应用程序中很有用。ENet允许以更快、更有效的方式执行大规模计算,这可能会大大节省成本。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2375859.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【免杀】C2免杀技术(三)shellcode加密

前言 shellcode加密是shellcode混淆的一种手段。shellcode混淆手段有多种:加密(编码)、偏移量混淆、UUID混淆、IPv4混淆、MAC混淆等。 随着杀毒软件的不断进化,其检测方式早已超越传统的静态特征分析。现代杀软往往会在受控的虚…

WPF之集合绑定深入

文章目录 引言ObservableCollection<T>基础什么是ObservableCollectionObservableCollection的工作原理基本用法示例ObservableCollection与MVVM模式ObservableCollection的局限性 INotifyCollectionChanged接口深入接口定义与作用NotifyCollectionChangedEventArgs详解自…

(C语言)超市管理系统(测试2版)(指针)(数据结构)(清屏操作)

目录 前言&#xff1a; 源代码&#xff1a; product.h product.c fileio.h fileio.c main.c 代码解析&#xff1a; 一、程序结构概述 二、product.c 函数详解 1. 初始化商品列表 Init_products 2. 添加商品 add_product 3. 显示商品 display_products 4. 修改商品 mo…

编译openssl源码

openssl版本 1.1.1c windows 安装环境 perl 先安装perl&#xff0c;生成makefile需要 https://strawberryperl.com/releases.html nasm nasm 也是生成makefile需要 https://www.nasm.us/ 安装完perl输入一下nasm&#xff0c;看看能不能找到&#xff0c;找不到的话需要配…

OpenCV实现数字水印的相关函数和示例代码

OpenCV计算机视觉开发实践&#xff1a;基于Qt C - 商品搜索 - 京东 实现数字水印的相关函数 用OpenCV来实现数字水印功能&#xff0c;需要使用一些位操作函数&#xff0c;我们需要先了解一下这些函数。 1. bitwise_and函数 bitwise_and函数是OpenCV中的位运算函数之一&…

坐席业绩数据分析

豆包提示词&#xff1a; 使用papaparse.js&#xff0c;chart.js&#xff0c;tailwindcss和font-awesome&#xff0c;生成一个可以交互的简洁且可以运行的HTML代码&#xff0c;不要输出无关内容。 具体要求如下&#xff1a; 1、按坐席姓名输出业绩折线图。 2、系统导航区域&…

怎样将MM模块常用报表设置为ALV默认格式(MB52、MB5B、ME2M、ME1M等)

【SAP系统研究】 对SAP系统中的报表,最方便的格式就是ALV了,可排序、可导出,非常友好。 但有些常见报表却不是默认ALV界面的,譬如MB52: 是不是有点别扭?但其实是可以后台配置进行调整的。 现将一些常用报表修改为默认ALV的方法进行总结,便于大家使用。 一、MB52、MB5…

Arduino使用红外收发模块

目录 Arduino UNO连接红外发射模块&#xff1a; Arduino D1连接红外接收模块&#xff1a; 有一个Arduini UNO板子和一个Arduino D1板子&#xff0c;我想通过红外发射模块和红外接收模块让他们进行通信。 先看结果&#xff1a; Arduino UNO连接红外发射模块&#xff1a; 发射模…

机器学习 Day16 聚类算法 ,数据降维

聚类算法 1.简介 1.1 聚类概念 无监督学习&#xff1a;聚类是一种无监督学习算法&#xff0c;不需要预先标记的训练数据 相似性分组&#xff1a;根据样本之间的相似性自动将样本归到不同类别 相似度度量&#xff1a;常用欧式距离作为相似度计算方法 1.2 聚类vs分类 聚类&…

软件测试——面试八股文(入门篇)

今天给大家分享软件测试面试题入门篇&#xff0c;看看大家能答对几题 一、 请你说一说测试用例的边界 参考回答&#xff1a; 边界值分析法就是对输入或输出的边界值进行测试的一种黑盒测试方法。通常边界值分析法是作为对等价类划分法的补充&#xff0c;这种情况下&#xff…

Yolov8的详解与实战-深度学习目标检测

Yolov8的详解与实战- 文章目录 摘要 模型详解 C2F模块 Loss head部分 模型实战 训练COCO数据集 下载数据集 COCO转yolo格式数据集&#xff08;适用V4&#xff0c;V5&#xff0c;V6&#xff0c;V7&#xff0c;V8&#xff09; 配置yolov8环境 训练 测试 训练自定义数据集 Labelme…

Python(1) 做一个随机数的游戏

有关变量的&#xff0c;其实就是 可以直接打印对应变量。 并且最后倒数第二行就是可以让两个数进行交换。 Py快捷键“ALTP 就是显示上一句的代码。 —————————————————————————————— 字符串 用 双引号或者单引号 。 然后 保证成双出现即可 要是…

【Bootstrap V4系列】学习入门教程之 组件-导航条(Navbar)

Bootstrap V4系列 学习入门教程之 组件-导航条&#xff08;Navbar&#xff09; 导航条&#xff08;Navbar&#xff09;一、How it works二、Supported content 支持的内容2.1 Brand 品牌2.2 Nav 导航2.3 Forms 表格 三、Color schemes 配色方案四、Containers 容器五、Placemen…

[Java实战]Spring Security 添加验证码(二十三)

[Java实战]Spring Security 添加验证码&#xff08;二十三&#xff09; 在现代的 Web 应用中&#xff0c;验证码是防止恶意攻击&#xff08;如暴力破解、自动注册等&#xff09;的重要手段之一。Spring Security 是一个功能强大的安全框架&#xff0c;提供了用户认证、授权等功…

万文c++继承

1、继承的概念与定义 1.1继承的概念 继承&#xff1a;是c代码复用的手段&#xff0c;允许在原有的基础上扩展&#xff0c;在此之前都是函数层次的复用&#xff0c;继承是类设计层次的复用。 下面有两个类Student和Teacher都有姓名/地址/电话/年龄等成员变量。都有identity身…

Linux grep -r 查找依赖包是否存在依赖类 Class

方法一&#xff1a;通过 Linux &#xff0c;grep -r ClassPath 命令 grep -f org.apache.kafka.connect.source.SourceRecord在 jar 包所在 lib 或者 lib/plugins 目录下执行&#xff0c;grep -r&#xff0c; flink-sql-connector-sqlserver-cdc-3.3.0.jar 中此 kafka Source…

41:像素坐标与实际坐标转化

采用上面的算子 将像素坐标点转换为实际坐标 image_points_to_world_plane(CamParam, Worldpose, Row, Column, m, X, Y) 第一个参数&#xff1a;标定得到的内参--根据标定助手得到的 第二个参数&#xff1a;标定得到的外参--根据标定助手得到的 第三个参数&#xff1a;计算…

大某麦演唱会门票如何自动抢

引言 仅供学习研究&#xff0c;欢迎交流 抢票难&#xff0c;难于上青天&#xff01;无论是演唱会、话剧还是体育赛事&#xff0c;大麦网的票总是秒光。大麦网是国内知名的票务平台&#xff0c;热门演出票往往一票难求。手动抢票不仅耗时&#xff0c;还容易错过机会。作为一名…

LVS负载均衡群集和keepalive

目录 一. 集群概述 1.1 集群的定义 1.2 集群的分类 1. 高可用集群 HA 2. 高性能运输群集 HPC 3.负载均衡群集 LB 4. 分布式存储集群 二. LVS概述 2.1 LVS的定义 2.2 LVS的工作原理 2.3 LVS 的三种工作模式 2.4 LVS 三种工作模式的对比 2.5 LVS 调度算法 1. 静态…

Apache Pulsar 消息、流、存储的融合

Apache Pulsar 消息、流、存储的融合 消息队列在大层面有两种不同类型的应用&#xff0c;一种是在线系统的message queue&#xff0c;一种是流计算&#xff0c;data pipeline的streaming高throughout&#xff0c;一致性较低&#xff0c;延迟较差的过程。 存算分离 扩容和缩容快…