文章目录
前言
上一篇博文实现dBeker版本的代码,一天之内居然有三个人再看,开心得不得了!由于想用Resnet网路代替VGG16,但是dBeker版本的代码我没弄出来,问了几个小伙伴,还有看评论区里的也有同样想用renset替换VGG的。但是都没有成功,好像是这个版本的代码缺少Resnet的参数,由于本人也是刚入门,改代码对我还是比较困难的,(但是如果有大神做出来了请您私信给我,交流交流。)所以又找到了新的代码试一试。
本博文使用代码:https://github.com/endernewton/tf-faster-rcnn
目前都是用Linux系统跑这个代码的,由于自己的是windows,所以尝试跑了一下。顺便记录。
测试demo.py
准备
根据作者在github上给的Readme,一步一步进行下去:
1.下载github源码到电脑上。
2.编译Cython:在lib路径下,编译Cython模块(确保你已经安装了easydict,如果没有,pip install easydict):这部分我没有编译,不会,然后我就向下进行了,有会的朋友可以评论给大家看,谢谢
3.安装COCO API
给出github下载地址:https://github.com/cocodataset/cocoapi
把安装包下载下来,解压到data文件夹下,然后进入coco/PythonAPI下运行:
python setup.py build_ext --inplace
python setup.py build_ext install
4.下载PASCAL VOC数据集:这部分请详见我的上篇博文:https://blog.youkuaiyun.com/JJJKJJ/article/details/103141229
下载模型
1.本文使用的是的是resnet01模型,由于需要翻墙,这里给出百度云下载链接:https://blog.youkuaiyun.com/char_QwQ/article/details/80980505提取码:8ahl。
下载后解压到data文件夹下,并将文件夹重命名为 voc_2007_trainval ,文件结构如下:
其中imagenet_weights文件夹先不管。
2。在tf-faster-rcnn根目录创建一个\output\res101\voc_2007_trainval\default文件夹并且在其中存放预训练模型,也就是将刚才下载好的resnet模型复制到或者移动到default文件夹中。
测试
运行demo.py之前,首先修改几处代码
1.def parse_args():中的default='pascal_voc_0712’修改为pascal_voc
2.if name == ‘main’:中tfmodel = os.path.join(‘output’, demonet, DATASETS[dataset][0], ‘default’,NETS[demonet][0])的output,修改为绝对路径,我的是’D:/1Aqilei—npupt/tf-faster-rcnn-master/output’。
3.tf-faster-rcnn/lib/datasets/voc_eval.py的第121行的
with open(cachefile,‘w’) as f修改为:with open(cachefile,‘wb’) as f
同时还要把第105行的 cachefile = os.path.join(cachedir, ‘%s_annots.pkl’ % imagesetfile)
改成:cachefile = os.path.join(cachedir, ‘%s_annots.pkl’ % imagesetfile.split("/")[-1].split(".")[0])
4.修改lib.model.nms_wrapper.py全部修改:
# --------------------------------------------------------
# Fast R-CNN
# Copyright (c) 2015 Microsoft
# Licensed under The MIT License [see LICENSE for details]
# Written by Ross Girshick
# --------------------------------------------------------
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from nms.py_cpu_nms import py_cpu_nms
def nms(dets, thresh, force_cpu=False):
"""Dispatch to either CPU or GPU NMS implementations."""
if dets.shape[0] == 0:
return []
# if cfg.USE_GPU_NMS and not force_cpu:
# return gpu_nms(dets, thresh, device_id=cfg.GPU_ID)
# else:
# return cpu_nms(dets, thresh)
return py_cpu_nms(dets=dets, thresh=thresh)
5.可能会出现No module named ‘lib.utils.Cython_bbox’的错误,这个错误的主要原因是,目前网上流行的Faster RCNN版本大多都是基于Py35的。当你使用Py36的环境去编译,那么就会出现这个问题。解决方法:https://pan.baidu.com/s/1-M2_Uic8n6Ac0M-DqH5-9Q
提取码:p1we.
将下载的文件放到lib\utils\文件夹下。问题解决
6.执行 demo.py,大功告成
7.有问题欢迎评论区评论,努力为大家解答
训练自己的数据集
注:此部分相关内容可参看https://blog.youkuaiyun.com/JJJKJJ/article/details/103141229
1.首先删除data/VOCdevkit2007/VOC2007/JPEGImages文件夹下的图片数据,换成自己的实验数据 --finish
这一步骤我将图片尺寸调整为900,600。同时rename。
2.删除data/VOCdevkit2007/VOC2007/Annotations文件夹下的xml文件,等待放入自己数据对应的xml文件 --finish
3.打开labelImg,对自己实验数据进行标注,点击change save dir改变xml文件的保存路径,一般保存在data\VOCdevkit2007\VOC2007\Annotations文件夹下 --finish
4.由于数据集数据有限,所以进行数据增强,通过上下镜像与左右镜像,增加自己的数据集。
附上代码:
上下镜像
'''
上下镜像
'''
import cv2
from PIL import Image
import xml.etree.ElementTree as ET
from tqdm import tqdm
import os
from PIL import Image
def flip_horizontal(jpg_file,new_jpg):
im = Image.open(jpg_file)
# out = im.transpose(Image.ROTATE_180)
out = im.transpose(Image.FLIP_TOP_BOTTOM)
out.save(new_jpg)
def flip_xml(xml_file,new_xml,height):
tree = ET.parse(xml_file)
objs = tree.findall('object')
for ix, obj in enumerate(objs):
name = obj.find('name').text
#if name == 'mouse':
#print(xml_file)
obj_new = obj.find('bndbox')
ymin = str( height - int(obj_new.find('ymax').text))#此2行保证翻转后ymin<ymax
ymax = str( height - int(obj_new.find('ymin').text))
obj_new.find('ymin').text = ymin
obj_new.find('ymax').text = ymax
tree.write(new_xml)
if __name__ == '__main__':
# path = r'E:\VOC2007\Annotations'
path = r'D:\1Aqilei---npupt\tf-faster-rcnn-master\data\VOCdevkit2007\VOC2007\Annotations'
xml_files = [os.path.join(rootdir, file) for rootdir, _, files in os.walk(path) for file in files if
(file.endswith('.xml'))]
print(xml_files)
jpg_files = [xmlfile.replace('Annotations', 'JPEGImages').replace('xml', 'jpg') for xmlfile in xml_files]
#jpg_files =[xmlfile.replace('xml','jpg') for xmlfile in xml_files]
#print(jpg_files)
# jpg_old_files = jpg_files
files = zip(jpg_files,xml_files)
#print(files)
for jpg_file,xml_file in tqdm(files):
#print(jpg_file)
im = Image.open(jpg_file)
height = im.size[1]
# print(width)
new_jpg = jpg_file.replace(jpg_file.split('\\')[-1].split('.')[0],jpg_file.split('\\')[-1].split('.')[0] + '_buttom')
#print(new_jpg)
# break
new_xml = new_jpg.replace('JPEGImages', 'Annotations').replace('jpg', 'xml')
# print(new_xml)
flip_xml(xml_file,new_xml,height)
flip_horizontal(jpg_file, new_jpg)
左右镜像
'''
左右镜像
'''
import cv2
from PIL import Image
import xml.etree.ElementTree as ET
from tqdm import tqdm
import os
from PIL import Image
def flip_horizontal(jpg_file,new_jpg):
im = Image.open(jpg_file)
# out = im.transpose(Image.ROTATE_180)
out = im.transpose(Image.FLIP_LEFT_RIGHT)
out.save(new_jpg)
def flip_xml(xml_file,new_xml,width):
tree = ET.parse(xml_file)
objs = tree.findall('object')
for ix, obj in enumerate(objs):
name = obj.find('name').text
#if name == 'mouse':
#print(xml_file)
obj_new = obj.find('bndbox')
xmin = str( width - int(obj_new.find('xmax').text))#此2行保证翻转后xmin<xmax
xmax = str( width - int(obj_new.find('xmin').text))
obj_new.find('xmin').text = xmin
obj_new.find('xmax').text = xmax
tree.write(new_xml)
if __name__ == '__main__':
# path = r'E:\数据集\VOC2007\Annotations'
path = r'D:\1Aqilei---npupt\tf-faster-rcnn-master\data\VOCdevkit2007\VOC2007\Annotations'
xml_files = [os.path.join(rootdir, file) for rootdir, _, files in os.walk(path) for file in files if
(file.endswith('.xml'))]
print(xml_files)
jpg_files = [xmlfile.replace('Annotations', 'JPEGImages').replace('xml', 'jpg') for xmlfile in xml_files]
#jpg_files =[xmlfile.replace('xml','jpg') for xmlfile in xml_files]
#print(jpg_files)
# jpg_old_files = jpg_files
files = zip(jpg_files,xml_files)
#print(files)
for jpg_file,xml_file in tqdm(files):
#print(jpg_file)
im = Image.open(jpg_file)
width = im.size[0]
# print(width)
new_jpg = jpg_file.replace(jpg_file.split('\\')[-1].split('.')[0],jpg_file.split('\\')[-1].split('.')[0] + '_filp')
#print(new_jpg)
# break
new_xml = new_jpg.replace('JPEGImages', 'Annotations').replace('jpg', 'xml')
# print(new_xml)
flip_xml(xml_file,new_xml,width)
flip_horizontal(jpg_file, new_jpg)
以上两个代码只需要改变路径就可以用了,数据增强完毕,翻了四倍。
5.生成4个txt文件
6.修改代码
6.1修改trainval_net.py
def parse_args():
"""
Parse input arguments
"""
parser = argparse.ArgumentParser(description='Train a Fast R-CNN network')
parser.add_argument('--cfg', dest='cfg_file',
help='optional config file',
default="../experiments/cfgs/res101.yml",type=str)
parser.add_argument('--weight', dest='weight',
help='initialize with pretrained model weights',
type=str,default="../data/imagenet_weights/res101.ckpt")
parser.add_argument('--imdb', dest='imdb_name',
help='dataset to train on',
default='voc_2007_trainval', type=str)
parser.add_argument('--imdbval', dest='imdbval_name',
help='dataset to validate on',
default='voc_2007_test', type=str)
parser.add_argument('--iters', dest='max_iters',
help='number of iterations to train',
default=70000, type=int)
parser.add_argument('--tag', dest='tag',
help='tag of the model',
default=None, type=str)
parser.add_argument('--net', dest='net',
help='vgg16, res50, res101, res152, mobile',
default='res101', type=str)
parser.add_argument('--set', dest='set_cfgs',
help='set config keys', default=None,
nargs=argparse.REMAINDER)
# if len(sys.argv) == 1:
# parser.print_help()
# sys.exit(1)
args = parser.parse_args()
return args
6.2 修改lib/datasets/pascal_voc.py
第36行的classe修改成自己的类别,background不可以删除
6.3修改lib/datasets/imdb.py
第25行_num_classes=? ,?换成你自己的类+1,比如香蕉,橘子,苹果三类,这里_num_classes就要等于3+1=4
7.执行trainval_net.py
训练的模型保存在out文件夹下
训练过程中遇到的问题(及针对自己的数据集的解决方法)
RuntimeWarning: invalid value encountered in log targets_dw = np.log(gt_widths / ex_widths) total loss=Nan
1.减小学习率 亲测不好用
2.这种报错说明数据集的数据有一些问题,多出现在没有控制好边界的情况,首先,打开lib/database/pascal_voc.py文件,找到208行,将208行至211行每一行后面的-1删除,如下所示:
x1 = float(bbox.find(‘xmin’).text)
y1 = float(bbox.find(‘ymin’).text)
x2 = float(bbox.find(‘xmax’).text)
y2 = float(bbox.find(‘ymax’).text)
原因是因为我们制作的xml文件中有些框的坐标是从左上角开始的,也就是(0,0)如果再减一就会出现log(-1)的情况
如果这样之后还是出现类似的报错,那么说明依然有-1或者其他负数的情况出现。解决方法是打开./lib/model/config.py文件,找到flipp选项,将其置为False
__C.TRAIN.USE_FLIPPED = False
如果这样以后还是报类似的错误,就一定检查一下自己制作数据集的过程,看看是否哪里没有考虑清楚。
亲测不好用!
3.打开