天天看點

MxNet系列——how_to——multi_devices在多個CPU/GPUs上以資料并行方式運作MXNet

部落格新址: http://blog.xuezhisd.top

郵箱:[email protected]

在多個CPU/GPUs上以資料并行方式運作MXNet

MXNet 支援在多個CPUs和GPUs上進行訓練。其中,這些CPUs和GPUs可能位于不同的實體機上。

資料并行 vs 模型并行

MXNet模式使用資料并行的方式将工作負載劃分到多個裝置上。假如有 n 個裝置,每一個裝置都将獲得完整的模型,并使用 1/n 的資料進行訓練。結果(比如,梯度)和更新後的模型在不同裝置之間進行通信。

MXNet也支援模型并行。這時,每個裝置上維護模型的一部分。當模型非常大以至于單個裝置無法存儲時,模型并行非常有用。有一個關于如何在多層LSTM上使用模型并行方法的教程 a tutorial 。本教程主要關注 資料并行。

單機上的多個GPUs

劃分工作負載

MXNet 預設會将一個資料批均勻地劃分到每一個GPU上。加入批大小是 b,GPUs的數目是 k,是以在每一次疊代過程中,每一個GPU将會在 b/k 個樣本上執行前向和後向傳播。在更新模型之前,會将所有GPUs上的梯度都加起來。

如何使用

為了使用 GPUs,需要編譯支援GPU的MXNet。

比如,在配置檔案

config.mk

中設定

USE_CUDA=1

,然後再

make

(更多選項,請檢視 MXNet installation guide)。

如果一台主機安裝了一個或多個GPU,每個GPU都會有一個編号(編号從0開始計數)。如果想使用某個特定的顯示卡,既可以指定在代碼中指定環境(context)

ctx

;也可以在指令行中傳遞參數

--gpus

。例如,如果想在Python中使用GPU 0和GPU 2,可以使用下面的代碼建立網絡模型。

import mxnet as mx
#清單包含多個GPU
model = mx.model.FeedForward(ctx=[mx.gpu(0), mx.gpu(2)], ...) 
           

如果程式接受參數

--gpus

,比如 example/image-classification,那麼可以嘗試下面的代碼。

python train_mnist.py --gpus 0,2 ...
           

進階用法

如果多個GPUs的計算能力不同,那麼可以根據它們的計算性能來劃分工作負載。比如,如果GPU 0 是 GPU 2 性能的3倍,那麼可以提供一個額外的負載選項

work_load_list=[3, 1]

。更多資訊,請檢視 model.fit。

如果所有其它超參都相同,在多個GPUs上訓練結果應該和單GPU上的訓練結果相同。但在實際應用中,由于随機存取(随機順序或其它augmentations),使用不同的種子初始化權重和CuDNN,結果可能不同。

我們可以控制梯度聚合和模型更新(如果執行,訓練過程)的位置,通過建立不同的

KVStore

(它是資料通信子產品)。既可以使用

mx.kvstore.create(type)

來建立一個執行個體,也可以使用程式的參數

--kv-store type

來實作功能。

有兩個常用的類型,

  • local

    : 所有的梯度都複制到CPU記憶體,并且權重也在那裡進行更新。
  • device

    : 梯度聚集和權重更新都在GPU上進行。它也會嘗試使用GPU的P2P通信(它可以加速通信)。但該選項會使用更多的GPU記憶體。

如果有大量的GPU(比如,>=4),我們建議使用

device

,以獲得更佳性能。

使用多個機器進行分布式訓練

我們可以通過簡單地修改

KVStore

,實作在多個機器上運作MXNet。

  • dist_sync

    。 它的行為和

    local

    相似。但一個主要差別是

    batch-size

    此處表示每個機器上的批大小。機器數量為 n,批大小為 b,

    dist_sync

    的行為等價于 批大小為 n/b

    local

    類型。
  • dist_device_sync

    。它 和

    dist_sync

    之間的差別,與

    device

    local

    之間的差別相同。即梯度聚集和權重更新都在GPU上進行。
  • dist_async

    。它執行一步更新。 一旦從任何機器上接收到梯度,立即更新權重。這種更新是具有原子性(不可分),即同一權重在相同的時間不可能出現兩個更新。然而卻無法保證順序。

如何啟動一個作業

如果使用分布式訓練,需要先設定

USE_DIST_KVSTORE=1

,再進行編譯。

(更多選項,請檢視 MXNet installation guide)。

啟動一個分布式作業和單機運作稍有不同。MXNet 提供了 tools/launch.py ,它利用

ssh

,

mpi

,

sge

, 或

yarn

啟動作業。

假定我們位于目錄

mxnet/example/image-classification

下。希望在資料集mnist上使用腳本 train_mnist.py 訓練LeNet。

單機運作時的指令:

python train_mnist.py --network lenet
           

現在有兩個可以使用SSH進行通信的機器,我們希望在這兩個機器上訓練網絡。首先,将這兩個主機的IPs或主機名儲存在

hosts

檔案中。比如,

$ cat hosts
172.30.0.172
172.30.0.171
           

接下來,兩個機器需要都可分通路mxnet檔案夾,比如 網絡檔案系統。

運作以下指令,将在多機上啟動MXNet。

../../tools/launch.py -n 2 --launcher ssh -H hosts python train_mnist.py --network lenet --kv-store dist_sync
           

注意:除了包括單機運作參數,此處還需:

  • 使用

    launch.py

    來送出作業。
  • --launcher

    提供啟動器。如果所有的機器可以互相ssh,那麼使用

    ssh

    ;如果

    mpirun

    可用,那麼使用

    mpi

    ; 如果Sun公司的網格引擎(Sun Grid Engine)可用,使用

    sge

    ;如果Apache Yarn可用,使用

    yarn

  • -n

    計算節點(worker nodes)的數量
  • -H

    指定host檔案(

    ssh

    mpi

    使用)
  • --kv-store

    使用

    dist_sync

    dist_async

同步目錄

現在開始考慮 MXNet 檔案夾不可通路的情況。我們可以先MXNet庫複制到目前目錄。

cp -r ../../python/mxnet .
cp -r ../../lib/libmxnet.so mxnet
           

然後,使用

launch.py

和參數

--sync-dst-dir

将目前目錄同步到所有機器的

/tmp/mxnet

目錄下。

../../tools/launch.py -n 2 -H hosts --sync-dst-dir /tmp/mxnet \
   python train_mnist.py --network lenet --kv-store dist_sync
           

使用一個特定的網絡接口

MXNet 一般會選擇第一個可用的網絡接口。但對于有多個接口的機器,我們通過環境變量

DMLC_INTERFACE

可以指定使用哪個網絡接口進行資料通信。例如,下面的代碼中使用了網絡接口

eth0

# 前面的指令設定網絡接口(網卡)
# 後面的指令和上面相同
export DMLC_INTERFACE=eth0; ../../tools/launch.py ...
           

調試連接配接

通過設定

PS_VERBOSE=1

,可以檢視調試日志。比如,

export PS_VERBOSE=1; ../../tools/launch.py ...
           

更多資料

  • 通過指令

    ../../tools/launch.py -h

    檢視更多啟動選項。
  • 檢視 ps-lite 的更多選項。

繼續閱讀