- 继承 nn.Module ,建立一个 network class
- 在 network class 的构造函数中定义== layers 为 类的属性(attributes)==
- 用 layers 属性和 nn.functional 的方法来定义forward()
torch.nn.Module 类
神经网络 和 神经网络的layers 都继承自 torch.nn.module 。
forward method 是 nn.module 类的一个 method。它指的是tensor进入network,通过所有 layers 直到 output 的过程。Forward method 可以是对应整个神经网络的提法,也可以是对一个 layer 的提法。forward method中经常使用 nn.functional 类下的内容。
Time to build one network
import torch.nn as nn
class Network(nn.Module):
def __init__(self):
super(Network, self).__init()##do not forget
self.conv1 = nn.Conv2d(in_channels=1, out_channels=6, kernel_size=5)
self.conv1 = nn.Conv2d(in_channels=6, out_channels=12, kernel_size=5)
self.fc1 = nn.Linear(in_features=12*4*4, out_features=120)
self.fc2 = nn.Linear(in_features=120, out_features=60)
self.out = nn.Linear(in_features=120, out_features=10)
def forward(self, t):
#implement forward
return t
注意,全连接层 fully connected layer = dense layer = linear layer,在pytorch 里,是 nn.Linear .
如何 implement forward() 呢?
先弄清 learnable parameters。Learnale parameters一般是随机指定的,神经网络在学习中获取适合的 learnable parameters 值,以获得更小的 loss。PyTorch中,learnable parameters 是 Parameter 类的对象。
Learnale parameters在哪儿?
network = Network()
print(network) #-> 网络结构
print(network.conv1) #-> conv1层结构
print(network.conv1.weight) #-> conv1层的 learnable parameters
weight 的 shape 跟网络结构(超参数)有关,观察一下shape :
for name, param in network.named_parameters():
print(name, '\t\t', param.shape)
观察得,卷积层 conv 的 learnable parameters 的 shape 是 torch.Size([out_channels, in_channels, kernel_size, kernel_size]),全连接层的learnable parameters 的 shape 是 torch.Size([out_features, in_features]),而且本示例网络每层都有bias,bias也是 learnable parameters ,shape 是 torch.Size([out_features])
Forward()
调用forward()时,直接将数据传入实例中来调用forward(t)
,而不是调用forward(),原理在 nn.module 类 源码中:
def __call__(self, *input, **kwargs):
result = self.forward(*input, **kwargs)
for hook in self._forward_hooks.values():
#将注册的hook拿出来用
hook_result = hook(self, input, result)
...
return result
一个forward()的例子:
def forward(self, t):
#input layer
t=t
#hidden conv layer
t = sef.conv1(t)
t = F.relu(t)
t = F.max_pool2d(t, kernel_size=2, stride=2)
#hidden conv layer
t = sef.conv2(t)
t = F.relu(t)
t = F.max_pool2d(t, kernel_size=2, stride=2)
#hidden linear layer
t = t.reshape(-1, 12 * 4 * 4)
t = self.fc1(t)
t = F.relu(t)
#hidden linear layer
t = self.fc2(t)
t = F.relu(t)
#output layer
t = self.out(y)
#t = F.softmax(t) Softmax会在计算crossentropy时自动实现,不在输出层中实施
return t
进行一次forward propagation测试
因为只是测试而已,我并不打算更新 learnable weights ,所以这里我要关闭梯度计算,节省内存。
torch.set_grad_enabled(False)
#创建网络实例
network = Network()
#传入一张图片,train_set 是 FashionMNIST 中 trainset 的dataloader实例化对象
sample = next(iter(train_set))
image, label = sample
image.shape #-> torch.Size([1, 28, 28])
#network总是接受一个batch的图像,即使这个batch只有一张图,所以输入的Rank必须是4
image.unsqueeze(0).shape #-> torch.Size([1, 1, 28, 28]),batchsize = 1
pred = network(image.unsqueeze(0))#-> torch.Size([1, 10]),输出的10个数对应十个类别的可能性
pred.argmax(dim=1) #-> tensor([2])由于没训练,这个值随机
F.softmax(pred, dim=1) #-> torch.Size([1, 10]),使 pred 的十个元素和为1,使输出对应可能性,并且能够使用crossenropy