1. 程式人生 > >機器學習之BP神經網路演算法實現影象分類

機器學習之BP神經網路演算法實現影象分類

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的值,將其調整到更佳的狀態。