玩命加载中 . . .

西瓜书课后习题第五章(5.5)


§1.题目

题目

§2.分析

§单隐层BP网络

BP网络及算法中额变量符号

§BP算法伪代码

误差逆传播算法

Algorithms 1. 标准BP算法
----
    输入: 训练集 D,学习率 η.
    过程: 
        1. 随即初始化连接权与阈值 (ω,θ).
        2. Repeat:
        3.   for x_k,y_k in D:
        4.     根据当前参数计算出样本误差 Ek.
        5.     根据公式计算出输出层神经元的随机梯度项 gj.
        6.     根据公式计算出隐层神经元的梯度项 eh.
        7.     根据公式更新 (ω,θ)(ν,γ).
        8.   end for
        9. until 达到停止条件
    输出:(ω,θ) (ν,γ) - 即相应的多层前馈神经网络.
----

Algorithms 2. 累积BP算法
----
    输入: 训练集 D,学习率 η,迭代次数 n.
    过程: 
        1. 随即初始化连接权与阈值 (ω,θ).
        2. Repeat:
        3.     根据当前参数计算出累积误差 E.
        4.     根据公式计算出标准梯度项 g.
        5.     根据公式计算出隐层神经元的梯度项 e.
        6.     根据公式更新 (ω,θ)(ν,γ).
        7.     n = n-1
        8. until n=0 or 达到停止条件
    输出:(ω,θ) (ν,γ) - 即相应的多层前馈神经网络.
----

§基本实现步骤
  • 1.处理数据集

    • 离散数据归一化(可用独热编码技术改进)
  • 2.定义初始化各参数

    • 定义初始化输入神经元的个数d(n个属性描述)

      d = n
      
    • 定义初始化输出神经元的个数l(输出l维实值向量)

      l = 1
      
    • 定义初始化隐层神经元的个数q

      q = d + 1
      
    • 定义初始化输出层神经元的阈值矩阵θ(1行l列)

      theta = [random.random() for i in range(l)]
      
    • 定义初始化隐层神经元的阈值矩阵γ(1行q列)

      gamma = [random.random() for i in range(q)]
      
    • 定义初始化输入层和隐层神经元之间的连接权重v矩阵(d行q列 输入层->输出层)

      v = [[random.random() for i in range(q)] for j in range(d)]
      
    • 定义初始化隐层和输出层神经元之间的连接权重w矩阵(q行l列 隐层->输入层)

      w = [[random.random() for i in range(l)] for j in range(q)]
      
    • 定义初始化学习(速)率(固定值)eta

      eta = 0.49 # the training speed
      
    • 定义初始化最大允许误差error

      error = 0.0001
      
    • 定义初始化训练次数及上限trainingTimes,maxTrainingTimes

      trainingTimes = maxTrainingTimes = 10000
      
  • 3.构造sigmoid()函数作为激活函数

    • 按照待处理的矩阵维(层)数划分情况
  • 4.标准BP算法实现

    • 输入: 训练集 D,学习率 η.
          过程: 
              1. 随即初始化连接权与阈值 (ω,θ).
              2. Repeat:
              3.   for x_k,y_k in D:
              4.     根据当前参数计算出样本误差 Ek.
              5.     根据公式计算出输出层神经元的随机梯度项 gj.
              6.     根据公式计算出隐层神经元的梯度项 eh.
              7.     根据公式更新 (ω,θ)(ν,γ).
              8.   end for
              9. until 达到停止条件
          输出:(ω,θ) (ν,γ) - 即相应的多层前馈神经网络.
      
  • 5.累计BP算法实现

    • 输入: 训练集 D,学习率 η,迭代次数 n.
          过程: 
              1. 随即初始化连接权与阈值 (ω,θ).
              2. Repeat:
              3.     根据当前参数计算出累积误差 E.
              4.     根据公式计算出标准梯度项 g.
              5.     根据公式计算出隐层神经元的梯度项 e.
              6.     根据公式更新 (ω,θ)(ν,γ).
              7.     n = n-1
              8. until n=0 or 达到停止条件
          输出:(ω,θ) (ν,γ) - 即相应的多层前馈神经网络.
      
  • 6.构造预测函数

    • 输入测试集
    • 使用训练好的网络模型数据(权值和阈值)
    • 输出预测结果
  • 7.算法训练结果可视化表示

    • 在限定学习率和误差的情况下对比训练次数和收敛情况等

§3.代码实现

§数据集(watermelonDataset_3.0)
编号,色泽,根蒂,敲声,纹理,脐部,触感,密度,含糖率,好瓜
1,青绿,蜷缩,浊响,清晰,凹陷,硬滑,0.697,0.46,是
2,乌黑,蜷缩,沉闷,清晰,凹陷,硬滑,0.774,0.376,是
3,乌黑,蜷缩,浊响,清晰,凹陷,硬滑,0.634,0.264,是
4,青绿,蜷缩,沉闷,清晰,凹陷,硬滑,0.608,0.318,是
5,浅白,蜷缩,浊响,清晰,凹陷,硬滑,0.556,0.215,是
6,青绿,稍蜷,浊响,清晰,稍凹,软粘,0.403,0.237,是
7,乌黑,稍蜷,浊响,稍糊,稍凹,软粘,0.481,0.149,是
8,乌黑,稍蜷,浊响,清晰,稍凹,硬滑,0.437,0.211,是
9,乌黑,稍蜷,沉闷,稍糊,稍凹,硬滑,0.666,0.091,否
10,青绿,硬挺,清脆,清晰,平坦,软粘,0.243,0.267,否
11,浅白,硬挺,清脆,模糊,平坦,硬滑,0.245,0.057,否
12,浅白,蜷缩,浊响,模糊,平坦,软粘,0.343,0.099,否
13,青绿,稍蜷,浊响,稍糊,凹陷,硬滑,0.639,0.161,否
14,浅白,稍蜷,沉闷,稍糊,凹陷,硬滑,0.657,0.198,否
15,乌黑,稍蜷,浊响,清晰,稍凹,软粘,0.36,0.37,否
16,浅白,蜷缩,浊响,模糊,平坦,硬滑,0.593,0.042,否
17,青绿,蜷缩,沉闷,稍糊,稍凹,硬滑,0.719,0.103,否
§参数

参数

§公式
§输出层和隐层的输入

输出层和隐层的输入

§预测输出
§预测输出
§均方误差

image-20201020193734321

§输出层神经元的梯度项

image-20201020192835297

§隐层神经元的梯度项

image-20201020193500602

image-20201020193524771

§更新公式:
  • 更新隐层和输出层神经元之间的连接权重

image-20201020192957235

  • 更新输出层神经元的阈值

image-20201020193006418

  • 更新输入层和隐层神经元之间的连接权重

image-20201020193014364

  • 更新隐层神经元之间的阈值

image-20201020193024595

§公式5.16

image-20201020193043804

§3.1标准BP算法
§核心代码:
# 4 标准BP算法实现
# do the repeat
while (trainingTimes > 0):
    # 训练次(轮)0数
    trainingTimes -= 1
    # 定义初始化累计误差
    sumE = 0
    for i in range(m):
    # 向前传播
        # 矩阵积 获得隐层各神经元的输入矩阵(shape=(1*d)*(d*q)=(1*q))
        alpha = np.dot(X[i], v)
        # 激活函数处理 获得隐层各神经元的实际值 b=f(alpha-gamma), shape=1*q
        b = sigmoid(alpha - gamma, 1)
        # 矩阵积 获得输出层各神经元的输入矩阵(shape=(1*q)*(q*l)=(1*l))
        beta = np.dot(b, w)
        # 公式5.3 激活函数处理 获得(预测值)样本输出矩阵(shape=1*l)
        predictY = sigmoid(beta - theta, 1)
        # 公式5.4 获得均方误差(1层)
        Ek = sum((predictY - trueY[i]) * (predictY - trueY[i])) / 2
        # 公式5.16 获得累计误差
        sumE += Ek
        # 公式5.10 获得输出层神经元的梯度项矩阵(shape=1*l)
        g = predictY * (1 - predictY) * (trueY[i] - predictY)  
        # 公式5.15 获得隐层神经元的梯度项矩阵(shape=1*q)
        e = b * (1 - b) * ((np.dot(w, g.T)).T) 
    # 向后更新
        # 公式5.11 更新隐层和输出层神经元之间的连接权重矩阵(shape=q*l)
        w += eta * np.dot(b.reshape((q, 1)), g.reshape((1, l)))
        # 公式5.12 更新输出层神经元的阈值矩阵(shape=1*l)
        theta -= eta * g
        # 公式5.13 更新输入层和隐层神经元之间的连接权重矩阵(shape=d*q)
        v += eta * np.dot(X[i].reshape((d, 1)), e.reshape((1, q)))
        # 公式5.14 更新隐层神经元之间的阈值矩阵(shape=1*q)
        gamma -= eta * e
    # print(sumE)
    print("累计误差:",sumE, "\t\t训练次数:", maxTrainingTimes - trainingTimes+1)
    if(sumE <= error):
        break
§3.2累计BP算法
§核心代码:
# 5 累计BP算法实现
trueY=trueY.reshape((m,l))
while(trainingTimes>0):
# 向前传播
    # 训练次(轮)0数
    trainingTimes-=1
    # 定义初始化累计误差
    sumE=0
    # 矩阵积 获得隐层各神经元的输入矩阵(shape=(m*d)*(d*q)=(m*q))
    alpha = np.dot(X, v)
    # 激活函数处理 获得隐层各神经元的实际值 b=f(alpha-gamma), shape=m*q
    b = sigmoid(alpha - gamma,2)
    # 公式5.3 激活函数处理 获得(预测值)样本输出矩阵(shape=m*l=(m*q)*(q*l))
    beta = np.dot(b, w)
    # 公式5.3 激活函数处理 获得(预测值)样本输出矩阵(shape=m*l)
    predictY = sigmoid(beta - theta,2)
    # 公式5.4 获得均方误差(2层)
    E = sum(sum((predictY - trueY) * (predictY - trueY))) / 2
    # print(round(E,5))
    # 公式5.10 获得输出层神经元的梯度项矩阵 (shape=m*l)
    g = predictY * (1 - predictY) * (trueY - predictY)
    # 公式5.15 获得隐层神经元的梯度项矩阵(shape=m*q)
    e = b * (1 - b) * ((np.dot(w, g.T)).T)

# 向后更新
    # 公式5.11 更新隐层和输出层神经元之间的连接权重矩阵(shape=q*l=(q*m)*(m*l))
    w += eta * np.dot(b.T, g)
    # 公式5.12 更新输出层神经元的阈值矩阵(shape=1*l)
    theta -= eta * g  # 5.12
    # 公式5.13 更新输入层和隐层神经元之间的连接权重矩阵(shape=d*q=(d,m)*(m,q))
    v += eta * np.dot(X.T, e)
    # 公式5.14 更新隐层神经元之间的阈值矩阵(shape=1*q)
    gamma -= eta * e

    print("累计误差:",E, "\t\t训练次数:", maxTrainingTimes - trainingTimes+1)
    if(E <= error):
       break
#     # print(E if(trainingTimes %500 == 0) )

§4.比较总结

§标准BP算法达到限定累计误差(0.001)所需训练次数(学习率:0.48)

image-20201020180208817

image-20201020180232016

§累计BP算法达到限定累计误差(0.001)所需训练次数(学习率:0.48)

image-20201020180405962

image-20201020180423235

§综合情况

训练结果对比图

训练结果评价

§分析:

​ 在相同学习率(0.48)的条件下,为达到0.001左右的误差标准BP算法需要训练6765轮左右,而累积BP算法大概需要1722轮。

​ 同时也注意到随着训练次数的增加,累计BP算法中累计误差的下降开始变得较标准BP算法更为缓慢。

§结论:

​ 标准BP算法每次更新只针对单个样例,参数更新的非常频繁,而且对不同样例进行更新的效果可能出现“抵消”现象。因此为了达到同样的累积误差极小点,标准BP算法往往需要进行更多次的迭代。

​ 累积BP算法直接针对累积误差最小化,它读取整个训练集D一遍后才对参数进行更新,其参数更新的频率低得多。但是在很多任务中,累积误差下降到一定程度后,进一步下降会非常缓慢,这时标准BP算法往往会更快获得较好的解,尤其是在训练集D非常大时更明显。

​ 用累积bp算法,更新神经网络的次数会少,所以学的快一些,而且能避免个别异常变量带来的误差导致过拟合。但是需要的样本量比较大,忽略个体而重视整体,就模型泛化能力上来讲,用累积bp算法训练出的模型对于边界条件的把握不一定强。


文章作者: Angus Lan
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Angus Lan !
评论
  目录