43_pytorch nn.Module,模型的创建,构建子模块,API介绍,Sequential(序号),ModuleList,ParameterList,案例等(学习笔记)

1.40.PyTorch nn.Module
1.40.1.模型的创建
1.40.2.构建子模块
1.40.3.nn.Module API介绍
1.40.3.1.核心功能
1.40.3.2.查看模块
1.40.3.3.类型转换
1.40.3.4.设置功能
1.40.3.5.注册功能
1.40.3.6.Sequential(序号)
1.40.3.7.ModuleList模型列表
1.40.3.8.ParameterList参数列表
1.40.4.nn.Module 其它API介绍
1.40.5.nn.Module介绍
1.40.6.nn.Module提供的便利
1.40.7.参考博文

1.40.PyTorch nn.Module

1.40.1.模型的创建

模型创建的步骤:
在这里插入图片描述
模型构建的两个要素:
1.构建子模块(构建网络层)
2.拼接子模块(拼接网络层)

1.40.2.构建子模块

在这里插入图片描述
以之前上传的纸币二分类代码为例,对模型的构建进行讲解。

在70行设置断点,查看如何构建LeNet网络。

net = LeNet(classes=2)
net.initialize_weights()

step into进入

class LeNet(nn.Module):
    def __init__(self, classes):
        super(LeNet, self).__init__()
        self.conv1 = nn.Conv2d(3, 6, 5)
        self.conv2 = nn.Conv2d(6, 16, 5)
        self.fc1 = nn.Linear(16 * 5 * 5, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, classes)

进入到LeNet的__init__函数构建子模块,创建了两个卷积层与三个全连接层。运行完最后一个子模块self.fc3就会跳出返回,模型的初始化便完成了。

net = LeNet(classes=2)
net.initialize_weights()

1.40.3.nn.Module API介绍

在这里插入图片描述
这是所有网络的基类,Modules也可以包括其他Modules, 运行使用树结构来嵌入,可以将子模块给模型赋予属性,从下列看出,self.conv1, self.conv2是模型的子模型。

# -*- coding: UTF-8 -*-

import torch.nn as nn
import torch.nn.functional as F


class Model(nn.Module):
    def __init__(self):
        super(Model, self).__init__()
        # submodule: Conv2d
        self.conv1 = nn.Conv2d(1, 20, 5)
        self.conv2 = nn.Conv2d(20, 20, 5)

    def forward(self, x):
        x = F.relu(self.conv1(x))
        return F.relu(self.conv2(x))
1.40.3.1.核心功能

add_module(name,module) 将子模块加入当前的模块中,被添加的模块可以name来获取

# -*- coding: UTF-8 -*-

import torch.nn as nn


class Model(nn.Module):
    def __init__(self):
        super(Model, self).__init__()
        self.add_module("conv", nn.Conv2d(10, 20, 4))
        # self.conv = nn.Conv2d(10, 20, 4) 和上面这个增加module的方式等价


model = Model()
print(model.conv)
"""
输出结果:
Conv2d(10, 20, kernel_size=(4, 4), stride=(1, 1))
"""

forward(*input) 每次运行时都会执行的步骤,所有自定义的module都要重写这个函数
state_dict(destination=None) 返回一个字典,保存module的所有状态
load_state_dict(state_dict): 用来加载模型参数

1.40.3.2.查看模块

parameters(memo=None): 返回一个 包含模型所有参数 的迭代器。一般用作optimizer参数
children(): 返回当前模型 子模块的迭代器。
name_children(): 返回 包含 模型当前子模块 的迭代器,yield 模块名字和模块本身。
modules(): 返回一个包含 当前模型 所有模块的迭代器。
named_modules(): 返回包含网络中所有模块的迭代器, yielding 模块名和模块本身。

# -*- coding: UTF-8 -*-

import torch.nn as nn


class Model(nn.Module):
    def __init__(self):
        super(Model, self).__init__()
        self.add_module("conv", nn.Conv2d(10, 20, 4))
        self.add_module("conv1", nn.Conv2d(20, 10, 4))


model = Model()

for module in model.modules():
    print(module)

print("---------------------------------------------------")

for children in model.children():
    print(module)

输出结果:

Model(
  (conv): Conv2d(10, 20, kernel_size=(4, 4), stride=(1, 1))
  (conv1): Conv2d(20, 10, kernel_size=(4, 4), stride=(1, 1))
)
Conv2d(10, 20, kernel_size=(4, 4), stride=(1, 1))
Conv2d(20, 10, kernel_size=(4, 4), stride=(1, 1))
---------------------------------------------------
Conv2d(20, 10, kernel_size=(4, 4), stride=(1, 1))
Conv2d(20, 10, kernel_size=(4, 4), stride=(1, 1))
1.40.3.3.类型转换

cpu(device_id=None):将所有的模型参数(parameters)和buffers复制到CPU
cuda(device_id=None):将所有的模型参数(parameters)和buffers赋值GPU
double() :将parameters和buffers的数据类型转换成double
float(): 将parameters和buffers的数据类型转换成float。
half():将parameters和buffers的数据类型转换成half。

1.40.3.4.设置功能

train(mode=True):将module设置为 training mode,只影响dropout和batchNorm
eval(): 将模型设置成evaluation模式,只影响dropout和batchNorm
zero_grad(): 将module中的所有模型的梯度设置为0

1.40.3.5.注册功能

register_parameter(name, param):向module添加 parameter,可以通过name获取
register_forward_hook(hook): 在module上注册一个forward hook。每次调用forward()计算输出的时候,这个hook就会被调用。
register_backward_hook(hook): 在module上注册一个bachward hook。每次计算module的inputs的梯度的时候,这个hook会被调用
register_buffer(name, tensor): 给module添加一个persistent buffer,通常用来保存一个不需要看成模型参数的状态。

1.40.3.6.Sequential(序号)

class torch.nn.Sequential(*args)

当你使用Sequential时,Modules会以传入的顺序来添加layer到容器中,也可以传入一个OrderedDict,下面是个简单的例子

import torch.nn as nn

# Example of using Sequential
model = nn.Sequential(
          nn.Conv2d(1,20,5),
          nn.ReLU(),
          nn.Conv2d(20,64,5),
          nn.ReLU()
        )
# Example of using Sequential with OrderedDict
model = nn.Sequential(OrderedDict([
          ('conv1', nn.Conv2d(1,20,5)),
          ('relu1', nn.ReLU()),
          ('conv2', nn.Conv2d(20,64,5)),
          ('relu2', nn.ReLU())
        ]))
1.40.3.7.ModuleList模型列表
class torch.nn.ModuleList(modules=None)

将你的字模型保存在一个list中,可以像python list一样被索引,moduleList中包含的modules已经被正确的注册,对所有module method可见

参数说明:
module(list, optional) – 将要被添加到ModuleList中的modules列表

方法:
append(module): 添加模型,等价于list的append
extend(modules): 等价于list的extend

例子:

import torch.nn as nn


class MyModule(nn.Module):
    def __init__(self):
        super(MyModule, self).__init__()
        self.linears = nn.ModuleList([nn.Linear(10, 10) for i in range(10)])

    def forward(self, x):
        # ModuleList can act as an iterable, or be indexed         using ints
        for i, l in enumerate(self.linears):
            x = self.linears[i // 2](x) + l(x)
        return x
1.40.3.8.ParameterList参数列表

class torch.nn.ParameterList(parameters=None)

将submodules 保存在一个list中。ParameterList 可以像一般的Python list一样被索引。而且 ParameterList 中包含的 parameters 已经被正确的注册,对所有的 module method可见。

参数说明:
modules (list, optional) – a list of nn.Parameter

方法:
append(module): 添加模型,等价于list的append
extend(modules): 等价于list的extend

例子:

import torch
import torch.nn as nn


class MyModule(nn.Module):
    def __init__(self):
        super(MyModule, self).__init__()
        self.params = nn.ParameterList([nn.Parameter(torch.randn(10, 10)) for i in range(10)])

    def forward(self, x):
        # ModuleList can act as an iterable, or be indexed using ints
        for i, p in enumerate(self.params):
            x = self.params[i // 2].mm(x) + p.mm(x)

卷积层:

class torch.nn.Conv1d()
class torch.nn.Conv2d()

1.40.4.nn.Module 其它API介绍

nn.Module在torch.nn下
在这里插入图片描述
nn.module通过八个有序字典来管理模型
在这里插入图片描述
parameters: 存储管理nn.Parameter类,如权值、偏置
modules: 存储管理nn.Module类,如卷积层,池化层
buffers: 存储管理缓冲属性,如BN层中的running_mean
***_hooks: 存储管理钩子函数

1.40.5.nn.Module介绍

nn.Module是所有网络层的父类,pytorch提供的线性层、卷积层也是集成自这个类,包括:

  • nn.Linear
  • nn.BatchNorm2d
  • nn.Conv2d

我们自己定义的网络层时也要继承这个类(nn.Module),并实现前馈函数forward。
在这里插入图片描述

1.40.6.nn.Module提供的便利

nn.Module提供了大量的现成的计算模块,比如以下:
Linear、Relu、Sigmoid、Con2d、ConvTransposed2d、Dropout等。

nn.Sequential,模块将按照构造函数中传递的顺序添加到模块中。另外,也可以传入一个有序模块。
在这里插入图片描述

self.net = nn.Sequential(
            nn.Conv2d(1, 32, 5, 1, 1),
            nn.MaxPool2d(2, 2),
            nn.ReLU(True),
            nn.BatchNorm2d(32),

            nn.Conv2d(32, 64, 3, 1, 1),
            nn.ReLU(True),
            nn.BatchNorm2d(64),

            nn.Conv2d(64, 64, 3, 1, 1),
            nn.MaxPool2d(2, 2),
            nn.ReLU(True),
            nn.BatchNorm2d(64),

            nn.Conv2d(64, 128, 3, 1, 1),
            nn.ReLU(True),
            nn.BatchNorm2d(128)
        )

官网示例:

# Example of using Sequential
model = nn.Sequential(
        nn.Conv2d(1, 20, 5),
        nn.ReLU(),
        nn.Conv2d(20, 64, 5),
        nn.ReLU()
    )

# Example of using Sequential with OrderedDict
model = nn.Sequential(OrderedDict([
                  ('conv1', nn.Conv2d(1,20,5)),
                  ('relu1', nn.ReLU()),
                  ('conv2', nn.Conv2d(20,64,5)),
                  ('relu2', nn.ReLU())
                ]))

可以使用torch.nn.Sequential快速搭建神经网络,为了方便比较,我们先用普通方法搭建一个神经网络。

class Net(torch.nn.Module):
    def __init__(self, n_feature, n_hidden, n_output):
        super(Net, self).__init__()
        self.hidden = torch.nn.Linear(n_feature, n_hidden)
        self.predict = torch.nn.Linear(n_hidden, n_output)

    def forward(self, x):
        x = F.relu(self.hidden(x))
        x = self.predict(x)
        return x


net1 = Net(1, 10, 1)

上面class继承了一个torch中的神经网络结构, 然后对其进行了修改;接下来我们来使用torch.nn.Sequential来快速搭建一个神经网络。

net2 = torch.nn.Sequential(
    torch.nn.Linear(1, 10),
    torch.nn.ReLU(),
    torch.nn.Linear(10, 1)
)

(3)net.parameters():构建好神经网络后,网络的参数都保存在parameters()函数当中。

import torch
import torch.nn as nn

net = nn.Sequential(nn.Linear(4, 2), nn.Linear(3,2))
# 网络的参数都保存在parameters()函数中
print(list(net.parameters())[0].shape)
print(list(net.parameters())[0].shape)
print(list(net.parameters())[0].shape)
print(list(net.parameters())[0].shape)

结果:

torch.Size([2, 4])
torch.Size([2])
torch.Size([2, 3])
torch.Size([2])

(4)modules:modules: all nodes,children: direct children

import torch
import torch.nn as nn


class BasicNet(nn.Module):
    def __init__(self):
        super(BasicNet, self).__init__()
        self.net = nn.Linear(4, 3)

    def forward(self, x):
        return self.net(x)


class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.net = nn.Sequential(BasicNet(), nn.ReLU(), nn.Linear(3, 2))
        
    def forward(self, x):
        return self.net(x)

(5)更换数据存放位置:cpu --> cuda

device = torch.device('cuda')
net = Net()
net.to(device)

(6)save and load: 保存和加载模型数据

device = torch.device('cuda')
net = Net()
net.to(device)

net.load_state_dict(torch.load('ckpt.mdl'))

# train...

torch.save(net.state_dict(), 'ckpt.mdl')

(7)train/test: 训练和测试阶段的切换

device = torch.device('cuda')
net = Net()
net.to(device)

# train
net.train()

# test
net.eval()

(8)Implement own layer

class Flatten(nn.Module):
    def __init__(self):
        super(Flatten, self).__init__()

    def forward(self, input):
        return input.view(input.size(0), -1)


class TestNet(nn.Module):
    def __init__(self):
        super(TestNet, self).__init__()
        self.net = nn.Sequential(nn.Conv2d(1, 16, stride=1, padding=1),
                                 nn.MaxPool2d(2, 2),
                                 Flatten(),
                                 nn.Linear(1 * 14 * 14, 10))

    def forward(self, x):
        return self.net(x)

1.40.7.参考博文

https://zhuanlan.zhihu.com/p/69526677
http://ddrv.cn/a/586531

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

涂作权的博客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值