浅谈Pytorch 定义的网络结构层能否重复使用

前言:最近在构建网络的时候,有一些层参数一样,于是就没有定义新的层,直接重复使用了原来已经有的层,发现效果和模型大小都没有什么变化,心中产生了疑问:定义的网络结构层能否重复使用?因此接下来利用了一个小模型网络实验了一下。

一、网络结构一:(连续使用相同的层)

1、网络结构如下所示:

class Cnn(nn.Module):
    def __init__(self):
        super(Cnn, self).__init__()
        self.conv1 = nn.Sequential(
          nn.Conv2d(
            in_channels = 3,  #(, 64, 64, 3)
            out_channels = 16,
            kernel_size = 3,
            stride = 1,
            padding = 1
          ),   ##( , 64, 64, 16)
          nn.ReLU(),
          nn.MaxPool2d(kernel_size = 2)
        )  ##( , 32, 32, 16)
        self.conv2 = nn.Sequential(
          nn.Conv2d(16,32,3,1,1),
          nn.ReLU(),
          nn.MaxPool2d(2)
        )
        self.conv3 = nn.Sequential(
          nn.Conv2d(32,64,3,1,1),
          nn.ReLU(),
          nn.MaxPool2d(2)
        )
        self.conv4 = nn.Sequential(
          nn.Conv2d(64,64,3,1,1),
          nn.BatchNorm2d(64),
          nn.ReLU(),
        )
        self.out = nn.Linear(64*8*8, 6)
    def forward(self, x):
        x = self.conv1(x)
        x = self.conv2(x)
        x = self.conv3(x)
        x = self.conv4(x)
        x = x.view(x.size(0),-1)
        out = self.out(x)
        return out

定义了一个卷积层conv4,接下来围绕着这个conv4做一些变化。打印一下网络结构:

和想象中的一样,其中

nn.BatchNorm2d # 对应上面的 module.conv4.1.*

激活层没有参数所以直接跳过

2、改变一下forward():

连续使用两个conv4层:

def forward(self, x):
        x = self.conv1(x)
        x = self.conv2(x)
        x = self.conv3(x)
        x = self.conv4(x)
        x = self.conv4(x)
        x = x.view(x.size(0),-1)
        out = self.out(x)
        return out

打印网络结构:

和1.1中的结构一样,conv4没有生效。

二、网络结构二:(间断使用相同的层)

网络结构多定义一个和conv4一样的层conv5,同时间断使用conv4:

    self.conv4 = nn.Sequential(
      nn.Conv2d(64,64,3,1,1),
      nn.BatchNorm2d(64),
      nn.ReLU(),
    )
    self.conv5 = nn.Sequential(
      nn.Conv2d(64,64,3,1,1),
      nn.BatchNorm2d(64),
      nn.ReLU(),
    )
    self.out = nn.Linear(64*8*8, 6)
def forward(self, x):
    x = self.conv1(x)
    x = self.conv2(x)
    x = self.conv3(x)
    x = self.conv4(x)
    x = self.conv5(x)
    x = self.conv4(x)
    x = x.view(x.size(0),-1)
    out = self.out(x)
    return out

打印网络结构:

果不其然,新定义的conv5有效,conv4还是没有生效。

本来以为,使用重复定义的层会像conv4.0,conv4.1,…这样下去,看样子是不能重复使用定义的层。

Pytorch_5.7 使用重复元素的网络--VGG

5.7.1 VGG块

VGG引入了Block的概念 作为模型的基础模块

import time
import torch
from torch import nn, optim
import pytorch_deep as pyd
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
def vgg_block(num_convs, in_channels, out_channels):
    blk = []
    for i in range(num_convs):
        if i == 0:
            blk.append(nn.Conv2d(in_channels, out_channels,kernel_size=3, padding=1))
        else:
            blk.append(nn.Conv2d(out_channels, out_channels,kernel_size=3, padding=1))
        blk.append(nn.ReLU())
    blk.append(nn.MaxPool2d(kernel_size=2, stride=2)) # 这⾥会使宽⾼减半
    return nn.Sequential(*blk)

实现VGG_11网络

8个卷积层和3个全连接

def vgg_11(conv_arch, fc_features, fc_hidden_units=4096):
    net = nn.Sequential()
    # 卷积层部分
    for i, (num_convs, in_channels, out_channels) in enumerate(conv_arch):
        # 每经过⼀个vgg_block都会使宽⾼减半
        net.add_module("vgg_block_" + str(i+1),vgg_block(num_convs, in_channels, out_channels))
    # 全连接层部分
    net.add_module("fc", nn.Sequential(
                    pyd.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, 10)
                    ))
    return net
ratio = 8
small_conv_arch = [(1, 1, 64//ratio), (1, 64//ratio, 128//ratio),(2, 128//ratio, 256//ratio),(2, 256//ratio, 512//ratio), (2, 512//ratio,512//ratio)]
fc_features = 512 * 7 * 7 # c *
fc_hidden_units = 4096 # 任意
net = vgg_11(small_conv_arch, fc_features // ratio, fc_hidden_units //ratio)
print(net)
Sequential(
  (vgg_block_1): Sequential(
    (0): Conv2d(1, 8, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (1): ReLU()
    (2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  )
  (vgg_block_2): Sequential(
    (0): Conv2d(8, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (1): ReLU()
    (2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  )
  (vgg_block_3): Sequential(
    (0): Conv2d(16, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (1): ReLU()
    (2): Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (3): ReLU()
    (4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  )
  (vgg_block_4): Sequential(
    (0): Conv2d(32, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (1): ReLU()
    (2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (3): ReLU()
    (4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  )
  (vgg_block_5): Sequential(
    (0): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (1): ReLU()
    (2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (3): ReLU()
    (4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  )
  (fc): Sequential(
    (0): FlattenLayer()
    (1): Linear(in_features=3136, out_features=512, bias=True)
    (2): ReLU()
    (3): Dropout(p=0.5)
    (4): Linear(in_features=512, out_features=512, bias=True)
    (5): ReLU()
    (6): Dropout(p=0.5)
    (7): Linear(in_features=512, out_features=10, bias=True)
  )
)

训练数据

batch_size = 32
# 如出现“out of memory”的报错信息,可减⼩batch_size或resize
train_iter, test_iter = pyd.load_data_fashion_mnist(batch_size,resize=224)
lr, num_epochs = 0.001, 5
optimizer = torch.optim.Adam(net.parameters(), lr=lr)
pyd.train_ch5(net, train_iter, test_iter, batch_size, optimizer,device, num_epochs)
training on  cuda
epoch 1, loss 0.5166, train acc 0.810, test acc 0.872,time 57.6 sec
epoch 2, loss 0.1557, train acc 0.887, test acc 0.902,time 57.9 sec
epoch 3, loss 0.0916, train acc 0.900, test acc 0.907,time 57.7 sec
epoch 4, loss 0.0609, train acc 0.912, test acc 0.915,time 57.6 sec
epoch 5, loss 0.0449, train acc 0.919, test acc 0.914,time 57.4 sec

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • 浅谈PyTorch的可重复性问题(如何使实验结果可复现)

    由于在模型训练的过程中存在大量的随机操作,使得对于同一份代码,重复运行后得到的结果不一致.因此,为了得到可重复的实验结果,我们需要对随机数生成器设置一个固定的种子. 许多博客都有介绍如何解决这个问题,但是很多都不够全面,往往不能保证结果精确一致.我经过许多调研和实验,总结了以下方法,记录下来. 全部设置可以分为三部分: 1. CUDNN cudnn中对卷积操作进行了优化,牺牲了精度来换取计算效率.如果需要保证可重复性,可以使用如下设置: from torch.backends import cu

  • pytorch构建网络模型的4种方法

    利用pytorch来构建网络模型有很多种方法,以下简单列出其中的四种. 假设构建一个网络模型如下: 卷积层-->Relu层-->池化层-->全连接层-->Relu层-->全连接层 首先导入几种方法用到的包: import torch import torch.nn.functional as F from collections import OrderedDict 第一种方法 # Method 1 --------------------------------------

  • 对pytorch网络层结构的数组化详解

    最近再写openpose,它的网络结构是多阶段的网络,所以写网络的时候很想用列表的方式,但是直接使用列表不能将网络中相应的部分放入到cuda中去. 其实这个问题很简单的,使用moduleList就好了. 1 我先是定义了一个函数,用来根据超参数,建立一个基础网络结构 stage = [[3, 3, 3, 1, 1], [7, 7, 7, 7, 7, 1, 1]] branches_cfg = [[[128, 128, 128, 512, 38], [128, 128, 128, 512, 19]

  • pytorch 更改预训练模型网络结构的方法

    一个继承nn.module的model它包含一个叫做children()的函数,这个函数可以用来提取出model每一层的网络结构,在此基础上进行修改即可,修改方法如下(去除后两层): resnet_layer = nn.Sequential(*list(model.children())[:-2]) 那么,接下来就可以构建我们的网络了: class Net(nn.Module): def __init__(self , model): super(Net, self).__init__() #取

  • 浅谈Pytorch 定义的网络结构层能否重复使用

    前言:最近在构建网络的时候,有一些层参数一样,于是就没有定义新的层,直接重复使用了原来已经有的层,发现效果和模型大小都没有什么变化,心中产生了疑问:定义的网络结构层能否重复使用?因此接下来利用了一个小模型网络实验了一下. 一.网络结构一:(连续使用相同的层) 1.网络结构如下所示: class Cnn(nn.Module): def __init__(self): super(Cnn, self).__init__() self.conv1 = nn.Sequential( nn.Conv2d(

  • 浅谈pytorch中的BN层的注意事项

    最近修改一个代码的时候,当使用网络进行推理的时候,发现每次更改测试集的batch size大小竟然会导致推理结果不同,甚至产生错误结果,后来发现在网络中定义了BN层,BN层在训练过程中,会将一个Batch的中的数据转变成正太分布,在推理过程中使用训练过程中的参数对数据进行处理,然而网络并不知道你是在训练还是测试阶段,因此,需要手动的加上,需要在测试和训练阶段使用如下函数. model.train() or model.eval() BN类的定义见pytorch中文参考文档 补充知识:关于pyto

  • 浅谈pytorch grad_fn以及权重梯度不更新的问题

    前提:我训练的是二分类网络,使用语言为pytorch Varibale包含三个属性: data:存储了Tensor,是本体的数据 grad:保存了data的梯度,本事是个Variable而非Tensor,与data形状一致 grad_fn:指向Function对象,用于反向传播的梯度计算之用 在构建网络时,刚开始的错误为:没有可以grad_fn属性的变量. 百度后得知要对需要进行迭代更新的变量设置requires_grad=True ,操作如下: train_pred = Variable(tr

  • 浅谈pytorch池化maxpool2D注意事项

    注意: 在搭建网络的时候用carpool2D的时候,让高度和宽度方向不同池化时, 用如下: nn.MaxPool2d(kernel_size=2, stride=(2, 1), padding=(0, 1)) 千万不要用: nn.MaxPool2d(kernel_size=2, stride=(2, 1), padding=(0, 0)), 这样在用交叉熵做损失函数的时候,有时候会出现loss为nan的情况,检查的时候发现,某些样本的提取出来的feature全为nan. 以上这篇浅谈pytorc

  • 浅谈pytorch torch.backends.cudnn设置作用

    cuDNN使用非确定性算法,并且可以使用torch.backends.cudnn.enabled = False来进行禁用 如果设置为torch.backends.cudnn.enabled =True,说明设置为使用使用非确定性算法 然后再设置: torch.backends.cudnn.benchmark = true 那么cuDNN使用的非确定性算法就会自动寻找最适合当前配置的高效算法,来达到优化运行效率的问题 一般来讲,应该遵循以下准则: 如果网络的输入数据维度或类型上变化不大,设置 

  • 浅谈Pytorch torch.optim优化器个性化的使用

    一.简化前馈网络LeNet import torch as t class LeNet(t.nn.Module): def __init__(self): super(LeNet, self).__init__() self.features = t.nn.Sequential( t.nn.Conv2d(3, 6, 5), t.nn.ReLU(), t.nn.MaxPool2d(2, 2), t.nn.Conv2d(6, 16, 5), t.nn.ReLU(), t.nn.MaxPool2d(2

  • 浅谈PyTorch中in-place operation的含义

    in-place operation在pytorch中是指改变一个tensor的值的时候,不经过复制操作,而是直接在原来的内存上改变它的值.可以把它成为原地操作符. 在pytorch中经常加后缀"_"来代表原地in-place operation,比如说.add_() 或者.scatter().python里面的+=,*=也是in-place operation. 下面是正常的加操作,执行结束加操作之后x的值没有发生变化: import torch x=torch.rand(2) #t

  • 浅谈PHP定义命令空间的几个注意点(推荐)

    1.声明命令空间必须是程序脚本的第一条语句.另外,所有非 PHP 代码包括空白符都不能出现在命名空间的声明之前. 下面是错误的示例: <html> <?php namespace MyProject; // 致命错误 - 命名空间必须是程序脚本的第一条语句 ?> 这个也是错误的 <?php // Lots // of // interesting // comments and white space namespace Foo; class Bar { } ?> 2.

  • 浅谈pytorch和Numpy的区别以及相互转换方法

    如下所示: # -*- coding: utf-8 -*- # @Time : 2018/1/17 16:37 # @Author : Zhiwei Zhong # @Site : # @File : Numpy_Pytorch.py # @Software: PyCharm import torch import numpy as np np_data = np.arange(6).reshape((2, 3)) # numpy 转为 pytorch格式 torch_data = torch.

  • 浅谈Pytorch中的torch.gather函数的含义

    pytorch中的gather函数 pytorch比tensorflow更加编程友好,所以准备用pytorch试着做最近要做的一些实验. 立个flag开始学习pytorch,新开一个分类整理学习pytorch中的一些踩到的泥坑. 今天刚开始接触,读了一下documentation,写一个一开始每太搞懂的函数gather b = torch.Tensor([[1,2,3],[4,5,6]]) print b index_1 = torch.LongTensor([[0,1],[2,0]]) ind

随机推荐