近期使用同样的数据同样的yolov3 tiny网络配置文件实验对比了GitHub - pjreddie/darknet: Convolutional Neural Networks和https://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
#include
#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]
然后编译顺利完成。
代码提交在https://github.com/arnoldfychen/darknet