赞
踩
这个教程是我在网上查找资料写的,为了便于自己查看,将多篇博客内容总结当成学习自己的笔记,。如若有对某位作者造成侵权问题,请作者联系我删除,谢谢 ! 由于本人水平有限,如果文章有不当之处还望评论区指出。
本文参考了如下博客:
https://blog.csdn.net/qq_38441692/article/details/103652760
在github上下载代码 :https://github.com/YunYang1994/tensorflow-yolov3
这里的数据集格式采用的是VOC格式
1)方法一:使用实验LabelImg工具进行制作
LabelImg下载地址和数据集的制作过程可参考博文:labelImg标注图像的详细教程
实验LabelImg工具打好标签后会生成两个文件夹:
Annotations —存放标记的图片
JPEGImages —存放xml格式的标签
2)方法二:从COCO数据集中提取
参考博文:COCO数据集提取某类并转化为VOC
JPEGImages文件夹放图片文件:
Annotations文件夹放标签xml文件:
训练时要有测试集和训练集,通过划分放在
E:\DeviceData\deviceData_20201108\ImageSets\Main
文件夹下,这里可以使用一段python代码按照9:1进行随机划分:
在deviceData_20201108文件夹建立一个python文件:split.py,代码如下
import os import random import sys if len(sys.argv) < 2: print("no directory specified, please input target directory") exit() root_path = sys.argv[1] xmlfilepath = root_path + '/Annotations' txtsavepath = root_path + '/ImageSets/Main' if not os.path.exists(root_path): print("cannot find such directory: " + root_path) exit() if not os.path.exists(txtsavepath): os.makedirs(txtsavepath) trainval_percent = 0.9 train_percent = 0.8 total_xml = os.listdir(xmlfilepath) num = len(total_xml) list = range(num) tv = int(num * trainval_percent) tr = int(tv * train_percent) trainval = random.sample(list, tv) train = random.sample(trainval, tr) print("train and val size:", tv) print("train size:", tr) ftrainval = open(txtsavepath + '/trainval.txt', 'w') ftest = open(txtsavepath + '/test.txt', 'w') ftrain = open(txtsavepath + '/train.txt', 'w') fval = open(txtsavepath + '/val.txt', 'w') for i in list: name = total_xml[i][:-4] + '\n' if i in trainval: ftrainval.write(name) if i in train: ftrain.write(name) else: fval.write(name) else: ftest.write(name) ftrainval.close() ftrain.close() fval.close() ftest.close()
打开控制台,运行该python文件,后跟Annotation的目录即可进行划分:
python .\split.py … (存放原始数据集的路径)
python .\split.py E:\DeviceData\deviceData_20201108
在ImageSets\Main下生成了四个文件,其中,train为训练集,test为验证集
上面代码已经实现了将数据集划分为训练集和验证集,但是tensorflow yolov3作者写的模型要求的数据集格式为:
所以我们需要写一个小脚本split-again.py,根据train.txt 和test.txt将数据集进行更改
根据这个小脚本就可进行划分为规定的格式,如果数据集的量比较大,可能有点慢,当然你也可以进行手动划分,省略前面几步操作,只要最终目录结构满足作者的格式就行
import os from shutil import copyfile #根据tarin.txt和test.txt将数据集分为标准数据集(改路径,存放数据集的路径(原始数据集路径)) train_text_path = 'E:/DeviceData/deviceData_20201108/ImageSets/Main/train.txt' test_text_path = 'E:/DeviceData/deviceData_20201108/ImageSets/Main/test.txt' #图片存放地址 (改路径,存放数据集的路径) image_path = 'E:/DeviceData/deviceData_20201108/JPEGImages/' #xml文件存放地址 (改路径,存放数据集的路径) xml_path = 'E:/DeviceData/deviceData_20201108/Annotations/' #输出的目录 (改路径,存放数据集的路径(生成数据集存放的路径)) outdir = 'E:/DeviceData/deviceData_20201108_VOC/' #创建各级文件夹 test_xml_out = os.path.join(outdir,'VOC/test/VOC2020/Annotations') os.makedirs(test_xml_out) os.makedirs(os.path.join(outdir,'VOC/test/VOC2020/ImageSets/Layout')) os.makedirs(os.path.join(outdir,'VOC/test/VOC2020/ImageSets/Main')) os.makedirs(os.path.join(outdir,'VOC/test/VOC2020/ImageSets/Segmentation')) test_img_out = os.path.join(outdir,'VOC/test/VOC2020/JPEGImages') os.makedirs(test_img_out) os.makedirs(os.path.join(outdir,'VOC/test/VOC2020/SegmentationClass')) os.makedirs(os.path.join(outdir,'VOC/test/VOC2020/SegmentationObject')) train_xml_out = os.path.join(outdir,'VOC/train/VOC2020/Annotations') os.makedirs(train_xml_out) os.makedirs(os.path.join(outdir,'VOC/train/VOC2020/ImageSets/Layout')) os.makedirs(os.path.join(outdir,'VOC/train/VOC2020/ImageSets/Main')) os.makedirs(os.path.join(outdir,'VOC/train/VOC2020/ImageSets/Segmentation')) train_img_out = os.path.join(outdir,'VOC/train/VOC2020/JPEGImages') os.makedirs(train_img_out) os.makedirs(os.path.join(outdir,'VOC/train/VOC2020/SegmentationClass')) os.makedirs(os.path.join(outdir,'VOC/train/VOC2020/SegmentationObject')) with open(train_text_path) as f: lines = f.readlines() for i in lines: img_save_path = os.path.join(train_img_out,i.rstrip('\n')+'.jpg') xml_save_path = os.path.join(train_xml_out, i.rstrip('\n') + '.xml') copyfile(os.path.join(image_path,i.rstrip('\n')+'.jpg'),img_save_path) copyfile(os.path.join(xml_path, i.rstrip('\n') + '.xml'), xml_save_path) print(i) with open(test_text_path) as f: lines = f.readlines() for i in lines: img_save_path = os.path.join(test_img_out, i.rstrip('\n') + '.jpg') xml_save_path = os.path.join(test_xml_out, i.rstrip('\n') + '.xml') copyfile(os.path.join(image_path, i.rstrip('\n') + '.jpg'), img_save_path) copyfile(os.path.join(xml_path, i.rstrip('\n') + '.xml'), xml_save_path) print(i)
打开控制台,运行该python文件:
python .\split_again.py
python .\split.py E:\DeviceData\deviceData_20201108_VOC\VOC\test\VOC2020
python .\split.py E:\DeviceData\deviceData_20201108_VOC\VOC\train\VOC2020
作者在github上声明,训练需要两个文件,如下所示:
dataset.txt:
xxx/xxx.jpg 18.19,6.32,424.13,421.83,20 323.86,2.65,640.0,421.94,20
xxx/xxx.jpg 48,240,195,371,11 8,12,352,498,14
image_path x_min, y_min, x_max, y_max, class_id x_min, y_min ,..., class_id
make sure that x_max < width and y_max < height
class.names:
person
bicycle
car
...
toothbrush
其实前几步都是为这两步做准备,通过目录下的 scripts/voc_annotation.py就可以生成dataset.txt文件,但是需要改一些代码参数:
1)只需更改 classes为自己的类别
classes = ['person', 'tv', 'laptop', 'tablet', 'cell phone']
2)default 更改为你自己的看注释
if __name__ == '__main__':
parser = argparse.ArgumentParser()
#default 更改为你自己数据集VOC的目录
parser.add_argument("--data_path", default="E:/DeviceData/deviceData_20201108_VOC/VOC")
parser.add_argument("--train_annotation", default="../data/dataset/voc_train.txt")
parser.add_argument("--test_annotation", default="../data/dataset/voc_test.txt")
flags = parser.parse_args()
if os.path.exists(flags.train_annotation):os.remove(flags.train_annotation)
if os.path.exists(flags.test_annotation):os.remove(flags.test_annotation)
#更改训练集和测试集的相对路径
num1 = convert_voc_annotation(os.path.join(flags.data_path, 'train/VOC2020'), 'trainval', flags.train_annotation, False)
num3 = convert_voc_annotation(os.path.join(flags.data_path, 'test/VOC2020'), 'trainval', flags.test_annotation, False)
print('=> The number of image for train is: %d\tThe number of image for test is:%d' %(num1 , num3))
更改后运行该python文件:
这就生成了dataset.txt
修改为自己的类别:
编辑您的文件./core/config.py以进行一些必要的配置
__C.YOLO.CLASSES = "./data/classes/voc.names"
__C.TRAIN.ANNOT_PATH = "./data/dataset/voc_train.txt"
__C.TEST.ANNOT_PATH = "./data/dataset/voc_test.txt"
有多种方式
1)从头开始训练:
$ python train.py
$ tensorboard --logdir ./data
2)从COCO配置训练(推荐):
$ cd checkpoint
$ wget https://github.com/YunYang1994/tensorflow-yolov3/releases/download/v1.0/yolov3_coco.tar.gz
$ tar -xvf yolov3_coco.tar.gz
$ cd ..
// 训练之前需要将COCO权重转换成预训练模型
$ python convert_weight.py --train_from_coco
// 训练模型
$ python train.py
训练完之后有多个权重文件,挑选其中的50作为测试权重。
1) 修改测试权重路径
编辑config.py中的__C.TEST.WEIGHT_FILE路径参数,将其改成我们测试的权重文件名
2)执行python evaluate.py
测试测试集
3)执行python main.py -na
生成测试报告
我的报错了,是因为我的类别中类别名(cell phone)有空格,需要把空格去掉
去到extra目录下,可执行python rename_class -c 旧类名 -n 新类名
通过改类名的方式去掉类名中的空格
再执行python main.py -na
可以得到测试报告 mAP值
1)修改类别数目
将video_demo.py中的 num_classes
的值改为你的class.names文件中类别数,我的class.names文件包括5种类别,所以num_classes=5
2)修改freeze_graph.py文件(修改权重文件)
修改freeze_graph.py文件中的ckpt_file
为自己训练的权重
运行freeze_graph.py
:
运行成功,并且可以看到.pb文件更新了:
如果不运行freeze_graph.py
就执行video_demo.py
会出现下面的这种情况。
3)执行python video_demo.py
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。