在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

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

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

3天內不再提示

基于numpy實現合成梯度

zhKF_jqr_AI ? 來源:未知 ? 作者:李倩 ? 2018-05-14 17:32 ? 次閱讀

DeepMind提出用合成梯度取代反向傳播,讓網絡層可以獨立學習,加快訓練速度。讓我們和DeepMind數據科學家、Udacity深度學習導師Andrew Trask一起,基于numpy實現合成梯度。

TLDR本文將通過從頭實現DeepMind的Decoupled Neural Interfaces Using Synthetic Gradients論文中的技術,學習這一技術背后的直覺。

一、合成梯度概述

通常,神經網絡比較預測和數據集,以決定如何更新權重。它接著使用反向傳播找出每個權重移動的方向,使得預測更精確。然而,在合成梯度(Synthetic Gradient)的情況下,每層各自做出數據的“最佳猜測”,然后根據猜測更新其權重?!白罴巡聹y”稱為合成梯度。數據用來幫助更新每層的“猜測器”(合成梯度生成器)。在大多數情況下,這讓網絡層可以獨立學習,以加快訓練的速度。

上圖(來自論文)提供了一個直觀的表示(自左向右)。圓角方塊為網絡層,菱形為合成梯度生成器。

二、使用合成梯度

讓我們暫時忽略合成梯度是如何生成的,直接看看它們是如何使用的。上圖最左展示了如何更新神經網絡的第一層。第一層前向傳播至合成梯度生成器(Mi+1),合成梯度生成器返回一個梯度。網絡使用這個合成梯度代替真實的梯度(計算真實梯度需要一次完整的前向傳播和反向傳播)。接著照常更新權重,假裝合成梯度是真實梯度。如果你需要溫習下權重是如何根據梯度更新的,請參考我之前寫的基于Numpy實現神經網絡:反向傳播和梯度下降。

所以,簡單來說,合成梯度和平常的梯度一樣,而且出于一些神奇的原因,它們看起來很精確(在沒有查看數據的情況下)!看起來像魔法?讓我們看看它們是如何生成的。

三、生成合成梯度

好吧,這部分非常巧妙,坦白地說,它可以起效真令人驚訝。如何為一個神經網絡生成合成梯度?好吧,你當然需要另一個網絡!合成梯度生成器不過是一個神經網絡,該網絡經訓練可以接受一個網絡層的輸出,然后預測該網絡層的梯度。

邊注:Geoffrey Hinton的相關工作

事實上這讓我回想起幾年前Geoffrey Hinton的工作,隨機合成權重支持的深度學習網絡(arXiv:1411.0247)。基本上,你可以通過隨機生成矩陣進行反向傳播,仍然能夠完成學習。此外,他展示了這具有某種正則化效應。這肯定是一項有趣的工作。

好,回到合成梯度。論文同時提到其他相關信息可以用作合成梯度生成網絡的輸入,不過論文本身看起來在普通前饋網絡上只使用了網絡層的輸出作為生成器的輸入。此外,論文甚至聲稱單線性層可以用作合成梯度生成器。令人驚奇!我們將嘗試一下這個。

網絡如何學習生成梯度?

這提出了一個問題,生成合成梯度的網絡如何學習?當我們進行完整的前向傳播和反向傳播時,我們實際得到了“正確”的梯度。我們可以將其與“合成”梯度進行比較,就像我們通常比較神經網絡輸出和數據集一樣。因此,我們可以假裝“真梯度”來自某個神秘的數據集,以此訓練合成梯度網絡……所以我們像訓練平常的網絡一樣訓練。酷!

等一下……如果合成梯度網絡需要反向傳播……這還有什么意義?

很好的問題!這一技術的全部價值在于允許獨立訓練網絡層,無需等待所有網絡層完成前向傳播和反向傳播。如果合成梯度網絡需要等待完整的前向/反向傳播步驟,我們豈不是又回到了原點,而且需要進行的計算更多了(比原先還糟)。為了找到答案,讓我們重新看下論文中對網絡架構的可視化。

讓我們聚焦左邊的第二塊區域??吹搅藳]有?梯度(Mi+2)經fi+1反向傳播至Mi+2。如你所見,每個合成梯度生成器實際上僅僅使用下一層生成的合成梯度進行訓練。因此,只有最后一層實際在數據上訓練。其他層,包括合成梯度生成網絡,基于合成梯度訓練。因此,訓練每層的合成梯度生成網絡時,只需等待下一層的合成梯度(沒有其他依賴)。太酷了!

四、基線神經網絡

到了寫代碼的時間了!我將首先實現一個通過反向傳播進行訓練的原味神經網絡,風格與基于Numpy實現神經網絡:反向傳播中的類似。(所以,如果你有不明白的地方,可以先去閱讀我之前寫的文章,然后再回過頭來閱讀本文)。然而,我將額外增加一層,不過這不會造成理解問題。我只是覺得,既然我們在討論減少依賴,更多的網絡層可能有助于形成更好的解釋。

至于我們訓練的數據集,我們將使用二進制加法生成一個合成數據集(哈哈?。K?,網絡將接受兩個隨機的二進制數作為輸入,并預測兩者之和(也是一個二進制數)。這使我們可以方便地根據需要增加維度(大致相當于難度)。下面是生成數據集的代碼。

import numpy as np

import sys

def generate_dataset(output_dim = 8,num_examples=1000):

def int2vec(x,dim=output_dim):

out = np.zeros(dim)

binrep = np.array(list(np.binary_repr(x))).astype('int')

out[-len(binrep):] = binrep

return out

x_left_int = (np.random.rand(num_examples) * 2**(output_dim - 1)).astype('int')

x_right_int = (np.random.rand(num_examples) * 2**(output_dim - 1)).astype('int')

y_int = x_left_int + x_right_int

x = list()

for i in range(len(x_left_int)):

x.append(np.concatenate((int2vec(x_left_int[i]),int2vec(x_right_int[i]))))

y = list()

for i in range(len(y_int)):

y.append(int2vec(y_int[i]))

x = np.array(x)

y = np.array(y)

return (x,y)

num_examples = 1000

output_dim = 12

iterations = 1000

x,y = generate_dataset(num_examples=num_examples, output_dim = output_dim)

print("Input: two concatenated binary values:")

print(x[0])

print("\nOutput: binary value of their sum:")

print(y[0])

下面則是相應的神經網絡代碼:

batch_size = 10

alpha = 0.1

input_dim = len(x[0])

layer_1_dim = 128

layer_2_dim = 64

output_dim = len(y[0])

weights_0_1 = (np.random.randn(input_dim,layer_1_dim) * 0.2) - 0.1

weights_1_2 = (np.random.randn(layer_1_dim,layer_2_dim) * 0.2) - 0.1

weights_2_3 = (np.random.randn(layer_2_dim,output_dim) * 0.2) - 0.1

for iter in range(iterations):

error = 0

for batch_i in range(int(len(x) / batch_size)):

batch_x = x[(batch_i * batch_size):(batch_i+1)*batch_size]

batch_y = y[(batch_i * batch_size):(batch_i+1)*batch_size]

layer_0 = batch_x

layer_1 = sigmoid(layer_0.dot(weights_0_1))

layer_2 = sigmoid(layer_1.dot(weights_1_2))

layer_3 = sigmoid(layer_2.dot(weights_2_3))

layer_3_delta = (layer_3 - batch_y) * layer_3 * (1 - layer_3)

layer_2_delta = layer_3_delta.dot(weights_2_3.T) * layer_2 * (1 - layer_2)

layer_1_delta = layer_2_delta.dot(weights_1_2.T) * layer_1 * (1 - layer_1)

weights_0_1 -= layer_0.T.dot(layer_1_delta) * alpha

weights_1_2 -= layer_1.T.dot(layer_2_delta) * alpha

weights_2_3 -= layer_2.T.dot(layer_3_delta) * alpha

error += (np.sum(np.abs(layer_3_delta)))

sys.stdout.write("\rIter:" + str(iter) + " Loss:" + str(error))

if(iter % 100 == 99):

print("")

現在,我真心覺得有必要做些我幾乎從不在學習時做的事,加上一點面向對象結構。通常,這會略微混淆網絡,更難看清代碼做了什么。然而,由于本文的主題是“解耦網絡接口”(Decoupled Neural Interfaces)及其優勢,如果不解耦這些接口的話,解釋起來會相當困難。因此,我將把上面的網絡轉換為一個Layer類,之后將進一步轉換為一個DNI(解耦網絡接口)。

classLayer(object):

def __init__(self,input_dim, output_dim,nonlin,nonlin_deriv):

self.weights = (np.random.randn(input_dim, output_dim) * 0.2) - 0.1

self.nonlin = nonlin

self.nonlin_deriv = nonlin_deriv

def forward(self,input):

self.input = input

self.output = self.nonlin(self.input.dot(self.weights))

return self.output

def backward(self,output_delta):

self.weight_output_delta = output_delta * self.nonlin_deriv(self.output)

return self.weight_output_delta.dot(self.weights.T)

def update(self,alpha=0.1):

self.weights -= self.input.T.dot(self.weight_output_delta) * alpha

在這個Layer類中,我們有一些變量。weights是我們從輸入到輸出進行線性變換的矩陣(就像平常的線性層)。我們同時引入了一個輸出nonlin函數,給我們的網絡輸出加上了非線性。如果我們不想要非線性,我們可以直接將其值設為lambda x:x。在我們的情形中,我們將傳入sigmoid函數。

我們傳入的第二個函數是nonlin_deriv,這是一個導數。該函數將接受我們的非線性輸出,并將其轉換為導數。就sigmoid而言,它的值為(out * (1 - out)),其中out為sigmoid的輸出。

現在,讓我們看下類中的幾個方法。forward,顧名思義,前向傳播,首先通過一個線性轉換,接著通過一個非線性函數。backward接受一個output_delta參數,該參數表示從下一層經反向傳播返回的真實梯度(非合成梯度)。我們接著使用這個參數來計算self.weight_output_delta,也就是權重輸出的導數。最后,反向傳播發送給前一層的誤差,并返回誤差。

update也許是其中最簡單的函數。它直接接受權重輸出的導數,并使用它更新權重。如果有任何步驟不明白,請再次參考基于Numpy實現神經網絡:反向傳播。

接著,讓我們看看layer對象是如何用于訓練的。

layer_1 = Layer(input_dim,layer_1_dim,sigmoid,sigmoid_out2deriv)

layer_2 = Layer(layer_1_dim,layer_2_dim,sigmoid,sigmoid_out2deriv)

layer_3 = Layer(layer_2_dim, output_dim,sigmoid, sigmoid_out2deriv)

for iter in range(iterations):

error = 0

for batch_i in range(int(len(x) / batch_size)):

batch_x = x[(batch_i * batch_size):(batch_i+1)*batch_size]

batch_y = y[(batch_i * batch_size):(batch_i+1)*batch_size]

layer_1_out = layer_1.forward(batch_x)

layer_2_out = layer_2.forward(layer_1_out)

layer_3_out = layer_3.forward(layer_2_out)

layer_3_delta = layer_3_out - batch_y

layer_2_delta = layer_3.backward(layer_3_delta)

layer_1_delta = layer_2.backward(layer_2_delta)

layer_1.backward(layer_1_delta)

layer_1.update()

layer_2.update()

layer_3.update()

如果你將上面的代碼和之前的腳本對比,基本上所有事情發生在基本相同的地方。我只是用方法調用替換了腳本中的相應操作。

所以,我們實際上做的是從之前的腳本中提取步驟,將其切分為類中不同的函數。

如果你搞不明白這個新版本的網絡,不要繼續下去。確保你在繼續閱讀下文之前習慣這種抽象的方式,因為下面會變得更復雜。

五、基于層輸出的合成梯度

現在,我們將基于了解的合成梯度的知識改寫Layer類,將其重新命名為DNI。

class DNI(object):

def __init__(self,input_dim, output_dim,nonlin,nonlin_deriv,alpha = 0.1):

# 和之前一樣

self.weights = (np.random.randn(input_dim, output_dim) * 0.2) - 0.1

self.nonlin = nonlin

self.nonlin_deriv = nonlin_deriv

# 新東西

self.weights_synthetic_grads = (np.random.randn(output_dim,output_dim) * 0.2) - 0.1

self.alpha = alpha

# 之前僅僅是`forward`,現在我們在前向傳播中基于合成梯度更新權重

def forward_and_synthetic_update(self,input):

# 緩存輸入

self.input = input

# 前向傳播

self.output = self.nonlin(self.input.dot(self.weights))

# 基于簡單的線性變換生成合成梯度

self.synthetic_gradient = self.output.dot(self.weights_synthetic_grads)

# 使用合成梯度更新權重

self.weight_synthetic_gradient = self.synthetic_gradient * self.nonlin_deriv(self.output)

self.weights += self.input.T.dot(self.weight_synthetic_gradient) * self.alpha

# 返回反向傳播的合成梯度(這類似Layer類的backprop方法的輸出)

# 同時返回前向傳播的輸出(我知道這有點怪……)

return self.weight_synthetic_gradient.dot(self.weights.T), self.output

# 和之前的`update`方法類似……除了基于合成權重之外

def update_synthetic_weights(self,true_gradient):

self.synthetic_gradient_delta = self.synthetic_gradient - true_gradient

self.weights_synthetic_grads += self.output.T.dot(self.synthetic_gradient_delta) * self.alpha

我們有了一些新的變量。唯一關鍵的是self.weights_synthetic_grads,這是我們的合成梯度生成器神經網絡(只是一個線性層……也就是……一個矩陣)。

前向傳播和合成更新:forward方法變為forward_and_synthetic_update。還記得我們不需要網絡的其他部分來更新權重嗎?這就是魔法發生之處。首先,照常進行前向傳播。接著,我們通過將輸出傳給一個非線性生成合成梯度。這一部分本可以是一個更復雜的神經網絡,不過我們沒有這么做,而是決定保持簡單性,直接使用一個簡單的線性層生成我們的合成梯度。得到我們的梯度之后,我們繼續更新權重。最后,我們反向傳播合成梯度,以便發送給之前的層。

更新合成梯度:下一層的update_synthetic_gradient方法將接受上一層的forward_and_synthetic_update方法返回的梯度。所以,如果我們位于第二層,那么第三層的forward_and_synthetic_update方法返回的梯度將作為第二層的update_synthetic_weights的輸入。接著,我們直接更新合成權重,就像在普通的神經網絡中做的那樣。這和通常的神經網絡的學習沒什么兩樣,只不過我們使用了一些特別的輸入和輸出而已。

基于合成梯度方法訓練網絡,我發現它不像我預料的那樣收斂。我的意思是,它在收斂,但是收斂得非常慢。我仔細調查了一下,發現隱藏的表示(也就是梯度生成器的輸入)在開始時比較扁平和隨機。換句話說,兩個不同的訓練樣本在不同網絡層結果會有幾乎一樣的輸出表示。這大大增加了梯度生成器工作的難度。在論文中,作者使用的解決方案是批歸一化,批歸一化將所有網絡層輸出縮放至0均值和單位方差。此外,論文還提到你可以使用其他形式的梯度生成器輸入。對于我們的簡單玩具神經網絡而言,批歸一化會加入大量復雜度。因此,我嘗試了使用輸出數據集。這并沒有破壞解耦狀態(秉持了DNI的精神),但在開始階段給網絡提供了非常強力的信息。

進行了這一改動后,訓練起來快多了!思考哪些可以充當梯度生成器的優良輸入真是一項迷人的活動。也許輸入數據、輸出數據、批歸一化層輸出的某種組合會是最佳的(歡迎嘗試!)希望你喜歡這篇教程

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

    關注

    42

    文章

    4771

    瀏覽量

    100766
  • 生成器
    +關注

    關注

    7

    文章

    315

    瀏覽量

    21011

原文標題:基于Numpy實現神經網絡:合成梯度

文章出處:【微信號:jqr_AI,微信公眾號:論智】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    什么是NumPy?選擇NUMPY的原因及其工作原理是什么

    NumPy 是一個免費的 Python 編程語言開源庫,它功能強大、已經過充分優化,并增加了對大型多維數組(也稱為矩陣或張量)的支持。
    的頭像 發表于 07-15 09:37 ?4044次閱讀

    如何更新權重實現梯度下降

    實現梯度下降
    發表于 07-15 10:09

    Numpy的學習總結

    Numpy學習筆記
    發表于 07-16 08:27

    機器學習:隨機梯度下降和批量梯度下降算法介紹

    梯度下降和批量梯度下降是兩種迭代求解思路,下面從公式和實現的角度對兩者進行分析。下面的h(x)是要擬合的函數,J(theta)損失函數,theta是參數,要迭代求解的,theta求解出來了那最終要擬合的函數h(theta)就出來
    發表于 11-28 04:00 ?8908次閱讀
    機器學習:隨機<b class='flag-5'>梯度</b>下降和批量<b class='flag-5'>梯度</b>下降算法介紹

    基于python的numpy深度解析

    numpy(Numerical Python)提供了python對多維數組對象的支持:ndarray,具有矢量運算能力,快速、節省空間。numpy支持高級大量的維度數組與矩陣運算,此外也針對數組運算提供大量的數學函數庫。
    的頭像 發表于 01-24 13:55 ?5262次閱讀
    基于python的<b class='flag-5'>numpy</b>深度解析

    基于Numpy實現同態加密神經網絡

    在分布式AI環境下,同態加密神經網絡有助于保護商業公司知識產權和消費者隱私。本文介紹了如何基于Numpy實現同態加密神經網絡。
    的頭像 發表于 03-27 14:52 ?7959次閱讀
    基于<b class='flag-5'>Numpy</b><b class='flag-5'>實現</b>同態加密神經網絡

    基于Numpy實現神經網絡:反向傳播

    和DeepMind數據科學家、Udacity深度學習導師Andrew Trask一起,基于Numpy手寫神經網絡,更深刻地理解反向傳播這一概念。
    的頭像 發表于 04-01 09:29 ?5152次閱讀
    基于<b class='flag-5'>Numpy</b><b class='flag-5'>實現</b>神經網絡:反向傳播

    如何使用Python和Numpy等技術實現圖像處理

    本文檔的主要內容詳細介紹的是如何使用Python、Numpy、Scipy和matplotlib執行圖像處理任務。
    發表于 08-28 09:36 ?8次下載
    如何使用Python和<b class='flag-5'>Numpy</b>等技術<b class='flag-5'>實現</b>圖像處理

    最詳細的 NumPy 圖解教程!

    NumPy是Python中用于數據分析、機器學習、科學計算的重要軟件包。它極大地簡化了向量和矩陣的操作及處理。python的不少數據處理軟件包依賴于NumPy作為其基礎架構的核心部分(例如
    的頭像 發表于 06-09 18:03 ?2480次閱讀
    最詳細的 <b class='flag-5'>NumPy</b> 圖解教程!

    Numpy詳解-軸的概念

    NumPy數組的維數稱為秩(rank),一維數組的秩為1,二維數組的秩為2,以此類推。在NumPy中,每一個線性的數組稱為是一個軸(axes),秩其實是描述軸的數量。
    的頭像 發表于 04-25 10:25 ?2927次閱讀

    Numpy數組的高級操作總結

    NumPy 包含一個迭代器對象numpy.nditer。它是一個有效的多維迭代器對象,可以用于在數組上進行迭代。數組的每個元素可使用 Python 的標準Iterator接口來訪問。
    的頭像 發表于 05-13 12:53 ?1353次閱讀

    使用Numpy和OpenCV實現傅里葉和逆傅里葉變換

      文章從實際出發,講述了什么是傅里葉變換,它的理論基礎以及Numpy和OpenCV實現傅里葉和逆傅里葉變換,并最終用高通濾波和低通濾波的示例。
    的頭像 發表于 07-05 16:04 ?1607次閱讀

    Python 梯度計算模塊如何實現一個邏輯回歸模型

    AutoGrad 是一個老少皆宜的 Python 梯度計算模塊。 對于初高中生而言,它可以用來輕易計算一條曲線在任意一個點上的斜率。 對于大學生、機器學習愛好者而言,你只需要傳遞給它Numpy這樣
    的頭像 發表于 10-21 11:01 ?501次閱讀
    Python <b class='flag-5'>梯度</b>計算模塊如何<b class='flag-5'>實現</b>一個邏輯回歸模型

    List和Numpy Array有什么區別

    Numpy 是Python科學計算的一個核心模塊。它提供了非常高效的數組對象,以及用于處理這些數組對象的工具。一個Numpy數組由許多值組成,所有值的類型是相同的。 Python的核心庫提供了
    的頭像 發表于 10-30 10:49 ?887次閱讀
    List和<b class='flag-5'>Numpy</b> Array有什么區別

    基于NumPy的機器學習算法實現

    David Bourgin 表示他一直在慢慢寫或收集不同模型與模塊的純 NumPy 實現,它們跑起來可能沒那么快,但是模型的具體過程一定足夠直觀。每當我們想了解模型 API 背后的實現,卻又不想看復雜的框架代碼,那么它可以作為快
    發表于 01-17 12:36 ?202次閱讀
    基于<b class='flag-5'>NumPy</b>的機器學習算法<b class='flag-5'>實現</b>
    主站蜘蛛池模板: 免费观看欧美成人1314色| 2019天天干天天操| 激情四月婷婷| 国模吧在线视频| 伊人91在线| 天天操天天射天天插| 亚洲综合在线观看一区www| 色天使色婷婷在线影院亚洲| 日本黄色免费大片| 国产一级aa大片毛片| 天天综合天天色| 亚洲性视频网站| 欧美一区二区精品| 三a大片| 奇米影视四色首页手机在线| 亚洲狠狠狠一区二区三区| 日韩怡红院| 天天干天天草| 99热.com| 高清激情小视频在线观看| 视频免费观看视频| 日韩精品系列产品| 天天操网| 亚洲影视大全| 欧美日a| 男人天堂资源网| 一级在线免费视频| 免费级毛片| 天天色天天操天天射| 精品一区二区国语对白| 天天摸天天碰中文字幕| 伊人天天操| 嘿嘿嘿视频在线观看网站| 韩国免费特一级毛片| 欧美yw193.c㎝在线观看| 日本视频黄色| 国产又爽又黄又粗又大| 禁漫画羞羞动漫入口| 给我免费播放片黄色| 22sihu国产精品视频影视资讯| 午夜骚|