VGG网络模型搭建 - Pytorch

【Pytorch】


⭐ vgg


官网vgg学习传送门


vgg特点


堆叠多个3 * 3 卷积核来替代大尺度卷积核 (减少所需的参数)


并且,论文中提出 堆叠 2个 3 * 3 卷积核 可以代替 5 * 5 的卷积核, 3个 3 * 3 卷积核 可代替 7 * 7


说明


我们假设 输入输出的channel数为C :


对于 7 * 7 的卷积核来说,它所需要的参数为: 7 * 7 * C * C = 49C^2


而对于1个 3 * 3 的卷积核来说, 需要的参数为: 3 * 3 * C * C = 9C^2


3个即为: 27C^2 < 49C^2


很显然,所需的参数大大减少!


注意,这边的代替是指 他们具有相同的感受野。


补充


感受野: 卷积神经网络每层输出的特征图上的一个点映射到输入图片的一块区域。


计算:从最后一层开始向上算。 F(i) = (F(i+1) - 1) * Stride + Ksize


F(i) : 第i层的感受野 Stride : 第i层的步距 Ksize :卷积核或采样核的个数


详情可参考这里


vgg模型解析


下图是 vgg模型图



vgg16 为例


首先输入是一张 224 * 224 的RGB三通道图片, 经过 两层 3 * 3 卷积层 --> 最大池化 --> 三层 3 * 3 卷积层 --> 最大池化 --> 三层 3 * 3 卷积层 --> 最大池化 --> 3 * 3 卷积层 --> 最大池化 --> 三个全连接层 --> softmax


这里卷积层的stride = 1, padding = 1


最大池化 kernel_size = 2,stride = 2



pytorch 实现 vgg搭建


# @Time : 2021/11/15
# @Author: J1ay
# @File : vgg_model.py

import torch
from torch import nn

# vgg后面都是经过三个全连接层以及soft-max函数
# 采用前面参数区分,后面统一构建

class VGG(nn.Module):
    def __init__(self, features, class_num=1000, init_weight=False):
        super(VGG, self).__init__()
        self.features = features
        # 全连接
        self.classifier = nn.Sequential(
            nn.Dropout(),  # 减小过拟合,50%失活神经元
            nn.Linear(512 * 7 * 7, 4096),
            nn.ReLU(True),
            nn.Dropout(),
            nn.Linear(4096, 4096),
            nn.ReLU(True),
            nn.Linear(4096, class_num)
        )
        if init_weight:
            self._initialize_weights()

    def forward(self, x):
        # 前面模型搭建
        x = self.features(x)
        # 展平操作
        # N * 512 * 7 * 7
        x = torch.flatten(x, start_dim=1)
        # 全连接
        x = self.classifier(x)
        return x

    # 初始化权重函数
    def _initialize_weights(self):
        for m in self.modules:
            # 若是卷积层,则利用xavier进行初始化
            if isinstance(m, nn.Conv2d):
                nn.init.xavier_uniform_(m.weight)
                # 若使用偏置
                if m.bias is not None:
                    nn.init.constant_(m.bias, 0) # 将偏置置为0
            # 若是全连接层
            elif isinstance(m, nn.Linear):
                nn.init.xavier_uniform_(m.weight)
                nn.init.constant_(m.bias, 0)


# 以列表形式记录vgg各个模型的参数
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 make_feature(cfgs):
    layers = []
    in_channels = 3 # 最初输入cannel为3
    for v in cfgs:
        # 最大池化
        if v == 'M':
            layers += [nn.MaxPool2d(kernel_size=2, stride=2)]
        else:
            conv2d = nn.Conv2d(in_channels=in_channels, out_channels=v, kernel_size=3, padding=1)
            layers += [conv2d, nn.ReLU(inplace=True)] # 采用ReLu激活函数
            in_channels = v  # 卷积后,卷积层输入channel变成上一层的channel
    # torch.nn.Sequential(* args) 按顺序添加到容器
    return nn.Sequential(*layers)

# 实例化vgg
def vgg(model_name="vgg16", **kwargs):
    try:
        cfg = cfgs[model_name]
    except:
        print("Warning: Model {} not in cfs dict!".format(model_name))
        exit(-1)

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


if __name__ == '__main__':
    # 默认是vgg16,可修改model名字
    vgg_model = vgg(model_name="vgg13")
    print(vgg_model)
posted @ 2021-11-16 22:18  J1ay  阅读(523)  评论(0编辑  收藏  举报