PyTorch 神经网络基础
层和块
nn.Sequential
和nn.Module
可以嵌套使用
# 回顾一下多层感知机
import torch
from torch import nn
from torch.nn import functional as F
net = nn.Sequential(nn.Linear(20,256),nn.ReLU(),nn.Linear(256,10))
X = torch.rand(2,20)
net(X)
参数管理
- 参数查看
- 参数初始化
- 自定义参数初始化
class MLP(nn.Module):
def __init__(self):
super().__init__() # 调用父类的__init__函数
self.hidden = nn.Linear(20,256)
self.out = nn.Linear(256,10)
def forward(self, X):
return self.out(F.relu(self.hidden(X)))
# 实例化多层感知机的层,然后在每次调用正向传播函数调用这些层
net = MLP()
X = torch.rand(2,20)
net(X)
在正向传播函数中执行代码
class FixedHiddenMLP(nn.Module):
def __init__(self):
super().__init__()
self.rand_weight = torch.rand((20,20),requires_grad=False)
self.linear = nn.Linear(20,20)
def forward(self, X):
X = self.linear(X)
X = F.relu(torch.mm(X, self.rand_weight + 1))
X = self.linear(X)
while X.abs().sum() > 1:
X /= 2
return X.sum()
net = FixedHiddenMLP()
X = torch.rand(2,20)
net(X)
- 直接设置参数
- 参数绑定
自定义层
- 不带参数的层
# 构造一个没有任何参数的自定义层
import torch
import torch.nn.functional as F
from torch import nn
class CenteredLayer(nn.Module):
def __init__(self):
super().__init__()
def forward(self, X):
return X - X.mean()
layer = CenteredLayer()
print(layer(torch.FloatTensor([1,2,3,4,5])))
# 将层作为组件合并到构建更复杂的模型中
net = nn.Sequential(nn.Linear(8,128),CenteredLayer())
Y = net(torch.rand(4,8))
print(Y.mean())
# 带参数的图层
class MyLinear(nn.Module):
def __init__(self, in_units, units):
super().__init__()
self.weight = nn.Parameter(torch.randn(in_units,units)) # nn.Parameter使得这些参数加上了梯度
self.bias = nn.Parameter(torch.randn(units,))
def forward(self, X):
linear = torch.matmul(X, self.weight.data) + self.bias.data
return F.relu(linear)
dense = MyLinear(5,3)
print(dense.weight)
# 使用自定义层直接执行正向传播计算
print(dense(torch.rand(2,5)))
# 使用自定义层构建模型
net = nn.Sequential(MyLinear(64,8),MyLinear(8,1))
print(net(torch.rand(2,64)))
- 带参数的层
# 参数绑定
shared = nn.Linear(8,8)
net = nn.Sequential(nn.Linear(4,8),nn.ReLU(),shared,nn.ReLU(),shared,nn.ReLU(),nn.Linear(8,1)) # 第2个隐藏层和第3个隐藏层是share权重的,第一个和第四个是自己的
net(X)
print(net[2].weight.data[0] == net[4].weight.data[0])
net[2].weight.data[0,0] = 100
print(net[2].weight.data[0] == net[4].weight.data[0])
读写文件
- 加载和保存张量
- 加载和保存模型参数
# 加载和保存张量
import torch
from torch import nn
from torch.nn import functional as F
x = torch.arange(4)
torch.save(x, 'x-file')
x2 = torch.load("x-file")
print(x2)
#存储一个张量列表,然后把它们读回内存
y = torch.zeros(4)
torch.save([x,y],'x-files')
x2, y2 = torch.load('x-files')
print(x2)
print(y2)
# 写入或读取从字符串映射到张量的字典
mydict = {'x':x,'y':y}
torch.save(mydict,'mydict')
mydict2 = torch.load('mydict')
print(mydict2)
# 加载和保存模型参数
class MLP(nn.Module):
def __init__(self):
super().__init__()
self.hidden = nn.Linear(20,256)
self.output = nn.Linear(256,10)
def forward(self, x):
return self.output(F.relu(self.hidden(x)))
net = MLP()
X = torch.randn(size=(2,20))
Y = net(X)
# 将模型的参数存储为一个叫做"mlp.params"的文件
torch.save(net.state_dict(),'mlp.params')
# 实例化了原始多层感知机模型的一个备份。直接读取文件中存储的参数
clone = MLP() # 必须要先声明一下,才能导入参数
clone.load_state_dict(torch.load("mlp.params"))
print(clone.eval()) # eval()是进入测试模式
Y_clone = clone(X)
print(Y_clone == Y)
Numpy与Torch对比
Numpy 是处理矩阵等数据的模块,会使用多核加速运算。而 PyTorch 就是神经网络中的 Numpy,是 Torch(张量)的类型,张量的维度可以大于 2。
下面举例说明 Numpy 和 Torch 的一些区别:
# 首先引入包
import torch
import numpy as np
# 创造一个numpy的数据,reshape成2行3列
np_data = np.arange(6).reshape((2, 3))
# 将numpy转换为torch中tensor的数据
torch_data = torch.from_numpy(np_data)
# 将tensor转换为numpy的数据
tensor2array = torch_data.numpy()
print(
'\nnumpy', np_data,
'\ntorch', torch_data,
'\ntensor2array', tensor2array,
)
进行矩阵相乘的操作:
data = [[1, 2], [3, 4]]
tensor = torch.FloatTensor(data)
# 将data变为numpy的data
data = np.array(data)
print(
'\nnumpy:', np.matmul(data, data), # 矩阵相乘
# 或使用:
# '\nnumpy:', data.dot(data),
'\ntorch:', torch.mm(tensor, tensor)
# 而在torch中使用dot给出的答案不一样
# '\nnumpy:', tensor.dot(tensor), # torch将结果展平:1×1+2×2+3×3+4×4
)
Variable 变量
我们介绍一些 PyTorch 的细节内容(神经网络的细节变化),tensor 与 Variable 的不同之处。
torch 是用 tensor 来计算的,神经网络的参数都是 Variable 变量的形式,将 tensor 数据放到 Variable 变量中,用变量来更新神经网络中的参数。
import torch
from torch.autograd import Variable
tensor = torch.FloatTensor([[1, 2], [3, 4]])
# requires_grad为是否涉及到反向传播过程,True会计算反向传播梯度
variable = Variable(tensor, requires_grad=True)
print(tensor)
print(variable)
# 进行一些计算
t_out = torch.mean(tensor*tensor) # x^2
v_out = torch.mean(variable*variable)
print(t_out)
print(v_out)
只有在反向传播时才会有差别,而 tensor
不能反向传播,而 variable
可以,为搭建图的信息。我们对 v_out
进行反向传递,而 variable
会受影响,因为这是一套体系,结点间相互联系。
v_out.backward() # 误差的反向传递
# v_out = 1/4*sum(var*var)
# d(v_out)/d(var) = 1/4*2*variable = variable/2
print(variable.grad) # 查看反向传播后的梯度更新值
print(variable) # 可以看variable中的信息
print(variable.data) # variable包含哪些data
# 如果要转换成numpy,则需先将variable转换为tensor
print(variable.data.numpy())
激励函数
我们的任务通常是非线性的,因此需要用激励函数将线性的转换为非线性的。激励函数让神经网络可以描述非线性问题的步骤,使神经网络变得更强大。
Torch 中的激励函数有很多, 不过我们平时要用到的就这几个 relu, sigmoid, tanh, softplus
将神经网络输出的结果代入到激励函数中,输出一个新的结果,是一种非线性化手段。
引入神经网络模块和画图模块
import torch
import torch.nn.functional as F # nn是神经网络模块
from torch.autograd import Variable
import matplotlib.pyplot as plt # python 的可视化模块
首先生成数据
x =torch.linspace(-5, 5, 200) # -5到5的线段中取200个点
x = Variable(x)
# torch的数据格式无法被matplot识别,要转换为numpy
x_np = x.data.numpy()
激励函数。softplus
做概率图,分类概率,不能被线图呈现
y_relu = F.relu(x).data.numpy()
y_sigmoid = F.sigmoid(x).data.numpy()
y_tanh = F.tanh(x).data.numpy()
y_softplus = F.softplus(x).data.numpy()
画图
plt.figure(1, figsize=(8, 6))
plt.subplot(221)
plt.plot(x_np, y_relu, c='red', label='relu')
plt.ylim((-1, 5))
plt.legend(loc='best')
plt.subplot(222)
plt.plot(x_np, y_sigmoid, c='red', label='sigmoid')
plt.ylim((-0.2, 1.2))
plt.legend(loc='best')
plt.subplot(223)
plt.plot(x_np, y_tanh, c='red', label='tanh')
plt.ylim((-1.2, 1.2))
plt.legend(loc='best')
plt.subplot(224)
plt.plot(x_np, y_softplus, c='red', label='softplus')
plt.ylim((-0.2, 6))
plt.legend(loc='best')
plt.show()