1 nn.Module
"""Pytorch中神经网络模块化接口nn的了解"""
torch.nn是专门为神经网络设计的模块化接口。
nn构建于autograd之上,可以用来定义和运行神经网络。
nn.Module是nn中十分重要的类,包含网络各层的定义及forward方法。
定义自已的网络:
需要继承nn.Module类,并实现forward方法。
=> 一般把网络中具有可学习参数的层放在构造函数__init__()中,
=> 不具有可学习参数的层(如ReLU)可放在构造函数中,也可不放在构造函数中(而在forward中使用nn.functional来代替)
只要在nn.Module的子类中定义了forward函数,backward函数就会被自动实现(利用Autograd)。
在forward函数中可以使用任何Variable支持的函数,毕竟在整个pytorch构建的图中,是Variable在流动。
还可以使用 if,for,print,log 等python语法.
注:Pytorch基于nn.Module构建的模型中,只支持mini-batch的Variable输入方式,
比如,只有一张输入图片,也需要变成 N x C x H x W 的形式:
input_image = torch.FloatTensor(1, 28, 28)
input_image = Variable(input_image)
input_image = input_image.unsqueeze(0) # 1 x 1 x 28 x 28
"""
# coding=utf-8
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.autograd import Variable
"""Pytorch中神经网络模块化接口nn的了解"""
"""
torch.nn是专门为神经网络设计的模块化接口。nn构建于autograd之上,可以用来定义和运行神经网络。
nn.Module是nn中十分重要的类,包含网络各层的定义及forward方法。
定义自已的网络:
需要继承nn.Module类,并实现forward方法。
一般把网络中具有可学习参数的层放在构造函数__init__()中,
不具有可学习参数的层(如ReLU)可放在构造函数中,也可不放在构造函数中(而在forward中使用nn.functional来代替)
只要在nn.Module的子类中定义了forward函数,backward函数就会被自动实现(利用Autograd)。
在forward函数中可以使用任何Variable支持的函数,毕竟在整个pytorch构建的图中,是Variable在流动。还可以使用
if,for,print,log等python语法.
注:Pytorch基于nn.Module构建的模型中,只支持mini-batch的Variable输入方式,
比如,只有一张输入图片,也需要变成 N x C x H x W 的形式:
input_image = torch.FloatTensor(1, 28, 28)
input_image = Variable(input_image)
input_image = input_image.unsqueeze(0) # 1 x 1 x 28 x 28
"""
class LeNet(nn.Module):
def __init__(self):
# nn.Module的子类函数必须在构造函数中执行父类的构造函数
super(LeNet, self).__init__() # 等价与nn.Module.__init__()
# nn.Conv2d返回的是一个Conv2d class的一个对象,该类中包含forward函数的实现
# 当调用self.conv1(input)的时候,就会调用该类的forward函数
self.conv1 = nn.Conv2d(1, 6, (5, 5)) # output (N, C_{out}, H_{out}, W_{out})`
self.conv2 = nn.Conv2d(6, 16, (5, 5))
self.fc1 = nn.Linear(256, 120)
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
def forward(self, x):
# 不具有可学习参数的层(如ReLU)可放在构造函数中,也可不放在构造函数中(而在forward中使用nn.functional来代替)
x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2)) # F.max_pool2d的返回值是一个Variable
x = F.max_pool2d(F.relu(self.conv2(x)), (2, 2))
x = x.view(x.size()[0], -1)
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = F.relu(self.fc3(x))
# 返回值也是一个Variable对象
return x
def output_name_and_params(net):
for name, parameters in net.named_parameters():
print('name: {}, param: {}'.format(name, parameters))
if __name__ == '__main__':
net = LeNet()
print('net: {}'.format(net))
params = net.parameters() # generator object
print('params: {}'.format(params))
output_name_and_params(net)
input_image = torch.FloatTensor(10, 1, 28, 28)
# 和tensorflow不一样,pytorch中模型的输入是一个Variable,而且是Variable在图中流动,不是Tensor。
# 这可以从forward中每一步的执行结果可以看出
input_image = Variable(input_image)
output = net(input_image)
print('output: {}'.format(output))
print('output.size: {}'.format(output.size()))
补充说明:
一般出现在model类的forward函数中,具体位置一般都是在调用分类器之前。
分类器是一个简单的nn.Linear()结构,输入输出都是维度为一的值,
x = x.view(x.size(0), -1) 这句话的出现就是为了将前面多维度的tensor展平成一维。
下面是个简单的例子,我将会根据例子来对该语句进行解析。
class NET(nn.Module):
def __init__(self,batch_size):
super(NET,self).__init__()
self.conv = nn.Conv2d(outchannels=3,in_channels=64,kernel_size=3,stride=1)
self.fc = nn.Linear(64*batch_size,10)
def forward(self,x):
x = self.conv(x)
x = x.view(x.size(0), -1)
out = self.fc(x)
上面是个简单的网络结构,包含一个卷积层和一个分类层。
forward()函数中,
input首先经过卷积层,此时的输出x是包含batchsize维度为4的tensor,即(batchsize,channels,x,y),
x.size(0)指batchsize的值。
x = x.view(x.size(0), -1)简化x = x.view(batchsize, -1)。
view()函数的功能与reshape类似,用来转换size大小。
x = x.view(batchsize, -1)中batchsize指转换后有几行,
-1指在不告诉函数有多少列的情况下,根据原tensor数据和batchsize自动分配列数。
eg: 这里batchsize是1,所以就是打平为一维数组
2 nn.Sequential
PyTorch - torch.nn.Sequential
官网的示例
# 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
import torch
import torch.nn as nn
import torch.nn.functional as F
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.model = nn.Sequential(
nn.Conv2d(1,20,5),
nn.ReLU(),
nn.Conv2d(20,64,5),
nn.ReLU()
)
output=Net()
print(output)
# =============================================================================
# Net(
# (model): Sequential(
# (0): Conv2d(1, 20, kernel_size=(5, 5), stride=(1, 1))
# (1): ReLU()
# (2): Conv2d(20, 64, kernel_size=(5, 5), stride=(1, 1))
# (3): ReLU()
# )
# )
# =============================================================================
示例代码2
# 每一层都有名字
import torch
import torch.nn as nn
import torch.nn.functional as F
from collections import OrderedDict
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.model = nn.Sequential(OrderedDict([
('conv1', nn.Conv2d(1,20,5)),
('relu1', nn.ReLU()),
('conv2', nn.Conv2d(20,64,5)),
('relu2', nn.ReLU())
]))
output=Net()
print(output)
# =============================================================================
# Net(
# (model): Sequential(
# (conv1): Conv2d(1, 20, kernel_size=(5, 5), stride=(1, 1))
# (relu1): ReLU()
# (conv2): Conv2d(20, 64, kernel_size=(5, 5), stride=(1, 1))
# (relu2): ReLU()
# )
# )
# =============================================================================
示例代码3
import torch
import torch.nn as nn
import torch.nn.functional as F
from collections import OrderedDict
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.model=nn.Sequential()
self.model.add_module('conv1', nn.Conv2d(1,20,5))
self.model.add_module('relu1', nn.ReLU())
self.model.add_module('conv2', nn.Conv2d(20,64,5))
self.model.add_module('relu2', nn.ReLU())
output=Net()
print(output)
# =============================================================================
# Net(
# (model): Sequential(
# (conv1): Conv2d(1, 20, kernel_size=(5, 5), stride=(1, 1))
# (relu1): ReLU()
# (conv2): Conv2d(20, 64, kernel_size=(5, 5), stride=(1, 1))
# (relu2): ReLU()
# )
# )
#
# =============================================================================
nn.Conv2d