C++调用Python文件,TensorFlow和PyTorch构建的深度学习模型,无法使用GPU的情况分析。
C++調用Python深度學習模型,包含TensorFlow和PyTorch等構造的模型,然后使用GPU出現問題。包含C++調用Python函數,C++加載模型到GPU,GPU內存占用過大,計算完畢內存無法釋放等問題!
- 1. C++調Python所構建的深度學習模型
- 1.1 項目描述
- 1.2 C++和Python代碼的構建
- 2. Python深度學習模型的構建代碼,Python文件名為DNN_algorithm.py
- 3. C++調用所構建的Python代碼的相關函數
- 4. 加載模型到GPU,然后使用GPU進行計算
- 4.1 C++加載TensorFlow和Keras模型到GPU
- 4.2 C++加載模型到GPU之后,神經網絡運行完預測函數,GPU的內存一直被占用,沒釋放的問題。
- 4.3 關于上一輪預測完成(也就是深度學習模型使用完成),下一次加載模型到GPU失敗的問題的解決方法。
- 5. GPU一直占著,加載成功,但是GPU的利用率為0,或者很低的情況。
- 參考資料
本文主要分析,C++調用Python深度學習模型,模型加載到GPU,然后GPU內存中的模型釋放,以及調用了GPU,GPU內存不夠,內存占用過多,Utilities利用率低,GPU跑不起來等各種疑難雜癥!
(注:關于GPU利用率低的問題,如何提高深度學習GPU使用效率的解決方案,請查看我的這一篇文章:深度學習PyTorch,TensorFlow中GPU利用率較低,CPU利用率很低,且模型訓練速度很慢的問題總結與分析)
1. C++調Python所構建的深度學習模型
1.1 項目描述
最近在幫忙做一個項目,上層用C++寫的一個QT軟件,是人臉識別分析的一個軟件。C++負責界面,多線程,實時顯示等各種應用的業務。Python主要負責深度學習這一方面。Python構建了幾個深度學習模型,包含ResNet101, LSTM, VGG16等網絡,用于特征提取,表情分類,時序分析等算法方面的邏輯。
C++這一塊,有一個選項是進行人臉檢測,這個時候,為了加速,需要調用GPU來進行計算。由于算法這邊提供的是Python寫好的,沒有進行TensorFlow或者PyTorch轉換成C++的這一種思路。況且,我們的深度學習模型,由于是不同人負責不同的塊,包含了TensorFlow,Keras,PyTorch,如果用一個轉換包,也不好將三種不同框架轉換為1個可用的C++代碼。
為了方便,就在Python下寫成單獨的函數,C++直接通過Python的接口,來調用Python代碼。換句話說就是,將你用Python寫的深度學習代碼,比如,文件名為:DNN_algorithm.py給導入到C++里面,調用相關函數就可以像運行python一樣通過C++運行深度學習代碼。
1.2 C++和Python代碼的構建
Python寫好深度學習的代碼,就可以用C++將你DNN_algorithm.py 里面的各個函數,類,使用起來了。我的python代碼,首先是加載訓練好的模型,函數名稱是load_model();然后,使用model_predict(image)函數,來進行圖像的人臉檢測,也叫做預測。
2. Python深度學習模型的構建代碼,Python文件名為DNN_algorithm.py
按照常規的方式,在Python下構建模型,訓練和保存好模型。當進行預測的時候,直接加載訓練好的權重文件就可以。這一部分到處都可以查到相關的指導文件,就不多說這一塊。
class DNN_model():def __init__(self):self.vgg_model = Noneself.LSTM_model = Nonedef load_model(self):VGG_net = # construct the model, you can use tensorflow, keras, PyTorch.LSTM_net = # construct the LSTM model.# load the trained weights to the constructed model architecture.self.vgg_model = load_wights(VGG_net, 'vgg_net.h5')self.LSTM_model = load_wights(LSTM_net , 'lstm_net.h5')def model_predict(self, image):class_out = self.vgg_model.predict(image)temporal_out = self.LSTM_model.predict(image)return class_out, temporal_out
3. C++調用所構建的Python代碼的相關函數
C++只講怎么調用你上面構建的Python的幾個函數。先是導入python文件名,然后導入相關函數就可以。具體C++怎么調用Python的,可以搜一下py.h。是Python官方自帶的,供C++使用的接口函數。
//創建代碼文件模塊:將你用Python寫的深度學習代碼DNN_algorithm.py給導入到C++里面,方便調用m_pModule = PyImport_ImportModule("DNN_algorithm");//下面就可以,將你DNN_algorithm.py 里面的各個函數,類,使用起來了。//我的python代碼,首先是加載訓練好的模型,函數名稱是load_model();//然后,使用model_predict(image)函數,來進行圖像的人臉檢測。PyObject* pResult = NULL;//調用python加載模型的函數load_model。pResult = PyObject_CallMethod(m_pInstanceME, "load_model", NULL);PyObject* pFunc = NULL;//調用python模型預測的函數model_predict。pFunc = PyObject_GetAttrString(m_pInstanceME, "model_predict");//這句話,就是將python函數,與C++這邊采集到的圖像argList,給模型拿去預測。pResult2 = PyEval_CallObject(pFunc, argList);
4. 加載模型到GPU,然后使用GPU進行計算
4.1 C++加載TensorFlow和Keras模型到GPU
對于這一塊,由于我遇到的問題是Tensorflow 和Keras這部分的,PyTorch下加載沒問題。所以就說一下TensorFlow和Keras,在C++調用模型的時候,如何加載模型到GPU,如何run起來。
其實只需要在調用Python的文件那邊,主動加入這些函數,你的模型,就自動加載到GPU上的。PyTorch不是這個用法,PyTorch需要顯示的將模型加到device上 :
model=model.to(device) #這是PyTorch的加載方法
# 這是Keras的加載方法import osos.environ['KMP_DUPLICATE_LIB_OK']='TRUE'os.environ['CUDA_VISIBLE_DEVICES']='0'os.environ["TF_CPP_MIN_LOG_LEVEL"]='3'## 如果你的GPU內存不夠,不允許TF和Keras開辟很大的內存,下面的也可以來進行限制。config = tf.ConfigProto()config.gpu_options.per_process_gpu_memory_fraction = 0.5 #程序最多只能占用指定gpu50%的顯存config.gpu_options.allow_growth = True #程序按需申請內存sess = tf.Session(config = config)
- 這個時候,查看你的任務管理器的GPU的情況,包括內存和cuda的使用率等。當C++調用了load_model的函數之后,查看你的GPU的內存和使用率是否上去。
- 如果內存利用率沒有上去,就是檢查你的模型是否load上去。這種情況下,先在python下面運行,看你的模型load上去GPU沒有,如果沒有,那就是python代碼的問題。
- 如果Python能夠load上GPU去,但是C++調用代碼之后,沒有load上GPU上,那就是C++調用Python的問題。你檢查你的C++代碼是否正確調用Python。如果不確定,先寫一個簡單的print函數,然后用C++調用一下,如果行,就按照這個調用方式調用函數。
- 我的Python代碼下面是一個類,你就要在C++這邊,先實例化這個類,才能調用下面的類的成員函數。
4.2 C++加載模型到GPU之后,神經網絡運行完預測函數,GPU的內存一直被占用,沒釋放的問題。
在Python下面,我們run完模型的預測函數,也就是model_predict()完成之后,或者代碼運行完,GPU的內存直接被釋放掉。因此,python下,無需考慮模型占用內存的問題。
當我們使用C++,來調用Python所寫的深度學習模型的時候,如上面所述的流程,先構建模型,加載權重文件,然后模型預測,階段性的處理完了采集的圖像。隨后,我們的界面,可以做其他的業務,比如,瀏覽,報表分析,等等。但此時,GPU還被占著,只有你關閉這個exe,或者退掉整個程序,才釋放了由于使用GPU進行神經網絡預測(推理)所加載的模型及其占用的GPU內存。
- 清除緩存
在Python下面,可以采用以下的方法,來清理緩存,收集垃圾數據,(PS:只是暫時的清除一些臨時變量,作用其實不大,GPU內存占用一樣的無法減少。)
def delete_model(self):del self.vgg_model #刪除模型del self.LSTM_model #刪除模型gc.collect() #回收一些臨時變量和垃圾數據K.clear_session() #清除sessiontf.reset_default_graph() # 重置 graph。
請注意:如果你只是暫時的沒有接收到數據,GPU暫時沒有需要處理的圖像數據(也許十幾秒之后,就采集到新的圖像,所以有可能隨時要用)。此時,不用釋放和刪除內存。如果刪除和釋放了GPU內存,如果新的圖像數據來了,你還要重新加載數據到GPU,這個過程是很耗時的。
- 強制釋放GPU所占用內存
當完成了人臉檢測任務,由于當前程序尚在執行,GPU內存一直被占著。
如果你的業務下面,有其他算法需要GPU來進行處理,或者GPU用于其他的處理線程,此時,可以關閉掉你人臉檢測任務,徹底清除掉GPU緩存和內存占用。個人感覺有點kill的意思。執行了下面的這個代碼,你的GPU內存瞬間釋放,因為前面整個加載的模型,全部被close了。這是強制性的。
from numba import cudacuda.select_device(0) #選擇你的device id。在上面我們指定了那一塊GPU用來處理,這里就指定那塊。cuda.close() # 然后,關閉掉這個cuda線程。
下面是簡要的描述一下Numba這個庫。
cuda.close()
Explicitly close all contexts in the current thread.
Compiled functions are associated with the CUDA context. This makes it not very useful to close and create new devices, though it is certainly useful for choosing which device to use when the machine has multiple GPUs.
Numba 是一個利用CUDA核在GPU上進行快速計算的Python庫,主要用于高性能計算。特點如下:
1. Numba: High Productivity for High-Performance Computing
2. GPU-Accelerated Libraries for Python
3. Massive Parallelism with CUDA Python]
當你的代碼,執行上述的close。此時,如果你還想加載模型,然后進行預測,會出問題的。因為你的cuda被強制close掉了。要想重新運行起來,只有關閉程序,重新運行代碼。如果想在這個程序里面,再次檢測人臉。。。。。這個時候,就報錯了。。。。
!!!因此,cuda.close()只適合于強制關閉GPU,留給其他任務。本任務是不可能再次使用的。
4.3 關于上一輪預測完成(也就是深度學習模型使用完成),下一次加載模型到GPU失敗的問題的解決方法。
如果你的C++寫的應用,比如QT界面,需要執行完本次深度學習預測任務,然后繼續去收集圖像或者其他數據,再次進行人臉檢測。這時候,如果你加載模型到GPU失敗了,應該是上一次執行的session未清空,或者這些緩存變量,沒有給清除掉。因此,你需要在每次執行完深度學習預測 model_predict()之后,clear某些session。因此,delete_model()就可以再次加載模型到GPU了。如果使用cuda.close()。你不能再次加載到GPU的。
5. GPU一直占著,加載成功,但是GPU的利用率為0,或者很低的情況。
這個時候,點開你的資源管理器,如果GPU內存被占,然后上面的利用率,cuda這個欄目,總是為0。你可以看一下,你的模型代碼,是否正在執行預測的前向計算,也就是是否正在進行model_predict。或者是檢查模型是否讀入圖像數據,正在輸出結果。這個時候,如果真的是在預測階段,那么GPU的利用率,一定有50%,或者80%,不可能是0。最大的原因是:你的模型,大部分時間花在了等待數據預處理階段,包括了圖像resize,人臉對齊,convert color space,還有就是特征檢測,濾波,(我遇到的問題是,大部分時間在花在光流法處理圖像)。因此,感覺非常慢,而且感覺GPU沒有利用上。一度懷疑是不是深度學習代碼的問題。最后是opencv圖像預處理的問題。你的GPU利用率就是有一個小的尖峰脈沖形式的抖動。其實代表你的模型正在預測,GPU正在被使用,只是速度極快,實時利用率這一欄只有一個小的脈沖抖動。
解決方法:采用CUDA來進行圖像預處理的加速,opencv-python 4.幾及其以上版本,已經完全支持某些特定函數的CUDA開發了,在python上就可以調用CUDA實現的的GPU加速圖像處理函數了。
- TODO:下一個博文,我就講我如何使用cuda和GPU進行圖像預處理的加速。平時大家總是覺得GPU主要用來深度學習的加速,其實某些耗時的圖像算法,CUDA也有對應版本。
參考資料
1. Numba: High-Performance Python with CUDA Acceleration
2. Numba for device management
3. CUDA Device Management
4. C++ call python neural network model, the model was loaded on GPU, but can’t run on the GPU, the CPU run the model.
如果有用,記得點贊👍加收藏哦。!!!!
總結
以上是生活随笔為你收集整理的C++调用Python文件,TensorFlow和PyTorch构建的深度学习模型,无法使用GPU的情况分析。的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 武汉有人一起看电影吗
- 下一篇: 任开头成语有哪些?