*免责声明:
1\此方法仅提供参考
2\搬了其他博主的操作方法,以贴上路径.
3*
场景一:nvidia-smi显示不出来
场景二:darknet在ubuntu下的使用,gpu
场景三:YOLOV3 测试图像添加置信度
场景四:labellmg闪退
场景五:darknet、yolyov3批量测试图片
场景六:图片视频相互转换
场景七:改变检测框的粗细
场景八:darknet、yolyov3保存检测视频
场景九:darknet、yolov4 python保存检测视频
场景十:darknet/yolov4火灾预警,输出指定标签到指定文件这去
场景十一:实现视频的逐帧图像导出
.
.
.
.
场景一:nvidia-smi显示不出来
问题描述
NVIDIA-SMI has failed because it couldn’t communicate with the NVIDIA driver
1、终端查看nvidia-smi,报错
2、查看cuda和cudnn,发现都在
3、解决方法
(1)造成这个原因是升级了驱动,首先,查看自己安装的nvidia版本,我的是460.32.03
命令:ls /usr/src | grep nvidia
(2)然后,终端执行一下命令
命令:sudo apt install dkms
命令:sudo dkms install -m nvidia -v 460.32.03
(3)再次输入nvidia-smi,显示:
场景二:darknet在ubuntu下的使用,gpu
1、基本配置
Nvidia/cuda/cudnn/opencv安装参考教程:参考教程
2、常见的依赖安装
yum -y install vim*
yum -y install net-tools
yum install gcc
yum install gcc-c++
yum install -y git
yum -y install wget
3、下载源码和权值文件
yolov3
darknet下载命令:git clone https://github.com/pjreddie/darknet
权值文件下载命令:wget https://pjreddie.com/media/files/yolov3.weights
yolov4
darknet下载命令:git clone https://github.com/AlexeyAB/darknet
下载yolov4的权值文件: 百度云地址 https://pan.baidu.com/share/init?surl=npCGwsL30uIUMzRxAoCi1g
密码:ubee
下载好把权值文件放在darknet目录下
4、无gpu支持下的编译测试
如果你有opencv,记得修改darknet下Makefile文件,有gpu的可以跳转下一步,也可以来体验一下没有gpu加速的效果。
命令:cd darknet
修改Makefile文件
4.1修改基本参数
GPU=0
CUDNN=0
OPENCV=1
OPENMP=0
DEBUG=0
如果修改了,记得保存,上面的选项有则为1,没有就是0。
4.2编译
编译命令:make (如果make出错就sudo make clean) 用./darknet命令测试,是否安装成功,返回以下表示成功
5、有gpu支持下的编译测试
命令:cd darknet
修改Makefile文件
命令:sudo gedit Makefile
5.1修改基本参数
开头修改如下:也可以把cudnn=1
5.2修改算力
根据自己电脑的硬件可在Makefile中对ARCH进行修改,我的显卡是GTX970,算力为5.2(具体算力nvidia官网可查)。
查看地址
修改如下:
5.3重定位nvcc
重新单位nvcc,修改为自己的路径。
NVCC=/usr/local/cuda-11.1/bin/nvcc # 原为 NVCC = nvcc,现在重新定位
5.4重定位cuda
重新单位cuda,修改为自己的路径。
5.5修改 vim /etc/profile进行编辑
在这个文件的最后一行的下面加入如下内容
export PATH=/usr/local/cuda-11.1/bin${PATH:+:${PATH}}
export LD_LIBRARY_PATH=/usr/local/cuda-11.1/lib64${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}
其中这里的cuda的版本改为你自己的版本
命令:source /etc/profile
5.6编译
编译命令:sudo make (如果已经编译或者make出错就sudo make clean)
用./darknet命令测试,是否安装成功,返回以下表示成功
6、有cudnn支持下的编译测试
运行速度:cudnn支持 > gpu的支持 >> cpu的支持
虽然不开启cudnn,gpu的开启也能达到加速的效果,但cudnn的开启确实要快一点,那为什么这里要分开呢,不与上面一起开启呢?
6.1错误描述
先按第五步进行修改,然后将cudnn开启,进行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’?
原因分析:
是因为pjreddie版的darknet的代码比较老旧了,依赖于cudnn7.x,所以在一个CUDA11.1+cudnn8.x的环境下编译pjreddie版的darknet的话,会报错。作者前面已经写了cudnn的版本是8.x版本的。
6.2解决方案
后来找了比较久搜到NVIDIA给出了一个针对cudnn8的解决方案代码,就是修改出错的文件src/convolutional_layer.c的代码,增加针对CUDNN_MAJOR>=8的处理:
开头处添加:
#define PRINT_CUDNN_ALGO 0
#define MEMORY_LIMIT 2000000000
找到下面函数
#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
}
#endif
#endif
然后再编译,这个问题就过了,然后make可能会继续报个小错误:
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]
或者像作者第五步中写道的那样,修改成为固定算力。
然后编译顺利完成。
7、测试图片/摄像头/视频
./darknet detect cfg/yolov3.cfg yolov3.weights data/dog.jpg
./darknet detector test cfg/coco.data cfg/yolov3.cfg yolov3.weights data/dog.jpg
效果对比:gpu比cup足足快了60倍
测试视频 ./darknet detector demo cfg/coco.data cfg/yolov3.cfg yolov3.weights <video file>
如:./darknet detector demo cfg/coco.data cfg/yolov3.cfg yolov3.weights data/1.mp4
加载摄像头 ./darknet detector demo cfg/coco.data cfg/yolov3.cfg yolov3.weights
8、测试时候内存溢出问题
在程序运行的过程中如果出现以下错误(内存溢出): cuda error: out of memory darknet:./src/cuda.c:36: check_error: Assertion `0’ failed.
应该进行如下修改:
将/darknet/cfg目录下yolov3.cfg的修改为:
将
[net]
# Testing
#batch=1
#subdivisions=1
# Training
batch=64
subdivisions=16
修改为
[net]
# Testing
batch=1
subdivisions=1
# Training
#batch=64
#subdivisions=16
场景三:YOLOV3 测试图像添加置信度
方式一:darknet源码
darknet/src/image.c文件中,修改draw_detections函数
四条语句:添加到相应的位置
char possible[10];//存放检测的置信值,这里是新添加的
sprintf(possible,"%.3f",dets[i].prob[j]);//置信值截取小数点后两位赋给possible,这里是新添加的
strcat(labelstr,possible);//标签中加入置信值,这里是新添加的
strcat(labelstr, possible);//标签中加入置信值,这里是新添加的
接下来 make clean
重新编译 make
测试
图片输出置信度不太美观,进行优化处理,修改如下地方
接下来 make clean
重新编译 make
测试
方式二:darknet-master源码
1.找到darknet-master\src\image.c文件。
2.打开该文件找到draw_detections_v3函数,在第431行加上下面的代码(复制粘贴就好,注意缩进):
char buff[5];
_gcvt((selected_detections[i].det.prob[selected_detections[i].best_class] * 100), 5, buff);
char prob[] = ":";
strcat(labelstr, prob);
strcat(labelstr, buff);
image prob_label = get_label_v3(alphabet, labelstr, (im.h*.03));
draw_label(im, top + width , left , prob_label, rgb);
free_image(prob_label);
如下图所示:
前后对照版:
3.重新编译(make),一定要重新编译。
4.结果展示:
场景四:labellmg闪退
1、在c盘,用户下,你自己的账户下 会有.labelimgSettings.pkl文件,删除再工具打开 (同级目录有 桌面 音乐)
2、还有可能是安装路径存在中文。
场景五:darknet、yolyov3批量测试图片
5.1修改makefile
批量测试图片,对于Makefile前五行一定要调成0。
5.2修改detector.c文件
在darknet/example/detector.c文件中,在前面添加GetFilename(char p)函数(注意后面的注释),建议给文档做一个备份。
命令:sudo cd example
命令:sudo gedit detector.c
# include "darknet.h"
# include <sys/stat.h>
# include<stdio.h>
# include<time.h>
# include<sys/types.h>
static int coco_ids[] = {1,2,3,4,5,6,7,8,9,10,11,13,14,15,16,17,18,19,20,21,22,23,24,25,27,28,31,32,33,34,35,36,37,38,39,40,41,42,43,44,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,67,70,72,73,74,75,76,77,78,79,80,81,82,84,85,86,87,88,89,90};
// 在下面添加GetFilename函数
char *GetFilename(char *p)
{
static char name[64]; // 作为返回值不能是局部变量
memset(name, 0, sizeof(name)); // 清空之前的静态变量
int length = 0;
char *q = strrchr(p,'/') + 1; // 获取第一个'/'后面的位置
length = strlen(q);
strncpy(name,q,length-4); // 赋值并且不要后缀
return name;
}
用下面代码替换detector.c文件的void test_detector函数(注意有3处要改成自己的路径)全部复制并代替,三处修改路径写对
void test_detector(char *datacfg, char *cfgfile, char *weightfile, char *filename, float thresh, float hier_thresh, char *outfile, int fullscreen)
{
list *options = read_data_cfg(datacfg);
char *name_list = option_find_str(options, "names", "data/names.list");
char **names = get_labels(name_list);
image **alphabet = load_alphabet();
network *net = load_network(cfgfile, weightfile, 0);
set_batch_network(net, 1);
srand(2222222);
double time;
char buff[256];
char *input = buff;
float nms=.45;
int i=0;
while(1){
if(filename){
strncpy(input, filename, 256);
image im = load_image_color(input,0,0);
image sized = letterbox_image(im, net->w, net->h);
//image sized = resize_image(im, net->w, net->h);
//image sized2 = resize_max(im, net->w);
//image sized = crop_image(sized2, -((net->w - sized2.w)/2), -((net->h - sized2.h)/2), net->w, net->h);
//resize_network(net, sized.w, sized.h);
layer l = net->layers[net->n-1];
float *X = sized.data;
time=what_time_is_it_now();
network_predict(net, X);
printf("%s: Predicted in %f seconds.\n", input, what_time_is_it_now()-time);
int nboxes = 0;
detection *dets = get_network_boxes(net, im.w, im.h, thresh, hier_thresh, 0, 1, &nboxes);
//printf("%d\n", nboxes);
//if (nms) do_nms_obj(boxes, probs, l.w*l.h*l.n, l.classes, nms);
if (nms) do_nms_sort(dets, nboxes, l.classes, nms);
draw_detections(im, dets, nboxes, thresh, names, alphabet, l.classes);
free_detections(dets, nboxes);
if(outfile)
{
save_image(im, outfile);
}
else{
save_image(im, "predictions");
#ifdef OPENCV
cvNamedWindow("predictions", CV_WINDOW_NORMAL);
if(fullscreen){
cvSetWindowProperty("predictions", CV_WND_PROP_FULLSCREEN, CV_WINDOW_FULLSCREEN);
}
show_image(im, "predictions");
cvWaitKey(0);
cvDestroyAllWindows();
#endif
}
free_image(im);
free_image(sized);
if (filename) break;
}
else {
printf("Enter Image Path: ");
fflush(stdout);
input = fgets(input, 256, stdin);
if(!input) return;
strtok(input, "\n");
list *plist = get_paths(input);
char **paths = (char **)list_to_array(plist);
printf("Start Testing!\n");
int m = plist->size;
if(access("/darknet/data/out",0)==-1)//"/darknet/data"修改成自己的路径
{
if (mkdir("/darknet/data/out",0777))//"/darknet/data"修改成自己的路径
{
printf("creat file bag failed!!!");
}
}
for(i = 0; i < m; ++i){
char *path = paths[i];
image im = load_image_color(path,0,0);
image sized = letterbox_image(im, net->w, net->h);
//image sized = resize_image(im, net->w, net->h);
//image sized2 = resize_max(im, net->w);
//image sized = crop_image(sized2, -((net->w - sized2.w)/2), -((net->h - sized2.h)/2), net->w, net->h);
//resize_network(net, sized.w, sized.h);
layer l = net->layers[net->n-1];
float *X = sized.data;
time=what_time_is_it_now();
network_predict(net, X);
printf("Try Very Hard:");
printf("%s: Predicted in %f seconds.\n", path, what_time_is_it_now()-time);
int nboxes = 0;
detection *dets = get_network_boxes(net, im.w, im.h, thresh, hier_thresh, 0, 1, &nboxes);
//printf("%d\n", nboxes);
//if (nms) do_nms_obj(boxes, probs, l.w*l.h*l.n, l.classes, nms);
if (nms) do_nms_sort(dets, nboxes, l.classes, nms);
draw_detections(im, dets, nboxes, thresh, names, alphabet, l.classes);
free_detections(dets, nboxes);
if(outfile){
save_image(im, outfile);
}
else{
char b[2048];
sprintf(b,"/darknet/data/out/%s",GetFilename(path));//"/darknet/data"修改成自己的路径
save_image(im, b);
printf("save %s successfully!\n",GetFilename(path));
#ifdef OPENCV
cvNamedWindow("predictions", CV_WINDOW_NORMAL);
if(fullscreen){
cvSetWindowProperty("predictions", CV_WND_PROP_FULLSCREEN, CV_WINDOW_FULLSCREEN);
}
show_image(im, "predictions");
cvWaitKey(0);
cvDestroyAllWindows();
#endif
}
free_image(im);
free_image(sized);
if (filename) break;
}
}
}
}
5.3记得重新make
命令:sudo make clean
命令:sudo make
5.4准备包含所有需要检测图片路径的txt文件
将需要检测的图片放在darknet/data/piliang文件夹下,然后在darknet/data下新建一个py文件:
命令:sudo touch make_piliang_txt.py
修改命令:sudo gedit make_piliang_txt.py
内容为:
# coding: utf-8import os
paths = "./piliang" # 测试图片的路径
f = open('test.txt', 'w') # 最后得到的图片路径txt文件
filenames = os.listdir(paths)
filenames.sort()for filename in filenames:
out_path = "/darknet/data/piliang/" + filename # 引号内为测试图片文件夹的路径
print(out_path)
f.write(out_path + '\n')
f.close()
然后运行make_piliang_txt.py,在data目录下会生成一个test.txt文件。
运行命令:sudo python make_piliang_txt.py
5.5在data下创建空文件夹out,用来保存批量识别的结果
命令:cd data
命令:sudo mkdir out
5.6测试
运行命令:./darknet detect cfg/yolov3.cfg yolov3.weights
会提示输入路径:把有图片路径的test.txt的全路径写上
5.7结果
场景六:图片视频相互转换
视频转图片
import cv2
cap=cv2.VideoCapture("./test/test.mp4")
i=1
while True:
ret,im=cap.read()
cv2.imwrite("./input/%06d.jpg"%i,im)
i = i+1
print(i)
if i == 72:
break
图片转视频
import cv2
import os
im_dir = './output_yolov3'
num = 72 #这里是帧数
out = cv2.VideoWriter('aa.avi', 0, 29,(1280,720)) #每一个图片的大小必须一致与确定
for i in range(1,num):
print(str("%06d"%i))
im_name = os.path.join(im_dir, str("%06d"%i)+'.jpg')
frame = cv2.imread(im_name)
cv2.imshow("frame",frame)
out.write(frame)
# print(im_name)
out.release()
print('finish')
场景七:改变检测框的粗细
打开src/image.c
查找"draw_detections_v3",找到函数定义部分,在函数体里找到"draw_box_width",其中变量width就是检测框的粗细。
原来的:
修改一下:
结果:
场景八:darknet、yolyov3保存检测视频
好家伙,找了好久,也是改来改去,没有成功,最后找到一个勉强的方法。
方法一:
在darknet/data下建立一个result文件夹,在result文件夹创建一个001文件夹。 然后执行待修改命令:
./darknet detector demo cfg/coco.data cfg/yolov3.cfg yolov3.weights data/1.mp4 -prefix data/result/001/1.mp4
完成以后,会在001下面逐帧保存结果,是大量的图片,你可以写个程序读取图片成为视频,也可以进行以下修改。
改进:(不推荐)
1.在src/image.c里面修改show_image函数
2.在src/image_opencv.cpp里面增加一个save_video函数,记得修改路径
int save_video(image im, const char*name, int ms)
{
// 静态数据成员,第一次调用初始化,之后调用不会在初始化
static VideoWriter* video;
Mat m = image_to_mat(im);
// imshow(name, m);
{
// 空视频对象则初始化一个对象
if(video == NULL){
const char* output_name = "data/result/video001.mp4"; //修改输出路径
// 新建视频保存对象
video = new VideoWriter(output_name, VideoWriter::fourcc('M','J','P','G'), 50, Size(im.w,im.h));
printf("\n DST output_video = %s \n", output_name);
}
// 写入每一帧的处理结果
video->write(m);
printf("\n cvWriteFrame \n");
}
int b = waitKey(ms);
if (b != -1) b = b%256;
return b;
}
3.重新编译,到darknet下命令: sudo make clean 命令:sudo make
4.执行测试命令
./darknet detector demo cfg/coco.data cfg/yolov3.cfg yolov3.weights data/1.mp4
这将会在data/reusult文件夹下生成一个video001.mp4;但是这个视频可能打不开,我就是没有打开但同时也说明确确实实生成了。
在darknet/result文件夹下创建002文件夹,执行下面语句,也会生成改进前的帧图片。
./darknet detector demo cfg/coco.data cfg/yolov3.cfg yolov3.weights data/1.mp4 -prefix data/result/002/1.mp4
方式二:修改源码
会了请告诉我
场景九:darknet、yolov4 python保存检测视频
要使用python脚本进行视频检测,需要libdarknet.so文件,相当于yolov3,yolov4生成.so文件要修改makefile文件,修改完以后重新编译。
相当于yolov3中,虽然yolov3提供的darknet.py脚本官方只是提供了脚本,但是只是能测试图片,而测试视频则需要修改源码。在上文yolov3保存检测视频中有提到。
.
而yolov4则提供了检测视频darknet_video.py+darknet.py和检测图片darknet_images.py+darknet.py的方法。
在这里我们需要保存检测视频,只需要修改darknet_video.py
场景十:yolov4指定标签到指定的文件中去
这个功能的需求是为了火灾预警,当我们训练了火灾,能达到检测到火灾的水平,但怎么去预警能.这里需要当我们检测到火灾的时候,把火灾的标签写入到指定文件夹中文件中,然后其他语言或者函数去读取这个文件,当这个文件不为空,或者是有匹配的字符串,函数向预警函数发出指令,进行预警.
主要修改darknet.py
至于其他函数怎么去完成读取这个文件和达到预警我不关心,我只实现了yolo怎么去提供可以进行预警判断的数据.
场景十一:实现视频的逐帧图像导出
环境:python、opencv
注意修改路径
import cv2
capture=cv2.VideoCapture('/darknet/data/1.mp4') #视频名称
print(capture.isOpened())
num=0
while True:
ret,img=capture.read()
if not ret:
break
cv2.imwrite('/darknet/data/out/001/%s.jpg'%('pic_'+str(num)),img) #写出视频图片.jpg格式
if num==303: #导出视频的前12帧图像
break
num=num+1
capture.release()
you did it