• <strike id="fdgpu"><input id="fdgpu"></input></strike>
    <label id="fdgpu"></label>
    <s id="fdgpu"><code id="fdgpu"></code></s>

  • <label id="fdgpu"></label>
  • <span id="fdgpu"><u id="fdgpu"></u></span>

    <s id="fdgpu"><sub id="fdgpu"></sub></s>
    您當前的位置是:  首頁(yè) > 新聞 > 專(zhuān)家觀(guān)點(diǎn) >

    李理:從Image Caption Generation理解深度學(xué)習3

    2016-12-13 14:55:37   作者:   來(lái)源:CTI論壇   評論:0  點(diǎn)擊:


      本系列文章面向程序員,希望通過(guò)Image Caption Generation,一個(gè)有意思的具體任務(wù),深入淺出地介紹深度學(xué)習的知識,涉及到很多深度學(xué)習流行的模型,如CNN,RNN/LSTM,Attention等。本文為第三篇。 
      作者:李理,目前就職于環(huán)信,即時(shí)通訊云平臺和全媒體智能客服平臺,在環(huán)信從事智能客服和智能機器人相關(guān)工作,致力于用深度學(xué)習來(lái)提高智能機器人的性能。
      相關(guān)文章:
      2.2.5反向傳播算法的推導
      前面我們用很簡(jiǎn)單的幾十行python代碼基本上完成了一個(gè)多層神經(jīng)網(wǎng)絡(luò )。但是還差最重要的部分,那就是計算lossfunction對參數的偏導數,也就是反向傳播算法。下面我們來(lái)仔細的完成公式的推導,以及接下來(lái)會(huì )講怎么用代碼來(lái)實(shí)現。這一部分數學(xué)公式多一些,可能很多讀者會(huì )希望跳過(guò)去,不過(guò)我還是建議大家仔細的閱讀,其實(shí)神經(jīng)網(wǎng)絡(luò )用到的數學(xué)相比svm,bayesnetwork等機器學(xué)習算法,已經(jīng)非常簡(jiǎn)單了。請讀者閱讀的時(shí)候最好準備一支筆和幾張白紙,每一個(gè)公式都能推導一下。如果堅持下來(lái),你會(huì )覺(jué)得其實(shí)挺簡(jiǎn)單的。
      (1)feedforward階段的矩陣參數表示和計算
      之前我們討論的是一個(gè)神經(jīng)元的計算,而在代碼里用到的卻是矩陣向量乘法。而且細心的讀者會(huì )發(fā)現我們在構造參數矩陣weights的時(shí)候,行數和列數分別是后一層的節點(diǎn)數和前一層的節點(diǎn)數。這似乎有點(diǎn)不自然,為什么不反過(guò)來(lái)呢?看過(guò)下面這一部分就會(huì )明白了。
    \
      首先我們熟悉一下第L(因為小寫(xiě)的L和1太像,所以我用大寫(xiě)的L)層的參數w_jk。它表示第L-1層的第k個(gè)神經(jīng)元到第L層的第j個(gè)神經(jīng)元的權重。比如第3層的w_24,參考上面的圖,它表示的是第2層的第4個(gè)神經(jīng)元到第3層的第二個(gè)神經(jīng)元。
      對bias和激活函數后的結果a也采用類(lèi)似的記號,如下圖所示。
    \
      b_32表示第2層的第3個(gè)神經(jīng)元的bias,而a_13第3層的第1個(gè)神經(jīng)元的激活。
      使用上面的記號,我們就可以計算第L層的第j個(gè)神經(jīng)元的輸出a_jl:
    \
      第L層的第j個(gè)神經(jīng)元的輸入是L-1層的a_1,a_2,...;對應的權值是w_j1,w_j2,...;bias是b_jL。所以a_jL就是上面的公式,k的范圍是從1到第L-1層的神經(jīng)元的個(gè)數。
      為了用矩陣向量乘法來(lái)一次計算第L層的所有神經(jīng)元的輸出,我們需要定義第L層的參數矩陣w_l,它的大小是m*n,其中m是第L層的神經(jīng)元個(gè)數;而n則是第L-1層的個(gè)數。它的第i行第j列就是我們上面定義的w_jk。此外我們還要定義向量b_l,它的大小是m(也就是第L層神經(jīng)元的個(gè)數),它的第j個(gè)元素就是我們上面定義的b_j。
      最后,我們定義element-wise的函數,比如f(x)=x^2,如果輸入是一個(gè)向量,那么結果是和輸入一樣大小的向量,它的每個(gè)元素是對輸入向量的每一個(gè)元素應用這個(gè)函數的結果。
    \
      有了上面的定義,我們就可以一次計算出第L層的輸出(一個(gè)長(cháng)度為m的向量)
    \
      下面是對上面這個(gè)公式的詳細證明(說(shuō)明):
      我們需要證明的是向量aL的第j個(gè)元素就是前面的a_jL
    \
      此外,為了方便后面的求解,我們把加權累加和也用一個(gè)符號z_l來(lái)表示。
    \
      其中,它的第j個(gè)元素就是第L層的第j個(gè)神經(jīng)元的加權累加和:
    \
      這樣a_l就可以簡(jiǎn)單的對z_l的每個(gè)元素計算激活函數
    \
      現在我們再回顧一下feedforward的代碼就非常直觀(guān)了:
    def feedforward(self, a):
    """Return the output of the network if a is input."""
    for b, w in zip(self.biases, self.weights):
    a = sigmoid(np.dot(w, a)+b)
    return a
      傳給函數feedforward的參數a就是輸入向量x,第一層就是x,第二層就是第一個(gè)隱層,每一層的計算就是非常簡(jiǎn)單的參數矩陣w_l乘以上一層的激活a_l-1在加上b_l,然后用激活函數計算。
      初始化的時(shí)候w的大小是(后一層的神經(jīng)元個(gè)數)*(前一層的神經(jīng)元個(gè)數),再回顧一下初始化參數的代碼:
    # sizes = [784, 30, 10]
    def __init__(self, sizes):
    self.num_layers = len(sizes)
    self.sizes = sizes
    self.biases = [np.random.randn(y, 1) for y in sizes[1:]]
    self.weights = [np.random.randn(y, x)for x, y in zip(sizes[:-1], sizes[1:])]
      x,yinzip(sizes[:-1],sizes[1:])x是第一層到最后倒數第二層,y是第二層到最后一層,比如上面的sizes=[784,30,10]
      x是[784,30],y是[30,10],注意隨機的矩陣是(y,x),所以self.weights是兩個(gè)矩陣,大小分別是30*784和10*30
      (2)關(guān)于損失函數C的兩個(gè)假設
      1.損失函數是每個(gè)訓練數據的損失的平均
      也就是C是這樣的形式:
    \
      對于之前我們使用的MSE損失函數,這是滿(mǎn)足的。我們使用batch的梯度下降的時(shí)候需要求C對參數w的偏導數,因為損失函數是每個(gè)訓練數據的損失的平均,所以我們只需要求每個(gè)數據的偏導數,然后加起來(lái)平均就行。這個(gè)假設幾乎所有的損失函數都是滿(mǎn)足的【我是沒(méi)見(jiàn)過(guò)損失函數不滿(mǎn)足這個(gè)條件】
      損失函數是最后一層輸出的函數
    \
      這個(gè)條件幾乎常見(jiàn)的損失函數都是這樣的,我們之前時(shí)候的MSE就是計算最后一層的輸出aL和正確的y(one-hot)的均方誤差,顯然是滿(mǎn)足的。
      (3)Hadamard product
      這個(gè)名字看起來(lái)很復雜,其實(shí)很簡(jiǎn)單,就是兩個(gè)向量elementwise的乘法。看一個(gè)例子就清楚了:
    \
      (4)反向傳播算法(back propagation)的4個(gè)公式
      回顧一下,我們之前說(shuō)了,梯度下降其實(shí)最核心的問(wèn)題就是求損失函數對每一個(gè)參數的偏導數。那我們就直接一個(gè)一個(gè)求好了,為什么又要搞出一個(gè)反向傳播算法呢?其實(shí)這個(gè)算法在不同的領(lǐng)域被不同的人重復“發(fā)現”過(guò)很多次,有過(guò)很多不同的名字,最本質(zhì)的應該就是逆向求導(reverse-mode differentiation)或者叫做自動(dòng)求導(automatic differentiation)。自動(dòng)求導(AD)是非常通用的一種求偏導數的方法,很早就在流體力學(xué)和大氣物理等領(lǐng)域使用,反向傳播算法可以認為是AD在神經(jīng)網(wǎng)絡(luò )中的應用。不過(guò)最早發(fā)現這個(gè)算法的人(是誰(shuí)最早好像還有點(diǎn)爭議)并不是先知道AD可以直接用于神經(jīng)網(wǎng)絡(luò ),他發(fā)現這個(gè)算法是基于錯誤的反向傳播而得到的,所有命名為(錯誤的)反向傳播算法。后面我們會(huì )講到AD,這是一個(gè)強大的算法,任何一個(gè)函數,你能把它分解成有向無(wú)環(huán)圖的計算圖【函數一般都能分解成一些無(wú)依賴(lài)的最基礎的變量的復合函數,因此肯定可以表示成這樣一個(gè)有向無(wú)環(huán)圖】,然后每個(gè)節點(diǎn)都表示一個(gè)函數。只要你能求出這個(gè)函數在特定點(diǎn)的梯度【也就是這個(gè)函數對所以自變量的偏導數】(不需要求解析的偏導數,當然很多情況,這些函數都是能直接求出解析解,然后代入這個(gè)特定點(diǎn)就行,但理論上我們是可以用其他方法,比如數值梯度近似來(lái)求的),就能自動(dòng)的計算損失函數對每一個(gè)參數的偏導數(也是在這個(gè)點(diǎn)的),而且只要反向根據拓撲排序遍歷這個(gè)圖一次就行,非常高效和簡(jiǎn)單。后面我們會(huì )詳細的介紹AD。這個(gè)方法非常通用,TensorFlow的核心就是AD。使用AD的框架就比較靈活,我想“創(chuàng )造”一種新的網(wǎng)絡(luò )結構,我又不想【其實(shí)更可能是不會(huì )】推導出梯度的公式,那么我只需要把我的網(wǎng)絡(luò )能用這樣一個(gè)有向無(wú)環(huán)圖表示就行。當然節點(diǎn)必須要能夠求出梯度來(lái),一般我們的函數比如矩陣的運算,卷積等等TensorFlow都封裝好了——它把它叫做一個(gè)op。我們只需要搭積木一樣把這個(gè)計算圖定義出來(lái),TensorFlow就自動(dòng)的能根據AD計算出損失函數對所有參數的梯度來(lái)了。當然如果你要用到一個(gè)TensorFlow沒(méi)有的op,那你就需要根據它的規范實(shí)現這個(gè)op,一個(gè)op最核心的接口就是兩個(gè),一個(gè)是輸入x,求f(x);另一個(gè)就是求f在某個(gè)x0點(diǎn)的梯度。
      不過(guò)這里,我們還是沿著(zhù)神經(jīng)網(wǎng)絡(luò )的發(fā)展歷史,從錯誤的反向傳播角度來(lái)理解和推導這個(gè)算法。
      首先,我們會(huì )對每一個(gè)神經(jīng)元比如第L層的第j個(gè),都定義一個(gè)錯誤δ_jL
    \
      也就是損失函數對z也就是線(xiàn)性累加和的偏導數。為什么定義這樣一個(gè)東西呢?我們假設在第L層的第j個(gè)神經(jīng)元上有一個(gè)精靈(Daemon)
    \
      當這個(gè)神經(jīng)元得到來(lái)自上一次的輸入累加計算出z_jL的時(shí)候,它會(huì )惡作劇的給一點(diǎn)很小的干擾Δz_jL。原來(lái)它應該輸出的是σ(z_jL),現在變成了σ(z_jL+Δz_jL)。這個(gè)微小的變化逐層傳播,最終導致?lián)p失函數C也發(fā)生如下的變化:
    \
      這個(gè)其實(shí)就是導數的直覺(jué)定義:微小的Δx引起微小的Δy,Δy/Δx約等于導數。
      不過(guò)這個(gè)精靈是個(gè)好精靈,它想幫助我們減少損失。當
    \
      大于0的時(shí)候,它讓Δz_jL小于0,反之當它小于0的時(shí)候它讓Δz_jL大于0.這樣
    \
      總是小于0
      因此我們的loss就會(huì )變小。而其絕對值越大,我們的損失減少的越多。
      當然你會(huì )說(shuō)為什么不能讓Δz_jL非常大,這樣我們的損失總是減少很多?可惜這個(gè)精靈是個(gè)數學(xué)家,它說(shuō)如果Δx太大,那么Δy=df/dx*Δx就不準確了。
      所以我們可以這樣認為:它就是第L層的第j個(gè)神經(jīng)元“引起”的“錯誤”。如果絕對值大,則它的“責任”也大,它就得多做出一些調整;反之如果它趨近于0,說(shuō)明它沒(méi)有什么“責任”,也就不需要做出什么改變。
      因此通過(guò)上面的啟發(fā),我們定義出δ_jL來(lái)。
    \
      接下來(lái)我們逐個(gè)介紹反向傳播算法的4個(gè)公式。
      公式1.第L層(最后一層)的錯誤
    \
      這個(gè)公式的第一項,就是損失C對a_jL的導數,它越大,說(shuō)明C受a_jL的影響也就越大,如果有了錯誤,第a_jL的“責任”也就越大,錯誤也就越大。第二項是a_jL受z_jL的影響。兩者乘起來(lái)就是z_jL對最終損失的影響,也就是它的“責任”的大小。
      這個(gè)公式很好計算,首先第二項就是把z_jL的值(這個(gè)在feedforward節點(diǎn)就算出來(lái)并存儲下來(lái)了)代入σ'(x)。如果σ是sigmoid函數,我們前面也推導過(guò)它的導數:σ’(x)=σ(x)*(1-σ(x))。第一項當然依賴(lài)于損失函數的定義,一般也很好求。比如我們的MSE損失:
    \
      具體的推導我在紙上寫(xiě)了一下,雖然很簡(jiǎn)單,我們也可以練練手,尤其是對于求和公式的展開(kāi),希望大家能熟悉它,以后的推導我可能就不展開(kāi)求和公式了,你需要知道求和公式里哪些項是和外面的自變量無(wú)關(guān)的。
    \
      公式BP1是elementwise的,我們需要變量j來(lái)計算每一個(gè)δ_jL。我們也可以把它寫(xiě)成向量的形式,以方便利用線(xiàn)性代數庫,它們可以一次計算向量或者矩陣,可以用很多技術(shù)利用硬件特性來(lái)優(yōu)化(包括GPU,SSE等)速度。
    \
      右邊δ'(z_L)很容易理解,左邊的記號可能有些費解,其實(shí)我們把?aC當成一個(gè)整體就好了,它是一個(gè)向量,第一個(gè)元素是∂C/∂a_1L,第二個(gè)就是∂C/∂a_2L,…
      如果算上函數C是MSE的話(huà),上面的公式就可以簡(jiǎn)化成:
    \
      公式2.第l層(非最后一層)的錯誤
    \
      等下我們會(huì )證明這個(gè)公式,不過(guò)首先我們來(lái)熟悉一下公式。如果我們想“背”下這個(gè)公式的話(huà),似乎看起來(lái)比第一個(gè)BP1要復雜很多。我們先檢查一下矩陣和向量的維度,假設l+1層有m個(gè)元素,l層n個(gè)。則w_l+1的大小是m*n,轉置之后是n*m,δ_l+1的大小是n*1,所以矩陣相乘后是m*1,這和δ_l是一樣的,沒(méi)有問(wèn)題。
      接下來(lái)我們仔細觀(guān)察一下BP2這個(gè)公式,首先第二項σ'(z_l)和前面的含義一樣,代表a_l對于z_l的變化率。
      而第一項復雜一點(diǎn),我們知道第l層的第j個(gè)神經(jīng)元會(huì )影響第l+1層的所有神經(jīng)元,從而也影響最終的損失C。這個(gè)公式直接給了一個(gè)矩陣向量的形式,看起來(lái)不清楚,所以我在草稿紙上展開(kāi)了:
    \
      最終第L層的第j個(gè)神經(jīng)元的損失就是如下公式:
    \
      這下應該就比較清楚了,第l層的第j個(gè)神經(jīng)元的損失,就是把l+1層的損失“反向傳播”回來(lái),當然要帶上權重,權重越大,“責任”也就越大。
      如果要“背”出這個(gè)公式也沒(méi)有那么復雜了,先不看σ'(z_l),第一項應該是矩陣w_l+1乘以δ_l+1.由于矩陣是m*n,而
      向量δ_l+1是m*1,為了能讓矩陣乘法成立,那么就只能把w轉置一下,變成n*m,然后就很容易記住這個(gè)公式了。
      注意,BP2的計算是從后往前的,首先根據BP1,最后一層的δ_L我們已經(jīng)算出來(lái)了,因此可以向前計算L-1層的δ_L-1,
      有了δ_L-1就能計算δ_L-2,…,最終能算出第一個(gè)隱層(也就是第2層)δ_1來(lái)。
      公式3.損失函數對偏置b的梯度
      這前面費了大力氣求δ_l,不要忘了我們的最終目標是求損失函數對參數w和b的偏導數,而不是求對中間變量z的偏導數。
      因此這個(gè)公式就是對b的偏導數。
    \
      或者寫(xiě)成向量的形式:
    \
    \
      ∂C/∂b就是δ!
      公式4.損失函數對w的梯度
    \
      或者參考下圖寫(xiě)成好記的形式:
    \

    \
      也就是說(shuō)對于一條邊w_jkL,∂C/∂w_ij就是這條邊射出的點(diǎn)的錯誤δ乘以進(jìn)入點(diǎn)的激活。非常好記。
      我們把這四個(gè)公式再總結一下:
    \
      (5)這四個(gè)公式的證明
      首先是BP1,請參考下圖:
    \
      然后是BP2:
      這里用到了chainrule,其實(shí)也非常簡(jiǎn)單和直觀(guān),就是復合函數層層組合。最簡(jiǎn)單的方法就是用圖畫(huà)出來(lái),比如y最終
      是x的函數,我們要求∂y/∂x,如果y是u,v的函數,然后u,v才是x的函數,那么我們把變量x,y,u,v都畫(huà)成圖上的點(diǎn),y是u,v的函數,那么我們畫(huà)上從u和v到y的邊,同樣,我們畫(huà)上從x到u和v的邊,然后從y到x的每條路徑,我們經(jīng)過(guò)的邊都是一個(gè)偏導數,我們把它累加起來(lái)就行【這其實(shí)就是后面我們會(huì )講的AD】。因此∂y/∂x=∂y/∂u * ∂u/∂x +∂y/∂v * ∂v/∂x。
    \
      剩下的BP3和BP4也非常類(lèi)似,我就不證明了。
      反向傳播算法
      1.a_1=輸入向量x
      2.Feedforward根據公式
    \
      和
    \
      計算z_l和a_l并存儲下來(lái)(反向傳播時(shí)要用的)
      3.計算最后一層的錯誤
    \
      向前計算所有層的錯誤
    \
      計算損失對所有參數的偏導數
    \
      2.2.6代碼實(shí)現反向傳播算法
      我們已經(jīng)把公式推導出來(lái)了,那怎么用代碼實(shí)現呢?我們先把代碼復制一下,然后說(shuō)明部分都是作為代碼的注釋了,
      請仔細閱讀。
    class Network(object):
      def update_mini_batch(self, mini_batch, eta):
        # mini_batch是batch大小,eta是learning rate
    
        nabla_b = [np.zeros(b.shape) for b in self.biases]
        # 構造和self.biases一樣大小的向量,比如前面的例子 sizes=[784,30,10],則
        # nabla_b是兩個(gè)向量,大小分別是30和10
    
        nabla_w = [np.zeros(w.shape) for w in self.weights]
        # 構造和self.weights一樣大小的矩陣,比如前面的例子 sizes=[784,30,10],則
        # nabla_w是兩個(gè)矩陣,大小分別是30*784和10*30
    
        for x, y in mini_batch: #對于每個(gè)訓練樣本x和y
     delta_nabla_b, delta_nabla_w = self.backprop(x, y)
     # 用backprop函數計算損失函數對每一個(gè)參數的偏導數。
     # backprop函數下面會(huì )詳細講解
    
     nabla_b = [nb+dnb for nb, dnb in zip(nabla_b, delta_nabla_b)]
     # 把返回的對b偏導數累加到nabla_b中
    
     nabla_w = [nw+dnw for nw, dnw in zip(nabla_w, delta_nabla_w)]
     # 把返回的對w的偏導數累加到nabla_w中
    
        self.weights = [w-(eta/len(mini_batch))*nw
      for w, nw in zip(self.weights, nabla_w)]
        # 計算完一個(gè)batch后更新參數w
    
        self.biases = [b-(eta/len(mini_batch))*nb
     for b, nb in zip(self.biases, nabla_b)]
        # 更新b
    ...
     def backprop(self, x, y):
        # 輸入是x和y,返回損失函數C對每個(gè)參數w和b的偏導數
        # 返回的格式是兩個(gè)元組,第一個(gè)是b的偏導數,第二個(gè)是w的。
        nabla_b = [np.zeros(b.shape) for b in self.biases]
        # 構造和self.biases一樣大小的向量,比如前面的例子 sizes=[784,30,10],則
        # nabla_b是兩個(gè)向量,大小分別是30和10
    
        nabla_w = [np.zeros(w.shape) for w in self.weights]
        # 構造和self.weights一樣大小的矩陣,比如前面的例子 sizes=[784,30,10],則
        # nabla_w是兩個(gè)矩陣,大小分別是30*784和10*30
    
        # feedforward
        activation = x
        activations = [x] # 用一個(gè)list保存所有層的激活,下面backward會(huì )有用的
        zs = [] # 同樣的用一個(gè)list保存所有層的加權累加和z,下面也會(huì )用到。
    
        #下面這段代碼在feedward也有,不過(guò)那里是用來(lái)predict用的不需要保存zs和activations
        for b, w in zip(self.biases, self.weights):
     z = np.dot(w, activation)+b
     zs.append(z)
     activation = sigmoid(z)
     activations.append(activation)
    
       # backward pass
      #1. 首先計算最后一層的錯誤delta,根據公式BP1,它是損失函數對a_L的梯度乘以σ'(z_L)
        #  sigmoid_prime就是σ'(z_L),而∂C/∂a_L就是函數cost_derivative,對于MSE的損失函數,
        #  它就是最后一層的激活activations[-1] - y
        delta = self.cost_derivative(activations[-1], y) * \
     sigmoid_prime(zs[-1])
        # 2. 根據公式BP3,損失對b的偏導數就是delta
        nabla_b[-1] = delta
        # 3. 根據公式BP4,損失對w的偏導數時(shí)delta_out * activation_in
        #  注意,我們的公式BP4是elementwise的,我們需要寫(xiě)成矩陣向量的形式
        #  那怎么寫(xiě)呢?我們只需要關(guān)心矩陣的大小就行了。
        #  假設最后一層有m(10)個(gè)神經(jīng)元,前一層有n(30)個(gè),
        #  則delta是10*1, 倒數第二層的激活activations[-2]是30*1
        #  我們想求的最后一層的參數nabla_w[-1]是10*30,那么為了能夠正確的矩陣乘法,
        #  只要一種可能就是 delta 乘以 activations[-2]的轉置,其實(shí)也就是向量delta和activations[-2]的外積
        nabla_w[-1] = np.dot(delta, activations[-2].transpose())
    
        # 接下來(lái)從倒數第二層一直往前計算delta,同時(shí)也把對w和b的偏導數求出來(lái)。
        # 這里用到一個(gè)比較小的trick就是python的下標是支持負數的,-1表示最后一個(gè)元素,-2是倒數第二個(gè)
        # l表示倒數第l層,2就表示倒數第2層,num_layers - 1就表示順數第2層(也就是第1個(gè)隱層)
        # 比如我們的例子:sizes=[784, 30, 10],那么l就是從2到3(不包含3),l就只能是2,頁(yè)就是第1個(gè)(也是唯一的一
        # 個(gè))隱層   
        for l in xrange(2, self.num_layers):
     # 倒數第l層的z
     z = zs[-l]
     # 計算σ'(z_l)
     sp = sigmoid_prime(z)
     # 根據BP2,計算delta_l,注意weights[-l+1]表示倒數第l層的下一層
     delta = np.dot(self.weights[-l+1].transpose(), delta) * sp
     # 同上,根據BP3
     nabla_b[-l] = delta
     # BP4,矩陣乘法參考前面的說(shuō)明
     nabla_w[-l] = np.dot(delta, activations[-l-1].transpose())
        return (nabla_b, nabla_w)
      2.2.7為什么反向傳播算法是一個(gè)高效的算法?
      分析完代碼,我們發(fā)現一次backprop函數調用需要feedforward一次,網(wǎng)絡(luò )有多少邊,就有多少次乘法,有多少個(gè)點(diǎn)就有多少次加分和激活函數計算(不算第一層輸入層)。反向計算也是一樣,不過(guò)是從后往前。也就是說(shuō)這是時(shí)間復雜度為O(n)的算法。
      如果我們不用反向傳播算法,假設我們用梯度的定義計算數值梯度。對于每一個(gè)參數wj,
      我們都用公式limit(f(w1,w2,…,wj+Δwj,…)-f(w1,w2,…,wj,…)/Δwj
      f(w1,w2,wj,…)只需要feedforward一次,但是對于每個(gè)參數wj,都需要feedforward一層來(lái)計算f(w1,w2,…,wj+Δwj,…),它的時(shí)間復雜度是O(n),那么對所有的參數的計算需要O(n^2)的時(shí)間復雜度。
      假設神經(jīng)網(wǎng)絡(luò )有1百萬(wàn)個(gè)參數,那么每次需要10^12這個(gè)數量級的運算,而反向傳播算法只需要10^6,因此這個(gè)方法比反向傳播算法要慢1百萬(wàn)倍。

    專(zhuān)題

    亚洲精品网站在线观看不卡无广告,国产a不卡片精品免费观看,欧美亚洲一区二区三区在线,国产一区二区三区日韩 乐都县| 中方县| 塘沽区| 萝北县| 博白县| 南陵县| 波密县| 子洲县| 辽源市| 海宁市| 双辽市| 金秀| 霍城县| 屏山县| 新竹市| 嘉祥县| 伊春市| 北海市| 漳州市| 剑阁县| 富锦市| 龙川县| 高平市| 襄城县| 鄱阳县| 廉江市| 阳原县| 平阴县| 永顺县| 乌什县| 阜城县| 旌德县| 望城县| 荃湾区| 普兰县| 新和县| 会东县| 淅川县| 滦南县| 泽库县| 沂源县| http://444 http://444 http://444 http://444 http://444 http://444