简单探究神经网络中权重、偏置维度的关系

利用PyTorch的tensor和autograd实现一个简单的神经网络,探究神经网络中权重、偏置维度的关系

  • 简单神经网络的分析和实现
    • 本次目标
    • 项目环境
    • 神经网络手绘图
    • 代码实现

简单神经网络的分析和实现

本次目标

利用PyTorch的tensor(向量)和autograd(自动求导)实现一个简单神经网络。
神经网络的目标是利用双层神经网络实现对正弦波的拟合。
重点是探究神经网络中各个神经元中权重的维度、每个神经元输出的维度,每个神经元输入的维度及其关系

项目环境

在线开发平台jupyter notebook

神经网络手绘图

(注意各个神经元中权重的维度、每个神经元输出的维度,每个神经元输入的维度)
此图忽略了每一层的激活函数tanh
简单探究神经网络中权重、偏置维度的关系_第1张图片

  1. 符号的含义
  • W[1]2 ,b[1]2,Z[1]2 表示第一层神经网络的第二个神经元的权重、偏置、输出
  • W[1] ,b[1] 表示第一层神经网络的整体权重、整体偏置。其实就是所有神经元的权重放一个矩阵里,方便计算。
  1. 预处理:
    首先x是一个实数,也可以说是一个(1x1)的矩阵,先分别将其进行预处理,得到一次方,二次方,三次方,并作为输入喂给神经网络。(此处不必纠结为什么是平方和三次方,您也可以四次方五次方)
  2. 第一层网络(注意上标和下标的含义)
    神经网络的第一层有四个神经元,第 i 个神经元有自己的权重和偏置W[1]i ,b[1]i ,i ∈[1~4],该层每个神经元的输入都是一个形状3x1的矩阵 x[1] = [[x],[x2],[x3]],通过Z[1]i = W[1]i *x[1]i + b[1]i 得到第 i 个神经元的输出Z[1]i ,Z[1]i 都是1x1的矩阵,由矩阵乘法的规则可以知道第 i 个神经元的权重W[1]i 的形状是1x3,通过计算四个神经元的输出,得到第一层的输出,如下图:
    简单探究神经网络中权重、偏置维度的关系_第2张图片

我们知道在编程中肯定不用for循环依次得到每个神经元的值,所以我们就可以将第一层每个神经元的权重组合,得到一个整体权重。其实就是每个神经元的权值作为行向量组合在一起,这样就可以通过一次的矩阵乘法和加法得到第一层神经网络的输出(而不是通过四次矩阵乘法和加法得到四个神经元的输出再组合)如下:
简单探究神经网络中权重、偏置维度的关系_第3张图片

  1. 第二层网络
    第一层的输出,也就是第二层的输出是一个形状4x1的矩阵Z[1] = [ [Z[1]1 ],[Z[1]2],[Z[1]3],[ Z[1]4 ] ],第二层只有一个神经元,只有一个权重W[2]和偏置b[2] ,第二层的输出Z[2]是一个1x1的矩阵,由Z[2] =W[2] *Z[1]i + b[1]i 可知W[2] 是一个1x4的矩阵,最终第二层的输出就是神经网络的输出
    如下图所示:
    简单探究神经网络中权重、偏置维度的关系_第4张图片

代码实现

1、 进入jupyter notebook,建立新项目,没使用过jupyter的小伙伴建议看一下jupyter notebook的使用方法。
2、代码详解

  • import 必要的包
import torch #torch的库
import torch.nn.functional as F #激活函数的库
  • 准备训练集,这里准备了1个数据(哈哈),[5,sin(5)]
dtype = torch.float
device = torch.device('cpu')
#x1 = [5]
x1 = torch.tensor(([5]),device=device,dtype=dtype,requires_grad=True).reshape(1,1)
#x1 = torch.linspace(-3,3,100,device=device,dtype=dtype,requires_grad=True).reshape(1,100)扩大训练集使用
y = torch.sin(x1)
y.require_grad=True
  • 预处理
x2 = x1.pow(2)
x3 = x1.pow(3)
X = torch.cat([x1,x2,x3],dim=0)
  • 神经网络中的参数(权重和偏置),学习率
W1 = torch.rand((4,3),device=device,dtype=dtype,requires_grad=True)
b1 = torch.rand((4,1),device=device,dtype=dtype,requires_grad=True)
W2 = torch.rand((1,4),device=device,dtype=dtype,requires_grad=True)
b2 = torch.rand((1,1),device=device,dtype=dtype,requires_grad=True)
rate=1e-2
  • 针对于这一个训练数据训练1000次
for i in range(1000):
	#第一层
    z1=torch.mm(W1,X)+b1
    a1=F.tanh(z1)#这里是手绘图中忽略的激活函数,简单来讲就是把第一层的输出矩阵Z1中,每个元素k替换为对应的tanh(k)
    #第二层
    z2=torch.mm(W2,a1)+b2
    a2=F.tanh(z2)
    #------------------------------------
    #损失函数,(神经网络的输出-y)的平方
    loss = (a2-y).pow(2).sum()
    #loss = (a2-y).pow(2).mean()扩大训练集使用
    if(i%100 == 99):
        print(i,loss)
    loss.backward(retain_graph=True)#反向传播,这里就用到了自动求导
    #梯度下降
    with torch.no_grad():#no_grad使得下面的运行不参与pytorch的计算图
        W1 -= rate*W1.grad
        b1 -= rate*b1.grad
        W2 -= rate*W2.grad
        b2 -= rate*b2.grad
        W1.grad=None
        W2.grad=None
        b1.grad=None
        b2.grad=None
  • 输出,可见神经网络的输出越来越接近sin(x)。
99 0.030371811240911484
199 0.006001389119774103
299 0.0027351940516382456
399 0.0015780997928231955
499 0.0010207908926531672
599 0.0007067644619382918
699 0.0005119863199070096
799 0.0003830592904705554
899 0.000293625402264297
999 0.00022934767184779048
  • 由于我们的权重是随机的,所以看官们的输出与我不同,如果效果不明显,您可以将学习率调大或者将训练集扩大,训练集扩大的方式是在上述代码中,找到下列两行代码,将其注释符号去掉,并且将该语句上面的一行的代码注释掉
#x1 = torch.linspace(-3,3,100,device=device,dtype=dtype,requires_grad=True).reshape(1,100)扩大训练集使用
#loss = (a2-y).pow(2).mean()扩大训练集使用
  • 本次主要是新人(我)探究神经网络中各个权重、偏置的维度的关系,以及能够简单使用pytorch写出代码,如有错误,请在评论区指正,谢谢!

你可能感兴趣的:(神经网络,pytorch)