作业4:实现例题中的前馈神经网络

 

一、过程推导——了解BP原理


二、数值计算


三、代码实现


使用numpy实现
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("输入值 x0, x1:", x1, x2)
print("输出值 y0, y1:", y1, y2)


def sigmoid(z):
    a = 1 / (1 + np.exp(-z))
    return a

#前向传播
def forward_propagate(x1, x2, 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("隐藏层h1=",h1,"h2=",h2)
    print("预测值o1=",o1,"o2=",o2)

    error = (1 / 2) * (o1 - y1) ** 2 + (1 / 2) * (o2 - y2) ** 2
    print("损失函数",error)

    return o1, o2, h1, h2

# 反向传播
def back_propagate(o1,o2,h1,h2):

    d_w5 = (o1 - y1) * o1 * (1 - o1) * h1
    d_w6 = (o2 - y2) * o2 * (1 - o2) * h1
    d_w7 = (o1 - y1) * o1 * (1 - o1) * h2
    d_w8 = (o2 - y2) * o2 * (1 - o2) * h2

    d_w1 = ((o1 - y1) * o1 * (1 - o1) * w5 + (o2 - y2) * o2 * (1 - o2) * w6) * h1 * (1 - h1) * x1
    d_w2 = ((o1 - y1) *o1 * (1 - o1) * w7 + (o2 - y2) * o2 * (1 - o2) * w8) * h2 * (1 - h2) * x1
    d_w3 = ((o1 - y1) * o1 * (1 - o1) * w5 + (o2 - y2) * o2 * (1 - o2) * w6) * h1 * (1 - h1) * x2
    d_w4 = ((o1 - y1) * o1 * (1 - o1) * w7 + (o2 - y2) * o2 * (1 - o2) * w8) * h2 * (1 - h2) * x2

    print("w的梯度:d_w1=",d_w1,"d_w2=",d_w2, "d_w3=",d_w3, "d_w4=",d_w4, "d_w5=",d_w5, "d_w6=",d_w6, "d_w7=",d_w7, "d_w8=",d_w8)

    return d_w1, d_w2, d_w3, d_w4, d_w5, d_w6, d_w7, d_w8


def update_w(w1, w2, w3, w4, w5, w6, w7, w8):
    # 步长
    step = 1
    w1 = w1 - step * d_w1
    w2 = w2 - step * d_w2
    w3 = w3 - step * d_w3
    w4 = w4 - step * d_w4
    w5 = w5 - step * d_w5
    w6 = w6 - step * d_w6
    w7 = w7 - step * d_w7
    w8 = w8 - step * d_w8
    return w1, w2, w3, w4, w5, w6, w7, w8


if __name__ == "__main__":

    print("权值w1=",w1,"w2=",w2, "w3=",w3, "w4=",w4, "w5=",w5, "w6=",w6, "w7=",w7, "w8=",w8)



    for i in range(5):
        print("=====第" + str(i+1) + "轮=====")
        o1, o2, h1, h2 = forward_propagate(x1, x2, w1, w2, w3, w4, w5, w6, w7, w8)
        d_w1, d_w2, d_w3, d_w4, d_w5, d_w6, d_w7, d_w8 = back_propagate(o1, o2, h1, h2)
        w1, w2, w3, w4, w5, w6, w7, w8 = update_w(w1, w2, w3, w4, w5, w6, w7, w8)

    print("更新后的权值w1=",w1,"w2=",w2, "w3=",w3, "w4=",w4, "w5=",w5, "w6=",w6, "w7=",w7, "w8=",w8)

运行结果: 

输入值 x0, x1: 0.5 0.3
输出值 y0, y1: 0.23 -0.07
权值w1= 0.2 w2= -0.4 w3= 0.5 w4= 0.6 w5= 0.1 w6= -0.5 w7= -0.3 w8= 0.8
=====第1轮=====
隐藏层h1= 0.5621765008857981 h2= 0.4950001666600003
预测值o1= 0.47694575860699684 o2= 0.5286964002912302
损失函数 0.2097097937078311
w的梯度:d_w1= -0.00842148046150221 d_w2= 0.012606653078458003 d_w3= -0.005052888276901326 d_w4= 0.007563991847074802 d_w5= 0.03463298928683772 d_w6= 0.08386609953820857 d_w7= 0.030494578556568334 d_w8= 0.07384466121071578
=====第2轮=====
隐藏层h1= 0.5635855084341747 h2= 0.4928573549015371
预测值o1= 0.46852995880225773 o2= 0.507207632428805
损失函数 0.19503259609013654
w的梯度:d_w1= -0.009881677937258563 d_w2= 0.010639538997404809 d_w3= -0.005929006762355137 d_w4= 0.006383723398442885 d_w5= 0.03347487045416149 d_w6= 0.08130956462065898 d_w7= 0.029273882775210872 d_w8= 0.07110547795750169
=====第3轮=====
隐藏层h1= 0.5652375137331292 h2= 0.4910491037080464
预测值o1= 0.46042362622378474 o2= 0.48642319040048887
损失函数 0.18135090716878854
w的梯度:d_w1= -0.011136617562339305 d_w2= 0.008804565414065013 d_w3= -0.006681970537403583 d_w4= 0.005282739248439008 d_w5= 0.03235701948492444 d_w6= 0.07856984139649568 d_w7= 0.028110104214062664 d_w8= 0.06825741260769976
=====第4轮=====
隐藏层h1= 0.5670975811306548 h2= 0.4895528919170278
预测值o1= 0.452605043776973 o2= 0.46642302621027565
损失函数 0.16865133428176904
w的梯度:d_w1= -0.012190984188369213 d_w2= 0.007115066380253227 d_w3= -0.007314590513021527 d_w4= 0.004269039828151936 d_w5= 0.03127612758065861 d_w6= 0.07570808633484445 d_w7= 0.02699944280233093 d_w8= 0.06535579385267748
=====第5轮=====
隐藏层h1= 0.5691315837214361 h2= 0.488343922155006
预测值o1= 0.4450557845148802 o2= 0.4472627559010082
损失函数 0.15690487454780833
w的梯度:d_w1= -0.01305497284092114 d_w2= 0.005577424919062039 d_w3= -0.007832983704552684 d_w4= 0.0033464549514372233 d_w5= 0.030229265485068435 d_w6= 0.07277887882948983 d_w7= 0.025938251351850346 d_w8= 0.062447989453055464
更新后的权值w1= 0.25468573299039043 w2= -0.4447432487892431 w3= 0.5328114397942342 w4= 0.5731540507264541 w5= -0.061970272291650697 w6= -0.8922324707196976 w7= -0.44081625970002314 w8= 0.45898866491834983

Process finished with exit code 0

使用pytorch实现
import torch

x = [0.5, 0.3]
y = [0.23, -0.07]

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_propagate(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("正向计算,隐藏层h1 ,h2:", end="")
    print(h1.data, h2.data)
    print("正向计算,预测值o1 ,o2:", end="")
    print(o1.data, o2.data)

    return o1, o2


def error(x, y):  # 损失函数
    y_pre = forward_propagate(x)  # 前向传播
    error = (1 / 2) * (y_pre[0] - y[0]) ** 2 + (1 / 2) * (y_pre[1] - y[1]) ** 2  # 考虑 : t.nn.MSELoss()
    print("损失函数:", error.item())
    return error


if __name__ == "__main__":
    for k in range(5):
        print("\n=====第" + str(k+1) + "轮=====")
        l = error(x, y)  # 前向传播,求 Loss,构建计算图
        l.backward()  # 反向传播,求出计算图中所有梯度存入w中. 自动求梯度,不需要人工编程实现。
        print("w的梯度: \n", end="  ")
        for i in range(0, 8):
            print(round(w[i].grad.item(), 2), end="  ")  # 查看梯度
        step = 1  # 步长
        for i in range(0, 8):
            w[i].data = w[i].data - step * w[i].grad.data  # 更新权值
            w[i].grad.data.zero_()  # 注意:将w中所有梯度清零
        print("\n更新后的权值w:")
        for i in range(0, 8):
            print(w[i].data, end="  ")

运行结果:  

=====第1轮=====
正向计算,隐藏层h1 ,h2:tensor([0.5622]) tensor([0.4950])
正向计算,预测值o1 ,o2:tensor([0.4769]) tensor([0.5287])
损失函数: 0.2097097933292389
w的梯度: 
  -0.01  0.01  -0.01  0.01  0.03  0.08  0.03  0.07  
更新后的权值w:
tensor([0.2084])  tensor([-0.4126])  tensor([0.5051])  tensor([0.5924])  tensor([0.0654])  tensor([-0.5839])  tensor([-0.3305])  tensor([0.7262])  
=====第2轮=====
正向计算,隐藏层h1 ,h2:tensor([0.5636]) tensor([0.4929])
正向计算,预测值o1 ,o2:tensor([0.4685]) tensor([0.5072])
损失函数: 0.19503259658813477
w的梯度: 
  -0.01  0.01  -0.01  0.01  0.03  0.08  0.03  0.07  
更新后的权值w:
tensor([0.2183])  tensor([-0.4232])  tensor([0.5110])  tensor([0.5861])  tensor([0.0319])  tensor([-0.6652])  tensor([-0.3598])  tensor([0.6550])  
=====第3轮=====
正向计算,隐藏层h1 ,h2:tensor([0.5652]) tensor([0.4910])
正向计算,预测值o1 ,o2:tensor([0.4604]) tensor([0.4864])
损失函数: 0.1813509315252304
w的梯度: 
  -0.01  0.01  -0.01  0.01  0.03  0.08  0.03  0.07  
更新后的权值w:
tensor([0.2294])  tensor([-0.4321])  tensor([0.5177])  tensor([0.5808])  tensor([-0.0005])  tensor([-0.7437])  tensor([-0.3879])  tensor([0.5868])  
=====第4轮=====
正向计算,隐藏层h1 ,h2:tensor([0.5671]) tensor([0.4896])
正向计算,预测值o1 ,o2:tensor([0.4526]) tensor([0.4664])
损失函数: 0.16865134239196777
w的梯度: 
  -0.01  0.01  -0.01  0.0  0.03  0.08  0.03  0.07  
更新后的权值w:
tensor([0.2416])  tensor([-0.4392])  tensor([0.5250])  tensor([0.5765])  tensor([-0.0317])  tensor([-0.8195])  tensor([-0.4149])  tensor([0.5214])  
=====第5轮=====
正向计算,隐藏层h1 ,h2:tensor([0.5691]) tensor([0.4883])
正向计算,预测值o1 ,o2:tensor([0.4451]) tensor([0.4473])
损失函数: 0.15690487623214722
w的梯度: 
  -0.01  0.01  -0.01  0.0  0.03  0.07  0.03  0.06  
更新后的权值w:
tensor([0.2547])  tensor([-0.4447])  tensor([0.5328])  tensor([0.5732])  tensor([-0.0620])  tensor([-0.8922])  tensor([-0.4408])  tensor([0.4590])  
Process finished with exit code 0

四、问题

1.对比【numpy】和【pytorch】程序,总结并陈述。

【numpy】需要的函数,反向传播都要自己手写定义,相对来说代码繁琐。【torch】可以调用backward()直接得到与函数相关的参数的梯度,进而进行梯度下降计算,不仅代码写的简单,也保证了正确性。通过结果对比发现,两种结果基本相同。


2.激活函数Sigmoid用PyTorch自带函数torch.sigmoid(),观察、总结并陈述。

Sigmoid函数:               

                                                   f(x)=\frac{1}{1+e^{-x}}

 torch.sigmoid() 函数将输入的张量(tensor)映射到值域范围为 (0,1) 的区间上。

有观察得,使用Sigmoid函数和使用Pytorch自带函数torch.sigmoid()没较为明显的差距。

3.激活函数Sigmoid改变为Relu,观察、总结并陈述。

 Relu函数:

                                                  
def forward_propagate(x):  # 计算图
    In_h1 = w[0] * x[0] + w[2] * x[1]
    h1 = torch.relu(In_h1)
    In_h2 = w[1] * x[0] + w[3] * x[1]
    h2 = torch.relu(In_h2)

    In_o1 = w[4] * h1 + w[6] * h2
    o1 = torch.relu(In_o1)
    In_o2 = w[5] * h1 + w[7] * h2
    o2 = torch.relu(In_o2)

    print("正向计算,隐藏层h1 ,h2:", end="")
    print(h1.data, h2.data)
    print("正向计算,预测值o1 ,o2:", end="")
    print(o1.data, o2.data)

    return o1, o2

 运行结果: 

=====第1轮=====
正向计算,隐藏层h1 ,h2:tensor([0.2500]) tensor([0.])
正向计算,预测值o1 ,o2:tensor([0.0250]) tensor([0.])
损失函数: 0.023462500423192978
w的梯度: 
  -0.01  0.0  -0.01  0.0  -0.05  0.0  -0.0  0.0  
更新后的权值w:
tensor([0.2103])  tensor([-0.4000])  tensor([0.5062])  tensor([0.6000])  tensor([0.1513])  tensor([-0.5000])  tensor([-0.3000])  tensor([0.8000])  
=====第2轮=====
正向计算,隐藏层h1 ,h2:tensor([0.2570]) tensor([0.])
正向计算,预测值o1 ,o2:tensor([0.0389]) tensor([0.])
损失函数: 0.020715968683362007
w的梯度: 
  -0.01  0.0  -0.01  0.0  -0.05  0.0  0.0  0.0  
更新后的权值w:
tensor([0.2247])  tensor([-0.4000])  tensor([0.5148])  tensor([0.6000])  tensor([0.2004])  tensor([-0.5000])  tensor([-0.3000])  tensor([0.8000])  
=====第3轮=====
正向计算,隐藏层h1 ,h2:tensor([0.2668]) tensor([0.])
正向计算,预测值o1 ,o2:tensor([0.0535]) tensor([0.])
损失函数: 0.01803365722298622
w的梯度: 
  -0.02  0.0  -0.01  0.0  -0.05  0.0  0.0  0.0  
更新后的权值w:
tensor([0.2424])  tensor([-0.4000])  tensor([0.5254])  tensor([0.6000])  tensor([0.2475])  tensor([-0.5000])  tensor([-0.3000])  tensor([0.8000])  
=====第4轮=====
正向计算,隐藏层h1 ,h2:tensor([0.2788]) tensor([0.])
正向计算,预测值o1 ,o2:tensor([0.0690]) tensor([0.])
损失函数: 0.015410471707582474
w的梯度: 
  -0.02  0.0  -0.01  0.0  -0.04  0.0  0.0  0.0  
更新后的权值w:
tensor([0.2623])  tensor([-0.4000])  tensor([0.5374])  tensor([0.6000])  tensor([0.2924])  tensor([-0.5000])  tensor([-0.3000])  tensor([0.8000])  
=====第5轮=====
正向计算,隐藏层h1 ,h2:tensor([0.2924]) tensor([0.])
正向计算,预测值o1 ,o2:tensor([0.0855]) tensor([0.])
损失函数: 0.012893404811620712
w的梯度: 
  -0.02  0.0  -0.01  0.0  -0.04  0.0  0.0  0.0  
更新后的权值w:
tensor([0.2834])  tensor([-0.4000])  tensor([0.5501])  tensor([0.6000])  tensor([0.3346])  tensor([-0.5000])  tensor([-0.3000])  tensor([0.8000])  
Process finished with exit code 0

对比可得,Relu激活函数收敛速度要优于使用sigmoid激活函数 

ReLU的一个主要缺点是它可能会导致所谓的"dead ReLU"问题。如果网络的某部分的所有激活值都为0(可能由于随机初始化或者其他因素),那么在这一部分就不会有梯度,这可能导致这一部分的权重无法更新。


4.损失函数MSE用PyTorch自带函数t.nn.MSELoss()替代,观察、总结并陈述。
def error(x1, x2, y1, y2):  # 损失函数
    y1_pred, y2_pred = forward_propagate(x1, x2, w)  # 前向传播
    # loss = (1 / 2) * (y1_pred - y1) ** 2 + (1 / 2) * (y2_pred - y2) ** 2  # 考虑 : t.nn.MSELoss()
    loss_func = torch.nn.MSELoss() # 创建损失函数
    y_pred = torch.cat((y1_pred, y2_pred), dim=0) # 将y1_pred, y2_pred合并成一个向量
    y = torch.cat((y1, y2), dim=0) # 将y1, y2合并成一个向量
    error= loss_func(y_pred, y) # 计算损失
    print("损失函数:", error.item())
    return error

 对比可得,结果基本相同。

5.损失函数MSE改变为交叉嫡,观察、总结并陈述。

 

def error(x1, x2, y1, y2):  # 损失函数
    y1_pred, y2_pred = forward_propagate(x1, x2,w)
    loss_func = torch.nn.CrossEntropyLoss()  # 创建交叉熵损失函数
    y_pred = torch.stack([y1_pred, y2_pred], dim=1)
    y = torch.stack([y1, y2], dim=1)
    error = loss_func(y_pred, y)  # 计算
    print("损失函数(交叉熵损失):", error.item())
    return error

运行结果:  

=====第1轮=====
隐藏层h1= tensor([0.5622], grad_fn=<MulBackward0>) h2= tensor([0.4950], grad_fn=<MulBackward0>)
预测值o1= tensor([0.4769], grad_fn=<MulBackward0>) o2= tensor([0.5287], grad_fn=<MulBackward0>)
损失函数(交叉熵损失): 0.11871970444917679
w的梯度:

-0.0  更新后的权值w 0 : tensor([0.2000])
0.01  更新后的权值w 1 : tensor([-0.4000])
-0.0  更新后的权值w 2 : tensor([0.5000])
0.0  更新后的权值w 3 : tensor([0.6000])
-0.02  更新后的权值w 4 : tensor([0.1000])
0.02  更新后的权值w 5 : tensor([-0.5000])
-0.02  更新后的权值w 6 : tensor([-0.3000])
0.02  更新后的权值w 7 : tensor([0.8000])

=====第2轮=====
隐藏层h1= tensor([0.5622], grad_fn=<MulBackward0>) h2= tensor([0.4950], grad_fn=<MulBackward0>)
预测值o1= tensor([0.4769], grad_fn=<MulBackward0>) o2= tensor([0.5287], grad_fn=<MulBackward0>)
损失函数(交叉熵损失): 0.11871970444917679
w的梯度:

-0.0  更新后的权值w 0 : tensor([0.2000])
0.01  更新后的权值w 1 : tensor([-0.4000])
-0.0  更新后的权值w 2 : tensor([0.5000])
0.0  更新后的权值w 3 : tensor([0.6000])
-0.02  更新后的权值w 4 : tensor([0.1000])
0.02  更新后的权值w 5 : tensor([-0.5000])
-0.02  更新后的权值w 6 : tensor([-0.3000])
0.02  更新后的权值w 7 : tensor([0.8000])

=====第3轮=====
隐藏层h1= tensor([0.5622], grad_fn=<MulBackward0>) h2= tensor([0.4950], grad_fn=<MulBackward0>)
预测值o1= tensor([0.4769], grad_fn=<MulBackward0>) o2= tensor([0.5287], grad_fn=<MulBackward0>)
损失函数(交叉熵损失): 0.11871970444917679
w的梯度:

-0.0  更新后的权值w 0 : tensor([0.2000])
0.01  更新后的权值w 1 : tensor([-0.4000])
-0.0  更新后的权值w 2 : tensor([0.5000])
0.0  更新后的权值w 3 : tensor([0.6000])
-0.02  更新后的权值w 4 : tensor([0.1000])
0.02  更新后的权值w 5 : tensor([-0.5000])
-0.02  更新后的权值w 6 : tensor([-0.3000])
0.02  更新后的权值w 7 : tensor([0.8000])

=====第4轮=====
隐藏层h1= tensor([0.5622], grad_fn=<MulBackward0>) h2= tensor([0.4950], grad_fn=<MulBackward0>)
预测值o1= tensor([0.4769], grad_fn=<MulBackward0>) o2= tensor([0.5287], grad_fn=<MulBackward0>)
损失函数(交叉熵损失): 0.11871970444917679
w的梯度:

-0.0  更新后的权值w 0 : tensor([0.2000])
0.01  更新后的权值w 1 : tensor([-0.4000])
-0.0  更新后的权值w 2 : tensor([0.5000])
0.0  更新后的权值w 3 : tensor([0.6000])
-0.02  更新后的权值w 4 : tensor([0.1000])
0.02  更新后的权值w 5 : tensor([-0.5000])
-0.02  更新后的权值w 6 : tensor([-0.3000])
0.02  更新后的权值w 7 : tensor([0.8000])

=====第5轮=====
隐藏层h1= tensor([0.5622], grad_fn=<MulBackward0>) h2= tensor([0.4950], grad_fn=<MulBackward0>)
预测值o1= tensor([0.4769], grad_fn=<MulBackward0>) o2= tensor([0.5287], grad_fn=<MulBackward0>)
损失函数(交叉熵损失): 0.11871970444917679
w的梯度:

-0.0  更新后的权值w 0 : tensor([0.2000])
0.01  更新后的权值w 1 : tensor([-0.4000])
-0.0  更新后的权值w 2 : tensor([0.5000])
0.0  更新后的权值w 3 : tensor([0.6000])
-0.02  更新后的权值w 4 : tensor([0.1000])
0.02  更新后的权值w 5 : tensor([-0.5000])
-0.02  更新后的权值w 6 : tensor([-0.3000])
0.02  更新后的权值w 7 : tensor([0.8000])

Process finished with exit code 0

有结果可得,改为交叉熵后,结果出现了更多的负值。

6.改变步长,训练次数,观察、总结并陈述。

 运行结果: 

步长=1,训练次数=5
=====第5轮=====
正向计算,隐藏层h1 ,h2:tensor([0.5691]) tensor([0.4883])
正向计算,预测值o1 ,o2:tensor([0.4451]) tensor([0.4473])
损失函数: 0.15690487623214722
w的梯度: 
  -0.01  0.01  -0.01  0.0  0.03  0.07  0.03  0.06  
更新后的权值w:
tensor([0.2547])  tensor([-0.4447])  tensor([0.5328])  tensor([0.5732])  tensor([-0.0620])  tensor([-0.8922])  tensor([-0.4408])  tensor([0.4590])  

步长=1,训练次数=50
=====第50轮=====
正向计算,隐藏层h1 ,h2:tensor([0.6517]) tensor([0.5092])
正向计算,预测值o1 ,o2:tensor([0.2758]) tensor([0.1304])
损失函数: 0.02112446539103985
w的梯度: 
  -0.01  -0.0  -0.0  -0.0  0.01  0.01  0.0  0.01  
更新后的权值w:
tensor([0.7606])  tensor([-0.3133])  tensor([0.8363])  tensor([0.6520])  tensor([-0.7251])  tensor([-2.3611])  tensor([-0.9798])  tensor([-0.7355])  


步长=0.1,训练次数=20
=====第20轮=====
正向计算,隐藏层h1 ,h2:tensor([0.5653]) tensor([0.4915])
正向计算,预测值o1 ,o2:tensor([0.4615]) tensor([0.4891])
损失函数: 0.18305820226669312
w的梯度: 
  -0.01  0.01  -0.01  0.01  0.03  0.08  0.03  0.07  
更新后的权值w:
tensor([0.2195])  tensor([-0.4216])  tensor([0.5117])  tensor([0.5871])  tensor([0.0329])  tensor([-0.6629])  tensor([-0.3587])  tensor([0.6574])  

步长=10,训练次数=50
=====第50轮=====
正向计算,隐藏层h1 ,h2:tensor([0.7442]) tensor([0.5580])
正向计算,预测值o1 ,o2:tensor([0.2291]) tensor([0.0185])
损失函数: 0.003917161840945482
w的梯度: 
  -0.0  -0.0  -0.0  -0.0  -0.0  0.0  -0.0  0.0  
更新后的权值w:
tensor([1.4089])  tensor([-0.0244])  tensor([1.2253])  tensor([0.8253])  tensor([-0.8268])  tensor([-3.9060])  tensor([-1.0695])  tensor([-1.9318])  
0

 步长一定的情况下,随着训练次数从10到50,均方误差下降速度也在逐渐降低,收敛速度也就下降了。


7.权值w1-w8初始值换为随机数,对比"“指定权值"的结果,观察、总结并陈述。
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) ]
 

运行结果:  

指定

=====第5轮=====
正向计算,隐藏层h1 ,h2:tensor([0.5691]) tensor([0.4883])
正向计算,预测值o1 ,o2:tensor([0.4451]) tensor([0.4473])
损失函数: 0.15690487623214722
w的梯度: 
  -0.01  0.01  -0.01  0.0  0.03  0.07  0.03  0.06  
更新后的权值w:
tensor([0.2547])  tensor([-0.4447])  tensor([0.5328])  tensor([0.5732])  tensor([-0.0620])  tensor([-0.8922])  tensor([-0.4408])  tensor([0.4590])  

随机

=====第5轮=====
正向计算,隐藏层h1 ,h2:tensor([[0.7221]]) tensor([[0.3530]])
正向计算,预测值o1 ,o2:tensor([[0.5512]]) tensor([[0.3206]])
损失函数: 0.12786653637886047
w的梯度: 
  -0.01  -0.0  -0.0  -0.0  0.06  0.06  0.03  0.03  
更新后的权值w:
tensor([[1.2782]])  tensor([[-0.5359]])  tensor([[1.0667]])  tensor([[-1.1233]])  tensor([[0.2030]])  tensor([[-1.0091]])  tensor([[0.0210]])  tensor([[-0.2186]])  

 权重的初始化不会影响收敛的结果,均方误差的下降速度与指定权值时相比有所降低,收敛速度小于指定权值。

8.权值w1-w8初始值换为0,观察、总结并陈述。

运行结果:  

=====第5轮=====
正向计算,隐藏层h1 ,h2:tensor([0.5014]) tensor([0.5014])
正向计算,预测值o1 ,o2:tensor([0.4678]) tensor([0.4325])
损失函数: 0.15450814366340637
w的梯度: 
  -0.01  -0.01  -0.0  -0.0  0.03  0.06  0.03  0.06  
更新后的权值w:
tensor([0.0136])  tensor([0.0136])  tensor([0.0081])  tensor([0.0081])  tensor([-0.1584])  tensor([-0.3328])  tensor([-0.1584])  tensor([-0.3328])  

权重初始值只影响收敛速度,并不会影响收敛结果。 


9.全面总结反向传播原理和编码实现,认真写心得体会。


通过对反向传播的手动求导,加深了对公式的理解。通过修改代码中激活函数、损失函数、步长、训练次数、权重的值,运行观察了一下对收敛速度、结果的影响。大部分就是影响了一下收敛的速度,但它们的结果都大致相同。反向传播算法的思想和前向传播是一样的,只是一个反向的过程,推导过程中注意链式法则,一层扣一环即可求得结果。    
                                                          

 参考

https://blog.csdn.net/qq_56829032/article/details/127135948

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Python,可以使用不同的库来构建前馈神经网络,其最常用的是TensorFlow和PyTorch。下面我将为您展示如何使用PyTorch来构建前馈神经网络。 首先,确保您已经安装了PyTorch库。可以使用以下命令来安装: ``` pip install torch ``` 接下来,我们将使用PyTorch构建一个简单的前馈神经网络来进行二分类任务。假设我们有一个包含两个特征的数据集,我们的目标是根据这些特征将数据分为两个类别。 以下是一个使用PyTorch构建前馈神经网络的示例代码: ```python import torch import torch.nn as nn # 定义前馈神经网络模型 class FeedforwardNN(nn.Module): def __init__(self, input_size, hidden_size, num_classes): super(FeedforwardNN, self).__init__() self.fc1 = nn.Linear(input_size, hidden_size) self.relu = nn.ReLU() self.fc2 = nn.Linear(hidden_size, num_classes) self.sigmoid = nn.Sigmoid() def forward(self, x): out = self.fc1(x) out = self.relu(out) out = self.fc2(out) out = self.sigmoid(out) return out # 定义模型参数 input_size = 2 hidden_size = 5 num_classes = 2 # 实例化模型 model = FeedforwardNN(input_size, hidden_size, num_classes) # 定义损失函数和优化器 criterion = nn.CrossEntropyLoss() optimizer = torch.optim.SGD(model.parameters(), lr=0.1) # 训练模型 num_epochs = 10 for epoch in range(num_epochs): # 正向传播 outputs = model(inputs) loss = criterion(outputs, labels) # 反向传播和优化 optimizer.zero_grad() loss.backward() optimizer.step() # 打印训练进度 if (epoch+1) % 100 == 0: print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item()}') # 使用模型进行预测 with torch.no_grad(): outputs = model(inputs) _, predicted = torch.max(outputs.data, 1) ``` 在上述代码,我们首先定义了一个名为`FeedforwardNN`的类,它继承自`nn.Module`。在该类,我们定义了两个全连接层(`nn.Linear`),使用ReLU作为激活函数,在输出层使用Sigmoid函数进行二分类。 然后,我们实例化了该类,并定义了损失函数(交叉熵损失)和优化器(随机梯度下降)。 接下来,我们迭代训练模型,通过正向传播计算输出并计算损失,然后进行反向传播和参数优化。 最后,我们使用训练好的模型进行预测。 这只是一个简单的示例,您可以根据自己的需求和数据集来调整模型结构、损失函数和优化器等。 希望这个示例能帮助您理解如何在Python使用PyTorch构建前馈神经网络。如果您有更多问题,请随时提问!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值