VGGNet架构解析

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

目录
相关文章
|
2天前
|
设计模式 Java API
微服务架构演变与架构设计深度解析
【11月更文挑战第14天】在当今的IT行业中,微服务架构已经成为构建大型、复杂系统的重要范式。本文将从微服务架构的背景、业务场景、功能点、底层原理、实战、设计模式等多个方面进行深度解析,并结合京东电商的案例,探讨微服务架构在实际应用中的实施与效果。
21 6
|
2天前
|
Kubernetes Cloud Native 云计算
云原生技术深度解析:重塑企业IT架构的未来####
本文深入探讨了云原生技术的核心理念、关键技术组件及其对企业IT架构转型的深远影响。通过剖析Kubernetes、微服务、容器化等核心技术,本文揭示了云原生如何提升应用的灵活性、可扩展性和可维护性,助力企业在数字化转型中保持领先地位。 ####
|
2天前
|
设计模式 Java API
微服务架构演变与架构设计深度解析
【11月更文挑战第14天】在当今的IT行业中,微服务架构已经成为构建大型、复杂系统的重要范式。本文将从微服务架构的背景、业务场景、功能点、底层原理、实战、设计模式等多个方面进行深度解析,并结合京东电商的案例,探讨微服务架构在实际应用中的实施与效果。
11 1
|
3天前
|
运维 Kubernetes Cloud Native
Kubernetes云原生架构深度解析与实践指南####
本文深入探讨了Kubernetes作为领先的云原生应用编排平台,其设计理念、核心组件及高级特性。通过剖析Kubernetes的工作原理,结合具体案例分析,为读者呈现如何在实际项目中高效部署、管理和扩展容器化应用的策略与技巧。文章还涵盖了服务发现、负载均衡、配置管理、自动化伸缩等关键议题,旨在帮助开发者和运维人员掌握利用Kubernetes构建健壮、可伸缩的云原生生态系统的能力。 ####
|
7天前
|
机器学习/深度学习 人工智能 自然语言处理
医疗行业的语音识别技术解析:AI多模态能力平台的应用与架构
AI多模态能力平台通过语音识别技术,实现实时转录医患对话,自动生成结构化数据,提高医疗效率。平台具备强大的环境降噪、语音分离及自然语言处理能力,支持与医院系统无缝集成,广泛应用于门诊记录、多学科会诊和急诊场景,显著提升工作效率和数据准确性。
|
11天前
|
消息中间件 编解码 开发者
深入解析 Flutter兼容鸿蒙next全体生态的横竖屏适配与多屏协作兼容架构
本文深入探讨了 Flutter 在屏幕适配、横竖屏切换及多屏协作方面的兼容架构。介绍了 Flutter 的响应式布局、逻辑像素、方向感知、LayoutBuilder 等工具,以及如何通过 StreamBuilder 和 Provider 实现多屏数据同步。结合实际应用场景,如移动办公和教育应用,展示了 Flutter 的强大功能和灵活性。
82 6
|
11天前
|
存储 SQL 缓存
AnalyticDB 实时数仓架构解析
AnalyticDB 是阿里云自研的 OLAP 数据库,广泛应用于行为分析、数据报表、金融风控等应用场景,可支持 100 trillion 行记录、10PB 量级的数据规模,亚秒级完成交互式分析查询。本文是对 《 AnalyticDB: Real-time OLAP Database System at Alibaba Cloud 》的学习总结。
32 1
|
29天前
|
缓存 Java 程序员
Map - LinkedHashSet&Map源码解析
Map - LinkedHashSet&Map源码解析
64 0
|
29天前
|
算法 Java 容器
Map - HashSet & HashMap 源码解析
Map - HashSet & HashMap 源码解析
51 0
|
29天前
|
存储 Java C++
Collection-PriorityQueue源码解析
Collection-PriorityQueue源码解析
58 0

推荐镜像

更多
下一篇
无影云桌面