天天看點

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

神經網絡算法利用了随機性,比如初始化随機權重,是以用同樣的資料訓練同一個網絡會得到不同的結果。

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

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

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

我們開始。

這個教程分為六部分:

為啥我每次得到的結果都不一樣? 不同結果的示範 解決方法 用theano 後端設定随機數種子 用tensorflow 後端設定随機數種子 得到的結果還是不同,咋辦?

該教程需要你安裝了python scipy。你能用python2或3來示範這個例子

需要你安裝keras (v2.0.3+),背景為tensorflow (v1.1.0+)或theano (v0.9+)

還需要你安裝了scikit-learn,pandas,numpy以及matplotlib

如果在python環境的設定方面需要幫助,請看下面這個文章:

<a href="http://machinelearningmastery.com/setup-python-environment-machine-learning-deep-learning-anaconda/" target="_blank">how to setup a python environment for machine learning and deep learning with anaconda</a>

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

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

我如何得到穩定的結果?

我如何得到可重複的結果

我應該如何設定種子點

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

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

初始化的随機性,比如權值

正則化的随機性,比如dropout

層的随機性,比如詞嵌入

最優化的随機性,比如随機優化

這些甚至更多的随機性來源意味着,當你對同一資料運作同一個神經網絡算法時,注定得到不同的結果。

想了解更多關于随機算法的原委,參考下面的文章

<a href="http://machinelearningmastery.com/randomness-in-machine-learning/" target="_blank">embrace randomness in machine learning</a>

我們可以用一個小例子來示範神經網絡的随機性.

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

下面是準備資料的代碼

我們要用的網絡,有1個輸入,10個隐層節點和1個輸出。這個網絡将采用均方差作為損失函數,用高效的adam算法來訓練資料

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

網絡訓練完之後,我們要對資料集進行預測并且輸出均方差 建立網絡的代碼如下

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

完整的代碼如下

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

下面是一個輸出的示例

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

解決方案#1:重複實驗

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

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

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

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

随機數由僞随機數生成器生成。一個随機生成器就是一個數學函數,該函數将生成一長串數字,這些數字對于一般目的的應用足夠随機。

随機生成器需要一個種子點開啟該程序,在大多數實作中,通常預設使用以毫秒為機關的目前時間。這是為了確定,預設情況下每次運作代碼都會生成不同的随機數字序列。該種子點可以是指定數字,比如“1”,來保證每次代碼運作時生成相同的随機數序列。隻要運作代碼時指定的種子的值不變,它是什麼并不重要。

設定随機數生成器的具體方法取決于後端,我們将探究下在theano和tensorflow後端下怎樣做到這點。

通常,keras從numpy随機數生成器中獲得随機源。

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

我們可以通過從random子產品中調用seed()函數的方式,設定numpy随機數生成器的種子,如下面所示:

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

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

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

每次運作代碼時,可以看到相同的均方內插補點的清單(在不同的機器上可能會有一些微小變化,這取決于機器的精度),如下面的示例所示:

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

keras從numpy随機生成器中獲得随機源,是以不管使用theano或者tensorflow後端的哪一個,都必須設定種子點。

必須在其他子產品的導入或者其他代碼之前,檔案的頂端部分通過調用seed()函數設定種子點。

另外,tensorflow有自己的随機數生成器,該生成器也必須在numpy随機數生成器之後通過立馬調用 set_random_seed() 函數設定種子點。

要明确的是,在代碼檔案的頂端,在其他之前,一定要有以下4行:

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

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

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

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

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

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

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

試着将你的代碼簡化到最低要求(例如,一個資料樣本,一輪訓練等等),并仔細閱讀api文檔,盡力減少可能引入随機性的第三方庫。

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

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

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

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

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

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

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

<a href="http://deeplearning.net/software/theano/sandbox/randomnumbers.html" target="_blank">random numbers</a>

<a href="http://deeplearning.net/software/theano/library/tensor/shared_randomstreams.html" target="_blank">friendly random numbers</a>

<a href="http://deeplearning.net/software/theano/tutorial/examples.html#using-random-numbers" target="_blank">using random numbers</a>

在tensorflow中,參考:

<a href="https://www.tensorflow.org/api_guides/python/constant_op" target="_blank">constants, sequences, and random values</a>

<a href="http://tf.set_random_seed/" target="_blank">tf.set_random_seed</a>

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

總 結

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

神經網絡是有意設計成随機的,固定随機源可以使結果可複現。

你可以為numpy和tensorflow的随機數生成器設定種子點,這将使大多數的keras代碼100%的可重複使用。

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

====================================分割線================================

本文作者:崔靜闖