C++调用Python文件,TensorFlow和PyTorch构建的深度学习模型,无法使用GPU的情况分析。
C++調(diào)用Python深度學(xué)習(xí)模型,包含TensorFlow和PyTorch等構(gòu)造的模型,然后使用GPU出現(xiàn)問(wèn)題。包含C++調(diào)用Python函數(shù),C++加載模型到GPU,GPU內(nèi)存占用過(guò)大,計(jì)算完畢內(nèi)存無(wú)法釋放等問(wèn)題!
- 1. C++調(diào)Python所構(gòu)建的深度學(xué)習(xí)模型
- 1.1 項(xiàng)目描述
- 1.2 C++和Python代碼的構(gòu)建
- 2. Python深度學(xué)習(xí)模型的構(gòu)建代碼,Python文件名為DNN_algorithm.py
- 3. C++調(diào)用所構(gòu)建的Python代碼的相關(guān)函數(shù)
- 4. 加載模型到GPU,然后使用GPU進(jìn)行計(jì)算
- 4.1 C++加載TensorFlow和Keras模型到GPU
- 4.2 C++加載模型到GPU之后,神經(jīng)網(wǎng)絡(luò)運(yùn)行完預(yù)測(cè)函數(shù),GPU的內(nèi)存一直被占用,沒(méi)釋放的問(wèn)題。
- 4.3 關(guān)于上一輪預(yù)測(cè)完成(也就是深度學(xué)習(xí)模型使用完成),下一次加載模型到GPU失敗的問(wèn)題的解決方法。
- 5. GPU一直占著,加載成功,但是GPU的利用率為0,或者很低的情況。
- 參考資料
本文主要分析,C++調(diào)用Python深度學(xué)習(xí)模型,模型加載到GPU,然后GPU內(nèi)存中的模型釋放,以及調(diào)用了GPU,GPU內(nèi)存不夠,內(nèi)存占用過(guò)多,Utilities利用率低,GPU跑不起來(lái)等各種疑難雜癥!
(注:關(guān)于GPU利用率低的問(wèn)題,如何提高深度學(xué)習(xí)GPU使用效率的解決方案,請(qǐng)查看我的這一篇文章:深度學(xué)習(xí)PyTorch,TensorFlow中GPU利用率較低,CPU利用率很低,且模型訓(xùn)練速度很慢的問(wèn)題總結(jié)與分析)
1. C++調(diào)Python所構(gòu)建的深度學(xué)習(xí)模型
1.1 項(xiàng)目描述
最近在幫忙做一個(gè)項(xiàng)目,上層用C++寫的一個(gè)QT軟件,是人臉識(shí)別分析的一個(gè)軟件。C++負(fù)責(zé)界面,多線程,實(shí)時(shí)顯示等各種應(yīng)用的業(yè)務(wù)。Python主要負(fù)責(zé)深度學(xué)習(xí)這一方面。Python構(gòu)建了幾個(gè)深度學(xué)習(xí)模型,包含ResNet101, LSTM, VGG16等網(wǎng)絡(luò),用于特征提取,表情分類,時(shí)序分析等算法方面的邏輯。
C++這一塊,有一個(gè)選項(xiàng)是進(jìn)行人臉檢測(cè),這個(gè)時(shí)候,為了加速,需要調(diào)用GPU來(lái)進(jìn)行計(jì)算。由于算法這邊提供的是Python寫好的,沒(méi)有進(jìn)行TensorFlow或者PyTorch轉(zhuǎn)換成C++的這一種思路。況且,我們的深度學(xué)習(xí)模型,由于是不同人負(fù)責(zé)不同的塊,包含了TensorFlow,Keras,PyTorch,如果用一個(gè)轉(zhuǎn)換包,也不好將三種不同框架轉(zhuǎn)換為1個(gè)可用的C++代碼。
為了方便,就在Python下寫成單獨(dú)的函數(shù),C++直接通過(guò)Python的接口,來(lái)調(diào)用Python代碼。換句話說(shuō)就是,將你用Python寫的深度學(xué)習(xí)代碼,比如,文件名為:DNN_algorithm.py給導(dǎo)入到C++里面,調(diào)用相關(guān)函數(shù)就可以像運(yùn)行python一樣通過(guò)C++運(yùn)行深度學(xué)習(xí)代碼。
1.2 C++和Python代碼的構(gòu)建
Python寫好深度學(xué)習(xí)的代碼,就可以用C++將你DNN_algorithm.py 里面的各個(gè)函數(shù),類,使用起來(lái)了。我的python代碼,首先是加載訓(xùn)練好的模型,函數(shù)名稱是load_model();然后,使用model_predict(image)函數(shù),來(lái)進(jìn)行圖像的人臉檢測(cè),也叫做預(yù)測(cè)。
2. Python深度學(xué)習(xí)模型的構(gòu)建代碼,Python文件名為DNN_algorithm.py
按照常規(guī)的方式,在Python下構(gòu)建模型,訓(xùn)練和保存好模型。當(dāng)進(jìn)行預(yù)測(cè)的時(shí)候,直接加載訓(xùn)練好的權(quán)重文件就可以。這一部分到處都可以查到相關(guān)的指導(dǎo)文件,就不多說(shuō)這一塊。
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++調(diào)用所構(gòu)建的Python代碼的相關(guān)函數(shù)
C++只講怎么調(diào)用你上面構(gòu)建的Python的幾個(gè)函數(shù)。先是導(dǎo)入python文件名,然后導(dǎo)入相關(guān)函數(shù)就可以。具體C++怎么調(diào)用Python的,可以搜一下py.h。是Python官方自帶的,供C++使用的接口函數(shù)。
//創(chuàng)建代碼文件模塊:將你用Python寫的深度學(xué)習(xí)代碼DNN_algorithm.py給導(dǎo)入到C++里面,方便調(diào)用m_pModule = PyImport_ImportModule("DNN_algorithm");//下面就可以,將你DNN_algorithm.py 里面的各個(gè)函數(shù),類,使用起來(lái)了。//我的python代碼,首先是加載訓(xùn)練好的模型,函數(shù)名稱是load_model();//然后,使用model_predict(image)函數(shù),來(lái)進(jìn)行圖像的人臉檢測(cè)。PyObject* pResult = NULL;//調(diào)用python加載模型的函數(shù)load_model。pResult = PyObject_CallMethod(m_pInstanceME, "load_model", NULL);PyObject* pFunc = NULL;//調(diào)用python模型預(yù)測(cè)的函數(shù)model_predict。pFunc = PyObject_GetAttrString(m_pInstanceME, "model_predict");//這句話,就是將python函數(shù),與C++這邊采集到的圖像argList,給模型拿去預(yù)測(cè)。pResult2 = PyEval_CallObject(pFunc, argList);
4. 加載模型到GPU,然后使用GPU進(jìn)行計(jì)算
4.1 C++加載TensorFlow和Keras模型到GPU
對(duì)于這一塊,由于我遇到的問(wèn)題是Tensorflow 和Keras這部分的,PyTorch下加載沒(méi)問(wèn)題。所以就說(shuō)一下TensorFlow和Keras,在C++調(diào)用模型的時(shí)候,如何加載模型到GPU,如何run起來(lái)。
其實(shí)只需要在調(diào)用Python的文件那邊,主動(dòng)加入這些函數(shù),你的模型,就自動(dòng)加載到GPU上的。PyTorch不是這個(gè)用法,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內(nèi)存不夠,不允許TF和Keras開辟很大的內(nèi)存,下面的也可以來(lái)進(jìn)行限制。config = tf.ConfigProto()config.gpu_options.per_process_gpu_memory_fraction = 0.5 #程序最多只能占用指定gpu50%的顯存config.gpu_options.allow_growth = True #程序按需申請(qǐng)內(nèi)存sess = tf.Session(config = config)
- 這個(gè)時(shí)候,查看你的任務(wù)管理器的GPU的情況,包括內(nèi)存和cuda的使用率等。當(dāng)C++調(diào)用了load_model的函數(shù)之后,查看你的GPU的內(nèi)存和使用率是否上去。
- 如果內(nèi)存利用率沒(méi)有上去,就是檢查你的模型是否load上去。這種情況下,先在python下面運(yùn)行,看你的模型load上去GPU沒(méi)有,如果沒(méi)有,那就是python代碼的問(wèn)題。
- 如果Python能夠load上GPU去,但是C++調(diào)用代碼之后,沒(méi)有l(wèi)oad上GPU上,那就是C++調(diào)用Python的問(wèn)題。你檢查你的C++代碼是否正確調(diào)用Python。如果不確定,先寫一個(gè)簡(jiǎn)單的print函數(shù),然后用C++調(diào)用一下,如果行,就按照這個(gè)調(diào)用方式調(diào)用函數(shù)。
- 我的Python代碼下面是一個(gè)類,你就要在C++這邊,先實(shí)例化這個(gè)類,才能調(diào)用下面的類的成員函數(shù)。
4.2 C++加載模型到GPU之后,神經(jīng)網(wǎng)絡(luò)運(yùn)行完預(yù)測(cè)函數(shù),GPU的內(nèi)存一直被占用,沒(méi)釋放的問(wèn)題。
在Python下面,我們r(jià)un完模型的預(yù)測(cè)函數(shù),也就是model_predict()完成之后,或者代碼運(yùn)行完,GPU的內(nèi)存直接被釋放掉。因此,python下,無(wú)需考慮模型占用內(nèi)存的問(wèn)題。
當(dāng)我們使用C++,來(lái)調(diào)用Python所寫的深度學(xué)習(xí)模型的時(shí)候,如上面所述的流程,先構(gòu)建模型,加載權(quán)重文件,然后模型預(yù)測(cè),階段性的處理完了采集的圖像。隨后,我們的界面,可以做其他的業(yè)務(wù),比如,瀏覽,報(bào)表分析,等等。但此時(shí),GPU還被占著,只有你關(guān)閉這個(gè)exe,或者退掉整個(gè)程序,才釋放了由于使用GPU進(jìn)行神經(jīng)網(wǎng)絡(luò)預(yù)測(cè)(推理)所加載的模型及其占用的GPU內(nèi)存。
- 清除緩存
在Python下面,可以采用以下的方法,來(lái)清理緩存,收集垃圾數(shù)據(jù),(PS:只是暫時(shí)的清除一些臨時(shí)變量,作用其實(shí)不大,GPU內(nèi)存占用一樣的無(wú)法減少。)
def delete_model(self):del self.vgg_model #刪除模型del self.LSTM_model #刪除模型gc.collect() #回收一些臨時(shí)變量和垃圾數(shù)據(jù)K.clear_session() #清除sessiontf.reset_default_graph() # 重置 graph。
請(qǐng)注意:如果你只是暫時(shí)的沒(méi)有接收到數(shù)據(jù),GPU暫時(shí)沒(méi)有需要處理的圖像數(shù)據(jù)(也許十幾秒之后,就采集到新的圖像,所以有可能隨時(shí)要用)。此時(shí),不用釋放和刪除內(nèi)存。如果刪除和釋放了GPU內(nèi)存,如果新的圖像數(shù)據(jù)來(lái)了,你還要重新加載數(shù)據(jù)到GPU,這個(gè)過(guò)程是很耗時(shí)的。
- 強(qiáng)制釋放GPU所占用內(nèi)存
當(dāng)完成了人臉檢測(cè)任務(wù),由于當(dāng)前程序尚在執(zhí)行,GPU內(nèi)存一直被占著。
如果你的業(yè)務(wù)下面,有其他算法需要GPU來(lái)進(jìn)行處理,或者GPU用于其他的處理線程,此時(shí),可以關(guān)閉掉你人臉檢測(cè)任務(wù),徹底清除掉GPU緩存和內(nèi)存占用。個(gè)人感覺(jué)有點(diǎn)kill的意思。執(zhí)行了下面的這個(gè)代碼,你的GPU內(nèi)存瞬間釋放,因?yàn)榍懊嬲麄€(gè)加載的模型,全部被close了。這是強(qiáng)制性的。
from numba import cudacuda.select_device(0) #選擇你的device id。在上面我們指定了那一塊GPU用來(lái)處理,這里就指定那塊。cuda.close() # 然后,關(guān)閉掉這個(gè)cuda線程。
下面是簡(jiǎn)要的描述一下Numba這個(gè)庫(kù)。
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 是一個(gè)利用CUDA核在GPU上進(jìn)行快速計(jì)算的Python庫(kù),主要用于高性能計(jì)算。特點(diǎn)如下:
1. Numba: High Productivity for High-Performance Computing
2. GPU-Accelerated Libraries for Python
3. Massive Parallelism with CUDA Python]
當(dāng)你的代碼,執(zhí)行上述的close。此時(shí),如果你還想加載模型,然后進(jìn)行預(yù)測(cè),會(huì)出問(wèn)題的。因?yàn)槟愕腸uda被強(qiáng)制close掉了。要想重新運(yùn)行起來(lái),只有關(guān)閉程序,重新運(yùn)行代碼。如果想在這個(gè)程序里面,再次檢測(cè)人臉。。。。。這個(gè)時(shí)候,就報(bào)錯(cuò)了。。。。
!!!因此,cuda.close()只適合于強(qiáng)制關(guān)閉GPU,留給其他任務(wù)。本任務(wù)是不可能再次使用的。
4.3 關(guān)于上一輪預(yù)測(cè)完成(也就是深度學(xué)習(xí)模型使用完成),下一次加載模型到GPU失敗的問(wèn)題的解決方法。
如果你的C++寫的應(yīng)用,比如QT界面,需要執(zhí)行完本次深度學(xué)習(xí)預(yù)測(cè)任務(wù),然后繼續(xù)去收集圖像或者其他數(shù)據(jù),再次進(jìn)行人臉檢測(cè)。這時(shí)候,如果你加載模型到GPU失敗了,應(yīng)該是上一次執(zhí)行的session未清空,或者這些緩存變量,沒(méi)有給清除掉。因此,你需要在每次執(zhí)行完深度學(xué)習(xí)預(yù)測(cè) model_predict()之后,clear某些session。因此,delete_model()就可以再次加載模型到GPU了。如果使用cuda.close()。你不能再次加載到GPU的。
5. GPU一直占著,加載成功,但是GPU的利用率為0,或者很低的情況。
這個(gè)時(shí)候,點(diǎn)開你的資源管理器,如果GPU內(nèi)存被占,然后上面的利用率,cuda這個(gè)欄目,總是為0。你可以看一下,你的模型代碼,是否正在執(zhí)行預(yù)測(cè)的前向計(jì)算,也就是是否正在進(jìn)行model_predict。或者是檢查模型是否讀入圖像數(shù)據(jù),正在輸出結(jié)果。這個(gè)時(shí)候,如果真的是在預(yù)測(cè)階段,那么GPU的利用率,一定有50%,或者80%,不可能是0。最大的原因是:你的模型,大部分時(shí)間花在了等待數(shù)據(jù)預(yù)處理階段,包括了圖像resize,人臉對(duì)齊,convert color space,還有就是特征檢測(cè),濾波,(我遇到的問(wèn)題是,大部分時(shí)間在花在光流法處理圖像)。因此,感覺(jué)非常慢,而且感覺(jué)GPU沒(méi)有利用上。一度懷疑是不是深度學(xué)習(xí)代碼的問(wèn)題。最后是opencv圖像預(yù)處理的問(wèn)題。你的GPU利用率就是有一個(gè)小的尖峰脈沖形式的抖動(dòng)。其實(shí)代表你的模型正在預(yù)測(cè),GPU正在被使用,只是速度極快,實(shí)時(shí)利用率這一欄只有一個(gè)小的脈沖抖動(dòng)。
解決方法:采用CUDA來(lái)進(jìn)行圖像預(yù)處理的加速,opencv-python 4.幾及其以上版本,已經(jīng)完全支持某些特定函數(shù)的CUDA開發(fā)了,在python上就可以調(diào)用CUDA實(shí)現(xiàn)的的GPU加速圖像處理函數(shù)了。
- TODO:下一個(gè)博文,我就講我如何使用cuda和GPU進(jìn)行圖像預(yù)處理的加速。平時(shí)大家總是覺(jué)得GPU主要用來(lái)深度學(xué)習(xí)的加速,其實(shí)某些耗時(shí)的圖像算法,CUDA也有對(duì)應(yīng)版本。
參考資料
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.
如果有用,記得點(diǎn)贊👍加收藏哦。!!!!
總結(jié)
以上是生活随笔為你收集整理的C++调用Python文件,TensorFlow和PyTorch构建的深度学习模型,无法使用GPU的情况分析。的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 武汉有人一起看电影吗
- 下一篇: Windows启动exe应用程序,无法正