nn.Module是PyTorch提供的神经网络类,并在类中实现了网络各层的定义及前向计算与反向计算机制。在初始化中定义模型结构与参数,在函数forward()中编写网络前向过程即可。
nn.Parameter:
torch.nn.Parameter是继承自torch.Tensor的子类,其主要作用是作为nn.Module中的可训练参数使用。它与torch.Tensor的区别就是nn.Parameter会自动被认为是module的可训练参数,即加入到parameter()这个迭代器中去;而module中非nn.Parameter()的普通tensor是不在parameter中的。注意到,nn.Parameter的对象的requires_grad属性的默认值是True,即是可被训练的,这与torch.Tensor对象的默认值相反。在nn.Module类中,Pytorch也是使用nn.Parameter来对每一个module的参数进行初始化的。
perception.py:
import torch
from torch import nn
#首先建立一个全连接的子module,继承nn.Module
class Linear(nn.Module):
def __init__(self, in_dim, out_dim): #初始化实例的值,这些值一般要供其他方法调用
#首先找到Linear的父类(父类是类nn.Module);
#然后把类Linear的对象self转换为类nn.Module的对象;
#当需要继承父类构造函数中的内容,并且子类需要在父类的基础上补充时,使用super().__init__()方法
#这里的补充则是参数in_dim、out_dim
super(Linear, self).__init__()
#使用nn.Parameter来构造需要学习的参数
self.w = nn.Parameter(torch.randn(in_dim, out_dim)) #全连接层中的w 维度(in_dim,out_dim)
self.b = nn.Parameter(torch.randn(out_dim)) #全连接层中的b 维度out_dim
#在forward中实现向前传播过程
def forward(self, x):
x = x.matmul(self.w) #使用Tensor.matmul实现矩阵相乘
y = x + self.b.expand_as(x) #使用Tensor.expand_as()来保证矩阵形状一致
return y
#构建感知机类,继承nn.Module,并调用了Linear的子module
class Perception(nn.Module):
def __init__(self, in_dim, hid_dim, out_dim):
super(Perception, self).__init__()
self.layer1 = Linear(in_dim, hid_dim) #维度是(in_dim,hid_dim) (2,3)
self.layer2 = Linear(hid_dim, out_dim) #维度是(hid_dim,out_dim) (3,2)
def forward(self, x):
x = self.layer1(x)
y = torch.sigmoid(x) #使用torch中的sigmoid作为激活函数
y = self.layer2(y)
y = torch.sigmoid(y)
return y
#in_dim=2、hid_dim=3、out_dim=2
终端:
>>> import torch
>>> from perception import Perception #调用上述模块
>>> #实例化一个网络,并赋值全连接中的维数,最终输出二维代表了二分类
>>> perception = Perception(2,3,2)
>>> #可以看到perception中包含上述定义的layer1与layer2
>>> perception
Perception(
(layer1): Linear()
(layer2): Linear()
)
>>> #named_parameters()可以返回学习参数的迭代器,分别为参数名与参数值
>>> for name,parameter in perception.named_parameters():
... print(name,parameter)
...
layer1.w Parameter containing:
tensor([[ 1.4509, -0.6111, -0.5108],
[-0.3818, -2.0542, 0.3184]], requires_grad=True)
layer1.b Parameter containing:
tensor([-1.5274, 0.1767, -0.5369], requires_grad=True)
layer2.w Parameter containing:
tensor([[ 0.1622, -0.3417],
[ 0.7079, -1.1008],
[-1.4995, 0.1793]], requires_grad=True)
layer2.b Parameter containing:
tensor([-0.2565, 0.8857], requires_grad=True)
>>> #随机生成数据,注意这里的4代表了样本数为4,每个样本有两维
>>> data = torch.randn(4,2)
>>> data
tensor([[ 1.2537, 0.3754],
[-0.6795, 1.6050],
[-0.3249, 0.1087],
[-2.7153, -0.6721]])
>>> #将输入数据传入perception,perception()相当于调用perception中的forward()函数
>>> output = perception(data)
>>> output
tensor([[0.3986, 0.6280],
[0.2546, 0.7122],
[0.3818, 0.5815],
[0.3646, 0.4857]], grad_fn=<SigmoidBackward>)
forward()
forward()函数用来进行网络的前向传播,并需要传入相应的Tensor,例如在上面的代码中perception(data)即是直接调用了forward()。在具体底层实现中,perception.call(data)将类的实例perception变成了可调用对象perception(data),而在perception.call(data)中主要调用了forward()函数
nn.Module可以自动利用Autograd机制实现反向传播,不需要自己手动实现
多个Module嵌套
在Module的搭建时,可以嵌套包含子Moudle,上例的Perception中调用了Linear这个类。PyTorch也提供了绝大多数的网络层,如全连接、卷积网络中的卷积、池化等,并自动实现前向与反向传播
nn.Module与nn.functional库
在PyTorch中,还有一个库为nn.functional,同样也提供了很多网络层与函数功能,但与nn.Module不同的是,利用nn.functional定义的网络层不可自动学习参数,还需要使用nn.Parameter封装。nn.functional的设计初衷是对于一些不需要学习参数的层,如激活函数层、BN(Batch Normalization)层,可以使用nn.functional,这样这些层就不需要在nn.Module中定义了
nn.Sequential()模块
当模型中只是简单的前馈网络时,即上一层的输出直接作为下一层的输入,这是可以采用nn.Sequential()模块来快读搭建模型,而不必手动在forward()函数中一层一层地前向传播。因此,如果想快速搭建模型而不考虑中间过程的话,推荐使用nn.Sequential
在上面的例子中,Perception类中的layer1与layer2是直接传递的,因此该Perception类可以使用nn.Sequential()快速搭建
perception_sequential.py:
from torch import nn
class Perception(nn.Module):
def __init__(self, in_dim, hid_dim, out_dim):
super(Perception, self).__init__()
#利用nn.Squential()快速搭建网络模块
self.layer = nn.Sequential(
nn.Linear(in_dim, hid_dim),
nn.Sigmoid(),
nn.Linear(hid_dim, out_dim),
nn.Sigmoid()
)
def forward(self, x):
y = self.layer(x)
return y
终端
>>> import torch
>>> #从上述文件中引入Perception类
>>> from perception_sequential import Perception
>>> model = Perception(100,1000,10) #构建类的实例,可以在尾部加上.cuda(),表明在CUDA上
>>> #打印model结构,会显示Sequential中每一层的具体参数配置
>>> model
Perception(
(layer): Sequential(
(0): Linear(in_features=100, out_features=1000, bias=True)
(1): Sigmoid()
(2): Linear(in_features=1000, out_features=10, bias=True)
(3): Sigmoid()
)
)
>>> input = torch.randn(100) #可以在尾部加上.cuda(),表明在CUDA上
>>> output = model(input) #将输入传入实例化的模型
>>> output.shape
torch.Size([10])