一、神经网络工具箱nn
torch.nn
是专门为深度学习设计的模块。torch.nn
的核心数据结构是Module, 他是一个抽象的概念,既可以表示神经网络的某个层(layer),也可以表示一个包含很多层的神经网络。
在实际使用中,最常见的做法是继承nn,Module,撰写自己及的网络/层。
下面来看看如何使用nn.Module实现自己的全连接层。
全连接层,又名仿射层,输出
和输入
满足
,
和
是可学习的参数。
import torch as t
from torch import nn
from torch.autograd import Variable as V
class Linear(nn.Module):
def __init__(self, in_features, out_features): #构造函数,需要调用nn.Mudule的构造函数
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) #mm(mat2) -> Tensor =>矩阵乘法:x=x*w
return x+self.b.expand_as(x) #b.expand_as(a)就是将b进行扩充,扩充到a的维度
layer=Linear(4,3) #定义并初始化模型参数
input=V(t.randn(2,4))
output=layer(input) #前向传播 执行forward()
print(output)
for name,parameter in layer.named_parameters():
print(name, parameter)
运行结果为:
tensor([[ 2.5089, -1.2151, -0.3574],
[ 0.3139, -0.4002, -1.2473]])
w Parameter containing:
tensor([[-0.2625, 1.5595, -0.3886],
[ 0.8469, 0.1103, 1.1023],
[-1.3694, -0.9084, 0.2651],
[ 0.4894, -0.4386, 0.7529]])
b Parameter containing:
tensor([ 2.0638, -0.2871, -0.0683])
注意:
1).自定义层Linear 必须继承nn.Module,并且在其构造函数中调用nn.Module 的构造函数,即
super(Linear,self).__init__()
或于nn.Module.__init__(self)
。
2)在构造函数__init__()
中必须自己定义可学习的参数,并封装成Parameter
.
如在本例题中我们把
和
封装成Parameter
。
Parameter
是一种特殊的Variable
, 但其默认需要求导(requires_grad=True
).
可以通过nn.Parameter??
查看Parameter类的源码。
3) forward()
函数实现前向传播过程,其输入可以是一个或多个Variable, 对x 的任何操作也必须是Variable 支持的操作。
4). 无需写反向传播函数,因为其前向传播都是对Variable
进行操作,nn.Module
能够利用autograd自动实现反向传播。
5). 使用时,直观上可以将layer看成数学概念中的函数,调用layer(input)即可得到input 对应的结果。
他等价于layer.__call__(input)
.
6). Module中的可学习参数可以通过named_parameters()
或者paramaters()
返回迭代器,前者或给每个parameter附上名字,使其更具有辨识度。。
Module能够自动检测到自己的parameter,并将其作为学习参数。 除了parameter,Module还包含子Module,主Module可以递归查找子Module中的parameter。
二、Pytorch模块下的数学操作符:
torch.numel() 返回一个tensor变量内所有元素个数,可以理解为矩阵内元素的个数
torch.squeeze() 对于tensor变量进行维度压缩,去除维数为1的的维度。例如一矩阵维度为A*1*B*C*1*D,通过squeeze()返回向量的维度为A*B*C*D。squeeze(a),表示将a的维数位1的维度删掉,squeeze(a,N)表示,如果第N维维数为1,则压缩去掉,否则a矩阵不变
torch.unsqueeze() 是squeeze()的反向操作,增加一个维度,该维度维数为1,可以指定添加的维度。例如unsqueeze(a,1)表示在1这个维度进行添加
torch.stack(sequence, dim=0, out=None),做tensor的拼接。sequence表示Tensor列表,dim表示拼接的维度,注意这个函数和concatenate是不同的,torch的concatenate函数是torch.cat,是在已有的维度上拼接,而stack是建立一个新的维度,然后再在该纬度上进行拼接。
expand_as(a)这是tensor变量的一个内置方法,如果使用b.expand_as(a)就是将b进行扩充,扩充到a的维度,需要说明的是a的低维度需要比b大,例如b的shape是3*1,如果a的shape是3*2不会出错,但是是2*2就会报错了。
三、多层感知机
由全连接层组成,层与层之间采用sigmoid函数作为激活函数。
# -*- coding: utf-8 -*-
"""
Created on Fri Jul 6 16:53:53 2018
@author: Duan
"""
import torch as t
from torch import nn
#from torch.autograd import Variable as V
class Linear(nn.Module):
def __init__(self, in_features, out_features): #构造函数,需要调用nn.Mudule的构造函数
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) #mm(mat2) -> Tensor =>矩阵乘法:x=x*w
return x+self.b.expand_as(x) #b.expand_as(a)就是将b进行扩充,扩充到a的维度
class Perceptron(nn.Module):
def __init__(self, in_features, hidden_features, out_features): #构造函数,需要调用nn.Mudule的构造函数
super(Perceptron,self).__init__() #等价于nn.Module.__init__(self)
self.layer1=Linear(in_features, hidden_features) #Linear里面有初始化
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,param in perceptron.named_parameters():
print(name, param.size())
运行结果:
layer1.w torch.Size([3, 4])
layer1.b torch.Size([4])
layer2.w torch.Size([4, 1])
layer2.b torch.Size([1])