深度學習theano/tensorflow多顯卡多人使用問題集

深度學習theano/tensorflow多顯卡多人使用問題集

其實一直想寫這篇東西,今天還是抽空系統整理一下吧。

深度學習在實驗環境通常會再一臺主機安裝多張顯卡,既可以滿足多人使用,也可以運行部分分佈式任務。

例如我這裏一臺主機安裝了3塊980Ti顯卡(雖然做了SLI但實際在深度學習用不着,其實只在windows下玩遊戲有用),不用水冷也可以正常三塊同時跑。運行環境是以keras爲主(anaconda虛擬環境,cuda7.5+cudnn4),後端有人選擇用theano,有人選擇用tensorflow,也有人不用keras直接跑tensorflow。由於是實驗環境外加正式環境(每天定時運行程序),有4、5個用戶可能會同時使用,在之前使用過程中經常會遇到各種衝突。經歷了各種痛苦後,我積累了一些心得,將各種解決方案列舉一下。

基本顯卡信息用nvidia-smi命令可以 當前運行情況:

可以看到第一塊顯卡和第三塊顯卡已經有程序運行着(一般接顯示器的顯卡會佔用200M左右顯存),但是我通過代碼已經限制了顯存的佔用(下面會提到)。

要看到什麼python代碼正在運行,可以用 ps ax | grep python 命令來看到其他人在運行的代碼。在實際使用中由於深度學習會長時間運行,可以考慮用apt-get安裝screen或tmux複用終端運行,這樣即便網絡斷線也不會導致程序的中斷。

接下去是正題了,默認情況下我們已經配置好使用顯卡運行深度學習程序:

1、運行多程序,但返回顯存不足

有時會碰到類似:MemoryError: Error allocating xxxxxxx bytes of device memory (CNMEM_STATUS_OUT_OF_MEMORY)的錯誤

一般情況下,當兩個程序同時在同一塊顯卡上試圖執行程序時,默認會返回這種錯誤。首先nvidia的顯卡用作深度學習的主要兩個關鍵部分,一個是顯存,一個是cuda流處理器,如下圖,注意流處理器和顯存容量兩個關鍵指標。

默認情況下,不管是theano還是tensorflow,都是在執行初始化時佔用滿顯存,請注意,是佔用滿。這樣,這塊顯卡都容不下第二個程序運行了。所以默認配置情況一塊顯卡同時只允許一個人運行一個深度學習程序。

那麼我們自然會想到是否一次只用一部分顯存,是否可以讓多個程序同時運行?答案自然是肯定的。

1.1:theano後臺限制顯存:每個用戶在自己home根目錄建立.theanorc文件(注意這個文件默認不存在,且文件名前面有個點),配置參數例子如下(參考:config – Theano Configuration):

[global]
floatX = float32
device = gpu0
optimizer_including = cudnn

[lib]
cnmem = 0.3

[cuda]
root = /usr/local/cuda/

其中cnmem部分是佔用多少比例顯存,也就是說如果配置0.3的話可以同時滿足1.0/0.3 = 3個程序同時運行(剩下0.1我留給顯示器顯示ubuntu桌面),每個程序一次佔用三分之一的顯存。device = gpu0說明啓動第0個GPU,配合nvidia-smi命令的輸出,gpu0其實表示的最下面的顯卡(請注意圖上顯示編號爲2),gpu1表示中間一塊(如果總共三塊顯卡),gpu2表示最上面一塊。默認情況,theano會使用第0塊顯卡(如果其他被佔用)。

1.2:tensorflow後臺限制顯存

tensorflow如果如果單純用tensorflow的話可以用代碼控制(參見:tensorflow.org/versions):

config = tf.ConfigProto()
config.gpu_options.per_process_gpu_memory_fraction = 0.4
session = tf.Session(config=config, ...)

如果使用keras作爲前端也可以用代碼控制(參見:Limit the resource usage for tensorflow backend · Issue #1538 · fchollet/keras · GitHub

import tensorflow as tf
from keras.backend.tensorflow_backend import set_session
config = tf.ConfigProto()
config.gpu_options.per_process_gpu_memory_fraction = 0.3
set_session(tf.Session(config=config))

這樣就可以讓同一塊顯卡同時執行多程序了。cuda流處理器也可以和多核CPU一樣滿足多程序運行。

2、只運行了一個程序,運行返回顯存不足

運行機器學習算法時,很多人一開始都會有意無意將數據集默認直接裝進顯卡顯存中,如果處理大型數據集(例如圖片尺寸很大)或是網絡很深且隱藏層很寬,也可能造成顯存不足。

這個情況隨着工作的深入會經常碰到,解決方法其實很多人知道,就是分塊裝入。以keras爲例,默認情況下用fit方法載數據,就是全部載入。換用fit_generator方法就會以自己手寫的方法用yield逐塊裝入。這裏稍微深入講一下fit_generator方法。

fit_generator方法定義

def fit_generator(self, generator, samples_per_epoch, nb_epoch,
                      verbose=1, callbacks=[],
                      validation_data=None, nb_val_samples=None,
                      class_weight=None, max_q_size=10, **kwargs):

其中generator參數傳入的是一個方法,validation_data參數既可以傳入一個方法也可以直接傳入驗證數據集,通常我們都可以傳入方法。這個方法需要我們自己手寫,僞代碼如下:

    def generate_batch_data_random(x, y, batch_size):
        """逐步提取batch數據到顯存,降低對顯存的佔用"""
        ylen = len(y)
        loopcount = ylen // batch_size
        while (True):
            i = randint(0,loopcount)
            yield x[i * batch_size:(i + 1) * batch_size], y[i * batch_size:(i + 1) * batch_size]

爲什麼推薦在自己寫的方法中用隨機呢?因爲fit方法默認shuffle參數也是True,fit_generator需要我們自己隨機打亂數據。另外,在方法中需要用while寫成死循環,因爲每個epoch不會重新調用方法,這個是新手通常會碰到的問題。

調用示例:

model.fit_generator(self.generate_batch_data_random(x_train, y_train, batch_size),                                  samples_per_epoch=len(y_train)//batch_size*batch_size,
                                    nb_epoch=epoch, validation_data=self.generate_valid_data(x_valid, y_valid,batch_size),
                                      nb_val_samples=(len(y_valid)//batch_size*batch_size), verbose=verbose,
                                    callbacks=[early_stopping])

這樣就可以將對顯存的佔用壓低了,配合第一部分的方法可以方便同時執行多程序。

3、多顯卡環境在某塊顯卡被佔用時在其他顯卡運行返回:Segmentation fault (core dumped)

最近幾個月使用頻繁時,經常有人會碰到Segmentation fault (core dumped)錯誤(這個問題似乎是突然出現的),當我在用編號爲2的顯卡時,其他人使用其他顯卡時就會報這個錯,而其他人使用編號0顯卡時,我使用編號2顯卡也會報錯。在網上也可以看到此類問題。

雖然tensorflow可以指定顯卡(參見:Using GPUs),但如果使用前端用keras時也無從指定。

其實有一勞永逸的方式,在CUDA層面屏蔽其他顯卡。

默認情況下,調用CUDA都會遍歷所有顯卡,有顯卡被佔用就可能會出core dumped錯誤,通過CUDA_VISIBLE_DEVICES參數可以控制CUDA可見哪些顯卡,只顯示自己用的就好,就不用關心別人的用沒用了。

將此參數配置加入系統變量即可:

export CUDA_VISIBLE_DEVICES=2

後面的編號表示幾號顯卡,也可以用逗號分隔。(參見:python - TensorFlow Choose GPU to use from multiple GPUs

通常可以將這行加入用戶home目錄下.bashrc,這樣每次遠程登錄就不用重新配置了。

如此,每個人使用不同顯卡就能互不干擾了。

————————————————

終於寫完了,應該算是乾貨吧,嘿嘿~~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章