pytorch实现两层神经网络

  • 1.神经网络结构图(出发点)
  • 2.pytorch代码
  • 3.程序结果
  • 4.pytorch程序改进(自动求梯度)
  • 5.pytorch程序再改进(创建model)
  • 6.参考文章


之前的版本使用的是numpy实现的两层神经网络,里边的一些方法难免和pytorch中的方法有些不一样,下面我们先列出torch中会用到的一些运算:

# pytorch中
## 内积
# tensor.mm(tensor)
## 转置
# tensor.t()
## 乘方运算
# tensor.pow(n)

1.神经网络结构图(出发点)

pytorch构建MLP分类mnist pytorch cnn mnist_pytorch

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值

pytorch构建MLP分类mnist pytorch cnn mnist_神经网络_02

pytorch构建MLP分类mnist pytorch cnn mnist_数据_03

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实现全连接神经网络