Vgg Net Pytorch实现+论文解读

论文为VERY DEEP CONVOLUTIONAL NETWORKS FOR LARGE-SCALE IMAGE RECOGNITION,主要讨论了在大规模图片识别中,卷积神经网络的深度对准确率的影响。本篇论文提出的vgg网络在2014年的ImageNet比赛中分别在定位和分类中获得了第一和第二的成绩。

改进创新点

VGGNet对2012年的AlexNet模型主要提出了两种改进思路:

  • 小卷积核(kernal size = 3x3)+小步幅(stride = 1)
  • 多尺度:使用多尺度图片来训练测试

卷积神经网络设置

架构


结构特点

  • 整体结构上包含5组卷积层,卷积层不改变输出图片的尺寸。
  • 每层包含有1-4个卷积操作,分别在论文中对应不同的VGG结构。卷积核大小为3x3,步幅为1。
  • 每组卷积层后跟1个最大池化层,池化核大小为2x2,步幅为2,因此池化层会使得图片尺寸缩小为原来一半。论文中共设计了5组池化层,因此图片的尺寸会变为原来的1/32。
  • 最后跟3层全连接层

对比试验

论文中针对网络深度、卷积核尺寸、LRN操作方面做了对比试验,设计了6个VGG结构。如下图所示。

为何使用3x3卷积核

  • 2个3x3卷积层的感受野 = 1个5x5卷积层的感受野。同理,3个3x3卷积层感受野 = 1个7x7卷积层感受野。这样加深了网络,同时由于激活函数的加入,增加了网络的非线性。
  • 参数量减少。这里作者举了一个例子,假设一个含有三层3x3卷积层堆叠的输入和输出都包含C个通道的网络,权重数量为3(32C^2)=27C^2; 而一个7x7的卷积层,需要72C2=49C2个权重参数,相对增加了81%。

为何使用1x1卷积核

  • 增加非线性,同时不影响感受野
  • 调整维度输出

训练

  • 初始化
    batch size为256,学习率初始化为0.01,用包含动量的小批量梯度下降。
    权重随机初始化,从0均值和0.01方差的正态分布中取值。偏差初始化为0。
  • 调整图片尺寸
    网络输入的图片尺寸为224x224,因此必须调整图片的尺寸。选取训练图像最小边为S,若S=224,则不需要裁剪;若S>>224,裁剪图像就会取图像的一小部分。这样选择的图片可以选取S>224的图片,作为多尺寸输入,只需要裁剪成224x224规格的图片即可。下面的测试将会分别固定尺寸测试和多尺寸测试。

测试

测试主要针对上面的6钟结构,然后加入了多尺寸输入训练以及测试。

测试的结果:

  • 加入了LRN,没有效果
  • 从11层到19层,随着层数的增大,错误率降低
  • 结构C(包含3个1x1卷积层)比网络B性能好,这意味着添加非线性层的确有用,但是使用卷积获取空间上下文信息更有用(D比C好)
  • 当深度达到19层时,错误率达到饱和
  • 加入多尺寸训练后,网络抵抗尺寸波动的性能增强

结论

本文评估了深度卷积网络(到19层)在大规模图片分类中的应用。
结果表明,深度有益于提高分类的正确率,通过在传统的卷积网络框架中使用更深的层能够在ImageNet数据集上取得优异的结果。

NOTE:

  • 每个图片或者特征图的维数看作4维:样本数 x 通道数c x 高h x 宽w
  • 卷积层看作5维:样本数 x 输出通道数cout x 输入通道数cin x 高h x 宽w
  • 全连接层看作2个维度:样本数 x (输出通道数cout * 高h * 宽w)

Pytorch实现VGGNet

import torch
import time
from torch import nn, optim
import torchvision
import sys

#定义VGG各种不同的结构和最后的全连接层结构
cfg = {
    'VGG11': [64, 'M', 128, 'M', 256,'M', 512, 'M', 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'],
    'FC':    [512*7*7, 4096, 10]
}

#将数据展开成二维数据,用在全连接层之前和卷积层之后
class FlattenLayer(torch.nn.Module):
    def __init__(self):
        super(FlattenLayer, self).__init__()
    def forward(self, x): # x shape: (batch, *, *, ...)
        return x.view(x.shape[0], -1)

class VGG(nn.Module):
    # nn.Module是一个特殊的nn模块,加载nn.Module,这是为了继承父类
    def __init__(self, vgg_name):
        super(VGG, self).__init__()
        # super 加载父类中的__init__()函数
        self.VGG_layer = self.vgg_block(cfg[vgg_name])
        self.FC_layer = self.fc_block(cfg['FC'])
    #前向传播算法
    def forward(self, x):
        out_vgg = self.VGG_layer(x)
        out = out_vgg.view(out_vgg.size(0), -1)
        # 这一步将out拉成out.size(0)的一维向量
        out = self.FC_layer(out_vgg)
        return out
    #VGG模块
    def vgg_block(self, cfg_vgg):
        layers = []
        in_channels = 1
        for out_channels in cfg_vgg:
            if out_channels == 'M':
                layers.append(nn.MaxPool2d(kernel_size=2, stride=2))
            else:
                layers.append(nn.Conv2d(in_channels, out_channels, kernel_size=3,padding=1, bias=False))
                layers.append(nn.BatchNorm2d(out_channels))
                layers.append(nn.ReLU(inplace=True))
                in_channels = out_channels
        return nn.Sequential(*layers)
    #全连接模块
    def fc_block(self, cfg_fc):
        fc_net = nn.Sequential()
        fc_features, fc_hidden_units, fc_output_units = cfg_fc[0:]
        fc_net.add_module("fc", nn.Sequential(
            FlattenLayer(),
            nn.Linear(fc_features, fc_hidden_units),
            nn.ReLU(),
            nn.Dropout(0.5),
            nn.Linear(fc_hidden_units, fc_hidden_units),
            nn.ReLU(),
            nn.Dropout(0.5),
            nn.Linear(fc_hidden_units, fc_output_units)
        ))
        return fc_net

#加载MNIST数据,返回训练数据集和测试数据集
def load_data_fashion_mnist(batch_size, resize=None, root='~/chnn/Datasets/FashionMNIST'):
    """Download the fashion mnist dataset and then load into memory."""
    trans = []
    if resize:
        trans.append(torchvision.transforms.Resize(size=resize))
    trans.append(torchvision.transforms.ToTensor())

    transform = torchvision.transforms.Compose(trans)
    mnist_train = torchvision.datasets.FashionMNIST(root=root, train=True, download=True, transform=transform)
    mnist_test = torchvision.datasets.FashionMNIST(root=root, train=False, download=True, transform=transform)
    if sys.platform.startswith('win'):
        num_workers = 0  # 0表示不用额外的进程来加速读取数据
    else:
        num_workers = 4
    train_iter = torch.utils.data.DataLoader(mnist_train, batch_size=batch_size, shuffle=True, num_workers=num_workers)
    test_iter = torch.utils.data.DataLoader(mnist_test, batch_size=batch_size, shuffle=False, num_workers=num_workers)

    return train_iter, test_iter

#测试准确率
def evaluate_accuracy(data_iter, net, device=None):
    if device is None and isinstance(net, torch.nn.Module):
        # 如果没指定device就使用net的device
        device = list(net.parameters())[0].device
    acc_sum, n = 0.0, 0
    with torch.no_grad():
        for X, y in data_iter:
            if isinstance(net, torch.nn.Module):
                net.eval() # 评估模式, 这会关闭dropout
                acc_sum += (net(X.to(device)).argmax(dim=1) == y.to(device)).float().sum().cpu().item()
                net.train() # 改回训练模式
            else: # 自定义的模型, 3.13节之后不会用到, 不考虑GPU
                if('is_training' in net.__code__.co_varnames): # 如果有is_training这个参数
                    # 将is_training设置成False
                    acc_sum += (net(X, is_training=False).argmax(dim=1) == y).float().sum().item()
                else:
                    acc_sum += (net(X).argmax(dim=1) == y).float().sum().item()
            n += y.shape[0]
    return acc_sum / n

#模型训练,定义损失函数、优化函数
def train_ch5(net, train_iter, test_iter, batch_size, optimizer, device, num_epochs):
    net = net.to(device)
    print("training on ", device)
    loss = torch.nn.CrossEntropyLoss()
    batch_count = 0
    for epoch in range(num_epochs):
        train_l_sum, train_acc_sum, n, start = 0.0, 0.0, 0, time.time()
        for X, y in train_iter:
            X = X.to(device)
            y = y.to(device)
            y_hat = net(X)
            l = loss(y_hat, y)
            optimizer.zero_grad()
            l.backward()
            optimizer.step()
            train_l_sum += l.cpu().item()
            train_acc_sum += (y_hat.argmax(dim=1) == y).sum().cpu().item()
            n += y.shape[0]
            batch_count += 1
        test_acc = evaluate_accuracy(test_iter, net)
        print('epoch %d, loss %.4f, train acc %.3f, test acc %.3f, time %.1f sec'
              % (epoch + 1, train_l_sum / batch_count, train_acc_sum / n, test_acc, time.time() - start))

def main():
    net = VGG('VGG16')
    print(net)

    #一个batch_size为64张图片,进行梯度下降更新参数
    batch_size = 64
    #使用cuda来训练
    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    #加载MNIST数据集,返回训练集和测试集
    train_iter, test_iter = load_data_fashion_mnist(batch_size, resize=224)
    lr, num_epochs = 0.001, 5
    #使用Adam优化算法替代传统的SGD,能够自适应学习率
    optimizer = torch.optim.Adam(net.parameters(), lr=lr)
    #训练--迭代更新参数
    train_ch5(net, train_iter, test_iter, batch_size, optimizer, device, num_epochs)

main()

NOTE:

程序中使用MNIST数据集,pytorch打印的网络结构为:

训练结果为:

因为使用原文结构参数量太大,造成显存爆满,于是将结构中的通道数变为1/8。训练结果中,迭代了5次后,训练集精确度提高,但测试集精度结果不是很理想。

已经将代码上传到GitHub:https://github.com/chnngege/vgg-pytorch

原文地址:https://www.cnblogs.com/chnngege/p/12110189.html

时间: 2024-07-31 02:21:30

Vgg Net Pytorch实现+论文解读的相关文章

R-CNN 论文解读及个人理解(转)

R-CNN 论文解读及个人理解(转) https://blog.csdn.net/briblue/article/details/82012575 本篇论文的题目是 <Rich feature hierarchies for accurate oject detection and semantic segmentation>,翻译过来就是针对高准确度的目标检测与语义分割的多特征层级,通俗地来讲就是一个用来做目标检测和语义分割的神经网络. 本文作者:Ross Girshick,JeffDona

CVPR2019论文解读:单眼提升2D检测到6D姿势和度量形状

CVPR2019论文解读:单眼提升2D检测到6D姿势和度量形状 ROI-10D: Monocular Lifting of 2D Detection to 6D Pose and Metric Shape 论文链接地址:https://arxiv.org/pdf/1812.02781.pdf 摘要内容: 本文提供了基于端到端单目3D目标检测和度量形状检索的深度学习方法.为了在3D中提升2D检测,定位,以及缩放,提出了一种新的loss函数.不同于各自独立的优化这些数量,3D示例允许适当的度量box

PyTorch源码解读之torchvision.models(转)

原文地址:https://blog.csdn.net/u014380165/article/details/79119664 PyTorch框架中有一个非常重要且好用的包:torchvision,该包主要由3个子包组成,分别是:torchvision.datasets.torchvision.models.torchvision.transforms.这3个子包的具体介绍可以参考官网:http://pytorch.org/docs/master/torchvision/index.html.具体

Features for Multi-Target Multi-Camera Tracking and Re-identification论文解读

解读一:Features for Multi-Target Multi-Camera Tracking and Re-identification Abstract MTMCT:从多个摄像头采集的视频中跟踪多个人. Re-id:从一系列图片中检索与一张被查询图片相似的图片. 我们用CNN为MTMCT和Reid学习好的特征. 贡献包括: ①为训练设计的一个自适应权重的三重损失 ②一种新的艰难身份挖掘技术 我们测验了好的re-id和好的MTMCT分数之间的相关性,并且做了消融研究,以阐明系统主要成分

Deep Learning 论文解读——Session-based Recommendations with Recurrent Neural Networks

博客地址:http://www.cnblogs.com/daniel-D/p/5602254.html 新浪微博:http://weibo.com/u/2786597434 欢迎多多交流~ Main Idea 这篇论文的工作是讲 RNN 应用到推荐系统中,想法在于把一个 session 点击一系列 item 的行为看做一个序列,用来训练一个 RNN 模型.在预测阶段,把 session 已知的点击序列作为输入,用 softmax 预测该session下一个最有可能点击的item.论文想法虽然很朴

An Analysis of Scale Invariance in Object Detection – SNIP 论文解读

前言 本来想按照惯例来一个overview的,结果看到一篇十分不错而且详细的介绍,因此copy过来,自己在前面大体总结一下论文,细节不做赘述,引用文章讲得很详细. 论文概述 引用文章 以下内容来自:http://lowrank.science/SNIP/ 这篇日志记录一些对下面这篇 CVPR 2018 Oral 文章的笔记. Singh B, Davis L S. An Analysis of Scale Invariance in Object Detection–SNIP[C]//Proce

PyTorch源码解读之torch.utils.data.DataLoader(转)

原文链接 https://blog.csdn.net/u014380165/article/details/79058479 写得特别好!最近正好在学习pytorch,学习一下! PyTorch中数据读取的一个重要接口是torch.utils.data.DataLoader,该接口定义在dataloader.py脚本中,只要是用PyTorch来训练模型基本都会用到该接口,该接口主要用来将自定义的数据读取接口的输出或者PyTorch已有的数据读取接口的输入按照batch size封装成Tensor

CVPR2019 | Mask Scoring R-CNN 论文解读

Mask Scoring R-CNN 作者 | 文永亮 研究方向 | 目标检测.GAN 推荐理由: 本文解读的是一篇发表于CVPR2019的paper,来自华科和地平线,文章提出了Mask Scoring R-CNN的框架是对Mask R-CNN的改进,简单地来说就是给Mask R-CNN添加一个新的分支来给mask打分从而预测出更准确的分数. 源码地址:https://github.com/zjhuang22/maskscoring_rcnn 研究动机: Mask R-CNN其实是何恺明大神在

论文解读《ImageNet Classification with Deep Convolutional Neural Networks》

这篇论文提出了AlexNet,奠定了深度学习在CV领域中的地位. 1. ReLu激活函数 2. Dropout 3. 数据增强 减小过拟合(Reducing Overfitting) 动机:由于整个网络拥有6000万个参数:尽管ILSVRC的1000个类使得每个训练示例对从图像到标签的映射施加10位约束,十分有必要去考虑过拟合的问题. 数据扩充(Data Augmentation) 图像数据扩充,即人工的扩大数据集, 是减小过拟合现象最简单和常用的方法,作者使用两者不同的数据扩充方法: --第一