【深度学习原理第9篇】DenseNet模型详解

article/2025/9/14 0:22:54

目录

    • 一、背景概述
    • 二、DenseNet
      • 2.1 DenseBlock
      • 2.2 Transition Layer
      • 2.3 DenseNet网络结构
    • 实验结果

一、背景概述

DenseNet是2017年CVPR的最佳论文,它不同于ResNet中的残差结构,也不同于GoogLetNet中的Inception网络结构。DenseNet提出了一种新的提升性能的思路,即作者通过对特征层的极致利用,使模型有了更好的性能,并且相比ResNet进一步减少了参数,提高了性能,特征层的极致利用表现在更密集的特征连接密集连接也是本篇文章的核心。让我们一起来学习它吧。
在这里插入图片描述

二、DenseNet

论文地址:https://arxiv.org/pdf/1608.06993.pdf

下图为DenseNet网络结构简单描述,我们可以看出它由多个DenseNet Block组成。
在这里插入图片描述

2.1 DenseBlock

在这里插入图片描述
我们可以看上图,上图为DenseNet的Dense Block结构,DenseNet就是由多个这样的Dense Block结构组成,它的核心思想就是后面每个层都会接受其前面所有层作为其额外的输入,可以看到最后Transition Layer处,所有颜色的线都有,也就是前面所有层都作为输入。如下面的公式,i 层的输出Xi 是前i-1层作为输入经过非线性变换得到。
DenseNet公式如下:
在这里插入图片描述

分析:图中X0,X1,X2,X3,Xi-1表示特征图,Hi表示非线性变换,非线性变换H是BN+ReLU+Conv(1×1)+Conv(3×3)的组合,[]表示将所有输出的特征层按通道组合拼接在一起,在一个卷积模块乃至整个Dense Block中,特征尺寸不变,这是为了拼接Concat时方便,1×1与3×3卷积,借鉴了以前的经典网络中减少参数的办法,算是一个小trick,现在网络基本都会用1×1和3×3来降低参数。
在这里插入图片描述
如上图,假设输入的特征层是x0,经过h1非线性变换后,得到x1和初始的x0堆叠,这是一个新的特征层,保留了x0和x1的特征。当网络程度不断加深,就可以实现前面所有层与后面层的具有密集连接。这样就实现了特征重用
代码如下:

def dense_block(x, blocks, name):for i in range(blocks):x = conv_block(x, 32, name=name + '_block' + str(i + 1))return x
def conv_block(x, growth_rate, name):bn_axis = 3 x1 = layers.BatchNormalization(axis=bn_axis,epsilon=1.001e-5,name=name + '_0_bn')(x)x1 = layers.Activation('relu', name=name + '_0_relu')(x1)x1 = layers.Conv2D(4 * growth_rate, 1,use_bias=False,name=name + '_1_conv')(x1)x1 = layers.BatchNormalization(axis=bn_axis, epsilon=1.001e-5,name=name + '_1_bn')(x1)x1 = layers.Activation('relu', name=name + '_1_relu')(x1)x1 = layers.Conv2D(growth_rate, 3,padding='same',use_bias=False,name=name + '_2_conv')(x1)x = layers.Concatenate(axis=bn_axis, name=name + '_concat')([x, x1])return x

代码中有个for循环,表示由多少个卷积模块组成。即卷积模块重复多少次。

对比ResNet
ResNet公式如下
在这里插入图片描述
在这里插入图片描述
ResNet有一个残差边,所以加了个x

2.2 Transition Layer

Transition layer由BN + Conv(1×1) +2×2 average-pooling组成。Transition Layer将不同DenseBlock之间进行连接的模块,主要功能是整合上一个DenseBlock获得的特征,缩小上一个DenseBlock的宽高,达到下采样效果,特征图的宽高减半。

:再次重申一下,作者希望各个Dense Block内的 feature map 的大小统一,这样做concatenation就直接堆叠即可,不必考虑size问题。也就是每一个Dense Block中的feature map 尺寸一样。

实现代码:

def transition_block(x, reduction, name):bn_axis = 3x = layers.BatchNormalization(axis=bn_axis, epsilon=1.001e-5,name=name + '_bn')(x)x = layers.Activation('relu', name=name + '_relu')(x)x = layers.Conv2D(int(backend.int_shape(x)[bn_axis] * reduction), 1,use_bias=False,name=name + '_conv')(x)x = layers.AveragePooling2D(2, strides=2, name=name + '_pool')(x)return x

2.3 DenseNet网络结构

有了前面的知识,我们可以分析整个DenseNet网络结构了。
在这里插入图片描述
我们来看看这个结构,首先最上面有DenseNet-121,DenseNet-169,DenseNet-201以及DenseNet-264,其中121表示有121个卷积层,我们可以简单计算一下,
1 + 2 * 6 + 1 + 2 * 12 + 1 + 2 * 24 + 1 + 2 *16 + 1 = 121

整个结构由一开始的卷积Convolution(7×7卷积核,步长为2),再接一个池化Pooling,之后就是多个DenseBlock和Transition Layer,DenseBlock进行密集连接,而Transition Layer进行整合,并下采样average pool。最后7×7average pool后,加一个全连接fully-connected,这个全连接用softmax作为激活函数,也可以视为softmax层。

实验结果

在这里插入图片描述
如图,相比ResNet,DenseNet的性能是更好的,其中k=24表示每一个DenseBlock输出的feature map都是24通道的,也是之前说的Dense Block中每个feature map的通道数都相同,这样方便Concat。DenseNet是将抽取的特征层并利用到极致,减少信息丢失,这一点它做的非常好,但是这个模型到现在也不是很流行。这是因为尽管它充分利用了特征,但是如果网络再复杂一些,可能开销就比较大了。但是这个对特征层利用的密集连接思想,意义巨大。

在这里插入图片描述


http://chatgpt.dhexx.cn/article/gun8UMPH.shtml

相关文章

DenseNet(密集连接的卷积网络)

这里写目录标题 前言1. DenseNet网络2.设计理念2.1 Resnet2.2 DenseNet2.3 密集连接的实现 3. DenseNet的实现3.1 Dense Block的实现3.2 Transition Layer的实现3.3 DenseNet网络3.4 DenseNet-121网络 4. 测试 前言 DenseNet是指Densely connected convolutional networks&…

DenseNet详解

入门小菜鸟,希望像做笔记记录自己学的东西,也希望能帮助到同样入门的人,更希望大佬们帮忙纠错啦~侵权立删。 ✨完整代码在我的github上,有需要的朋友可以康康✨ https://github.com/tt-s-t/Deep-Learning.git 目录 一、DenseNet网…

DenseNet网络结构详解及代码复现

1. DenseNet论文详解 Abstract: 如果在靠近输入和靠近输出层之间包含更短的连接,那么卷积神经网络可以很大程度上更深,更准确和高效地进行训练。根据这一结果,我们提出了DenseNet(密集卷积网络): 对于每一层&#xf…

设计模式六大原则(6)开闭原则(Open Close Principle)

开闭原则(Open Close Principle) 定义:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。 问题由来:在软件的生命周期内,因为变化、升级和维护等原因需要对软件原有代码进行修改时,可…

Linux C/C++编程: 文件操作open/close、fopen与freopen/fclose

open是linux下的底层系统调用函数,fopen与freopen c/c下的标准I/O库函数,带输入/输出缓冲。 linxu下的fopen是open的封装函数,fopen最终还是要调用底层的系统调用open。 所以在linux下如果需要对设备进行明确的控制,那最好使用底…

Linux之open()、close()函数

目录 open函数 函数介绍 头文件及函数原型 参数 close函数 函数介绍 头文件函数原型 open()、close()函数使用 open函数 函数介绍 在Linux中open()函数用来打开或创建一个文件,当打开文件失败时返回值为-1;成功则返回作为文件描述符(一个非负的…

Linux李哥私房菜——open、close和fd

open() 头文件&#xff1a;#include<fcntl.h>//在centos6.0中只要此头文件就可以#include<sys/types.h>#incldue<sys/stat.h> 功能&#xff1a;打开和创建文件&#xff08;建立一个文件描述符&#xff0c;其他的函数可以通过文件描述符对指定文件进行读取与…

详解C中的系统调用open/close/read/write

文章目录 open() and close()read() and write()实操:代码示例1 将in.txt文件中的内容写入到out.txt文件中&#xff08;一个一个字符写入&#xff09;2 将in.txt文件中的内容写入到out.txt文件中&#xff08;数组写入&#xff09; 先谈谈open/close/read/write与fopen/fclose/f…

JavaScript中window对象及open和close使用

Window对象 是一个顶级对象&#xff0c;不是任何对象的属性&#xff0c;所以可以不写window.xxx而直接使用内部的属性和方法。 实际上&#xff0c;在web前端开发时&#xff0c;所有的全局变量都自动成为window对象的属性 Window对象的属性 Screen History Location Navigat…

Python基础(十三)——文件操作(open函数、close函数)

本文以Python3以上为学习基础。 目录 1、 使用文件操作第一原则 2、open函数 2.1、文件打开模式 2.1.1、只读模式打开文件——只读&#xff08;r&#xff09; 2.1.2、读写模式打开文件——读写模式&#xff08;r&#xff09; ​ 2.1.3、写模式打开文件——写模式&#…

layer中的open与close

关于layer中的open方法与close方法 open方法open函数的定义open函数里面optionsopen函数中返回的值 close方法如何使用close方法关于layer中的一些发现 写在最后的话 open方法 open函数用来创建一个弹出层。 open函数的定义 形式为&#xff1a;layer.open(options) 例如&…

open函数详解与close函数详解

open() 头文件&#xff1a;#include<fcntl.h>//在centos6.0中只要此头文件就可以#include<sys/types.h>#incldue<sys/stat.h> 功能&#xff1a;打开和创建文件&#xff08;建立一个文件描述符&#xff0c;其他的函数可以通过文件描述符对指定文件进行读取与…

open和close函数

open函数&#xff1a;打开或创建文件 系统调用open可以用来打开普通文件、块设备文件、字符设备文件、链接文件和管道文件&#xff0c;但只能用来创建普通文件&#xff0c;创建特殊文件需要使用特定的函数。 头文件&#xff1a; #include <sys/types.h> #include <…

linux close 头文件,Linux open close read write lseek函数的使用

我们经常需要在Linux中进行文件操作,今天我就来分享下文件操作用到的一些函数 1 open 所需头文件: 函数原型:int open(const char *pathname,flags,int perms) pathname:被打开的文件名,可包含路径 flag :文件打开的方式,参数可以通过“|” 组合构成,但前3 个参数不能互…

linux的open close函数

目录 opencloseopen 参数说明代码 解析报错不用怕,我提供解决思路 前言 开始进入学linux的第一个阶段 第一阶段的 Linux的系统函数 第一节 先讲 open close 函数 open 怎么在liunx查看呢 我们利用下面的命令 linux自带的工具 man 手册 man 1 是普通shell 的命令 比如 ls ma…

简述Java序列化的几种方式

目录 JDK原生的序列化 字符串获取字节流 Protobuf Protostuff Thrift kryo hessian fst JSON字符串序列化 Jackson Gson FastJson 序列化和反序列化在网络传输过程中需要做的事情。 序列化 就是得的 字节流&#xff0c;反序列化就是得的对象。 下面梳理Java编程需要…

java序列化之writeObject 和readObject

什么是序列化和反序列化&#xff1f; 序列化&#xff1a;将对象转化为字节的过程称为序列化过程。 反序列化&#xff1a;将字节转化为对象的过程称为反序列化。 序列化主要应用于网络传输和数据存储的场景。在java中&#xff0c;只有类实现了java.io.serializable接口&#x…

java序列化总结

目录 对象序列化是什么 为什么需要序列化与反序列化 序列化及反序列化相关知识 Java 序列化中如果有些字段不想进行序列化&#xff0c;怎么办&#xff1f; Java序列化接口 java.io.Serializable 使用序列化和serialVersionUID进行类重构 Java外部化接口 java.io.Externa…

java序列化接口Serializable

Serializable接口说明 类的可序列化性通过实现(implements) java.io.Serializable可序列化接口。 没有实现这个接口的类不会将其任何状态序列化或反序列化。 可序列化类的所有子类型本身可序列化。 序列化接口没有方法或字段只用于识别可序列化的语义。 为了允许序列化不可序…

Java序列化之serialVersionUID

Java序列化之serialVersionUID 今天讲一讲Java对象中的serialVersionUID&#xff0c;先从序列化讲起。 什么是序列化 序列化&#xff0c;简单的说&#xff0c;就是将一个对象转化&#xff08;编码&#xff09;成可以传输的输出流&#xff08;字节流&#xff09;。而反序列化…