誤差反向傳播法 《深度學(xué)習(xí)入門(mén) 基于Python的理論實(shí)現(xiàn)》第五章


layout: post
title: 深度學(xué)習(xí)入門(mén) 基于Python的理論實(shí)現(xiàn)
subtitle: 第五章 誤差反向傳播法
tags: [Machine learning, Reading]


第五章 誤差反向傳播法

上一章介紹了神經(jīng)網(wǎng)絡(luò)的學(xué)習(xí)靡努,并通過(guò)數(shù)值微分計(jì)算了神經(jīng)網(wǎng)絡(luò)的權(quán)重參數(shù)的梯度鸠信,數(shù)值微分雖然簡(jiǎn)單丙挽,但是計(jì)算起來(lái)比較浪費(fèi)時(shí)間。本章使用一個(gè)能夠高效計(jì)算權(quán)重參數(shù)的梯度的方法--誤差反向傳播法滑肉。
正確理解反向傳播法,有兩種方法屡限,一種基于計(jì)算圖尘喝,一種基于數(shù)學(xué)式。后者是比較常見(jiàn)的方法送滞,本章通過(guò)計(jì)算圖來(lái)理解侠草。

5.1 計(jì)算圖

5.1.1 用計(jì)算圖求解

我們嘗試用計(jì)算圖解決問(wèn)題,目的是為了讓大家熟悉計(jì)算圖犁嗅。

問(wèn)題1:太郎在超市買(mǎi)了 2 個(gè) 100 日元一個(gè)的蘋(píng)果边涕,消費(fèi)稅是 10%,請(qǐng)計(jì)算支付金額褂微。

計(jì)算圖通過(guò)節(jié)點(diǎn)和箭頭表示計(jì)算過(guò)程功蜓,節(jié)點(diǎn)用圓圈表示,圓圈內(nèi)是計(jì)算的內(nèi)容宠蚂。將計(jì)算的中間結(jié)果寫(xiě)在箭頭上方式撼,表示各個(gè)節(jié)點(diǎn)的計(jì)算結(jié)果從左向右傳遞,對(duì)于上述問(wèn)題求厕,求解過(guò)程如圖所示著隆。


comput_graph_1.png

開(kāi)始時(shí)扰楼,蘋(píng)果的100日元流到 \times2 節(jié)點(diǎn),變成200日元美浦,然后傳遞到下一個(gè)節(jié)點(diǎn)弦赖,流向 \times1.1 節(jié)點(diǎn),變成220日元抵代。因此答案是220日元腾节。
上圖中把 \times2 \times1.1 整體擴(kuò)起來(lái),不過(guò)只用圓圈表示 \times 也是可以的荤牍,此時(shí)案腺,可以將 2 和 1.1 分別作為變量“蘋(píng)果的個(gè)數(shù)”和“消費(fèi)稅”表在外面。

comput_graph_2.png

問(wèn)題2:太郎在超市買(mǎi)了兩個(gè)蘋(píng)果三個(gè)橘子康吵,其中劈榨,蘋(píng)果每個(gè)100日元。橘子每個(gè)150日元晦嵌,消費(fèi)稅是10%同辣,請(qǐng)計(jì)算支付金額。按照上面的思路惭载,求解過(guò)程如圖所示旱函。

comput_graph_3.png.png

綜上,用計(jì)算圖解題的流程如下:

1.構(gòu)建計(jì)算圖

2.在計(jì)算圖上從左向右計(jì)算

第二部的“從左向右計(jì)算”是一種正方向上的傳播過(guò)程描滔,稱為正向傳播棒妨,與之相對(duì)應(yīng)的是反向傳播

5.1.2 局部計(jì)算

計(jì)算圖可以通過(guò)傳遞“局部計(jì)算”獲得最終結(jié)果含长。下面是一個(gè)局部計(jì)算的例子券腔。

comput_graph_4.png

這個(gè)圖也很好理解,結(jié)論是拘泞,無(wú)論全局計(jì)算有多么復(fù)雜纷纫,只要按照步驟,都可以最終計(jì)算出結(jié)果陪腌。

5.1.3 為何用計(jì)算圖解題

優(yōu)點(diǎn)一:局部計(jì)算辱魁,無(wú)論全局多么復(fù)雜的計(jì)算,都可以通過(guò)局部計(jì)算使各個(gè)節(jié)點(diǎn)致力于簡(jiǎn)單的計(jì)算诗鸭。
優(yōu)點(diǎn)二:通過(guò)反向傳播計(jì)算導(dǎo)數(shù)商叹。

我們重新思考問(wèn)題1,假設(shè)我們想知道蘋(píng)果價(jià)格的波動(dòng)會(huì)在多大程度上影響最終支付的金額只泼,也就是求“支付金額關(guān)于蘋(píng)果價(jià)格的導(dǎo)數(shù)”,設(shè)蘋(píng)果價(jià)格為 x,支付金額為 L卵洗,則相當(dāng)于求 \frac{\partial L}{\partial x}请唱。

現(xiàn)在使用計(jì)算圖的反向傳播求這個(gè)導(dǎo)數(shù)弥咪。

comput_graph_5.png

如上圖所示,反向傳播使用與正方向相反的箭頭(粗線)表示十绑。反向傳播傳遞“局部導(dǎo)數(shù)”聚至,將導(dǎo)數(shù)值寫(xiě)在下方,這里墜重支付金額關(guān)于蘋(píng)果價(jià)格的導(dǎo)數(shù)是2.2本橙,也就是說(shuō)蘋(píng)果價(jià)格每上升1元扳躬,最終支付金額會(huì)上漲2.2元。

5.2 鏈?zhǔn)椒▌t

5.2.1 計(jì)算圖的反向傳播

假設(shè)存在 y = f(x) 的計(jì)算甚亭,這個(gè)計(jì)算的反向傳播如圖所示贷币。

comput_graph_6.png

反向傳播的計(jì)算順序是,將信號(hào)E乘以節(jié)點(diǎn)的局部導(dǎo)數(shù) \frac{\partial y}{\partial x}亏狰,然后將結(jié)果傳遞給下一個(gè)節(jié)點(diǎn)役纹,這里所說(shuō)的局部導(dǎo)數(shù)是指正向傳播中 y = f(x) 的導(dǎo)數(shù),也就是y關(guān)于x的導(dǎo)數(shù) \frac{\partial y}{\partial x}暇唾。比如促脉,假設(shè) y = f(x) = x^2
則局部導(dǎo)數(shù)為 \frac{\partial y}{\partial x}= 2x 策州。把這個(gè)局部導(dǎo)數(shù)乘以上游傳過(guò)來(lái)的值( 本 例 中 為 E )瘸味, 然后傳遞給前面的節(jié)點(diǎn)。

5.2.2 鏈?zhǔn)椒▌t

介紹鏈?zhǔn)椒▌t之前够挂,先要從復(fù)合函數(shù)說(shuō)起旁仿,復(fù)合函數(shù)是多個(gè)函數(shù)構(gòu)成的函數(shù),比如 z = (x+y)^2 是由以下兩個(gè)式子構(gòu)成的下硕。
z = t^2 \\ t = x + y
鏈?zhǔn)椒▌t是關(guān)于復(fù)合函數(shù)的導(dǎo)數(shù)的性質(zhì)丁逝,定義如下。

如果某個(gè)函數(shù)由復(fù)合函數(shù)表示梭姓,則該復(fù)合函數(shù)的導(dǎo)數(shù)可以用構(gòu)成復(fù)合函數(shù)的各個(gè)函數(shù)的導(dǎo)數(shù)的乘積表示

這就是鏈?zhǔn)椒▌t的原理霜幼,用上面的表達(dá)式為例,\frac{\partial z}{\partial x}(z關(guān)于x的導(dǎo)數(shù))可以用 \frac{\partial z}{\partial t} (z關(guān)于t的導(dǎo)數(shù))和 \frac{\partial t}{\partial x}(t關(guān)于x的導(dǎo)數(shù))的乘積表示誉尖。數(shù)學(xué)表示如下:

\frac{\partial z}{\partial x} = \frac{\partial z}{\partial t}\frac{\partial t}{\partial x}

式子中的 {\partial t} 可以相互抵消罪既。

現(xiàn)在我們用鏈?zhǔn)椒▌t,試著求上面表達(dá)式的導(dǎo)數(shù)铡恕,接下來(lái)要求式子中的局部導(dǎo)數(shù)(偏導(dǎo)數(shù))

\frac{\partial z}{\partial t} = 2t \\ \frac{\partial t}{\partial x} = 1

于是可以得到:

\frac{\partial z}{\partial x} = \frac{\partial z}{\partial t}\frac{\partial t}{\partial x}=2t \times 1 = 2(x+y)

5.2.3 鏈?zhǔn)椒▌t和計(jì)算圖

現(xiàn)在我們嘗試將鏈?zhǔn)椒▌t的計(jì)算用計(jì)算圖表達(dá)出來(lái)琢感。

comput_graph_7.png

如圖所示,計(jì)算圖的反向傳播從右往左傳播信號(hào)探熔,反向傳播的計(jì)算順序是驹针,先將節(jié)點(diǎn)的輸入信號(hào)乘以節(jié)點(diǎn)的偏導(dǎo)數(shù),然后再傳遞給下一個(gè)節(jié)點(diǎn)诀艰。比如柬甥,反向傳播時(shí)饮六,“**2”節(jié)點(diǎn)的輸入是 \frac{\partial z}{\partial z},將其乘以局部導(dǎo)數(shù) \frac{\partial z}{\partial z} 因?yàn)檎騻鞑サ妮斎胧莟苛蒲,輸出是z卤橄,所以這個(gè)節(jié)點(diǎn)的局部導(dǎo)數(shù)是 \frac{\partial z}{\partial t} 然后傳遞給下一個(gè)節(jié)點(diǎn)。
在圖中最左邊是反向傳播的結(jié)果臂外,他的計(jì)算基于上面的規(guī)則窟扑,因此有 \frac{\partial z}{\partial z}\frac{\partial z}{\partial t}\frac{\partial t}{\partial x} = \frac{\partial z}{\partial t}\frac{\partial t}{\partial x}=\frac{\partial z}{\partial x},對(duì)應(yīng)z關(guān)于x的導(dǎo)數(shù)。代入得到 \frac{\partial z}{\partial x} 的結(jié)果是 2(x+y)

comput_graph_8.png

5.3 反向傳播

5.3.1 加法節(jié)點(diǎn)的反向傳播

首先看一下加法節(jié)點(diǎn)的反向傳播這漏健,這里以 z = x + y 為對(duì)象嚎货,觀察反向傳播。z = x + y 的導(dǎo)數(shù)可以由下式計(jì)算出來(lái)漾肮。

\frac{\partial z}{\partial x} = 1 \\ \frac{\partial z}{\partial y} = 1

上面兩個(gè)式子都等于1厂抖,用計(jì)算圖表示如下所示。

comput_graph_9.png

comput_graph_10.png

下面來(lái)看一個(gè)具體的例子克懊。假設(shè)有“10 + 5 =15”這樣的計(jì)算忱辅,加法節(jié)點(diǎn)的反向傳播只是將信號(hào)輸出到下一個(gè)節(jié)點(diǎn)。

5.3.2 乘法節(jié)點(diǎn)的反向傳播

用同樣的方式看乘法節(jié)點(diǎn)谭溉。假設(shè) z =xy 于是有

\frac{\partial z}{\partial x} = y \\ \frac{\partial z}{\partial y} = x

下面看一個(gè)具體的例子墙懂, 10 \times 5 =50

comput_graph_11.png
comput_graph_12.png

5.3.3 蘋(píng)果的例子

接著來(lái)思考一下蘋(píng)果的例子扮念。這里要解的問(wèn)題是蘋(píng)果的價(jià)格损搬、蘋(píng)果的個(gè)數(shù)、消費(fèi)稅這3個(gè)變量各自如何影響最終支付的金額柜与。這個(gè)問(wèn)題相當(dāng)于求“支付金額關(guān)于蘋(píng)果的價(jià)格的導(dǎo)數(shù)”“支付金額關(guān)于蘋(píng)果的個(gè)數(shù)的導(dǎo)數(shù)”“支付金額關(guān)于消費(fèi)稅的導(dǎo)數(shù)”巧勤。


comput_graph_13.png

5.4 簡(jiǎn)單層的實(shí)現(xiàn)

本節(jié)用python實(shí)現(xiàn)前面的蘋(píng)果例子,乘法節(jié)點(diǎn)稱為“乘法層”弄匕,加法節(jié)點(diǎn)稱為“加法層”颅悉。

5.4.1 乘法層的實(shí)現(xiàn)

class MulLayer:
    def __init__(self):
        self.x = None
        self.y = None

    def forward(self, x, y):
        self.x = x
        self.y = y
        out = x * y

        return out

    def backward(self, dout):
        dx = dout * self.y
        dy = dout * self.x

        return dx,dy

init() 中會(huì)初始化實(shí)例變量 x 和 y,它們用于保存正向傳播時(shí)的輸入值迁匠。 forward() 接收 x 和 y 兩個(gè)參數(shù)剩瓶,將它們相乘后輸出质和。backward() 將從上游傳 來(lái)的導(dǎo)數(shù)(dout)乘以正向傳播的翻轉(zhuǎn)值狭莱,然后傳給下游。

comput_graph_13.png

參照上圖可以作如下實(shí)現(xiàn)蝉绷。


apple = 100
apple_num = 2
tax = 1.1

#layer

mul_apple_layer = MulLayer()
mul_tax_layer = MulLayer()

#forward

apple_price = mul_apple_layer.forward(apple,apple_num)
price = mul_tax_layer.forward(apple_price,tax)

print(price)



#backward

dprice = 1
dapple_price,dtax = mul_tax_layer.backward(dprice)
dapple,dapple_num = mul_apple_layer.backward(dapple_price)

print(dapple,dapple_num,dtax)

5.4.2 加法層的實(shí)現(xiàn)


class AddLayer:
    def __init__(self):
        pass

    def forward(self,x,y):

        out = x + y

        return out

    def backward(self,dout):

        dx = dout * 1
        dy = dout * 1

        return dx,dy
comput_graph_14.png

使用之前的方法進(jìn)行實(shí)現(xiàn)亡哄。

apple = 100
orange = 150
apple_num = 2
orange_num = 3
tax = 1.1

#layer

mul_apple_layer = MulLayer()
mul_orange_layer = MulLayer()
add_apple_orange_layer = AddLayer()
mul_tax_layer = MulLayer()

#forward

apple_price = mul_apple_layer.forward(apple,apple_num)
orange_price = mul_orange_layer.forward(orange,orange_num)
all_price = add_apple_orange_layer.forward(apple_price,orange_price)
price = mul_tax_layer.forward(all_price,tax)

#backward
dprice = 1
dall_price,dtax   = mul_tax_layer.backward(dprice)
dapple_price, dorange_price = add_apple_orange_layer.backward(dall_price)
dorange,dorange_num = mul_orange_layer.backward(dorange_price)
dapple,dapple_num = mul_apple_layer.backward(dapple_price)

print(price)
print(dapple_num,dapple,dorange,dorange_num,dtax)

5.5 激活函數(shù)層的實(shí)現(xiàn)

現(xiàn)在把計(jì)算圖的思想應(yīng)用到神經(jīng)網(wǎng)絡(luò)枝缔。

5.5.1 ReLU層

激活函數(shù)ReLU數(shù)學(xué)表達(dá)式如下:

f(x) = \begin{cases} x & x \gt 0 \\ 0 & x \leqslant 0 \end{cases}

可以求出y關(guān)于x的導(dǎo)數(shù):

\frac{\partial y}{\partial x} = \begin{cases} 1 & x \gt 0 \\ 0 & x \leqslant 0 \end{cases}

comput_graph_15.png

根據(jù)上面的表達(dá)式可以得知,正向傳播時(shí)如果輸入x大于零蚊惯,則反向傳播會(huì)將上游的值原封不動(dòng)的傳遞魂仍,當(dāng)正向傳播的值x小于0時(shí)拐辽,會(huì)將信號(hào)停留在此處。

下面是是實(shí)現(xiàn):

class Relu:
   def __init__(self):
       self.mask = None

   def forward(self, x):
       self.mask = (x <= 0)
       out = x.copy()
       out[self.mask] = 0 #True的位置變成0 也就是小于0的變成0

       return out

   def backward(self,dout):
       dout[self.mask] = 0
       dx = dout

       return dx

x = np.array([[1,-0.5],[-2.0,3.0]])
print(x)
mask = (x<=0)
out = x.copy()
out[mask] = 0
print(out)

5.5.2 Sigmoid 層

接下來(lái)是sigmoid函數(shù)的實(shí)現(xiàn)

y = \frac{1}{1+exp(-x)}

計(jì)算圖如下:

comput_graph_16.png

下面簡(jiǎn)單看一下反向傳播的流程:

步驟1

“/”節(jié)點(diǎn)表示 y=\frac{1}{x} 導(dǎo)數(shù)如下:

\frac{\partial y}{\partial x} = -\frac{1}{x^2} \\ =-y^2

因此如下圖所示

comput_graph_17.png

步驟2
下面的節(jié)點(diǎn)是加法節(jié)點(diǎn)擦酌,原封不動(dòng)的傳給下游

comput_graph_18.png

步驟3
“exp”節(jié)點(diǎn)表示 y = exp(x), 他的導(dǎo)數(shù)由下式表示。

\frac{\partial y}{\partial x} = exp(x)

comput_graph_19.png

步驟4

乘法節(jié)點(diǎn)翻轉(zhuǎn)相乘菠劝。

comput_graph_20.png

根據(jù)上面的計(jì)算赊舶,簡(jiǎn)化后,得到如圖所示的圖赶诊,和上面的計(jì)算結(jié)果相同笼平。

comput_graph_21.png

進(jìn)一步作整理:

$$

\frac{\partial L}{\partial y}y^2exp(-x) = \frac{\partial L}{\partial y}\frac{1}{(1+exp(-x))^2}exp(-x) \
=\frac{\partial L}{\partial y}\frac{1}{1+exp(-x)}\frac{exp(-x)}{1+exp(-x)} \
=\frac{\partial L}{\partial y}y(1-y)
$$

因此,我們可以簡(jiǎn)化如下:

comput_graph_22.png

以下是實(shí)現(xiàn):

class Sigmoid:
    def __init__(self):
        self.out = None

    def forward(self, x):
        out = 1 / (1 + np.exp(-x))
        self.out = out

        return out

    def backward(self, dout):
        dx = dout * (1.0 - self.out) * self.out

        return dx

5.6 Affine/Softamx層的實(shí)現(xiàn)

5.6.1 Affine層

上一章講解了矩陣的乘法舔痪,使用Y= np.dot(X, W) + B計(jì)算寓调,這里把這個(gè)運(yùn)算表達(dá)出來(lái)。

comput_graph_23.png
comput_graph_24.png

現(xiàn)在考慮上圖的反向傳播锄码。對(duì)于加法節(jié)點(diǎn)來(lái)說(shuō)夺英,原封不動(dòng)的傳遞 \frac{\partial L}{\partial Y},對(duì)于dot節(jié)點(diǎn),交換乘轉(zhuǎn)置滋捶,得到 \frac{\partial L}{\partial Y}W^T痛悯。同理得到:

\frac{\partial L}{\partial X} = \frac{\partial L}{\partial Y}W^T \\ \frac{\partial L}{\partial W} = X^T\frac{\partial L}{\partial Y}

轉(zhuǎn)置的概念不再贅述。

comput_graph_25.png

簡(jiǎn)化上面的表達(dá)式重窟,可以得到:

comput_graph_26.png

5.6.2 批版本的Affine層

前面介紹的X是以單個(gè)數(shù)據(jù)為對(duì)象的载萌,現(xiàn)在考慮N個(gè)數(shù)據(jù)一起正向傳播的情況。

comput_graph_28.png

實(shí)現(xiàn):


class Affine:
    def __init__(self, W, b):
        self.W = W
        self.b = b
        self.x = None
        self.dW = None
        self.db = None


    def forward(self, x):
        self.x = x
        out = np.dot(x, self.W) + self.b

        return out

    def backward(self, dout):
        dx = np.dot(dout, self.W.T)
        self.dW = np.dot(self.x.T, dout)
        self.db = np.sum(dout,axis = 0)

        return dx

5.6.3 Softmax-with-Loss 層

最后介紹輸出層的softmax函數(shù)巡扇。手寫(xiě)數(shù)字識(shí)別的時(shí)候扭仁,整個(gè)神經(jīng)網(wǎng)絡(luò)的結(jié)構(gòu)如圖所示。

comput_graph_29.png

下面實(shí)現(xiàn)Softmax層厅翔,考慮到這里也包含交叉熵誤差乖坠,所以也稱為Softmax-with-Loss層。以下是計(jì)算圖和簡(jiǎn)化版:

comput_graph_30.png
comput_graph_31.png

實(shí)現(xiàn):



def cross_entropy_error(y,t):
    delta = 1e-7
    return -np.sum(t*np.log(y + delta))

def softmax(x):
    exp_x = np.exp(x-np.max(x))
    sum_exp_x = np.sum(exp_x)

    return exp_x/sum_exp_x

class SoftmaxWithLoss:

    def __init__(self):
        self.loss = None
        self.y = None
        self.t = None


    def forward(self, x, t):
        self.t = t
        self.y = softmax(x)
        self.loss = cross_entropy_error(self.y,self.t)

        return self.loss

    def backward(self,dout=1):
        batch_size = self.t.shape[0]
        dx = (self.y - self.t) / batch_size

        return dx

5.7 誤差反向傳播法的實(shí)現(xiàn)

5.7.1 神經(jīng)網(wǎng)絡(luò)學(xué)習(xí)的全貌

前提

神經(jīng)網(wǎng)絡(luò)中有合適的權(quán)重和偏置知给,調(diào)整權(quán)重和偏置以便擬合訓(xùn)練數(shù)據(jù)的 過(guò)程稱為學(xué)習(xí)瓤帚。神經(jīng)網(wǎng)絡(luò)的學(xué)習(xí)分為下面 4 個(gè)步驟。

步驟1(mini-batch)

從訓(xùn)練數(shù)據(jù)中隨機(jī)選擇一部分?jǐn)?shù)據(jù)涩赢。

步驟2(計(jì)算梯度)

計(jì)算損失函數(shù)關(guān)于各個(gè)權(quán)重參數(shù)的梯度戈次。

步驟3(更新參數(shù))

將權(quán)重參數(shù)沿梯度方向進(jìn)行微小的更新。

步驟4(重復(fù))

重復(fù)步驟 1筒扒、步驟 2怯邪、步驟 3。

5.7.2 對(duì)應(yīng)誤差反向傳播法的神經(jīng)網(wǎng)絡(luò)的實(shí)現(xiàn)

下面是TwoLayerNet的代碼實(shí)現(xiàn):

import sys, os
sys.path.append(os.pardir)  # 為了導(dǎo)入父目錄的文件而進(jìn)行的設(shè)定
import numpy as np
from common.layers import *
from common.gradient import numerical_gradient
from collections import OrderedDict

class TwoLayerNet:

    def __init__(self, input_size, hidden_size, output_size, weight_init_std=0.01):

        #初始化權(quán)重
        self.params = {}
        self.params['W1'] = weight_init_std * np.random.randn(input_size, hidden_size)
        self.params['b1'] = np.zeros(hidden_size)
        self.params['W2'] = weight_init_std * np.random.randn(hidden_size, output_size)
        self.params['b2'] = np.zeros(output_size)


        #生成層

        self.layers = OrderedDict()
        self.layers['Affine1'] = Affine(self.params['W1'], self.params['b1'])
        self.layers['Relu1'] = Relu()
        self.layers['Affine2'] = Affine(self.params['W'],self.params['b2'])

        self.lastlayer = SoftmaxWithLoss()

        def predict(self, x):
            for layer in self.layers.values():
                x = layer.forward(x)

            return x

        def loss(self, x, t):
            y = self.predict(x)

            return self.lastlayer.forward(y, t)

        def accuracy(self, x, t):
            y = self.predict(x)
            y = np.argmax(y, axis = 1)
            if t.ndim != 1 : t = np.argmax(t, axis=1)

            accuracy = np.sum(y == t) / float(x.shape[0])

            return accuracy

        def numerical_gradient(self, x, t):
            loss_W = lambda W : self.loss(x, t)

            grads = {}
            grads['W1'] = numerical_gradient(loss_W, self.params['W1'])
            grads['b1'] = numerical_gradient(loss_W, self.params['b1'])
            grads['W2'] = numerical_gradient(loss_W, self.params['W2'])
            grads['b2'] = numerical_gradient(loss_W, self.params['b2'])

            return grads

        def gradient(self, x, t):
            self.loss(x, t)

            dout = 1
            dout = self.lastLayer.backward(dout)

            layers = list(self.layers.values())
            layers.reverse()
            for layer in layers:
                dout = layer.backward(dout)
            # 設(shè)定
            grads = {}
            grads['W1'] = self.layers['Affine1'].dW
            grads['b1'] = self.layers['Affine1'].db
            grads['W2'] = self.layers['Affine2'].dW
            grads['b2'] = self.layers['Affine2'].db

            return grads
import sys, os
sys.path.append(os.pardir)
import numpy as np
from dataset.mnist import load_mnist
from two_layer_net import TwoLayerNet
# 讀入數(shù)據(jù)

(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label = True)

network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10)
x_batch = x_train[:3]

t_batch = t_train[:3]
grad_backprop = network.gradient(x_batch, t_batch)
# 求各個(gè)權(quán)重的絕對(duì)誤差的平均值
grad_numerical = network.numerical_gradient(x_batch, t_batch)
for key in grad_numerical.keys():
    diff = np.average( np.abs(grad_backprop[key] - grad_numerical[key]) )
    print(key + ":" + str(diff))

計(jì)算后的結(jié)果如下:

W1:3.5949338619330523e-10
b1:2.239133814485334e-09
W2:5.190797970067163e-09
b2:1.4008290402101054e-07

結(jié)果表明花墩,使用數(shù)值微分和誤差反向傳播法求出的梯度的差非常小悬秉。也就是說(shuō)澄步,反向傳播法是正確的。

5.7.4 使用誤差反向傳播法的學(xué)習(xí)

實(shí)現(xiàn):


import sys, os
sys.path.append(os.pardir)
import numpy as np
from dataset.mnist import load_mnist
from two_layer_net import TwoLayerNet

(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label = True)

network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10)

iters_num = 10000
train_size = x_train.shape[0]
batch_size = 100
learning_rate = 0.1
train_loss_list = []
train_acc_list = []
test_acc_list = []

iter_per_epoch = max(train_size / batch_size, 1)

for i in range(iters_num):
    batch_mask = np.random.choice(train_size, batch_size)
    x_batch = x_train[batch_mask]
    t_batch = t_train[batch_mask]

    grad = network.gradient(x_batch, t_batch)

    for key in ('W1', 'b1', 'W2', 'b2'):
        network.params[key] -= learning_rate * grad[key]

    loss = network.loss(x_batch, t_batch)
    train_loss_list.append(loss)
    if i % iter_per_epoch == 0:
        train_acc = network.accuracy(x_train, t_train)
        test_acc = network.accuracy(x_test, t_test)
        train_acc_list.append(train_acc)
        test_acc_list.append(test_acc)
        print(train_acc, test_acc)

最大的變化是計(jì)算速度顯著提高和泌。

5.8 小結(jié)

本章我們介紹了將計(jì)算過(guò)程可視化的計(jì)算圖村缸,并使用計(jì)算圖,介紹了神經(jīng)網(wǎng)絡(luò)中的誤差反向傳播法武氓,并以層為單位實(shí)現(xiàn)了神經(jīng)網(wǎng)絡(luò)中的處理梯皿。

  • 通過(guò)使用計(jì)算圖,可以直觀地把握計(jì)算過(guò)程县恕。
  • 計(jì)算圖的節(jié)點(diǎn)是由局部計(jì)算構(gòu)成的东羹。局部計(jì)算構(gòu)成全局計(jì)算。
  • 計(jì)算圖的正向傳播進(jìn)行一般的計(jì)算忠烛。通過(guò)計(jì)算圖的反向傳播属提,可以計(jì)算各個(gè)節(jié)點(diǎn)的導(dǎo)數(shù)。
  • 通過(guò)將神經(jīng)網(wǎng)絡(luò)的組成元素實(shí)現(xiàn)為層美尸,可以高效地計(jì)算梯度(反向傳播法)冤议。
  • 通過(guò)比較數(shù)值微分和誤差反向傳播法的結(jié)果,可以確認(rèn)誤差反向傳播法的實(shí)現(xiàn)是否正確(梯度確認(rèn))火惊。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末求类,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子屹耐,更是在濱河造成了極大的恐慌尸疆,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件惶岭,死亡現(xiàn)場(chǎng)離奇詭異寿弱,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)按灶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)症革,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人鸯旁,你說(shuō)我怎么就攤上這事噪矛。” “怎么了铺罢?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵艇挨,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我韭赘,道長(zhǎng)缩滨,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮脉漏,結(jié)果婚禮上苞冯,老公的妹妹穿的比我還像新娘。我一直安慰自己侧巨,他們只是感情好舅锄,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著刃泡,像睡著了一般巧娱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上烘贴,一...
    開(kāi)封第一講書(shū)人閱讀 49,036評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音撮胧,去河邊找鬼桨踪。 笑死,一個(gè)胖子當(dāng)著我的面吹牛芹啥,可吹牛的內(nèi)容都是我干的锻离。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼墓怀,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼汽纠!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起傀履,我...
    開(kāi)封第一講書(shū)人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤虱朵,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后钓账,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體碴犬,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年梆暮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了服协。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡啦粹,死狀恐怖偿荷,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情唠椭,我是刑警寧澤跳纳,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站泪蔫,受9級(jí)特大地震影響棒旗,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一铣揉、第九天 我趴在偏房一處隱蔽的房頂上張望饶深。 院中可真熱鬧,春花似錦逛拱、人聲如沸敌厘。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)俱两。三九已至,卻和暖如春曹步,著一層夾襖步出監(jiān)牢的瞬間宪彩,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工讲婚, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留尿孔,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓筹麸,卻偏偏與公主長(zhǎng)得像活合,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子物赶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

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