YOLOv3在这个网址下载,并且按照他的指示先配置好环境:
https://github.com/YunYang1994/tensorflow-yolov3
或者你可以参考我的这篇更详细的博客来配置环境还有安装YOLOv3,那里面的COCO数据集就不用准备了,COCO的训练部分也不要走,因为我们要训练的是VOC数据:
https://blog.csdn.net/qq_25799253/article/details/88598525
先准备好VOC数据,可以参考这篇文章准备VOC数据。
https://www.cnblogs.com/antflow/p/7350274.html
然后打开这个文件,这个文件是我们的指导纲领:
里面的内容是:
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下面:
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改成:
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。
3.注意,看到第四、五行,--xxxx是参数标识符,这个后面就是路径参数,列如这里的--dataset_txt是路径参数标识符,它的后面就是用来输入的txt文件的路径。你的路径一定要存在,不存在的更换路径或是自己创建这个目录。后面的--tfrecord_path_prefix就是输出的tfrecord文件的地址,我这里是./data/data_train/VOCdevkit/VOC2007/voc_test,我用的是相对路径,最后面的这个voc_test或者voc_train是生成的tfrecord文件名,这个不是文件夹。
然后全选这个文件的内容,复制,打开anaconda prompt,激活有tensorflow的环境(命令:activate 环境名 来激活你的tensorflow环境),然后用cd命令进入tensorflow-yolov3-master\scripts目录,粘贴刚刚的复制的东西,运行。
然后如果出现错误,为了调错,可以用你的anaconda prompt一行一行地运行上面的命令。
最后再强调一下,路径一定要正确,包括那些txt文件内容里的路径。
打开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
*****完结撒花*****
附录:
1.Unix的cat在Windows环境下的替代者:type
https://blog.csdn.net/Super_Tiger_Lee/article/details/78075775
2.必备知识:from . import,“.” 代表使用相对路径导入,即从当前项目中寻找需要导入的包或函数
https://blog.csdn.net/qq_27158747/article/details/80936975
3.当我在运行这个命令时:
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
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文件中有空行,把空行去掉。
4.输入命令:
python train.py命令时,出现错误:
OutOfRangeError (see above for traceback): End of sequence
[[Node: cond/IteratorGetNext = IteratorGetNext[output_shapes=[[?,416,416,3],
[[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文件。
5.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
实际上类似于这种错误都是因为路径问题,好好查看你的路径。
6.当我在运行这个命令时:
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写的博客:
https://blog.csdn.net/qq_25799253/article/details/88598525
发现,我得降低我的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能不能用,哎~真的要按要求来啊。
这个问题总算是解决了。
ERROR7:无法Import mvsdk模块,你需要去这个网址下载mindvision驱动程序(尽管你没用到工业相机,但是我懒得改代码了):
http://www.mindvision.com.cn/rjxz/list_12.aspx?lcid=138
安装后即可。
ERROR8:
当我想使用内置相机来进行目标检测,使用相应的代码时,报错:
Traceback (most recent call last):
File "Built_in_camera.py", line 27, in
raise ValueError("No image!")
ValueError: No image!
检查后发现我打不开我的笔记本的内置相机,在上一个错误我是因为没有安装mindvision才无法打开内置相机的,但这次我已经安装了mindvision,但也打不开。(原则上,我不安装mindvision的驱动也应该能打开笔记本的内置相机的,但是上一次错误指出我安装了mindvision的驱动之后才能使用笔记本的内置相机,这笔记本本身就有问题。)
仔细思索,我之前安装了ASIO的驱动,那么很可能就是因为这个的原因才使笔记本无法使用内置相机。因此,我决定重装一次mindvision驱动。
ERROR9:
IndexError: index 26480 is out of bounds for axis 0 with size 10647
更换了.pb文件后忘记更换.names文件了。