反向傳播演算法python(反向傳播演算法python代碼)

本文目錄一覽:

一文搞懂梯度下降&反向傳播

如果把神經網路模型比作一個黑箱,把模型參數比作黑箱上面一個個小旋鈕,那麼根據通用近似理論(universal approximation theorem),只要黑箱上的旋鈕數量足夠多,而且每個旋鈕都被調節到合適的位置,那這個模型就可以實現近乎任意功能(可以逼近任意的數學模型)。

顯然,這些旋鈕(參數)不是由人工調節的,所謂的機器學習,就是通過程序來自動調節這些參數。神經網路不僅參數眾多(少則十幾萬,多則上億),而且網路是由線性層和非線性層交替疊加而成,上層參數的變化會對下層的輸出產生非線性的影響,因此,早期的神經網路流派一度無法往多層方向發展,因為他們找不到能用於任意多層網路的、簡潔的自動調節參數的方法。

直到上世紀80年代,祖師爺辛頓發明了反向傳播演算法,用輸出誤差的均方差(就是loss值)一層一層遞進地反饋到各層神經網路,用梯度下降法來調節每層網路的參數。至此,神經網路才得以開始它的深度之旅。

本文用python自己動手實現梯度下降和反向傳播演算法。 請點擊這裡 到Github上查看源碼。

梯度下降法是一種將輸出誤差反饋到神經網路並自動調節參數的方法,它通過計算輸出誤差的loss值( J )對參數 W 的導數,並沿著導數的反方向來調節 W ,經過多次這樣的操作,就能將輸出誤差減小到最小值,即曲線的最低點。

雖然Tensorflow、Pytorch這些框架都實現了自動求導的功能,但為了徹底理解參數調節的過程,還是有必要自己動手實現梯度下降和反向傳播演算法。我相信你和我一樣,已經忘了之前學的微積分知識,因此,到可汗學院複習下 Calculus

和 Multivariable Calculus 是個不錯的方法,或是拜讀 這篇關於神經網路矩陣微積分的文章 。

Figure2是求導的基本公式,其中最重要的是 Chain Rule ,它通過引入中間變數,將「 y 對 x 求導」的過程轉換為「 y 對中間變數 u 求導,再乘以 u 對 x 求導」,這樣就將一個複雜的函數鏈求導簡化為多個簡單函數求導。

如果你不想涉及這些求導的細節,可以跳過具體的計算,領會其思想就好。

對於神經網路模型: Linear – ReLu – Linear – MSE(Loss function) 來說,反向傳播就是根據鏈式法則對 求導,用輸出誤差的均方差(MSE)對模型的輸出求導,並將導數傳回上一層神經網路,用於它們來對 w 、 b 和 x (上上層的輸出)求導,再將 x 的導數傳回到它的上一層神經網路,由此將輸出誤差的均方差通過遞進的方式反饋到各神經網路層。

對於 求導的第一步是為這個函數鏈引入中間變數:

接著第二步是對各中間變數求導,最後才是將這些導數乘起來。

首先,反向傳播的起點是對loss function求導,即 。 :

mse_grad()之所以用unsqueeze(-1)給導數增加一個維度,是為了讓導數的shape和tensor shape保持一致。

linear層的反向傳播是對 求導,它也是一個函數鏈,也要先對中間變數求導再將所有導數相乘:

這些中間變數的導數分別是:

對向量 求導,指的是對向量所有的標量求偏導( ),即: ,這個橫向量也稱為y的梯度。

這裡 ,是一個向量,因此, 求導,指的是y的所有標量(y_1, y_2, …, y_n)對向量x求偏導,即:

這個矩陣稱為雅克比矩陣,它是個對角矩陣,因為 ,因此 。

同理, 。

因此,所有中間導數相乘的結果:

lin_grad() 中的inp.g、w.g和b.g分別是求 的導數,以inp.g為例,它等於 ,且需要乘以前面各層的導數,即 outp.g @ w.t() ,之所以要用點積運算符(@)而不是標量相乘,是為了讓它的導數shape和tensor shape保持一致。同理,w.g和b.g也是根據相同邏輯來計算的。

ReLu層的求導相對來說就簡單多了,當輸入 = 0時,導數為0,當輸入 0時,導數為1。

求導運算終於結束了,接下來就是驗證我們的反向傳播是否正確。驗證方法是將forward_backward()計算的導數和Pytorch自動微分得到的導數相比較,如果它們相近,就認為我們的反向傳播演算法是正確的。

首先,將計算好的參數導數保存到w1g、b1g、w2g和b2g中,再用Pytorch的自動微分來求w11、b11、w22和b22的導數。

最後,用np.allclose()來比較導數間的差異,如果有任何一個導數不相近,assert就會報錯。結果證明,我們自己動手實現的演算法是正確的。

反向傳播是遵循鏈式法則的,它將前向傳播的輸出作為輸入,輸入作為輸出,通過遞進的方式將求導這個動作從後向前傳遞迴各層。神經網路參數的求導需要進行矩陣微積分計算,根據這些導數的反方向來調節參數,就可以讓模型的輸出誤差的優化到最小值。

歡迎關注和點贊,你的鼓勵將是我創作的動力

從零開始用Python構建神經網路

從零開始用Python構建神經網路

動機:為了更加深入的理解深度學習,我們將使用 python 語言從頭搭建一個神經網路,而不是使用像 Tensorflow 那樣的封裝好的框架。我認為理解神經網路的內部工作原理,對數據科學家來說至關重要。

這篇文章的內容是我的所學,希望也能對你有所幫助。

神經網路是什麼?

介紹神經網路的文章大多數都會將它和大腦進行類比。如果你沒有深入研究過大腦與神經網路的類比,那麼將神經網路解釋為一種將給定輸入映射為期望輸出的數學關係會更容易理解。

神經網路包括以下組成部分

? 一個輸入層,x

? 任意數量的隱藏層

? 一個輸出層,?

? 每層之間有一組權值和偏置,W and b

? 為隱藏層選擇一種激活函數,σ。在教程中我們使用 Sigmoid 激活函數

下圖展示了 2 層神經網路的結構(注意:我們在計算網路層數時通常排除輸入層)

2 層神經網路的結構

用 Python 可以很容易的構建神經網路類

訓練神經網路

這個網路的輸出 ? 為:

你可能會注意到,在上面的等式中,輸出 ? 是 W 和 b 函數。

因此 W 和 b 的值影響預測的準確率. 所以根據輸入數據對 W 和 b 調優的過程就被成為訓練神經網路。

每步訓練迭代包含以下兩個部分:

? 計算預測結果 ?,這一步稱為前向傳播

? 更新 W 和 b,,這一步成為反向傳播

下面的順序圖展示了這個過程:

前向傳播

正如我們在上圖中看到的,前向傳播只是簡單的計算。對於一個基本的 2 層網路來說,它的輸出是這樣的:

我們在 NeuralNetwork 類中增加一個計算前向傳播的函數。為了簡單起見我們假設偏置 b 為0:

但是我們還需要一個方法來評估預測結果的好壞(即預測值和真實值的誤差)。這就要用到損失函數。

損失函數

常用的損失函數有很多種,根據模型的需求來選擇。在本教程中,我們使用誤差平方和作為損失函數。

誤差平方和是求每個預測值和真實值之間的誤差再求和,這個誤差是他們的差值求平方以便我們觀察誤差的絕對值。

訓練的目標是找到一組 W 和 b,使得損失函數最好小,也即預測值和真實值之間的距離最小。

反向傳播

我們已經度量出了預測的誤差(損失),現在需要找到一種方法來傳播誤差,並以此更新權值和偏置。

為了知道如何適當的調整權值和偏置,我們需要知道損失函數對權值 W 和偏置 b 的導數。

回想微積分中的概念,函數的導數就是函數的斜率。

梯度下降法

如果我們已經求出了導數,我們就可以通過增加或減少導數值來更新權值 W 和偏置 b(參考上圖)。這種方式被稱為梯度下降法。

但是我們不能直接計算損失函數對權值和偏置的導數,因為在損失函數的等式中並沒有顯式的包含他們。因此,我們需要運用鏈式求導發在來幫助計算導數。

鏈式法則用於計算損失函數對 W 和 b 的導數。注意,為了簡單起見。我們只展示了假設網路只有 1 層的偏導數。

這雖然很簡陋,但是我們依然能得到想要的結果—損失函數對權值 W 的導數(斜率),因此我們可以相應的調整權值。

現在我們將反向傳播演算法的函數添加到 Python 代碼中

為了更深入的理解微積分原理和反向傳播中的鏈式求導法則,我強烈推薦 3Blue1Brown 的如下教程:

Youtube:

整合併完成一個實例

既然我們已經有了包括前向傳播和反向傳播的完整 Python 代碼,那麼就將其應用到一個例子上看看它是如何工作的吧。

神經網路可以通過學習得到函數的權重。而我們僅靠觀察是不太可能得到函數的權重的。

讓我們訓練神經網路進行 1500 次迭代,看看會發生什麼。 注意觀察下面每次迭代的損失函數,我們可以清楚地看到損失函數單調遞減到最小值。這與我們之前介紹的梯度下降法一致。

讓我們看看經過 1500 次迭代後的神經網路的最終預測結果:

經過 1500 次迭代訓練後的預測結果

我們成功了!我們應用前向和方向傳播演算法成功的訓練了神經網路並且預測結果收斂於真實值。

注意預測值和真實值之間存在細微的誤差是允許的。這樣可以防止模型過擬合併且使得神經網路對於未知數據有著更強的泛化能力。

下一步是什麼?

幸運的是我們的學習之旅還沒有結束,仍然有很多關於神經網路和深度學習的內容需要學習。例如:

? 除了 Sigmoid 以外,還可以用哪些激活函數

? 在訓練網路的時候應用學習率

? 在面對圖像分類任務的時候使用卷積神經網路

我很快會寫更多關於這個主題的內容,敬請期待!

最後的想法

我自己也從零開始寫了很多神經網路的代碼

雖然可以使用諸如 Tensorflow 和 Keras 這樣的深度學習框架方便的搭建深層網路而不需要完全理解其內部工作原理。但是我覺得對於有追求的數據科學家來說,理解內部原理是非常有益的。

這種練習對我自己來說已成成為重要的時間投入,希望也能對你有所幫助

怎樣用python構建一個卷積神經網路

用keras框架較為方便

首先安裝anaconda,然後通過pip安裝keras

以下轉自wphh的博客。

#coding:utf-8

”’

    GPU run command:

        THEANO_FLAGS=mode=FAST_RUN,device=gpu,floatX=float32 python cnn.py

    CPU run command:

        python cnn.py

2016.06.06更新:

這份代碼是keras開發初期寫的,當時keras還沒有現在這麼流行,文檔也還沒那麼豐富,所以我當時寫了一些簡單的教程。

現在keras的API也發生了一些的變化,建議及推薦直接上keras.io看更加詳細的教程。

”’

#導入各種用到的模塊組件

from __future__ import absolute_import

from __future__ import print_function

from keras.preprocessing.image import ImageDataGenerator

from keras.models import Sequential

from keras.layers.core import Dense, Dropout, Activation, Flatten

from keras.layers.advanced_activations import PReLU

from keras.layers.convolutional import Convolution2D, MaxPooling2D

from keras.optimizers import SGD, Adadelta, Adagrad

from keras.utils import np_utils, generic_utils

from six.moves import range

from data import load_data

import random

import numpy as np

np.random.seed(1024)  # for reproducibility

#載入數據

data, label = load_data()

#打亂數據

index = [i for i in range(len(data))]

random.shuffle(index)

data = data[index]

label = label[index]

print(data.shape[0], ‘ samples’)

#label為0~9共10個類別,keras要求格式為binary class matrices,轉化一下,直接調用keras提供的這個函數

label = np_utils.to_categorical(label, 10)

###############

#開始建立CNN模型

###############

#生成一個model

model = Sequential()

#第一個卷積層,4個卷積核,每個卷積核大小5*5。1表示輸入的圖片的通道,灰度圖為1通道。

#border_mode可以是valid或者full,具體看這裡說明:

#激活函數用tanh

#你還可以在model.add(Activation(‘tanh’))後加上dropout的技巧: model.add(Dropout(0.5))

model.add(Convolution2D(4, 5, 5, border_mode=’valid’,input_shape=(1,28,28))) 

model.add(Activation(‘tanh’))

#第二個卷積層,8個卷積核,每個卷積核大小3*3。4表示輸入的特徵圖個數,等於上一層的卷積核個數

#激活函數用tanh

#採用maxpooling,poolsize為(2,2)

model.add(Convolution2D(8, 3, 3, border_mode=’valid’))

model.add(Activation(‘tanh’))

model.add(MaxPooling2D(pool_size=(2, 2)))

#第三個卷積層,16個卷積核,每個卷積核大小3*3

#激活函數用tanh

#採用maxpooling,poolsize為(2,2)

model.add(Convolution2D(16, 3, 3, border_mode=’valid’)) 

model.add(Activation(‘relu’))

model.add(MaxPooling2D(pool_size=(2, 2)))

#全連接層,先將前一層輸出的二維特徵圖flatten為一維的。

#Dense就是隱藏層。16就是上一層輸出的特徵圖個數。4是根據每個卷積層計算出來的:(28-5+1)得到24,(24-3+1)/2得到11,(11-3+1)/2得到4

#全連接有128個神經元節點,初始化方式為normal

model.add(Flatten())

model.add(Dense(128, init=’normal’))

model.add(Activation(‘tanh’))

#Softmax分類,輸出是10類別

model.add(Dense(10, init=’normal’))

model.add(Activation(‘softmax’))

#############

#開始訓練模型

##############

#使用SGD + momentum

#model.compile里的參數loss就是損失函數(目標函數)

sgd = SGD(lr=0.05, decay=1e-6, momentum=0.9, nesterov=True)

model.compile(loss=’categorical_crossentropy’, optimizer=sgd,metrics=[“accuracy”])

#調用fit方法,就是一個訓練過程. 訓練的epoch數設為10,batch_size為100.

#數據經過隨機打亂shuffle=True。verbose=1,訓練過程中輸出的信息,0、1、2三種方式都可以,無關緊要。show_accuracy=True,訓練時每一個epoch都輸出accuracy。

#validation_split=0.2,將20%的數據作為驗證集。

model.fit(data, label, batch_size=100, nb_epoch=10,shuffle=True,verbose=1,validation_split=0.2)

“””

#使用data augmentation的方法

#一些參數和調用的方法,請看文檔

datagen = ImageDataGenerator(

        featurewise_center=True, # set input mean to 0 over the dataset

        samplewise_center=False, # set each sample mean to 0

        featurewise_std_normalization=True, # divide inputs by std of the dataset

        samplewise_std_normalization=False, # divide each input by its std

        zca_whitening=False, # apply ZCA whitening

        rotation_range=20, # randomly rotate images in the range (degrees, 0 to 180)

        width_shift_range=0.2, # randomly shift images horizontally (fraction of total width)

        height_shift_range=0.2, # randomly shift images vertically (fraction of total height)

        horizontal_flip=True, # randomly flip images

        vertical_flip=False) # randomly flip images

# compute quantities required for featurewise normalization 

# (std, mean, and principal components if ZCA whitening is applied)

datagen.fit(data)

for e in range(nb_epoch):

    print(‘-‘*40)

    print(‘Epoch’, e)

    print(‘-‘*40)

    print(“Training…”)

    # batch train with realtime data augmentation

    progbar = generic_utils.Progbar(data.shape[0])

    for X_batch, Y_batch in datagen.flow(data, label):

        loss,accuracy = model.train(X_batch, Y_batch,accuracy=True)

        progbar.add(X_batch.shape[0], values=[(“train loss”, loss),(“accuracy:”, accuracy)] )

“””

如何用 Python 構建神經網路擇時模型

import math

import random

random.seed(0)

def rand(a,b): #隨機函數

return (b-a)*random.random()+a

def make_matrix(m,n,fill=0.0):#創建一個指定大小的矩陣

mat = []

for i in range(m):

mat.append([fill]*n)

return mat

#定義sigmoid函數和它的導數

def sigmoid(x):

return 1.0/(1.0+math.exp(-x))

def sigmoid_derivate(x):

return x*(1-x) #sigmoid函數的導數

class BPNeuralNetwork:

def __init__(self):#初始化變數

self.input_n = 0

self.hidden_n = 0

self.output_n = 0

self.input_cells = []

self.hidden_cells = []

self.output_cells = []

self.input_weights = []

self.output_weights = []

self.input_correction = []

self.output_correction = []

#三個列表維護:輸入層,隱含層,輸出層神經元

def setup(self,ni,nh,no):

self.input_n = ni+1 #輸入層+偏置項

self.hidden_n = nh #隱含層

self.output_n = no #輸出層

#初始化神經元

self.input_cells = [1.0]*self.input_n

self.hidden_cells= [1.0]*self.hidden_n

self.output_cells= [1.0]*self.output_n

#初始化連接邊的邊權

self.input_weights = make_matrix(self.input_n,self.hidden_n) #鄰接矩陣存邊權:輸入層-隱藏層

self.output_weights = make_matrix(self.hidden_n,self.output_n) #鄰接矩陣存邊權:隱藏層-輸出層

#隨機初始化邊權:為了反向傳導做準備—隨機初始化的目的是使對稱失效

for i in range(self.input_n):

for h in range(self.hidden_n):

self.input_weights[i][h] = rand(-0.2 , 0.2) #由輸入層第i個元素到隱藏層第j個元素的邊權為隨機值

for h in range(self.hidden_n):

for o in range(self.output_n):

self.output_weights[h][o] = rand(-2.0, 2.0) #由隱藏層第i個元素到輸出層第j個元素的邊權為隨機值

#保存校正矩陣,為了以後誤差做調整

self.input_correction = make_matrix(self.input_n , self.hidden_n)

self.output_correction = make_matrix(self.hidden_n,self.output_n)

#輸出預測值

def predict(self,inputs):

#對輸入層進行操作轉化樣本

for i in range(self.input_n-1):

self.input_cells[i] = inputs[i] #n個樣本從0~n-1

#計算隱藏層的輸出,每個節點最終的輸出值就是權值*節點值的加權和

for j in range(self.hidden_n):

total = 0.0

for i in range(self.input_n):

total+=self.input_cells[i]*self.input_weights[i][j]

# 此處為何是先i再j,以隱含層節點做大循環,輸入樣本為小循環,是為了每一個隱藏節點計算一個輸出值,傳輸到下一層

self.hidden_cells[j] = sigmoid(total) #此節點的輸出是前一層所有輸入點和到該點之間的權值加權和

for k in range(self.output_n):

total = 0.0

for j in range(self.hidden_n):

total+=self.hidden_cells[j]*self.output_weights[j][k]

self.output_cells[k] = sigmoid(total) #獲取輸出層每個元素的值

return self.output_cells[:] #最後輸出層的結果返回

#反向傳播演算法:調用預測函數,根據反向傳播獲取權重後前向預測,將結果與實際結果返回比較誤差

def back_propagate(self,case,label,learn,correct):

#對輸入樣本做預測

self.predict(case) #對實例進行預測

output_deltas = [0.0]*self.output_n #初始化矩陣

for o in range(self.output_n):

error = label[o] – self.output_cells[o] #正確結果和預測結果的誤差:0,1,-1

output_deltas[o]= sigmoid_derivate(self.output_cells[o])*error#誤差穩定在0~1內

#隱含層誤差

hidden_deltas = [0.0]*self.hidden_n

for h in range(self.hidden_n):

error = 0.0

for o in range(self.output_n):

error+=output_deltas[o]*self.output_weights[h][o]

hidden_deltas[h] = sigmoid_derivate(self.hidden_cells[h])*error

#反向傳播演算法求W

#更新隱藏層-輸出權重

for h in range(self.hidden_n):

for o in range(self.output_n):

change = output_deltas[o]*self.hidden_cells[h]

#調整權重:上一層每個節點的權重學習*變化+矯正率

self.output_weights[h][o] += learn*change + correct*self.output_correction[h][o]

#更新輸入-隱藏層的權重

for i in range(self.input_n):

for h in range(self.hidden_n):

change = hidden_deltas[h]*self.input_cells[i]

self.input_weights[i][h] += learn*change + correct*self.input_correction[i][h]

self.input_correction[i][h] = change

#獲取全局誤差

error = 0.0

for o in range(len(label)):

error = 0.5*(label[o]-self.output_cells[o])**2 #平方誤差函數

return error

def train(self,cases,labels,limit=10000,learn=0.05,correct=0.1):

for i in range(limit): #設置迭代次數

error = 0.0

for j in range(len(cases)):#對輸入層進行訪問

label = labels[j]

case = cases[j]

error+=self.back_propagate(case,label,learn,correct) #樣例,標籤,學習率,正確閾值

def test(self): #學習異或

cases = [

[0, 0],

[0, 1],

[1, 0],

[1, 1],

] #測試樣例

labels = [[0], [1], [1], [0]] #標籤

self.setup(2,5,1) #初始化神經網路:輸入層,隱藏層,輸出層元素個數

self.train(cases,labels,10000,0.05,0.1) #可以更改

for case in cases:

print(self.predict(case))

if __name__ == ‘__main__’:

nn = BPNeuralNetwork()

nn.test()

原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/157434.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-11-18 19:59
下一篇 2024-11-18 19:59

相關推薦

  • 如何查看Anaconda中Python路徑

    對Anaconda中Python路徑即conda環境的查看進行詳細的闡述。 一、使用命令行查看 1、在Windows系統中,可以使用命令提示符(cmd)或者Anaconda Pro…

    編程 2025-04-29
  • Python周杰倫代碼用法介紹

    本文將從多個方面對Python周杰倫代碼進行詳細的闡述。 一、代碼介紹 from urllib.request import urlopen from bs4 import Bea…

    編程 2025-04-29
  • Python列表中負數的個數

    Python列表是一個有序的集合,可以存儲多個不同類型的元素。而負數是指小於0的整數。在Python列表中,我們想要找到負數的個數,可以通過以下幾個方面進行實現。 一、使用循環遍歷…

    編程 2025-04-29
  • Python中引入上一級目錄中函數

    Python中經常需要調用其他文件夾中的模塊或函數,其中一個常見的操作是引入上一級目錄中的函數。在此,我們將從多個角度詳細解釋如何在Python中引入上一級目錄的函數。 一、加入環…

    編程 2025-04-29
  • Python計算陽曆日期對應周幾

    本文介紹如何通過Python計算任意陽曆日期對應周幾。 一、獲取日期 獲取日期可以通過Python內置的模塊datetime實現,示例代碼如下: from datetime imp…

    編程 2025-04-29
  • Python字典去重複工具

    使用Python語言編寫字典去重複工具,可幫助用戶快速去重複。 一、字典去重複工具的需求 在使用Python編寫程序時,我們經常需要處理數據文件,其中包含了大量的重複數據。為了方便…

    編程 2025-04-29
  • 蝴蝶優化演算法Python版

    蝴蝶優化演算法是一種基於仿生學的優化演算法,模仿自然界中的蝴蝶進行搜索。它可以應用於多個領域的優化問題,包括數學優化、工程問題、機器學習等。本文將從多個方面對蝴蝶優化演算法Python版…

    編程 2025-04-29
  • Python清華鏡像下載

    Python清華鏡像是一個高質量的Python開發資源鏡像站,提供了Python及其相關的開發工具、框架和文檔的下載服務。本文將從以下幾個方面對Python清華鏡像下載進行詳細的闡…

    編程 2025-04-29
  • python強行終止程序快捷鍵

    本文將從多個方面對python強行終止程序快捷鍵進行詳細闡述,並提供相應代碼示例。 一、Ctrl+C快捷鍵 Ctrl+C快捷鍵是在終端中經常用來強行終止運行的程序。當你在終端中運行…

    編程 2025-04-29
  • Python程序需要編譯才能執行

    Python 被廣泛應用於數據分析、人工智慧、科學計算等領域,它的靈活性和簡單易學的性質使得越來越多的人喜歡使用 Python 進行編程。然而,在 Python 中程序執行的方式不…

    編程 2025-04-29

發表回復

登錄後才能評論