如何解决pjreddie版darknet不能使用cudnn8编译的问题

      近期使用同样的数据同样的yolov3 tiny网络配置文件实验对比了GitHub - pjreddie/darknet: Convolutional Neural Networkshttps://github.com/AlexeyAB/darknet,发现使用两者训练出来的weights文件拿到Jetson Nano上去嵌入到deepstream中使用(网络cfg文件是一样的),用来做视频识别,发现实际表现上,两者训练出来的weights导致模型的精度和召回率相差很大,Alexey版明显比pjreddie差很多,一下想不出准确原因在哪,或许是因为目前版本的deepstream中内置的基于TensorRT实现的yolov3(/tiny)是完全与pjreddie的实现保持一致的?(原因已查明,deepstream内在调用模型做识别时,当模型内部有定制层用plugin实现时,cuda stream必须和模型的其他层使用同一个,不能内部自行再创建或者不传入cuda stream使用tensorrt内部默认的stream,另外deepstream在后处理metadata过滤bbox时有个bug,报给了NVIDIA)。

      之前在RTX3090 GPU server上使用pjreddie版的darknet面临一个左右为难的问题,RTX3090 GPU只能使用CUDA11.x才能跑得正常,但是没有与CUDA11.x对应的cudnn7.x,而pjreddie版的darknet的代码比较老旧了,依赖于cudnn7.x,所以在一个CUDA11.1+cudnn8.x的环境下编译pjreddie版的darknet的话,修改Makefile,设置:

GPU=1
CUDNN=1
OPENCV=1

 后,一执行make就报错:

       ./src/convolutional_layer.c:153:13: error: 'CUDNN_CONVOLUTION_FWD_SPECIFY_WORKSPACE_LIMIT' undeclared (first use in this function);

       did you mean 'CUDNN_CONVOLUTION_FWD_ALGO_DIRECT'?

cudnn8.x里是没有CUDNN_CONVOLUTION_FWD_SPECIFY_WORKSPACE_LIMIT这个宏定义的,而CUDA11.x又不能配套使用cudnn7.x,但是RTX30序列的GPU又必须使用CUDA11.x才能正常跑,感觉进了死胡同。后来找了比较久搜到NVIDIA给出了一个针对cudnn8的解决方案代码,就是修改出错的文件src/convolutional_layer.c的代码,增加针对CUDNN_MAJOR>=8的处理:

#include <stdio.h>
 #include <time.h>
 
 #define PRINT_CUDNN_ALGO 0
 #define MEMORY_LIMIT 2000000000

 #ifdef AI2
 #include "xnor_layer.h"
 #endif
 
 ...

 #ifdef GPU
 #ifdef CUDNN
 void cudnn_convolutional_setup(layer *l)
 {
     ...

     #if CUDNN_MAJOR >= 7
     cudnnSetConvolutionGroupCount(l->convDesc, l->groups);
     #else
     if(l->groups > 1){
         error("CUDNN < 7 doesn't support groups, please upgrade!");
     }
     #endif


    #if CUDNN_MAJOR >= 8
    int returnedAlgoCount;
    cudnnConvolutionFwdAlgoPerf_t       fw_results[2 * CUDNN_CONVOLUTION_FWD_ALGO_COUNT];
    cudnnConvolutionBwdDataAlgoPerf_t   bd_results[2 * CUDNN_CONVOLUTION_BWD_DATA_ALGO_COUNT];
    cudnnConvolutionBwdFilterAlgoPerf_t bf_results[2 * CUDNN_CONVOLUTION_BWD_FILTER_ALGO_COUNT];

    cudnnFindConvolutionForwardAlgorithm(cudnn_handle(),
            l->srcTensorDesc,
            l->weightDesc,
            l->convDesc,
            l->dstTensorDesc,
            CUDNN_CONVOLUTION_FWD_ALGO_COUNT,
            &returnedAlgoCount,
	    fw_results);
    for(int algoIndex = 0; algoIndex < returnedAlgoCount; ++algoIndex){
        #if PRINT_CUDNN_ALGO > 0
        printf("^^^^ %s for Algo %d: %f time requiring %llu memory\n",
               cudnnGetErrorString(fw_results[algoIndex].status),
               fw_results[algoIndex].algo, fw_results[algoIndex].time,
               (unsigned long long)fw_results[algoIndex].memory);
        #endif
        if( fw_results[algoIndex].memory < MEMORY_LIMIT ){
            l->fw_algo = fw_results[algoIndex].algo;
            break;
	}
    }

    cudnnFindConvolutionBackwardDataAlgorithm(cudnn_handle(),
            l->weightDesc,
            l->ddstTensorDesc,
            l->convDesc,
            l->dsrcTensorDesc,
            CUDNN_CONVOLUTION_BWD_DATA_ALGO_COUNT,
            &returnedAlgoCount,
            bd_results);
    for(int algoIndex = 0; algoIndex < returnedAlgoCount; ++algoIndex){
        #if PRINT_CUDNN_ALGO > 0
        printf("^^^^ %s for Algo %d: %f time requiring %llu memory\n",
               cudnnGetErrorString(bd_results[algoIndex].status),
               bd_results[algoIndex].algo, bd_results[algoIndex].time,
               (unsigned long long)bd_results[algoIndex].memory);
        #endif
        if( bd_results[algoIndex].memory < MEMORY_LIMIT ){
            l->bd_algo = bd_results[algoIndex].algo;
            break;
        }
    }

    cudnnFindConvolutionBackwardFilterAlgorithm(cudnn_handle(),
            l->srcTensorDesc,
            l->ddstTensorDesc,
            l->convDesc,
            l->dweightDesc,
            CUDNN_CONVOLUTION_BWD_FILTER_ALGO_COUNT,
            &returnedAlgoCount,
            bf_results);
    for(int algoIndex = 0; algoIndex < returnedAlgoCount; ++algoIndex){
        #if PRINT_CUDNN_ALGO > 0
        printf("^^^^ %s for Algo %d: %f time requiring %llu memory\n",
               cudnnGetErrorString(bf_results[algoIndex].status),
               bf_results[algoIndex].algo, bf_results[algoIndex].time,
               (unsigned long long)bf_results[algoIndex].memory);
        #endif
        if( bf_results[algoIndex].memory < MEMORY_LIMIT ){
            l->bf_algo = bf_results[algoIndex].algo;
            break;
        }
    }

    #else
    
     cudnnGetConvolutionForwardAlgorithm(cudnn_handle(),
             l->srcTensorDesc,
             l->weightDesc,
             l->convDesc,
             l->dstTensorDesc,
             CUDNN_CONVOLUTION_FWD_SPECIFY_WORKSPACE_LIMIT,
             2000000000,
             &l->fw_algo);
     cudnnGetConvolutionBackwardDataAlgorithm(cudnn_handle(),
             l->weightDesc,
             l->ddstTensorDesc,
             l->convDesc,
             l->dsrcTensorDesc,
             CUDNN_CONVOLUTION_BWD_DATA_SPECIFY_WORKSPACE_LIMIT,
             2000000000,
             &l->bd_algo);
     cudnnGetConvolutionBackwardFilterAlgorithm(cudnn_handle(),
             l->srcTensorDesc,
             l->ddstTensorDesc,
             l->convDesc,
             l->dweightDesc,
             CUDNN_CONVOLUTION_BWD_FILTER_SPECIFY_WORKSPACE_LIMIT,
             2000000000,
             &l->bf_algo);
    
    #endif

然后再编译,这个问题就过了,然后继续报个小错误:

   nvcc fatal   : Unsupported gpu architecture 'compute_30'

这个很好解决,把Makefile里的配置修改一下,去掉ARCH配置中的 -gencode arch=compute_30,code=sm_30 \ 这行,改成下面这样即可:

ARCH= -gencode arch=compute_35,code=sm_35 \
      -gencode arch=compute_50,code=[sm_50,compute_50] \
      -gencode arch=compute_52,code=[sm_52,compute_52] \
      -gencode arch=compute_70,code=[sm_70,compute_70] \
      -gencode arch=compute_75,code=[sm_75,compute_75]\
      -gencode arch=compute_86,code=[sm_86,compute_86]

然后编译顺利完成。

版权声明:本文为CSDN博主「Arnold-FY-Chen」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/XCCCCZ/article/details/112793411

Arnold-FY-Chen

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

AlexeyAB DarkNet YOLOv3 Loss计算全解析

先附上AlexeyAB大神版本的DarkNet:github 一、前言 目前还没有对yolo loss计算方法讲的很明白的资料,尤其是loss计算中是如何选取正负样本和忽略样本的。因此在这里做出详细的解释。本文是基于

Yolov3/Yolov4原理对比改进创新

YoLoV3原理详解 Yolo的整个网络,吸取了Resnet、Densenet、FPN的精髓,可以说是融合了目标检测当前业界最有效的全部技巧。 一、backbone主网络 1、升级为Darknet-53 y

【darknet】1、yolov4模型训练之数据处理

本文主要写了使用yolov4进行模型训练前的数据准备。darknet框架使用的数据格式是yolo格式,但我们常见的目标检测数据格式是COCO和VOC.所以本文将以车辆检测为例,将coco2017和voc2007及vo