阅读论文(3)VGG:Very Deep Convolutional Networks for Large-Scale Image Recognition

arXiv:1409.1556

参考:

https://www.bilibili.com/video/BV1Ao4y117Pd/?spm_id_from=333.999.0.0

4.2 使用pytorch搭建VGG网络_哔哩哔哩_bilibili

VGG模型

VGG结构共有5个VGG块,主要模型为VGG-16和VGG-19,分别对应16层和19层结构(包括全连接层),所有卷积层均使用3x3的卷积核,每一个VGG块由若干相同的卷积层构成

image-20230208094232355

VGG核AlexNet的比较,相当于是将AlexNet一部分抽象出来形成VGG块,然后堆叠VGG块以增加模型层数

image-20230208093027383

复现(pytorch)

image-20230208095044656

可以看到每一个VGG块中保持图像的长宽不变,由于kernel size = 3,根据公式计算得padding = 1

同时块内卷积层之间通道数也是相同的

为了使得一个文件能够实现不同架构的VGG模型(VGG16、VGG19...),可以将不同的部分抽象出来,公用相同的部分,创建模型时声明具体的要求(参数)即可。

实现代码如下

model.py

import torch
from torch import nn


# cfgs字典记录了不同层的VGG模型
# 数字表示卷积核的个数, “M”表示池化层
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'],
}


# 不同层的VGG模型的差别是特征提取部分(卷积层),模型分类部分都相同(3层全连接)
# 因此把VGG特征提取部分抽象出来,定义make_features,根据传入配置,构建不同的特征提取部分
def make_features(cfg: list):
    layers = []
    in_channels = 3  # 初始输入通道数,RGB 3通道
    for v in cfg:
        if v == 'M':  # 最大池化层
            layers += [nn.MaxPool2d(2, 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)  # * 为解包操作


class VGG(nn.Module):
    # 通过初始化参数features,可以传入不同VGG模型的特征提取部分
    def __init__(self, features, cla_num=1000, init_weight=False):
        super(VGG, self).__init__()
        self.features = features            # VGG模型中特征提取部分
        # VGG模型分类器
        self.classifier = nn.Sequential(
            nn.Flatten(),
            nn.Linear(512 * 7 * 7, 2048),
            nn.ReLU(True),
            nn.Dropout(p=0.5),
            nn.Linear(2048, 2048),
            nn.ReLU(True),
            nn.Dropout(p=0.5),
            nn.Linear(2048, cla_num)
        )
        if init_weight:
            self._initialize_weights()

    def forward(self, x):   # 前向传播
        x = self.features(x)
        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')
                if m.bias is not None:
                    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)


def vgg(model_name='vgg16', **kwargs):
    try:
        cfg = cfgs[model_name]
    except:
        print("Warning: model number {} is not in cfgs dict!".format(model_name))
        exit(-1)
    model = VGG(make_features(cfg), **kwargs)   # *kwargs是可变参数,包括cla_num和init_weights
    return model

在需要创建网络模型时,只需要调用vgg函数并声明参数即可

model_name = "vgg16"
net = vgg(model_name, cla_num=5, init_weights=True)
posted @ 2023-02-08 10:39  dctwan  阅读(81)  评论(0编辑  收藏  举报