真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

梯度下降函數(shù)python,梯度下降函數(shù)分解

如何通過(guò)Python進(jìn)行深度學(xué)習(xí)?

作者 | Vihar Kurama

成都創(chuàng)新互聯(lián)從2013年成立,先為臨淄等服務(wù)建站,臨淄等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢服務(wù)。為臨淄企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問題。

編譯 | 荷葉

來(lái)源 | 云棲社區(qū)

摘要:深度學(xué)習(xí)背后的主要原因是人工智能應(yīng)該從人腦中汲取靈感。本文就用一個(gè)小例子無(wú)死角的介紹一下深度學(xué)習(xí)!

人腦模擬

深度學(xué)習(xí)背后的主要原因是人工智能應(yīng)該從人腦中汲取靈感。此觀點(diǎn)引出了“神經(jīng)網(wǎng)絡(luò)”這一術(shù)語(yǔ)。人腦中包含數(shù)十億個(gè)神經(jīng)元,它們之間有數(shù)萬(wàn)個(gè)連接。很多情況下,深度學(xué)習(xí)算法和人腦相似,因?yàn)槿四X和深度學(xué)習(xí)模型都擁有大量的編譯單元(神經(jīng)元),這些編譯單元(神經(jīng)元)在獨(dú)立的情況下都不太智能,但是當(dāng)他們相互作用時(shí)就會(huì)變得智能。

我認(rèn)為人們需要了解到深度學(xué)習(xí)正在使得很多幕后的事物變得更好。深度學(xué)習(xí)已經(jīng)應(yīng)用于谷歌搜索和圖像搜索,你可以通過(guò)它搜索像“擁抱”這樣的詞語(yǔ)以獲得相應(yīng)的圖像。-杰弗里·辛頓

神經(jīng)元

神經(jīng)網(wǎng)絡(luò)的基本構(gòu)建模塊是人工神經(jīng)元,它模仿了人類大腦的神經(jīng)元。這些神經(jīng)元是簡(jiǎn)單、強(qiáng)大的計(jì)算單元,擁有加權(quán)輸入信號(hào)并且使用激活函數(shù)產(chǎn)生輸出信號(hào)。這些神經(jīng)元分布在神經(jīng)網(wǎng)絡(luò)的幾個(gè)層中。

inputs 輸入 outputs 輸出 weights 權(quán)值 activation 激活

人工神經(jīng)網(wǎng)絡(luò)的工作原理是什么?

深度學(xué)習(xí)由人工神經(jīng)網(wǎng)絡(luò)構(gòu)成,該網(wǎng)絡(luò)模擬了人腦中類似的網(wǎng)絡(luò)。當(dāng)數(shù)據(jù)穿過(guò)這個(gè)人工網(wǎng)絡(luò)時(shí),每一層都會(huì)處理這個(gè)數(shù)據(jù)的一方面,過(guò)濾掉異常值,辨認(rèn)出熟悉的實(shí)體,并產(chǎn)生最終輸出。

輸入層:該層由神經(jīng)元組成,這些神經(jīng)元只接收輸入信息并將它傳遞到其他層。輸入層的圖層數(shù)應(yīng)等于數(shù)據(jù)集里的屬性或要素的數(shù)量。輸出層:輸出層具有預(yù)測(cè)性,其主要取決于你所構(gòu)建的模型類型。隱含層:隱含層處于輸入層和輸出層之間,以模型類型為基礎(chǔ)。隱含層包含大量的神經(jīng)元。處于隱含層的神經(jīng)元會(huì)先轉(zhuǎn)化輸入信息,再將它們傳遞出去。隨著網(wǎng)絡(luò)受訓(xùn)練,權(quán)重得到更新,從而使其更具前瞻性。

神經(jīng)元的權(quán)重

權(quán)重是指兩個(gè)神經(jīng)元之間的連接的強(qiáng)度或幅度。你如果熟悉線性回歸的話,可以將輸入的權(quán)重類比為我們?cè)诨貧w方程中用的系數(shù)。權(quán)重通常被初始化為小的隨機(jī)數(shù)值,比如數(shù)值0-1。

前饋深度網(wǎng)絡(luò)

前饋監(jiān)督神經(jīng)網(wǎng)絡(luò)曾是第一個(gè)也是最成功的學(xué)習(xí)算法。該網(wǎng)絡(luò)也可被稱為深度網(wǎng)絡(luò)、多層感知機(jī)(MLP)或簡(jiǎn)單神經(jīng)網(wǎng)絡(luò),并且闡明了具有單一隱含層的原始架構(gòu)。每個(gè)神經(jīng)元通過(guò)某個(gè)權(quán)重和另一個(gè)神經(jīng)元相關(guān)聯(lián)。

該網(wǎng)絡(luò)處理向前處理輸入信息,激活神經(jīng)元,最終產(chǎn)生輸出值。在此網(wǎng)絡(luò)中,這稱為前向傳遞。

inputlayer 輸入層 hidden layer 輸出層 output layer 輸出層

激活函數(shù)

激活函數(shù)就是求和加權(quán)的輸入到神經(jīng)元的輸出的映射。之所以稱之為激活函數(shù)或傳遞函數(shù)是因?yàn)樗刂浦せ钌窠?jīng)元的初始值和輸出信號(hào)的強(qiáng)度。

用數(shù)學(xué)表示為:

我們有許多激活函數(shù),其中使用最多的是整流線性單元函數(shù)、雙曲正切函數(shù)和solfPlus函數(shù)。

激活函數(shù)的速查表如下:

反向傳播

在網(wǎng)絡(luò)中,我們將預(yù)測(cè)值與預(yù)期輸出值相比較,并使用函數(shù)計(jì)算其誤差。然后,這個(gè)誤差會(huì)傳回這個(gè)網(wǎng)絡(luò),每次傳回一個(gè)層,權(quán)重也會(huì)根絕其導(dǎo)致的誤差值進(jìn)行更新。這個(gè)聰明的數(shù)學(xué)法是反向傳播算法。這個(gè)步驟會(huì)在訓(xùn)練數(shù)據(jù)的所有樣本中反復(fù)進(jìn)行,整個(gè)訓(xùn)練數(shù)據(jù)集的網(wǎng)絡(luò)更新一輪稱為一個(gè)時(shí)期。一個(gè)網(wǎng)絡(luò)可受訓(xùn)練數(shù)十、數(shù)百或數(shù)千個(gè)時(shí)期。

prediction error 預(yù)測(cè)誤差

代價(jià)函數(shù)和梯度下降

代價(jià)函數(shù)度量了神經(jīng)網(wǎng)絡(luò)對(duì)給定的訓(xùn)練輸入和預(yù)期輸出“有多好”。該函數(shù)可能取決于權(quán)重、偏差等屬性。

代價(jià)函數(shù)是單值的,并不是一個(gè)向量,因?yàn)樗鼜恼w上評(píng)估神經(jīng)網(wǎng)絡(luò)的性能。在運(yùn)用梯度下降最優(yōu)算法時(shí),權(quán)重在每個(gè)時(shí)期后都會(huì)得到增量式地更新。

兼容代價(jià)函數(shù)

用數(shù)學(xué)表述為差值平方和:

target 目標(biāo)值 output 輸出值

權(quán)重更新的大小和方向是由在代價(jià)梯度的反向上采取步驟計(jì)算出的。

其中η 是學(xué)習(xí)率

其中Δw是包含每個(gè)權(quán)重系數(shù)w的權(quán)重更新的向量,其計(jì)算方式如下:

target 目標(biāo)值 output 輸出值

圖表中會(huì)考慮到單系數(shù)的代價(jià)函數(shù)

initial weight 初始權(quán)重 gradient 梯度 global cost minimum 代價(jià)極小值

在導(dǎo)數(shù)達(dá)到最小誤差值之前,我們會(huì)一直計(jì)算梯度下降,并且每個(gè)步驟都會(huì)取決于斜率(梯度)的陡度。

多層感知器(前向傳播)

這類網(wǎng)絡(luò)由多層神經(jīng)元組成,通常這些神經(jīng)元以前饋方式(向前傳播)相互連接。一層中的每個(gè)神經(jīng)元可以直接連接后續(xù)層的神經(jīng)元。在許多應(yīng)用中,這些網(wǎng)絡(luò)的單元會(huì)采用S型函數(shù)或整流線性單元(整流線性激活)函數(shù)作為激活函數(shù)。

現(xiàn)在想想看要找出處理次數(shù)這個(gè)問題,給定的賬戶和家庭成員作為輸入

要解決這個(gè)問題,首先,我們需要先創(chuàng)建一個(gè)前向傳播神經(jīng)網(wǎng)絡(luò)。我們的輸入層將是家庭成員和賬戶的數(shù)量,隱含層數(shù)為1, 輸出層將是處理次數(shù)。

將圖中輸入層到輸出層的給定權(quán)重作為輸入:家庭成員數(shù)為2、賬戶數(shù)為3。

現(xiàn)在將通過(guò)以下步驟使用前向傳播來(lái)計(jì)算隱含層(i,j)和輸出層(k)的值。

步驟:

1, 乘法-添加方法。

2, 點(diǎn)積(輸入*權(quán)重)。

3,一次一個(gè)數(shù)據(jù)點(diǎn)的前向傳播。

4, 輸出是該數(shù)據(jù)點(diǎn)的預(yù)測(cè)。

i的值將從相連接的神經(jīng)元所對(duì)應(yīng)的輸入值和權(quán)重中計(jì)算出來(lái)。

i = (2 * 1) + (3* 1) → i = 5

同樣地,j = (2 * -1) + (3 * 1) → j =1

K = (5 * 2) + (1* -1) → k = 9

Python中的多層感知器問題的解決

激活函數(shù)的使用

為了使神經(jīng)網(wǎng)絡(luò)達(dá)到其最大預(yù)測(cè)能力,我們需要在隱含層應(yīng)用一個(gè)激活函數(shù),以捕捉非線性。我們通過(guò)將值代入方程式的方式來(lái)在輸入層和輸出層應(yīng)用激活函數(shù)。

這里我們使用整流線性激活(ReLU):

用Keras開發(fā)第一個(gè)神經(jīng)網(wǎng)絡(luò)

關(guān)于Keras:

Keras是一個(gè)高級(jí)神經(jīng)網(wǎng)絡(luò)的應(yīng)用程序編程接口,由Python編寫,能夠搭建在TensorFlow,CNTK,或Theano上。

使用PIP在設(shè)備上安裝Keras,并且運(yùn)行下列指令。

在keras執(zhí)行深度學(xué)習(xí)程序的步驟

1,加載數(shù)據(jù);

2,創(chuàng)建模型;

3,編譯模型;

4,擬合模型;

5,評(píng)估模型。

開發(fā)Keras模型

全連接層用Dense表示。我們可以指定層中神經(jīng)元的數(shù)量作為第一參數(shù),指定初始化方法為第二參數(shù),即初始化參數(shù),并且用激活參數(shù)確定激活函數(shù)。既然模型已經(jīng)創(chuàng)建,我們就可以編譯它。我們?cè)诘讓訋?kù)(也稱為后端)用高效數(shù)字庫(kù)編譯模型,底層庫(kù)可以用Theano或TensorFlow。目前為止,我們已經(jīng)完成了創(chuàng)建模型和編譯模型,為進(jìn)行有效計(jì)算做好了準(zhǔn)備?,F(xiàn)在可以在PIMA數(shù)據(jù)上運(yùn)行模型了。我們可以在模型上調(diào)用擬合函數(shù)f(),以在數(shù)據(jù)上訓(xùn)練或擬合模型。

我們先從KERAS中的程序開始,

神經(jīng)網(wǎng)絡(luò)一直訓(xùn)練到150個(gè)時(shí)期,并返回精確值。

從零開始用Python構(gòu)建神經(jīng)網(wǎng)絡(luò)

從零開始用Python構(gòu)建神經(jīng)網(wǎng)絡(luò)

動(dòng)機(jī):為了更加深入的理解深度學(xué)習(xí),我們將使用 python 語(yǔ)言從頭搭建一個(gè)神經(jīng)網(wǎng)絡(luò),而不是使用像 Tensorflow 那樣的封裝好的框架。我認(rèn)為理解神經(jīng)網(wǎng)絡(luò)的內(nèi)部工作原理,對(duì)數(shù)據(jù)科學(xué)家來(lái)說(shuō)至關(guān)重要。

這篇文章的內(nèi)容是我的所學(xué),希望也能對(duì)你有所幫助。

神經(jīng)網(wǎng)絡(luò)是什么?

介紹神經(jīng)網(wǎng)絡(luò)的文章大多數(shù)都會(huì)將它和大腦進(jìn)行類比。如果你沒有深入研究過(guò)大腦與神經(jīng)網(wǎng)絡(luò)的類比,那么將神經(jīng)網(wǎng)絡(luò)解釋為一種將給定輸入映射為期望輸出的數(shù)學(xué)關(guān)系會(huì)更容易理解。

神經(jīng)網(wǎng)絡(luò)包括以下組成部分

? 一個(gè)輸入層,x

? 任意數(shù)量的隱藏層

? 一個(gè)輸出層,?

? 每層之間有一組權(quán)值和偏置,W and b

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

下圖展示了 2 層神經(jīng)網(wǎng)絡(luò)的結(jié)構(gòu)(注意:我們?cè)谟?jì)算網(wǎng)絡(luò)層數(shù)時(shí)通常排除輸入層)

2 層神經(jīng)網(wǎng)絡(luò)的結(jié)構(gòu)

用 Python 可以很容易的構(gòu)建神經(jīng)網(wǎng)絡(luò)類

訓(xùn)練神經(jīng)網(wǎng)絡(luò)

這個(gè)網(wǎng)絡(luò)的輸出 ? 為:

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

因此 W 和 b 的值影響預(yù)測(cè)的準(zhǔn)確率. 所以根據(jù)輸入數(shù)據(jù)對(duì) W 和 b 調(diào)優(yōu)的過(guò)程就被成為訓(xùn)練神經(jīng)網(wǎng)絡(luò)。

每步訓(xùn)練迭代包含以下兩個(gè)部分:

? 計(jì)算預(yù)測(cè)結(jié)果 ?,這一步稱為前向傳播

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

下面的順序圖展示了這個(gè)過(guò)程:

前向傳播

正如我們?cè)谏蠄D中看到的,前向傳播只是簡(jiǎn)單的計(jì)算。對(duì)于一個(gè)基本的 2 層網(wǎng)絡(luò)來(lái)說(shuō),它的輸出是這樣的:

我們?cè)?NeuralNetwork 類中增加一個(gè)計(jì)算前向傳播的函數(shù)。為了簡(jiǎn)單起見我們假設(shè)偏置 b 為0:

但是我們還需要一個(gè)方法來(lái)評(píng)估預(yù)測(cè)結(jié)果的好壞(即預(yù)測(cè)值和真實(shí)值的誤差)。這就要用到損失函數(shù)。

損失函數(shù)

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

誤差平方和是求每個(gè)預(yù)測(cè)值和真實(shí)值之間的誤差再求和,這個(gè)誤差是他們的差值求平方以便我們觀察誤差的絕對(duì)值。

訓(xùn)練的目標(biāo)是找到一組 W 和 b,使得損失函數(shù)最好小,也即預(yù)測(cè)值和真實(shí)值之間的距離最小。

反向傳播

我們已經(jīng)度量出了預(yù)測(cè)的誤差(損失),現(xiàn)在需要找到一種方法來(lái)傳播誤差,并以此更新權(quán)值和偏置。

為了知道如何適當(dāng)?shù)恼{(diào)整權(quán)值和偏置,我們需要知道損失函數(shù)對(duì)權(quán)值 W 和偏置 b 的導(dǎo)數(shù)。

回想微積分中的概念,函數(shù)的導(dǎo)數(shù)就是函數(shù)的斜率。

梯度下降法

如果我們已經(jīng)求出了導(dǎo)數(shù),我們就可以通過(guò)增加或減少導(dǎo)數(shù)值來(lái)更新權(quán)值 W 和偏置 b(參考上圖)。這種方式被稱為梯度下降法。

但是我們不能直接計(jì)算損失函數(shù)對(duì)權(quán)值和偏置的導(dǎo)數(shù),因?yàn)樵趽p失函數(shù)的等式中并沒有顯式的包含他們。因此,我們需要運(yùn)用鏈?zhǔn)角髮?dǎo)發(fā)在來(lái)幫助計(jì)算導(dǎo)數(shù)。

鏈?zhǔn)椒▌t用于計(jì)算損失函數(shù)對(duì) W 和 b 的導(dǎo)數(shù)。注意,為了簡(jiǎn)單起見。我們只展示了假設(shè)網(wǎng)絡(luò)只有 1 層的偏導(dǎo)數(shù)。

這雖然很簡(jiǎn)陋,但是我們依然能得到想要的結(jié)果—損失函數(shù)對(duì)權(quán)值 W 的導(dǎo)數(shù)(斜率),因此我們可以相應(yīng)的調(diào)整權(quán)值。

現(xiàn)在我們將反向傳播算法的函數(shù)添加到 Python 代碼中

為了更深入的理解微積分原理和反向傳播中的鏈?zhǔn)角髮?dǎo)法則,我強(qiáng)烈推薦 3Blue1Brown 的如下教程:

Youtube:

整合并完成一個(gè)實(shí)例

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

神經(jīng)網(wǎng)絡(luò)可以通過(guò)學(xué)習(xí)得到函數(shù)的權(quán)重。而我們僅靠觀察是不太可能得到函數(shù)的權(quán)重的。

讓我們訓(xùn)練神經(jīng)網(wǎng)絡(luò)進(jìn)行 1500 次迭代,看看會(huì)發(fā)生什么。 注意觀察下面每次迭代的損失函數(shù),我們可以清楚地看到損失函數(shù)單調(diào)遞減到最小值。這與我們之前介紹的梯度下降法一致。

讓我們看看經(jīng)過(guò) 1500 次迭代后的神經(jīng)網(wǎng)絡(luò)的最終預(yù)測(cè)結(jié)果:

經(jīng)過(guò) 1500 次迭代訓(xùn)練后的預(yù)測(cè)結(jié)果

我們成功了!我們應(yīng)用前向和方向傳播算法成功的訓(xùn)練了神經(jīng)網(wǎng)絡(luò)并且預(yù)測(cè)結(jié)果收斂于真實(shí)值。

注意預(yù)測(cè)值和真實(shí)值之間存在細(xì)微的誤差是允許的。這樣可以防止模型過(guò)擬合并且使得神經(jīng)網(wǎng)絡(luò)對(duì)于未知數(shù)據(jù)有著更強(qiáng)的泛化能力。

下一步是什么?

幸運(yùn)的是我們的學(xué)習(xí)之旅還沒有結(jié)束,仍然有很多關(guān)于神經(jīng)網(wǎng)絡(luò)和深度學(xué)習(xí)的內(nèi)容需要學(xué)習(xí)。例如:

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

? 在訓(xùn)練網(wǎng)絡(luò)的時(shí)候應(yīng)用學(xué)習(xí)率

? 在面對(duì)圖像分類任務(wù)的時(shí)候使用卷積神經(jīng)網(wǎng)絡(luò)

我很快會(huì)寫更多關(guān)于這個(gè)主題的內(nèi)容,敬請(qǐng)期待!

最后的想法

我自己也從零開始寫了很多神經(jīng)網(wǎng)絡(luò)的代碼

雖然可以使用諸如 Tensorflow 和 Keras 這樣的深度學(xué)習(xí)框架方便的搭建深層網(wǎng)絡(luò)而不需要完全理解其內(nèi)部工作原理。但是我覺得對(duì)于有追求的數(shù)據(jù)科學(xué)家來(lái)說(shuō),理解內(nèi)部原理是非常有益的。

這種練習(xí)對(duì)我自己來(lái)說(shuō)已成成為重要的時(shí)間投入,希望也能對(duì)你有所幫助

如何用 python 實(shí)現(xiàn)帶隨機(jī)梯度下降的線性回歸

線性回歸是一種用于預(yù)測(cè)真實(shí)值的方法。讓人困惑的是,這些需要預(yù)測(cè)真實(shí)值的問題被稱為回歸問題(regression problems)。線性回歸是一種用直線對(duì)輸入輸出值進(jìn)行建模的方法。在超過(guò)二維的空間里,這條直線被想象成一個(gè)平面或者超平面(hyperplane)。預(yù)測(cè)即是通過(guò)對(duì)輸入值的組合對(duì)輸出值進(jìn)行預(yù)判。

python怎么實(shí)現(xiàn)邏輯回歸的梯度下降法

import sys

#Training data set

#each element in x represents (x0,x1,x2)

x = [(1,0.,3) , (1,1.,3) ,(1,2.,3), (1,3.,2) , (1,4.,4)]

#y[i] is the output of y = theta0 * x[0] + theta1 * x[1] +theta2 * x[2]

y = [95.364,97.217205,75.195834,60.105519,49.342380]

epsilon = 0.0001

#learning rate

alpha = 0.01

diff = [0,0]

max_itor = 1000

error1 = 0

error0 =0

cnt = 0

m = len(x)

#init the parameters to zero

theta0 = 0

theta1 = 0

theta2 = 0

while True:

cnt = cnt + 1

#calculate the parameters

for i in range(m):

diff[0] = y[i]-( theta0 + theta1 * x[i][1] + theta2 * x[i][2] )

theta0 = theta0 + alpha * diff[0] * x[i][0]

theta1 = theta1 + alpha * diff[0]* x[i][1]

theta2 = theta2 + alpha * diff[0]* x[i][2]

#calculate the cost function

error1 = 0

for lp in range(len(x)):

error1 += ( y[i]-( theta0 + theta1 * x[i][1] + theta2 * x[i][2] ) )**2/2

if abs(error1-error0) epsilon:

break

else:

error0 = error1

print ' theta0 : %f, theta1 : %f, theta2 : %f, error1 : %f'%(theta0,theta1,theta2,error1)

print 'Done: theta0 : %f, theta1 : %f, theta2 : %f'%(theta0,theta1,theta2)

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

如果把神經(jīng)網(wǎng)絡(luò)模型比作一個(gè)黑箱,把模型參數(shù)比作黑箱上面一個(gè)個(gè)小旋鈕,那么根據(jù)通用近似理論(universal approximation theorem),只要黑箱上的旋鈕數(shù)量足夠多,而且每個(gè)旋鈕都被調(diào)節(jié)到合適的位置,那這個(gè)模型就可以實(shí)現(xiàn)近乎任意功能(可以逼近任意的數(shù)學(xué)模型)。

顯然,這些旋鈕(參數(shù))不是由人工調(diào)節(jié)的,所謂的機(jī)器學(xué)習(xí),就是通過(guò)程序來(lái)自動(dòng)調(diào)節(jié)這些參數(shù)。神經(jīng)網(wǎng)絡(luò)不僅參數(shù)眾多(少則十幾萬(wàn),多則上億),而且網(wǎng)絡(luò)是由線性層和非線性層交替疊加而成,上層參數(shù)的變化會(huì)對(duì)下層的輸出產(chǎn)生非線性的影響,因此,早期的神經(jīng)網(wǎng)絡(luò)流派一度無(wú)法往多層方向發(fā)展,因?yàn)樗麄冋也坏侥苡糜谌我舛鄬泳W(wǎng)絡(luò)的、簡(jiǎn)潔的自動(dòng)調(diào)節(jié)參數(shù)的方法。

直到上世紀(jì)80年代,祖師爺辛頓發(fā)明了反向傳播算法,用輸出誤差的均方差(就是loss值)一層一層遞進(jìn)地反饋到各層神經(jīng)網(wǎng)絡(luò),用梯度下降法來(lái)調(diào)節(jié)每層網(wǎng)絡(luò)的參數(shù)。至此,神經(jīng)網(wǎng)絡(luò)才得以開始它的深度之旅。

本文用python自己動(dòng)手實(shí)現(xiàn)梯度下降和反向傳播算法。 請(qǐng)點(diǎn)擊這里 到Github上查看源碼。

梯度下降法是一種將輸出誤差反饋到神經(jīng)網(wǎng)絡(luò)并自動(dòng)調(diào)節(jié)參數(shù)的方法,它通過(guò)計(jì)算輸出誤差的loss值( J )對(duì)參數(shù) W 的導(dǎo)數(shù),并沿著導(dǎo)數(shù)的反方向來(lái)調(diào)節(jié) W ,經(jīng)過(guò)多次這樣的操作,就能將輸出誤差減小到最小值,即曲線的最低點(diǎn)。

雖然Tensorflow、Pytorch這些框架都實(shí)現(xiàn)了自動(dòng)求導(dǎo)的功能,但為了徹底理解參數(shù)調(diào)節(jié)的過(guò)程,還是有必要自己動(dòng)手實(shí)現(xiàn)梯度下降和反向傳播算法。我相信你和我一樣,已經(jīng)忘了之前學(xué)的微積分知識(shí),因此,到可汗學(xué)院復(fù)習(xí)下 Calculus

和 Multivariable Calculus 是個(gè)不錯(cuò)的方法,或是拜讀 這篇關(guān)于神經(jīng)網(wǎng)絡(luò)矩陣微積分的文章 。

Figure2是求導(dǎo)的基本公式,其中最重要的是 Chain Rule ,它通過(guò)引入中間變量,將“ y 對(duì) x 求導(dǎo)”的過(guò)程轉(zhuǎn)換為“ y 對(duì)中間變量 u 求導(dǎo),再乘以 u 對(duì) x 求導(dǎo)”,這樣就將一個(gè)復(fù)雜的函數(shù)鏈求導(dǎo)簡(jiǎn)化為多個(gè)簡(jiǎn)單函數(shù)求導(dǎo)。

如果你不想涉及這些求導(dǎo)的細(xì)節(jié),可以跳過(guò)具體的計(jì)算,領(lǐng)會(huì)其思想就好。

對(duì)于神經(jīng)網(wǎng)絡(luò)模型: Linear - ReLu - Linear - MSE(Loss function) 來(lái)說(shuō),反向傳播就是根據(jù)鏈?zhǔn)椒▌t對(duì) 求導(dǎo),用輸出誤差的均方差(MSE)對(duì)模型的輸出求導(dǎo),并將導(dǎo)數(shù)傳回上一層神經(jīng)網(wǎng)絡(luò),用于它們來(lái)對(duì) w 、 b 和 x (上上層的輸出)求導(dǎo),再將 x 的導(dǎo)數(shù)傳回到它的上一層神經(jīng)網(wǎng)絡(luò),由此將輸出誤差的均方差通過(guò)遞進(jìn)的方式反饋到各神經(jīng)網(wǎng)絡(luò)層。

對(duì)于 求導(dǎo)的第一步是為這個(gè)函數(shù)鏈引入中間變量:

接著第二步是對(duì)各中間變量求導(dǎo),最后才是將這些導(dǎo)數(shù)乘起來(lái)。

首先,反向傳播的起點(diǎn)是對(duì)loss function求導(dǎo),即 。 :

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

linear層的反向傳播是對(duì) 求導(dǎo),它也是一個(gè)函數(shù)鏈,也要先對(duì)中間變量求導(dǎo)再將所有導(dǎo)數(shù)相乘:

這些中間變量的導(dǎo)數(shù)分別是:

對(duì)向量 求導(dǎo),指的是對(duì)向量所有的標(biāo)量求偏導(dǎo)( ),即: ,這個(gè)橫向量也稱為y的梯度。

這里 ,是一個(gè)向量,因此, 求導(dǎo),指的是y的所有標(biāo)量(y_1, y_2, ..., y_n)對(duì)向量x求偏導(dǎo),即:

。

這個(gè)矩陣稱為雅克比矩陣,它是個(gè)對(duì)角矩陣,因?yàn)? ,因此 。

同理, 。

因此,所有中間導(dǎo)數(shù)相乘的結(jié)果:

lin_grad() 中的inp.g、w.g和b.g分別是求 的導(dǎo)數(shù),以inp.g為例,它等于 ,且需要乘以前面各層的導(dǎo)數(shù),即 outp.g @ w.t() ,之所以要用點(diǎn)積運(yùn)算符(@)而不是標(biāo)量相乘,是為了讓它的導(dǎo)數(shù)shape和tensor shape保持一致。同理,w.g和b.g也是根據(jù)相同邏輯來(lái)計(jì)算的。

ReLu層的求導(dǎo)相對(duì)來(lái)說(shuō)就簡(jiǎn)單多了,當(dāng)輸入 = 0時(shí),導(dǎo)數(shù)為0,當(dāng)輸入 0時(shí),導(dǎo)數(shù)為1。

求導(dǎo)運(yùn)算終于結(jié)束了,接下來(lái)就是驗(yàn)證我們的反向傳播是否正確。驗(yàn)證方法是將forward_backward()計(jì)算的導(dǎo)數(shù)和Pytorch自動(dòng)微分得到的導(dǎo)數(shù)相比較,如果它們相近,就認(rèn)為我們的反向傳播算法是正確的。

首先,將計(jì)算好的參數(shù)導(dǎo)數(shù)保存到w1g、b1g、w2g和b2g中,再用Pytorch的自動(dòng)微分來(lái)求w11、b11、w22和b22的導(dǎo)數(shù)。

最后,用np.allclose()來(lái)比較導(dǎo)數(shù)間的差異,如果有任何一個(gè)導(dǎo)數(shù)不相近,assert就會(huì)報(bào)錯(cuò)。結(jié)果證明,我們自己動(dòng)手實(shí)現(xiàn)的算法是正確的。

反向傳播是遵循鏈?zhǔn)椒▌t的,它將前向傳播的輸出作為輸入,輸入作為輸出,通過(guò)遞進(jìn)的方式將求導(dǎo)這個(gè)動(dòng)作從后向前傳遞回各層。神經(jīng)網(wǎng)絡(luò)參數(shù)的求導(dǎo)需要進(jìn)行矩陣微積分計(jì)算,根據(jù)這些導(dǎo)數(shù)的反方向來(lái)調(diào)節(jié)參數(shù),就可以讓模型的輸出誤差的優(yōu)化到最小值。

歡迎關(guān)注和點(diǎn)贊,你的鼓勵(lì)將是我創(chuàng)作的動(dòng)力

Python實(shí)現(xiàn)簡(jiǎn)單多線程任務(wù)隊(duì)列

Python實(shí)現(xiàn)簡(jiǎn)單多線程任務(wù)隊(duì)列

最近我在用梯度下降算法繪制神經(jīng)網(wǎng)絡(luò)的數(shù)據(jù)時(shí),遇到了一些算法性能的問題。梯度下降算法的代碼如下(偽代碼):

defgradient_descent(): # the gradient descent code plotly.write(X, Y)

一般來(lái)說(shuō),當(dāng)網(wǎng)絡(luò)請(qǐng)求 plot.ly 繪圖時(shí)會(huì)阻塞等待返回,于是也會(huì)影響到其他的梯度下降函數(shù)的執(zhí)行速度。

一種解決辦法是每調(diào)用一次 plotly.write 函數(shù)就開啟一個(gè)新的線程,但是這種方法感覺不是很好。 我不想用一個(gè)像 cerely(一種分布式任務(wù)隊(duì)列)一樣大而全的任務(wù)隊(duì)列框架,因?yàn)榭蚣軐?duì)于我的這點(diǎn)需求來(lái)說(shuō)太重了,并且我的繪圖也并不需要 redis 來(lái)持久化數(shù)據(jù)。

那用什么辦法解決呢?我在 python 中寫了一個(gè)很小的任務(wù)隊(duì)列,它可以在一個(gè)單獨(dú)的線程中調(diào)用 plotly.write函數(shù)。下面是程序代碼。

fromthreadingimportThreadimportQueueimporttime classTaskQueue(Queue.Queue):

首先我們繼承 Queue.Queue 類。從 Queue.Queue 類可以繼承 get 和 put 方法,以及隊(duì)列的行為。

def__init__(self, num_workers=1): Queue.Queue.__init__(self) self.num_workers=num_workers self.start_workers()

初始化的時(shí)候,我們可以不用考慮工作線程的數(shù)量。

defadd_task(self, task,*args,**kwargs): args=argsor() kwargs=kwargsor{} self.put((task, args, kwargs))

我們把 task, args, kwargs 以元組的形式存儲(chǔ)在隊(duì)列中。*args 可以傳遞數(shù)量不等的參數(shù),**kwargs 可以傳遞命名參數(shù)。

defstart_workers(self): foriinrange(self.num_workers): t=Thread(target=self.worker) t.daemon=True t.start()

我們?yōu)槊總€(gè) worker 創(chuàng)建一個(gè)線程,然后在后臺(tái)刪除。

下面是 worker 函數(shù)的代碼:

defworker(self): whileTrue: tupl=self.get() item, args, kwargs=self.get() item(*args,**kwargs) self.task_done()

worker 函數(shù)獲取隊(duì)列頂端的任務(wù),并根據(jù)輸入?yún)?shù)運(yùn)行,除此之外,沒有其他的功能。下面是隊(duì)列的代碼:

我們可以通過(guò)下面的代碼測(cè)試:

defblokkah(*args,**kwargs): time.sleep(5) print“Blokkah mofo!” q=TaskQueue(num_workers=5) foriteminrange(1): q.add_task(blokkah) q.join()# wait for all the tasks to finish. print“Alldone!”

Blokkah 是我們要做的任務(wù)名稱。隊(duì)列已經(jīng)緩存在內(nèi)存中,并且沒有執(zhí)行很多任務(wù)。下面的步驟是把主隊(duì)列當(dāng)做單獨(dú)的進(jìn)程來(lái)運(yùn)行,這樣主程序退出以及執(zhí)行數(shù)據(jù)庫(kù)持久化時(shí),隊(duì)列任務(wù)不會(huì)停止運(yùn)行。但是這個(gè)例子很好地展示了如何從一個(gè)很簡(jiǎn)單的小任務(wù)寫成像工作隊(duì)列這樣復(fù)雜的程序。

defgradient_descent(): # the gradient descent code queue.add_task(plotly.write, x=X, y=Y)

修改之后,我的梯度下降算法工作效率似乎更高了。如果你很感興趣的話,可以參考下面的代碼。fromthreadingimportThreadimportQueueimporttime classTaskQueue(Queue.Queue): def__init__(self, num_workers=1):Queue.Queue.__init__(self)self.num_workers=num_workersself.start_workers() defadd_task(self, task,*args,**kwargs):args=argsor()kwargs=kwargsor{}self.put((task, args, kwargs)) defstart_workers(self):foriinrange(self.num_workers):t=Thread(target=self.worker)t.daemon=Truet.start() defworker(self):whileTrue:tupl=self.get()item, args, kwargs=self.get()item(*args,**kwargs)self.task_done() deftests():defblokkah(*args,**kwargs):time.sleep(5)print"Blokkah mofo!" q=TaskQueue(num_workers=5) foriteminrange(10):q.add_task(blokkah) q.join()# block until all tasks are doneprint"All done!" if__name__=="__main__":tests()


本文題目:梯度下降函數(shù)python,梯度下降函數(shù)分解
當(dāng)前鏈接:http://weahome.cn/article/hesige.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部