利用神經(jīng)網(wǎng)絡(luò)的反向傳播算法實(shí)現(xiàn)手寫數(shù)字識(shí)別

前言

在之前的學(xué)習(xí)中,已經(jīng)了解了神經(jīng)網(wǎng)絡(luò)及其神經(jīng)網(wǎng)絡(luò)的反向傳播算法的具體算法分析糖荒,現(xiàn)在阱州,我們可以用使用該算法實(shí)現(xiàn)手寫數(shù)字的識(shí)別鼓寺,即也就是用python實(shí)現(xiàn)一個(gè)多分類問題。

神經(jīng)網(wǎng)絡(luò)的實(shí)現(xiàn)

首先勋磕,根據(jù)神經(jīng)網(wǎng)絡(luò)的相關(guān)算法原理妈候,用python實(shí)現(xiàn)神經(jīng)網(wǎng)絡(luò)的前向傳播算法

  • 導(dǎo)入相關(guān)庫(kù)
    與之前的代碼一樣,我們需要導(dǎo)入相關(guān)庫(kù)以便實(shí)現(xiàn)一些神經(jīng)網(wǎng)絡(luò)的運(yùn)算挂滓,導(dǎo)入以下相關(guān)庫(kù)苦银。
import matplotlib.pyplot as plt
import numpy as np
import scipy.io as scio
import scipy.optimize as opt
  • 初始化一些參數(shù)
    這些參數(shù)的介紹如下注釋所示:
input_layer_size = 400  # 20x20 輸入像素矩陣
hidden_layer_size = 25  # 25個(gè)隱藏層
num_labels = 10         # 0到9的十個(gè)輸出
  • 數(shù)據(jù)可視化
    參考python手寫數(shù)字識(shí)別的訓(xùn)練集介紹,導(dǎo)入訓(xùn)練集杂彭,并隨機(jī)選擇100個(gè)訓(xùn)練集實(shí)現(xiàn)數(shù)據(jù)可視化墓毒,具體代碼如下所示(參考注釋):
def display_data(x):
 (m, n) = x.shape
 # m = 100
 # n = 400

 # 設(shè)置每個(gè)數(shù)字的寬度與高度(像素)
 example_width = np.round(np.sqrt(n)).astype(int)# example_width=20
 example_height = (n / example_width).astype(int) #example_height=20

 # 計(jì)算顯示的行數(shù)與列數(shù)
 display_rows = np.floor(np.sqrt(m)).astype(int) #display_rows=10
 display_cols = np.ceil(m / display_rows).astype(int)#display_rows=10

 # 單個(gè)圖像之間的間隔
 pad = 1

 # 設(shè)置并初始化顯示像素矩陣的大小211*211 ,1+(10*20+1)
 display_array = - np.ones((pad + display_rows * (example_height + pad),
                           pad + display_rows * (example_height + pad)))

 # 將每個(gè)訓(xùn)練樣本顯示在矩陣中
 curr_ex = 0 
 for j in range(display_rows):
     for i in range(display_cols):
         if curr_ex > m:
             break

         # 每次每行和每列讀取一個(gè)20*20像素的數(shù)字,矩陣大小加21
         # 實(shí)際上矩陣形式可以認(rèn)為 10*10*400(20*20像素)
         # 填充要顯示的像素矩陣
         max_val = np.max(np.abs(x[curr_ex]))
         display_array[pad + j * (example_height + pad) + np.arange(example_height),
                       pad + i * (example_width + pad) + np.arange(example_width)[:, np.newaxis]] = \
                       x[curr_ex].reshape((example_height, example_width)) / max_val
         curr_ex += 1

     if curr_ex > m:
         break

 # Display image
 plt.figure()
 plt.imshow(display_array, cmap='gray', extent=[-1, 1, -1, 1])
 plt.axis('off')  

rand_indices = np.random.permutation(range(m))
selected = X[rand_indices[0:100], :]   #隨機(jī)選擇100個(gè)數(shù)據(jù)
display_data(selected)

最后亲怠,隨機(jī)選擇100個(gè)輸入樣本,調(diào)用以上函數(shù)柠辞,實(shí)現(xiàn)數(shù)據(jù)可視化团秽,如下所示:


  • 神經(jīng)網(wǎng)絡(luò)模型選擇
    我們選擇的神經(jīng)網(wǎng)絡(luò)如下圖所示,由三層構(gòu)成叭首,包括一個(gè)輸入層习勤,隱藏層和輸出層,輸入層是一個(gè)數(shù)字圖片的像素矩陣焙格,大小為20X20像素图毕,所以輸入層有400個(gè)輸入單元(不計(jì)算偏置單元),訓(xùn)練集中已經(jīng)給我們提供了參數(shù)矩陣眷唉,我們選擇的神經(jīng)網(wǎng)絡(luò)是一個(gè)三層神經(jīng)網(wǎng)絡(luò)予颤,顯然,需要兩個(gè)參數(shù)矩陣冬阳,第一個(gè)參數(shù)矩陣\theta^{(1)}是25X401維的矩陣蛤虐,而第二個(gè)參數(shù)矩陣\theta^{(2)}是26X10維的矩陣。(與輸出層10個(gè)數(shù)字類別相對(duì)應(yīng))肝陪。

  • 反向傳播算法的損失函數(shù)
    神經(jīng)網(wǎng)絡(luò)正則化的損失函數(shù)如下所示:


很明顯驳庭,K=10,所以h_\theta(x^{(i)})的輸出如下所示:

假設(shè)通過神經(jīng)網(wǎng)絡(luò)輸出y的值是5氯窍,則y_5=1,即向量y的第5個(gè)元素是1饲常,其他元素是0.
綜上所述,參考反向傳播算法損失函數(shù)的相關(guān)介紹,損失函數(shù)與梯度的計(jì)算代碼如下:

def nn_cost_function(nn_params, input_layer_size, hidden_layer_size, num_labels, X, y, lmd):
    
    theta1 = nn_params[:hidden_layer_size * (input_layer_size + 1)].reshape(hidden_layer_size, input_layer_size + 1)
    theta2 = nn_params[hidden_layer_size * (input_layer_size + 1):].reshape(num_labels, hidden_layer_size + 1)

    m = y.size
    cost = 0
    theta1_grad = np.zeros(theta1.shape)  # 25 x 401
    theta2_grad = np.zeros(theta2.shape)  # 10 x 26
    Y = np.zeros((m, num_labels))  # 5000 x 10

    for i in range(m):
        Y[i, y[i]-1] = 1

    a1 = np.c_[np.ones(m), X]  # 5000 x 401
    a2 = np.c_[np.ones(m), sigmoid(np.dot(a1, theta1.T))]  # 5000 x 26
    hypothesis = sigmoid(np.dot(a2, theta2.T))  # 5000 x 10

    reg_theta1 = theta1[:, 1:]  # 25 x 400
    reg_theta2 = theta2[:, 1:]  # 10 x 25

    cost = np.sum(-Y * np.log(hypothesis) - np.subtract(1, Y) * np.log(np.subtract(1, hypothesis))) / m \
            + (lmd / (2 * m)) * (np.sum(reg_theta1 * reg_theta1) + np.sum(reg_theta2 * reg_theta2))

    e3 = hypothesis - Y  # 5000 x 10
    e2 = np.dot(e3, theta2) * (a2 * np.subtract(1, a2))  # 5000 x 26
    e2 = e2[:, 1:]  # drop the intercept column  # 5000 x 25

    delta1 = np.dot(e2.T, a1)  # 25 x 401
    delta2 = np.dot(e3.T, a2)  # 10 x 26

    p1 = (lmd / m) * np.c_[np.zeros(hidden_layer_size), reg_theta1]
    p2 = (lmd / m) * np.c_[np.zeros(num_labels), reg_theta2]

    theta1_grad = p1 + (delta1 / m)
    theta2_grad = p2 + (delta2 / m)
    grad = np.concatenate([theta1_grad.flatten(), theta2_grad.flatten()])

    return cost, grad

初始化一些參數(shù)狼讨,并且調(diào)用上述函數(shù)贝淤,計(jì)算結(jié)果如下所示:

data = scio.loadmat('ex4weights.mat')
theta1 = data['Theta1']
theta2 = data['Theta2']

lmd = 1
nn_params = np.concatenate([theta1.flatten(), theta2.flatten()])
cost, grad = nn_cost_function(nn_params, input_layer_size, hidden_layer_size, num_labels, X, y, lmd)
print(cost)
  • sigmoid函數(shù)求導(dǎo)
    激活函數(shù)的求導(dǎo)可以用以下公式表示:

g(z) = \frac{1}{1+e^{-z}}

g'(z) = \fracaiocqse{dz}g(z) = g(z)*(1-g(z))

根據(jù)以上公式,用代碼實(shí)現(xiàn)方式如下所示:

def sigmoid_gradient(z):
    g = np.zeros(z.shape)
    g = sigmoid(z)*(1-sigmoid(z))
    return g

隨機(jī)輸入一組參數(shù)熊楼,計(jì)算結(jié)果如下所示:


  • 隨機(jī)初始化
    正如之前的介紹一樣霹娄,神經(jīng)網(wǎng)絡(luò)中參數(shù)初始化與邏輯回歸中不同能犯,不能初始化為0,應(yīng)該是隨機(jī)初始化犬耻。如下代碼所示:
def rand_initialization(l_in, l_out):
    
    w = np.zeros((l_out, 1 + l_in))
    ep_init = 0.12
    w = np.random.rand(l_out, 1 + l_in) * (2 * ep_init) - ep_init
    return w
  • 梯度檢測(cè)
    為了有效減小神經(jīng)網(wǎng)絡(luò)反向傳播算法中的造成的誤差踩晶,為此比較數(shù)值化的計(jì)算方法與梯度下降算法是否接近,數(shù)值化的梯度計(jì)算方法如下所示:
def compute_numerial_gradient(cost_func, theta):
    numgrad = np.zeros(theta.size)
    perturb = np.zeros(theta.size)

    e = 1e-4

    for p in range(theta.size):
        perturb[p] = e
        loss1, grad1 = cost_func(theta - perturb)
        loss2, grad2 = cost_func(theta + perturb)

        numgrad[p] = (loss2 - loss1) / (2 * e)
        perturb[p] = 0

    return numgrad

在經(jīng)過梯度檢測(cè)之后枕磁,我們要對(duì)權(quán)重參數(shù)重新進(jìn)行校正渡蜻,詳細(xì)代碼如下所示:

def debug_initialize_weights(fan_out, fan_in):
    w = np.zeros((fan_out, 1 + fan_in))
    w = np.sin(np.arange(w.size)).reshape(w.shape) / 10
    return w

有了以上代碼,梯度檢測(cè)算法的實(shí)現(xiàn)如下所示:

def check_nn_gradients(lmd):

    input_layer_size = 3
    hidden_layer_size = 5
    num_labels = 3
    m = 5

    # 產(chǎn)生一些隨機(jī)參數(shù)
    theta1 = debug_initialize_weights(hidden_layer_size, input_layer_size)
    theta2 = debug_initialize_weights(num_labels, hidden_layer_size)

    
    X = debug_initialize_weights(m, input_layer_size - 1)
    y = 1 + np.mod(np.arange(1, m + 1), num_labels)

    # 參數(shù)展開
    nn_params = np.concatenate([theta1.flatten(), theta2.flatten()])

    def cost_func(p):
        return nn_cost_function(p, input_layer_size, hidden_layer_size, num_labels, X, y, lmd)

    cost, grad = cost_func(nn_params)
    numgrad = compute_numerial_gradient(cost_func, nn_params)

    print(np.c_[grad, numgrad])

以上代碼中cost_func()函數(shù)和grad_func()函數(shù)的實(shí)現(xiàn)過程如下所示:

def cost_func(p):
    return nn_cost_function(p, input_layer_size, hidden_layer_size, num_labels, X, y, lmd)[0]


def grad_func(p):
    return nn_cost_function(p, input_layer_size, hidden_layer_size, num_labels, X, y, lmd)[1]

通過以上代碼的運(yùn)行计济,得到的反向傳播得到的梯度參數(shù)和數(shù)值化計(jì)算得到的梯度參數(shù)如下所示,通過分析茸苇,可以看出來,兩者大小基本一致沦寂。

  • 查看隱藏層
    通過調(diào)用display_data()函數(shù)学密,傳入隱藏層權(quán)重參數(shù),隱藏層的實(shí)現(xiàn)效果如下所示:

數(shù)據(jù)預(yù)測(cè)

通過輸入?yún)?shù)和已經(jīng)通過神經(jīng)網(wǎng)絡(luò)訓(xùn)練之后得到的權(quán)重參數(shù)传藏,就可以實(shí)現(xiàn)手寫數(shù)字的識(shí)別了腻暮,具體代碼如下,f返回值為訓(xùn)練精確度。

def predict(theta1, theta2, x):
    m = x.shape[0]

    x = np.c_[np.ones(m), x]
    h1 = sigmoid(np.dot(x, theta1.T))
    h1 = np.c_[np.ones(h1.shape[0]), h1]
    h2 = sigmoid(np.dot(h1, theta2.T))
    p = np.argmax(h2, axis=1) + 1

    return p

最后毯侦,運(yùn)行以上代碼哭靖,得到的訓(xùn)練精確度如下所示:


?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市侈离,隨后出現(xiàn)的幾起案子试幽,更是在濱河造成了極大的恐慌,老刑警劉巖卦碾,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件铺坞,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡蔗坯,警方通過查閱死者的電腦和手機(jī)康震,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來宾濒,“玉大人腿短,你說我怎么就攤上這事』婷危” “怎么了橘忱?”我有些...
    開封第一講書人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)卸奉。 經(jīng)常有香客問我钝诚,道長(zhǎng),這世上最難降的妖魔是什么榄棵? 我笑而不...
    開封第一講書人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任凝颇,我火速辦了婚禮潘拱,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘拧略。我一直安慰自己芦岂,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開白布垫蛆。 她就那樣靜靜地躺著禽最,像睡著了一般。 火紅的嫁衣襯著肌膚如雪袱饭。 梳的紋絲不亂的頭發(fā)上川无,一...
    開封第一講書人閱讀 49,829評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音虑乖,去河邊找鬼懦趋。 笑死,一個(gè)胖子當(dāng)著我的面吹牛决左,可吹牛的內(nèi)容都是我干的愕够。 我是一名探鬼主播,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼佛猛,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了坠狡?” 一聲冷哼從身側(cè)響起继找,我...
    開封第一講書人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎逃沿,沒想到半個(gè)月后婴渡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡凯亮,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年边臼,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片假消。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡柠并,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出富拗,到底是詐尸還是另有隱情臼予,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布啃沪,位于F島的核電站粘拾,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏创千。R本人自食惡果不足惜缰雇,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一入偷、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧械哟,春花似錦疏之、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至糯崎,卻和暖如春几缭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背沃呢。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工年栓, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人薄霜。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓某抓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親惰瓜。 傳聞我的和親對(duì)象是個(gè)殘疾皇子否副,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容