参考:
yolov3
darknet
yolo源码解析
bacth参数对性能影响
backpropogation算法
yolo中7*7个grid和rpn中的9个anchors
darknet源码学习
darknet是一个轻型的、完全基于C与CUDA的开源深度学习框架,支持CPU和GPU两种计算方式。
grid和anchors的唯一作用是为了计算IOU,从而确定正负样本。
对于darknet文件夹,在实践过程中,主要修改的文件有:
在自己的指定目录下下载,终端输入
git clone https://github.com/pjreddie/darknet.git
修改Makefile。GPU环境下的编译配置都是在/darknet/Makefile/中定义的。终端输入
cd darknet
gedit Makefile
在打开的文本上最前面修改
GPU=1
CUDNN=1
OPENCV=1
表示使用GPU CUDNN OPENCV。
更改ARCH配置,根据自己的GPU型号来定。我的GPU是华硕 RTX 2060,计算能力是,GTX1080的计算能力是6.1。故更改为如下:吧前面几行语句注释掉,只保留值为52的那个。
ARCH= # -gencode arch=compute_30,code=sm_30 \
# -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]
compute_30表示显卡的计算能力是3.0。
在Makefile51行,有cuda的安装路径,这里指的路径不是你下载安装包时的路径,而是系统自己存放的cude文件夹和cuda软链接文件夹的路径,在其他位置——计算机——usr——local中。所以是不需要修改makefile文件夹中的cuda安装路径,默认就是与系统实际相匹配的。
注意:每次修改完makefile都要重新Make一下才能生效。
编译,我的cpu是i7-8700,是12线程的6核的,所以使用指令j12,每次使用make指令时都要加上j12,会加快编译速度。终端输入:
make -j12
到这一步时遇到错误,这个错误是在darknet目录下执行make指令显示的错误。显示内容如下:
./src/image_opencv.cpp:5:10: fatal error: opencv2/opencv.hpp: 没有那个文件或目录
#include "opencv2/opencv.hpp"
compilation terminated.
Makefile:86: recipe for target 'obj/image_opencv.o' failed
make: *** [obj/image_opencv.o] Error 1
make: *** 正在等待未完成的任务....
出现上面错误的原因是之前我安装的opencv是python的,即opencv_python。这里模型的训练需要用到c++的opencv。所以这里再装一遍opencv。
我在官网上选择的opencv4.1.0安装的opencv4.1.0
git clone https://github.com/opencv/opencv.git
然后
cd opencv
sudo pip3 install cmake #如果已经安装过cmake,则该步骤省略
#安装依赖库
sudo apt-get install build-essential libgtk2.0-dev libavcodec-dev libavformat-dev libjpeg-dev libswscale-dev libtiff5-dev:i386 libtiff5-dev
创建一个编译文件夹并且进入
mkdir build
cd build/
cmake -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=/usr/local/opencv4 ..
上面的指令修改安装路径到/usr/local/opencv4,可以自己修改到自己需要的位置,如果该命令中不加-D CMAKE_INSTALL_PREFIX=/usr/local/opencv4,则默认各部分分别安装在/usr/local/目录的include/ bin/ lib/3个文件夹下。注意上面指令路径后面还有两个点。
在终端上输入命令时tab键具有补全功能。
会下载ippicv,需要等待比较长时间才能下载完成。
然后进行make编译,需要很久。
make -j12
make编译指令不需要再前面添加sudo,这样的创建的一些文件就需要sudo权限。
进行make install安装
sudo make install
安装完成,配置opencv编译环境。
sudo gedit /etc/ld.so.conf.d/opencv.conf
在打开的空文件末尾添加上:
/usr/local/opencv4/lib
终端输入使配置的路径生效
sudo ldconfig
环境配置完成,进行测试,进入到opencv/samples/cpp/example_cmake目录下。因为更改了opencv的安装路径,所以这里测试前需要CMakeLists.txt文件的14行find_package(OpenCV REQUIRED)前面加上
set(OpenCV_DIR /usr/local/opencv4/lib/cmake/opencv4)
终端在opencv/samples/cpp/example_cmake目录下执行:
cmake .
注意cmake后面有一个点
接着在终端输入
make -j12
输入
./opencv_example
正常结果是:电脑打开了摄像头,在摄像头采集到的图片左上角出现hello opencv字样,即配置成功。
若电脑没有摄像头,则另一种检测方法是终端输入:
python3
import cv2
cv2.__version__
配置成功的结果是显示出opencvz的版本号,注意指令version前后都是有两个_符号。
安装完成opencv4.1.0后,在darknet下编译还是有和之前一样的错误,故使用另一种方法:卸载该版本的opencv,software/opencv/build路径下(从github下载包的路径,不是后来的安装路径)终端输入:因为在这个路径下存在文件cmake_uninstall.cmake。
sudo make uninstall
然后再把local安装路径下和software下载包的路径下把opencv4的文件全部删除。
local文件夹下的需要sudo来删除文件夹。
sudo rm -r opencv4
终端重新安装opencv3.4.6。
同样的安装步骤,这次成功了,原因并不是之前猜测的opencv版本的原因,而是需要创建软链接来解决。(但是有时安装是不用创建软链接的,但是这次这里需要,缺失的步骤是在安装cudnn时,在终端执行完两条如下的cp指令即copy操作后,还需要添加上执行软链接操作)
sudo cp cuda/lib64/libcudnn* /usr/local/cuda/lib64/
具体的解决办法,添加的软链接语句见安装cudnn笔记
经历过上面的错误后,总结出的在安装上的一个建议是:
如果不会创建软链接,不会在文档中添加各个文件的path,就最好安装在默认路径下,不要像上面一样再自行创建新的文件夹来存储,这里创建的是usr/local/opencv4。
安装成功的步骤如下,与上面的步骤大部分一致。安装的是opencv-3.4.6
~/software/opencv-3.4.6$ mkdir build
~/software/opencv-3.4.6$ cd build/
#这一条指令有变化,没有再自行创建opencv文件夹了
~/software/opencv-3.4.6/build$ cmake -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=/usr/local ..
~/software/opencv-3.4.6/build$ make -j16
~/software/opencv-3.4.6/build$ sudo make install
~/software/opencv-3.4.6/build$ sudo ldconfig
#注意,这条指令之后出现问题,显示如下
/sbin/ldconfig.real: /usr/local/cuda-10.1/targets/x86_64-linux/lib/libcudnn.so.7 不是符号链接
下面的几条语句就是在安装cudnn时缺少的创建软链接的指令
~/software/opencv-3.4.6/build$ cd /usr/local/cuda-10.1/
/usr/local/cuda-10.1$ cd lib64
/usr/local/cuda-10.1/lib64$ ls libcudnn.*
#执行后显示
libcudnn.so libcudnn.so.7 libcudnn.so.7.6.1
#接着输入
/usr/local/cuda-10.1/lib64$ rm libcudnn.so libcudnn.so.7
#执行后显示
rm:是否删除有写保护的普通文件 'libcudnn.so'? ^C
#接着输入
#添加sudo权限来删除
/usr/local/cuda-10.1/lib64$ sudo rm libcudnn.so libcudnn.so.7
/usr/local/cuda-10.1/lib64$ sudo ln -sf libcudnn.so.7.6.1 libcudnn.so.7
/usr/local/cuda-10.1/lib64$ sudo ln -sf libcudnn.so.7 libcudnn.so
上面三条两条创建软链接指令的解释:
ln命令的功能是为某个文件在另外一个位置建立一个同步的链接,这个命令最常用的参数是-s,具体用法是:ln –s 源文件 目标文件。
当需要在不同的目录用到相同文件时,不需要在每个需要的目录下都放一个相同的文件,只要在某个固定的目录,放上该文件,然后在其它的目录下用ln命令链接(link)它就可以,不必重复的占用磁盘空间。
例如上面用到的:
ln -sf libcudnn.so.7 libcudnn.so
解释:
-s 是代号(symbolic)的意思。对源文件建立符号连接,而非硬连接。
-f或–force 强行建立文件或目录的连接,不论文件或目录是否存在。
这里使用的是两者的叠加-sf。
分析完毕,最后在终端上接着上面的两条创建软链接指令后输入下面一条语句就完成了。
/usr/local/cuda-10.1/lib64$ sudo ldconfig
进入software/darknet目录下,终端输入编译语句,不再出现错误。
make -j12
安装过程有参考该链接
下载预训练模型。
cd darknet
wget https://pjreddie.com/media/files/yolov3.weights
修改网络配置文件。修改darknet/cfg/yolov3.cfg,如下,注释掉Training参数,取消注释Testing参数。
终端输入:
cd cfg
gedit yolov3.cfg
打开的文本中修改如下
#Testing
batch=1
subdivisions=1
#Training
#batch=64
#subdivisions=16
单张图像检测。运行探测器指令,这是单张图片的测试命令
./darknet detect cfg/yolov3.cfg yolov3.weights data/dog.jpg
备注:上面的指令要在darknet文件夹路径下的终端运行。
cd darknet
make
编译成功后会生成一个darknet可执行文件,执行./darknet就可以运行。可以修改Makefile的参数,但是注意每次修改都要重新make一下。
指令的解释:
./darknet 是执行当前文件下面已经编译好的darknet文件;
detect 是命令;
后面三个分别是参数;
参数cfg/yolov3.cfg表示网络模型;
参数yolov3.weights表示网络权重;
参数data/dog.jpg表示需要检测的图片。
上面的指令等同于下面的指令,一般使用上面的指令,更简洁。如果是训练情况下,则把下面命令中的test换为train。即detector train
./darknet detector test cfg/coco.data cfg/yolov3.cfg yolov3.weights data/dog.jpg
运行后会看到这样的输出:
layer filters size input output
0 conv 32 3 x 3 / 1 608 x 608 x 3 -> 608 x 608 x 32 0.639 BFLOPs
1 conv 64 3 x 3 / 2 608 x 608 x 32 -> 304 x 304 x 64 3.407 BFLOPs
2 conv 32 1 x 1 / 1 304 x 304 x 64 -> 304 x 304 x 32 0.379 BFLOPs
3 conv 64 3 x 3 / 1 304 x 304 x 32 -> 304 x 304 x 64 3.407 BFLOPs
4 res 1 304 x 304 x 64 -> 304 x 304 x 64
5 conv 128 3 x 3 / 2 304 x 304 x 64 -> 152 x 152 x 128 3.407 BFLOPs
6 conv 64 1 x 1 / 1 152 x 152 x 128 -> 152 x 152 x 64 0.379 BFLOPs
7 conv 128 3 x 3 / 1 152 x 152 x 64 -> 152 x 152 x 128 3.407 BFLOPs
8 res 5 152 x 152 x 128 -> 152 x 152 x 128
9 conv 64 1 x 1 / 1 152 x 152 x 128 -> 152 x 152 x 64 0.379 BFLOPs
10 conv 128 3 x 3 / 1 152 x 152 x 64 -> 152 x 152 x 128 3.407 BFLOPs
11 res 8 152 x 152 x 128 -> 152 x 152 x 128
12 conv 256 3 x 3 / 2 152 x 152 x 128 -> 76 x 76 x 256 3.407 BFLOPs
13 conv 128 1 x 1 / 1 76 x 76 x 256 -> 76 x 76 x 128 0.379 BFLOPs
14 conv 256 3 x 3 / 1 76 x 76 x 128 -> 76 x 76 x 256 3.407 BFLOPs
15 res 12 76 x 76 x 256 -> 76 x 76 x 256
16 conv 128 1 x 1 / 1 76 x 76 x 256 -> 76 x 76 x 128 0.379 BFLOPs
17 conv 256 3 x 3 / 1 76 x 76 x 128 -> 76 x 76 x 256 3.407 BFLOPs
18 res 15 76 x 76 x 256 -> 76 x 76 x 256
19 conv 128 1 x 1 / 1 76 x 76 x 256 -> 76 x 76 x 128 0.379 BFLOPs
20 conv 256 3 x 3 / 1 76 x 76 x 128 -> 76 x 76 x 256 3.407 BFLOPs
21 res 18 76 x 76 x 256 -> 76 x 76 x 256
22 conv 128 1 x 1 / 1 76 x 76 x 256 -> 76 x 76 x 128 0.379 BFLOPs
23 conv 256 3 x 3 / 1 76 x 76 x 128 -> 76 x 76 x 256 3.407 BFLOPs
24 res 21 76 x 76 x 256 -> 76 x 76 x 256
25 conv 128 1 x 1 / 1 76 x 76 x 256 -> 76 x 76 x 128 0.379 BFLOPs
26 conv 256 3 x 3 / 1 76 x 76 x 128 -> 76 x 76 x 256 3.407 BFLOPs
27 res 24 76 x 76 x 256 -> 76 x 76 x 256
28 conv 128 1 x 1 / 1 76 x 76 x 256 -> 76 x 76 x 128 0.379 BFLOPs
29 conv 256 3 x 3 / 1 76 x 76 x 128 -> 76 x 76 x 256 3.407 BFLOPs
30 res 27 76 x 76 x 256 -> 76 x 76 x 256
31 conv 128 1 x 1 / 1 76 x 76 x 256 -> 76 x 76 x 128 0.379 BFLOPs
32 conv 256 3 x 3 / 1 76 x 76 x 128 -> 76 x 76 x 256 3.407 BFLOPs
33 res 30 76 x 76 x 256 -> 76 x 76 x 256
34 conv 128 1 x 1 / 1 76 x 76 x 256 -> 76 x 76 x 128 0.379 BFLOPs
35 conv 256 3 x 3 / 1 76 x 76 x 128 -> 76 x 76 x 256 3.407 BFLOPs
36 res 33 76 x 76 x 256 -> 76 x 76 x 256
37 conv 512 3 x 3 / 2 76 x 76 x 256 -> 38 x 38 x 512 3.407 BFLOPs
38 conv 256 1 x 1 / 1 38 x 38 x 512 -> 38 x 38 x 256 0.379 BFLOPs
39 conv 512 3 x 3 / 1 38 x 38 x 256 -> 38 x 38 x 512 3.407 BFLOPs
40 res 37 38 x 38 x 512 -> 38 x 38 x 512
41 conv 256 1 x 1 / 1 38 x 38 x 512 -> 38 x 38 x 256 0.379 BFLOPs
42 conv 512 3 x 3 / 1 38 x 38 x 256 -> 38 x 38 x 512 3.407 BFLOPs
43 res 40 38 x 38 x 512 -> 38 x 38 x 512
44 conv 256 1 x 1 / 1 38 x 38 x 512 -> 38 x 38 x 256 0.379 BFLOPs
45 conv 512 3 x 3 / 1 38 x 38 x 256 -> 38 x 38 x 512 3.407 BFLOPs
46 res 43 38 x 38 x 512 -> 38 x 38 x 512
47 conv 256 1 x 1 / 1 38 x 38 x 512 -> 38 x 38 x 256 0.379 BFLOPs
48 conv 512 3 x 3 / 1 38 x 38 x 256 -> 38 x 38 x 512 3.407 BFLOPs
49 res 46 38 x 38 x 512 -> 38 x 38 x 512
50 conv 256 1 x 1 / 1 38 x 38 x 512 -> 38 x 38 x 256 0.379 BFLOPs
51 conv 512 3 x 3 / 1 38 x 38 x 256 -> 38 x 38 x 512 3.407 BFLOPs
52 res 49 38 x 38 x 512 -> 38 x 38 x 512
53 conv 256 1 x 1 / 1 38 x 38 x 512 -> 38 x 38 x 256 0.379 BFLOPs
54 conv 512 3 x 3 / 1 38 x 38 x 256 -> 38 x 38 x 512 3.407 BFLOPs
55 res 52 38 x 38 x 512 -> 38 x 38 x 512
56 conv 256 1 x 1 / 1 38 x 38 x 512 -> 38 x 38 x 256 0.379 BFLOPs
57 conv 512 3 x 3 / 1 38 x 38 x 256 -> 38 x 38 x 512 3.407 BFLOPs
58 res 55 38 x 38 x 512 -> 38 x 38 x 512
59 conv 256 1 x 1 / 1 38 x 38 x 512 -> 38 x 38 x 256 0.379 BFLOPs
60 conv 512 3 x 3 / 1 38 x 38 x 256 -> 38 x 38 x 512 3.407 BFLOPs
61 res 58 38 x 38 x 512 -> 38 x 38 x 512
62 conv 1024 3 x 3 / 2 38 x 38 x 512 -> 19 x 19 x1024 3.407 BFLOPs
63 conv 512 1 x 1 / 1 19 x 19 x1024 -> 19 x 19 x 512 0.379 BFLOPs
64 conv 1024 3 x 3 / 1 19 x 19 x 512 -> 19 x 19 x1024 3.407 BFLOPs
65 res 62 19 x 19 x1024 -> 19 x 19 x1024
66 conv 512 1 x 1 / 1 19 x 19 x1024 -> 19 x 19 x 512 0.379 BFLOPs
67 conv 1024 3 x 3 / 1 19 x 19 x 512 -> 19 x 19 x1024 3.407 BFLOPs
68 res 65 19 x 19 x1024 -> 19 x 19 x1024
69 conv 512 1 x 1 / 1 19 x 19 x1024 -> 19 x 19 x 512 0.379 BFLOPs
70 conv 1024 3 x 3 / 1 19 x 19 x 512 -> 19 x 19 x1024 3.407 BFLOPs
71 res 68 19 x 19 x1024 -> 19 x 19 x1024
72 conv 512 1 x 1 / 1 19 x 19 x1024 -> 19 x 19 x 512 0.379 BFLOPs
73 conv 1024 3 x 3 / 1 19 x 19 x 512 -> 19 x 19 x1024 3.407 BFLOPs
74 res 71 19 x 19 x1024 -> 19 x 19 x1024
75 conv 512 1 x 1 / 1 19 x 19 x1024 -> 19 x 19 x 512 0.379 BFLOPs
76 conv 1024 3 x 3 / 1 19 x 19 x 512 -> 19 x 19 x1024 3.407 BFLOPs
77 conv 512 1 x 1 / 1 19 x 19 x1024 -> 19 x 19 x 512 0.379 BFLOPs
78 conv 1024 3 x 3 / 1 19 x 19 x 512 -> 19 x 19 x1024 3.407 BFLOPs
79 conv 512 1 x 1 / 1 19 x 19 x1024 -> 19 x 19 x 512 0.379 BFLOPs
80 conv 1024 3 x 3 / 1 19 x 19 x 512 -> 19 x 19 x1024 3.407 BFLOPs
81 conv 255 1 x 1 / 1 19 x 19 x1024 -> 19 x 19 x 255 0.189 BFLOPs
82 yolo
83 route 79
84 conv 256 1 x 1 / 1 19 x 19 x 512 -> 19 x 19 x 256 0.095 BFLOPs
85 upsample 2x 19 x 19 x 256 -> 38 x 38 x 256
86 route 85 61
87 conv 256 1 x 1 / 1 38 x 38 x 768 -> 38 x 38 x 256 0.568 BFLOPs
88 conv 512 3 x 3 / 1 38 x 38 x 256 -> 38 x 38 x 512 3.407 BFLOPs
89 conv 256 1 x 1 / 1 38 x 38 x 512 -> 38 x 38 x 256 0.379 BFLOPs
90 conv 512 3 x 3 / 1 38 x 38 x 256 -> 38 x 38 x 512 3.407 BFLOPs
91 conv 256 1 x 1 / 1 38 x 38 x 512 -> 38 x 38 x 256 0.379 BFLOPs
92 conv 512 3 x 3 / 1 38 x 38 x 256 -> 38 x 38 x 512 3.407 BFLOPs
93 conv 255 1 x 1 / 1 38 x 38 x 512 -> 38 x 38 x 255 0.377 BFLOPs
94 yolo
95 route 91
96 conv 128 1 x 1 / 1 38 x 38 x 256 -> 38 x 38 x 128 0.095 BFLOPs
97 upsample 2x 38 x 38 x 128 -> 76 x 76 x 128
98 route 97 36
99 conv 128 1 x 1 / 1 76 x 76 x 384 -> 76 x 76 x 128 0.568 BFLOPs
100 conv 256 3 x 3 / 1 76 x 76 x 128 -> 76 x 76 x 256 3.407 BFLOPs
101 conv 128 1 x 1 / 1 76 x 76 x 256 -> 76 x 76 x 128 0.379 BFLOPs
102 conv 256 3 x 3 / 1 76 x 76 x 128 -> 76 x 76 x 256 3.407 BFLOPs
103 conv 128 1 x 1 / 1 76 x 76 x 256 -> 76 x 76 x 128 0.379 BFLOPs
104 conv 256 3 x 3 / 1 76 x 76 x 128 -> 76 x 76 x 256 3.407 BFLOPs
105 conv 255 1 x 1 / 1 76 x 76 x 256 -> 76 x 76 x 255 0.754 BFLOPs
106 yolo
Loading weights from yolov3.weights...Done!
data/dog.jpg: Predicted in 0.063622 seconds.
dog: 100%
truck: 92%
bicycle: 99%
Gtk-Message: 20:09:45.990: Failed to load module "canberra-gtk-module"
伴随这输出的还有一张如下的图片
更改检测阈值和检测多张图片的详情见官网
不需要给定测试图片的路径,直接输入以下指令,然后程序会提示你输入测试图像路径,直到ctrl+c退出程序。
./darknet detect cfg/yolo.cfg yolo.weights
基于yolo.weights模型参数,使用“-thresh"参数控制显示的bounding-box个数,darknet默认只显示被检测的物体中confidence大于或者等于0.25的bounding-box,可以通过参数-thresh
实时摄像头检测 / webcam检测,使用到cuda和opencv编译darknet。
终端输入:
./darknet detector demo cfg/coco.data cfg/yolov3.cfg yolov3.weights
video检测,使用opencv检测视频。
终端输入:
./darknet detector demo cfg/coco.data cfg/yolov3.cfg yolov3.weights
如果想使用不同的训练方案,可以从头开始训练yolo。这里先训练官网数据集。voc数据集或者coco数据集。
参照官网步骤
wget https://pjreddie.com/media/files/VOCtrainval_11-May-2012.tar
wget https://pjreddie.com/media/files/VOCtrainval_06-Nov-2007.tar
wget https://pjreddie.com/media/files/VOCtest_06-Nov-2007.tar
tar xf VOCtrainval_11-May-2012.tar
tar xf VOCtrainval_06-Nov-2007.tar
tar xf VOCtest_06-Nov-2007.tar
指令解释:
(1)wget命令用来从指定的URL下载文件。wget非常稳定,它在带宽很窄的情况下和不稳定网络中有很强的适应性,如果是由于网络的原因下载失败,wget会不断的尝试,直到整个文件下载完毕。如果是服务器打断下载过程,它会再次联到服务器上从停止的地方继续下载。这对从那些限定了链接时间的服务器上下载大文件非常有用。
(2)tar解压命令。-x:解压。-f: 使用档案名字,切记,这个参数是最后一个参数,后面只能接档案名。
上述命令是从作者的数据仓库中下载数据,可能比较慢。可从Pascal_voc的官网下载数据:2007数据集和2012数据集(在development kit中下载)
将三个解压后的文件,放在文件夹VOCdevkit中。
wget https://pjreddie.com/media/files/voc_label.py
python3 voc_label.py
执行指令查看目前路径下的文件
ls
可以看到包括了如下几个文件
2007_test.txt, 2007_train.txt, 2007_val.txt, 2012_train.txt, 2012_val.txt
cat 2007_train.txt 2007_val.txt 2012_*.txt > train.txt
指令解释:cat 命令用于连接文件并打印到标准输出设备上。指令作用是把2007_train.txt 和2007_val.txt 和2012_*.txt的内容全部输出到 train.txt文本中。
classes= 3 #修改为自己的类别数
train = /home/learner/darknet/data/voc/train.txt #修改为自己的路径
valid = /home/learner/darknet/data/voc/2007_test.txt #修改为自己的路径
names = /home/learner/darknet/data/voc.names #修改见voc.names文件
backup = /home/learner/darknet/backup #修改为自己的路径,输出的权重信息将存储这个文件内
head #改为自己需要探测的类别,一行一个
eye
nose
wget https://pjreddie.com/media/files/darknet53.conv.74
[net]
# Testing
batch=64
subdivisions=32 #每批训练的个数=batch/subvisions,根据GPU修改,显存不够值就大一些
# Training
# batch=64
# subdivisions=16
……
learning_rate=0.001
burn_in=1000
max_batches = 50200 #训练步数
policy=steps
steps=40000,45000 #开始衰减的步数
scales=.1,.1
[convolutional]
.....
[convolutional]
……
[yolo]
……
classes=3 #修改为自己的类别数
……
[route]
layers = -4
[convolutional]
……
[upsample]
stride=2
[route]
layers = -1, 61
[convolutional]
……
[convolutional]
……
[convolutional]
……
[convolutional]
……
[convolutional]
……
[convolutional]
……
[convolutional]
……
[yolo]
……
classes=3 #修改为自己的类别数
……
[route]
layers = -4
[convolutional]
……
[upsample]
stride=2
[route]
layers = -1, 36
[convolutional]
……
[convolutional]
……
[convolutional]
……
[convolutional]
……
[convolutional]
……
[convolutional]
……
[convolutional]
……
[yolo]
……
classes=3 #修改为自己的类别数
……
#单GPU训练的指令,除此之外还有多GPU训练
./darknet detector train cfg/voc.data cfg/yolov3-voc.cfg darknet53.conv.74
#include
安装labelImg
git clone https://github.com/tzutalin/labelImg
sudo apt-get install pyqt4-dev-tools #安装PyQt4
sudo pip3 install lxml#这里应该使用pip指令
cd labelImg
make -j12 all
python3 labelImg.py#这里应该使用python指令
注意在制作自己数据集,标注图片时的类别名称用小写名字,不要用大写字母。
上面的命令执行后出现如下错误:
指令
labelImg$ make -j12
显示
make: pyrcc5: Command not found
Makefile:24: recipe for target 'qt5py3' failed
make: *** [qt5py3] Error 127
ERROR: test_qt (unittest.loader._FailedTest)
ImportError: Failed to import test module: test_qt
ModuleNotFoundError: No module named 'PyQt5'
ModuleNotFoundError: No module named 'sip'
ERROR: test_stringBundle (unittest.loader._FailedTest)
ImportError: Failed to import test module: test_stringBundle
Makefile:11: recipe for target 'testpy3' failed
make: *** [testpy3] Error 1
指令
python3 labelImg.py
显示
ModuleNotFoundError: No module named 'PyQt5'
PyQt是一个用于创建GUI应用程序的跨平台工具包,它将python与Qt库融为一体。Qt是使用c++语言编写的GUI库。PyQt允许python语言调用Qt库中的API。
出现上面的错误后,我就先去验证PyQt4是否安装成功。检查方式是在终端输入:
python
import PyQt4
注意:输入指令时,不要把大写模块名写成小写。
结果,能够导入成功。
我继续验证
python3
import PyQt4
结果:不能导入成功。
lxml是python的一个解析库,支持HTML和XML的解析,支持XPath解析方式,XPath,全称XML Path Language,即XML路径语言,它是一门在XML文档中查找信息的语言,最初用来搜寻XML文档,同样适用于HTML文档的搜索。检测安装是否成功的方法:
python3
import lxml
总结:出现上面错误的原因是因为PyQt与Python关联,而安装的lxml与Python3关联。解决办法是再重新安装PyQt5,在终端执行:
sudo apt-get install pyqt5-dev-tools
cd labelImg
make qt5py3 # 用make all 会导致先识别pyqt4
python3 labelImg.py
总结:安装labelImg的正确完整步骤:
sudo apt-get install pyqt5-dev-tools
sudo pip3 install lxml
git clone https://github.com/tzutalin/labelImg.git
cd labelImg
make qt5py3 # 用make all 会导致先识别pyqt4
python3 labelImg.py #打开labelImg
classes= 3 #有几类就改成几类
train = /自己的路径/VOCdevkit/VOC2012/2012_train.txt
valid = /自己的路径/VOCdevkit/VOC2012/2012_test.txt
names = /自己的路径/data/voc.names
backup = /自己的路径/results
cd darknet
./darknet detector train wp_data/cfg/voc.data wp_data/cfg/yolov3-voc.cfg 2>&1 | tee wp_data/visualization/train_yolov3.log #保存训练日志
#上条代码解释:./darknet表示编译后的执行文件,detector train是指令,train表示是训练的过程。wp_data/cfg/voc.data表示的是wp_data/cfg路径下的文件voc.data。wp_data/cfg/yolov3-voc.cfg表示的是wp_data/cfg路径下的文件yolov3-voc.cfg。2>&1 | tee wp_data/visualization/train_yolov3.log表示保存日志,为了后续绘制loss曲线。若没有这条语句就不会保存日志。
训练好后可以在backup看到权重文件,尝试test前要修改cfg文件,切换到test状态。注释掉train,打开test。输入测试的终端命令:
./darknet detector test cfg/voc.data cfg/yolov3-voc.cfg backup/yolov3-voc.weights
代码解释:命令detector test后面是三个参数:
cfg/voc.data表示cfg路径下的voc.data
cfg/yolov3-voc.cfg表示cfg路径下的yolov3-voc.cfg
backup/yolov3-voc.weights表示backup路径下的yolov3-voc.weights
执行后测试集里的图片会一张张显示出测试结果。
参考计算准确率
darknet分类没有像caffe一样训练的同时,日志文件输出测试集的准确率,但提供了valid函数来输出top-1的准确率。
终端命令如下:
./darknet classifier valid cfg/door.data cfg/darknet19.cfg classify_result/darknet19_18.weights
用相同的数据集对比caffe pytorch框架,用近似的网络训练,darknet框架训练的平均loss更低,准确率更高,模型的泛化能力更好,对比caffe,没有第三方库,c也更方便移植到嵌入式平台。
训练过程中输出的参数的意义
参考:darknet卷积层浅层可视化
参考测试结果可视化
cd darknet
./darknet detector train wp_data/cfg/voc.data wp_data/cfg/yolov3-voc.cfg 2>&1 | tee wp_data/visualization/train_yolov3.log
'''
该文件用来提取训练log,去除不可解析的log后使log文件格式化,生成新的log文件再用可视化工具绘图
'''
import inspect
import os
import random
import sys
def extract_log(log_file,new_log_file,key_word):
with open(log_file.'r')as f:
with open(new_log_file,'w')as train_log:
for line in f:
# 去除多gpu的同步log
if 'Syncing' in line:
continue
# 去除除零错误的bug
if 'nan' in line:
continue
if key_word in line:
train_log.write(line)
f.close()
train_log.close()
# 运行后会解析出log文件的loss行和iou行得到两个txt文件。
extract_log('train_yolov3.log','train_log_loss.txt','images')
extract_log('train_yolov3.log','train_log_iou.txt','IOU')
'''
可视化yolo v3-darknet训练过程日志中的loss
运行该程序后会在脚本所在路径生成avg_loss.png,可以通过分析损失变化函数,修改cfg中的学习率变化策略
'''
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# 根据train_log_loss.txt的行数修改lines值
lines=25100
result=pd.read_csv('train_log_loss.txt',skiprows=[x for x in range(lines)],error_bad_lines=False,names=['loss','avg','rate','seconds','images'])
result.head()
result['loss']=result['loss'].str.split('').str.get(1)
result['avg']=result['avg'].str.split('').str.get(1)
result['rate']=result['rate'].str.split('').str.get(1)
result['seconds']=result['seconds'].str.split('').str.get(1)
result['images']=result['images'].str.split('').str.get(1)
result.head()
result.tail()
import numpy as np
import matplotlib.pyplot as plt
lines=9873
result=pd.read_csv('train_log_loss.txt',skipows=[x for x in range(lines) if((x<1000))],error_vad_lines=False,names=['loss','avg','rate','seconds','images'])
result.head()
result['loss']=result['loss'].str.split('').str.get(1)
result['avg']=result['avg'].str.split('').str.get(1)
result['rate']=result['rate'].str.split('').str.get(1)
result['seconds']=result['seconds'].str.split('').str.get(1)
result['images']=result['images'].str.split('').str.get(1)
result.head()
result.tail()
print(result['loss'])
print*result['avg']
print(result['rate'])
print(result['seconds'])
print(result['images'])
result['loss']=pd.to_numeric(result['loss'])
result['avg']=pd.to_numeric(result['avg'])
result['rate']=pd.to_numeric(result['seconds'])
result['images']=pd.to_numeric(result['images'])
result.dtypes
fig=plt.figure()
ax=fig.add_subplot(1,1,1)
ax.plot(result['avg'].values,label='avg_loss')
ax.legend(loc='best')
ax.set_title('The loss curves')
ax.set_xlabel('batches')
fig.savefig('avg_loss')
print(result['loss'])
print(result['avg'])
print(result['rate'])
print(result['seconds'])
print(result['images'])
result['loss']=pd.to_numeric(result['loss'])
result['avg']=pd.to_numeric(result['avg'])
result['rate']=pd.to_numeric(result['rate'])
result['seconds']=pd.to_numeric(result['seconds'])
result['images']=pd.to_numeric(result['images'])
result.dtypes
fig=plt.figure()
ax=fig.add_subplot(1,1,1)
ax.plot(result['avg'].values,label='avg_loss')
ax.legend(loc='best')
ax.set_title('The loss curves')
ax.set_xlabel('batches')
fig.savefig('avg_loss')
# 修改上面代码中的lines为train_log_loss.txt中的行数,并且根据需要修改要跳过的行数。
skiprows=[x for x in range(lines) if (x%10!=9)|(x<1000)]
'''
可视化yolo v3-darknet训练过程日志中的参数
可以可视化的参数包括:Region Avg IOU / Class / Obj / No Obj / Avg Recall / Count等
运行该程序会在脚本所在路径生成相应的曲线图
'''
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# 根据train_log_iou.txt的行数值来修改lines值
lines=122956
result=pd.read_csv('train_log_iou.txt',skiprows=[x for x in range(lines) if(x%10==0 or x%10==9)],error_bad_lines=False,names=['Region Avg IOU','Class','Obj','No Obj','Avg Recall','Count'])
result.head()
result['Region Avg IOU']=result['Region Avg IOU'].str.get(1)
result['class']=result['class'].str.split(':').str.get(1)
result['Obj']=result['Obj'].str.split(':').str.get(1)
result['No Obj']=result['No Obj'].str.split(':').str.get(1)
result['Avg Recall']=result['Avg Recall'].str.split(':').str.get(1)
result['Count']=result['Count'].str.split(':').str.get(1)
result.head()
result.tail()
print(result['Region Avg IOU'])
result['Region Avg IOU']=pd.to_numeric(result['Region Avg IOU'])
result['class']=pd.to_numeric(result['Class'])
result['Obj']=pd.to_numeric(result['Obj'])
result['No ObJ']=pd.to_numeric(result['No Obj'])
result['Avg Recall']=pd.to_numeric(result['Avg Recall'])
result['Count']=pd.to_numeric(result['Count'])
result.dtypes
fig=plt.figure()
ax=fig.add_subplot(1,1,1)
ax.plot(result['Region Avg IOU'].values,label='Region Avg IOU')
ax.legend(loc='best')
ax.set_title('The Region Avg IOU curves')
ax.set_xlabel('batches')
fig.savefig('Region Avg IOU')