大二菜鸡,因为要准备一个水下识别的比赛,想到了用yolov3这个强大的框架,参考了许多大佬的博客,在这里记录一下自己的配置过程。
**
**
我的显卡的GTX1060,因为之前为了安装Tensorflow2.0,所以选择CUDA10.0。
下载地址在这:
https://developer.nvidia.com/cuda-10.0-download-archive?target_os=Windows&target_arch=x86_64&target_version=10&target_type=exelocal
下载可能会有点慢,请耐心等待
CUDA和CUDNN的安装过程参考了这个博客(不用安装tensorflow):
Tensorflow2.0+Anaconda + Windows10+cuda10.0+python3.7+spyder安装教程
在这里要特别提醒一下,在运行CUDA的安装程序的时候记得去C盘找一下C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v9.0\extras\visual_studio_integration\MSBuildExtensions这个文件,把它复制一下,之后在配置VS的时候有用。我之后配置的时候在我的CUDA目录下找不到这个文件夹,在网上查了一下这个是只在安装时出现的默认文件,可在"C:\Users\用户名\AppData\Local\Temp\CUDA"下找到。
**
**
这步很简单,我用的是比较老的3.4.0版,在网站上选择WINDOWS下载即可,网站在这:
官网下载连接
双击下载好的exe文件,选择解压路径后点击Extract即可,解压后会生成一个opencv的文件夹。
将解压后的…opencv\build\x64\vc14\bin添加到环境变量
到这opencv就安装好了。
**
**
首先在Github官网下载压缩包:
https://github.com/AlexeyAB/darknet
下面可按照这篇博客进行配置(点之前先看一下我下面的说明,配置属性看我的就可以了,我觉得他给的不太详细):
Win10上darknet-yolov3的配置及使用(VS2019)GPU+OpenCV
我们安装的就是CUDA10,博客的步骤一我们可以忽略
步骤二在配置属性->常规->平台工具集处选择Visual Studio 2015(v140),如果你的VS上在Visual Studio 2015(v140)后面显示未安装(我记得是这三个字),请看这里:
在Vistual Studio Installer中选择修改->单个组件->编译器、生成工具和运行时 选择MSVC v140
步骤四就用到了我在CUDA安装那块提到的4个文件,按照他说的放入对应文件夹。奇怪的是我的MSBuild最初并没有Microsoft.Cpp这个文件,是先把那四个文件放入VS2019的BuildCustomizations目录下运行失败了一次才出现的Microsoft.Cpp\v4.0\V140\BuildCustomizations。
步骤五 配置属性
之前你以前打开了darknet-master\build\darknet\darknet.sln,现在来配置属性,这里我推荐看这篇博客,保证正确,就是注意一下平台工具集咱们用的是2015版的v140工具集和CUDA版本与他不同,无需修改:
win10+vs2017+yolov3+opencv3.4实时目标检测
在所有属性都配置完成后,就可以编译darknet了。
编译成功后下载权重:
https://pjreddie.com/media/files/yolov3.weights
放到darknet-master\build\darknet\x64下
将…\opencv\build\x64\vc14\bin下的opencv_world340.dll 和opencv_world340d.dll 复制到 darknet-master\build\darknet\x64的同级别目录下就可以运行测试图片或视频了,注意视频好像没有例子,自己找一段mp4命名为test放到x64下就可以运行darknet_yolo_v3_video.cmd测试了。
**
**
这里直接给出参考博客,写的很详细,有一些细节我也会列出:
Yolov3:win10下训练自己的数据(GPU版)(详细步骤)
如果没有自己的数据集只是想尝试一下的话可以下载VOC的数据集来当测试,地址如下:
https://pjreddie.com/projects/pascal-voc-dataset-mirror/
因为是测试,在这里我建议选择VOC2007,数据比较少。
下载之后解压出来是一个叫VOCdevkit的文件夹,我们制作自己的数据集时就按照这种文件格式来就行。
比如我的数据集是自己选取的500张有关海参、海胆、扇贝的图像,标注完的文件在E:\darknet-master\scripts\VOCdevkit\VOC2020下格式如下:
注意,划掉的labels文件夹在制作时是没有的,是运行voc_label.py之后生成的
Annotations放标注的xml文件,JPEGImages放图片,ImageSets里的Main文件放训练和验证的图片编号,如图:
在自己制作数据集时可用美图秀秀的批处理软件处理图片编号。
这里给出对应VOC2007和我自己数据集的voc_label.py代码
VOC2007
import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join
sets=[('2007', 'train'), ('2007', 'val'), ('2007', 'test')]
classes = ["aeroplane", "bicycle", "bird", "boat", "bottle", "bus", "car", "cat", "chair", "cow", "diningtable", "dog", "horse", "motorbike", "person", "pottedplant", "sheep", "sofa", "train", "tvmonitor"]
def convert(size, box):
dw = 1./size[0]
dh = 1./size[1]
x = (box[0] + box[1])/2.0
y = (box[2] + box[3])/2.0
w = box[1] - box[0]
h = box[3] - box[2]
x = x*dw
w = w*dw
y = y*dh
h = h*dh
return (x,y,w,h)
def convert_annotation(year, image_id):
in_file = open('E:\\darknet-master\\scripts\\VOCdevkit\\VOC%s\\Annotations\\%s.xml'%(year, image_id))
out_file = open('E:\\darknet-master\\scripts\\VOCdevkit\\VOC%s\\labels\\%s.txt'%(year, image_id), 'w')
tree=ET.parse(in_file)
root = tree.getroot()
size = root.find('size')
w = int(size.find('width').text)
h = int(size.find('height').text)
for obj in root.iter('object'):
difficult = obj.find('difficult').text
cls = obj.find('name').text
if cls not in classes or int(difficult) == 1:
continue
cls_id = classes.index(cls)
xmlbox = obj.find('bndbox')
b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text), float(xmlbox.find('ymax').text))
bb = convert((w,h), b)
out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')
wd = getcwd()
for year, image_set in sets:
if not os.path.exists('E:\\darknet-master\\scripts\\VOCdevkit\\VOC%s\\labels\\'%(year)):
os.makedirs('E:\\darknet-master\\scripts\\VOCdevkit\\VOC%s\\labels\\'%(year))
image_ids = open('E:\\darknet-master\\scripts\\VOCdevkit\\VOC2007\\ImageSets\\Main\\train.txt').read().strip().split()
list_file = open('%s_%s.txt'%(year, image_set), 'w')
for image_id in image_ids:
list_file.write('E:\\darknet-master\\build\\darknet\\x64\\data\\obj\\%s.jpg\n'%(image_id))
convert_annotation(year, image_id)
list_file.close()
我自己的数据集
import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join
sets=[('2020', 'train'), ('2020', 'val')]
classes = ["holothurian", "echinus", "scallop"]
def convert(size, box):
dw = 1./size[0]
dh = 1./size[1]
x = (box[0] + box[1])/2.0
y = (box[2] + box[3])/2.0
w = box[1] - box[0]
h = box[3] - box[2]
x = x*dw
w = w*dw
y = y*dh
h = h*dh
return (x,y,w,h)
def convert_annotation(year, image_id):
in_file = open('E:\\darknet-master\\scripts\\VOCdevkit\\VOC%s\\Annotations\\%s.xml'%(year, image_id))
out_file = open('E:\\darknet-master\\scripts\\VOCdevkit\\VOC%s\\labels\\%s.txt'%(year, image_id), 'w')
tree=ET.parse(in_file)
root = tree.getroot()
size = root.find('size')
w = int(size.find('width').text)
h = int(size.find('height').text)
for obj in root.iter('object'):
difficult = obj.find('difficult').text
cls = obj.find('name').text
if cls not in classes or int(difficult) == 1:
continue
cls_id = classes.index(cls)
xmlbox = obj.find('bndbox')
b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text), float(xmlbox.find('ymax').text))
bb = convert((w,h), b)
out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')
wd = getcwd()
for year, image_set in sets:
if not os.path.exists('E:\\darknet-master\\scripts\\VOCdevkit\\VOC%s\\labels\\'%(year)):
os.makedirs('E:\\darknet-master\\scripts\\VOCdevkit\\VOC%s\\labels\\'%(year))
image_ids = open('E:\\darknet-master\\scripts\\VOCdevkit\\VOC2020\\ImageSets\\Main\\train.txt').read().strip().split()
list_file = open('%s_%s.txt'%(year, image_set), 'w')
for image_id in image_ids:
list_file.write('E:\\darknet-master\\build\\darknet\\x64\\data\\obj\\%s.jpg\n'%(image_id))
convert_annotation(year, image_id)
list_file.close()
运行成功后应该有这些txt文件,就是图片的地址:
之后继续按照上面博客的内容进行就可以了。在这里特别提醒一下要把之前voc_label.py生成的labels里的txt文件也放入E:\darknet-master\build\darknet\x64\data\obj文件夹,这是由xml转成的txt文件,就是你标注的数据。博客里没细说我忘了放了结果训练了半天一看全是nan…
数据都放好之后在E:\darknet-master\build\darknet\x64下打开cmd,输入:
darknet.exe detector train data/voc.data yolov3-voc.cfg darknet53.conv.74 data/weights >> yolov3.log
耐心等待就好了,每1000轮会在weights文件夹里生成一个权重,比如1000轮就叫叫yolov3-voc_1000.weights
下面可以用来测试,同样在E:\darknet-master\build\darknet\x64下打开cmd,然后输入:
darknet.exe detector test data/voc.data yolov3-voc.cfg data/yolov3-voc_1000.weights -thresh 0.1
这里的-thresh就是置信度,我一开始测的1000轮的权重发现测试图片没有识别框,因为不加**-thresh 0.1**的话置信度默认0.25,对于训练轮数很少的情况下肯定没有框啦!这个0.1可按自己的情况调整,最后附上我的预测结果: