小白学PyTorch | 1 搭建一个超简单的网络

2024-03-22 16:24:39
终于在微信公众号里找到一个不错的教程,可以从入门到熟练学习PyTorch
参考文章小白学PyTorch | 1 搭建一个超简单的网络

文章目录

  1. 任务
  2. 实现思路
  3. 实现过程
    3.1 引入必要的库
    3.2 创建训练集
    3.3 搭建网络
    3.4 设置优化器
    3.5 训练网络
    3.6 测试

搭建一个超简单的网络流程图

1. 任务

首先介绍一下我们搭建网络的要完成的学习任务:让我们的神经网络学会逻辑异或运算,异或运算的运算法则就是“相同取0,不同取1”。

对于异或运算(⊕,exclusive),我开始不是很记得清楚为什么相同取0,不同取1,可以从名字来分析,看英文,exclusive是排它的意思,可以得知这个运算所期望的是排他的一个输入,于是,当两个输入是不同的两个数字的时候,结果就会输出为1,也就是说达到了这个运算所期望的。从中文也可以理解,带有一个“异”,也就是说期望有不同的输入,于是当两个输入为不同的数字的时候,结果为1。

解析我们的需求,也就是有两个输入,总共可以知道有4种情况:

输入1 输入2 输出
0 0 0
0 1 1
1 0 1
1 1 0

2. 实现思路

从上面分析可以知道,我们的有两个输入,一个输出,所以我们需要在输入层设置两个输入节点,输出层设置一个输出节点。因为这个异或操作的实现逻辑很简单,所以我们的网络的隐含层设置10个节点就可以的达到不错的效果了。隐含层的激活函数我们采用ReLU函数,输出层我们用Sigmoid函数,让输出保持在0到1的一个范围内,如果输出大于0.5,即可让输出结果为1,小于0.5,让输出结果为0。

什么是ReLU函数,什么是Sigmoid函数

3. 实现过程

我们使用简单的快速搭建法

什么是快速搭建法?

3.1 引入必要的库

import torch
import torch.nn as nn
import numpy as np

用pytorch当然要引入torch包,然后为了写代码方便,我们用nn来代替torch包中的nn,nn这个包的名称就是neural network的缩写,专门用来搭建神经网络的一个包。因为需要创建矩阵作为输入,所以引入了numpy

3.2 创建训练集

x =np.mat(
  '0 0;'
  '0 1;'
  '1 0;'
  '1 1'
)
x = torch.tensor(x).float()
y = np.mat(
  '1;'
  '0;'
  '0;'
  '1'
)
y = torch.tensor(y).float()

参考文章的笔者说他个人比较喜欢实用np.mat这种方式构建矩阵,感觉写法比较简单,好吧,你说简单,那我也就只有跟着你一起写咯,毕竟其他的我也不会,qwq。他说,用其他的凡是构建矩阵也是可以的,但是一定要注意构建完矩阵一定要有这一步torch.tensor(x).float(),必须要把我们所创建的矩阵转化成tensor张量。

总之就记住吧,这个torch.tensor(x).float()命令的作用就是将我们的所构建的x矩阵转化为tensor张量,但是为什么第二个'.'后面的东西是float()?这玩意也不是表示矩阵呀,而是浮点型,不是吗?这是我所不能理解的,就留着这个疑问吧,之后再解决,继续往下看。

好,接下来原文作者开始解释了,什么是tensor呢?我们可以简单的把它理解为torch中用的一种变量,我们想要用torch这个框架就必须将我们的变量转化为tensor张量。而我们这个神经网络会要求你的输入和输出必须是float浮点型的,指的是tensor变量中的浮点型,而我们用的np.mat所创建的输入是int型的,转换成tensor也会对应转换成tensor的int型,所以要在后面加个.float(),将我们利用np.mat()创建的int型矩阵转换为浮点型矩阵。

这样我们就构建完了神经网络的输入和输出,分别是x矩阵和y矩阵(但我怎么觉得如果是异或操作的话,这输出是写反了啊),x是四行二列的一个矩阵,他的每一行是一个输入,一次输入两个值,这里,我们在构建矩阵的时候已经将所有的情况都列了出来。输出y是一个四行一列的矩阵,每一行都是一个输出,对应x矩阵的每一行的输入

3.3 搭建网络

myNet = nn.Sequential(
  nn.Linear(2,10),
  nn.ReLU(),
  nn.Linear(10,1),
  nn.Sigmoid()
)
print(myNet)

咱就是想问啊,这个seuential的首字母是必须大写不?后面再用ai查一下吧

输出结果:

Sequential(
  (0): Linear(in_feartures=2, out_features=10, bias=True)
  (1): ReLU
  (2): Linear(in_feartures=10, out_features=1, bias=True)
  (3): Sigmoid()
)

我们使用nn包中的Sequentail搭建网络,这个函数可以让我们如同搭积木一般的搭建神经网络。

为什么它可以啊?
也就是说Sequential这个函数,使用它的时候代码是nn.Sequentail(),这样就已经暗示了这个函数是nn包下的一个函数

nn.Linear(2,10)这行代码的在这里是用于搭建输入层,里面的2带边输入节点个数,10代表输出节点个数。Linear英文很简单嘛,都知道是线性的意思,意思就是这层不包括任何其他的激活函数,寓意着你输入啥它就给你输出啥。
nn.ReLU()这行代码代表一个激活函数层,跟着刚刚的Linear()nn.ReLU()函数就表示着把刚才的2个节点的输入扔到ReLU函数中去。接着又来了一个Linear,最后再将ReLU的输出扔到Sigmoid函数中区。
2,10,1就分别代表了三个层的个数,简单明了。

不是哥,汗流浃背了,怎么没看懂2,10,1是代表三个层的个数呢,这个不应该是两层然后,两个输入输出吗分别是2-10,10-1,我这理解没问题吧?行,先往后看吧

3.4 设置优化器

optimzer = torch.optim.SGD(myNet.parameters(),lr=0.05)
loss_func = nn.MSELoss()

怎么理解这一步呢?你需要有一个优化的方法来训练你的网络,所以这步设置了我们所要采用的优化方法。
torch.optim.SGD的意思就是采用SGD(随机梯度下降)方法来训练,你只需要把你网络的参数和学习率穿进去就可以了,分别是myNet.paramterslrloss_func这句设置了代价函数,因为我们的这个问题比较简单,所以采用了MSE,也就是均方误差代价函数

代价函数也就是损失函数吧。
这里定义了loss_func这个变量,nn.MSEloss()这个函数是怎样运行的呢

3.5 训练网络

for epoch in range(5000):
  out = myNet(x)
  loss = loss_func(out,y)
  optimzer.zero_grad()
  loss.backward()
  optimzer.step()

我这里设置了一个5000次的循环(可能不需要这么多次),让训练的动作迭代5000次。每一次的输出直接用myNet(x),把输入扔进你的网络就得到了输出out(就是这么简单粗暴!),然后用代价函数和你的标准输出y求误差。清楚梯度的那一步是为了每一次重新迭代的时候清楚上一次所求出的梯度,你就把这一步就行,初学不用理解太深。loss.backward()当然就是让误差反向传播,接着optimzer.step()也就是让我们刚刚设置的优化器开始工作

东西一多就要开始慢慢理才清楚得了了,这个out是怎么突然蹦出来的。loss又是在哪里定义的,optimzer.zero_grad()就是清楚梯度是吧,大概读得懂,根据这个zero和grad。这个应该是python的一个基础吧,上一行函数的输出可以直接到下一行来,主要是optimzer.zero_grad()这玩意在前面也没有定义啊。先这样吧,先大致理解着。

3.6 测试

print(myNet(x).data)

运行结果:

tensor([
  [0.9330],
  [0.0461],
  [0.0446],
  [0.9546]]
)

可以看到这个结果已经非常接近我们所期待的结果了,原文笔者说我们可以换个数据测试,结果也会是相似的,这里简单解释为什么我们的代码末尾加上了一个.data,因为我们的tensor变量其实是包含两个部分的,一部分是tensor数据,另一部分是tensor的自动求导参数,我们加上.data的意思是输出取tensor中的数据,如果不加的话输出会变成下面这样:

tensor([
  [0.9330],
  [0.0461],
  [0.0446],
  [0.9546], grad_fn=<SigmoidBackward>]
)

喂(#`O′),笔者没有解释最后为什么会出现那一串东西呀,后面再看看吧

2024-03-22 18:04:08 完美运行

3.7如何可以进一步的学习好这个代码

posted @ 2024-03-22 17:54  MoonSheep|  阅读(744)  评论(0)    收藏  举报