nn.Module模块概述
nn.Module类的基本定义
在定义自已的网络的时候,需要继承nn.Module类,并重新实现构造函数__init__()和forward这两个方法。在构造函数__init__()中使用super(Model, self).init()来调用父类的构造函数,forward方法是必须要重写的,它是实现模型的功能,实现各个层之间的连接关系的核心。
1.一般把网络中具有可学习参数的层(如全连接层、卷积层)放在构造函数__init__()中。
2.一般把不具有可学习参数的层(如ReLU、dropout)可放在构造函数中,也可不放在构造函数中(在forward中使用nn.functional来调用)。
示例1:将具有可学习参数层和不具有可学习参数层均放在构造函数中
import torch.nn as nn
import torch.nn.functional as F
class Model(nn.Module):
def __init__(self):
super(Model, self).__init__() # 调用父类的构造函数
self.con2v = nn.Conv2d(1, 3, 3, 1)
self.relu = nn.ReLU()
self.max_pooling = nn.MaxPool2d(2, 1)
def forward(self, x):
x = self.con2v(x)
x = self.relu(x)
x = self.max_pooling(x)
return x
model = Model()
print(model)
''' 可看到输出的模型结构
Model(
(con2v): Conv2d(1, 3, kernel_size=(3, 3), stride=(1, 1))
(relu): ReLU()
(max_pooling): MaxPool2d(kernel_size=2, stride=1, padding=0, dilation=1, ceil_mode=False)
)
'''
示例2:把不具有可学习参数的层不放在构造函数中(在forward中使用nn.functional调用)
import torch.nn as nn
import torch.nn.functional as F
class Model(nn.Module):
def __init__(self):
super(Model, self).__init__() # 调用父类的构造函数
self.con2v = nn.Conv2d(1, 3, 3, 1)
self.max_pooling = nn.MaxPool2d(2, 1)
def forward(self, x):
x = self.con2v(x)
x = F.relu(x)
x = self.max_pooling(x)
return x
model = Model()
print(model)
''' 可看到输出的模型结构
Model(
(con2v): Conv2d(1, 3, kernel_size=(3, 3), stride=(1, 1))
(max_pooling): MaxPool2d(kernel_size=2, stride=1, padding=0, dilation=1, ceil_mode=False)
)
'''
由此可看出不具有可学习参数层没有放在构造函数里面,那么这些层就不会出现在model中。
也就是在构造函数__init__()中只是定义了模型的结构,而在forward方法中实现了模型中的所有层的连接。
3.只要在nn.Module中定义了forward函数,backward函数就会被自动实现(利用Autograd)。而且一般不是显式的调用forward(layer.forward), 而是layer(input), 会自执行forward()。
Sequential类的概述
nn.Sequential的定义:一个有顺序容器,神经网络模块将按照构造函数中传递的顺序添加到该容器中。此外,也可以传入一个有序的模块字典。
Sequenrial类实现了整数索引,每一个层是没有名称的,默认是以0、1、2…这样的index来命名,可以使用model[index]这样的方式获取一个层,并不能够通过名称(如model[“Conv2d”])来获取层。
示例如下:
import torch.nn as nn
class Model(nn.Module):
def __init__(self):
super(Model, self).__init__() # 调用父类的构造函数
self.model1= nn.Sequential(
nn.Conv2d(1, 3, 3, 1),
nn.ReLU(),
nn.Conv2d(3, 9, 3, 1),
nn.MaxPool2d(2, 1)
)
def forward(self, x):
x = self.struct(x)
return x
model = Model()
print(model)
print(model.model1[2]) # 通过索引获取第几个层
''' 输出结果
Model(
(model1): Sequential(
(0): Conv2d(1, 3, kernel_size=(3, 3), stride=(1, 1))
(1): ReLU()
(2): Conv2d(3, 9, kernel_size=(3, 3), stride=(1, 1))
(3): MaxPool2d(kernel_size=2, stride=1, padding=0, dilation=1, ceil_mode=False)
)
)
Conv2d(3, 9, kernel_size=(3, 3), stride=(1, 1))
'''
Sequential的三种包装方式
示例如下:
import torch.nn as nn
from collections import OrderedDict
class Model(nn.Module):
def __init__(self):
super(Model, self).__init__() # 调用父类的构造函数
self.model1 = nn.Sequential( # 方式一
nn.Conv2d(1, 3, 3, 1),
nn.ReLU()
)
self.model2 = nn.Sequential( # 方式二
OrderedDict([
('conv1', nn.Conv2d(1, 3, 3, 1)),
('relu1', nn.ReLU())
])
)
self.model3 = nn.Sequential() # 方式三
self.model3.add_module('conv1', nn.Conv2d(1, 3, 3, 1)),
self.model3.add_module('relu1', nn.ReLU())
def forward(self, x):
x = self.model1(x)
x = self.model2(x)
x = self.model3(x)
return x
model = Model()
print(model)
''' 输出结果
Model(
(model1): Sequential(
(0): Conv2d(1, 3, kernel_size=(3, 3), stride=(1, 1))
(1): ReLU()
)
(model2): Sequential(
(conv1): Conv2d(1, 3, kernel_size=(3, 3), stride=(1, 1))
(relu1): ReLU()
)
(model3): Sequential(
(conv1): Conv2d(1, 3, kernel_size=(3, 3), stride=(1, 1))
(relu1): ReLU()
)
)
'''