神經網絡學習(二)

神經網絡學習(二)

手寫數字識別

認識數據集

from sklearn.datasets import load_digits   #導入手寫數字數據集

digits = load_digits()
print(digits.keys())
dict_keys(['data', 'target', 'frame', 'feature_names', 'target_names', 'images', 'DESCR'])

print(digits.data)
print(digits.data.shape)
[[ 0.  0.  5. ...  0.  0.  0.]
 [ 0.  0.  0. ... 10.  0.  0.]
 [ 0.  0.  0. ... 16.  9.  0.]
 ...
 [ 0.  0.  1. ...  6.  0.  0.]
 [ 0.  0.  2. ... 12.  0.  0.]
 [ 0.  0. 10. ... 12.  1.  0.]]
(1797, 64)
#數據裏面存儲了圖片的所有信息,一共有1797張圖面,每張圖面有64個像素點
print(digits.target)
print(digits.target.shape)
[0 1 2 ... 8 9 8]
(1797,)
#從標籤可以看出數據的範圍是從0-9
print(digits.images)
print(digits.images.shape)
[[[ 0.  0.  5. ...  1.  0.  0.]
  [ 0.  0. 13. ... 15.  5.  0.]
  [ 0.  3. 15. ... 11.  8.  0.]
  ...
  [ 0.  4. 16. ... 16.  6.  0.]
  [ 0.  8. 16. ... 16.  8.  0.]
  [ 0.  1.  8. ... 12.  1.  0.]]]
(1797, 8, 8)
#圖像信息時8*8的矩陣存儲的

數據集圖像顯示

import matplotlib.pyplot as plt
plt.figure(figsize=(8,8))
for i in range(20):
    plt.subplot(2,10,i+1)  #圖片是2*10的 參數(行數,列數,當前圖片的序號)
    plt.imshow(digits.images[i],cmap="Greys")
    plt.xlabel(digits.target[i])
    plt.xticks([])
    plt.yticks([])  #去掉座標軸
plt.show()

神經網絡設計

網絡結構

整個神經網絡分爲3層,由於圖像的像素是64,所以輸入節點一共64個,隱藏層設計爲100個,輸出一共有10種情況,所以設計爲10個。
即網絡結構爲64 x 100 x10

激活函數

S(x)=11+exS(x)=\frac{1}{1+e^{-x}}
S(x)=S(x)(1S(x))S'(x)=S(x) \cdot (1-S(x))

反向傳播更新公式

α\alpha:爲學習步長
ω2\bm{\omega}^{2}:輸入層神經網絡權重
ω3\bm{\omega}^{3}:隱藏層神經網路權重
隱藏層參數更新:
δ(3)=(ya(3))f(z(3))=(ya(3))S(z(3))(1S(z(3)))ω3E=δ(3)(a(2))Tω3=ω3αω3E \begin{aligned} \bm{\delta}^{(3)} &=-(\bm{y}-\bm{a}^{(3)}) \odot f'(\bm{z}^{(3)}) \\ &=-(\bm{y}-\bm{a}^{(3)}) \odot S(\bm{z}^{(3)})(1-S(\bm{z}^{(3)})) \\ \nabla_{\bm{\omega}^{3}}E &= \bm{\delta}^{(3)}(\bm{a}^{(2)})^\text{T} \\ \bm{\omega}^{3} &= \bm{\omega}^{3} - \alpha \nabla_{\bm{\omega}^{3}}E \end{aligned}
輸入層參數更新:
δ(2)=((ω3)Tδ3)S(z(2))ω2E=δ(2)(x)Tω2=ω2αω2E \begin{aligned} \bm{\delta}^{(2)} &= \left( (\bm{\omega}^{3})^{\text{T}}\bm{\delta}^{3} \right)\odot S'(\bm{z}^{(2)}) \\ \nabla_{\bm{\omega}^{2}}E &= \bm{\delta}^{(2)}(\bm{x})^\text{T} \\ \bm{\omega}^{2} &= \bm{\omega}^{2} - \alpha \nabla_{\bm{\omega}^{2}}E \end{aligned}

實例程序

L1對應a(2)a^{(2)}
L2對應a(3)a^{(3)}
V對應ω2\bm{\omega}^{2}
W對應ω3\bm{\omega}^{3}
L1_delta對應δ(2)\bm{\delta}^{(2)}
L2_delta對應δ(3)\bm{\delta}^{(3)}

import numpy as np
from sklearn.datasets import load_digits  #導入手寫數字數據集
from sklearn.preprocessing import LabelBinarizer  # 標籤二值化
from sklearn.model_selection import train_test_split  # 切割數據,交叉驗證法
import matplotlib.pyplot as plt

def sigmoid(x):
    return 1 / (1 + np.exp(-x))
    
def dsigmoid(x):
    return x * (1 - x)
    
class NeuralNetwork:
    def __init__(self, layers):  # (64,100,10)
        # 權重的初始化,範圍-1到1:+1的一列是偏置值
        self.V = np.random.random((layers[0] + 1, layers[1] + 1)) * 2 - 1
        self.W = np.random.random((layers[1] + 1, layers[2])) * 2 - 1

    def train(self, X, y, lr=0.11, epochs=10000):
        # 添加偏置值:最後一列全是1
        temp = np.ones([X.shape[0], X.shape[1] + 1])
        temp[:, 0:-1] = X
        X = temp

        for n in range(epochs + 1):
            # 在訓練集中隨機選取一行(一個數據):randint()在範圍內隨機生成一個int類型
            i = np.random.randint(X.shape[0])
            x = [X[i]]
            # 轉爲二維數據:由一維一行轉爲二維一行
            x = np.atleast_2d(x)

            # L1:輸入層傳遞給隱藏層的值;輸入層64個節點,隱藏層100個節點
            # L2:隱藏層傳遞到輸出層的值;輸出層10個節點
            L1 = sigmoid(np.dot(x, self.V))
            L2 = sigmoid(np.dot(L1, self.W))

            # L2_delta:輸出層對隱藏層的誤差改變量
            # L1_delta:隱藏層對輸入層的誤差改變量
            L2_delta = (y[i] - L2) * dsigmoid(L2)
            L1_delta = L2_delta.dot(self.W.T) * dsigmoid(L1)

            # 計算改變後的新權重
            self.W += lr * L1.T.dot(L2_delta)
            self.V += lr * x.T.dot(L1_delta)

            # 每訓練1000次輸出一次準確率
            if n % 1000 == 0:
                predictions = []
                for j in range(X_test.shape[0]):
                    # 獲取預測結果:返回與十個標籤值逼近的距離,數值最大的選爲本次的預測值
                    o = self.predict(X_test[j])
                    # 將最大的數值所對應的標籤返回
                    predictions.append(np.argmax(o))
                # np.equal():相同返回true,不同返回false
                accuracy = np.mean(np.equal(predictions, y_test))
                print('迭代次數:', n, '準確率:', accuracy)

    def predict(self, x):
        # 添加偏置值:最後一列全是1
        temp = np.ones([x.shape[0] + 1])
        temp[0:-1] = x
        x = temp
        # 轉爲二維數據:由一維一行轉爲二維一行
        x = np.atleast_2d(x)

        # L1:輸入層傳遞給隱藏層的值;輸入層64個節點,隱藏層100個節點
        # L2:隱藏層傳遞到輸出層的值;輸出層10個節點
        L1 = sigmoid(np.dot(x, self.V))
        L2 = sigmoid(np.dot(L1, self.W))
        return L2
        
# 載入數據:8*8的數據集
digits = load_digits()
print(digits.keys())
X = digits.data
Y = digits.target
# 輸入數據歸一化:當數據集數值過大,乘以較小的權重後還是很大的數,代入sigmoid激活函數就趨近於1,不利於學習
X -= X.min()
X /= X.max()

NN = NeuralNetwork([64, 100, 10])
# sklearn切分數據
X_train, X_test, y_train, y_test = train_test_split(X, Y)
# 標籤二值化:將原始標籤(十進制)轉爲新標籤(二進制)
labels_train = LabelBinarizer().fit_transform(y_train)
labels_test = LabelBinarizer().fit_transform(y_test)

print('開始訓練')
NN.train(X_train, labels_train, epochs=20000)
print('訓練結束')
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章