VGG小结

提示:本文是参考李沐老师和另一个B站up主代码以及讲解对自己所学东西的整理,具体资料连接会在文章中给出。且全部实验代码是在kaggle平台上验证过滴。


前言

建议先看我推荐的资料

李沐老师参考资料地址:link.
B站up主霹雳吧啦Wz:link.
注意:本文主要是对VGG网络的梳理,且主要是对代码的梳理,是Pytorch版本。视以后情况,可能会增加tensorflow版本代码。看懂改代码需要一定MLP、CNN和Pytorch基础知识,B站有相关up主讲解比较详细,在此我推荐几个up主吧,大家自行决定决定要不要看吧。
李沐老师主页:link.
B站up主刘二大人:link.
B站up主二次元的Datawhale:link.
其中二次元的Datawhale是一个开源组织,这个开源组织还有其他资料也比较好,pandas教程,西瓜书教程(偏理论教学),其中南瓜书就是由这个开源组织编写的。我觉得可能对刚入门的小伙伴比较友好一些。
还有请大家知晓一下啦,本博客基本是对自己所学知识整理,方便以后自己复习(主要是代码整理)。而且自己也还是学生,初学深度学习(但是不是人工智能方向相关专业学生哦,只是需要用到深度学习作为一个工具使用),有很多表述可能有不当和错误,希望大家可以指出来哦!谢谢大家。


一、VGG网络详解

第一章参考博客地址
VGG网络原论文参考地址
VGG网络的创新点:通过堆叠多个小卷积核来替代大尺度卷积核,可以减少训练参数,同时能保证相同的感受野
论文中提到,可以通过堆叠两个3×3的卷积核替代5x5的卷积核,堆叠三个3×3的卷积核替代7x7的卷积核。

1.1 CNN感受野的定义

感受野的定义:在卷积神经网络中,决定某一层输出结果中一个元素所对应的输入层的区域大小,被称作感受野
以下图为例,输出层 layer3 中一个单元对应 输入层 layer2 上区域大小为2×2(池化操作),对应输入层 layer1 上大小为5×5。

在这里插入图片描述
感受野的计算公式:
F ( i ) = ( F ( i + 1 ) − 1 ) × S t r i d e + K s i z e F(i)=(F(i+1)-1)×Stride+Ksize F(i)=(F(i+1)1)×Stride+Ksize
其中
F ( i ) 为 第 i 层 感 受 野 S t r i d e 是 第 i 层 的 步 距 K s i z e 为 第 i 层 核 ( 如 卷 积 核 、 池 化 核 ) 尺 寸 F(i)为第i层感受野\\Stride是第i层的步距\\Ksize为第i层核(如卷积核、池化核)尺寸 F(i)iStrideiKsizei()
以上图为例:
F e a t u r e m a p : F ( 3 ) = 1 P o o l 1 : F ( 2 ) = ( F ( 3 ) − 1 ) × 2 + 2 = 2 C o n v 1 : F ( 1 ) = ( F ( 2 ) − 1 ) × 2 + 3 = 5 Feature\quad map:F(3) = 1\\Pool1:F(2)=(F(3)-1)×2+2=2\\Conv1:F(1)=(F(2)-1)×2+3=5 FeaturemapF(3)=1Pool1F(2)=(F(3)1)×2+2=2Conv1F(1)=(F(2)1)×2+3=5

1.2 参数对比

为了减少模型参数,VGG网络堆叠使用小卷积核来代替大卷积核。下面计算两者参数:
CNN参数个数计算公式: C N N 参 数 个 数 = 卷 积 尺 寸 核 × 输 入 特 征 矩 阵 深 度 × 输 出 特 征 矩 阵 深 度 CNN参数个数=卷积尺寸核×输入特征矩阵深度×输出特征矩阵深度 CNN=××现假设 输入特征矩阵深度 = 输出特征矩阵深度 = C
使用7×7的卷积核模型所需参数为: 7 × 7 × C × C = 49 C 2 7×7×C×C = 49C^2 7×7×C×C=49C2堆叠使用三个3×3的卷积核所需要的的参数个数为: 3 × 3 × C × C × 3 = 27 C 2 3×3×C×C×3=27C^2 3×3×C×C×3=27C2

1.3 VGG16

VGG网络有多个版本,一般常用的是VGG-16模型,其网络结构如下所示:
在这里插入图片描述
在填充padding = 1,步幅Stride = 1的情况下,经过3×3卷积的特征矩阵的尺寸是不改变的,计算公式如下:
o u t s i z e = ( i n s i z e − F s i z e + 2 P ) / S + 1 = ( i n s i z e − 3 + 2 ) / 1 + 1 = i n s i z e {out}_{size} = ({in}_{size} - F_{size} + 2P)/S + 1 = ({in}_{size} - 3 + 2)/1 + 1 = {in}_{size} outsize=(insizeFsize+2P)/S+1=(insize3+2)/1+1=insize

二、Pytorch搭建VGG网络

代码参考地址。在github上可能需要合理翻墙。
在这里插入图片描述
我们实现上述A、B、D、E的模型,代码如下。

2.1 模型建立

import torch.nn as nn
import torch

# official pretrain weights,官方预训练好的模型参数(在学迁移学习的时候使用)
model_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'
}


class VGG(nn.Module):
    def __init__(self, features, num_classes=1000, init_weights=False):
        super(VGG, self).__init__()
        # 提取特征
        self.features = features
        # 线形层用于分类
        self.classifier = nn.Sequential(
        	'''也可以加Flatten层'''
        	# nn.Flatten(),
            nn.Linear(512*7*7, 4096),
            nn.ReLU(True),
            nn.Dropout(p=0.5),
            nn.Linear(4096, 4096),
            nn.ReLU(True),
            nn.Dropout(p=0.5),
            nn.Linear(4096, num_classes)
        )
        if init_weights:
            self._initialize_weights()

    def forward(self, x):
        # N x 3 x 224 x 224
        x = self.features(x)
        # N x 512 x 7 x 7
        x = torch.flatten(x, start_dim=1)
        # N x 512*7*7
        x = self.classifier(x)
        return x

    def _initialize_weights(self):
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                # nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
                nn.init.xavier_uniform_(m.weight)
                if m.bias is not None:
                    nn.init.constant_(m.bias, 0)
            elif isinstance(m, nn.Linear):
                nn.init.xavier_uniform_(m.weight)
                # nn.init.normal_(m.weight, 0, 0.01)
                nn.init.constant_(m.bias, 0)


def make_features(cfg: list):
    layers = []
    in_channels = 3
    for v in cfg:
        if v == "M":
            layers += [nn.MaxPool2d(kernel_size=2, stride=2)]
        else:
            conv2d = nn.Conv2d(in_channels, v, kernel_size=3, padding=1)
            layers += [conv2d, nn.ReLU(True)]
            in_channels = v
    return nn.Sequential(*layers)


cfgs = {
    'vgg11': [64, 'M', 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],
    'vgg13': [64, 64, 'M', 128, 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],
    'vgg16': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'M', 512, 512, 512, 'M', 512, 512, 512, 'M'],
    'vgg19': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 256, 'M', 512, 512, 512, 512, 'M', 512, 512, 512, 512, 'M'],
}


def vgg(model_name="vgg16", **kwargs):
    assert model_name in cfgs, "Warning: model number {} not in cfgs dict!".format(model_name)
    cfg = cfgs[model_name]

    model = VGG(make_features(cfg), **kwargs)
    return model

2.2 模型定义

# 定义vgg16模型
model_name = "vgg16"
net = vgg(model_name=model_name, num_classes=5, init_weights=True)

其余包括数据处理,模型训练、预测部分代码可看AlexNet版本二处代码,都是一样的。
链接地址


  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值