opencv dnn模塊 示例(15) opencv4.2版本dnn支持cuda加速(vs2015異常解決)

opencv在4.2.0版本正式發佈,DNN深度神經網絡模塊集成Google Summer of Code的項目CUDA後端支持。(詳細changelog

1、編譯

常規編譯過程,這裏使用軟硬件環境如下:

  • nvidia gtx1080ti
  • cuda 10.1
  • cudnn 7.6.3
  • vs2015

這裏建議使用高版本的vs,vs2015編譯源碼會有cuda設備相關代碼的錯誤,作者已經修復,在下版本可正常使用。後面會給出在vs2015使用的解決辦法。

1.1 cmake配置

確保勾選 WITH_CUDAWITH_CUDNN,以及OPENCV_DNN_CUDA等選項。
在這裏插入圖片描述
若cuda、cndnn等環境安裝正常,點擊config後會自動填入相關cuda、dnn的環境包括頭文件、庫的路徑。
如下:
在這裏插入圖片描述
之後點擊generate,等待下載相關依賴第三方的包完成。

若下載緩慢,可以查看build目錄下的CMakeDownloadLog.txt文件,找到路徑手動下載,按照文件提示放入指定目錄,一般在source/.cache中。

(若提示cuda_arch_bin的版本要求,根據自己顯卡算力填寫相應的值,我使用gtx 1080ti,設置“6.1 7.0 7.5”)

linux下可以使用:
cmake -BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/home/opencv/opencv-4.2.0/build/install -DOPENCV_EXTRA_MODULES_PATH=/home/opencv/opencv-4.2.0/opencv_contrib-4.2.0/modules -DOPENCV_DNN_CUDA=True -DWITH_CUDA=True -DCUDA_ARCH_BIN=“6.1 7.0 7.5” -DBUILD_TESTS=False

generate成功後,打開項目,編譯即可。

1.2 vs2015編譯opencv庫

使用vs2015編譯,唯獨opencv_dnn模塊的庫會生成失敗,其他正常。
查看報錯問題,如下:

4>d:\opencv\opencv4.2.0\sources\modules\dnn\src\cuda\grid_stride_range.hpp(16): error C2912: 錕斤拷式專錕矯夥拷錕斤拷錕斤拷unsigned int cv::dnn::cuda4dnn::csl::device::detail::getGridDim<0>(void)錕斤拷錕斤拷錕角猴拷錕斤拷模錕斤拷錕階拷沒錕?
4>d:\opencv\opencv4.2.0\sources\modules\dnn\src\cuda\grid_stride_range.hpp(17): error C2912: 錕斤拷式專錕矯夥拷錕斤拷錕斤拷unsigned int cv::dnn::cuda4dnn::csl::device::detail::getGridDim<1>(void)錕斤拷錕斤拷錕角猴拷錕斤拷模錕斤拷錕階拷沒錕?
4>d:\opencv\opencv4.2.0\sources\modules\dnn\src\cuda\grid_stride_range.hpp(18): error C2912: 錕斤拷式專錕矯夥拷錕斤拷錕斤拷unsigned int cv::dnn::cuda4dnn::csl::device::detail::getGridDim<2>(void)錕斤拷錕斤拷錕角猴拷錕斤拷模錕斤拷錕階拷沒錕?
4>d:\opencv\opencv4.2.0\sources\modules\dnn\src\cuda\grid_stride_range.hpp(21): error C2912: 錕斤拷式專錕矯夥拷錕斤拷錕斤拷unsigned int cv::dnn::cuda4dnn::csl::device::detail::getBlockDim<0>(void)錕斤拷錕斤拷錕角猴拷錕斤拷模錕斤拷錕階拷沒錕?
4>d:\opencv\opencv4.2.0\sources\modules\dnn\src\cuda\grid_stride_range.hpp(22): error C2912: 錕斤拷式專錕矯夥拷錕斤拷錕斤拷unsigned int cv::dnn::cuda4dnn::csl::device::detail::getBlockDim<1>(void)錕斤拷錕斤拷錕角猴拷錕斤拷模錕斤拷錕階拷沒錕?
4>d:\opencv\opencv4.2.0\sources\modules\dnn\src\cuda\grid_stride_range.hpp(23): error C2912: 錕斤拷式專錕矯夥拷錕斤拷錕斤拷unsigned int cv::dnn::cuda4dnn::csl::device::detail::getBlockDim<2>(void)錕斤拷錕斤拷錕角猴拷錕斤拷模錕斤拷錕階拷沒錕?
4>d:\opencv\opencv4.2.0\sources\modules\dnn\src\cuda\grid_stride_range.hpp(26): error C2912: 錕斤拷式專錕矯夥拷錕斤拷錕斤拷unsigned int cv::dnn::cuda4dnn::csl::device::detail::getBlockIdx<0>(void)錕斤拷錕斤拷錕角猴拷錕斤拷模錕斤拷錕階拷沒錕?
4>d:\opencv\opencv4.2.0\sources\modules\dnn\src\cuda\grid_stride_range.hpp(27): error C2912: 錕斤拷式專錕矯夥拷錕斤拷錕斤拷unsigned int cv::dnn::cuda4dnn::csl::device::detail::getBlockIdx<1>(void)錕斤拷錕斤拷錕角猴拷錕斤拷模錕斤拷錕階拷沒錕?
4>d:\opencv\opencv4.2.0\sources\modules\dnn\src\cuda\grid_stride_range.hpp(28): error C2912: 錕斤拷式專錕矯夥拷錕斤拷錕斤拷unsigned int cv::dnn::cuda4dnn::csl::device::detail::getBlockIdx<2>(void)錕斤拷錕斤拷錕角猴拷錕斤拷模錕斤拷錕階拷沒錕?
4>d:\opencv\opencv4.2.0\sources\modules\dnn\src\cuda\grid_stride_range.hpp(31): error C2912: 錕斤拷式專錕矯夥拷錕斤拷錕斤拷unsigned int cv::dnn::cuda4dnn::csl::device::detail::getThreadIdx<0>(void)錕斤拷錕斤拷錕角猴拷錕斤拷模錕斤拷錕階拷沒錕?
4>d:\opencv\opencv4.2.0\sources\modules\dnn\src\cuda\grid_stride_range.hpp(32): error C2912: 錕斤拷式專錕矯夥拷錕斤拷錕斤拷unsigned int cv::dnn::cuda4dnn::csl::device::detail::getThreadIdx<1>(void)錕斤拷錕斤拷錕角猴拷錕斤拷模錕斤拷錕階拷沒錕?
4>d:\opencv\opencv4.2.0\sources\modules\dnn\src\cuda\grid_stride_range.hpp(33): error C2912: 錕斤拷式專錕矯夥拷錕斤拷錕斤拷unsigned int cv::dnn::cuda4dnn::csl::device::detail::getThreadIdx<2>(void)錕斤拷錕斤拷錕角猴拷錕斤拷模錕斤拷錕階拷沒錕?
4>d:\opencv\opencv4.2.0\sources\modules\dnn\src\cuda4dnn\csl\cudnn/cudnn.hpp(41): error C2912: 錕斤拷式專錕矯夥拷錕斤拷錕斤拷cudnnDataType_t cv::dnn::cuda4dnn::csl::cudnn::detail::get_data_type<__half>(void)錕斤拷錕斤拷錕角猴拷錕斤拷模錕斤拷錕階拷沒錕?
4>d:\opencv\opencv4.2.0\sources\modules\dnn\src\cuda4dnn\csl\cudnn/cudnn.hpp(42): error C2912: 錕斤拷式專錕矯夥拷錕斤拷錕斤拷cudnnDataType_t cv::dnn::cuda4dnn::csl::cudnn::detail::get_data_type(void)錕斤拷錕斤拷錕角猴拷錕斤拷模錕斤拷錕階拷沒錕?

對應錯誤代碼位置爲
在這裏插入圖片描述
解決方案:
(1)修改sources\modules\dnn\src\cuda\grid_stride_range.hpp文件
替換15-33行爲:

using dim3_member_type = decltype(dim3::x);

template <int>  __device__ dim3_member_type getGridDim();
template <> inline __device__ dim3_member_type getGridDim<0>() { return gridDim.x; }
template <> inline __device__ dim3_member_type getGridDim<1>() { return gridDim.y; }
template <> inline __device__ dim3_member_type getGridDim<2>() { return gridDim.z; }

template <int> __device__ dim3_member_type getBlockDim();
template <> inline __device__ dim3_member_type getBlockDim<0>() { return blockDim.x; }
template <> inline __device__ dim3_member_type getBlockDim<1>() { return blockDim.y; }
template <> inline __device__ dim3_member_type getBlockDim<2>() { return blockDim.z; }

using uint3_member_type = decltype(uint3::x);

template <int> __device__ uint3_member_type getBlockIdx();
template <> inline __device__ uint3_member_type getBlockIdx<0>() { return blockIdx.x; }
template <> inline __device__ uint3_member_type getBlockIdx<1>() { return blockIdx.y; }
template <> inline __device__ uint3_member_type getBlockIdx<2>() { return blockIdx.z; }

template <int> __device__ uint3_member_type getThreadIdx();
template <> inline __device__ uint3_member_type getThreadIdx<0>() { return threadIdx.x; }
template <> inline __device__ uint3_member_type getThreadIdx<1>() { return threadIdx.y; }
template <> inline __device__ uint3_member_type getThreadIdx<2>() { return threadIdx.z; }

(2) 修改sources\modules\dnn\src\cuda4dnn\csl\cudnn\cudnn.hpp文件
替換40-42行爲:

using cudnn_data_enum_type = decltype(CUDNN_DATA_FLOAT);
template <class> cudnn_data_enum_type get_data_type();
template <> inline cudnn_data_enum_type get_data_type<half>() { return CUDNN_DATA_HALF; }
template <> inline cudnn_data_enum_type get_data_type<float>() { return CUDNN_DATA_FLOAT; }

之後保存,重新編譯即可成功。

2、benchmark

詳細的性能提升說明見 https://github.com/opencv/opencv/pull/14827,這裏給出幾張相關截圖。
(1)dnn支持cuda加速的層
在這裏插入圖片描述
(2)常見模型執行效率
這裏測試使用的NVIDIA GTX 1080ti顯卡
在這裏插入圖片描述
(3)opencv cuda 和Tensorflow duda執行效率
在這裏插入圖片描述
(4)yolo3效率對比
這裏使用的是 NVIDIA RTX 2080ti顯卡。
在這裏插入圖片描述

3、Yolo3的對比測試

這裏的對比測試和opencv dnn模塊 示例(3) 目標檢測 object_detection (2) YOLO object 進行對比。使用相同場景,相同模型,相同的代碼。

這裏使用opencv4.2時,需要修改上述文章中34.35兩行代碼

//int backendId = cv::dnn::DNN_BACKEND_OPENCV;
//int targetId = cv::dnn::DNN_TARGET_CPU;

int backendId = cv::dnn::DNN_BACKEND_CUDA;
int targetId = cv::dnn::DNN_TARGET_CUDA;

使用opencv作爲後端,執行效率在360ms左右。
這裏使用cuda作爲後端,執行效率在16ms左右,提升效率近22倍
在這裏插入圖片描述
資源佔用如下
在這裏插入圖片描述

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