1.过程推导 - 了解BP原理
2.数值计算 - 手动计算
3.实现例题中的前馈神经网路
(1)使用numpy实现(不使用DL框架)
import numpy as np
w1,w2,w3,w4,w5,w6,w7,w8=0.2,-0.4,0.5,0.6,0.1,-0.5,0.3,0.8
x1,x2=0.5,0.3
y1,y2=0.23,-0.07
print('输入:',x1,x2)
print('标注信息:',y1,y2)
print('权重:',round(w1,2),round(w2,2),round(w3,2),round(w4,2),round(w5,2),round(w6,2),round(w7,2),round(w8,2))
def sigmoid(z):
m=1/(1+np.exp(-z))
return m
def forward(x1,x2,y1,y2,w1,w2,w3,w4,w5,w6,w7,w8):
In_h1=w1*x1+w3*x2
h1=sigmoid(In_h1)
In_h2 = w2 * x1 + w4 * x2
h2 = sigmoid(In_h2)
In_o1 = w5 * h1 + w7 * h2
o1 = sigmoid(In_o1)
In_o2 = w6 * h1 + w8 * h2
o2 = sigmoid(In_o2)
print('隐藏层:',round(h1,5),round(h2,5),end=',')
print('预测:', round(o1, 5), round(o2, 5), end=',')
error=(1/2)*(o1-y1)**2+(1/2)*(o2-y2)**2
print('loss:',round(error,5))
return o1,o2,h1,h2,
def backward(o1,o2,h1,h2,y1,y2,x1,x2,w5,w6,w7,w8):
grad_o1=o1-y1
grad_o2=o2-y2
grad_w1=(grad_o1*o1*(1-o1)*w5+grad_o2*o2*(1-o2)*w6)*h1*(1-h1)*x1
grad_w2=(grad_o1*o1*(1-o1)*w7+grad_o2*o2*(1-o2)*w8)*h2*(1-h2)*x1
grad_w3=(grad_o1*o1*(1-o1)*w5+grad_o2*o2*(1-o2)*w6)*h1*(1-h1)*x2
grad_w4=(grad_o1*o1*(1-o1)*w7+grad_o2*o2*(1-o2)*w8)*h2*(1-h2)*x2
grad_w5=grad_o1*o1*(1-o1)*h1
grad_w6 = grad_o2 * o2 * (1 - o2) * h1
grad_w7 = grad_o1 * o1 * (1 - o1) * h2
grad_w8 = grad_o2 * o2 * (1 - o2) * h2
print('w的梯度:',round(grad_w1,2),round(grad_w2,2),round(grad_w3,2),round(grad_w4,2),round(grad_w5,2),round(grad_w6,2),round(grad_w7,2),round(grad_w8,2),end=',')
return grad_w1,grad_w2,grad_w3,grad_w4,grad_w5,grad_w6,grad_w7,grad_w8
def update_w(w1,w2,w3,w4,w5,w6,w7,w8):
step=1
w1=w1-step*grad_w1
w2 = w2 - step * grad_w2
w3 = w3 - step * grad_w3
w4 = w4 - step * grad_w4
w5 = w5 - step * grad_w5
w6 = w6 - step * grad_w6
w7 = w7 - step * grad_w7
w8 = w8 - step * grad_w8
return w1,w2,w3,w4,w5,w6,w7,w8
if __name__=='__main__':
for i in range(5):
print('\n--第' + str(i + 1) + '轮--')
o1,o2,h1,h2=forward(x1,x2,y1,y2,w1,w2,w3,w4,w5,w6,w7,w8)
grad_w1,grad_w2,grad_w3,grad_w4,grad_w5,grad_w6,grad_w7,grad_w8=backward(o1,o2,h1,h2,y1,y2,x1,x2,w5,w6,w7,w8)
w1, w2, w3, w4, w5, w6, w7, w8=update_w(w1,w2,w3,w4,w5,w6,w7,w8)
print('更新后权重:',round(w1,2),round(w2,2),round(w3,2),round(w4,2),round(w5,2),round(w6,2),round(w7,2),round(w8,2))
步长为1,次数为5:
步长为0.1,次数为5
步长小时,次数相同,权重更加接近手动计算的结果,但损失较大
步长为0.1,次数为500
步长相同,次数不同时,损失更少。
(2)使用pytorch实现
import torch
lx = [0.5,0.3] # 输入值
ly = [0.23,-0.07] # 输入数据标注信息
print('输入值:',lx[0],lx[1])
print('输入数据标注信息:',ly[0],ly[1])
w=[torch.tensor([0.2]),torch.tensor([-0.4]),torch.tensor([0.5]),torch.tensor([0.6]),torch.tensor([0.1]),torch.tensor([-0.5]),torch.tensor([-0.3]),torch.tensor([0.8])]
for i in range(0,8):
w[i].requires_grad = True # 是否求梯度
for i in range(0,8):
print(w[i].data,end=',')
def forward(x):
In_h1 = w[0] * x[0] + w[2] * x[1]
h1=torch.sigmoid(In_h1)
In_h2 = w[1] * x[0] + w[3] * x[1]
h2 = torch.sigmoid(In_h2)
In_o1 = w[4] * h1 + w[6] * h2
o1 = torch.sigmoid(In_o1)
In_o2 = w[5] * h1 + w[7] * h2
o2 = torch.sigmoid(In_o2)
print('正向输出隐层:',end=',')
print(h1, h2)
print('正向输出预测值:',end=',')
print(o1,o2)
return o1,o2
def loss(x,y):
y_pred=forward(x)
Error=0.5*(y_pred[0]-y[0])**2+0.5*(y_pred[1]-y[1])**2
print('损失的loss为:',Error.item())
return Error
for j in range(1):
print('\n--第' + str(j + 1) + '轮--')
l=loss(lx,ly)
l.backward() # 求梯度,存起来
print('w的梯度:',end=' ')
for i in range(0,8):
print(round(w[i].grad.item(),2),end=',')
step=1 # 步长
for i in range(0,8):
print('\tgrad W:',w[i].grad.item())
w[i].data = w[i].data - step * w[i].grad.data
w[i].grad.data.zero_() # 梯度清零
print('更新后的权重:')
for i in range(0,8):
print(w[i].data, end=',')
步长为1,次数为1
步长为1,次数为5
步长为0.1,次数为5
步长小时,次数相同,权重更加接近手动计算的结果,但损失较大
步长为0.1,次数为500
步长相同,次数不同时,损失更少。
问题:
1.比较pytorch和numpy实现前馈神经网络
答:pytorch的代码量更少,因为本身含有反向传播的函数可以直接调用,梯度都逐渐减小,得到一个优解,我个人认为使用torch更为精确。
2.激活函数sigmoid和pytorch自带函数torch.sigmoid(),观察,总结并陈述。
答:这个函数接受一个张量作为输入,返回相同形状的张量。torch.sigmoid()的损失更少,当轮次相同,权重更新的更快。h1和h2两个输出相同,到后面有一丝差别。
3.激活函数sigmoid()改变Relu,和观察,总结并陈述。
Relu(x)=max(0,x)
梯度快速下降,收敛速度更快,Relu函数,当输入值小于0时,ReLU函数的输出为0,这意味着ReLU函数可以激活稀疏性,运算量不同导致收敛速度不同。
4.损失函数MSE用pytorch自带函数t.nn.MSELoss()替代,观察,总结并陈述。
原代码的收敛结果比自带函数torch.nn.MSELoss好
5.损失函数MSE改变为交叉熵,观察,总结并陈述。
MSE主要用于回归问题,检测最优化预测值与真实值之间的平方差,而交叉熵用于分类问题,输出0或1,交叉熵结果出现更多的负数,因为交叉熵有个负对数。
def loss_fuction(x1, x2, y1, y2):
y1_pred, y2_pred = forward(x1, x2)
loss_func = torch.nn.CrossEntropyLoss() # 创建交叉熵损失函数
y_pred = torch.stack([y1_pred, y2_pred], dim=1)
y = torch.stack([y1, y2], dim=1)
loss = loss_func(y_pred, y) # 计算
print("损失函数(交叉熵损失):", loss.item())
return loss
6.改变步长,训练次数,观察总结并陈述。
步长为1,次数为1:
次数为500
步长为0.1,次数为1
次数为500
step小时,速度减慢,适当调大,加快收敛速度,达到效果
7.权值初始换为随机数,对比结果,观察,总结,并陈述。
w = [torch.randn(1, 1), torch.randn(1, 1), torch.randn(1, 1), torch.randn(1, 1), torch.randn(1, 1), torch.randn(1, 1), torch.randn(1, 1), torch.randn(1, 1)] #权重初始值
初始值只会影响网络速度,不会影响结果
8.权值换为0,观察,总结,陈述
w = [torch.tensor([0.0]),torch.tensor([0.0]),torch.tensor([0.0]), torch.tensor([0.0]),torch.tensor([0.0]),torch.tensor([0.0]),torch.tensor([0.0]),torch.tensor([0.0])] #权重初始值
初始值只会影响网络速度,结果影响小。