天天看點

BP神經網絡的Python實作

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')

           

實作結果圖

BP神經網絡的Python實作
BP神經網絡的Python實作

繼續閱讀