BP神經網絡的Python實作
利用python實作了簡易的 bp神經網絡模型,利用誤差逆傳播算法以及梯度下降法對網絡進行訓練,具體公式推到等可參考《機器學習》等相關書籍。
源碼以及資料集可在連結 https://download.csdn.net/download/wz2671/10790394下載下傳。
BP_TEST.py
# -*- coding: UTF-8 -*-
from BPNet.bpNet import *
import matplotlib.pyplot as plt
# 資料集
bpnet = BPNet()
bpnet.loadDataSet("testSet2.txt")
bpnet.normalize()
# 繪制資料集散點圖
bpnet.drawClassScatter(plt)
# BP神經網絡進行資料分類
bpnet.bpTrain()
# 計算和繪制分類線
x, z = bpnet.BPClassfier()
bpnet.classfyLine(plt, x, z)
plt.show()
# 繪制誤差曲線
bpnet.TrendLine(plt)
plt.show()
bpNet.py
# -*- coding: utf-8 -*-
from numpy import *
import matplotlib.pyplot as plt
"""
BP神經網絡的Python實作
公式推導等可參考:周志華《機器學習》
"""
class BPNet(object):
def __init__(self):
# 網絡參數
self.eb = 0.01 # 誤差容限
self.eta = 0.1 # 學習率
self.mc = 0.3 # 動量因子
self.maxiter = 2000 # 最大疊代次數
self.errlist = [] # 誤差清單
self.data = None # 資料集
self.label = None # 分類集
self.nSampNum = 0 # 樣本集行數
self.nSampDim = 0 # 樣本次元
self.nHidden = 4 # 隐含層神經元
self.nOut = 1 # 輸出層
self.iterator = 0 # 最優時疊代次數
self.hide_wb = None # 隐含層模型參數
self.out_wb = None # 輸出層模型參數
# 激活函數
def logistic(self, net):
return 1.0 / (1.0 + exp(-net))
# 傳遞函數的導函數
def dlogit(self, net):
return multiply(net, (1.0 - net))
# 矩陣各元素平方之和
def errorfunc(self, inX):
return sum(power(inX, 2)) * 0.5
# 資料歸一化
def normalize(self):
[m, n] = shape(self.data)
for i in range(n - 1):
self.data[:, i] = (self.data[:, i] - mean(self.data[:, i])) / (std(self.data[:, i]) + 1.0e-10)
return self.data
# 加載資料集
def loadDataSet(self, filename):
self.data = []
self.label = []
fr = open(filename)
for line in fr.readlines():
lineArr = line.strip().split()
self.data.append([float(lineArr[0]), float(lineArr[1]), 1.0])
self.label.append(int(lineArr[2]))
self.data = array(self.data)
self.label = array(self.label)
m, n = shape(self.data)
self.nSampNum = m # 樣本數量
self.nSampDim = n # 樣本次元
# Train the bp net
def bpTrain(self):
# 資料集矩陣化
SampIn = mat(self.data.T)
expected = mat(self.label)
self.hide_wb = mat(2.0 * (random.rand(self.nHidden, self.nSampDim) - 0.5))
self.out_wb = mat(2.0 * (random.rand(self.nOut, self.nHidden + 1) - 0.5))
# 預設權值
dout_wbOld = 0.0
dhide_wbOld = 0.0
for i in range(self.maxiter):
# 工作信号正向傳播
# 輸入層到隐含層
hide_input = self.hide_wb * SampIn
hide_output = vstack((self.logistic(hide_input), ones((1, self.nSampNum))))
# 隐含層到輸出層
out_input = self.out_wb * hide_output
out_output = self.logistic(out_input)
# 誤差計算
err = expected - out_output
sse = self.errorfunc(err)
self.errlist.append(sse)
# 判斷是否收斂至最優
if sse <= self.eb:
self.iterator = i + 1
break
# 誤差信号反向傳播
# 計算輸出層梯度
delta_out = multiply(err, self.dlogit(out_output))
dout_wb = delta_out * hide_output.T
# 計算隐含層梯度
delta_hide = multiply(self.out_wb[:, :-1].T * delta_out, self.dlogit(hide_output[:-1, :]))
dhide_wb = delta_hide * SampIn.T
# 更新輸出層和隐含層權值
if i == 0:
self.out_wb = self.out_wb + self.eta * dout_wb
self.hide_wb = self.hide_wb + self.eta * dhide_wb
else:
self.out_wb = self.out_wb + (1.0 - self.mc) * self.eta * dout_wb + self.mc * dout_wbOld
self.hide_wb = self.hide_wb + (1.0 - self.mc) * self.eta * dhide_wb + self.mc * dhide_wbOld
dout_wbOld = dout_wb
dhide_wbOld = dhide_wb
# bp神經網絡分類器
def BPClassfier(self, steps=30):
x = linspace(self.data.min()-1, self.data.max()+1, steps)
xx = tile(x, (steps, 1))
yy = xx.T
# 三維矩陣的騷操作,一般人别想看懂
hide_output = array(self.hide_wb).dot(stack((xx, yy, ones((30, 30)))).transpose((1, 0, 2)))
out_output = array(self.out_wb).dot(vstack((self.logistic(hide_output), ones((1, steps, steps)))).transpose((1, 0, 2)))
zz = self.logistic(out_output)
return x, zz[0]
# 繪制分類線
def classfyLine(self, plt, x, z):
plt.contour(x, x, z, 1, colors='black')
# 繪制趨勢線:
def TrendLine(self, plt, color='r'):
X = linspace(0, self.maxiter, self.maxiter)
Y = log2(self.errlist)
plt.xlabel("iteration")
plt.ylabel("loss")
plt.plot(X, Y, color)
# 繪制分類點
def drawClassScatter(self, plt):
negat_point = self.label == 0
plt.scatter(self.data[negat_point, 0], self.data[negat_point, 1], c='b', marker='o')
plt.scatter(self.data[~negat_point, 0], self.data[~negat_point, 1], c='r', marker='s')
實作結果圖