精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

神經網絡理論到實踐(2):理解并實現反向傳播及驗證神經網絡是否正確

電子設計 ? 來源:電子設計 ? 作者:電子設計 ? 2020-12-10 19:27 ? 次閱讀
專欄中《零神經網絡實戰》系列持續更新介紹神經元怎么工作,最后使用python從0到1不調用任何依賴神經網絡框架(不使用tensorflow等框架)來實現神經網絡,梯度下降、反向傳播、卷積神經網絡CNN、循環神經網絡RNN。從0基礎角度進行神經網絡實戰。
上一篇:零基礎神經網絡實戰(1):單個神經元+隨機梯度下降學習邏輯與規則
作者:司南牧

實例介紹反向傳播,為何說深度學習離不開反向傳播?

之前介紹了單個神經元如何利用隨機梯度下降自己調節權重。深度學習指的是數以百千層的層數很深的神經網絡,每層又有數以百千個神經元。那么深度學習是否也可以使用這種形式的梯度下降來進行調節權重呢?答:很難。為什么?主要原因是太深了。為何“深”用梯度下降解會有問題呢?主要是因為鏈式法則導致計算損失函數對前面層權重的導數時,損失函數對后面層權重的導數總是被重復計算,反向傳播就是將那些計算的值保存減少重復計算。不明白?那這篇文章就看對了。接下來將解釋這個重復計算過程。反向傳播就是梯度下降中的求導環節,它從后往前計算導數重復利用計算過的導數而已。。梯度下降不懂或者神經網絡不懂請先閱讀這個文章單個神經元+隨機梯度下降學習邏輯與規則

文章結構:

  1. 為何要使用反向傳播?
  2. 反向傳播優化神經網絡權重參數實踐。

為何要使用反向傳播?

我們用一個最簡單的三層神經網絡(無激活函數)來進行解釋為何需要使用反向傳播,所使用的三層神經網絡如下所示:

這里我們有三個要優化的參數:w1,w2,w3。

我們先用傳統的梯度下降方法來看看哪些地方重復計算了,而反向傳播就是將這些重復計算的地方計算結果保存,并且向前面層傳播這個值以減少運算復雜度。 梯度下降需要先得求損失函數對w1,w2,w3的導數,然后根據導數來不斷迭代更新w1,w2,w3的值。

第1層:求損失函數L(w1,w2,w3)對w1的導數(更規范的講是偏導數)。

我們先看看損失函數L(w1,w2,w3)和w1之間的關系是什么。

$$L(w1,w2,w3)=1/2 (e-/hat e )^2$$
e=w3 * z
z=w2 * y
y=w1 * x

所以這是個復合函數的求導。根據高中學習到的復合函數求導法則(也是大家可能經常聽到的鏈式法則),復合函數求導等于各級復合函數導數的乘積,也就是這樣

第2層:求損失函數L(w1,w2,w3)對w2的導數。
我們再看看損失函數L(w1,w2,w3)和w2之間的關系是什么。

$$L(w1,w2,w3)=1/2 (e-/hat e )^2$$
e=w3 * z
z=w2 * y

根據復合函數求導可得:

第3層:求損失函數L(w1,w2,w3)對w3的導數。
我們再看看損失函數L(w1,w2,w3)和w3之間的關系是什么。

$$L(w1,w2,w3)=1/2 (e-/hat e )^2$$
e=w3 * z

根據復合函數求導可得:

我們將這三層的損失函數對相應層權重導數列在一起看看哪兒重復計算了:


我們再看看這個圖:

所搭建的最簡單的三層神經網絡

你會發現,如果將損失函數也看做是一層的話。即我們認為e->L(w1,w2,w3)這也算一層。

找規律

反向傳播過程理解

前面我們提到了可以從后面往前面計算,將公共部分的導數往前傳。這只是解決了求導問題,那怎么進行參數更新呢?答:參數更新跟梯度下降完全一樣,都是這個公式。反向傳播就是梯度下降中的求導環節,它重復利用計算過的導數而已。

我們看看反向傳播版的使用梯度下降進行參數更新是怎樣的。

損失函數L(w1,w2,w3)是這樣:$$L(w1,w2,w3)=1/2 (e-/hat e )^2$$

其他的幾層函數如下所示:

第3層:e=w3 * z
第2層:z=w2 * y
第1層:y=w1 * x

在這篇文章“單個神經元+隨機梯度下降學習邏輯與規則”介紹了,權重更新是一個不斷猜(迭代更新)的過程。下一次權重值 = 本次權重值 - 學習率* 損失函數對該權重的導數。定義學習率為α. 接下來我們只需要知道怎么利用后面層數傳遞過來的值來求“損失函數對當前層權重wi的導數”即可。

則各層網絡更新權重的步驟為如下所示:

1.更新第3層權重參數w3.

2.更新第2層權重參數w2

3.更新第1層權重參數w1.

所以,將上面3步用偽代碼寫可以寫成下面這樣。

終于可以告別可怕的公式了,越難的東西你堅持了,你的不可替代性就越強。加油你不是一個人在奮斗。

反向傳播實踐

我們將上面的偽代碼轉成Python代碼。我們希望這個神經網絡能自己學習到的功能是輸入x輸出的e=-x.

我們提供訓練集數據(我們只有兩條數據):


重復訓練次數epoch = 160。

好開工實現它。

# -*- coding: UTF-8 -*-
"""
@author 知乎:@Ai醬
"""
class NeuralNetwork:

    def __init__(self):
        self.LEARNING_RATE = 0.05 # 設置學習率
        # 初始化網絡各層權重(權重的初試值也會影響神經網絡是否收斂)
        # 博主試了下權重初始值都為0.2333是不行的
        self.w3 = -0.52133
        self.w2 = -0.233
        self.w1 = 0.2333
        self.data = [1, -1] # 輸入數據
        self.label= [-1, 1]

    def train(self):
        epoch = 160
        for _ in range(epoch):
            # 逐個樣本進行訓練模型
            for i in range(len(self.data)):
                x = self.data[i]
                e_real = self.label[i]

                self.y = self.w1 * x #計算第1層輸出
                self.z = self.w2 * self.y # 計算第2層輸出
                self.e = self.w3 * self.z # 計算第3層輸出

                # 開始反向傳播優化權重
                self.result3 = self.e - e_real
                self.w3 = self.w3 - self.LEARNING_RATE * self.result3 * self.z

                self.result2 = self.result3 * self.w3
                self.w2 = self.w2 - self.LEARNING_RATE * self.result2 * self.y

                self.w1 = self.w1 - self.LEARNING_RATE * self.result2 * self.w2 * x

    def predict(self,x):
        self.y = self.w1 * x #計算第1層輸出
        self.z = self.w2 * self.y # 計算第2層輸出
        self.e = self.w3 * self.z # 計算第3層輸出
        return 1 if self.e>0 else -1
nn = NeuralNetwork()
nn.train()
print(1,',',nn.predict(1))
print(-1,',',nn.predict(-1))
'''
輸出:
1 , -1
-1 , 1
'''

如何檢驗反向傳播是否寫對?

手動推導,人工判斷

前面提到了反向傳播本質是梯度下降,那么關鍵在于導數必須對。我們現在網絡比較小可以直接手動計算導數比對代碼中對各權重導數是否求對。

比如上面代碼中三個參數的導數將代碼中的result*展開表示就是:

dw3 = (self.e - e_real) * self.z
    = (self.e - e_real) * self.w2 * self.y
    =  (self.e - e_real) * self.w2 * self.w1 * x
    = (self. w3 * self.w2 * self.w1 * x - e_real) * self.w2 * self.w1 * x

dw2 = (self.e - e_real) * self.w3* self.y
    = (self.e - e_real) * self.w3* self.w1 * x
    = (self. w3 * self.w2 * self.w1 * x - e_real) * self.w3* self.w1 * x

dw3 =  self.result3 * self.z
    = (self.e - e_real) * self.w2 * self.w1 * x
    = (self. w3 * self.w2 * self.w1 * x - e_real)* self.w2 * self.w1 * x

而損失函數展開可以表示為: $$L(w1,w2,w3) = 1/2 (w3 * w2 * w1 * x - /hat e)^2$$

對各權重參數求導為:

$${dL}/ {dw3} = (w3 * w2 * w1 * x - /hat e) * w2 * w1$$

$${dL}/ {dw2} = (w3 * w2 * w1 * x - /hat e) * w3 * w1$$

$${dL}/ {dw1} = (w3 * w2 * w1 * x - /hat e) * w3 * w2$$

可以發現我們代碼展開,與我們實際的公式求導是一致的證明我們代碼是正確的。

但是,一旦層數很深,那么我們就不能這么做了

我們需要用代碼自動判斷是否反向傳播寫對了

代碼自動判斷反向傳播的導函數是否正確

這個和手工判斷方法類似。反向傳播是否正確,關鍵在于dL/dwi是否計算正確。根據高中學過的導數的定義,對于位于點θ的導數有:

$$f'(/theta) = /lim_{/epsilon/to 0} {f(/theta + /epsilon) + f(/theta - /epsilon) } /{2/epsilon}$$

所以我們可以看反向傳播求的導函數值和用導數定義求的導函數值是否接近。

即我們需要讓代碼判斷這個式子是否成立:$${dL}/ {dwi} /approx {L(wi+ 10^{-4}) - L(wi- 10^{-4})} /{2* 10^{-4}}$$

左邊的dL/dwi是反向傳播求得,右邊是導數定義求的導數值。這兩個導數應當大致相同。

實踐:程序自動檢驗導函數是否正確:

新增了一個梯度檢驗函數check_gradient(),如下所示:

# -*- coding: UTF-8 -*-
"""
@author 知乎:@Ai醬
"""
class NeuralNetwork:

    def __init__(self):
        self.LEARNING_RATE = 0.05 # 設置學習率
        # 初始化網絡各層權重(權重的初試值也會影響神經網絡是否收斂)
        # 博主試了下權重初始值都為0.2333是不行的
        self.w3 = -0.52133
        self.w2 = -0.233
        self.w1 = 0.2333

        self.data = [1, -1] # 輸入數據
        self.label= [-1, 1]
    def L(self,w1,w2,w3,x,e_real):
        '''
        損失函數 return 1/2 * (e - e_real)^2
        '''
        return 0.5*(w1*w2*w3*x - e_real)**2

    def train(self):
        epoch = 160
        for _ in range(epoch):
            # 逐個樣本進行訓練模型
            for i in range(len(self.data)):
                x = self.data[i]
                e_real = self.label[i]

                self.y = self.w1 * x #計算第1層輸出
                self.z = self.w2 * self.y # 計算第2層輸出
                self.e = self.w3 * self.z # 計算第3層輸出

                # 開始反向傳播優化權重
                self.result3 = self.e - e_real
                self.w3 = self.w3 - self.LEARNING_RATE * self.result3 * self.z

                self.result2 = self.result3 * self.w3
                self.w2 = self.w2 - self.LEARNING_RATE * self.result2 * self.y

                self.w1 = self.w1 - self.LEARNING_RATE * self.result2 * self.w2 * x
                self.check_gradient(x,e_real)

    def check_gradient(self,x,e_real):
        # 反向傳播所求得的損失函數對各權重的導數
        dw3 = self.result3 * self.z
        dw2 = self.result2 * self.y
        dw1 = self.result2 * self.w2 * x

        # 使用定義求損失函數對各權重的導數
        epsilon = 10**-4 # epsilon為10的4次方
        # 求損失函數在w3處的左極限和右極限
        lim_dw3_right = self.L(self.w1, self.w2, self.w3+epsilon, x, e_real)
        lim_dw3_left = self.L(self.w1, self.w2, self.w3-epsilon, x, e_real)
        # 利用左右極限求導
        lim_dw3 = (lim_dw3_right - lim_dw3_left)/(2*epsilon)

        lim_dw2_right = self.L(self.w1, self.w2+epsilon, self.w3, x, e_real)
        lim_dw2_left = self.L(self.w1, self.w2-epsilon, self.w3, x, e_real)
        lim_dw2 = (lim_dw2_right - lim_dw2_left)/(2*epsilon)

        lim_dw1_right = self.L(self.w1+epsilon, self.w2, self.w3, x, e_real)
        lim_dw1_left = self.L(self.w1-epsilon, self.w2, self.w3, x, e_real)
        lim_dw1 = (lim_dw1_right - lim_dw1_left)/(2*epsilon)

        # 比對反向傳播求的導數和用定義求的導數是否接近
        print("dl/dw3反向傳播求得:%f,定義求得%f"%(dw3,lim_dw3))
        print("dl/dw2反向傳播求得:%f,定義求得%f"%(dw2,lim_dw2))
        print("dl/dw1反向傳播求得:%f,定義求得%f"%(dw1,lim_dw1))

    def predict(self,x):
        self.y = self.w1 * x #計算第1層輸出
        self.z = self.w2 * self.y # 計算第2層輸出
        self.e = self.w3 * self.z # 計算第3層輸出
        return 1 if self.e>0 else -1
nn = NeuralNetwork()
nn.train()
print(1,',',nn.predict(1))
print(-1,',',nn.predict(-1))
'''
輸出:
dl/dw1反向傳播求得:-0.026729,定義求得-0.026727
dl/dw3反向傳播求得:0.003970,定義求得0.004164
dl/dw2反向傳播求得:-0.032617,定義求得-0.033257
dl/dw1反向傳播求得:-0.027502,定義求得-0.027499
dl/dw3反向傳播求得:0.004164,定義求得0.004367
dl/dw2反向傳播求得:-0.033272,定義求得-0.033932
dl/dw1反向傳播求得:-0.028291,定義求得-0.028288
dl/dw3反向傳播求得:0.004367,定義求得0.004579
dl/dw2反向傳播求得:-0.033947,定義求得-0.034625
dl/dw1反向傳播求得:-0.029097,定義求得-0.029094
... ...
1 , -1
-1 , 1
'''

可以發現反向傳播求得損失函數對各參數求得的導數和我們用高中學的定義法求導數,兩者基本一致,證明我們反向傳播求得的導數沒有問題。

附上上面的易讀版代碼的github代碼下載地址:從本質如何理解機器學習?

框架化反向傳播

每個程序員都有一個寫框架的夢想,不如我們將前面的代碼寫個類似TensorFlow這種框架的反向傳播簡單框架吧。附上框架版的代碼github下載地址:https://github.com/varyshare/newbie_neural_network_practice/blob/master/backpropagation/backpropagation_framework.py


# -*- coding: utf-8 -*-
"""
框架化反向傳播編程
@author: 知乎@Ai醬
"""

import random
class Layer(object):
    '''
    本文中,一層只有一個神經元,一個神經元只有一個輸入一個輸出
    '''
    def __init__(self,layer_index):
        '''
        layer_index: 第幾層
        '''
        self.layer_index = layer_index
        # 初始化權重[0,1] - 0.5 = [-0.5,0.5]保證初始化有正有負
        self.w = random.random() - 0.5 
        # 當前層的輸出
        self.output = 0
        
    def forward(self,input_var):
        '''
        前向傳播:對輸入進行運算,并將結果保存
        input_var: 當前層的輸入
        '''
        self.input = input_var
        self.output = self.w * self.input
        
    
    def backward(self, public_value):
        '''
        反向傳播:計算上層也會使用的導數值并保存
        假設當前層的計算規則是這樣output = f(input),
        而 input == 前一層的輸出,
        因此,根據鏈式法則損失函數對上一層權重的導數 = 后面層傳過來的公共導數* f'(input) * 前一層的導數
        也就是說,后面層傳過來的公共導數值* f'(input) 是需要往前傳的公用的導數值。
        由于本層中對輸入做的運算為:output = f(input) = w*input
        所以, f'(input) = w.
        public_value: 后面傳過來的公共導數值
        '''
        # 當前層要傳給前面層的公共導數值 = 后面傳過來的公共導數值 * f'(input)
        self.public_value = public_value * self.w
        # 損失函數對當前層參數w的導數 = 后面傳過來的公共導數值 * f'(input) * doutput/dw
        self.w_grad = self.public_value * self.input
    
    def upate(self, learning_rate):
        '''
        利用梯度下降更新參數w
        參數迭代更新規則(梯度下降): w = w - 學習率*損失函數對w的導數
        learning_rate: 學習率
        '''
        self.w = self.w - learning_rate * self.w_grad
    
    def display(self):
        print('layer',self.layer_index,'w:',self.w)

class Network(object):
    def __init__(self,layers_num):
        '''
        構造網絡
        layers_num: 網絡層數
        '''
        self.layers = []
        # 向網絡添加層
        for i in range(layers_num):
            self.layers.append(Layer(i+1))#層編號從1開始
    
    def predict(self, sample):
        '''
        sample: 樣本輸入
        return 最后一層的輸出
        '''
        output = sample
        for layer in self.layers:
            layer.forward(output)
            output = layer.output
        return 1 if output>0 else -1
    
    def calc_gradient(self, label):
        '''
        從后往前計算損失函數對各層的導數
        '''
        # 計算最后一層的導數
        last_layer = self.layers[-1]
        # 由于損失函數=0.5*(last_layer.output - label)^2
        # 由于backward中的public_value = 輸出對輸入的導數
        # 對于損失函數其輸入是last_layer.output,損失函數對該輸入的導數=last_layer.output - label
        # 所以 最后一層的backward的public_value = last_layer.output - label
        last_layer.backward(last_layer.output - label)
        public_value = last_layer.public_value
        for layer in self.layers:
            layer.backward(public_value) # 計算損失函數對該層參數的導數
            public_value= layer.public_value
            
    def update_weights(self, learning_rate):
        '''
        更新各層權重
        '''
        for layer in self.layers:
            layer.upate(learning_rate)
        
    
    def train_one_sample(self, label, sample, learning_rate):
        self.predict(sample) # 前向傳播,使得各層的輸入都有值
        self.calc_gradient(label) # 計算各層導數
        self.update_weights(learning_rate) # 更新各層參數
        
    def train(self, labels, data_set, learning_rate, epoch):
        '''
        訓練神經網絡
        labels: 樣本標簽
        data_set: 輸入樣本們
        learning_rate: 學習率
        epoch: 同樣的樣本反復訓練的次數
        '''
        for _ in range(epoch):# 同樣數據反復訓練epoch次保證權重收斂
            for i in range(len(labels)):#逐樣本更新權重
                self.train_one_sample(labels[i], data_set[i], learning_rate)

nn = Network(3)
data_set = [1,-1]
labels   = [-1,1]
learning_rate = 0.05
epoch = 160
nn.train(labels,data_set,learning_rate,epoch)
print(nn.predict(1)) # 輸出 -1
print(nn.predict(-1)) # 輸出 1

歡迎關注我的知乎專欄適合初學者的機器學習神經網絡理論到實踐。
上一篇為零基礎神經網絡實戰(1):單個神經元+隨機梯度下降學習邏輯與規則
下一篇為適合初學者的神經網絡理論到實踐(3):打破概念束縛:強化學習是個啥?

審核編輯:符乾江
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 神經網絡
    +關注

    關注

    42

    文章

    4762

    瀏覽量

    100541
  • 人工智能
    +關注

    關注

    1791

    文章

    46859

    瀏覽量

    237582
收藏 人收藏

    評論

    相關推薦

    bp神經網絡反向傳播神經網絡區別在哪

    反向傳播神經網絡(Backpropagation Neural Network,簡稱BP神經網絡)是一種多層前饋神經網絡,它通過
    的頭像 發表于 07-04 09:51 ?384次閱讀

    神經網絡反向傳播算法的優缺點有哪些

    神經網絡反向傳播算法(Backpropagation Algorithm)是一種廣泛應用于深度學習和機器學習領域的優化算法,用于訓練多層前饋神經網絡。本文將介紹
    的頭像 發表于 07-03 11:24 ?683次閱讀

    神經網絡反向傳播算法的作用是什么

    神經網絡反向傳播算法(Backpropagation)是一種用于訓練人工神經網絡的算法,它通過計算損失函數關于網絡參數的梯度來更新
    的頭像 發表于 07-03 11:17 ?1207次閱讀

    神經網絡反向傳播算法的原理、數學推導及實現步驟

    神經網絡反向傳播算法(Backpropagation Algorithm)是一種用于訓練多層神經網絡的算法,其基本原理是通過梯度下降法來最小化損失函數,從而找到
    的頭像 發表于 07-03 11:16 ?676次閱讀

    神經網絡前向傳播反向傳播神經網絡訓練過程中的作用

    神經網絡是一種強大的機器學習模型,它通過模擬人腦神經元的連接方式來處理復雜的數據。神經網絡的核心是前向傳播反向
    的頭像 發表于 07-03 11:11 ?995次閱讀

    反向傳播神經網絡建模基本原理

    反向傳播神經網絡(Backpropagation Neural Network,簡稱BP神經網絡)是一種多層前饋神經網絡,通過
    的頭像 發表于 07-03 11:08 ?401次閱讀

    反向傳播神經網絡概念是什么

    反向傳播神經網絡(Backpropagation Neural Network,簡稱BP神經網絡)是一種多層前饋神經網絡,它通過
    的頭像 發表于 07-03 11:06 ?515次閱讀

    反向傳播神經網絡優點和缺點有哪些

    反向傳播神經網絡(Backpropagation Neural Network,簡稱BP神經網絡)是一種多層前饋神經網絡,通過
    的頭像 發表于 07-03 11:05 ?742次閱讀

    反向傳播神經網絡分為多少層

    反向傳播神經網絡(Backpropagation Neural Network,簡稱BP神經網絡)是一種多層前饋神經網絡,它通過
    的頭像 發表于 07-03 11:02 ?384次閱讀

    反向傳播神經網絡和bp神經網絡的區別

    反向傳播神經網絡(Backpropagation Neural Network,簡稱BP神經網絡)是一種多層前饋神經網絡,它通過
    的頭像 發表于 07-03 11:00 ?679次閱讀

    bp神經網絡和卷積神經網絡區別是什么

    結構、原理、應用場景等方面都存在一定的差異。以下是對這兩種神經網絡的比較: 基本結構 BP神經網絡是一種多層前饋神經網絡,由輸入層、隱藏層和輸出層組成。每個神經元之間通過權重連接,
    的頭像 發表于 07-03 10:12 ?1028次閱讀

    神經網絡前向傳播反向傳播區別

    神經網絡是一種強大的機器學習模型,廣泛應用于各種領域,如圖像識別、語音識別、自然語言處理等。神經網絡的核心是前向傳播反向傳播算法。本文將詳
    的頭像 發表于 07-02 14:18 ?664次閱讀

    神經網絡反向傳播算法原理是什么

    介紹反向傳播算法的原理、數學基礎、實現步驟和應用場景。 神經網絡簡介 神經網絡是一種受人腦啟發的計算模型,由大量的
    的頭像 發表于 07-02 14:16 ?504次閱讀

    反向傳播神經網絡模型的特點

    反向傳播神經網絡(Backpropagation Neural Network,簡稱BP神經網絡)是一種多層前饋神經網絡,它通過
    的頭像 發表于 07-02 14:14 ?351次閱讀

    反向傳播神經網絡建模的基本原理

    反向傳播神經網絡(Backpropagation Neural Network,簡稱BP神經網絡)是一種多層前饋神經網絡,通過
    的頭像 發表于 07-02 14:05 ?258次閱讀