# YOLO3 darknet训练自己的数据 (呼之) 本文内容列表 1 准备训练数据和验证数据 2 生成train.txt 和 val.txt 3 准备KD.names文件 4 准备KD.data文件 5 准备yolov3-KD.cfg_train文件 6 下载预训练权重 7 开始训练 8 测试 9 计算mAP 10 常见问题 如果照着本文的流程出现问题,可以查看第10常见问题,也许会有解决办法 本文将在darknet环境下用yolo3来训练自己的数据,如若未安装darknet,请参考下面的链接 GPU版本 JustDoIT:windows下darknet之yolo(gpu版本)安装 zhuanlan.zhihu.com 图标 CPU版本 JustDoIT:windows下darknet之YOLO3安装 zhuanlan.zhihu.com 图标 如果电脑有独显,建议使用GPU版本的,因为实在是快太多了 官方教程 https://github.com/AlexeyAB/darknet github.com 本文的数据和代码均可以在我github上找到 JustTryItNow/YOLO_images_script github.com 图标 1 准备训练数据和验证数据 收集图片 这里的图片我是从网上自己下载的,下载的是库里和杜兰特的图片。由于时间原因,只下载了50张图片,当然,这些数据对于训练一个很好的模型是远远不够的。当然,我也会把这些数据集放到百度云盘上,方便大家下载从而节省时间。把图片分到两个文件夹中,一个是train_images(一般放build\darknet\x64\data文件夹里),一个是val_images(一般放build\darknet\x64\data文件夹里)。 做标签 推荐labelImg 下载后解压缩,双击labelImg.exe出现下面的界面 点击Open Dir打开要做标签的文件夹,这里用train_images举例,val_images的操作一样 点击Create RectBox开始做标签(图片里面出现几个目标就标注几个框) 如下图,图片里有库里(KuLi)和杜兰特(DuLanTe),分别标注两个目标,然后点击Save,然后Next Image就可以标注下一张了 做完标签的两个文件夹分别是这样的 xml转txt 标签文件是xml格式的,yolo要求是txt(每张图片对应一个txt文件,txt的文件名要和图片的文件名一个) xml文件格式如下 而txt的格式要求每个标注框的格式如下 <object-class> <x_center> <y_center> <width> <height> <object-class> 类名:从0到(类别数-1),在这里一共有KuLI和DuLanTe两类,这里记KuLI为0,DuLanTe为 <x_center> 中心点横坐标:这里的坐标并不是绝对坐标(真实坐标),而是相对于图片宽度的相对坐标,转换公式为<x_center> = <absolute_x> / <image_width>,这里的absolute_x是指标注框中心的横坐标 <y_center> 中心点纵坐标:这里的坐标并不是绝对坐标(真实坐标),而是相对于图片高度的相对坐标,转换公式为<x_center> = <absolute_y> / <image_height>,这里的absolute_x是指标注框中心的纵坐标 <width> 标注框宽度:这里的宽度并不是绝对宽度(真实宽度),而是相对于图片宽度的相对宽度,转换公式为<width> = <absolute_width> / <image_width> <height> 标注框宽度:这里的宽度并不是绝对宽度(真实宽度),而是相对于图片宽度的相对高度,转换公式为<height> = <absolute_height> / <image_height> 对于上面的那个xml文件,其对应的txt文件内容应为 0 0.229 0.3605015673981191 0.063 0.10344827586206896 1 0.685 0.22100313479623823 0.061 0.10815047021943573 xml转txt代码(python3)如下: # 此代码和data文件夹同目录 import glob import xml.etree.ElementTree as ET # 类名 class_names = ['KuLi', 'DuLanTe'] # xml文件路径,train_images只需改为val_images就可以处理val_images的了 path = 'data/train_images/' # 转换一个xml文件为txt def single_xml_to_txt(xml_file): tree = ET.parse(xml_file) root = tree.getroot() # 保存的txt文件路径 txt_file = xml_file.split('.')[0]+'.txt' with open(txt_file, 'w') as txt_file: for member in root.findall('object'): # filename = root.find('filename').text picture_width = int(root.find('size')[0].text) picture_height = int(root.find('size')[1].text) class_name = member[0].text # 类名对应的index class_num = class_names.index(class_name) box_x_min = int(member[4][0].text) # 左上角横坐标 box_y_min = int(member[4][1].text) # 左上角纵坐标 box_x_max = int(member[4][2].text) # 右下角横坐标 box_y_max = int(member[4][3].text) # 右下角纵坐标 # 转成相对位置和宽高 x_center = (box_x_min + box_x_max) / (2 * picture_width) y_center = (box_y_min + box_y_max) / (2 * picture_height) width = (box_x_max - box_x_min) / picture_width height = (box_y_max - box_y_min) / picture_height print(class_num, x_center, y_center, width, height) txt_file.write(str(class_num) + ' ' + str(x_center) + ' ' + str(y_center) + ' ' + str(width) + ' ' + str(height) + '\n') # 转换文件夹下的所有xml文件为txt def dir_xml_to_txt(path): for xml_file in glob.glob(path + '*.xml'): single_xml_to_txt(xml_file) dir_xml_to_txt(path) 转换完的结果如下图: 转换完之后可以把xml删除掉,当然xml文件留着说不定以后还有用,建议剪切到其他地方。 ## **生成train.txt 和 val.txt (一般放build\darknet\x64\data文件夹里)** train.txt文件包含train_images中所有图片的路径,每个图片一行 val.txt文件包含val_images中所有图片的路径,每个图片一行 train.txt格式如下: data/train_images/1.jpg data/train_images/2.jpg 生成train.txt val.txt的代码如下: #此代码和data文件夹同目录 import glob path = 'data/' def generate_train_and_val(image_path, txt_file): with open(txt_file, 'w') as tf: for jpg_file in glob.glob(image_path + '*.jpg'): tf.write(jpg_file + '\n') generate_train_and_val(path + 'train_images/', path + 'train.txt') generate_train_and_val(path + 'val_images/', path + 'val.txt') 3 准备KD.names文件(一般放build\darknet\x64\data文件夹里) 这个文件每一行是一个类名(注意顺序),如下: KuLi DuLanTe 4 准备KD.data文件(一般放build\darknet\x64\data文件夹里) classes= 2 train = data/train.txt valid = data/val.txt names = data/KD.names backup = backup/ classes 是类别数 5 准备yolov3-KD.cfg_train文件(一般放build\darknet\x64\cfg文件夹里) 在build\darknet\x64\cfg下创建一个yolov3-KD.cfg_train文件,里面的内容可以复制build\darknet\x64\cfg\yolov3.cfg里面的内容,然后做几处修改即可: batch=16 subdivisions=16 每次计算的图片数目 = batch/subdivisions,然后把结果合起来也就是一个batch更新模型一次 如果batch设置过大,会报显存不够错误,我电脑配置太低,batch设置为16,subdivisions为16,可以根据自己的情况进行设置,如下图 classes=2 classes是类别数,这里只有两类,所以设置为2,文件里一共有3处需要修改classes,一般是文件的第610、689、776行 filters=21 filters的计算公式为(classes + 5)x3,我们这里有两类,所以是(2+5)*3=21,文件里一共有3处需要修改,这里需要注意,文件里有多处filter,但我们只需要修改[yolo]层之前的[convolutional]层下面的filters,位置一般是文件的第603、696、783行,如下图 6 下载预训练权重(放到build\darknet\x64文件夹里) https://pjreddie.com/media/files/darknet53.conv.74 pjreddie.com 7 开始训练 使用以下的命令进行训练(命令窗口切换到build\darknet\x64) darknet.exe detector train data/KD.data cfg/yolov3-KD.cfg_train darknet53.conv.74 每迭代100次就会在backup文件夹上生成一个模型权重 当avg loss在好几个迭代中都没有下降,此时可以停止训练了 8 测试 使用以下的命令进行训练(命令窗口切换到build\darknet\x64) darknet.exe detector test data/KD.data cfg/yolov3-KD.cfg_test backup/KD_yolov3_2000.weights data/test1.jpg -thresh 0.5 cfg/yolov3-KD.cfg_test 为测试的配置文件,只需要复制cfg/yolov3-KD.cfg_train的内容然后把batch和subdivisions设置为1即可 backup/KD_yolov3_2000.weights 为模型权重 data/test1.jpg 为测试图片的路径 -thresh 0.5 设置阈值,例如0.5,如果没有标注框就设置低点,如果很低都还没有标注框,那可能是某个环节出问题了,再仔细检查一下每个步骤 9 计算mAP 如果想计算mAP,可以参考下面链接 rafaelpadilla/Object-Detection-Metrics github.com 图标 10 常见问题 Couldn't open file: data/train_labels/1.txt 可以新建一个data/train_labels文件夹,把data/train_images中的所有txt文件放到该文件夹中 显示darknet.exe不是内部或外部命令,也不是可运行的程序(感谢@汪洋 提供的解决办法) 把darknet.exe复制到x64目录下,就可以了 couldn't open file: data/train.txt 可能是在window环境下处理文件出现编码格式的问题 解决方法: 应该使用Notepad++ 1)视图》显示符号》显示所有符号; 2)编辑》换行符》转换为UNIX格式; 确保最后一行有且仅有一个LF; 如果大家有什么问题请在下方留言! 如果觉得文章不错的可以关注我,一起交流学习!
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up