1 . torch.nn 是专门为深度学习而设计的模块,它的核心数据结构是 Module,这是一个抽象的概念,既可以表示神经网络中的某个层,也可以表示一个包含很多层的神经网络。在实际使用中,常见的做法是继承 nn.Module,撰写自己的网络/层。 下面自定义一个全连接层。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import torch as t
from torch import nn


class Linear(nn.Module):
def __init__(self, in_features, out_features):
super(Linear, self).__init__() # 等价于 nn.Module.__init__(self)
self.w = nn.Parameter(t.randn(in_features, out_features))
self.b = nn.Parameter(t.randn(out_features))

def forward(self, x):
x = x.mm(self.w)
return x + self.b.expand_as(x)


layer = Linear(4, 3)
input = t.randn(2, 4)
output = layer(input)
print(output)

for name, parameter in layer.named_parameters():
print(name, parameter)

有几点需要注意:

  • 自定义层必须继承 nn.Module,并且在其构造函数中需调用 nn.Module 的构造函数;
  • 在构造函数 __init__ 中必须自己定义可学习的参数,并封装成 nn.ParameterParameter 是一种特殊的 Tensor,但其默认需要求导(requires_grad=True);
  • forward 函数实现前向传播过程,其输入可以是一个或多个 tensor;
  • 无需写反向传播函数,nn.Module 能够利用 autograd 自动实现反向传播;
  • Module 中的可学习参数可以通过 named_parameters() 或者 parameters() 返回迭代器,前者会给每个 parameter 都附上名字,使其更具有辨识度。

2 . Module 能够自动检测到自己的 Parameter,并将其作为学习参数,除了 Parameter 之外,Module 还包含子 Module,主 Module 能够递归查找子 Module 中的 Parameter,下面实现一个多层感知机。

Input:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import torch as t
from torch import nn


class Linear(nn.Module):
def __init__(self, in_features, out_features):
super(Linear, self).__init__() # 等价于 nn.Module.__init__(self)
self.w = nn.Parameter(t.randn(in_features, out_features))
self.b = nn.Parameter(t.randn(out_features))

def forward(self, x):
x = x.mm(self.w)
return x + self.b.expand_as(x)


class Perceptron(nn.Module):
def __init__(self, in_features, hidden_features, out_features):
super(Perceptron, self).__init__()
self.layer1 = Linear(in_features, hidden_features)
self.layer2 = Linear(hidden_features, out_features)

def forward(self, x):
x = self.layer1(x)
x = t.sigmoid(x)
return self.layer2(x)


perceptron = Perceptron(3, 4, 1)
for name, parameter in perceptron.named_parameters():
print(name, parameter.size())

Output:

Module 中 parameter 的命名规范:

  • 对于类似 self.param_name = nn.Parameter(t.randn(3, 4)),命名为 param_name;
  • 对于子 Module 中的 parameter,会其名字之前加上当前 Module 的名字。如对于 self.sub_module = SubModel()SubModel中有个 parameter 的名字叫做 param_name,那么二者拼接而成的 parameter name 就是 sub_module.param_name

3 . 为方便用户使用,PyTorch 实现了神经网络中绝大多数的 layer,这些 layer 都继承于 nn.Module,封装了可学习参数 Parameter,并实现了 forward 函数。这些自定义的 layer 对输入形状都有假设:输入的不是单个数据,而是一个 batch,输入只有一个数据,则必须调用 tensor.unsqueeze(0)tensor[None] 将数据伪装成 batch_size=1 的 batch。


笔记来源:《pytorch-book》