针对图像的经典卷积网络结构进化史及可视化
- P176--LeNet-5【1988】
- 模型结构说明
- 模型结构代码
- 模型结构可视化
- P177--AlexNet【2012】
- 模型结构及创新性说明
- 模型结构代码
- 模型结构可视化
- P178--VGGNet【2014】
- VGG19模型结构及创新性说明
- VGG19模型结构代码
- VGG19模型结构可视化
- P179--ResNet【2015】
- 模型结构及创新性说明
- ResNet-50、101、152模型结构代码
- ResNet-50代码
- ResNet-101代码
- ResNet-152代码
- ResNet系列模型结构可视化
- P180--DenseNet【2017】
- 模型结构及创新性
- DenseNet-121、169、201模型结构代码
- DenseNet-121代码
- DenseNet-169代码
- DenseNet-201代码
- DenseNet系列模型结构可视化
运行系统:macOS Sequoia 15.0
Python编译器:PyCharm 2024.1.4 (Community Edition)
Python版本:3.12
TensorFlow版本:2.17.0
Pytorch版本:2.4.1
往期链接:
1-5 | 6-10 | 11-20 | 21-30 | 31-40 | 41-50 |
---|
51-60:函数 | 61-70:类 | 71-80:编程范式及设计模式 |
---|
81-90:Python编码规范 | 91-100:Python自带常用模块-1 |
---|
101-105:Python自带模块-2 | 106-110:Python自带模块-3 |
---|
111-115:Python常用第三方包-频繁使用 | 116-120:Python常用第三方包-深度学习 |
---|
121-125:Python常用第三方包-爬取数据 | 126-130:Python常用第三方包-为了乐趣 |
---|
131-135:Python常用第三方包-拓展工具1 | 136-140:Python常用第三方包-拓展工具2 |
---|
Python项目实战
141-145 | 146-150 | 151-155 | 156-160 | 161-165 | 166-170 | 171-175 |
---|
P176–LeNet-5【1988】
LeNet-5 是一种经典的卷积神经网络(CNN)架构,由 Yann LeCun 等人在 1998 年提出。它最初是为手写数字识别任务(如 MNIST 数据集)设计的,但其架构已成为许多后续深度学习模型的基础。
模型结构说明
LeNet-5 由以下几个主要层组成:
- 输入层:28x28 像素的灰度图像。
- 卷积层 1 (C1):使用 6 个 5x5 的卷积核,步长为 1,输出 6 个 24x24 的特征图。
- 池化层 1 (S2):使用 2x2 的平均池化,步长为 2,输出 6 个 12x12 的特征图。
- 卷积层 2 (C3):使用 16 个 5x5 的卷积核,输出 16 个 8x8 的特征图。
- 池化层 2 (S4):使用 2x2 的平均池化,步长为 2,输出 16 个 4x4 的特征图。
- 全连接层 1 (C5):将 16 个 4x4 的特征图展平为一个 400 维的向量,并与 120 个神经元全连接。
- 全连接层 2 (F6):与 84 个神经元全连接。
- 输出层:使用 Softmax 激活函数输出 10 个类别(0-9 的手写数字)。
模型结构代码
import matplotlib.pyplot as plt
from keras.utils import plot_model
from tensorflow.keras import layers, models
# 定义 LeNet-5 模型
def create_lenet5():
model = models.Sequential()
model.add(layers.Conv2D(6, (5, 5), activation='tanh', input_shape=(28, 28, 1)))
model.add(layers.AveragePooling2D(pool_size=(2, 2))) # 添加 pool_size 参数
model.add(layers.Conv2D(16, (5, 5), activation='tanh'))
model.add(layers.AveragePooling2D(pool_size=(2, 2))) # 添加 pool_size 参数
model.add(layers.Conv2D(120, (5, 5), activation='tanh'))
model.add(layers.Flatten())
model.add(layers.Dense(84, activation='tanh'))
model.add(layers.Dense(10, activation='softmax'))
return model
# 创建模型
model = create_lenet5()
# 保存模型结构
plot_model(model, to_file='lenet5_model.png', show_shapes=True, show_layer_names=True)
# 显示可视化结果
img = plt.imread('lenet5_model.png')
plt.figure(figsize=(10, 10))
plt.title('lenet5')
plt.imshow(img)
plt.axis('off')
plt.show()
模型结构可视化
P177–AlexNet【2012】
AlexNet 是一种深度卷积神经网络(CNN),由 Alex Krizhevsky、Ilya Sutskever 和 Geoffrey Hinton 在 2012 年提出。它在 ImageNet 竞赛中取得了显著的成功,推动了深度学习在计算机视觉领域的广泛应用。
模型结构及创新性说明
AlexNet 的架构如下所示:
- 输入层:224x224 像素的 RGB 图像。
- 卷积层 1 (Conv1):使用 96 个 11x11 的卷积核,步长为 4。
- 激活层 1 (ReLU):应用 ReLU 激活函数。
- 池化层 1 (Max Pooling):使用 3x3 的最大池化,步长为 2。
- 卷积层 2 (Conv2):使用 256 个 5x5 的卷积核。
- 激活层 2 (ReLU):应用 ReLU 激活函数。
- 池化层 2 (Max Pooling):使用 3x3 的最大池化,步长为 2。
- 卷积层 3 (Conv3):使用 384 个 3x3 的卷积核。
- 激活层 3 (ReLU):应用 ReLU 激活函数。
- 卷积层 4 (Conv4):使用 384 个 3x3 的卷积核。
- 激活层 4 (ReLU):应用 ReLU 激活函数。
- 卷积层 5 (Conv5):使用 256 个 3x3 的卷积核。
- 激活层 5 (ReLU):应用 ReLU 激活函数。
- 池化层 3 (Max Pooling):使用 3x3 的最大池化,步长为 2。
- 全连接层 1 (FC1):与 4096 个神经元全连接。
- 激活层 6 (ReLU):应用 ReLU 激活函数。
- Dropout 层 1:以 50% 的概率随机丢弃神经元。
- 全连接层 2 (FC2):与 4096 个神经元全连接。
- 激活层 7 (ReLU):应用 ReLU 激活函数。
- Dropout 层 2:以 50% 的概率随机丢弃神经元。
- 全连接层 3 (FC3):与 1000 个神经元全连接(对应 1000 个类别)。
- 输出层:使用 Softmax 激活函数。
创新性
AlexNet 模型的创新性体现在多个方面,以下是其关键特点:
- 深层网络结构
深度卷积网络:相比之前的浅层网络,AlexNet 采用了更深的结构,包含多个卷积层和全连接层,能够学习更复杂的特征。 - 激活函数的创新
ReLU 激活函数:引入了 ReLU(修正线性单元)作为激活函数,解决了传统激活函数(如 Sigmoid 和 Tanh)在深层网络中造成的梯度消失问题,加速了训练过程。 - 数据增强和正则化
数据增强:通过随机裁剪、翻转和颜色变换等方法扩充训练数据,增强模型的泛化能力。 - Dropout的加入
在全连接层中使用 Dropout 技术,随机丢弃一部分神经元,减少过拟合,提高模型的鲁棒性。
模型结构代码
import matplotlib.pyplot as plt
from keras.utils import plot_model
from tensorflow.keras import layers, models
# macos系统显示中文
plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']
# 定义 alexnet 模型
def create_alexnet(input_shape=(224, 224, 3), num_classes=1000):
model = models.Sequential()
# 卷积层1 激活函数ReLU 池化层1
model.add(layers.Conv2D(96, kernel_size=(11, 11), strides=(4, 4), activation='relu', input_shape=input_shape))
model.add(layers.MaxPooling2D(pool_size=(3, 3), strides=(2, 2)))
# 卷积层2 激活函数ReLU 最大池化层2
model.add(layers.Conv2D(256, kernel_size=(5, 5), activation='relu'))
model.add(layers.MaxPooling2D(pool_size=(3, 3), strides=(2, 2)))
# 卷积层3 激活函数ReLU
model.add(layers.Conv2D(384, kernel_size=(3, 3), activation='relu'))
# 卷积层4 激活函数ReLU
model.add(layers.Conv2D(384, kernel_size=(3, 3), activation='relu'))
# 卷积层5 激活函数ReLU 最大池化层5
model.add(layers.Conv2D(256, kernel_size=(3, 3), activation='relu'))
model.add(layers.MaxPooling2D(pool_size=(3, 3), strides=(2, 2)))
# 展平层,为了后面的全连接层
model.add(layers.Flatten())
# 全连接层 激活函数ReLU,Dropout概率0.5
model.add(layers.Dense(4096, activation='relu'))
model.add(layers.Dropout(0.5))
# 全连接层 Dropout概率0.5
model.add(layers.Dense(4096, activation='relu'))
model.add(layers.Dropout(0.5))
# 全连接层,激活函数Softmax
model.add(layers.Dense(num_classes, activation='softmax'))
return model
# 创建 AlexNet 模型
model = create_alexnet()
model.summary()
# 保存模型结构
plot_model(model, to_file='AlexNet_model.png', show_shapes=True, show_layer_names=True)
# 显示可视化结果
img = plt.imread('AlexNet_model.png')
plt.figure(figsize=(10, 10))
plt.title('AlexNet 结构可视化')
plt.imshow(img)
plt.axis('off')
plt.show()
模型结构可视化
P178–VGGNet【2014】
VGGNet 是由牛津大学视觉几何组(Visual Geometry Group)在 2014 年提出的卷积神经网络(CNN)架构。VGGNet 在 ImageNet 大规模视觉识别挑战赛中取得了优异的成绩,并以其简单而有效的设计理念而闻名。VGGNet 有多个变体,最常用的包括 VGG16 和 VGG19,数字表示网络中的层数。本文以VGG19为例:
VGG19模型结构及创新性说明
- 输入层:输入图像尺寸:224x224 像素,RGB 图像。
- Conv Block 1:
- Conv1-1: 3x3卷积,64个滤波器
- Conv1-2: 3x3卷积,64个滤波器
- Max Pooling: 2x2
- Conv Block 2:
- Conv2-1: 3x3卷积,128个滤波器
- Conv2-2: 3x3卷积,128个滤波器
- Max Pooling: 2x2
- Conv Block 3:
- Conv3-1: 3x3卷积,256个滤波器
- Conv3-2: 3x3卷积,256个滤波器
- Conv3-3: 3x3卷积,256个滤波器
- Max Pooling: 2x2
- Conv Block 4:
- Conv4-1: 3x3卷积,512个滤波器
- Conv4-2: 3x3卷积,512个滤波器
- Conv4-3: 3x3卷积,512个滤波器
- Max Pooling: 2x2
- Conv Block 5:
- Conv5-1: 3x3卷积,512个滤波器
- Conv5-2: 3x3卷积,512个滤波器
- Conv5-3: 3x3卷积,512个滤波器
- Max Pooling: 2x2
- 展开层
- 全连接层:
- FC1: 4096个神经元,ReLU 激活
- FC2: 4096个神经元,ReLU 激活
- FC3: 1000个神经元(对应 1000 个类别),Softmax 激活
创新性
VGGNet结构的创新性:
- 简单而深层的结构
VGGNet 使用简单的 3x3 卷积和 2x2 最大池化构建深层网络,证明了通过增加网络深度可以提高模型的性能。 - 一致的卷积核大小
所有卷积层均采用相同大小的卷积核(3x3),使网络结构更加简洁且易于理解。 - 深度网络的有效性
VGGNet 通过增加网络深度(16 或 19 层)来提高分类性能,展示了深度学习在复杂图像任务中的优势。 - 可解释性
尽管模型较深,但其结构相对简单,易于可视化和理解。
VGG19模型结构代码
import matplotlib.pyplot as plt
from keras.utils import plot_model
from tensorflow.keras import layers, models
# macos系统显示中文
plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']
def create_vgg19(input_shape=(224, 224, 3), num_classes=1000):
model = models.Sequential()
# Conv Block 1
model.add(layers.Conv2D(64, (3, 3), padding='same', activation='relu', input_shape=input_shape))
model.add(layers.Conv2D(64, (3, 3), padding='same', activation='relu'))
model.add(layers.MaxPooling2D((2, 2), strides=(2, 2)))
# Conv Block 2
model.add(layers.Conv2D(128, (3, 3), padding='same', activation='relu'))
model.add(layers.Conv2D(128, (3, 3), padding='same', activation='relu'))
model.add(layers.MaxPooling2D((2, 2), strides=(2, 2)))
# Conv Block 3
model.add(layers.Conv2D(256, (3, 3), padding='same', activation='relu'))
model.add(layers.Conv2D(256, (3, 3), padding='same', activation='relu'))
model.add(layers.Conv2D(256, (3, 3), padding='same', activation='relu'))
model.add(layers.MaxPooling2D((2, 2), strides=(2, 2)))
# Conv Block 4
model.add(layers.Conv2D(512, (3, 3), padding='same', activation='relu'))
model.add(layers.Conv2D(512, (3, 3), padding='same', activation='relu'))
model.add(layers.Conv2D(512, (3, 3), padding='same', activation='relu'))
model.add(layers.MaxPooling2D((2, 2), strides=(2, 2)))
# Conv Block 5
model.add(layers.Conv2D(512, (3, 3), padding='same', activation='relu'))
model.add(layers.Conv2D(512, (3, 3), padding='same', activation='relu'))
model.add(layers.Conv2D(512, (3, 3), padding='same', activation='relu'))
model.add(layers.MaxPooling2D((2, 2), strides=(2, 2)))
# Flattening Layer
model.add(layers.Flatten())
# Fully Connected Layers
model.add(layers.Dense(4096, activation='relu'))
model.add(layers.Dense(4096, activation='relu'))
model.add(layers.Dense(num_classes, activation='softmax'))
return model
# 创建 VGG19 模型
vgg19_model = create_vgg19()
vgg19_model.summary()
plot_model(vgg19_model, to_file='vgg19_model.png', show_shapes=True, show_layer_names=True, dpi=500)
# 显示可视化结果
img = plt.imread('vgg19_model.png')
plt.figure(figsize=(10, 10))
plt.title('VGG19 结构可视化')
plt.imshow(img)
plt.axis('off')
plt.show()
VGG19模型结构可视化
P179–ResNet【2015】
模型结构及创新性说明
ResNet(Residual Network)是由 Kaiming He 等人在 2015 年提出的一种深度卷积神经网络。其主要创新在于引入了残差学习(Residual Learning)框架,解决了深层网络训练中的梯度消失和退化问题。
模型结构
ResNet 的核心思想是通过引入跳跃连接(skip connections)来构建残差块(Residual Block)。以下是 ResNet 的基本结构:
- 输入层:
输入图像尺寸:通常为 224x224 像素的 RGB 图像。 - 初始卷积层:
使用 7x7 的卷积核,64 个滤波器,步长为 2,后跟最大池化层。 - 残差块:
由多个残差块组成,每个残差块包含两个或三个卷积层。每个残差块的输出通过跳跃连接与输入相加,形成残差学习。残差块可以分为以下几种类型:- Basic Block:适用于较小的特征图。
- Bottleneck Block:适用于较大的特征图,使用 1x1 卷积减少维度,后接 3x3 卷积和再用 1x1 卷积恢复维度。
- 全局平均池化层:
在所有残差块之后,使用全局平均池化层减小特征图的尺寸。 - 全连接层:
最后一层使用 Softmax 激活函数输出类别概率。
ResNet 的创新性
- 残差学习
引入残差块,通过跳跃连接直接将输入添加到输出,允许网络学习残差而非直接学习目标函数,缓解了深层网络训练中的梯度消失问题。 - 可以实现极深的网络结构
ResNet 允许构建非常深的网络(例如 ResNet-50、ResNet-101、ResNet-152),在 2015 年 ImageNet 竞赛中表现优异。 - 简单的构建模块
残差块的设计使得构建深层网络变得简单,极大地推动了深度学习领域的发展。 - 普适性
ResNet 的设计思想被广泛应用于其他任务和模型,如目标检测、语义分割等。
ResNet-50、101、152模型结构代码
import matplotlib.pyplot as plt
from keras.utils import plot_model
from tensorflow.keras import layers, models
# macos系统显示中文
plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']
def identity_block(x, filters, kernel_size=3):
x_skip = x
f1, f2, f3 = filters
x = layers.Conv2D(f1, (1, 1), strides=(1, 1), padding='valid')(x)
x = layers.BatchNormalization()(x)
x = layers.Activation('relu')(x)
x = layers.Conv2D(f2, kernel_size, strides=(1, 1), padding='same')(x)
x = layers.BatchNormalization()(x)
x = layers.Activation('relu')(x)
x = layers.Conv2D(f3, (1, 1), strides=(1, 1), padding='valid')(x)
x = layers.BatchNormalization()(x)
x = layers.Add()([x, x_skip])
x = layers.Activation('relu')(x)
return x
def convolutional_block(x, filters, kernel_size=3, stride=2):
x_skip = x
f1, f2, f3 = filters
x = layers.Conv2D(f1, (1, 1), strides=(stride, stride), padding='valid')(x)
x = layers.BatchNormalization()(x)
x = layers.Activation('relu')(x)
x = layers.Conv2D(f2, kernel_size, strides=(1, 1), padding='same')(x)
x = layers.BatchNormalization()(x)
x = layers.Activation('relu')(x)
x = layers.Conv2D(f3, (1, 1), strides=(1, 1), padding='valid')(x)
x = layers.BatchNormalization()(x)
x_skip = layers.Conv2D(f3, (1, 1), strides=(stride, stride), padding='valid')(x_skip)
x_skip = layers.BatchNormalization()(x_skip)
x = layers.Add()([x, x_skip])
x = layers.Activation('relu')(x)
return x
def ResNet(input_shape, num_classes, blocks):
inputs = layers.Input(shape=input_shape)
x = layers.ZeroPadding2D(padding=(3, 3))(inputs)
x = layers.Conv2D(64, (7, 7), strides=(2, 2))(x)
x = layers.BatchNormalization()(x)
x = layers.Activation('relu')(x)
x = layers.MaxPooling2D((3, 3), strides=(2, 2))(x)
x = convolutional_block(x, [64, 64, 256], kernel_size=3, stride=1)
for _ in range(blocks[0] - 1):
x = identity_block(x, [64, 64, 256], kernel_size=3)
x = convolutional_block(x, [128, 128, 512], kernel_size=3, stride=2)
for _ in range(blocks[1] - 1):
x = identity_block(x, [128, 128, 512], kernel_size=3)
x = convolutional_block(x, [256, 256, 1024], kernel_size=3, stride=2)
for _ in range(blocks[2] - 1):
x = identity_block(x, [256, 256, 1024], kernel_size=3)
x = convolutional_block(x, [512, 512, 2048], kernel_size=3, stride=2)
for _ in range(blocks[3] - 1):
x = identity_block(x, [512, 512, 2048], kernel_size=3)
x = layers.GlobalAveragePooling2D()(x)
x = layers.Dense(num_classes, activation='softmax')(x)
model = models.Model(inputs, x)
return model
ResNet-50代码
# ResNet50
resnet50 = ResNet((224, 224, 3), 1000, [3, 4, 6, 3])
resnet50.summary()
plot_model(resnet50, to_file='resnet50.pdf', show_shapes=True,
show_layer_names=True)
ResNet-101代码
# ResNet101
resnet101 = ResNet((224, 224, 3), 1000, [3, 4, 23, 3])
resnet101.summary()
plot_model(resnet101, to_file='resnet101.pdf', show_shapes=True,
show_layer_names=True)
ResNet-152代码
# ResNet152
resnet152 = ResNet((224, 224, 3), 1000, [3, 8, 36, 3])
resnet152.summary()
plot_model(resnet152, to_file='resnet152.pdf', show_shapes=True,
show_layer_names=True)
ResNet系列模型结构可视化
ResNet50、101、152模型结构PDF下载地址
P180–DenseNet【2017】
模型结构及创新性
DenseNet(Densely Connected Convolutional Networks)是由 Gao Huang 等人在 2017 年提出的一种卷积神经网络架构。DenseNet 的核心思想是通过密集连接(Dense Connectivity)来构建网络,使得每一层都与之前所有层相连。
模型结构
- 输入层: 输入图像尺寸:通常为 224x224 像素的 RGB 图像。
- 初始卷积层: 使用 7x7 的卷积核,64 个滤波器,步长为 2,后跟最大池化层。
- 密集块(Dense Block):
网络由多个密集块组成,每个密集块内部包含多个卷积层。每个卷积层的输出被直接连接到后续的所有卷积层,形成了密集连接。通过将所有前面层的特征图作为输入,DenseNet 能够有效地传递特征并减少梯度消失。 - 过渡层(Transition Layer):
每个密集块后面有一个过渡层,用于减少特征图的尺寸和通道数。过渡层通常包含 1x1 的卷积和 2x2 的平均池化。 - 全局平均池化层:
在最后一个密集块之后,使用全局平均池化层减小特征图的尺寸。 - 全连接层: 最后一层使用 Softmax 激活函数输出类别概率。
DenseNet 的创新性
密集连接:
每一层都与前面的所有层相连,这种连接方式增强了特征的传播和重用,解决了深层网络中的梯度消失问题。
参数效率:
DenseNet 通过重用特征图,显著减少了模型参数的数量,相比于传统的卷积网络,DenseNet 具有更高的参数效率。
特征重用:
通过密集连接,DenseNet 能够在不同层之间共享特征,使得网络更加高效,并且有助于学习更丰富的特征表示。
适应性强:
DenseNet 在不同的任务和数据集上表现出色,适用于图像分类、目标检测等多种计算机视觉任务。
网络深度:
DenseNet 可构建非常深的网络(如 DenseNet-121、DenseNet-169、DenseNet-201),在多个基准数据集上取得了优秀的结果。
DenseNet-121、169、201模型结构代码
import matplotlib.pyplot as plt
import tensorflow as tf
from keras.utils import plot_model
from tensorflow.keras import layers, models
# macos系统显示中文
plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']
def dense_block(x, units):
for i in range(units):
x1 = layers.BatchNormalization()(x)
x1 = layers.ReLU()(x1)
x1 = layers.Conv2D(32, (1, 1), padding='same')(x1)
x2 = layers.BatchNormalization()(x1)
x2 = layers.ReLU()(x2)
x2 = layers.Conv2D(32, (3, 3), padding='same')(x2)
x = layers.Concatenate()([x, x2])
return x
def transition_layer(x, reduction):
x = layers.BatchNormalization()(x)
x = layers.ReLU()(x)
x = layers.Conv2D(int(tf.keras.backend.int_shape(x)[-1] * reduction), (1, 1), padding='same')(x)
x = layers.AveragePooling2D((2, 2), strides=(2, 2))(x)
return x
def create_densenet(input_shape=(224, 224, 3), num_classes=1000, dense_blocks=(6, 12, 24, 16)):
inputs = layers.Input(shape=input_shape)
x = layers.Conv2D(64, (7, 7), strides=2, padding='same')(inputs)
x = layers.BatchNormalization()(x)
x = layers.ReLU()(x)
x = layers.MaxPooling2D((3, 3), strides=2)(x)
for i, block_size in enumerate(dense_blocks):
x = dense_block(x, units=block_size)
if i < len(dense_blocks) - 1:
x = transition_layer(x, reduction=0.5)
x = layers.GlobalAveragePooling2D()(x)
outputs = layers.Dense(num_classes, activation='softmax')(x)
model = models.Model(inputs, outputs)
return model
DenseNet-121代码
# 创建 DenseNet-121 模型
densenet121_model = create_densenet(dense_blocks=(6, 12, 24, 16))
densenet121_model.summary()
plot_model(densenet121_model, to_file='densenet121_model.pdf', show_shapes=True,
show_layer_names=True)
DenseNet-169代码
# 创建 DenseNet-169 模型
densenet169_model = create_densenet(dense_blocks=(6, 12, 32, 32))
densenet169_model.summary()
plot_model(densenet169_model, to_file='densenet169_model.pdf', show_shapes=True,
show_layer_names=True)
DenseNet-201代码
# 创建 DenseNet-201 模型
densenet201_model = create_densenet(dense_blocks=(6, 12, 48, 32))
densenet201_model.summary()
plot_model(densenet201_model, to_file='densenet201_model.pdf', show_shapes=True,
show_layer_names=True)
DenseNet系列模型结构可视化
DenseNet121、169、201模型PDF高清结构下载地址