import torch
import torch.nn as nn
import numpy as np
#1 任务 有监督学习
# 首先说下我们要搭建的网络要完成的学习任务:让我们的神经网络学会逻辑异或运算,异或运算也就是俗称的“相同取0,不同取1” 。
# 再把我们的需求说的简单一点,也就是我们需要搭建这样一个神经网络,让我们在输入(1,1)时输出0,输入(1,0)时输出1(相同取0,不同取1),以此类推。
#2 实现思路
# 因为我们的需求需要有两个输入,一个输出,所以我们需要在输入层设置两个输入节点,输出层设置一个输出节点。
# 因为问题比较简单,所以隐含层我们只需要设置10个节点就可以达到不错的效果了,
# 隐含层的激活函数我们采用ReLU函数,输出层我们用Sigmoid函数,让输出保持在0到1的一个范围,如果输出大于0.5,即可让输出结果为1,小于0.5,让输出结果为0.
# 构建输入集
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()
# 搭建网络,我们使用nn包中的Sequential搭建网络,这个函数就是那个可以让我们像搭积木一样搭神经网络的一个东西。
myNet = nn.Sequential(
nn.Linear(2,10), #意思搭建输入层,里面的2代表输入节点个数,10代表输出节点个数.Linear也就是英文的线性,意思也就是这层不包括任何其它的激活函数,你输入了啥他就给你输出了啥。
nn.ReLU(), #nn.ReLU()这个就代表把一个激活函数层,把你刚才的输入扔到了ReLU函数中去。
nn.Linear(10,1), #接着又来了一个Linear,最后再扔到Sigmoid函数中去。
nn.Sigmoid()
)
print(myNet)
# 对这一步的理解就是,你需要有一个优化的方法来训练你的网络,所以这步设置了我们所要采用的优化方法。
# torch.optim.SGD的意思就是采用SGD(随机梯度下降)方法训练,你只需要把你网络的参数和学习率传进去就可以了,分别是myNet.paramets和lr。
# loss_func这句设置了代价函数,因为我们的这个问题比较简单,所以采用了MSE,也就是均方误差代价函数。
optimzer = torch.optim.SGD(myNet.parameters(),lr=0.05)
loss_func = nn.MSELoss()
# 我这里设置了一个5000次的循环(可能不需要这么多次),让这个训练的动作迭代5000次。
# 每一次的输出直接用myNet(x),把输入扔进你的网络就得到了输出out(就是这么简单粗暴!),然后用代价函数和你的标准输出y求误差。
# zero_grad() 清除梯度的那一步是为了每一次重新迭代时清除上一次所求出的梯度,你就把这一步记住就行,初学不用理解太深。
# loss.backward()当然就是让误差反向传播,接着optimzer.step()也就是让我们刚刚设置的优化器开始工作。
#
#
for epoch in range(5000):
out = myNet(x) # 输入x带入网络模型
#下面4行是对网络进行梯度下降计算
loss = loss_func(out,y) # 第一步,定义计算误差的函数;要有模型计算出来的值out与真实值y的均方误差(计算值和真实值之间的差距,越小代表越接近)
optimzer.zero_grad() # 第二步,清除梯度,初始化;每次循环的梯度不需要关联;
loss.backward() # 第三步,反向传播的方式执行第一步的函数;
optimzer.step() #第四步,开始执行梯度下降计算,误差收敛
# 可以看到这个结果已经非常接近我们期待的结果了 1 0 0 1
print(myNet(x).data)
Sequential(
(0): Linear(in_features=2, out_features=10, bias=True)
(1): ReLU()
(2): Linear(in_features=10, out_features=1, bias=True)
(3): Sigmoid()
)
tensor([[0.9537],
[0.0529],
[0.0532],
[0.9523]])
Process finished with exit code 0