VGG16

article/2025/8/30 5:18:12

VGG16模型的学习以及源码分析

part one

主要学习参考

  1. pytorch 英文文档
  2. VGG16学习笔记
  3. VGG16网络原理分析与pytorch实现
  4. 【深度学习】全面理解VGG16模型
  5. VGG模型的pytorch代码实现
  6. VGG16源代码详解
  7. 【论文】 VERY DEEP CONVOLUTIONAL NETWORKS FOR LARGE-SCALE IMAGE RECOGNITION

part two

一、VGG网络

1、 VGG是由Simonyan 和Zisserman在文献《Very Deep Convolutional Networks for Large Scale Image Recognition》中提出卷积神经网络模型,其名称来源于作者所在的牛津大学视觉几何组(Visual Geometry Group)的缩写

2、 VGG6种结构配置(根据卷积核大小和卷积层数目的不同)(绿色部分为VGG16采用的结构)

在这里插入图片描述

二、VGG16

1)VGG16结构

包括:

  • 13个卷积层(Convolutional Layer),分别用conv3-XXX表示

  • 3个全连接层(Fully connected Layer),分别用FC-XXXX表示

  • 5个池化层(Pool layer),分别用maxpool表示

    注意:卷积层和全连接层具有权重系数,也被称为权重层,13+3=16(出处)

2)特点

1、卷积层:均采用相同的卷积核参数

conv3-xxxconv3代表卷积核的尺寸(kernel size)是3 ,即宽(width)和高(height)均为3 ,卷积核尺寸是3×3xxx代表卷积层通道数 \ 特征通道数

卷积核 也就是过滤器 filter

2、池化层:采用相同的池化层参数 2×2 ( kernel_size=2并且stride=2的pooling操作可以让长宽各降低一半 ,即特征图尺寸减半)

还有均值池化

3、 Small filters, Deeper networks

在这里插入图片描述

3) 块结构

1、Block1~block5 每一个块内包含若干卷积层一个池化层

2、 同一块内,卷积层的通道(channel)数相同

3、VGG的输入图像是 224x224x3 的图像张量(tensor),随着层数的增加,后一个块内的张量相比于前一个块内的张量:

  • 通道数翻倍,由64依次增加到128,再到256,直至512保持不变,不再翻倍
  • 高和宽变减半,由 224→112→56→28→14→7

在这里插入图片描述

4)权重参数

1、 这些参数包括卷积核权重全连接层权重

  • 例如,对于第一层卷积,由于输入图的通道数是3,网络必须学习大小为3x3,通道数为3的的卷积核,这样的卷积核有64个,因此总共有(3x3x3)x64 = 1728个参数

  • 计算全连接层的权重参数数目的方法为:前一层节点数×本层的节点数前一层节点数×本层的节点数。因此,全连接层的参数分别为:

    • 7×7×512×4096 = 1027,645,444
    • 1×1×4096×4096 = 16,781,321
    • 1×1×4096×1000 = 4096000
  • 整个网络存储参数,(不考虑偏置), 蓝色是计算权重参数数量的部分;红色是计算所需存储容量的部分

在这里插入图片描述

三、VGG类的整体结构

1、 类初始化函数需要提供num_classes,表示需要进行多少分类

2、 init()extract_feature 属性 负责卷积、激活和最大池化 ( net这个空list通过不断append新的操作实现特征提取 )

​ 》》 reshape 操作 , forward()前进行,forward()负责前向传播

classifier 属性 提供最后的三个全连接操作

part three

源码


import torch
import torch.nn as nn__all__ = ['VGG', 'vgg11', 'vgg11_bn', 'vgg13', 'vgg13_bn', 'vgg16', 'vgg16_bn','vgg19_bn', 'vgg19',
]from torch.hub import load_state_dict_from_urlmodel_urls = {'vgg11': 'https://download.pytorch.org/models/vgg11-bbd30ac9.pth','vgg13': 'https://download.pytorch.org/models/vgg13-c768596a.pth','vgg16': 'https://download.pytorch.org/models/vgg16-397923af.pth','vgg19': 'https://download.pytorch.org/models/vgg19-dcbb9e9d.pth','vgg11_bn': 'https://download.pytorch.org/models/vgg11_bn-6002323d.pth','vgg13_bn': 'https://download.pytorch.org/models/vgg13_bn-abd245e5.pth','vgg16_bn': 'https://download.pytorch.org/models/vgg16_bn-6c64b313.pth','vgg19_bn': 'https://download.pytorch.org/models/vgg19_bn-c79401a0.pth',
}# VGG类,输入特征层和类别个数,得到类别向量
class VGG(nn.Module):   # 定义了名为VGG的网络,继承了nn.Module的属性。def __init__(self, features, num_classes=1000, init_weights=True):super(VGG, self).__init__()   #在实现自己的某层的时候借助了nn.Module,在构造函数中要调用Module的构造函数# 等价于nn.Module.__init__(self)self.features = features                         #features:输入参数,,features对应的是模型的卷积部分self.avgpool = nn.AdaptiveAvgPool2d((7, 7))      #nn.AdaptiveAvgPool2d:平均池化函数,尺寸:7*7# 利用nn.Sequential()方法定义了一个固定的全连接网络模块结构self.classifier = nn.Sequential(                 # 定义分类器 , #Sequential:组合形成一个子网络:分类网络nn.Linear(512 * 7 * 7, 4096),                # Linear:接受固定的输入nn.ReLU(True),nn.Dropout(),nn.Linear(4096, 4096),nn.ReLU(True),nn.Dropout(),nn.Linear(4096, num_classes),)# 初始化权重if init_weights:self._initialize_weights()# 利用forward函数来调用定义好的网络def forward(self, x):             # 把输入图像通过feature计算得到特征层x = self.features(x)x = self.avgpool(x)x = torch.flatten(x, 1)      #连接全连接层和卷积层,要拉成一维向量x = self.classifier(x)return x# 权重初始化的方法def _initialize_weights(self):for m in self.modules():if isinstance(m, nn.Conv2d):      # isinstance 检查m是哪一个类型nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')if m.bias is not None:nn.init.constant_(m.bias, 0)elif isinstance(m, nn.BatchNorm2d):nn.init.constant_(m.weight, 1)nn.init.constant_(m.bias, 0)elif isinstance(m, nn.Linear):nn.init.normal_(m.weight, 0, 0.01)nn.init.constant_(m.bias, 0)'''
比较关键的一层,从cfg构建特征提取网络
'''# 根据不同的配置文件,定义不同的网络卷积层
def make_layers(cfg, batch_norm=False):layers = []in_channels = 3for v in cfg:# 如果是M,生成最大池化层if v == 'M':layers += [nn.MaxPool2d(kernel_size=2, stride=2)]# 生成卷积层else:conv2d = nn.Conv2d(in_channels, v, kernel_size=3, padding=1)# 如果是batch_norm,批次正交化,加入批次正交化,加速网络训练if batch_norm:layers += [conv2d, nn.BatchNorm2d(v), nn.ReLU(inplace=True)]else:layers += [conv2d, nn.ReLU(inplace=True)]in_channels = v# Sequential:可以生成静态的网络,也可以生成动态的网络return nn.Sequential(*layers)# cfg 用字母作为字典索引,方便获得对应的列表  vgg16对应D 详见论文
cfgs = {'A': [64, 'M', 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],'B': [64, 64, 'M', 128, 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],'D': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'M', 512, 512, 512, 'M', 512, 512, 512, 'M'],'E': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 256, 'M', 512, 512, 512, 512, 'M', 512, 512, 512, 512, 'M'],
}'''_vgg的含义 通过读取cfg构建输入参数对应的网络如果要构建vgg16,输入参数:arch = 'vgg16'cfg = 'D'batch_norm = False
'''# 对VGG再进行封装 ,,arch和cfg都是字典,指定哪种vgg结构进行后续步骤,,batch_norm 是bool类型,判断是否经过bn
def _vgg(arch, cfg, batch_norm, pretrained, progress, **kwargs): # pretrained用不用预训练模型,也是boolif pretrained:         # **kwargs 是字典参量,键值对 ,, 如果要预训练,那就不初始化权重了,而是有已知权重??kwargs['init_weights'] = Falsemodel = VGG(make_layers(cfgs[cfg], batch_norm=batch_norm), **kwargs) # 建模,创建VGG类if pretrained:# load_state_dict_from_url:加载模型参数,progress:是否显示进度条state_dict = load_state_dict_from_url(model_urls[arch], progress=progress)# 加载模型model.load_state_dict(state_dict)return model# bn 是 batch normalization  批标准化
def vgg11(pretrained=False, progress=True, **kwargs):return _vgg('vgg11', 'A', False, pretrained, progress, **kwargs)def vgg11_bn(pretrained=False, progress=True, **kwargs):return _vgg('vgg11_bn', 'A', True, pretrained, progress, **kwargs)def vgg13(pretrained=False, progress=True, **kwargs):return _vgg('vgg13', 'B', False, pretrained, progress, **kwargs)def vgg13_bn(pretrained=False, progress=True, **kwargs):return _vgg('vgg13_bn', 'B', True, pretrained, progress, **kwargs)# models.vgg16  跳转到这个函数,用_vgg 构造出vgg16
def vgg16(pretrained=False, progress=True, **kwargs):return _vgg('vgg16', 'D', False, pretrained, progress, **kwargs)def vgg16_bn(pretrained=False, progress=True, **kwargs):return _vgg('vgg16_bn', 'D', True, pretrained, progress, **kwargs)def vgg19(pretrained=False, progress=True, **kwargs):return _vgg('vgg19', 'E', False, pretrained, progress, **kwargs)def vgg19_bn(pretrained=False, progress=True, **kwargs):return _vgg('vgg19_bn', 'E', True, pretrained, progress, **kwargs)

简单模型

# 知乎:VGG16网络原理分析与pytorch实现  https://zhuanlan.zhihu.com/p/87555358import torch
import torch.nn as nnclass NEW_VGG(nn.Module):  # nn.Module作为基类 , NEW_VGG 是对其的继承def __init__(self, num_classes):super().__init__()self.num_classes = num_classes# define an empty for Conv_ReLU_MaxPoolnet = []# block 1net.append(nn.Conv2d(in_channels=3, out_channels=64, padding=1, kernel_size=3, stride=1))net.append(nn.ReLU())net.append(nn.Conv2d(in_channels=64, out_channels=64, padding=1, kernel_size=3, stride=1))net.append(nn.ReLU())net.append(nn.MaxPool2d(kernel_size=2, stride=2))# block 2net.append(nn.Conv2d(in_channels=64, out_channels=128, kernel_size=3, stride=1, padding=1))net.append(nn.ReLU())net.append(nn.Conv2d(in_channels=128, out_channels=128, kernel_size=3, stride=1, padding=1))net.append(nn.ReLU())net.append(nn.MaxPool2d(kernel_size=2, stride=2))# block 3net.append(nn.Conv2d(in_channels=128, out_channels=256, kernel_size=3, padding=1, stride=1))net.append(nn.ReLU())net.append(nn.Conv2d(in_channels=256, out_channels=256, kernel_size=3, padding=1, stride=1))net.append(nn.ReLU())net.append(nn.Conv2d(in_channels=256, out_channels=256, kernel_size=3, padding=1, stride=1))net.append(nn.ReLU())net.append(nn.MaxPool2d(kernel_size=2, stride=2))# block 4net.append(nn.Conv2d(in_channels=256, out_channels=512, kernel_size=3, padding=1, stride=1))net.append(nn.ReLU())net.append(nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, padding=1, stride=1))net.append(nn.ReLU())net.append(nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, padding=1, stride=1))net.append(nn.ReLU())net.append(nn.MaxPool2d(kernel_size=2, stride=2))# block 5net.append(nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, padding=1, stride=1))net.append(nn.ReLU())net.append(nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, padding=1, stride=1))net.append(nn.ReLU())net.append(nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, padding=1, stride=1))net.append(nn.ReLU())net.append(nn.MaxPool2d(kernel_size=2, stride=2))# add net into class propertyself.extract_feature = nn.Sequential(*net)# define an empty container for Linear operationsclassifier = []classifier.append(nn.Linear(in_features=512 * 7 * 7, out_features=4096))classifier.append(nn.ReLU())classifier.append(nn.Dropout(p=0.5))classifier.append(nn.Linear(in_features=4096, out_features=4096))classifier.append(nn.ReLU())classifier.append(nn.Dropout(p=0.5))classifier.append(nn.Linear(in_features=4096, out_features=self.num_classes))# add classifier into class propertyself.classifier = nn.Sequential(*classifier)def forward(self, x):feature = self.extract_feature(x)feature = feature.view(x.size(0), -1)classify_result = self.classifier(feature)return classify_resultif __name__ == "__main__":x = torch.rand(size=(8, 3, 224, 224))vgg = NEW_VGG(num_classes=1000)out = vgg(x)print(out.size())

http://chatgpt.dhexx.cn/article/6rFLBR3e.shtml

相关文章

VGG16 - 用于分类和检测的卷积网络

VGG16是由牛津大学的K. Simonyan和A. Zisserman在“用于大规模图像识别的非常深卷积网络”的论文中提出的卷积神经网络模型。 该模型在ImageNet中实现了92.7%的前5个测试精度,这是属于1000个类的超过1400万张图像的数据集。它是ILSVRC-2014提交的着名模型…

VGG-16网络结构详解

VGG,又叫VGG-16,顾名思义就是有16层,包括13个卷积层和3个全连接层,是由Visual Geometry Group组的Simonyan和Zisserman在文献《Very Deep Convolutional Networks for Large Scale Image Recognition》中提出卷积神经网络模型&…

经典卷积神经网络——VGG16

VGG16 前言一、VGG发展历程二、VGG网络模型三、VGG16代码详解1.VGG网络架构2.VGG16网络验证2.读取数据,进行数据增强3.训练模型,测试准确率 四、VGG缺点 前言 我们都知道Alexnet是卷积神经网络的开山之作,但是由于卷积核太大,移动…

VGG16网络模型的原理与实现

VGG 最大的特点就是通过比较彻底地采用 3x3 尺寸的卷积核来堆叠神经网络,这样也加深整个神经网络的深度。这两个重要的改变对于人们重新定义卷积神经网络模型架构也有不小的帮助,至少证明使用更小的卷积核并且增加卷积神经网络的深度,可以更有…

深度学习——VGG16模型详解

1、网络结构 VGG16模型很好的适用于分类和定位任务,其名称来自牛津大学几何组(Visual Geometry Group)的缩写。 根据卷积核的大小核卷积层数,VGG共有6种配置,分别为A、A-LRN、B、C、D、E,其中D和E两种是最…

RK3399平台开发系列讲解(PCI/PCI-E)5.54、PCIE INTx中断机制

文章目录 一、PCIe中断过程二、PCIE 控制器支持的中断三、PCIE 控制器注册中断四、PCIe设备中断号分配沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇章将介绍RK3399平台PCIE总线中断INTx相关内容。 一、PCIe中断过程 层级结构为:PCIe设备 => PCIe控制器 =&g…

RK3399—中断

中断是操作系统最常见的事件之一,无论是系统层的“软中断”还是CPU底层的“硬中断”都是编程时常用的。中断的作用之一是充分利用CPU资源,正常情况下,CPU执行用户任务,当外设触发中断产生时,CPU停止当前任务&#xff0…

基于RK3399分析Linux系统下的CPU时钟管理 - 第3篇

1. 时钟系统结构 rockchip的时钟系统代码位于drivers/clk/rockchip,目录整体结构如下: ├── rockchip │ ├── clk.c---------------时钟系统注册 │ ├── clk-cpu.c-----------CPU调频 │ ├── clk-ddr.c-----------DDR调频 │ ├──…

基于RK3399+PID的手持稳定云台的设计与实现

手持稳定云台的主要作用是将外界环境因数引起的相机姿态变化进行隔离。如因操作者运动造成的机体震动、风阻力矩等,为了确保工作中相机的视轴始终保持期望的姿态不动。云台相机要拍摄出高质量的影像最重要的就是保证相机的视轴相对目标保持稳定。因此在相机拍摄的过…

RK3399学习

RK3399学习 韦东山rk3399:http://dev.t-firefly.com/forum-460-1.html firefly官网教程:http://wiki.t-firefly.com/zh_CN/Firefly-RK3399/started.html firefly官网3399资料:http://dev.t-firefly.com/forum-263-1.html 100ask 3399-pc教…

RK3399平台开发系列讲解(内核入门篇)1.53、platform平台设备

🚀返回专栏总目录 文章目录 一、设备配置-非设备树1.1、资源1.2、平台数据1.3、声明平台设备二、设备配置 - DTS沉淀、分享、成长,让自己和他人都能有所收获!😄 📢平台设备在内核中表示为struct platform_device的实例。 有两种方法可以把有关设备所需的资源(IRQ、DMA…

RK3399 Android7.1 编译

RK3399 Android7.1 编译 文章目录 RK3399 Android7.1 编译前言设置 Linux 编译环境安装 JDK可选- 更新默认的 Java 版本 安装所需的程序包(Ubuntu 14.04) 下载 Android SDK 前言 RK官网编译 Android搭建编译环境 设置 Linux 编译环境 使用的环境Linux 16.0.4 安装 JDK 如…

基于RK3399+5G的医用视频终端设计

当前在各种先进的信息通信技术的驱动下,医疗行业已呈现出信息化、移动化、智能化的发展趋势。特别是 5G 通信技术的落地应用推动了智慧医疗行业的 蓬勃发展,涌现出大量基于 5G 技术的医疗健康应用与服务,进一步融合了 5G 、 物联网与大数据…

RK3399平台开发系列讲解(PCI/PCI-E)PCIE相关配置说明

🚀返回专栏总目录 文章目录 一、DTS 配置二、menuconfig 配置三、cmdline 配置沉淀、分享、成长,让自己和他人都能有所收获!😄 📢 本篇将介绍在使用 RK3399 平台 PCIE 时候的配置。 一、DTS 配置 ep-gpios = <&gpio3 13 GPIO_ACTIVE_HIGH>; 此项是设置 PCIe…

RK3399快速上手 | 02-rockchip rk3399 linux sdk的使用(编译内核、编译uboot)

更新时间更新内容2022-09-15增加内核编译方法2022-10-21增加uboot编译方法和sdk开发版配置链路分析一、sdk区别 瑞芯微提供了两套sdk,一套是通过官方git仓库释放,适合于项目使用,另一套是通过github释放,适合于爱好者。 本文中使用从瑞芯微官方释放的正式linux sdk 2.7版…

RK3399平台开发系列讲解(中断篇)中断控制器驱动初始化

🚀返回专栏总目录 文章目录 一、设备树源文件1.1、gic控制器节点1.2、timer节点二、中断控制器匹配表三、中断控制器初始化3.1、函数of_irq_init3.2、函数gicv3_of_init3.3、函数gic_init_bases沉淀、分享、成长,让自己和他人都能有所收获!😄 一、设备树源文件 ARM64架构…

RK3399平台开发系列讲解(内存篇)15.34、 Linux 进程内存布局

🚀返回专栏总目录 文章目录 一、抽象内存布局二、32位机器 Linux 进程内存布局三、64位机器 Linux 进程内存布局沉淀、分享、成长,让自己和他人都能有所收获!😄 📢 我们一起来看下进程内部的虚拟内存布局,或者说单一进程是如何安排自己的各种数据的。 一、抽象内存布…

RK3399平台开发系列讲解(内核调试篇)2.50、嵌入式产品启动速度优化

平台内核版本安卓版本RK3399Linux4.4Android7.1🚀返回专栏总目录 沉淀、分享、成长,让自己和他人都能有所收获!😄 📢启动速度是嵌入式产品一个重要的性能指标,更快的启动速度会让客户有更好的使用体验,在某些方面还会节省能耗,因为可以直接关机而不需要休眠。 启动速…

钉钉F1 RK3399 咸鱼80元板子使用记录

1.简单介绍 12V电源&#xff0c;建议2A&#xff0c; 默认插电不开机&#xff0c;有大佬找到金属罩下的焊盘&#xff0c;短接可上电开机。 在usb旁边的旁边有个端子接口&#xff0c;短接就可以开机&#xff0c;建议找个一样大的接口接个开关&#xff0c;到目前为止还未测试需要…

RK3399平台开发系列讲解(网络篇)7.38、网卡驱动程序数据结构

平台内核版本安卓版本RK3399Linux4.4Android7.1🚀返回专栏总目录 文章目录 一、套接字缓冲区结构:sk_buff二、网络接口结构:net_device沉淀、分享、成长,让自己和他人都能有所收获!😄 📢处理网卡设备时需要使用两种数据结构。 struct sk_buff结构在include/linux/skb…