當前位置:
首頁 > 新聞 > 用深度學習每次得到的結果都不一樣,怎麼辦?

用深度學習每次得到的結果都不一樣,怎麼辦?

用深度學習每次得到的結果都不一樣,怎麼辦?

雷鋒網按:本文作者 Jason Brownlee 為澳大利亞知名機器學習專家、教育者,對時間序列預測尤有心得。原文發佈於其博客。雷鋒網崔靜闖、朱婷編譯。

神經網路演算法利用了隨機性,比如初始化隨機權重,因此用同樣的數據訓練同一個網路會得到不同的結果。

初學者可能會有些懵圈,因為演算法表現得不太穩定。但實際上它們就是這麼設計的。隨機初始化可以讓網路通過學習,得到一個所學函數的很好的近似。

然而, 有時候用同樣的數據訓練同一個網路,你需要每次都得到完全相同的結果。例如在教學和產品上。

在這個教程中,你會學到怎樣設置隨機數生成器,才能每次用同樣的數據訓練同一網路時,都能得到同樣的結果。

我們開始。

教程概覽

這個教程分為六部分:


  1. 為啥我每次得到的結果都不一樣?

  2. 不同結果的演示

  3. 解決方法

  4. 用Theano 後端設置隨機數種子

  5. 用TensorFlow 後端設置隨機數種子

  6. 得到的結果還是不同,咋辦?

運行環境

  • 該教程需要你安裝了Python SciPy。你能用Python2或3來演示這個例子

  • 需要你安裝Keras (v2.0.3+),後台為TensorFlow (v1.1.0+)或Theano (v0.9+)

  • 還需要你安裝了scikit-learn,Pandas,NumPy以及Matplotlib

如果在Python環境的設置方面需要幫助,請看下面這個帖子:

How to Setup a Python Environment for Machine Learning and Deep Learning with Anaconda

為啥我每次得到的結果都不一樣?

我發現這對神經網路和深度學習的初學者而言是個常見問題。

這種誤解可能出於以下問題:

  • 我如何得到穩定的結果?

  • 我如何得到可重複的結果

  • 我應該如何設置種子點

神經網路特意用隨機性來保證,能通過有效學習得到問題的近似函數。採用隨機性的原因是:用它的機器學習演算法,要比不用它的效果更好。

在神經網路中,最常見的利用隨機性的方式是網路權值的隨機初始化,儘管在其他地方也能利用隨機性,這有一個簡短的清單:

  • 初始化的隨機性,比如權值

  • 正則化的隨機性,比如dropout

  • 層的隨機性,比如詞嵌入

  • 最優化的隨機性,比如隨機優化

這些甚至更多的隨機性來源意味著,當你對同一數據運行同一個神經網路演算法時,註定得到不同的結果。

想了解更多關於隨機演算法的原委,參考下面的帖子

Embrace Randomness in Machine Learning

不同結果的演示

我們可以用一個小例子來演示神經網路的隨機性.

在這一節中,我們會建立一個多層感知器模型來學習一個以0.1為間隔的從0.0到0.9的短序列。給出0.0,模型必須預測出0.1;給出0.1,模型必須預測出0.2;以此類推。

下面是準備數據的代碼


# create sequence

length = 10

sequence = [i/float(length) for i in range(length)]

# create X/y pairs

df = DataFrame(sequence)

df = concat([df.shift(1), df], axis=1)

df.dropna(inplace=True)

# convert to MLPfriendly format

values = df.values

X, y = values[:,0], values[:,1]

我們要用的網路,有1個輸入,10個隱層節點和1個輸出。這個網路將採用均方差作為損失函數,用高效的ADAM演算法來訓練數據

這個網路需要約1000輪才能有效的解決這個問題,但我們只對它訓練100輪。這樣是為了確保我們在預測時能得到一個有誤差的模型。


網路訓練完之後,我們要對數據集進行預測並且輸出均方差

建立網路的代碼如下

# design network

model = Sequential

model.add(Dense(10, input_dim=1))

model.add(Dense(1))

model.compile(loss="mean_squared_error", optimizer="adam")

# fit network

model.fit(X, y, epochs=100, batch_size=len(X), verbose=0)

# forecast

yhat = model.predict(X, verbose=0)

print(mean_squared_error(y, yhat[:,0]))

在這個例子中,我們要建立10次網路並且輸出10個不同的網路得分

完整的代碼如下


from pandas import DataFrame

from pandas import concat

from keras.models import Sequential

from keras.layers import Dense

from sklearn.metrics import mean_squared_error

# fit MLP to dataset and print error

def fit_model(X, y):

# design network

model = Sequential

model.add(Dense(10, input_dim=1))

model.add(Dense(1))

model.compile(loss="mean_squared_error", optimizer="adam")

# fit network

model.fit(X, y, epochs=100, batch_size=len(X), verbose=0)

# forecast

yhat = model.predict(X, verbose=0)

print(mean_squared_error(y, yhat[:,0]))

# create sequence

length = 10

sequence = [i/float(length) for i in range(length)]

# create X/y pairs

df = DataFrame(sequence)

df = concat([df.shift(1), df], axis=1)

df.dropna(inplace=True)

# convert to MLP friendly format

values = df.values

X, y = values[:,0], values[:,1]

# repeat experiment

repeats = 10

for _ in range(repeats):

fit_model(X, y)

運行這個例子會在每一行輸出一個不同的精確值,具體結果也都不同。

下面是一個輸出的示例


0.0282584265697

0.0457025913022

0.145698137198

0.0873461454407

0.0309397604521

0.046649185173

0.0958450337178

0.0130660263779

0.00625176026631

0.00296055161492

解決方案

下面是兩個主要的解決方案。

解決方案#1:重複實驗

解決這個問題傳統且切實可行的方法是多次運行網路(30+),然後運用統計學方法概括模型的性能,並與其他模型作比較。

我強烈推薦這種方法,但是由於有些模型的訓練時間太長,這種方法並不總是可行的。

解決方案#2:設置隨機數字生成器的種子

另一種解決方案是為隨機數字生成器使用固定的種子。

隨機數由偽隨機數生成器生成。一個隨機生成器就是一個數學函數,該函數將生成一長串數字,這些數字對於一般目的的應用足夠隨機。

隨機生成器需要一個種子點開啟該進程,在大多數實現中,通常默認使用以毫秒為單位的當前時間。這是為了確保,默認情況下每次運行代碼都會生成不同的隨機數字序列。該種子點可以是指定數字,比如「1」,來保證每次代碼運行時生成相同的隨機數序列。只要運行代碼時指定的種子的值不變,它是什麼並不重要。

設置隨機數生成器的具體方法取決於後端,我們將探究下在Theano和TensorFlow後端下怎樣做到這點。

用Theano後端設置隨機數種子

通常,Keras從NumPy隨機數生成器中獲得隨機源。

大部分情況下,Theano後端也是這樣。

我們可以通過從random模塊中調用seed函數的方式,設置NumPy隨機數生成器的種子,如下面所示:


from numpy.random import seedseed(1)

最好在代碼文件的頂部導入和調用seed函數。

這是最佳的實現方式(best practice),這是因為當各種各樣的Keras或者Theano(或者其他的)庫作為初始化的一部分被導入時,甚至在直接使用他們之前,可能會用到一些隨機性。

我們可以在上面示例的頂端再加兩行,並運行兩次。

每次運行代碼時,可以看到相同的均方差值的列表(在不同的機器上可能會有一些微小變化,這取決於機器的精度),如下面的示例所示:


0.169326527063

2.75750621228e-05

0.0183287291562

1.93553737255e-07

0.0549871087449

0.0906326807824

0.00337575114075

0.00414857518259

8.14587362008e-08

0.0522927019639

你的結果應該跟我的差不多(忽略微小的精度差異)。

用TensorFlow後端設置隨機數種子

Keras從NumPy隨機生成器中獲得隨機源,所以不管使用Theano或者TensorFlow後端的哪一個,都必須設置種子點。

必須在其他模塊的導入或者其他代碼之前,文件的頂端部分通過調用seed函數設置種子點。


from numpy.random import seedseed(1)

另外,TensorFlow有自己的隨機數生成器,該生成器也必須在NumPy隨機數生成器之後通過立馬調用 set_random_seed 函數設置種子點。


from tensorflow import set_random_seedset_random_seed(2)

要明確的是,在代碼文件的頂端,在其他之前,一定要有以下4行:


from numpy.random import seed

seed(1)

from tensorflow import set_random_seed

set_random_seed(2)

你可以使用兩個相同或者不同的種子。我認為這不會造成多大差別,因為隨機源進入了不同的進程。

在以上示例中增加這4行,可以使代碼每次運行時都產生相同的結果。你應該看到與下面列出的相同的均方差值(也許有一些微小差別,這取決於不同機器的精度):


0.224045112999

0.00154879478823

0.00387589994044

0.0292376881968

0.00945528404353

0.013305765525

0.0206255228201

0.0359538356108

0.00441943512128

0.298706569397

你的結果應該與我的差不多(忽略精度的微小差異)。

如果我仍然得到不同的結果,怎麼辦?

為了重複迭代,報告結果和比較模型魯棒性最好的做法是多次(30+)重複實驗,並使用匯總統計。如果這是不可行的,你可以通過為代碼使用的隨機數發生器設置種子來獲得100%可重複的結果。

如果你已經按照上面的說明去做,仍然用相同的數據從相同的演算法中獲得了不同的結果,怎麼辦?

這可能是有其他的隨機源你還沒有考慮到。

來自第三方庫的隨機性

也許你的代碼使用了另外的庫,該庫使用不同的也必須設置種子的隨機數生成器。

試著將你的代碼簡化到最低要求(例如,一個數據樣本,一輪訓練等等),並仔細閱讀API文檔,儘力減少可能引入隨機性的第三方庫。

使用GPU產生的隨機性

以上所有示例都假設代碼是在一個CPU上運行的。

這種情況也是有可能的,就是當使用GPU訓練模型時,可能後端設置的是使用一套複雜的GPU庫,這些庫中有些可能會引入他們自己的隨機源,你可能會或者不會考慮到這個。

例如,有證據顯示如果你在堆棧中使用了 Nvidia cuDNN,這可能引入額外的隨機源( introduce additional sources of randomness),並且使結果不能準確再現。

來自複雜模型的隨機性

由於模型的複雜性和訓練的並行性,你可能會得到不可復現的結果。

這很可能是由後端庫的效率造成的,或者是不能在內核中使用隨機數序列。我自己沒有遇到過這個,但是在一些GitHub問題和StackOverflowde問題中看到了一些案例。

如果只是縮小成因的範圍的話,你可以嘗試降低模型的複雜度,看這樣是否影響結果的再現。

我建議您閱讀一下你的後端是怎麼使用隨機性的,並看一下是否有任何選項向你開放。在Theano中,參考:

  • Random Numbers

  • Friendly random numbers

  • Using Random Numbers

在TensorFlow中,參考:

Constants, Sequences, and Random Values

tf.set_random_seed

另外,為了更深入地了解,考慮一下尋找擁有同樣問題的其他人。一些很好的搜尋平台包括GitHub、StackOverflow 和 CrossValidated。

總 結

在本教程中,你了解了如何在Keras上得到神經網路模型的可重複結果。特別是,你學習到了:

  • 神經網路是有意設計成隨機的,固定隨機源可以使結果可復現。

  • 你可以為NumPy和TensorFlow的隨機數生成器設置種子點,這將使大多數的Keras代碼100%的可重複使用。

  • 在有些情況下存在另外的隨機源,並且你知道如何找出他們,或許也是固定它們。

via machine learning mastery,雷鋒網崔靜闖、朱婷編譯

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 雷鋒網 的精彩文章:

支付寶又出「黑科技」,停車場不停車通過
美國海豹突擊隊前隊員駕駛特斯拉車毀人亡,事故調查原因出爐
哈爾濱搖號系統遭黑客攻擊癱瘓,「搖不著號」這回不是幻覺!
微信封殺偽 ofo 小程序;工信部整治假寬頻;共享電動滑板車要來了?

TAG:雷鋒網 |

您可能感興趣

一生只開一次花,只接一次果的香蕉,有錢也不一定買得到,你見過嗎?
他和刑天一樣,都曾斷過頭而不死,為何得到人們不一樣的評價呢
心肌梗塞不用怕!用這個常見的綠色植物,你會得到意想不到的結果!
如果你得到的不是你想要的,該怎麼辦?
領導最討厭這五種下屬,再努力也不會得到提拔,有你嗎?
幾十年也挖不出來這樣的一個極品,有錢不一定買得到!
想要得到對方,你就得不到一段真正好的關係
一些得到,不一定長久,一些失去,未必不再擁有
輕易得到了就不會去珍惜,得不到才是一種境界
都是偷東西,但原因不同,得到的評價也不一樣
怎麼讓三角肌中束得到灼燒?3個動作,讓你得到意想不到的效果
想要得到對方的深愛,就一定不能做這四件事!
不強求,不妄取,一切隨緣,想要的沒得到,是緣分未到
不要再亂喝茶了。。長期喝茶後得到這樣的後果,真沒想到。
女子只因瞧不起那些比自己差的人 沒想到就「得到」這樣的結局
這個世界就這麼不完美。你想得到些什麼就不得不失去些什麼
看到不遠處有條魚,扔魚餌到它面前都不動,直接抓就得到了,都不用釣
成熟是一個很痛的詞,它不一定會得到什麼,卻一定會失去些什麼
無論生活還是感情,只要我們努力了,珍惜了,就算不曾得到也不後悔
不要再亂喝茶了……長期喝茶後得到這樣的後果,真沒想到