2022年 11月 4日

机器学习—西瓜书BP算法python实现

算法流程:

python代码实现:

  1. import numpy as np
  2. np.set_printoptions(suppress=True) #取消使用科学计数法
  3. def Sigmoid(x): # 激活函数
  4. function = 1.0 / (1.0 + np.exp(-x))
  5. return function
  6. def forward(X, v1, v2, w1, w2, yz1, yz2, yz3, yz4): # 前向传播
  7. y_hat1 = []
  8. y_hat2 = []
  9. for i in range(X.shape[0]): # X.shape表示有几个样本
  10. x = X[i]
  11. # 隐层的两个神经元的输入值
  12. h1 = np.dot(x, v1)
  13. h2 = np.dot(x, v2)
  14. # 隐层的两个神经元的输出值 也就是 输出层的输入
  15. h1_out = Sigmoid(h1 - yz1)
  16. h2_out = Sigmoid(h2 - yz2)
  17. h_out = np.array([h1_out, h2_out])
  18. # 输出层的两个神经元的输出层
  19. out1 = np.dot(h_out, w1)
  20. out2 = np.dot(h_out, w2)
  21. # 预测值的输出
  22. y_hat1.append(Sigmoid(out1 - yz3))
  23. y_hat2.append(Sigmoid(out2 - yz4))
  24. Y_hat = np.array(list(zip(y_hat1, y_hat2))) # 训练集对应的预测值
  25. return Y_hat
  26. def loss(y, y_hat): # 误差函数
  27. out = np.sum((y - y_hat) ** 2) / 2 * y.shape[0] # y.shape[0]指神经元的个数
  28. return out
  29. # 误差逆传播(标准bp算法)
  30. def BackPropagation(X, v1, v2, w1, w2, yz1, yz2, yz3, yz4, Y, learnrate):
  31. Y_hat = forward(X, v1, v2, w1, w2, yz1, yz2, yz3, yz4)
  32. Ek_sum = 0
  33. for i in range(X.shape[0]):
  34. x = X[i]
  35. # 隐层的两个神经元的输入值
  36. h1 = np.dot(x, v1)
  37. h2 = np.dot(x, v2)
  38. # 隐层的两个神经元的输出值 也就是 输出层的输入
  39. h1_out = Sigmoid(h1 - yz1)
  40. h2_out = Sigmoid(h2 - yz2)
  41. y1 = Y_hat[i][0]
  42. y2 = Y_hat[i][1]
  43. Ek = loss(Y[i], Y_hat[i])
  44. Ek_sum = Ek_sum + Ek
  45. # 输出层神经元的梯度项
  46. g1 = y1 * (1 - y1) * (Y[i][0] - y1)
  47. g2 = y2 * (1 - y2) * (Y[i][1] - y2)
  48. # 隐层神经元的梯度项
  49. e1 = h1_out * (1 - h1_out) * (w1[0] * g1 + w1[1] * g2)
  50. e2 = h2_out * (1 - h2_out) * (w2[0] * g1 + w2[1] * g2)
  51. # 更新连接权和阈值
  52. v1[0] = v1[0] + (learnrate * e1 * x[0])
  53. v1[1] = v1[1] + (learnrate * e2 * x[0])
  54. v2[0] = v2[0] + (learnrate * e1 * x[1])
  55. v2[1] = v2[1] + (learnrate * e2 * x[1])
  56. w1[0] = w1[0] + (learnrate * g1 * h1_out)
  57. w1[1] = w1[1] + (learnrate * g2 * h1_out)
  58. w2[0] = w2[0] + (learnrate * g1 * h2_out)
  59. w2[1] = w2[1] + (learnrate * g2 * h2_out)
  60. yz1 = yz1 + (-learnrate * e1)
  61. yz2 = yz2 + (-learnrate * e2)
  62. yz3 = yz3 + (-learnrate * g1)
  63. yz4 = yz4 + (-learnrate * g2)
  64. print(Ek_sum)
  65. return v1, v2, w1, w2, yz1, yz2, yz3, yz4
  66. # 误差逆传播(累计bp算法)
  67. def BackPropagation_accumulate(X, v1, v2, w1, w2, yz1, yz2, yz3, yz4, Y, learnrate):
  68. Y_hat = forward(X, v1, v2, w1, w2, yz1, yz2, yz3, yz4)
  69. Ek_sum = 0
  70. g1 = []
  71. g2 = []
  72. e1 = []
  73. e2 = []
  74. for i in range(X.shape[0]):
  75. x = X[i]
  76. # 隐层的两个神经元的输入值
  77. h1 = np.dot(x, v1)
  78. h2 = np.dot(x, v2)
  79. # 隐层的两个神经元的输出值 也就是 输出层的输入
  80. h1_out = Sigmoid(h1 - yz1)
  81. h2_out = Sigmoid(h2 - yz2)
  82. y1 = Y_hat[i][0]
  83. y2 = Y_hat[i][1]
  84. Ek = loss(Y[i], Y_hat[i])
  85. Ek_sum = Ek_sum + Ek
  86. # 输出层神经元的梯度项
  87. g1.append(y1 * (1 - y1) * (Y[i][0] - y1))
  88. g2.append(y2 * (1 - y2) * (Y[i][1] - y2))
  89. # 隐层神经元的梯度项
  90. e1.append(h1_out * (1 - h1_out) * (w1[0] * g1[i] + w1[1] * g2[i]))
  91. e2.append(h2_out * (1 - h2_out) * (w2[0] * g1[i] + w2[1] * g2[i]))
  92. # 更新连接权和阈值
  93. g1_aver = np.mean(g1)
  94. g2_aver = np.mean(g2)
  95. e1_aver = np.mean(e1)
  96. e2_aver = np.mean(e2)
  97. v1[0] = v1[0] + (learnrate * e1_aver * x[0])
  98. v1[1] = v1[1] + (learnrate * e2_aver * x[0])
  99. v2[0] = v2[0] + (learnrate * e1_aver * x[1])
  100. v2[1] = v2[1] + (learnrate * e2_aver * x[1])
  101. w1[0] = w1[0] + (learnrate * g1_aver * h1_out)
  102. w1[1] = w1[1] + (learnrate * g2_aver * h1_out)
  103. w2[0] = w2[0] + (learnrate * g1_aver * h2_out)
  104. w2[1] = w2[1] + (learnrate * g2_aver * h2_out)
  105. yz1 = yz1 + (-learnrate * e1_aver)
  106. yz2 = yz2 + (-learnrate * e2_aver)
  107. yz3 = yz3 + (-learnrate * g1_aver)
  108. yz4 = yz4 + (-learnrate * g2_aver)
  109. print(Ek_sum)
  110. return v1, v2, w1, w2, yz1, yz2, yz3, yz4
  111. # ---------------------main-------------------
  112. # 对于输出层神经元,假设好瓜应为10,坏瓜为01
  113. # 在(0,1)范围内随机初始化网络中所有连接权和阈值
  114. v11, v12, v21, v22, w11, w12, w21, w22, yz1, yz2, yz3, yz4 = np.random.random(12)
  115. v1 = np.array([v11, v12])
  116. v2 = np.array([v21, v22])
  117. w1 = np.array([w11, w12])
  118. w2 = np.array([w21, w22])
  119. # 学习率
  120. learnrate = 0.1
  121. p = [0.634, 0.608, 0.556, 0.403, 0.481, 0.437,
  122. 0.666, 0.639, 0.657, 0.593,0.719] # 密度
  123. sug = [0.264, 0.318, 0.215, 0.237, 0.149, 0.211,
  124. 0.091, 0.161, 0.198, 0.042,0.103] # 糖分
  125. Y = np.array([[1, 0], [1, 0], [1, 0], [1, 0], [1, 0], [1, 0],
  126. [0, 1], [0, 1], [0, 1], [0, 1], [0, 1]]) # y值
  127. X = np.array(list(zip(p, sug)))
  128. a = forward(X, v1, v2, w1, w2, yz1, yz2, yz3, yz4) # 初始的权值和阈值 算出来的预测值
  129. print(a)
  130. for i in range(10000):
  131. v1, v2, w1, w2, yz1, yz2, yz3, yz4 = BackPropagation_accumulate(X, v1, v2, w1, w2, yz1, yz2, yz3, yz4, Y, learnrate) # 训练
  132. b = forward(X, v1, v2, w1, w2, yz1, yz2, yz3, yz4) # 训练的权值和阈值 算出来的预测值
  133. print(b)

 本次实验中,使用一个隐层,且一个隐层只包含2个神经元,在输出层我使用【0,1】表示坏瓜,【1,0】表示好瓜

 

训练集:

训练之前根据初始的权值和阈值 算出来的预测值:

训练时:误差函数不断下降

 训练10000次后 输出的预测值:

累计BP:误差函数下降的很慢(我认为可能是分类编码的原因)

 

训练了一万次:

下降的非常慢,以我目前的水平还不知道为啥。