使用yolov3跑自己的数据集(图片、摄像头均可使用)——积木实验

一、下载及安装darknet

1、下载darknet

2、下载imageNet权重

wget https://pjreddie.com/media/files/darknet53.conv.74

3、进入darknet编译

cd darknet

修改Makefile的GPU和OPENCV

make

此时完成darknet的安装

假如make的时候出现了

error:/usr/bin/ld: 找不到 -lippicv
collect2: error: ld returned 1 exit status

那么,就找到-lippicv对应的库(libippicv.a),该库位于安装目录opencv-3.1.0/3rdparty/ippicv/unpack/ippicv_lnx/lib/intel64文件夹下 ,进入该文件夹下执行

sudo cp libippicv.a /usr/local/lib/即可  

继续执行make 即可

假如找不到nvcc

解决方法:修改darknet下的Makefile文件,将其中的NVCC=nvcc改为/usr/local/cuda-*/bin/nvcc即安装的cuda版本信息

保存  继续执行make 即可

二、制作数据集及anchor box生成

1、将combine_bbox.py combine_train_val.py kmeans.py 放到darknet新建的shell目录下

运行这些py程序之前,需要安装numpy和pandas

sudo apt-get install python-numpy
sudo apt-get install python-pandas

2、使用Label_Img来获得txt文件,其中的txt文件包括所截取ROI所属的类别,以及其归一化的参数

将图片及其对应的txt文件放在一个文件夹(train_data)中,并将该train_data文件放到darknet目录下:

2、由于数据集的尺寸大小为1062*598,所以要修改combine_bbox.py中的乘子,改为图片的长宽

其中,image_path为刚才train_data的目录地址,改为../train_data

运行它python combine_bbox.py,可在上层目录生成TXT文件for_kmeans.txt

3、kmeans.py中的for_kmeans.txt文件的路径也需要修改,保证能读取到for_kmeans.txt

并将yolo_anchors.txt的生成地址改成你所需要的,这里我改成上层目录,运行kmeans.py

原理:https://blog.csdn.net/hrsstudy/article/details/71173305?utm_source=itdadao&utm_medium=referral

可以看到,上层目录生成了

4、将数据分成训练集和测试集两个文件夹(即将刚才train_data中的一部分数据集cut到同一层的文件夹val_data中(连同txt文件)

5、进入shell目录,修改combine_train_val.py中的train_dir 和val_dir 为刚才训练集和测试集的目录,并修改生成的train.txt和val.txt的生成目录,这里我将其生成目录设为上层目录

运行它,即可在上层目录得到两个txt文件

三、文件配置

1、首先将darknet/cfg下的yolov3.cfg复制一个,将其命名为test.cfg,修改:

1)修改batch,当出现out of memory时可以考虑改batch(调小),意为一次处理多少张图片

2)修改subdivisions=8

(1080ti显存最多支持到batch=96 subdivisons=8 random=0)

random为多尺度训练如图像中的物体大小不一差距很大的话,建议开启。但是比较占用显存

如果batch太小数据量也很少会导致训练时有大量nan

修改的时候注释掉两个没有注释的,改两个注释了的,因为是训练

3)修改三个yolo层前面的卷积层filters的大小,改为(class数量+5)×3

4)修改yolo层中的class数量

修改yolo层中的anchor box(复制kmeans生成的那个yolo_anchors里面的)

其中[net]层中的learning_rate为学习率,max_batches为最大迭代次数

至此,cfg文件修改完成

2、将类别对应的txt文件改为block.names放入darknet/data中

3、在cfg文件夹中创建DATA.data,在里面输入几个部件的位置

classes 类别数

train = /.../ 训练集

valid = /.../ 测试集

names = data/xxx.names 类别名称

backup = backup 在darnet新建一个backup目录,存储.weight

经过上述修改之后,记得重新make一下darknet

四、训练及使用

如果不需要使用服务器,直接运行

./darknet detector train cfg/DATA.data cfg/test.cfg darknet53.conv.74 -gpus 0,1

如果需要使用服务器:

1、首先连接服务器开一个终端链接服务器

ssh -X [email protected]

cd /media/user/SSD4T1/Test

pwd

得到目录后复制

2、然后,打开另一个终端,将darknet传到服务器上

scp -r darknet [email protected]:/media/user/SSD4T1/TestDarknet

此时,目录下就会出现上传至服务器的文件

3、进入darknet,修改文件

由于我们要执行下面这句指令

./darknet detector train cfg/DATA.data cfg/test.cfg darknet53.conv.74 -gpus 0,1

所以,需要修改DATA.data部件

将它们的地址改为服务器上对应的地址

cd darknet

cd cfg

vi DATA.data

再修改shell中的combine_train_val.py的地址,改为服务器的地址

运行一下它

最终的weights都会生成在darknet/backup目录下

在跑训练的时候,在训练log中会出现各种参数,下面是各参数的意义

Class:标注物体的概率,期望该值趋近于1

Obj:期望该值趋近于1

No Obj:期望该值越来越小但不为0

Avg ReCall:期望该值趋近于1

avg:平均损失,期望该值趋近于0

rate:当前学习率

跑的过程中,1000batch以下为每100×gpu数量个batch保存一次,可以再example/detector.c的第138行修改保存时机,这里我改到6000,跑的差不多了之后,会备份在test.backup中,假如你中间还想继续跑,那么就用这个东西替换conv53,再运行

./darknet detector train cfg/DATA.data cfg/test.cfg backup/test.backup -gpus 0,1

好,训练完成,接下来会在backup目录下得到weights文件,我们需要用这个文件去做测试

./darknet detector test cfg/DATA.data cfg/test.cfg backup/xxx.weights test_data/xxx.jpg

如果需要使用摄像头,就调用下面的命令

./darknet detector demo cfg/ xxx.data cfg/xxx.cfg xxx.weights usb摄像头(默认video0)

跑完以后,可以得到下面的结果

对下面这种存在漏检的情况,分析可能是因为漏检样本的训练集不够造成的,因为我发现测试集上的蓝色圆形积木有几个都没有识别出来

对于比较简单的情况,可以识别完全正确

对于这种垂直方向看的测试集,有时会把圆的识别成方的,这也难怪,因为人眼看的时候你有时都很难分辨出它是圆的还是方的

其他的测试结果我就不一一展示了

这里我还用摄像头跑了yolo,416的输入下FPS是12

发现有点慢了,于是修改参数,这时FPS达到了16,满足了实时性要求

分析部分

参考自:https://blog.csdn.net/yudiemiaomiao/article/details/72469135

首先在darknet目录下新建一个文件夹,将其命名为analyse

一、yolo模型训练可视化

在训练的过程中,或者训练结束的时候,需要检测各项指标(如loss)是否达到了期望的数值,比如

Class:标注物体的概率,期望该值趋近于1

Obj:期望该值趋近于1

No Obj:期望该值越来越小但不为0

Avg ReCall:期望该值趋近于1

avg:平均损失,期望该值趋近于0

rate:当前学习率

通过这些参数来帮助我们分析问题。

如果需要可视化中间参数,可以保存训练时输出的日志文件,通过下面的指令来在训练的同时保存训练日志

./darknet detector train cfg/DATA.data cfg/test.cfg darknet53.conv.74 -gpus 0,1 | tee train_log.txt

这样,在darknet目录下就会生成一个train_log.txt文件,这里面输出的是训练时的参数信息

1)首先需要将该日志信息格式化成新的log文件,便于可视化工具绘图,新建一个format_log.py文件:

# coding=utf-8
# 该文件用来提取训练log,去除不可解析的log后使log文件格式化,生成新的log文件供可视化工具绘图

def format_log(log_file,new_log_file,key_word):
    
    f = open(log_file)
    log = open(new_log_file, 'w')
    for line in f:
        # 去除多gpu的同步log
        if 'Syncing' in line:
            continue
        # 去除除零错误的log
        if 'nan' in line:
	    continue
        if key_word in line:
            log.write(line)
    f.close()
    log.close()

format_log('../train_log.txt','train_loss.txt','images')   #voc_train_log.txt 用于绘制loss曲线
format_log('../train_log.txt','train_IoU.txt','IOU')

运行它,这样,就可以在当前目录下得到train_loss.txt和train_IoU.txt两个文件

2)loss变化曲线的绘制

首先确认你安装了pandas,如果没有安装的话需要执行

sudo apt-get install python-pandas

附:如果需要安装numpy的话,请访问该地址,里面有不同的版本,可根据自己情况选择

https://sourceforge.net/projects/numpy/files/NumPy/

然后,在终端输入

sudo apt-get install python-numpy

安装完成后,

在analyse目录下新建一个train_loss_visualization.py文件

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
#%matplotlib inline

lines =1705
result = pd.read_csv('train_loss.txt', skiprows=[x for x in range(lines) if ((x%10!=9) |(x<1000))] ,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()

#print(result.head())
# print(result.tail())
# print(result.dtypes)

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.plot(result['loss'].values,label='loss')
ax.legend(loc='best')
ax.set_title('The loss curves')
ax.set_xlabel('batches')
fig.savefig('avg_loss')
#fig.savefig('loss')

修改train_loss_visualization.py中lines为train_log.txt的行数,并根据需要修改要跳过的行数

skiprows=[x for x in range(lines) if ((x%10!=9) |(x<1000))]
运行它,即可在当前路径生成一个训练loss变化曲线avg_loss.png

3)可视化Avg IOU,Avg Recall等参数

新建一个train_iou_visualization.py,使用方法同上

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
#%matplotlib inline

lines =55022
result = pd.read_csv('train_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.split(': ').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.head())
# print(result.tail())
# print(result.dtypes)
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.plot(result['Class'].values,label='Class')
#ax.plot(result['Obj'].values,label='Obj')
#ax.plot(result['No Obj'].values,label='No Obj')
#ax.plot(result['Avg Recall'].values,label='Avg Recall')
#ax.plot(result['count'].values,label='count')
ax.legend(loc='best')
#ax.set_title('The Region Avg IOU curves')
ax.set_title('The Region Avg IOU curves')
ax.set_xlabel('batches')
#fig.savefig('Avg IOU')
fig.savefig('Region Avg IOU')

评估性能

参考自:https://blog.csdn.net/hysteric314/article/details/54093734

首先学习一下召回率(Recall),精确率(Precision),平均正确率(Average_precision(AP)),交并比(intersection-over-Union(IoU))

上面通过对测试集进行测试,可以围绕测试集介绍这几个概念

定义:

True positives:测试集中A被正确识别成了A

True negatives:测试集中B没有被识别出来,你的分类系统正确地认为它们是B

False positives:测试集中的B被错误地识别为了A

False negatives:测试集中的A没有被识别出来,分类系统错误地认为它们是B

精确率(precision):

精确率是测试集中识别出来的图片中,True positives所占的比率

n为分类系统一共识别出来多少张图片,在下面的结果中

假如是红色方框,它有1个被正确识别,但可以看到,有一个圆的也被错误地识别成了红色方形积木

所及它的精确率就是1/(1+1)=0.5

召回率(Recall):

召回率是指被正确识别出来的A的个数与测试集中所有A的个数的比值

比如上面的图,有1个圆形的积木没有被识别出来,而有4个被正确识别了,那么召回率就是

4/(4+1)

调整阈值:

这里有一个计算IOU的脚本可以使用

https://blog.csdn.net/eddy_zheng/article/details/52126641

终极参考

https://blog.csdn.net/gojawee/article/details/77508809

猜你喜欢

转载自blog.csdn.net/CSDN_dzh/article/details/81633913