目錄
- 簡介
- 構建步驟
- 實現方式
- Demo演示
一、簡介
1) 使用單台機器或者單個GPU/CPU來進行模型訓練,訓練速度會受資源的影響,因為畢竟單個的設備的計算能力和存儲能力具有一定的上限的,針對這個問題,TensorFlow支持分布式模型運算,支持多機器、多GPU、多CPU各種模型的組合運行方案的設計。(默認情況下,TensorFlow程序會將程序運行在第一個GPU上<如果有GPU,並且安裝的TensorFlow支持GPU運行>)
2)TensorFlow的分布式支持單機多GPU、單機GPU+CPU、多機GPU等結構,不過所有結構的構建方式基本類似。
3) 除了TensorFlow外,Caffe、DeepLearning4j等也支持分布式訓練,TensorFlow中的集群(Cluster)指的是一系列能夠對TensorFlow中的圖(graph)進行分布式計算的任務(task)。每個任務是同服務(server)相關聯的。TensorFlow中的服務會包含一個用於創建session的主節點和至少一個用於圖運算的工作節點。另外在TensorFlow中,一個集群可以被拆分為一個或者多個作業(job),每個作業可以包含至少一個任務。
4)cluster(集群)、job(作業)、task(任務)概念:三者可以簡單的看成是層次關系,task可以看成每台機器上的一個進程,多個task組成job;job又有:ps、worker兩種,分別用於參數服務、計算服務,組成cluster。
二、構建步驟
TensorFlow分布式集群的構建主要通過代碼實現,主要步驟如下:
①創建集群(Cluster)
- 創建一個tf.train.ClusterSpec用於對集群中的所有任務進行描述,該描述內容對於所有內容應該是相同的。
- 創建tf.train.Server並將tf.train.ClusterSpec中參數傳入構造函數,
②使用tf.device API指定運算的設備,構建計算圖,最后提交運算
備注:TensorFlow負責內部作業之間的數據傳輸
詳細見最后的實驗代碼。
三、實現方式
TensorFlow中主要包含兩個方面
第一:對不同數據大小進行計算的任務(work作業)
第二:用於不停更新共享參數的任務(ps作業)。這樣任務都可以運行不同在機器上,在TensorFlow中,主要實現方式如下:
- 圖內的拷貝(In-Graph Replication)
- 圖間的拷貝(Between-Graph Replication)
- 異步訓練(Asynchronous Training)
- 同步訓練(Synchronous Training)
3.1)在In-Graph Replication
指定整個集群由一個客戶端來構建圖,並且這個客戶端來提交圖到集群中,worker只負責處理執行任務。In-Graph模式的好處在於解耦了TensorFlow集群和訓練應用之間的關系,這樣可以提前構建好參數服務器和計算服務器,而這些角色本身不需要額外的邏輯代碼,只需要使用join等待即可,真正的訓練邏輯全部位於客戶端,具有足夠高的靈活性。
備注:在小規模數據集的情況下,經常使用。在海量數據的訓練過程中,不建議使用該方式,建議使用Between-Graph Replication模式。
3.2)在Between-Graph Replication
每個客戶端會構建一個相似的圖結構,該結構中的參數均通過ps作業進行聲明並使用tf.train.replica_device_setter方法將參數映射到不同的任務作業中。
3.3)Synchronous Training
在同步訓練中,每個graph的副本讀取相同的parameter值,並行的計算,然后將計算完的結果放到一起處理。在TensorFlow中,如果是Betweengraph replication的情況下,可以通tf.train.SyncReplicasOptimizer來處理,如果是In-graph replication情況下,直接對結果進行處理即可(比如平均).
3.4)Asynchronous Training
在異步訓練中,每個任務計算完后,就會直接使用計算出的結果更新parameter值。不同的任務之間不存在協調進度。
同步訓練需要等待最慢的一個任務執行完后,才可用更新參數;異步訓練中,可以每執行完一個任務,就更新一次參數。一般情況下,建議使用異步訓練。
四、Demo演示
server-demo.py服務器代碼:
1 import tensorflow as tf 2 # 1. 配置服務器相關信息 3 # 因為tensorflow底層代碼中,默認就是使用ps和work分別表示兩類不同的工作節點 4 # ps:變量/張量的初始化、存儲相關節點 5 # work: 變量/張量的計算/運算的相關節點 6 ps_hosts = ['127.0.0.1:33331', '127.0.0.1:33332'] 7 work_hosts = ['127.0.0.1:33333', '127.0.0.1:33334', '127.0.0.1:33335'] 8 cluster = tf.train.ClusterSpec({'ps': ps_hosts, 'work': work_hosts}) 9 # 2. 定義一些運行參數(在運行該python文件的時候就可以指定這些參數了) 10 tf.app.flags.DEFINE_string('job_name', default_value='work', docstring="One of 'ps' or 'work'") 11 tf.app.flags.DEFINE_integer('task_index', default_value=0, docstring="Index of task within the job") 12 FLAGS = tf.app.flags.FLAGS 13 # 2. 啟動服務 14 def main(_): 15 print(FLAGS.job_name) 16 server = tf.train.Server(cluster, job_name=FLAGS.job_name, task_index=FLAGS.task_index) 17 server.join() 18 if __name__ == '__main__': 19 # 底層默認會調用main方法 20 tf.app.run()
客戶端代碼:client-demo01
1 import tensorflow as tf 2 import numpy as np 3 # 1. 構建圖 4 with tf.device('/job:ps/task:0'): 5 # 2. 構造數據 6 x = tf.constant(np.random.rand(100).astype(np.float32)) 7 # 3. 使用另外一個機器 8 with tf.device('/job:work/task:1'): 9 y = x * 0.1 + 0.3 10 # 4. 運行 11 with tf.Session(target='grpc://127.0.0.1:33335', 12 config=tf.ConfigProto(log_device_placement=True, allow_soft_placement=True)) as sess: 13 print(sess.run(y))
執行:
1、通過命令行,進入對應環境:我的是activate tensorflow-gpu,再進入對應server-demo.py所在文件夾,重復打開5個,分別輸入(雖然最后結果只是在最后3335中顯示,但是必須要全部運行,才能運算出結果):
python server-demo.py --job_name=ps --task_index=0
python server-demo.py --job_name=ps --task_index=1
python server-demo.py --job_name=work --task_index=0
python server-demo.py --job_name=work --task_index=1
python server-demo.py --job_name=work --task_index=2
2、運行客戶端,最后結果如下: