pytorch实现两层神经网络
- 1.神经网络结构图(出发点)
- 2.pytorch代码
- 3.程序结果
- 4.pytorch程序改进(自动求梯度)
- 5.pytorch程序再改进(创建model)
- 6.参考文章
之前的版本使用的是numpy实现的两层神经网络,里边的一些方法难免和pytorch中的方法有些不一样,下面我们先列出torch中会用到的一些运算:
# pytorch中
## 内积
# tensor.mm(tensor)
## 转置
# tensor.t()
## 乘方运算
# tensor.pow(n)
1.神经网络结构图(出发点)
2.pytorch代码
此部分来说相对比较简单,因为流程还是一样的,需要的就是将numpy中的一些方法替换为torch中的方法
# @Time : 2020/5/9 13:51
# @Author : kingback
# @File : pytorch_practice01.py
# @Software: PyCharm
import torch
import time
##使用pytorch实现之前使用numpy实现的两层神经网络
#此部分用于检测该程序运行多长时间
start=time.time()
device=torch.device("cpu")
#选择是使用cpu进行计算还是gpu
#device=torch.device("cuda")
#神经网络参数定义:
N,D_in,D_out,H=64,1000,10,100
# N:代表64个人
# D_in:代表每个人输入到神经网络1000个数据点
# D_out:代表每个人从神经网络输出10个数据点
# H:代表该神经网络含有100个隐藏层
x=torch.randn(N,D_in,device=device)
#定义输入到神经网络之前的数据矩阵,大小为64*1000
#这里需要注意的是我们需要指定device为我们刚刚设定好的device
y=torch.randn(N,D_out,device=device)
#定义从神经网络输出的的数据矩阵,大小为64*10
w_1=torch.randn(D_in,H,device=device)
#大小为1000*100
w_2=torch.randn(H,D_out,device=device)
#大小为100*10
learning_rate=1e-6
for it in range(500):
#forword pass
h=x.mm(w_1)
#numpy中的点乘np.dot是数学意义上的向量内积
#print(h.shape)
#打印矩阵维度信息
h_relu=h.clamp(min=0)
#定义relu 函数,在pytorch中使用.clamp方法
y_hat=h_relu.mm(w_2)
#大小为64*10
#计算损失compute loss
loss=(y_hat-y).pow(2).sum()
#估计值与真实值之间差值的平方和再取和,替换numpy的square方法
print(it,loss)
#计算梯度,主要是对(y_hat-y)^2求各项偏导
y_hat_grad=2*(y_hat-y)
w_2_grad=h_relu.t().mm(y_hat_grad)
h_relu_grad=y_hat_grad.mm(w_2.t())
h_grad=h_relu_grad.clone()
h_grad[h<0]=0
w_1_grad=x.t().mm(h_grad)
#更新w_1和w_2的权值
w_1=w_1-learning_rate*w_1_grad
w_2=w_2-learning_rate*w_2_grad
end=time.time()
print('Running time: %s Seconds'%(end-start))
#输出此程序使用时间
3.程序结果
程序开始时loss值 | 程序结束时loss值 |
4.pytorch程序改进(自动求梯度)
上边的程序我们是自己求各参数的梯度,其实torch已经提供了方法自动求取其梯度,我们只需再对以上程序作一些改进即可:
# @Time : 2020/5/9 16:40
# @Author : kingback
# @File : pytorch_practice02.py
# @Software: PyCharm
import torch
import time
##使用pytorch实现两层神经网络,
## 本程序采用自动求偏导,不再人为求,相对来说简单一些
#此部分用于检测程序运行了多长时间
start=time.time()
#选择是使用cpu进行计算还是gpu
device=torch.device("cpu")
# device=torch.device("cuda")
dtype=torch.float
#定义一下数据类型
#神经网络参数定义:
N,D_in,D_out,H=64,1000,10,100
# N:代表64个人
# D_in:代表每个人输入到神经网络1000个数据点
# D_out:代表每个人从神经网络输出10个数据点
# H:代表该神经网络含有100个隐藏层
x=torch.randn(N,D_in,device=device,dtype=dtype)
#定义输入到神经网络之前的数据矩阵,大小为64*1000
#这里需要注意的是我们需要指定device为我们刚刚设定好的device
y=torch.randn(N,D_out,device=device,dtype=dtype)
#定义从神经网络输出的的数据矩阵,大小为64*10
w_1=torch.randn(D_in,H,device=device,dtype=dtype,requires_grad=True)
#大小为1000*100
w_2=torch.randn(H,D_out,device=device,dtype=dtype,requires_grad=True)
#大小为100*10,在这里需要声明一下w1和w2两个参数需要梯度
learning_rate=1e-6
#定义学习率
for it in range(500):
#forword pass
h=x.mm(w_1)
#numpy中的点乘np.dot是数学意义上的向量内积
#print(h.shape)
#打印矩阵维度信息
h_relu=h.clamp(min=0)
#定义relu 函数,在pytorch中使用.clamp方法
y_hat=h_relu.mm(w_2)
#大小为64*10
#计算损失compute loss
loss=(y_hat-y).pow(2).sum()
#估计值与真实值之间差值的平方和再取和,替换numpy的square方法
print(it,loss.item())
#此时的loss是只有一个数的tensor,我们可以使用.item()将其值转为数字
loss.backward()
# PyTorch给我们提供了autograd的方法做反向传播。如果一个Tensor的requires_grad=True,
# backward会自动计算loss相对于每个Tensor的gradient。在backward之后,
# w_1.grad和w_2.grad会包含两个loss相对于两个Tensor的gradient信息。
with torch.no_grad():
w_1-=learning_rate*w_1.grad
w_2-=learning_rate*w_2.grad
#梯度清零,否则会出现累加效应
w_1.grad.zero_()
w_2.grad.zero_()
end = time.time()
print('Running time: %s Seconds' % (end - start))
这里的程序结果我就不再列出了,和上边的结果一样的。哈哈~
5.pytorch程序再改进(创建model)
我们经常看到别人的模型都是使用torch训练一个model,那么我们的这个可不可以呢?答案当然是肯定的,下面我们介绍使用torch.nn来创建模型。
PyTorch autograd使定义计算图形和计算梯度变得很容易,但是对于定义复杂的神经网络来说,原始autograd可能太低级了;这就是nn包可以提供帮助的地方。nn包定义了一组模块, 您可以将其视为一个神经网络层,它从输入生成输出,并且可能具有一些可训练的权重。
# @Time : 2020/5/9 23:00
# @Author : kingback
# @File : pytorch_practice03.py
# @Software: PyCharm
#PyTorch autograd使定义计算图形和计算梯度变得很容易,但是对于定义复杂的神经网络来说,
# 原始autograd可能太低级了;这就是nn包可以提供帮助的地方。nn包定义了一组模块,
# 您可以将其视为一个神经网络层,它从输入生成输出,并且可能具有一些可训练的权重。
import torch
#神经网络参数定义:
N,D_in,D_out,H=64,1000,10,100
# N:代表64个人
# D_in:代表每个人输入到神经网络1000个数据点
# D_out:代表每个人从神经网络输出10个数据点
# H:代表该神经网络含有100个隐藏层
device=torch.device("cpu")
dtype=torch.float
x=torch.randn(N,D_in,device=device,dtype=dtype)
#定义输入到神经网络之前的数据矩阵,大小为64*1000,这里需要注意的是我们需要指定device为我们刚刚设定好的device
y=torch.randn(N,D_out,device=device,dtype=dtype)
#定义从神经网络输出的的数据矩阵,大小为64*10
#使用nn包将我们的模型定义为一个层序列。神经网络。Sequential是一个包含其他模块的模块,
# 并按顺序应用它们来产生它的输出。每个线性模块使用一个线性函数从输入计算输出,并保存内部张量的权重和偏差。
model=torch.nn.Sequential(
torch.nn.Linear(D_in,H),
torch.nn.ReLU(),
torch.nn.Linear(H,D_out),
)
# nn包还包含流行的损失函数的定义;在这种情况下,我们将使用均方误差(MSE)作为损失函数。
loss_fn=torch.nn.MSELoss(reduction="sum")
learning_rate=1e-04
for it in range(500):
#前向传递: 通过向模型传递x来计算预测y。模块对象覆盖了操作符,所以你可以像调用函数一样调用它们。当你这样做的时候,
# 你把一个输入数据的张量传递给模块,它就会产生一个输出数据的张量。
y_hat=model(x)
#计算和打印损失。我们传递包含y的预测值和真值的张量,损失函数返回一个包含损失的张量。
loss=loss_fn(y_hat,y)
if(it%10==9):
print(it,loss.item())
#在进行反向传播之前将梯度置为0
model.zero_grad()
#反向传播: 根据模型的所有可学习参数计算损失的梯度。在内部,每个模块的参数都存储在带有requires_grad = True的张量中,
# 因此这个调用将为模型中的所有可学习参数计算梯度。
loss.backward()
# 使用梯度下降更新权重。每个参数都是一个张量,所以我们可以像以前一样得到它的梯度。
with torch.no_grad():
for param in model.parameters():
param-=learning_rate*param.grad
6.参考文章
- 1.【Code】numpy、pytorch实现全连接神经网络