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