自己之前用的模型在准确性以及实时性方面没有达到一个很好的均衡,在大佬同学的介绍下,开始转向Retinanet。
1.运行环境
运行环境:Windows10操作系统,python3.6(通过anaconda安装),tensorflow1.10,keras2.2.4。
2.数据预览
主要参考github上一篇介绍文档:https://github.com/fizyr/keras-retinanet,建议对说明文档多看几遍。retinanet模型训练的数据是按照VOC2007格式进行。首先看一下最后数据集文件夹以及数据格式预览:(.record和.pbtxt文件可以忽略,这是Google tensorflow API训练模型时用到的文件,与retinanet无关。)
其中:.csv文件是由voc2csv.py产生,generator_voc.py用来产生ImageSets中的文件。
Annotation文件夹如下:
Annotation文件里时格式为.xml的标注文件,注意文件名字以及文件数量和JPEGImages文件夹里的图片保持一致。 ImageSet文件夹下有一个Main文件夹,里面有四个文件:
Main文件夹需要自己创建,剩余的四个txt文件由代码自动生成。
3.数据制作
在数据制作时,特别感谢这两篇博客的作者:
https://blog.csdn.net/u012426298/article/details/80450537
https://blog.csdn.net/u012426298/article/details/80334292
3.1制作数据前提:JPEGImages文件夹里自己训练的图片,对图片进行标注的.xml文件夹Annotations。
3.2有了这两个文件,用generator_voc.py去产生ImageSets中的文件,在windows下,可以到文件下,按Shift+右键,然后打开Powershell直接运行命令:(个人感觉比cmd命令行简单一些):
python generator_voc.py
generator_voc.py代码如下(参考上面博客链接):
import os
import random
trainval_percent = 0.9 #训练数据和交叉验证数据占的比例,自己根据实际调节
train_percent = 0.8 #训练数据占trainval的比例,即用来训练的数据
xmlfilepath = 'Annotations'
txtsavepath = 'ImageSets\Main'
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)
ftrainval = open('ImageSets/Main/trainval.txt', 'w') #需要提前建立Main文件
ftest = open('ImageSets/Main/test.txt', 'w')
ftrain = open('ImageSets/Main/train.txt', 'w')
fval = open('ImageSets/Main/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()
运行完之后,ImageSets/Main文件下就会产生四个txt文件。(后续训练时,我也没看到这四个文件在哪里体现,囧)
3.3利用voc_csv.py产生.csv文件,同样在Powershell里:
python voc_csv.py
voc_csv.py代码如下:
# -*- coding:utf-8 -*-
import csv
import os
import glob
import sys
class PascalVOC2CSV(object):
def __init__(self,xml=[], ann_path='./annotations.csv',classes_path='./classes.csv'):
'''
:param xml: 所有Pascal VOC的xml文件路径组成的列表
:param ann_path: ann_path
:param classes_path: classes_path
'''
self.xml = xml
self.ann_path = ann_path
self.classes_path=classes_path
self.label=[]
self.annotations=[]
self.data_transfer()
self.write_file()
def data_transfer(self):
for num, xml_file in enumerate(self.xml):
try:
# print(xml_file)
# 进度输出
sys.stdout.write('\r>> Converting image %d/%d' % (
num + 1, len(self.xml)))
sys.stdout.flush()
with open(xml_file, 'r') as fp:
for p in fp:
if '' in p:
self.filen_ame = p.split('>')[1].split('<')[0]
if '
运行完之后,就会产生两个.csv文件,annotations.csv文件用notepad打开,格式如下:
红线部分就是图片的名字,黄色部分就是标记的类别,中间四个数字是标记框的位置。 到这里本该结束了,但是我在后续训练时遇到一个问题,就是模型报错:找不到JPEGImages/........(....点表示上面红线部分的名字)。原因是这里没有加上图片的后缀名.jpg,所以模型从这里读取红色部分时,对应不上JPEGImages文件夹下的图片(图片都带有后缀名)。所以我在这里对代码进行了修改,就是把 52行的
self.annotations.append([os.path.join('JPEGImages',self.filen_ame),x1,y1,x2,y2,self.supercategory])
修改为:
self.annotations.append([os.path.join('JPEGImages',self.filen_ame+'.jpg'),x1,y1,x2,y2,self.supercategory])
这样生成的annotation.csv文件中就包含了后缀名。感觉原作者没有修改也产生了后缀名,不知道怎么回事。
4.检测产生的数据是否合格
至此,Retinanet数据集的制作算是初步完成了。为了检测生成的数据是否合格,github上的作者给出了一个debug.py 进行检测,检测方式也很简单,同样在当前目录下打开powershell,运行:
python keras_retinanet/bin/debug.py csv csv/annotations.csv csv/classes.csv
上述代码运行的前提是:你要从github上把retinanet代码clone下来,并且对keras_retinanet进行了正确的安装以及编译。安装以及编译github说明文档有详细介绍,我也会在接下来文章中进行解释。
下面来看一下运行之后出的一个错误:
第一个错误是自己写的路径有问题,第二个问题就是我上面提到的,显示未找到JPEGImages,不过这里是因为后缀名变成了*****.jpg.jpg,几万个annotations里大概有十几个出现了这样问题。这个时候,就需要把文件名字复制出来,一个一个去annotations.csv文件里搜索修改后缀名。(还是建议用notepad打开csv文件,方便搜索以及及时修改)
最后,如果数据完全没问题,debug.py运行一段时间后,会弹出你的第一张训练图片,关掉这张图片,会继续按顺序弹出第二张,说明数据制作大功告成,关掉powershell即可。
5.特别感谢:
https://github.com/fizyr/keras-retinanet
https://blog.csdn.net/u012426298/article/details/80334292
https://blog.csdn.net/u012426298/article/details/80450537