1. 程式人生 > 實用技巧 >BP神經網路演算法程式實現鳶尾花(iris)資料集分類

BP神經網路演算法程式實現鳶尾花(iris)資料集分類

作者有話說

最近學習了一下BP神經網路,寫篇隨筆記錄一下得到的一些結果和程式碼,該隨筆會比較簡略,對一些簡單的細節不加以說明。

目錄

  • BP演算法簡要推導
  • 應用例項
  • PYTHON程式碼

BP演算法簡要推導

該部分用一個$2\times3\times 2\times1$的神經網路為例簡要說明BP演算法的步驟。

  • 向前計算輸出

  • 反向傳播誤差

  • 權重更新

應用例項

鳶尾花資料集一共有150個樣本,分為3個類別,每個樣本有4個特徵,(資料集連結:http://archive.ics.uci.edu/ml/datasets/Iris)。針對該資料集,選取如下神經網路結構和啟用函式

  • 神經網路組成

  • 隱含層神經元個數對準確率的影響

調節隱含層神經元的個數,得到模型分類準確率的變化影象如下:

  • 梯度更新步長對準確率的影響

調節梯度更新步長(學習率)的大小,得到模型分類準確率的變化影象如下:

可見準確率最高可達98.6666666666667%

PYTHON程式碼

BPNeuralNetwork.py

# coding=utf-8
import numpy as np


def tanh(x):
    return np.tanh(x)


def tanh_deriv(x):
    return 1.0 - np.tanh(x) * np.tanh(x)


def logistic(x):
    return 1.0 / (1.0 + np.exp(-x))


def logistic_derivative(x):
    return logistic(x) * (1.0 - logistic(x))


class NeuralNetwork:
    def __init__(self, layers, activation='tanh'):
        """
        """
        if activation == 'logistic':
            self.activation = logistic
            self.activation_deriv = logistic_derivative
        elif activation == 'tanh':
            self.activation = tanh
            self.activation_deriv = tanh_deriv

        self.weights = []
        self.weights.append((2 * np.random.random((layers[0] + 1, layers[1] - 1)) - 1) * 0.25)
        for i in range(2, len(layers)):
            self.weights.append((2 * np.random.random((layers[i - 1], layers[i])) - 1) * 0.25)
            # self.weights.append((2*np.random.random((layers[i]+1,layers[i+1]))-1)*0.25)

    def fit(self, X, y, learning_rate=0.2, epochs=10000):
        X = np.atleast_2d(X)
        # atlest_2d函式:確認X至少二位的矩陣
        temp = np.ones([X.shape[0], X.shape[1] + 1])
        # 初始化矩陣全是1(行數,列數+1是為了有B這個偏向)
        temp[:, 0:-1] = X
        # 行全選,第一列到倒數第二列
        X = temp
        y = np.array(y)
        # 資料結構轉換
        for k in range(epochs):
            # 抽樣梯度下降epochs抽樣
            i = np.random.randint(X.shape[0])
            a = [X[i]]
            # print(self.weights)

            for l in range(len(self.weights) - 1):
                b = self.activation(np.dot(a[l], self.weights[l]))
                b = b.tolist()
                b.append(1)
                b = np.array(b)
                a.append(b)

            a.append(self.activation(np.dot(a[-1], self.weights[-1])))

            # 向前傳播,得到每個節點的輸出結果
            error = y[i] - a[-1]
            # 最後一層錯誤率
            deltas = [error * self.activation_deriv(a[-1])]

            for l in range(len(a) - 2, 0, -1):
                deltas.append(deltas[-1].dot(self.weights[l].T) * self.activation_deriv(a[l]))
            deltas.reverse()
            for i in range(len(self.weights) - 1):
                layer = np.atleast_2d(a[i])
                delta = np.atleast_2d(deltas[i])
                delta = delta[:, : -1]
                self.weights[i] += learning_rate * layer.T.dot(delta)
            layer = np.atleast_2d(a[-2])
            delta = np.atleast_2d(deltas[-1])
            # print('w=',self.weights[-1])
            # print('l=',layer)
            # print('d=',delta)
            self.weights[-1] += learning_rate * layer.T.dot(delta)

    def predict(self, x):
        x = np.atleast_2d(x)
        # atlest_2d函式:確認X至少二位的矩陣
        temp = np.ones(x.shape[1] + 1)
        # 初始化矩陣全是1(行數,列數+1是為了有B這個偏向)
        temp[:4] = x[0, :]
        a = temp
        # print(self.weights)

        for l in range(len(self.weights) - 1):
            b = self.activation(np.dot(a, self.weights[l]))
            b = b.tolist()
            b.append(1)
            b = np.array(b)
            a = b

        a = self.activation(np.dot(a, self.weights[-1]))
        return (a)

Text.py

from BPNeuralNetwork import NeuralNetwork
import numpy as np
from openpyxl import load_workbook
import xlrd

nn = NeuralNetwork([4, 12, 3], 'tanh')
x = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
y = np.array([0, 1, 1, 0])
import openpyxl

# 開啟excel檔案,獲取工作簿物件
data = xlrd.open_workbook('BbezdekIris.xlsx')
table = data.sheets()[0]
nrows = table.nrows  # 行數
ncols = table.ncols  # 列數
datamatrix = np.zeros((nrows, ncols - 1))
for k in range(ncols - 1):
    cols = table.col_values(k)
    minVals = min(cols)
    maxVals = max(cols)
    cols1 = np.matrix(cols)  # 把list轉換為矩陣進行矩陣操作
    ranges = maxVals - minVals
    b = cols1 - minVals
    normcols = b / ranges  # 資料進行歸一化處理
    datamatrix[:, k] = normcols  # 把資料進行儲存
# print(datamatrix)
datalabel = table.col_values(ncols - 1)
for i in range(nrows):
    if datalabel[i] == 'Iris-setosa':
        datalabel[i] = [1, 0, 0]
    if datalabel[i] == 'Iris-versicolor':
        datalabel[i] = [0, 1, 0]
    if datalabel[i] == 'Iris-virginica':
        datalabel[i] = [0, 0, 1]
datamatrix1 = table.col_values(0)
for i in range(nrows):
    datamatrix1[i] = datamatrix[i]
x = datamatrix1
y = datalabel
nn.fit(x, y)
CategorySet = ['Iris-setosa', 'Iris-versicolor', 'Iris-virginica']
P = np.zeros((1, len(y)))
P = y

a = [0, 1, 3, 5, 4, 7, 8, 1, 5, 1, 5, 5, 1]
print(a.index(max(a)))
b = nn.predict(x[1])
b = b.tolist()
print(b.index(max(b)))

for i in range(len(y)):
    Predict = nn.predict(x[i])
    Predict = Predict.tolist()
    Index = Predict.index(max(Predict, key=abs))
    Real = y[i]
    Category = Real.index(max(Real, key=abs))
    if Index == Category:
        P[i] = 1
        print('樣本', i + 1, ':', x[i], '   ', '實際類別', ':', CategorySet[Category], '   ', '預測類別', ':', CategorySet[Index],
              '   ', '預測正確')
    else:
        P[i] = 0
        print('樣本', i + 1, ':', x[i], '   ', '實際類別', ':', CategorySet[Category], '   ', '預測類別', ':', CategorySet[Index],
              '   ', '預測錯誤')

print('準確率', ':', sum(P) / len(P))