NNDL 作业四

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])] #权重初始值

初始值只会影响网络速度,结果影响小。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值