機器學習之BP神經網路演算法實現影象分類
阿新 • • 發佈:2018-12-17
BP 演算法是一個迭代演算法,它的基本思想為:(1) 先計算每一層的狀態和啟用值,直到最後一層(即訊號是前向傳播的);(2) 計算每一層的誤差,誤差的計算過程是從最後一層向前推進的(這就是反向傳播演算法名字的由來);(3) 更新引數(目標是誤差變小),迭代前面兩個步驟,直到滿足停止準則(比如相鄰兩次迭代的誤差的差別很小)。
下面用圖片的形式展示其推到過程
資料集:資料集採用Sort_1000pics資料集。資料集包含1000張圖片,總共分為10類。分別是人(0),沙灘(1),建築(2),大卡車(3),恐龍(4),大象(5),花朵(6),馬(7),山峰(8),食品(9)十類,每類100張,(資料集可以到網上下載)。注意網上下載的資料集是一個整體,需要自己手動將圖片進行整理分類,方便python進行讀取操作, 參考和參考進行資料集處理。
import datetime starttime = datetime.datetime.now() import numpy as np from sklearn.cross_validation import train_test_split from sklearn.metrics import confusion_matrix, classification_report import os import cv2 X = [] Y = [] for i in range(0, 10): #遍歷資料夾,讀取圖片 for f in os.listdir("./photo/%s" % i): #開啟一張圖片並灰度化 Images = cv2.imread("./photo/%s/%s" % (i, f)) image=cv2.resize(Images,(256,256),interpolation=cv2.INTER_CUBIC) hist = cv2.calcHist([image], [0,1], None, [256,256], [0.0,255.0,0.0,255.0]) X.append((hist/255).flatten()) Y.append(i) X = np.array(X) Y = np.array(Y) #切分訓練集和測試集 X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.3, random_state=1) from sklearn.preprocessing import LabelBinarizer import random def logistic(x): return 1 / (1 + np.exp(-x)) def logistic_derivative(x): return logistic(x) * (1 - logistic(x)) class NeuralNetwork: def predict(self, x): for b, w in zip(self.biases, self.weights): # 計算權重相加再加上偏向的結果 z = np.dot(x, w) + b # 計算輸出值 x = self.activation(z) return self.classes_[np.argmax(x, axis=1)] class BP(NeuralNetwork): def __init__(self,layers,batch): self.layers = layers self.batch = batch self.activation = logistic self.activation_deriv = logistic_derivative self.num_layers = len(layers) self.biases = [np.random.randn(x) for x in layers[1:]] self.weights = [np.random.randn(x, y) for x, y in zip(layers[:-1], layers[1:])] def fit(self, X, y, learning_rate=0.1, epochs=1): labelbin = LabelBinarizer() y = labelbin.fit_transform(y) self.classes_ = labelbin.classes_ training_data = [(x,y) for x, y in zip(X, y)] n = len(training_data) for k in range(epochs): #每次迭代都迴圈一次訓練 # 攪亂訓練集,讓其排序順序發生變化 random.shuffle(training_data) batches = [training_data[k:k+self.batch] for k in range(0, n, self.batch)] #批量梯度下降 for mini_batch in batches: x = [] y = [] for a,b in mini_batch: x.append(a) y.append(b) activations = [np.array(x)] #向前一層一層的走 for b, w in zip(self.biases, self.weights): #計算啟用函式的引數,計算公式:權重.dot(輸入)+偏向 z = np.dot(activations[-1],w)+b #計算輸出值 output = self.activation(z) #將本次輸出放進輸入列表,後面更新權重的時候備用 activations.append(output) #計算誤差值 error = activations[-1]-np.array(y) #計算輸出層誤差率 deltas = [error * self.activation_deriv(activations[-1])] #迴圈計算隱藏層的誤差率,從倒數第2層開始 for l in range(self.num_layers-2, 0, -1): deltas.append(self.activation_deriv(activations[l]) * np.dot(deltas[-1],self.weights[l].T)) #將各層誤差率順序顛倒,準備逐層更新權重和偏向 deltas.reverse() #更新權重和偏向 for j in range(self.num_layers-1): # 權重的增長量,計算公式,增長量 = 學習率 * (錯誤率.dot(輸出值)),單個訓練資料的誤差 delta = learning_rate/self.batch*((np.atleast_2d(activations[j].sum(axis=0)).T).dot(np.atleast_2d(deltas[j].sum(axis=0)))) #更新權重 self.weights[j] -= delta #偏向增加量,計算公式:學習率 * 錯誤率 delta = learning_rate/self.batch * deltas[j].sum(axis=0) #更新偏向 self.biases[j] -= delta return self clf0 = BP([X_train.shape[1],10],10).fit(X_train,y_train,epochs=100) predictions_labels = clf0.predict(X_test) print(confusion_matrix(y_test, predictions_labels)) print (classification_report(y_test, predictions_labels)) endtime = datetime.datetime.now() print (endtime - starttime)
實驗結果為:
[[19 0 1 0 0 2 1 1 6 1] [ 2 10 6 1 0 3 0 1 7 1] [ 3 1 12 1 0 3 1 0 3 2] [ 1 0 0 21 0 0 1 0 3 3] [ 0 1 1 0 29 0 0 1 0 0] [ 1 7 1 0 1 17 1 2 2 2] [ 2 0 1 0 0 0 24 0 1 2] [ 2 0 0 0 0 1 0 21 0 2] [ 2 1 2 2 0 2 0 0 20 2] [ 0 1 3 2 2 1 2 2 1 16]] precision recall f1-score support 0 0.59 0.61 0.60 31 1 0.48 0.32 0.38 31 2 0.44 0.46 0.45 26 3 0.78 0.72 0.75 29 4 0.91 0.91 0.91 32 5 0.59 0.50 0.54 34 6 0.80 0.80 0.80 30 7 0.75 0.81 0.78 26 8 0.47 0.65 0.54 31 9 0.52 0.53 0.52 30 avg / total 0.63 0.63 0.63 300 0:01:14.663123
因為權值和閾值每次都是隨機初始化的,所以每次執行結果就會不一樣。讀者可以更改w和b的值,將其調整到更佳的狀態。