實戰(zhàn)Google深度學習框架:TensorFlow計算加速
要將深度學習應用到實際問題中,一個非常大的問題在于訓練深度學習模型需要的計算量太大。比如Inception-v3模型在單機上訓練到78%的正確率需要將近半年的時間 ,這樣的訓練速度是完全無法應用到實際生產中的。為了加速訓練過程,本章將介紹如何通過TensorFlow利用GPU或/和分布式計算進行模型訓練。本文節(jié)選自《TensorFlow:實戰(zhàn)Google深度學習框架》第十章。
本文將介紹如何在TensorFlow中使用單個GPU進行計算加速,也將介紹生成TensorFlow會話(tf.Session)時的一些常用參數(shù)。通過這些參數(shù)可以使調試更加方便而且程序的可擴展性更好。然而,在很多情況下,單個GPU的加速效率無法滿足訓練大型深度學習模型的計算量需求,這時將需要利用更多的計算資源。為了同時利用多個GPU或者多臺機器,10.2節(jié)中將介紹訓練深度學習模型的并行方式。然后,10.3節(jié)將介紹如何在一臺機器的多個GPU上并行化地訓練深度學習模型。在這一節(jié)中也將給出具體的TensorFlow樣例程序來使用多GPU訓練模型,并比較并行化效率提升的比率。最后在10.4節(jié)中將介紹分布式TensorFlow,以及如何通過分布式TensorFlow訓練深度學習模型。在這一節(jié)中將給出具體的TensorFlow樣例程序來實現(xiàn)不同的分布式深度學習訓練模式。雖然TensorFlow可以支持分布式深度學習模型訓練,但是它并不提供集群創(chuàng)建、管理等功能。為了更方便地使用分布式TensorFlow,10.4節(jié)中將介紹才云科技基于Kubernetes容器云平臺搭建的分布式TensorFlow系統(tǒng)。
01
TensorFlow使用GPU
TensorFlow程序可以通過tf.device函數(shù)來指定運行每一個操作的設備,這個設備可以是本地的CPU或者GPU,也可以是某一臺遠程的服務器。但在本節(jié)中只關心本地的設備。TensorFlow會給每一個可用的設備一個名稱,tf.device函數(shù)可以通過設備的名稱來指定執(zhí)行運算的設備。比如CPU在TensorFlow中的名稱為/cpu:0。在默認情況下,即使機器有多個CPU,TensorFlow也不會區(qū)分它們,所有的CPU都使用/cpu:0作為名稱。而一臺機器上不同GPU的名稱是不同的,第n個GPU在TensorFlow中的名稱為/gpu:n。比如第一個GPU的名稱為/gpu:0,第二個GPU名稱為/gpu:1,以此類推。
TensorFlow提供了一個快捷的方式來查看運行每一個運算的設備。在生成會話時,可以通過設置log_device_placement參數(shù)來打印運行每一個運算的設備。下面的程序展示了如何使用log_device_placement這個參數(shù)。
'a'
在以上代碼中,TensorFlow程序生成會話時加入了參數(shù)log_device_placement=True,所以程序會將運行每一個操作的設備輸出到屏幕。于是除了可以看到最后的計算結果之外,還可以看到類似“add: /job:localhost/replica:0/task:0/cpu:0”這樣的輸出。這些輸出顯示了執(zhí)行每一個運算的設備。比如加法操作add是通過CPU來運行的,因為它的設備名稱中包含了/cpu:0。
在配置好GPU環(huán)境的TensorFlow中 ,如果操作沒有明確地指定運行設備,那么TensorFlow會優(yōu)先選擇GPU。比如將以上代碼在亞馬遜(Amazon Web Services, AWS)的 g2.8xlarge實例上運行時,會得到以下運行結果。
name
從上面的輸出可以看到在配置好GPU環(huán)境的TensorFlow中,TensorFlow會自動優(yōu)先將運算放置在GPU上。不過,盡管g2.8xlarge實例有4個GPU,在默認情況下,TensorFlow只會將運算優(yōu)先放到/gpu:0上。于是可以看見在上面的程序中,所有的運算都被放在了/gpu:0上。如果需要將某些運算放到不同的GPU或者CPU上,就需要通過tf.device來手工指定。下面的程序給出了一個通過tf.device手工指定運行設備的樣例。

在以上代碼中可以看到生成常量a和b的操作被加載到了CPU上,而加法操作被放到了第二個GPU“/gpu:1”上。在TensorFlow中,不是所有的操作都可以被放在GPU上,如果強行將無法放在GPU上的操作指定到GPU上,那么程序將會報錯。以下代碼給出了一個報錯的樣例。
_cpu = tf.Variable(0, name="a_
不同版本的TensorFlow對GPU的支持不一樣,如果程序中全部使用強制指定設備的方式會降低程序的可移植性。在TensorFlow的kernel 中定義了哪些操作可以跑在GPU上。比如可以在variable_ops.cc程序中找到以下定義。
REGISTER_GPU_KERNELS(type)
在這段定義中可以看到GPU只在部分數(shù)據(jù)類型上支持tf.Variable操作。如果在TensorFlow代碼庫中搜索調用這段代碼的宏TF_CALL_GPU_NUMBER_TYPES,可以發(fā)現(xiàn)在GPU上,tf.Variable操作只支持實數(shù)型(float16、float32和double)的參數(shù)。而在報錯的樣例代碼中給定的參數(shù)是整數(shù)型的,所以不支持在GPU上運行。為避免這個問題,TensorFlow在生成會話時可以指定allow_soft_placement參數(shù)。當allow_soft_placement參數(shù)設置為True時,如果運算無法由GPU執(zhí)行,那么TensorFlow會自動將它放到CPU上執(zhí)行。以下代碼給出了一個使用allow_soft_placement參數(shù)的樣例。

雖然GPU可以加速TensorFlow的計算,但一般來說不會把所有的操作全部放在GPU上。一個比較好的實踐是將計算密集型的運算放在GPU上,而把其他操作放到CPU上。GPU是機器中相對獨立的資源,將計算放入或者轉出GPU都需要額外的時間。而且GPU需要將計算時用到的數(shù)據(jù)從內存復制到GPU設備上,這也需要額外的時間。TensorFlow可以自動完成這些操作而不需要用戶特別處理,但為了提高程序運行的速度,用戶也需要盡量將相關的運算放在同一個設備上。
02
深度學習訓練并行模式
TensorFlow可以很容易地利用單個GPU加速深度學習模型的訓練過程,但要利用更多的GPU或者機器,需要了解如何并行化地訓練深度學習模型。常用的并行化深度學習模型訓練方式有兩種,同步模式和異步模式。本節(jié)中將介紹這兩種模式的工作方式及其優(yōu)劣。
為幫助讀者理解這兩種訓練模式,本節(jié)首先簡單回顧一下如何訓練深度學習模型。圖10-1展示了深度學習模型的訓練流程圖。深度學習模型的訓練是一個迭代的過程。在每一輪迭代中,前向傳播算法會根據(jù)當前參數(shù)的取值計算出在一小部分訓練數(shù)據(jù)上的預測值,然后反向傳播算法再根據(jù)損失函數(shù)計算參數(shù)的梯度并更新參數(shù)。在并行化地訓練深度學習模型時,不同設備(GPU或CPU)可以在不同訓練數(shù)據(jù)上運行這個迭代的過程,而不同并行模式的區(qū)別在于不同的參數(shù)更新方式。
圖10-2展示了異步模式的訓練流程圖。從圖10-2中可以看到,在每一輪迭代時,不同設備會讀取參數(shù)最新的取值,但因為不同設備讀取參數(shù)取值的時間不一樣,所以得到的值也有可能不一樣。根據(jù)當前參數(shù)的取值和隨機獲取的一小部分訓練數(shù)據(jù),不同設備各自運行反向傳播的過程并獨立地更新參數(shù)??梢院唵蔚卣J為異步模式就是單機模式復制了多份,每一份使用不同的訓練數(shù)據(jù)進行訓練。在異步模式下,不同設備之間是完全獨立的。

深度學習模型訓練流程圖

異步模式深度學習模型訓練流程圖
然而使用異步模式訓練的深度學習模型有可能無法達到較優(yōu)的訓練結果。圖10-3中給出了一個具體的樣例來說明異步模式的問題。其中黑色曲線展示了模型的損失函數(shù),黑色小球表示了在t0時刻參數(shù)所對應的損失函數(shù)的大小。假設兩個設備d0和d1在時間t0同時讀取了參數(shù)的取值,那么設備d0和d1計算出來的梯度都會將小黑球向左移動。假設在時間t1設備d0已經(jīng)完成了反向傳播的計算并更新了參數(shù),修改后的參數(shù)處于圖10-3中小灰球的位置。然而這時的設備d1并不知道參數(shù)已經(jīng)被更新了,所以在時間t2時,設備d1會繼續(xù)將小球向左移動,使得小球的位置達到圖10-3中小白球的地方。從圖10-3中可以看到,當參數(shù)被調整到小白球的位置時,將無法達到最優(yōu)點。

異步模式訓練深度學習模型存在的問題示意圖

同步模式深度學習模型訓練流程圖
為了避免更新不同步的問題,可以使用同步模式。在同步模式下,所有的設備同時讀取參數(shù)的取值,并且當反向傳播算法完成之后同步更新參數(shù)的取值。單個設備不會單獨對參數(shù)進行更新,而會等待所有設備都完成反向傳播之后再統(tǒng)一更新參數(shù) 。圖10-4展示了同步模式的訓練過程。從圖10-4中可以看到,在每一輪迭代時,不同設備首先統(tǒng)一讀取當前參數(shù)的取值,并隨機獲取一小部分數(shù)據(jù)。然后在不同設備上運行反向傳播過程得到在各自訓練數(shù)據(jù)上參數(shù)的梯度。注意雖然所有設備使用的參數(shù)是一致的,但是因為訓練數(shù)據(jù)不同,所以得到參數(shù)的梯度就可能不一樣。當所有設備完成反向傳播的計算之后,需要計算出不同設備上參數(shù)梯度的平均值,最后再根據(jù)平均值對參數(shù)進行更新。