分布式訓練


分布式訓練

深度學習中,越來越多的場景需要分布式訓練。由於分布式系統面臨單機單卡所沒有的分布式任務調度、復雜的資源並行等問題,因此,通常情況下,分布式訓練對用戶有一定的技術門檻。

在 OneFlow 中,通過頂層設計與工程創新,做到了 分布式最易用,用戶不需要特別改動網絡結構和業務邏輯代碼,就可以方便地使用 OneFlow 進行分布式訓練。這是 OneFlow 區別於其它框架的 最重要特性

本文將介紹:

  • 如何將單機程序修改為分布式程序
  • OneFlow 中節點概念及分工

OneFlow 分布式優勢

  • 采用去中心化的流式架構,而非 master 與 worker 架構,最大程度優化節點網絡通信效率
  • 提供 consistent view,使得用戶可以像編寫單機單卡程序那樣編寫分布式程序
  • 提供 mirrored view,熟悉其它框架分布式訓練的用戶可直接上手
  • 極簡配置,由單機單卡的訓練程序轉變為分布式訓練程序,只需要幾行配置代碼

配置分布式訓練網絡

只需要增加幾行簡單的配置代碼,指定分布式計算的節點 IP 以及每個節點使用 GPU 的數量,即可實現分布式的訓練網絡。

換句話說,這使得單機訓練程序與分布式訓練程序幾乎是一樣的,作為 OneFlow 用戶,只需要專注於程序的 業務邏輯 及 模型結構本身 ,而不用操心分布式執行問題。分布式的一切問題,都由 OneFlow 處理。

下面,介紹一個例子:將單機版的訓練程序,通過添加幾行配置代碼后將其改造為分布式訓練程序。

單機訓練程序

以下是單機訓練程序的框架,因為其網絡結構及業務邏輯與文末的分布式程序完全一樣,因此函數實現未詳細列出。

import numpy as np

import oneflow as flow

import oneflow.typing as tp

 

BATCH_SIZE = 100

 

def mlp(data):

  #構建網絡...

 

 

@flow.global_function(type="train")

def train_job(

    images: tp.Numpy.Placeholder((BATCH_SIZE, 1, 28, 28), dtype=flow.float),

    labels: tp.Numpy.Placeholder((BATCH_SIZE,), dtype=flow.int32),

) -> tp.Numpy:

  #作業函數實現...

  #配置訓練優化方法和參數

 

 

if __name__ == '__main__':

  #調用作業函數,開始訓練...

      loss = train_job(images, labels)

  #...

GPU及端口配置

在 oneflow.config 模塊中,提供了分布式相關的設置接口,主要使用其中兩個:

  • oneflow.config.gpu_device_num : 設置所使用的 GPU 的數目,這個參數會應用到所有的機器中;
  • oneflow.config.ctrl_port : 設置用於通信的端口號,所有機器上都將使用相同的端口號進行通信。

以下代碼中,設置每台主機使用的 GPU 數目為1,采用9988端口通信。大家可以根據自身環境的具體情況進行修改。

#每個節點的 gpu 使用數目

flow.config.gpu_device_num(1)

#通信端口

flow.env.ctrl_port(9988)

注意,即使是單機的訓練,只要有多張 GPU 卡,也可以通過 flow.config.gpu_device_num 將單機程序,設置為單機多卡的分布式程序,如以下代碼,設置1台(每台)機器上,2張 GPU 卡參與分布式訓練:

flow.config.gpu_device_num(2)

節點配置

接着,需要配置網絡中的主機關系,需要提前說明的是,OneFlow 中,將分布式中的主機稱為節點(node)。

每個節點的組網信息,由一個 dict 類型存放,其中的 "addr" 這個 key 對應了節點的 IP 。 所有的節點放置在一個 list 中,經接口 flow.env.machine 告之 OneFlow ,OneFlow 內部會自動建立各個節點之間的連接。

nodes = [{"addr":"192.168.1.12"}, {"addr":"192.168.1.11"}]

flow.env.machine(nodes)

如以上代碼中,的分布式系統中有2個節點,IP 分別為"192.168.1.12"與"192.168.1.11"。

注意,節點 list 中的第0個節點(以上代碼中的"192.168.1.12"),又稱為 master node,整個分布式訓練系統啟動后,完成構圖,其它節點等待;當構圖完成后,所有節點會收到通知,知曉各自聯系的其它節點,去中心化地協同運行。

在訓練過程中,由 master node 保留標准輸出及保存模型,其它節點只負責計算。

可以將針對分布式的配置代碼封裝為函數,方便調用:

def config_distributed():

    print("distributed config")

    #每個節點的gpu使用數目

    flow.config.gpu_device_num(1)

    #通信端口

    flow.env.ctrl_port(9988)

 

    #節點配置

    nodes = [{"addr":"192.168.1.12"}, {"addr":"192.168.1.11"}]

    flow.env.machine(nodes)

分布式訓練及代碼

單機程序加入 OneFlow 的分布式配置代碼后,就成為了分布式程序,在所有的節點運行一樣的程序即可。

可以將分布式訓練程序與上文的 單機訓練程序 比較,會發現僅僅只是增加了 config_distributed 函數並調用,之前的單機訓練腳本,就成為了分布式訓練腳本。

分布式腳本代碼:distributed_train.py

在 192.168.1.12 及 192.168.1.12 上 均運行:

wget https://docs.oneflow.org/code/basics_topics/distributed_train.py

python3 distributed_train.py

192.168.1.12 機器上將顯示程序結果。

FAQ

  • 運行本文分布式代碼后,程序長期等待,未顯示計算結果
  1. 請檢查 ssh 配置,確保兩台機器之間能夠免密 ssh 互聯
  2. 請確保兩台機器使用了相同版本的 OneFlow、運行的腳本程序完全一樣
  3. 請確保訓練使用的端口未被占用,或使用 oneflow.config.ctrl_port 更換端口
  4. 如果在環境變量中設置了代理,請確保代理能夠正常工作,或者取消掉代理
  • 在 docker 中跑訓練,程序長期等待,未顯示計算結果

docker 默認的模式下,物理機與容器中的端口是隔離的,請使用 --net=host host 模式,或者啟動容器時使用 -v 選項進行端口映射。具體請查閱 docker 的手冊

  • 存在虛擬網卡的情況

若存在虛擬網卡,可能因為 nccl 的通信走虛擬網卡而無法通信。此時需要通過 export NCCL_SOCKET_IFNAME=device_name 來指定通信網卡,具體可參閱 nccl 官方文檔

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM