VGGNet架构解析

本文涉及的产品
云解析DNS,个人版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: VGGNet 是 2014 年 ImageNet Challenge 图像识别比赛的亚军。参赛团队是来自牛津 大学的研究组 VGG (Visual Geometry Group) 。VGGNet 的很多设计思想都受到 AlexNet 的影响,所以跟 AlexNet 也有一点点相似的地方。VGGNet 不仅在图像识别方向有着广泛应 用,很多目标检测,目标分割,人脸识别等方面的应用也会使用 VGGNet 作为基础模型。

@toc

参考论文:VERY DEEP CONVOLUTIONAL NETWORKS FOR LARGE-SCALE IMAGE RECOGNITION

作者:Karen Simonyan ∗ & Andrew Zisserman +

2014年ImageNet图像分类竞赛亚军、定位竞赛冠军

1、VGGNet简介

  VGGNet 是 2014 年 ImageNet Challenge 图像识别比赛的亚军。参赛团队是来自牛津 大学的研究组 VGG (Visual Geometry Group) 。VGGNet 的很多设计思想都受到 AlexNet 的影响,所以跟 AlexNet 也有一点点相似的地方。VGGNet 不仅在图像识别方向有着广泛应 用,很多目标检测,目标分割,人脸识别等方面的应用也会使用 VGGNet 作为基础模型。

  VGGNet 在 2014,2015 年左右的流行程度甚至超过了 2014 年 ImageNet Challenge 图像识别比赛的冠军 GoogleNet,是当时用得最多的深度学习模型。VGGNet 被广泛使用 也是有一定原因的,VGGNet 的网络结构比较简单,也容易搭建,并且 VGGNet 的单模型结 果与 GoogleNet 相当。ImageNet Challenge 是一个比赛,在比赛中我们经常会使用模型 融合(Ensemble Model)策略,把多个模型组合在一起,这样有可能会得到更好的结果。 2014 年,在 ImageNet Challenge 比赛中,多个 GoogleNet 融合后的结果比多个 VGGNet 融合后的结果要更好,所以 GoogleNet 得到了冠军。最早提出 VGGNet 的论文是《Very Deep Convolutional Networks for Large-Scale Image Recognition》

2、VGGNet模型结构

  VGGNet 有多个版本,如下图所示。

image-20220813194748898

   图中 ConvNet Configuration 表示网络结构;weight layers 表示网络层数;input 表示输入;conv 表示卷积;maxpool 表示最大池化;FC 表示全连接层。

  我们可以看出 VGGNet 有 6 个不同的版本,他们的主要区别是网络层数和网络结构的区 别。图中的 conv3 表示 3×3 的卷积,conv1 表示 1×1 的卷积;conv3-128 表示 3×3 的 卷积计算后生成 128 个特征图;LRN(Local Response Normalization)是局部响应归一 化,一种在 AlexNet 中使用的数据归一化计算,不过 VGGNet 的作者认为 LRN 并没有什么 用,所以在 VGGNet 中并没有使用。

  其中使用得比较多的有 B,因为它有 13 层,我们称之为 VGG13。使用得比较多的还有 D,因为它有 16 层,我们称之为 VGG16。使用得比较多的还有 E,因为它有 19 层,我们称 之为 VGG19。在 ImageNet Challenge 图像识别比赛中效果最好的是 VGG19,其次到 VGG16,最后是 VGG13。

  上面几种模型对应的参数量(单位:百万)

image-20220813194901611

  每个版本的模型网络结构不同,所以参数的数量也有所不同。参数数量最少的是 A,有 1 亿 3 千多万个参数。最多的是 E,有 1 亿 4 千多万个参数。别看网络中有很多的卷积层,其 实网络中大部分的参数都是在全连接层中。比如在 VGG16 中,卷积层的参数数量占所有参 数的 13%,而全连接层的参数数量占到了 87%。

3、VGG16架构

  由于在应用中VGG16架构用的多一点,所以这里研究并复现一下该架构。

3.1 模型结构

image-20220813195032890

img

   图中 fc 表示 fully connected,代表全连接;pool 表示 max pooling,代表最大池化; conv 表示 convolution,代表卷积;output 表示输出。

  VGG16 的所有卷积都是 3×3,步长为 1,same padding;所有池化都是 2×2,步长 为 2,same padding;输出层函数为 softmax,除了输出层以外,其他层激活函数都是 ReLU 函数。

  VGG16 受 AlexNet 的影响和启发,图片的输入为 224×224 的大小,卷积层后面也使用了 3 个全连接层,并且全连接层也是使用 4096 个神经元。

  VGG16 是一个 16 层的网络,它的结构比较简单易懂,叠加了很多个卷积池化层。2× 2,步长为 2 的池化特会使得特征图的长宽减少为原来 1/2,池化后的下一个卷积会使得特征图的数量会变成原来的 2 倍。

3.2 各block块参数说明

  VGG16 的输入是 224×224 大小的图片。

  block1 为第 1,2 层,其中包含了 2 个卷积和 1 池化,卷积后图像大小没有发生变化 224×224,池化后特征图大小变成了 112×112,特征图的数量为 64。

  block2 为第 3,4 层,其中包含了 2 个卷积和 1 池化,卷积后图像大小没有发生变化 112×112,池化后特征图大小变成了 56×56,特征图的数量为 128。

  block3 为第 5,6,7 层,其中包含了 3 个卷积和 1 池化,卷积后图像大小没有发生变化 56×56,池化后特征图大小变成了 28×28,特征图的数量为 256。

  block4 为第 8,9,10 层,其中包含了 3 个卷积和 1 池化,卷积后图像大小没有发生变 化 28×28,池化后特征图大小变成了 14×14,特征图的数量为 512。

  block5 为第 11,12,13 层,其中包含了 3 个卷积和 1 池化,卷积后图像大小没有发生 变化 14×14,池化后特征图大小变成了 7×7,特征图的数量为 512。大家可能会稍微有点 疑惑,block5 中的特征图的数量按照规律不应该会变成 1024 吗,但是这里还是 512。这里的原因我猜测是作者他们肯定也尝试过 1024,但是最后的效果估计跟 512 的效果差不多。 并且改成 1024 后会增加很多计算量和需要训练的权值,所以最后的版本中就没有使用 1024。

  第 14 层计算。把 pool5 的 512 个 7×7 的特征图数据跟 fc1 中的 4096 个神经元进行全 连接计算。

  第 15 层计算。把 fc2 的 4096 个神经元跟 fc1 中的 4096 个神经元进行全连接计算。

  第 16 层计算。把 output 的 1000(ImageNet Challenge 比赛有 1000 个分类)个神 经元跟 fc2 中的 4096 个神经元进行全连接计算。最后再经过 softmax 计算得到类别的概率 值进行输出。

   VGGNet 网络结构本身并没有太多创新的内容,它可以看成是对 AlexNet 网络的改进优 化版本。

3.3 VGG16模型复现

import numpy as np
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.utils import to_categorical
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, Conv2D, MaxPool2D, Flatten, Input
from tensorflow.keras.models import Model
from tensorflow.keras.optimizers import Adam
import matplotlib.pyplot as plt
from tensorflow.keras.callbacks import LearningRateScheduler
from plot_model import plot_model
这里我是在自己的数据集上面跑的,所以只有17个类别,原始应该是用的ImageNet数据集,有1000个类别
# 类别数
num_class = 17
# 批次大小
batch_size = 32
# 周期数
epochs = 100
# 图片大小
image_size = 224

网络搭建

本来想训练下这个模型,但是近一亿四千万的参数我机器实在是跑不动,想跑的话还是用预训练好的模型跑吧,这里主要是复现模型结构。
# VGG16网络搭建
inputs = Input(shape=(image_size,image_size,3))
# block1
x=Conv2D(filters=64,kernel_size=(3,3),strides=(1,1),padding='same',activation='relu')(inputs)
x=Conv2D(filters=64,kernel_size=(3,3),strides=(1,1),padding='same',activation='relu')(x)
x=MaxPool2D(pool_size=(2,2),strides=2,padding='same')(x)

# block2
x=Conv2D(filters=128,kernel_size=(3,3),strides=(1,1),padding='same',activation='relu')(x)
x=Conv2D(filters=128,kernel_size=(3,3),strides=(1,1),padding='same',activation='relu')(x)
x=MaxPool2D(pool_size=(2,2),strides=2,padding='same')(x)

# block3
x=Conv2D(filters=256,kernel_size=(3,3),strides=(1,1),padding='same',activation='relu')(x)
x=Conv2D(filters=256,kernel_size=(3,3),strides=(1,1),padding='same',activation='relu')(x)
x=Conv2D(filters=256,kernel_size=(3,3),strides=(1,1),padding='same',activation='relu')(x)
x=MaxPool2D(pool_size=(2,2),strides=2,padding='same')(x)

# block4
x=Conv2D(filters=512,kernel_size=(3,3),strides=(1,1),padding='same',activation='relu')(x)
x=Conv2D(filters=512,kernel_size=(3,3),strides=(1,1),padding='same',activation='relu')(x)
x=Conv2D(filters=512,kernel_size=(3,3),strides=(1,1),padding='same',activation='relu')(x)
x=MaxPool2D(pool_size=(2,2),strides=2,padding='same')(x)

# block5
x=Conv2D(filters=512,kernel_size=(3,3),strides=(1,1),padding='same',activation='relu')(x)
x=Conv2D(filters=512,kernel_size=(3,3),strides=(1,1),padding='same',activation='relu')(x)
x=Conv2D(filters=512,kernel_size=(3,3),strides=(1,1),padding='same',activation='relu')(x)
x=MaxPool2D(pool_size=(2,2),strides=2,padding='same')(x)
# 全连接
x=Flatten()(x)
x=Dense(4096,activation='relu')(x)
x=Dropout(0.5)(x)
x=Dense(4096,activation='relu')(x)
x=Dropout(0.5)(x)
out=Dense(1000,activation='softmax')(x)
model=Model(inputs=inputs,outputs=out)
model.summary()
plot_model(model,to_file='img/VGG16.png',show_shapes=True)

模型摘要如下:

Model: "model"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_1 (InputLayer)         [(None, 224, 224, 3)]     0         
_________________________________________________________________
conv2d (Conv2D)              (None, 224, 224, 64)      1792      
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 224, 224, 64)      36928     
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 112, 112, 64)      0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 112, 112, 128)     73856     
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 112, 112, 128)     147584    
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 56, 56, 128)       0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 56, 56, 256)       295168    
_________________________________________________________________
conv2d_5 (Conv2D)            (None, 56, 56, 256)       590080    
_________________________________________________________________
conv2d_6 (Conv2D)            (None, 56, 56, 256)       590080    
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 28, 28, 256)       0         
_________________________________________________________________
conv2d_7 (Conv2D)            (None, 28, 28, 512)       1180160   
_________________________________________________________________
conv2d_8 (Conv2D)            (None, 28, 28, 512)       2359808   
_________________________________________________________________
conv2d_9 (Conv2D)            (None, 28, 28, 512)       2359808   
_________________________________________________________________
max_pooling2d_3 (MaxPooling2 (None, 14, 14, 512)       0         
_________________________________________________________________
conv2d_10 (Conv2D)           (None, 14, 14, 512)       2359808   
_________________________________________________________________
conv2d_11 (Conv2D)           (None, 14, 14, 512)       2359808   
_________________________________________________________________
conv2d_12 (Conv2D)           (None, 14, 14, 512)       2359808   
_________________________________________________________________
max_pooling2d_4 (MaxPooling2 (None, 7, 7, 512)         0         
_________________________________________________________________
flatten (Flatten)            (None, 25088)             0         
_________________________________________________________________
dense (Dense)                (None, 4096)              102764544 
_________________________________________________________________
dropout (Dropout)            (None, 4096)              0         
_________________________________________________________________
dense_1 (Dense)              (None, 4096)              16781312  
_________________________________________________________________
dropout_1 (Dropout)          (None, 4096)              0         
_________________________________________________________________
dense_2 (Dense)              (None, 1000)              4097000   
=================================================================
Total params: 138,357,544
Trainable params: 138,357,544
Non-trainable params: 0

image-20220813200219310

References

Karen Simonyan, & Andrew Zisserman (2015). Very Deep Convolutional Networks for Large-Scale Image Recognition

【精读AI论文】VGG深度学习图像分类算法

目录
相关文章
|
3天前
|
存储 SQL BI
深入解析实时数仓Doris:介绍、架构剖析、应用场景与数据划分细节
深入解析实时数仓Doris:介绍、架构剖析、应用场景与数据划分细节
|
9天前
|
前端开发 JavaScript 测试技术
安卓应用开发中的架构模式解析
【6月更文挑战第21天】在软件开发领域,架构模式是设计优雅、高效、可维护应用程序的基石。本文深入探讨了安卓应用开发中常见的架构模式,包括MVC、MVP、MVVM和Clean Architecture,旨在为开发者提供一个清晰的指导,帮助他们选择最适合自己项目的架构风格。通过对比分析这些架构模式的特点、优势以及适用场景,文章揭示了如何根据项目需求和团队能力来采用恰当的架构模式,以实现代码的可维护性、可扩展性和可测试性。
25 7
|
4天前
|
存储 缓存 监控
深入解析Elasticsearch的内存架构与管理
深入解析Elasticsearch的内存架构与管理
深入解析Elasticsearch的内存架构与管理
|
11天前
|
弹性计算 负载均衡 API
微服务架构下的API网关模式解析
在现代软件工程中,微服务架构因其灵活性和可维护性而受到青睐。本文将探讨API网关模式在微服务架构中的关键角色,分析其设计原则、实现方式及面临的挑战,并结合实际案例阐述如何有效整合API网关以提升系统整体性能和安全性。
|
9天前
|
存储 弹性计算 安全
构建高效企业应用架构:阿里云产品组合实践深度解析
该方案展现了阿里云产品组合的强大能力和灵活性,不仅满足了当前业务需求,也为未来的扩展打下了坚实的基础。希望本文的分享能为读者在设计自己的IT解决方案时提供一定的参考和启发。
108 1
|
1天前
|
存储 前端开发 JavaScript
构建高性能返利App的技术架构解析
构建高性能返利App的技术架构解析
|
2天前
|
网络协议 安全 分布式数据库
技术分享:分布式数据库DNS服务器的架构思路
技术分享:分布式数据库DNS服务器的架构思路
7 0
|
1天前
|
负载均衡 Java 开发者
细解微服务架构实践:如何使用Spring Cloud进行Java微服务治理
【6月更文挑战第30天】Spring Cloud是Java微服务治理明星框架,整合Eureka(服务发现)、Ribbon(客户端负载均衡)、Hystrix(断路器)、Zuul(API网关)和Config Server(配置中心),提供完整服务治理解决方案。通过Eureka实现服务注册与发现,Ribbon进行负载均衡,Hystrix确保服务容错,Config Server集中管理配置,Zuul则作为API入口统一处理请求。理解和使用Spring Cloud是现代Java开发者的关键技能。
14 2
|
2天前
|
缓存 监控 负载均衡
探索微服务架构中的API网关模式
在现代软件开发领域,微服务架构因其灵活性和可扩展性而备受青睐。本文将深入探讨微服务架构中至关重要的组件——API网关。通过分析API网关的核心功能、设计原则以及实际应用案例,我们旨在揭示其在提高系统性能、增强安全性及简化客户端与服务间通信中的重要作用。结合最新研究和实际开发经验,本文将为读者提供关于如何有效实施API网关的深刻见解。
|
1天前
|
存储 负载均衡 云计算
微服务架构中的服务发现与注册机制
在分布式系统设计中,微服务架构因其灵活性和可伸缩性而受到青睐。本文深入探讨了微服务架构下的服务发现与注册机制,通过分析Eureka、Consul和Zookeeper等工具的原理与实践,揭示了这些机制如何优化服务间的通信和故障转移。文章结合最新研究和案例,提供了对微服务架构中关键组件的深刻见解,并讨论了其在不同场景下的应用效果。

推荐镜像

更多