tenforflow版YOLOv3下VOC数据集的准备和训练

本篇博客对应的旧代码:

带模型版665.5MB+:

百度网盘链接 提取码: bre5

只含代码版5MB:

tensorflow_yolov3_mud.rar - 蓝奏云

如果你没有配置环境还有安装YOLOv3,在看此篇博客之前先转到这篇博客完成安装:

Win10安装YOLOv3.0

第一步:准备数据

先标注好VOC数据,可以参考这篇文章标注VOC数据:

给实验室同学看的标注说明书

        标注完数据之后,看到tensorflow-yolov3\data\data_train\VOCdevkit\VOC2007这个目录(没有则自己创建),这个目录的结构应该是下面这样含四个文件夹:Annotations、ImageSets、ImageSets\Main和JPEGImages,不是这样的则需要自己创建这几个文件夹,注意名字不能有一点差错,否则你的文件夹名会与我代码里写的路径对不上:

--VOC2007 
    --Annotations  
    --ImageSets  
      --Main  
    --JPEGImages

        其中文件夹Annotations中主要存放xml文件,每一个xml对应一张图像,并且每个xml中存放的是标记的各个目标的位置和类别信息,命名通常与对应的原始图像一样,你需要把之前标注好的所有.xml文件放进去;

        JPEGImages文件夹中放我们已按统一规则命名好的原始图像。

        而ImageSets我们只需要用到Main文件夹,这里面存放的是一些文本文件,为:trainval.txt、train.txt、val.txt、test.txt,该文本文件里面的内容是需要用来训练或测试的图像的名字(无后缀无路径);在VOC2007里有一个voc_to_txt.py文件,打开命令行进入VOC2007所在的路径,然后运行这个代码,如下:

cd <你的路径>\tensorflow-yolov3\data\data_train\VOCdevkit\VOC2007
python voc_to_txt.py

就会按照voc_to_txt.py里你指定的训练集和测试集的比例生成上面那四个txt文件。

当然你要先voc_to_txt.py代码里面设置好训练、验证的比例,一般数据比较少比如数百幅图片的时候test占0.2、0.3,成千上万幅图片test设置0.1就行了:

    testScale = 0.1  # 测试集占总数据集的比例
    trainScale = 0.72  # 训练集占训练验证集的比例

总数据集=test(测试集)+trainval(训练验证集),trainval=train(训练集)+val(验证集)

看到这里,下面的部分是我的debug过程,可以直接跳过。你现在ctrl+f页面搜索:

如果下载的是我的代码的话直接打开tensorflow-yolov3\scripts\make_voc_tfrecords.txt就是下面的内容

跳到make_voc_tfrecords.txt的这一部分再往下看。

然后用记事本打开这个make_voc_tfrecords.sh文件,这个文件是我们准备训练数据的指导纲领:

 里面的内容是:

python scripts/extract_voc.py --voc_path /home/yang/test/VOC/train/ --dataset_info_path ./
cat ./2007_train.txt ./2007_val.txt > voc_train.txt
python scripts/extract_voc.py --voc_path /home/yang/test/VOC/test/ --dataset_info_path ./
cat ./2007_test.txt > voc_test.txt
python core/convert_tfrecord.py --dataset_txt ./voc_train.txt --tfrecord_path_prefix /home/yang/test/VOC/train/voc_train
python core/convert_tfrecord.py --dataset_txt ./voc_test.txt  --tfrecord_path_prefix /home/yang/test/VOC/test/voc_test

第一行:python scripts/extract_voc.py --voc_path /home/yang/test/VOC/train/ --dataset_info_path ./

这一行的作用就是,提取你的VOC数据集的图片路径和标注框的位置生成txt文件,txt文件的内容为:

E:\xxx\xxx\VOCdevkit\VOC2007\JEPGImages\xxxxxx.jpg x_min y_min x_max y_max class_id

# 图片的路径   标注框的位置信息   类别号

但是这个extract_voc.py文件用不了,可能是我不会用吧。根据这个网址的指示:

https://github.com/YunYang1994/tensorflow-yolov3/issues/56

为了代替这个extract_voc.py文件,我去了下面这个网站,复制了这个叫voc_annotations.py的文件,然后我把它放在tensorflow-yolo3/scripts下面,如果你下载的是本文开头我的代码就不用再去下面这个网址去下载voc_annotations.py文件了:

https://github.com/qqwweee/keras-yolo3

然后把这个voc_annotations.py文件修改成下面这样,如果你用的是本文开头下载的我的代码,代码里面已经改好了,不用去动了:

# coding=utf-8
import xml.etree.ElementTree as ET
from os import getcwd

sets=[('2007', 'train'), ('2007', 'val'), ('2007', 'test')]

classes =['mud'] # 这里是你要识别的类别  ["aeroplane", "bicycle", "bird", "boat", "bottle", "bus", "car", "cat", "chair", "cow", "diningtable", "dog", "horse", "motorbike", "person", "pottedplant", "sheep", "sofa", "train", "tvmonitor"]


def convert_annotation(year, image_id, list_file):
    in_file = open('./../data/data_train/VOCdevkit/VOC%s/Annotations/%s.xml'%(year, image_id), encoding='UTF-8')   # 强烈注意这个地方,要加上, encoding='UTF-8'这个地方就是你用来训练的标注文件
    tree=ET.parse(in_file)
    root = tree.getroot()

    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 = (int(xmlbox.find('xmin').text), int(xmlbox.find('ymin').text), int(xmlbox.find('xmax').text), int(xmlbox.find('ymax').text))
        list_file.write(" " + " ".join([str(a) for a in b]) + ' ' + str(cls_id))  # 把这里的逗号换成空格,这样才是yunyang的版本要求的格式,这个文件从qqwwee来

wd = getcwd()

for year, image_set in sets:
    image_ids = open('./../data/data_train/VOCdevkit/VOC%s/ImageSets/Main/%s.txt'%(year, image_set)).read().strip().split()
    list_file = open('%s_%s.txt'%(year, image_set), 'w')
    for image_id in image_ids:
        list_file.write('.\..\data\data_train\VOCdevkit\VOC2007\JEPGImages\%s.jpg'%(image_id))  # 这里改为反斜杠,我使用的是相对路径,从Anaconda Prompt里进入yolov3的根目录
        '''上面这一行原为list_file.write('%s\VOCdevkit\VOC%s\JPEGImages\%s.jpg'%(wd, year, image_id)) ,这个路径要根据你的VOC文件目录改变,这行带路径的代码的作用就是在txt文件里写入图片的路径
         假如这里放入你的VOC数据的绝对路径,那么这个绝对路径会不生效,因为你的路径中会有‘\tensorflow’,'\t'这是个转义字符,要让它写入txt时显示为’\‘,你要这样写’\\t‘,但这样路径就无效了,不知道为什么
         但是假如你进入那个JEPGImages的文件夹,直接在txt里粘贴这个文件夹的路径,却又能用,令人费解'''
        convert_annotation(year, image_id, list_file)
        list_file.write('\n')
    list_file.close()

上面有注释‘#’的地方都是我修改过的。

然后把这个make_voc_tfrecord.sh改成下面这样,用开头给出的我的代码的话,就不用改了,

如果下载的是我的代码的话直接打开tensorflow-yolov3\scripts\make_voc_tfrecords.txt就是下面的内容:

python ./voc_annotations.py
type .\2007_train.txt .\2007_val.txt > .\voc_train.txt
type .\2007_test.txt > .\voc_test.txt
python ./../core/convert_tfrecord.py --dataset_txt ./voc_train.txt --tfrecord_path_prefix ./../data/data_train/VOCdevkit/VOC2007/voc_train
python ./../core/convert_tfrecord.py --dataset_txt ./voc_test.txt  --tfrecord_path_prefix ./../data/data_train/VOCdevkit/VOC2007/voc_test

1.第一行:python scripts/voc_annotations.py,这一行是把你的标注的图片和标注框的信息放入三个txt文件:train.txt、val.txt、test.txt,这三个文件会生成在voc_annotations.py文件的相同目录里。

2.第二三行就是把‘>’前面的txt文件里的内容复制粘贴入‘>’后面的txt文件里去。这里原来是cat ./2007_train.txt ./2007_val.txt > voc_train.txt,那为什么要改成type呢?因为windows用type,linux用cat。

然后此时,voc_train.txt和voc_text.txt文件里的内容为:

注意每张图片中至少需要一个标注,否则在生成tfrecords文件的时候会报错如文章末尾的bug4。

3.注意,看到第四、五行,--xxxx是参数标识符,这个后面就是路径参数,列如这里的--dataset_txt是路径参数标识符,它的后面就是用来输入的txt文件的路径。你的路径一定要存在,不存在的更换路径或是自己创建这个目录。后面的--tfrecord_path_prefix就是输出的tfrecord文件的地址,我这里是./data/data_train/VOCdevkit/VOC2007/voc_test,我用的是相对路径,最后面的这个voc_test或者voc_train是生成的tfrecord文件名,这个不是文件夹。

为了方便调错,你需要打开你的anaconda prompt,cd进入tensorflow-yolov3\scripts目录后,activate 环境名 来激活你的tensorflow环境,一行一行地运行make_voc_tfrecords.txt里面的命令。

或者你也可以直接全选内容一次性运行,但是这样有时候报错不好debug。

最后再强调一下,路径一定要正确,包括那些txt文件内容里的路径。做这个项目有很多地方需要修改路径,在路径上有时会卡很久的bug,多了一个空格,少打一个字母都不行。

第二步:开始训练

打开tensorflow-yolo3根目录下面的qiuck_train.py文件:

 

 1.   BATCH_SIZE是总共训练包的个数,但你训练时出现显存不够(Out of range),或是蓝屏、程序崩溃的时候可以尝试把这个参数调小。

2.    STEPS是迭代次数的多少,低则识别率低,反之则否,我用3000幅左右的图片来训练并且迭代2500次用了一个半小时,我迭代50000次则用了25个小时左右。

3.    CLASSES之后的路径是存放你要识别的类别的txt文件。

4.    ANCHORS之后的路径是你训练的网络单元的权重文件,这个txt文件名含有anchors,我们用的是VOC格式的数据,这里要改为voc_anchors.txt。

最下面的两个train_tfrecord和test_tfrecord是之前生成的,改好路径。在本人这里我改为:

仅供参考,这个quick_train.py我又复制了一份,更名为train.py,这样留个备份。训练的时候我习惯用train.py来训练。(实际上quick_train.py.bak就是源文件作者的备份)

于是在anaconda prompt下,进入tensorflow-yolo3根目录,输入命令:

python train.py

来开始训练。

它会出现:

这个STEP后面的49700就是你现在训练迭代到 第几步了,loss_xy是你的损失函数,也就是预测值与真实值之间的差别,训练得好的话,这个值会不断震荡,最后趋近于0。

loss_xy是目标中心点的,loss_wh是高和宽的,loss_class是类别的,loss_conf是综合中心点和长宽的

每迭代100次,会出现:

这个recall就是召回率,假如你要识别人,图片列出的100个人中,你能识别出来的人的百分比,

这个precision就是识别精度,图片列出的100个物体中,你正确识别为人的百分比。

第三步:测试与评估

训练完之后会在tensorflow-yolo3/checkpoint下生成三个ckpt文件:

 我迭代了50000步,上面的那三个49500是它训练途中备份的,可以删掉。这三个ckpt文件就是训练完生成的模型。

然后在anaconda prompt中进入tensorflow-yolo3根目录,输入命令:

python convert_weight.py -cf ./checkpoint/yolov3.ckpt-50000 -nc 1 -ap ./data/voc_anchors.txt --freeze

 再次强调要保证目录正确,目录下存在这个文件。

之后会在tensorflow-yolo3/checkpoint下生成两个pb文件:

这两个文件是用来测试的, 当你在一台新电脑上要识别物体时,需要的就是.pb文件和.names文件和测试的图片以及配置好环境。

然后打开tensorflow-yolo3下的quick_test.py文件:

1. 改一下这里的classes后面的目录,这个目录是你要识别的类别的文件,我的这个voc_mud.names文件里只有一个mud字符串。因为我只要识别一个mud类

2.再改一下image_path后面的目录,这里是你用来测试的图片,这里每次只能测试一个图片。

3.最后再改一下input_tensor,output_tensors后面的路径,这个yolo3_gpu_nms.pb就是上面生成的那两个pb文件之一。改成*_cpu_nms.pb就是用cpu测试。

输入:

python quick_test.py

开始测试。

你要识别的物体会被框出来:

 

 这里mud 后的数字就是电脑认为是mud的概率。

接下来就是评估:

打开tensorflow-yolo3根目录下的evaluate.py文件,修改红线部分的路径,根据你自己的情况修改:

在tensorflow-yolo3根目录下的anaconda prompt中输入:

python evaluate.py

 评估结果:

我这里的识别率mAP达到0.9662

用tensorboard查看训练过程中的损失函数值的变动:

anaconda prompt中进入tensorflow-yolov3的根目录,输入:

tensorboard --logdir=D:\tensorflow-yolov3-master\data --host=127.0.0.1

*****完结撒花*****

Bugs:

bug1.Unix的cat在Windows环境下的替代者:type

Unix的cat在Windows环境下的替代者:type_Super_Tiger_Lee的博客-CSDN博客

bug2.必备知识:from . import,“.”  代表使用相对路径导入,即从当前项目中寻找需要导入的包或函数

python的包导入问题(一)from . import 的使用_Supergirl12138的博客-CSDN博客

bug3.当我在运行这个命令时:

python core/convert_tfrecord.py --dataset_txt ./scripts/voc_test.txt  --tfrecord_path_prefix ./data/data_train/VOCdevkit/VOC2007/voc_test

出现错误:

(base) E:\tensorflow-yolov3-master>python core/convert_tfrecord.py --dataset_txt ./scripts/voc_test.txt  --tfrecord_path_prefix ./data/data_train/VOCdevkit/VOC2007/voc_test
E:\Anaconda3-5.2.0-Windows-x86_64\lib\site-packages\h5py\__init__.py:36: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`.
  from ._conv import register_converters as _register_converters
>> Processing 1001 images
Traceback (most recent call last):
  File "core/convert_tfrecord.py", line 58, in <module>
    if __name__ == "__main__":main(sys.argv[1:])
  File "core/convert_tfrecord.py", line 43, in main
    image = tf.gfile.FastGFile(image_paths[i], 'rb').read()
  File "E:\Anaconda3-5.2.0-Windows-x86_64\lib\site-packages\tensorflow\python\lib\io\file_io.py", line 125, in read
    self._preread_check()
  File "E:\Anaconda3-5.2.0-Windows-x86_64\lib\site-packages\tensorflow\python\lib\io\file_io.py", line 85, in _preread_check
    compat.as_bytes(self.__name), 1024 * 512, status)
  File "E:\Anaconda3-5.2.0-Windows-x86_64\lib\site-packages\tensorflow\python\framework\errors_impl.py", line 519, in __exit__
    c_api.TF_GetCode(self.status.status))
tensorflow.python.framework.errors_impl.InvalidArgumentError: NewRandomAccessFile failed to Create/Open:
 : \udcce?\udcfe\udcc3\udcfb\udca1\udca2??\udcc3\udcfb\udcbb\udcf2\udcbe\udced\udcb1\udcea\udcd3?\udcb2\udcbb\udcd5\udcfd?\udca1\udca3
; Unknown error

这个错误是因为你的voc_test.txt文件中有空行,把空行去掉。

bug4.当我在运行这个命令时:

python ./../core/convert_tfrecord.py --dataset_txt ./voc_train.txt --tfrecord_path_prefix ./../data/data_train/VOCdevkit/VOC2007/voc_train 

出现错误:

tensorflow.python.framework.errors_impl.InvalidArgumentError: NewRandomAccessFile failed to Create/Open: 
.\..\data\data_train\VOCdevkit\VOC2007\JEPGImages\000100.jpg: 
\udcceļ\udcfe\udcc3\udcfb\udca1\udca2Ŀ¼\udcc3\udcfb\udcbb\udcf2\udcbe\udced\udcb1\udcea\udcd3﷨\udcb2\udcbb\udcd5\udcfdȷ\udca1\udca3
; Unknown error

估计是路径有问题,找不到000100.jpg这个图片。

查看命令涉及的文件:voc_train.txt

这个路径好像没有问题啊?

然后我才发现,文件名和后缀名之间多了个空格,估计是用freeRename批量修改文件名的时候多打了空格:

继续输入:

python ./../core/convert_tfrecord.py --dataset_txt ./voc_train.txt --tfrecord_path_prefix ./../data/data_train/VOCdevkit/VOC2007/voc_train 

还是错误。

然后我把voc_train.txt里的数据只保留一行:

>> Processing 1 images
WARNING:tensorflow:From ./../core/convert_tfrecord.py:43: FastGFile.__init__ (from tensorflow.python.platform.gfile) is deprecated and will be removed in a future version.
Instructions for updating:
Use tf.gfile.GFile.
>> Saving 1 images in ./../data/data_train/VOCdevkit/VOC2007/voc_train.tfrecords

这样却能成功,放多行数据却不行,真tm恼火。

solution:

最后发现原来在运行命令:

python ./voc_annotations.py

的时候,忘记把自己的类别添加进voc_annotations.py里的classes变量了:

浪费了一个下午!!

bug5.输入命令:
python train.py命令时,出现错误:

OutOfRangeError (see above for traceback): End of sequence
         [[Node: cond/IteratorGetNext = IteratorGetNext[output_shapes=[[?,416,416,3], <unknown>, <unknown>, <unknown>], output_types=[DT_FLOAT, DT_FLOAT, DT_FLOAT, DT_FLOAT], _device="/job:localhost/replica:0/task:0/device:CPU:0"](cond/IteratorGetNext/Switch:1)]]
         [[Node: cond/IteratorGetNext/_547 = _Recv[client_terminated=false, recv_device="/job:localhost/replica:0/task:0/device:GPU:0", send_device="/job:localhost/replica:0/task:0/device:CPU:0", send_device_incarnation=1, tensor_name="edge_678_cond/IteratorGetNext", tensor_type=DT_FLOAT, _device="/job:localhost/replica:0/task:0/device:GPU:0"]()]]

其实这个错误不是因为超出显存,而是因为tfrecord的路径有错误,检查检查train.py文件中tfrecord的路径是否正确,或者看看这个路径下是否有tfrecord文件。

bug6.tensorflow.python.framework.errors_impl.NotFoundError: NewRandomAccessFile failed to Create/Open: ./checkpoint/2500/yolov3_gpu_nms.pb : ??\udcd5?\udcbb\udcb5\udcbd?\udcb6\udca8\udcb5\udcc4·\udcbe\udcb6\udca1\udca3
; No such process
实际上类似于这种错误都是因为路径问题,好好查看你的路径。

bug7.当我在运行这个命令时:
python core/convert_tfrecord.py --dataset_txt ./scripts/voc_test.txt  --tfrecord_path_prefix

先报错:

module not found 'numpy'

然后pip install numpy,发现装不上,查看tensorflow-yolov3/docs/requirements.txt:

numpy==1.15.1
Pillow==5.3.0
scipy==1.1.0
tensorflow-gpu==1.11.0
wget==3.2
seaborn==0.9.0
看到numpy版本不对,于是重新装了numpy==1.15.1,接着运行命令:

python core/convert_tfrecord.py --dataset_txt ./scripts/voc_test.txt  --tfrecord_path_prefix

报错:numpy.core._multiarray_umath failed to import

你的numpy版本和你的tensorflow-gpu版本不符,查看我的tensorflow-gpu版本,发现和requirements.txt里的不一样,于是卸载后装1.11.0

报错:  File "F:\anaconda\envs\tensorflow-gpu\lib\imp.py", line 343, in load_dynamic
    return _load(spec)
ImportError: DLL load failed: 找不到指定的模块。

我以为是CUDA的问题,结果去降低版本装了CUDA8,Cudnn6,还是报错:

  File "F:\anaconda\envs\tensorflow-gpu\lib\imp.py", line 343, in load_dynamic
    return _load(spec)
ImportError: DLL load failed: 找不到指定的模块。

而且Cudnn还装不上了:Could not load 'cudnn64_5.dll'.

仔细思索后,我回到我以前配置成功tensorflow-gpu版yolov3写的博客:

Win10安装YOLOv3.0_UryWu的博客-CSDN博客

发现,我得降低我的tensorflow-gpu版本,(从1.11.0到1.10.0,python==3.6)因为我的显卡算力只有3.5,tensorflow-gpu==1.11.0要算力大于3.7以上的显卡。所以我按照以前的要求配,然后在nvidia控制面板的系统信息里我的显卡驱动是支持CUDA9.0的,其实一开始就应该装CUDA9.0的,只是我想试一下高版本的CUDA能不能用,哎~真的要按要求来啊。

这个问题总算是解决了。

bug8:无法Import mvsdk模块,你需要去这个网址下载mindvision驱动程序(尽管你没用到工业相机,但是我懒得改代码了):

工业双目摄像头-高速相机-深圳市迈德威视科技有限公司

安装后即可。

bug9:

当我想使用内置相机来进行目标检测,使用相应的代码时,报错:

Traceback (most recent call last):
  File "Built_in_camera.py", line 27, in <module>
    raise ValueError("No image!")
ValueError: No image!

检查后发现我打不开我的笔记本的内置相机,在上一个错误我是因为没有安装mindvision才无法打开内置相机的,但这次我已经安装了mindvision,但也打不开。(原则上,我不安装mindvision的驱动也应该能打开笔记本的内置相机的,但是上一次错误指出我安装了mindvision的驱动之后才能使用笔记本的内置相机,这笔记本本身就有问题。)

仔细思索,我之前安装了ASIO的驱动,那么很可能就是因为这个的原因才使笔记本无法使用内置相机。因此,我决定重装一次mindvision驱动。

bug10:

IndexError: index 26480 is out of bounds for axis 0 with size 10647

更换了.pb文件后忘记更换.names文件了。

参考博客

准备数据部分参考:YOLOv2训练自己的数据集(VOC格式)

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 24
    评论
评论 24
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值