NVIDIA GPU / CUDA 中使用 OpenCV 深度神經(jīng)網(wǎng)絡模塊

在本教程中,您將學習如何將 OpenCV 的“深度神經(jīng)網(wǎng)絡”(DNN) 模塊與 NVIDIA GPU、CUDA 和 cuDNN 結(jié)合使用,以將推理速度提高 211-1549%。
早在 2017 年 8 月,我發(fā)表了我的第一個關(guān)于使用 OpenCV 的“深度神經(jīng)網(wǎng)絡”(DNN)模塊進行圖像分類的教程。
PyImageSearch 的讀者非常喜歡 OpenCV 的 dnn 模塊的便利性和易用性,因此我陸續(xù)發(fā)布了有關(guān) dnn 模塊的一些教程。
這些教程都使用 OpenCV 的 dnn 模塊來進行下面操作:
(1) 從磁盤加載預訓練的網(wǎng)絡;
(2) 對輸入圖像進行預測;
(3) 顯示結(jié)果,允許您構(gòu)建自己的自定義計算機視覺 /deep learning 管道用于您的特定項目。
然而,OpenCV 的 dnn 模塊最大的問題是缺乏 NVIDIA GPU/CUDA 支持——這些模型你不能輕易地使用 GPU 來提高管道的每秒幀數(shù) (FPS) 處理率。
對于 Single Shot Detector (SSD) 教程來說,這并不是什么大問題,它可以輕松地在 CPU 上以 25-30+ FPS 的速度運行,但對于 YOLO 和 Mask R-CNN 來說,這是一個巨大的問題,它們很難做到在 CPU 上獲得超過 1-3 FPS。
這一切在 2019 年的 Google Summer of Code (GSoC) 中發(fā)生了變化。
在 dlib 的 Davis King 的帶領(lǐng)下,由 Yashas Samaga 實施,OpenCV 4.2 現(xiàn)在支持使用 OpenCV 的 dnn 模塊進行推理的 NVIDIA GPU,將推理速度提高了 1549%!
在今天的教程中,我將向您展示如何編譯和安裝 OpenCV 以利用您的 NVIDIA GPU 進行深度神經(jīng)網(wǎng)絡推理。
然后在下周的教程中,我將為您提供 Single Shot Detector、YOLO 和 Mask R-CNN 代碼,這些代碼可用于使用 OpenCV 來利用您的 GPU。接著我們將對結(jié)果進行基準測試,并將它們與僅使用 CPU 的推理進行比較,以便您了解哪些模型可以從使用 GPU 中獲益最多。
要了解如何使用 NVIDIA GPU、CUDA 和 cuDNN 支持編譯和安裝 OpenCV 的“dnn”模塊,請繼續(xù)閱讀!
如何在 NVIDIA GPU、CUDA 和 cuDNN 中使用 OpenCV 的“dnn”模塊
在本教程的其余部分,我將向您展示如何從源代碼編譯 OpenCV,以便您可以利用 NVIDIA GPU 加速推理來進行預訓練的深度神經(jīng)網(wǎng)絡。
為 NVIDIA GPU 支持編譯 OpenCV 時的假設(shè)
為了在 NVIDIA GPU 支持下編譯和安裝 OpenCV 的“深度神經(jīng)網(wǎng)絡”模塊,我將做出以下假設(shè):
1、你有一個 NVIDIA GPU。這應該是一個明顯的假設(shè)。如果您沒有 NVIDIA GPU,則無法編譯具有 NVIDIA GPU 支持的 OpenCV 的“dnn”模塊。
2、您正在使用 Ubuntu 18.04(或其他基于 Debian 的發(fā)行版)。說到深度學習,我強烈推薦基于 Unix 的機器而不是 Windows 系統(tǒng)(實際上,我在 PyImageSearch 博客上不支持 Windows)。如果您打算使用 GPU 進行深度學習,請在 macOS 或 Windows 上使用 Ubuntu——它更容易配置。
3、您知道如何使用命令行。我們將在本教程中使用命令行。如果您不熟悉命令行,我建議您先閱讀此命令行介紹,然后花幾個小時(甚至幾天)練習。同樣,本教程不適用于那些全新的命令行。
4、您能夠閱讀終端輸出并診斷問題。如果您以前從未這樣做過,從源代碼編譯 OpenCV 可能具有挑戰(zhàn)性——有很多事情會讓您感到困惑,包括丟失的包、不正確的庫路徑等。即使使用我的詳細指南,您也可能會犯錯誤一路上。不要氣餒!花點時間了解您正在執(zhí)行的命令、它們的作用,最重要的是,閱讀命令的輸出!不要盲目復制粘貼;你只會遇到錯誤。
說了這么多,讓我們開始為 NVIDIA GPU 推理配置 OpenCV 的“dnn”模塊。
第 1 步:安裝 NVIDIA CUDA 驅(qū)動程序、CUDA Toolkit 和 cuDNN

本教程假設(shè)您已經(jīng)擁有:
一個英偉達 GPU已安裝該特定 GPU 的 CUDA 驅(qū)動程序CUDA Toolkit 和 cuDNN 配置和安裝
如果您的系統(tǒng)上有 NVIDIA GPU,但尚未安裝 CUDA 驅(qū)動程序、CUDA Toolkit 和 cuDNN,則您需要先配置您的機器——我不會在本指南中介紹 CUDA 配置和安裝。一旦您安裝了正確的 NVIDIA 驅(qū)動程序和工具包,您就可以返回本教程。
第 2 步:安裝 OpenCV 和“dnn”GPU 依賴項
為 NVIDIA GPU 推理配置 OpenCV 的“dnn”模塊的第一步是安裝適當?shù)囊蕾図棧?/p>$ sudo apt-get update$ sudo apt-get upgrade$ sudo apt-get install build-essential cmake unzip pkg-config$ sudo apt-get install libjpeg-dev libpng-dev libtiff-dev$ sudo apt-get install libavcodec-dev libavformat-dev libswscale-dev$ sudo apt-get install libv4l-dev libxvidcore-dev libx264-dev$ sudo apt-get install libgtk-3-dev$ sudo apt-get install libatlas-base-dev gfortran$ sudo apt-get install python3-dev
如果您遵循我的 Ubuntu 18.04 深度學習配置指南,那么應該已經(jīng)安裝了大多數(shù)這些軟件包,但為了安全起見,我建議運行上述命令。
第 3 步:下載 OpenCV 源代碼
沒有支持 NVIDIA GPU 的“pip-installable”版本的 OpenCV——相反,我們需要使用正確的 NVIDIA GPU 配置集從頭開始編譯 OpenCV。
這樣做的第一步是下載 OpenCV v4.2 的源代碼:
$ cd ~$ wget -O opencv.zip https://github.com/opencv/opencv/archive/4.2.0.zip$ wget -O opencv_contrib.zip https://github.com/opencv/opencv_contrib/archive/4.2.0.zip$ unzip opencv.zip$ unzip opencv_contrib.zip$ mv opencv-4.2.0 opencv$ mv opencv_contrib-4.2.0 opencv_contrib
我們現(xiàn)在可以繼續(xù)配置我們的構(gòu)建。
第 4 步:配置 Python 虛擬環(huán)境

如果您遵循我的 Ubuntu 18.04、TensorFlow 和 Keras 深度學習配置指南,那么您應該已經(jīng)安裝了 virtualenv 和 virtualenvwrapper:
如果您的機器已配置,請?zhí)帘竟?jié)中的 mkvirtualenv 命令。
否則,請按照以下每個步驟配置您的機器。
Python 虛擬環(huán)境是 Python 開發(fā)的最佳實踐。它們允許您在隔離的、獨立的開發(fā)和生產(chǎn)環(huán)境中測試不同版本的 Python 庫。Python 虛擬環(huán)境被認為是 Python 世界中的最佳實踐——我每天都在使用它們,你也應該這樣做。
如果您還沒有安裝 pip,Python 的包管理器,您可以使用以下命令安裝:
$ wget https://bootstrap.pypa.io/get-pip.py$ sudo python3 get-pip.py
安裝 pip 后,您可以同時安裝 virtualenv 和 virtualenvwrapper:
$ sudo pip install virtualenv virtualenvwrapper$ sudo rm -rf ~/get-pip.py ~/.cache/pip
然后,您需要打開 ~/.bashrc 文件并更新它以在打開終端時自動加載 virtualenv/virtualenvwrapper。我更喜歡使用 nano 文本編輯器,但您可以使用最適合的編輯器:
$ nano ~/.bashrc打開 ~/.bashrc 文件后,滾動到文件底部,然后插入以下內(nèi)容:
# virtualenv and virtualenvwrapperexport WORKON_HOME=$HOME/.virtualenvsexport VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3source /usr/local/bin/virtualenvwrapper.sh
從那里,保存并退出您的終端(ctrl + x , y ,回車)。然后,您可以在終端會話中重新加載 ~/.bashrc 文件:
$ source ~/.bashrc你只需要運行一次上面的命令——因為你更新了你的 ~/.bashrc 文件,當你打開一個新的終端窗口時,virtualenv/virtualenvwrapper 環(huán)境變量將自動設(shè)置。
最后一步是創(chuàng)建你的 Python 虛擬環(huán)境:
$ mkvirtualenv opencv_cuda -p python3mkvirtualenv 命令使用 Python 3 創(chuàng)建一個名為 opencv_cuda 的新 Python 虛擬環(huán)境。然后,您應該將 NumPy 安裝到 opencv_cuda 環(huán)境中:
$ pip install numpy如果您曾經(jīng)關(guān)閉終端或停用 Python 虛擬環(huán)境,您可以通過 workon 命令再次訪問它:
$ workon opencv_cuda如果您不熟悉 Python 虛擬環(huán)境,我建議您花一點時間閱讀它們的工作原理——它們是 Python 世界中的最佳實踐。如果您選擇不使用它們,那完全沒問題,但請記住,您的選擇并不能免除您學習正確的 Python 最佳實踐的責任。現(xiàn)在就花時間投資于您的知識。
第 5 步:確定您的 CUDA 架構(gòu)版本
在編譯支持 NVIDIA GPU 的 OpenCV 的“dnn”模塊時,我們需要確定我們的 NVIDIA GPU 架構(gòu)版本:
1、當我們在下一節(jié)的 cmake 命令中設(shè)置 CUDA_ARCH_BIN 變量時,這個版本號是必需的。2、NVIDIA GPU 架構(gòu)版本取決于您使用的 GPU,因此請確保提前了解您的 GPU 型號。3、未能正確設(shè)置 CUDA_ARCH_BIN 變量可能導致 OpenCV 仍在編譯但無法使用 GPU 進行推理(使診斷和調(diào)試變得麻煩)。
確定您的 NVIDIA GPU 架構(gòu)版本的最簡單方法之一是簡單地使用 nvidia-smi 命令:

檢查輸出,您可以看到我使用的是 NVIDIA Tesla V100 GPU。在繼續(xù)之前,請確保您自己運行 nvidia-smi 命令以驗證您的 GPU 模型。
現(xiàn)在我有了我的 NVIDIA GPU 模型,我可以繼續(xù)確定架構(gòu)版本。
您可以使用此頁面找到適用于您的特定 GPU 的 NVIDIA GPU 架構(gòu)版本:
https://developer.nvidia.com/cuda-gpus向下滾動到支持 CUDA 的 Tesla、Quadro、NVS、GeForce/Titan 和 Jetson 產(chǎn)品列表:

由于我使用的是 V100,我將單擊“啟用 CUDA 的 Tesla 產(chǎn)品”部分:

向下滾動,我可以看到我的 V100 GPU:

如您所見,我的 NVIDIA GPU 架構(gòu)版本是 7.0 — 您應該為自己的 GPU 模型執(zhí)行相同的過程。確定 NVIDIA GPU 架構(gòu)版本后,請記下它,然后繼續(xù)下一部分。
第 6 步:使用 NVIDIA GPU 支持配置 OpenCV
此時,我們已準備好使用 cmake 命令配置我們的構(gòu)建。cmake 命令掃描依賴項,配置構(gòu)建,并生成 make 實際編譯 OpenCV 所需的文件。要配置構(gòu)建,首先確保您位于用于編譯具有 NVIDIA GPU 支持的 OpenCV 的 Python 虛擬環(huán)境中:
$ workon opencv_cuda接下來,將目錄更改為您下載 OpenCV 源代碼的位置,然后創(chuàng)建一個構(gòu)建目錄:
$ cd ~/opencv$ mkdir build$ cd build
然后,您可以運行以下 cmake 命令,確保根據(jù)您在上一節(jié)中找到的 NVIDIA GPU 架構(gòu)版本設(shè)置 CUDA_ARCH_BIN 變量:
$ cmake -D CMAKE_BUILD_TYPE=RELEASE \-D CMAKE_INSTALL_PREFIX=/usr/local \-D INSTALL_PYTHON_EXAMPLES=ON \-D INSTALL_C_EXAMPLES=OFF \-D OPENCV_ENABLE_NONFREE=ON \-D WITH_CUDA=ON \-D WITH_CUDNN=ON \-D OPENCV_DNN_CUDA=ON \-D ENABLE_FAST_MATH=1 \-D CUDA_FAST_MATH=1 \-D CUDA_ARCH_BIN=7.0 \-D WITH_CUBLAS=1 \-D OPENCV_EXTRA_MODULES_PATH=~/opencv_contrib/modules \-D HAVE_opencv_python3=ON \-D PYTHON_EXECUTABLE=~/.virtualenvs/opencv_cuda/bin/python \-D BUILD_EXAMPLES=ON ..
在這里您可以看到我們正在編譯 OpenCV,同時啟用了 CUDA 和 cuDNN 支持(分別為 WITH_CUDA 和 WITH_CUDNN)。
我們還指示 OpenCV 構(gòu)建具有 CUDA 支持的“dnn”模塊(OPENCV_DNN_CUDA)。我們還使用 ENABLE_FAST_MATH、CUDA_FAST_MATH 和 WITH_CUBLAS 進行優(yōu)化。
最重要且容易出錯的配置是您的 CUDA_ARCH_BIN — 確保正確設(shè)置!
CUDA_ARCH_BIN 變量必須映射到您在上一節(jié)中找到的 NVIDIA GPU 架構(gòu)版本。
如果您錯誤地設(shè)置了這個值,OpenCV 仍然可以編譯,但是當您嘗試使用 dnn 模塊執(zhí)行推理時,您將收到以下錯誤消息:
File "ssd_object_detection.py", line 74, indetections = net.forward()cv2.error: OpenCV(4.2.0) /home/a_rosebrock/opencv/modules/dnn/src/cuda/execution.hpp:52: error: (-217:Gpu API call) invalid device function in function 'make_policy'
如果您遇到此錯誤,那么您就知道您的 CUDA_ARCH_BIN 設(shè)置不正確。您可以通過查看輸出來驗證您的 cmake 命令是否正確執(zhí)行:
...-- NVIDIA CUDA: YES (ver 10.0, CUFFT CUBLAS FAST_MATH)-- NVIDIA GPU arch: 70-- NVIDIA PTX archs:---- cuDNN: YES (ver 7.6.0)...
在這里可以看到 OpenCV 和 cmake 已經(jīng)正確識別了我的支持 CUDA 的 GPU、NVIDIA GPU 架構(gòu)版本和 cuDNN 版本。
我還喜歡查看 OpenCV 模塊部分,特別是待構(gòu)建部分:
-- OpenCV modules:-- To be built: aruco bgsegm bioinspired calib3d ccalib core cudaarithm cudabgsegm cudacodec cudafeatures2d cudafilters cudaimgproc cudalegacy cudaobjdetect cudaoptflow cudastereo cudawarping cudev datasets dnn dnn_objdetect dnn_superres dpm face features2d flann fuzzy gapi hdf hfs highgui img_hash imgcodecs imgproc line_descriptor ml objdetect optflow phase_unwrapping photo plot python3 quality reg rgbd saliency shape stereo stitching structured_light superres surface_matching text tracking ts video videoio videostab xfeatures2d ximgproc xobjdetect xphoto-- Disabled: world-- Disabled by dependency: --- Unavailable: cnn_3dobj cvv freetype java js matlab ovis python2 sfm viz-- Applications: tests perf_tests examples apps-- Documentation: NO-- Non-free algorithms: YES
在這里您可以看到有許多 cuda* 模塊,這表明 cmake 正在指示 OpenCV 構(gòu)建我們支持 CUDA 的模塊(包括 OpenCV 的“dnn”模塊)。
您還可以查看 Python 3 部分以驗證您的 Interpreter 和 numpy 是否都指向您的 Python 虛擬環(huán)境:
-- Python 3:-- Interpreter: /home/a_rosebrock/.virtualenvs/opencv_cuda/bin/python3 (ver 3.5.3)-- Libraries: /usr/lib/x86_64-linux-gnu/libpython3.5m.so (ver 3.5.3)-- numpy: /home/a_rosebrock/.virtualenvs/opencv_cuda/lib/python3.5/site-packages/numpy/core/include (ver 1.18.1)-- install path: lib/python3.5/site-packages/cv2/python-3.5
確保你也記下安裝路徑!當我們完成 OpenCV 安裝時,您將需要該路徑。
第 7 步:使用“dnn”GPU 支持編譯 OpenCV
如果 cmake 沒有錯誤退出,您可以使用以下命令編譯具有 NVIDIA GPU 支持的 OpenCV:
$ make -j8您可以將 8 替換為處理器上可用的內(nèi)核數(shù)。由于我的處理器有 8 個內(nèi)核,我提供 8 個內(nèi)核。如果您的處理器只有 4 個內(nèi)核,請將 8 替換為 4 。
如您所見,我的編譯完成且沒有錯誤:

您可能會看到的一個常見錯誤如下:
$ makemake: * No targets specified and no makefile found. Stop.
如果發(fā)生這種情況,您應該返回第 6 步并檢查您的 cmake 輸出 - cmake 命令可能會因錯誤退出。如果 cmake 出現(xiàn)錯誤退出,則無法生成 make 的構(gòu)建文件,因此 make 命令報告沒有可供編譯的構(gòu)建文件。如果發(fā)生這種情況,請返回到您的 cmake 輸出并查找錯誤。
第 8 步:安裝支持“dnn”GPU 的 OpenCV
如果您在步驟 #7 中的 make 命令成功完成,您現(xiàn)在可以通過以下方式安裝 OpenCV:
$ sudo make install$ sudo ldconfig
最后一步是將 OpenCV 庫符號鏈接到您的 Python 虛擬環(huán)境中。
為此,您需要知道安裝 OpenCV 綁定的位置——您可以通過步驟 #6 中的安裝路徑配置確定該路徑。
就我而言,安裝路徑是 lib/python3.5/site-packages/cv2/python-3.5。這意味著我的 OpenCV 綁定應該在 /usr/local/lib/python3.5/site-packages/cv2/python-3.5 中。
我可以使用 ls 命令確認位置:
$ ls -l /usr/local/lib/python3.5/site-packages/cv2/python-3.5total 7168-rw-r--r-1 root staff 7339240 Jan 17 18:59 cv2.cpython-35m-x86_64-linux-gnu.so
在這里你可以看到我的 OpenCV 綁定被命名為 cv2.cpython-35m-x86_64-linux-gnu.so——你的名字應該與你的 Python 版本和 CPU 架構(gòu)相似。
現(xiàn)在我知道了 OpenCV 綁定的位置,我需要使用 ln 命令將它們符號鏈接到我的 Python 虛擬環(huán)境中:
$ cd ~/.virtualenvs/opencv_cuda/lib/python3.5/site-packages/$ ln -s /usr/local/lib/python3.5/site-packages/cv2/python-3.5/cv2.cpython-35m-x86_64-linux-gnu.so cv2.so
花一點時間先驗證您的文件路徑——如果 OpenCV 綁定的路徑不正確,ln 命令將“靜默失敗”。
再次提醒,不要盲目復制粘貼上面的命令!仔細檢查您的文件路徑!
第 9 步:驗證 OpenCV 是否使用帶有“dnn”模塊的 GPU
最后一步是驗證:
OpenCV 可以導入到您的終端OpenCV 可以通過 dnn 模塊訪問您的 NVIDIA GPU 進行推理
讓我們首先驗證我們是否可以導入 cv2 庫:
$ workon opencv_cuda$ pythonPython 3.5.3 (default, Sep 27 2018, 17:25:39)[GCC 6.3.0 20170516] on linuxType "help", "copyright", "credits" or "license" for more information.>>> import cv2>>> cv2.__version__'4.2.0'>>>
請注意,我使用 workon 命令首先訪問我的 Python 虛擬環(huán)境——如果您使用的是虛擬環(huán)境,您應該這樣做。
從那里我導入 cv2 庫并顯示版本。
果然,報出的OpenCV版本是v4.2,確實是我們編譯而來的OpenCV版本。
接下來,讓我們驗證 OpenCV 的“dnn”模塊是否可以訪問我們的 GPU。確保 OpenCV 的“dnn”模塊使用 GPU 的關(guān)鍵可以通過在模型加載后和推理執(zhí)行之前立即添加以下兩行來完成:
net.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA)net.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA)
上面兩行指示 OpenCV 應該使用我們的 NVIDIA GPU 進行推理。
要查看運行中的 OpenCV + GPU 模型的示例,請首先使用本教程的“下載”部分下載我們的示例源代碼和預訓練的 SSD 對象檢測器。
從那里,打開一個終端并執(zhí)行以下命令:
$ python ssd_object_detection.py --prototxt MobileNetSSD_deploy.prototxt \--model MobileNetSSD_deploy.caffemodel \--input guitar.mp4 --output output.avi \--display 0 --use-gpu 1[INFO] setting preferable backend and target to CUDA...[INFO] accessing video stream...[INFO] elasped time: 3.75[INFO] approx. FPS: 65.90
--use-gpu 1 標志指示 OpenCV 使用我們的 NVIDIA GPU 通過 OpenCV 的“dnn”模塊進行推理。
如您所見,我使用 NVIDIA Tesla V100 GPU 獲得了約 65.90 FPS。
然后,我可以將我的輸出與僅使用 CPU(即不使用 GPU)進行比較:
$ python ssd_object_detection.py --prototxt MobileNetSSD_deploy.prototxt \--model MobileNetSSD_deploy.caffemodel --input guitar.mp4 \--output output.avi --display 0[INFO] accessing video stream...[INFO] elasped time: 11.69[INFO] approx. FPS: 21.13
這里我只獲得了約 21.13 FPS,這意味著通過使用 GPU,我獲得了 3 倍的性能提升!
“make_policy”錯誤
檢查、雙重檢查和三重檢查 CUDA_ARCH_BIN 變量是非常非常重要的。如果設(shè)置不正確,在運行上一節(jié)中的 ssd_object_detection.py 腳本時可能會遇到以下錯誤:
File "real_time_object_detection.py", line 74, indetections = net.forward()cv2.error: OpenCV(4.2.0) /home/a_rosebrock/opencv/modules/dnn/src/cuda/execution.hpp:52: error: (-217:Gpu API call) invalid device function in function 'make_policy'
該錯誤表明您的 CUDA_ARCH_BIN 值在運行 cmake 時設(shè)置不正確。
您需要返回第 5 步(在此確定您的 NVIDIA CUDA 架構(gòu)版本),然后重新運行 cmake 和 make。
我還建議您在運行 cmake 和 make 之前刪除構(gòu)建目錄并重新創(chuàng)建它:
$ cd ~/opencv$ rm -rf build$ mkdir build$ cd build
從那里你可以重新運行 cmake 和 make——在一個新的構(gòu)建目錄中這樣做將確保你有一個干凈的構(gòu)建并且任何以前的(不正確的)配置都消失了。
概括
在本教程中,您學習了如何在 NVIDIA GPU、CUDA 和 cuDNN 支持下編譯和安裝 OpenCV 的“深度神經(jīng)網(wǎng)絡”(DNN)模塊,讓您獲得 211-1549% 的推理和預測速度。
使用 OpenCV 的“dnn”模塊需要你從源代碼編譯——你不能“pip install”支持 GPU 的 OpenCV。在下周的教程中,我將針對 CPU 和 GPU 推理速度對流行的深度學習模型進行基準測試,包括:SSD、YOLO、MaskR-CNN使用此信息,您將了解使用 GPU 最能受益的模型,確保您可以就 GPU 是否適合您的特定項目做出明智的決定。

作者:沂水寒城,CSDN博客專家,個人研究方向:機器學習、深度學習、NLP、CV
Blog: http://yishuihancheng.blog.csdn.net
贊 賞 作 者





點擊下方閱讀原文加入社區(qū)會員
