CNN——VGG

1.VGG简介

        论文下载地址:https://arxiv.org/pdf/1409.1556.pdf 

        VGGNet 是由牛津大学视觉几何小组(Visual Geometry Group, VGG)提出的一种深层卷积网络结构,他们以 7.32% 的错误率赢得了 2014 年 ILSVRC 分类任务的亚军(冠军由 GoogLeNet 以 6.65% 的错误率夺得)和 25.32% 的错误率夺得定位任务(Localization)的第一名(GoogLeNet 错误率为 26.44%)。 

        VGG通过vgg块的堆积,VGG19最高让网络达到了16 个卷积层和 3 个全连接层,共计 19 层网络(池化层不带参数,一般不算一层)。这也导致参数量非常的多,模型比较臃肿(第一个全连接层占了非常大一部分)

        包括VGG11,VGG13,VGG16和VGG19,性能依次提升,最常用的是VGG16。

核心点:

  1. 全部使用3×3步长为1的小卷积核。3×3卷积核是最小的能够表示上下左右中心的尺寸。

                        

         假设输入为5×5,使用2次3×3卷积后最终得到1×1的特征图,那么这个1×1的特征图的感受野为5×5。这和直接使用一个5×5卷积核得到1×1的特征图是一样的。也就是说2次3×3卷积可以代替一次5×5卷积同时,2次3×3卷积的参数更少(2×3×3=18<5×5=25)而且会经过两次激活函数进行非线性变换,学习能力会更好同样的3次3×3卷积可以替代一次7×7的卷积

        此外步长为1可以不会丢失信息

        2.相同的vgg块堆叠

        3.深度深,且成功证明深度增加可以提高网络性能

2.VGG网络结构详解

        这里以最常用的VGG16为例子。VGG11,VGG13,VGG19都是根据上面的表使用不同的卷积个数。

vgg_block包括若干个3×3卷积(padding=1,stride=1)+激活+2×2池化(padding=0,stride=2),第一个卷积将通道数翻倍

  • 3×3卷积,padding=1,stride=1,output=(input-3+2×1)/1+1=input,特征图尺寸不变
  • 2×2池化,padding=0,stride=2,output=(input-2)/2+1=1/2input,特征图尺寸减半

1.输入层。224×224×3,RGB图

2.vgg_block1

操作填充步长输入通道数输出通道数输出特征图尺寸
3×3卷积11364224×224
Relu激活//6464224×224
3×3卷积116464224×224
Relu激活//6464224×224
2×2最大池化026464112×112

2.vgg_block2

操作填充步长输入通道数输出通道数输出特征图尺寸
3×3卷积1164128112×112
Relu激活//128128112×112
3×3卷积11128128112×112
Relu激活//128128112×112
2×2最大池化0212812856×56

3.vgg_block3

        从这个块开始卷积变成3次

操作填充步长输入通道数输出通道数输出特征图尺寸
3×3卷积1112825656×56
Relu激活//25625656×56
3×3卷积1125625656×56
Relu激活//25625656×56
3×3卷积1125625656×56
Relu激活//25625656×56
2×2最大池化0225625628×28

4.vgg_block4

操作填充步长输入通道数输出通道数输出特征图尺寸
3×3卷积1125651228×28
Relu激活//51251228×28
3×3卷积1151251228×28
Relu激活//51251228×28
3×3卷积1151251228×28
Relu激活//51251228×28
2×2最大池化0251251214×14

 4.vgg_block5

操作填充步长输入通道数输出通道数输出特征图尺寸
3×3卷积1151251214×14
Relu激活//51251214×14
3×3卷积1151251214×14
Relu激活//51251214×14
3×3卷积1151251214×14
Relu激活//51251214×14
2×2最大池化025125127×7

6.向量化

        flatten,7×7×512(25,088) ->> 1×1×25,088

7.全连接FC1

        1×1×25,088 ->>1×1×4096

8.全连接FC2

        1×1×4096 ->> 1×1×4096

9.全连接FC3(Softmax)

        1×1×4096 ->> 1×1×1000

3.VGGPytorch实现

3.1 手动实现VGG

# 定义VGG块
def vgg_block(num_convs, in_channels, out_channels):layers = []  # 初始化一个空列表用于存放层(卷积层和ReLU激活函数)for _ in range(num_convs):  # 循环创建指定数量的卷积层和ReLU激活函数layers.append(nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1))  # 添加一个卷积层layers.append(nn.ReLU(inplace=True))  # 添加一个ReLU激活函数,并在原地执行节省内存in_channels = out_channels  # 更新输入通道数为输出通道数,以便下一层使用layers.append(nn.MaxPool2d(kernel_size=2, stride=2))  # 添加一个最大池化层return nn.Sequential(*layers)  # 返回一个由这些层组成的Sequential模型# 定义VGG网络
class VGG(nn.Module):def __init__(self, cfg, num_classes=1000):super(VGG, self).__init__()self.conv_layers = self._make_layers(cfg)  # 创建VGG的卷积层部分self.fc_layers = nn.Sequential(  # 创建VGG的全连接层部分nn.Linear(512 * 7 * 7, 4096),  # 全连接层1nn.ReLU(inplace=True),  # ReLU激活函数nn.Dropout(),  # Dropout层用于防止过拟合nn.Linear(4096, 4096),  # 全连接层2nn.ReLU(inplace=True),  # ReLU激活函数nn.Dropout(),  # Dropout层用于防止过拟合nn.Linear(4096, num_classes)  # 全连接层3,输出类别数)self.flatten = nn.Flatten()def forward(self, x):x = self.conv_layers(x)  # 卷积层部分x = self.flatten(x)  # 将特征张量展平以输入全连接层x = self.fc_layers(x)  # 全连接层部分return xdef _make_layers(self, cfg):layers = []  # 初始化一个空列表用于存放VGG的层in_channels = 3  # 输入通道数为RGB图像的3通道for num_convs, out_channels in cfg:layers.append(vgg_block(num_convs, in_channels, out_channels))  # 添加VGG块in_channels = out_channels  # 更新输入通道数为输出通道数,以便下一层使用return nn.Sequential(*layers)  # 返回一个由VGG块组成的Sequential模型# 不同版本的VGG配置
cfgs = {'VGG11': [(1, 64), (1, 128), (2, 256), (2, 512), (2, 512)],  # VGG11的卷积层配置'VGG13': [(2, 64), (2, 128), (2, 256), (2, 512), (2, 512)],  # VGG13的卷积层配置'VGG16': [(2, 64), (2, 128), (3, 256), (3, 512), (3, 512)],  # VGG16的卷积层配置'VGG19': [(2, 64), (2, 128), (4, 256), (4, 512), (4, 512)]   # VGG19的卷积层配置
}# 实例化不同版本的VGG
def get_vgg(model_name, num_classes=1000):cfg = cfgs[model_name]  # 获取指定版本的VGG配置model = VGG(cfg, num_classes)  # 根据配置创建相应版本的VGG模型return model  # 返回指定版本的VGG模型# 实例化不同版本的VGG示例
# vgg11 = get_vgg('VGG11')
# vgg13 = get_vgg('VGG13')
vgg16 = get_vgg('VGG16') # 修改分类数目,vgg16 = get_vgg('VGG16',num_classes=10)
# vgg19 = get_vgg('VGG19')summary(vgg16.to(device), (3, 224, 224))

 3.2 手动实现VGG16简易版

        还有一个简单易懂的实现方式,如VGG16实现如下。但这种方式如果网络比较深代码就比较冗长了,而且一次只能实现一种模型

# 定义VGG16模型结构
class VGG16(nn.Module):def __init__(self, num_classes=1000):super(VGG16, self).__init__()# 特征层self.features = nn.Sequential(nn.Conv2d(3, 64, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(64, 64, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2, stride=2),nn.Conv2d(64, 128, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(128, 128, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2, stride=2),nn.Conv2d(128, 256, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(256, 256, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(256, 256, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2, stride=2),nn.Conv2d(256, 512, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(512, 512, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(512, 512, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2, stride=2),nn.Conv2d(512, 512, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(512, 512, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(512, 512, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2, stride=2),)self.flatten = nn.Flatten()# 分类层 self.classifier = nn.Sequential(nn.Linear(512 * 7 * 7, 4096),nn.ReLU(inplace=True),nn.Dropout(),nn.Linear(4096, 4096),nn.ReLU(inplace=True),nn.Dropout(),nn.Linear(4096, num_classes),)def forward(self, x):x = self.features(x)x = self.flatten(x)x = self.classifier(x)return x

  3.2 使用Pytorch自带的VGG

        官方文档:VGG — Torchvision 0.16 documentation (pytorch.org)。Pytorch官方实现了VGG,并且还附带有在ImageNet上预训练权重

        可以看到还有bn版本可选,即在卷积后增加使用了batch-normalization批量归一化。下面是使用的示例:

# 初始化预训练的vgg16模型
modelPre = models.vgg16(weights='DEFAULT')
summary(modelPre.to(device), (3, 224, 224))

        weights='DEFAULT'会默认使用最新最好的权重,或者直接指明weights='IMAGENET1K_V1',什么模型有什么权重可以直接去官方文档中查看就好。

        除了加入了全局平均池化层之外,其他和我们自己实现的是一样的。全局平均池化层可以支持任意输入尺寸,无论31输出什么尺寸,全部变成7×7

4.VGG在CIFAR-10简单实践 

        所需库

import torch
import torch.nn as nn
from torchsummary import summary
import torch.optim as optim
import torchvision.datasets as datasets
import torchvision.transforms as transforms
from torch.utils.data import DataLoader
from tqdm import tqdm
from torchvision import models
import matplotlib.pyplot as plt

1.修改网络结构

        CIFAR-10输入尺寸为32×32,为了适应该数据集,需要简单修改一下第一层全连接层的输入参数。根据网络结构,尺寸会减半5次,对于224×224来说会降到7,则会降低到1。

        将nn.Linear(512 * 7 * 7, 4096)修改为nn.Linear(512 * 1 * 1, 4096)

# 定义VGG16模型结构
class VGG16(nn.Module):def __init__(self, num_classes=1000):super(VGG16, self).__init__()# 特征层self.features = nn.Sequential(nn.Conv2d(3, 64, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(64, 64, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2, stride=2),nn.Conv2d(64, 128, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(128, 128, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2, stride=2),nn.Conv2d(128, 256, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(256, 256, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(256, 256, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2, stride=2),nn.Conv2d(256, 512, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(512, 512, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(512, 512, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2, stride=2),nn.Conv2d(512, 512, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(512, 512, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(512, 512, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2, stride=2),)self.flatten = nn.Flatten()# 分类层 self.classifier = nn.Sequential(#nn.Linear(512 * 7 * 7, 4096),nn.Linear(512 * 1 * 1, 4096),nn.ReLU(inplace=True),nn.Dropout(),nn.Linear(4096, 4096),nn.ReLU(inplace=True),nn.Dropout(),nn.Linear(4096, num_classes),)def forward(self, x):x = self.features(x)x = self.flatten(x)x = self.classifier(x)return x# 打印模型结构
model = VGG16(num_classes=10).to(device)
summary(model, (3, 32, 32))

2.读取数据集

# 数据预处理
transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225)),
])# 加载CIFAR-10数据集
train_dataset = datasets.CIFAR10(root='./dataset', train=True, download=True, transform=transform)
test_dataset = datasets.CIFAR10(root='./dataset', train=False, download=True, transform=transform)# 数据加载器
train_dataloader = DataLoader(train_dataset, batch_size=128, shuffle=True)
test_dataloader = DataLoader(test_dataset, batch_size=128, shuffle=False)

3.使用GPU

device = 'cuda' if torch.cuda.is_available() else 'cpu'

4.模型训练

def train(model, lr, epochs, train_dataloader, device, save_path):# 将模型放入GPUmodel = model.to(device)# 使用交叉熵损失函数loss_fn = nn.CrossEntropyLoss().to(device)# SGDoptimizer = torch.optim.SGD(model.parameters(), lr=lr, weight_decay=5e-4, momentum=0.9)# 记录训练与验证数据train_losses = []train_accuracies = []# 开始迭代   for epoch in range(epochs):   # 切换训练模式model.train()  # 记录变量train_loss = 0.0correct_train = 0total_train = 0# 读取训练数据并使用 tqdm 显示进度条for i, (inputs, targets) in tqdm(enumerate(train_dataloader), total=len(train_dataloader), desc=f"Epoch {epoch+1}/{epochs}", unit='batch'):# 训练数据移入GPUinputs = inputs.to(device)targets = targets.to(device)# 模型预测outputs = model(inputs)# 计算损失loss = loss_fn(outputs, targets)# 梯度清零optimizer.zero_grad()# 反向传播loss.backward()# 使用优化器优化参数optimizer.step()# 记录损失train_loss += loss.item()# 计算训练正确个数_, predicted = torch.max(outputs, 1)total_train += targets.size(0)correct_train += (predicted == targets).sum().item()# 计算训练正确率并记录train_loss /= len(train_dataloader)train_accuracy = correct_train / total_traintrain_losses.append(train_loss)train_accuracies.append(train_accuracy)# 输出训练信息print(f"Epoch [{epoch + 1}/{epochs}] - Train Loss: {train_loss:.4f}, Train Acc: {train_accuracy:.4f}")# 绘制损失和正确率曲线plt.figure(figsize=(10, 5))plt.subplot(1, 2, 1)plt.plot(range(epochs), train_losses, label='Training Loss')plt.xlabel('Epoch')plt.ylabel('Loss')plt.legend()plt.subplot(1, 2, 2)plt.plot(range(epochs), train_accuracies, label='Accuracy')plt.xlabel('Epoch')plt.ylabel('Accuracy')plt.legend()plt.tight_layout()plt.show()torch.save(model.state_dict(), save_path)
model = VGG16(num_classes=10)
lr = 0.01 
epochs = 10
save_path = './modelWeight/VGG16_CIFAR10'
train(model,lr,epochs,train_dataloader,device,save_path)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/597232.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2024年MySQL学习指南(二),探索MySQL数据库,掌握未来数据管理趋势

文章目录 前言4. DDL- 操作数据库4.1 查询4.2 创建数据库4.3 删除数据库4.4 使用数据库 5. DDL- 操作数据表5.1 数据类型5.2 查询表5.3 创建表5.4 删除表5.5 修改表 6. 实战案例详解 前言 接上一篇文章【2024年MySQL学习指南&#xff08;一&#xff09;】 4. DDL- 操作数据库 …

2023-2024 年广东省职业院校技能大赛高职组 “软件测试”赛项竞赛规程

2023-2024 年广东省职业院校技能大赛&#xff08;高职组&#xff09; “软件测试”赛项竞赛规程 一、赛项信息 赛项名称&#xff1a;软件测试 赛项编号&#xff1a;GZ034 赛项组别&#xff1a;高职组 二、竞赛目标 软件是新一代信息技术的灵魂&#xff0c;是数字经济发展的基础…

LeetCode 每日一题 Day 32 ||递归单调栈

2487. 从链表中移除节点 给你一个链表的头节点 head 。 移除每个右侧有一个更大数值的节点。 返回修改后链表的头节点 head 。 示例 1&#xff1a; 输入&#xff1a;head [5,2,13,3,8] 输出&#xff1a;[13,8] 解释&#xff1a;需要移除的节点是 5 &#xff0c;2 和 3 。…

大数据 - Doris系列《二》- Doris安装(亲测成功版)

目录 &#x1f436;2.1 安装前准备 &#x1f959;1.设置系统最大文件打开句柄数 >启动一个程序的时候&#xff0c;打开文件的数量就是句柄数 &#x1f959;3.时钟同步 &#x1f959;4.关闭交换分区&#xff08;swap&#xff09; &#x1f436;2.2 安装FE &#x1f436…

论文悦读(7)——NVM文件系统之Trio(SOSP‘23)文件系统

TRIO&#xff08;SOSP23&#xff09; 1. 背景&#xff08;Background&#xff09;1.1 NVM Technologis1.2 File System Customization1.3 Userspace NVM File Systems 2. 观察与动机&#xff08;Observation & Motivation&#xff09;3. 设计与实现&#xff08;Design &…

JMeter 插件大全:详细介绍 Jmeter 常用插件

JMeter作为一个开源的接口性能测试工具&#xff0c;其本身的小巧和灵活性给了测试人员很大的帮助&#xff0c;但其本身作为一个开源工具&#xff0c;相比于一些商业工具&#xff08;比如 LoadRunner&#xff09;&#xff0c;在功能的全面性上就稍显不足。这篇博客&#xff0c;就…

傅里叶级数、傅里叶变换、小波变换、离散余弦变换的理解

目录 1. 傅里叶级数2.傅里叶变换 1. 傅里叶级数 功能&#xff1a;能把任意周期性函数展开成一系列正弦、余弦函数的和。 公式&#xff1a; f ( x ) a 0 2 ∑ n 1 ∞ ( a n cos ⁡ ( 2 π n x T ) b n sin ⁡ ( 2 π n x T ) ) 傅里叶系数 a n 2 T ∫ x 0 x 0 T f ( x )…

网络安全|2024年需要重点关注的10种DNS攻击类型

目前&#xff0c;针对域名系统&#xff08;DNS&#xff09;的攻击已经成为企业组织数字化发展中的一个严重问题&#xff0c;每年都有数千个网站成为此类攻击的受害者。据最近的研究数据显示&#xff0c;2023年企业组织与DNS攻击相关的损失同比增加了49%&#xff0c;这些损失不仅…

即时设计:一键查看设计稿与页面差异,让设计师的工作更便捷高效

设计稿走查 在设计工作中&#xff0c;对设计稿和实际页面进行对比是必不可少的环节。然而&#xff0c;传统的对比方式往往耗时耗力&#xff0c;无法精确测量差异。为了解决这个问题&#xff0c;我们推出了一款强大的工具&#xff0c;它可以通过图片对比&#xff0c;轻松查看设…

使用results.csv文件数据绘制mAP对比图

yolov5每次train完成&#xff08;如果没有中途退出&#xff09;都会在run目录下生成expX目录&#xff08;X代表生成结果次数 第一次训练完成生成exp0 第二次生成exp1…以此类推&#xff09;。expX目录下会保存训练生成的weights以及result.txt文件&#xff0c;其中weights是训练…

Redis第3讲——跳跃表详解

一、什么是跳跃表 跳跃表&#xff08;skiplist&#xff09;是一种随机化的数据结构&#xff0c;由William Pugh在论文《Skip lists: a probabilistic alternative to balanced trees》中提出。它通过在每个节点中维持多个指向其它节点的指针&#xff0c;从而达到快速访问节点的…

Zabbix 监控介绍

1、功能概述 通常所说的监控&#xff0c;会模糊地包含以上下个细分领域的内容&#xff1a; 应用性能监控&#xff08;Application Performance Monitoring&#xff09;业务交易监控&#xff08;Business Transaction Monitoring&#xff09;网络性能监控&#xff08;Network …

华为云CES监控与飞书通知

华为云负载均衡连接数监控与飞书通知 在云服务的日常运维中&#xff0c;持续监控资源状态是保障系统稳定性的关键步骤之一。本文通过一个实际案例展示了如何使用华为云的Go SDK获取负载均衡器的连接数&#xff0c;并通过飞书Webhook发送通知到团队群组&#xff0c;以便运维人员…

福利来袭,.NET Core开发5大案例,30w字PDF文档大放送!!!

千里之行&#xff0c;始于足下&#xff0c;若想提高软件编程能力&#xff0c;最最重要的是实践&#xff0c;所谓纸上得来终觉浅&#xff0c;绝知此事要躬行。根据相关【艾宾浩斯遗忘曲线】研究表明&#xff0c;如果不动手实践&#xff0c;记住的东西会很快忘记。 为了便于大家查…

C#设计模式之观察者模式

前言 观察者&#xff08;Observer)模式也称发布-订阅&#xff08;Publish-Subscribe&#xff09;模式&#xff0c;定义了对象间一种一对多的依赖关系&#xff0c;当一个对象的状态发生改变时&#xff0c;所有依赖于它的对象都得到通知并被自动更新。 观察者模式的图解如下所示…

小程序测试和APP测试的区别

今天看了一下关于如何测试小程序的教学视频&#xff0c;里面讨论了一个很经典的面试题&#xff1a;小程序测试和APP测试的区别&#xff0c;包括在之前的面试过程中也确实是遇到过这个问题&#xff0c;所以这次打算把它记录下来&#xff0c;也算是知识巩固了。 首先从测试的内容…

android7以上 代码安装APK

一、所需权限 <!--请求安装APK的权限--> <uses-permission android:name"android.permission.REQUEST_INSTALL_PACKAGES" /> <!--写如外部存储的权限--> <uses-permission android:name"android.permission.WRITE_EXTERNAL_STORAGE"…

【DevOps-03】Build阶段-Maven安装配置

一、简要说明 下载安装JDK8下载安装Maven二、复制准备一台虚拟机 1、VM虚拟复制克隆一台机器 2、启动刚克隆的虚拟机,修改IP地址 刚刚克隆的虚拟机 ,IP地址和原虚拟的IP地址是一样的,需要修改克隆后的虚拟机IP地址,以免IP地址冲突。 # 编辑修改IP地址 $ vi /etc/sysconfig…

内存管理的概念-第四十一天

目录 前言 内存空间的分配与回收 内存空间的扩展 地址转换 存储保护 上下限寄存器 重定位寄存器和界地址寄存器 本节思维导图 前言 操作系统作为系统资源的管理者&#xff0c;当然也需要对内存进行管理&#xff0c;要管理什么呢&#xff1f; 操作系统复杂内存空间的分…

Lazada商品详情API(lazada.item_get)进行商品的实时更新

一、引言 在数字时代&#xff0c;电商平台如Lazada成为了商品交易的重要场所。为了保持竞争力&#xff0c;实时更新商品信息变得至关重要。Lazada提供的商品详情API&#xff08;lazada.item_get&#xff09;为开发者提供了一个高效的方式来获取并更新商品数据。本文将深入探讨…