1. 程式人生 > >[開發技巧]·TensorFlow&Keras GPU使用技巧

[開發技巧]·TensorFlow&Keras GPU使用技巧

[開發技巧]·TensorFlow&Keras GPU使用技巧


1.問題描述

在使用TensorFlow&Keras通過GPU進行加速訓練時,有時在訓練一個任務的時候需要去測試結果,或者是需要並行訓練資料的時候就會顯示OOM視訊記憶體容量不足的錯誤。以下簡稱在訓練一個任務的時候需要去測試結果,或者是需要並行訓練資料為進行新的運算任務。

首先介紹下TensorFlow&Keras GPU使用的機制:TensorFlow&Keras會在有GPU可以使用時,自動將資料與運算放到GPU進行訓練(這個不同於MXNet與PyTorch處理方式不同,MXNet與PyTorch需要手動程式設計去指定資料與運算的Device,這裡不討論這些方法之間的優劣,選擇適合自己的就好了),預設充滿GPU所有視訊記憶體。 

所以當用戶在執行一個運算任務時會佔據所有視訊記憶體,如果再去開啟一個新任務就會記憶體不足,引起OOM視訊記憶體容量不足的錯誤。

 

2.問題分析

通過對上述問題解讀,應該可以通過以下的方法解決:

  1. 當一個訓練任務預設佔據所有GPU視訊記憶體的時候,可以使用CPU進行新的任務(這顯然不是最優方法,使用CPU進行新的任務速度會很慢)
  2. 當一個訓練任務預設佔據所有GPU視訊記憶體的時候,使用者可以設定此任務佔用的GPU視訊記憶體大小,現在再使用GPU進行新的任務時,就可以並行運行了
  3. 如果有多個GPU可以預設指定任務在不同GPU上。

 

3.使用教程

 

1.解決方法一:使用CPU進行新的任務

這不是最優方法,使用CPU進行新的任務速度會很慢,但是也是一種解決方式

import os

os.environ['CUDA_VISIBLE_DEVICES'] = '-1'  

# 列印 TF 可用的 GPU
print(os.environ['CUDA_VISIBLE_DEVICES'])

# -1 表示不使用GPU

2.解決方法二:設定任務佔用的GPU視訊記憶體大小

這個是筆者比較推薦的方式,由於TensorFlow&Keras執行一個運算任務時會佔據所有視訊記憶體,其實有時並沒有用到那麼多。

這樣做也會有點小問題就是,單個任務會變慢一點,筆者測試結果是在使用上述方法並行執行兩個單個任務速度變為0.8左右,但是換來了可以執行兩個任務,還是很值得的。(推測變慢的原因是兩個任務並行運算時,對GPU壓力更大,每個任務上分配的效能就會降低,類似於在電腦上跑多個任務,電腦會卡頓)

這樣做要注意一點,在分配視訊記憶體空間後,模型訓練佔據的記憶體要設定好(這個是指實際佔用記憶體,可以通過修改batch_size來控制),不要超出你所分配的大小,不然會有不期望的結果出現。

import tensorflow as tf

# 在開啟對話session前,先建立一個 tf.ConfigProto() 例項物件

gpuConfig = tf.ConfigProto(allow_soft_placement=True)

# 限制一個程序使用 60% 的視訊記憶體
gpuConfig.gpu_options.per_process_gpu_memory_fraction = 0.6

# 把你的配置部署到session  變數名 sess 無所謂
sess1 =tf.Session(config=gpuConfig)


#這樣,如果你指定的卡的視訊記憶體是2000M的話,你這個程序只能用1200M。

輸出結果(with 1228 MB memory,代表使用1228 MB,這與設定的0.6 * 2000相符)

Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 1228 MB memory) -> 
physical GPU (device: 0, name: GeForce MX150, pci bus id: 0000:01:00.0, compute capability: 6.1)

3.解決方法三:多個GPU指定在不同GPU執行

 

如果條件允許,擁有多個,就可以把不同任務放置在不同GPU上,要注意如果是和同事共用,要約定好如何分配,免得大家都用了同一個。

設定方法與方法一類似。-1代表不使用,0代表第一個,1代表第二個

以兩個GPU舉例,第一個任務開頭可以使用如下,第二個任務就把0改為1,多個GPU方法類似。注意一點要放置在開頭位置。

import os

os.environ['CUDA_VISIBLE_DEVICES'] = '0' 

# 列印 TF 可用的 GPU
print(os.environ['CUDA_VISIBLE_DEVICES'])

# -1 表示不使用GPU 0代表第一個

如果多於兩個GPU,想在某個任務設定多個GPU,可以使用下述方法

import os

os.environ['CUDA_VISIBLE_DEVICES'] = '0,1' 

# 列印 TF 可用的 GPU
print(os.environ['CUDA_VISIBLE_DEVICES'])

# -1 表示不使用GPU 0代表第一個

最後留個大家一個思考問題,os.environ['CUDA_VISIBLE_DEVICES'] = '-1,0' 時會怎麼樣呼叫?

歡迎大家在評論區留言釋出自己看法和解讀。。

 

4.參考

1.https://www.cnblogs.com/tectal/p/9048184.