网上很多都是基于linux和pytorch0.4.1的训练教程,为了不重装cuda和pytorch,直接在自己电脑上搭建centernet环境并训练自己的数据集;【win10+cuda10.0+cudnn7.6.2+pytorch1.0.1+1660ti】
避免本文太长,先分几部分分别介绍
1、centernet论文和理论
2、搭建centernet环境(win10+pytorch1.0.1)
3、训练自己的数据集(记录报错问题)
论文地址:https://arxiv.org/pdf/1904.07850.pdf
论文代码:https://github.com/xingyizhou/CenterNet
2019 年 4 月,得克萨斯奥斯汀大学和伯克利提出了同名的 CenterNet :Objects as Points,取得了最佳的速度-准确性权衡;尝试利用物体中心点的信息进行物体检测。网上对centernet介绍的文章非常多,这里就不单独写篇文章介绍了,直接贴出几篇浏览量排在前面的几篇供参考。
论文精读——CenterNet :Objects as Points
论文也撞衫,你更喜欢哪个无锚点CenterNet?
主要是在win10上对centernet环境的搭建,作者源代码在GitHub上是基于linux系统上的,但网上也有很多基于win上环境搭建,改几行代码编译一下就可以,贴上写的较详细的教程:win10 + cuda10.0 + pytorch1.2 + CenterNet 环境搭建
在最后跑模型的时候出了一个错误:
urllib.error.HTTPError: HTTP Error 404: Not Found
主要原因是在运行完
python demo.py ctdet --demo ../images/17790319373_bd19b24cfc_k.jpg --load_model ../models/ctdet_coco_dla_2x.pth
这条命令行后,它会自动下载dla34-ba72cf86.pth模型导致出错,所以可以离线下载并放在C:\Users\ ***\ .torch\models下(每个人路径不一样)
这里增加两点:
如果要调用网络摄像头,命令如下
python demo.py ctdet --demo webcam --load_model ../models/ctdet_coco_dla_2x.pth
如果要输出关键点热力图,命令如下
python demo.py ctdet --demo ../images/17790319373_bd19b24cfc_k.jpg --load_model ../models/ctdet_coco_dla_2x.pth --debug 2
python demo.py multi_pose --demo ../images/17790319373_bd19b24cfc_k.jpg --load_model ../models/multi_pose_dla_3x.pth --debug 2
如果还出现别的问题,来这里:https://github.com/xingyizhou/CenterNet/issues/7 基本上覆盖了所有的问题。
1、这里的数据集一般是images和自己标注好的xml文件,需要将voc格式转化为coco格式,也就是将xml转为json文件,val、test、train三部分分别转为成对应的json文件,贴上别人的代码:能找到的尽量不自己写
这里报了一个错误:
SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in position 2-3:
这个错误很低级,就是路径转义的问题,在路径前面加上r或者将反斜杠换为正斜杠
2、生成三个json文件后,在centernet/data下新建一个新的文件夹(名字取自己要训练的名称,注意不能中文,不然后面会报错)
三个json文件放annotations里面
images里面把所有的图片放进来(val+test+train)
3、计算均值和标准差,后续改配置文件的时候需要用到图片总的均值和标准差,这里先计算一下,直接计算的代码
import cv2, os, argparse
import numpy as np
from tqdm import tqdm
def main():
dirs = r'F:\CenterNet\data\headout\images' # 修改你自己的图片路径
img_file_names = os.listdir(dirs)
m_list, s_list = [], []
for img_filename in tqdm(img_file_names):
img = cv2.imread(dirs + '/' + img_filename)
img = img / 255.0
m, s = cv2.meanStdDev(img)
m_list.append(m.reshape((3,)))
s_list.append(s.reshape((3,)))
m_array = np.array(m_list)
s_array = np.array(s_list)
m = m_array.mean(axis=0, keepdims=True)
s = s_array.mean(axis=0, keepdims=True)
print("mean = ", m[0][::-1])
print("std = ", s[0][::-1])
if __name__ == '__main__':
main()
这里我用的另外一种方法:毕竟还是用的别人的
因为报错了,所以提一下;
报错一:
ImportError: cannot import name 'PILLOW_VERSION' from 'PIL'
原因:torchvision 模块内import pillow的时候发现找不到PILLOW_VERSION, 因为默认装的最新版本为7.0.0,在 7.0.0 后的版本就没有 PILLOW_VERSION了。把它改为6.0.0即可
报错二:
cannot import name 'imread' from 'scipy.misc'
原因:版本过高,把1.3.1改为1.2.1,pip install scipy==1.2.1,虽然成功了,但还是提示scipy.misc.imread()被弃用,应该用imageio.imwrite()来替代
3、修改配置文件,在src/lib/datasets/dataset里面新建一个“ped. py”,文件内容先把文件夹下coco.py全部复制过来再进行修改
a:类COCO改为自己设置的文件名ped
class Ped(data.Dataset):
b:15行num_classes=80改成自己的类别数
c:17行的mean和std改成自己图片数据集的均值和标准差
num_classes = 6
default_resolution = [512, 512]
mean = np.array([0.304048, 0.300987, 0.298292],
dtype=np.float32).reshape(1, 1, 3)
std = np.array([0.326341, 0.326124, 0.325749],
dtype=np.float32).reshape(1, 1, 3)
d:修改数据和图片路径,data_dir 输入的是咱们之前建立的数据集文件夹的名字,img_dir 输入的是 images 图片文件夹,super后的类改为Ped
def __init__(self, opt, split):
super(Ped, self).__init__()
self.data_dir = os.path.join(opt.data_dir, 'headout')
self.img_dir = os.path.join(self.data_dir, 'images')
e:修改Json文件路径,并且把test的也加上,后续测试时需要用到
if split == 'val':
self.annot_path = os.path.join(
self.data_dir, 'annotations',
'val.json').format(split)
else:
if opt.task == 'exdet':
self.annot_path = os.path.join(
self.data_dir, 'annotations',
'train.json').format(split)
if split == 'test':
self.annot_path = os.path.join(
self.data_dir, 'annotations',
'test.json').format(split)
else:
self.annot_path = os.path.join(
self.data_dir, 'annotations',
'train.json').format(split)
f:类别名和类别id。这里得根据生成的json文件里面的类别和id一一对应,不然后续测试的结果类别会弄混。
self.max_objs = 128
self.class_name = [
'__background__', 'openwindow', 'stand_2', 'no_brake', 'leave_2', 'sit_2', 'opendoor'
]
self._valid_ids = [0, 1, 2, 3, 4, 5, 6]
4、将数据集加入src/lib/datasets/dataset_factory.py里面,导入自己的类Ped以及在dataset_factory字典里加入自己的数据集名字
from .dataset.ped import Ped
dataset_factory = {
'coco': COCO,
'pascal': PascalVOC,
'kitti': KITTI,
'coco_hp': COCOHP,
'ped': Ped
}
5、修改/src/lib/opts.py
a:将自己的数据集设为默认数据集,加入到help里面
self.parser.add_argument('--dataset', default='ped',
help='coco | kitti | coco_hp | pascal | ped')
b:修改ctdet任务使用的默认数据集改为新添加的数据集,修改分辨率,类别数,均值,标准差,数据集名字
def init(self, args=''):
default_dataset_info = {
'ctdet': {'default_resolution': [512, 512], 'num_classes': 6,
'mean': [0.304, 0.300, 0.298], 'std': [0.326, 0.326, 0.325],
'dataset': 'ped'},
c:修改batch_size,出现内存溢出的报错,就把batchsize改小一点
self.parser.add_argument('--batch_size', type=int, default=4,
help='batch size')
6、修改src/lib/utils/debugger.py文件(变成自己数据的类别和名字,前后数据集名字一定保持一致)
a:46行加上这两行
elif num_classes == 6 or dataset == 'ped':
self.names = ped_class_name
b:460行加上自己的类(不要背景)
ped_class_name = [
'openwindow', 'no_brake', 'opendoor', 'sit_2', 'stand_2',
'leave_2']
我的环境是win10+cuda10.0+cudnn7.6.2+pytorch1.0.1+1660ti
cuda10和cudnn的搭建就不提了,网上的教程也非常多
主要提一下pytorch的安装,我是离线安装的:教程
第二部分已经搭建好了centernet的环境了,接下来就是训练数据了
在.Centernet/src/目录下,运行main.py文件,这里head改成你自己要保存的实验结果文件夹名称即可:
1、不加载预训练权重
python main.py ctdet --exp_id head --batch_size 4 --lr 1.25e-4 --gpus 0
2、加载预训练权重
python main.py ctdet --exp_id head --batch_size 4 --lr 1.25e-4 --gpus 0 --load_model ../models/ctdet_coco_dla_2x.pth
3、断点恢复训练
python main.py ctdet --exp_id head --batch_size 4 --lr 1.25e-4 --gpus 0 --resume
成功开始训练
训练完成后,在./exp/ctdet/head/文件夹下会出现一堆文件;
其中,model_last是最后一次epoch的模型;model_best是val最好的模型;
运行test.py文件
python test.py --exp_id head --not_prefetch_test ctdet --load_model ../exp/ctdet/food/model_best.pth
输出结果(我是在自己的笔记本上运行的,样本只用100张,epoch也只有40个,只是为了跑通算法哈,所以结果0.0)
测试单张图片(因为效果并不理想,图就不放出来了)
python demo.py ctdet --demo ../data/head/images/image1.jpg --load_model ../exp/ctdet/food/model_best.pth
如果需要保存你的预测结果,可以到目录 /src/lib/detecors/ctdet.py下,在show_results函数中的末尾加入这句:
debugger.save_all_imgs(path='/CenterNet-master/outputs', genID=True)
写个py文件将F:\CenterNet\exp\ctdet\head\logs_2020-01-13-09-42目录下的log.txt里的loss值绘制成曲线
其实过程并没有这么简单,遇到了非常多的问题,筛选几个多数会碰到的问题
1、训练阶段一开始就报错,错误如下:
AttributeError: Can't pickle local object 'get_dataset.<locals>.Dataset'
(tensorflow-gpu) F:\CenterNet\src>Traceback (most recent call last):
File "" , line 1, in <module>
File "D:\Anaconda\envs\tensorflow-gpu\lib\multiprocessing\spawn.py", line 105, in spawn_main
exitcode = _main(fd)
File "D:\Anaconda\envs\tensorflow-gpu\lib\multiprocessing\spawn.py", line 115, in _main
self = reduction.pickle.load(from_parent)
EOFError: Ran out of input
大多数都遇到了这个问题,有些论坛上说在main.py文件前面加上
torch.backends.cudnn.enabled = False
但还是报错了,尝试好多方法后最终发现是num_workers的问题,修改方法是在/src/lib/opts.py把num_workers修改为0
self.parser.add_argument('--num_workers', type=int, default=0,
help='dataloader threads. 0 for single-thread.')
之后在训练第五步后进行val的时候又会报这个错误,在main.py文件修改为0
val_loader = torch.utils.data.DataLoader(
Dataset(opt, 'val'),
batch_size=1,
shuffle=False,
num_workers=0,
pin_memory=True
)
理由:官方解释:DataLoader的函数定义中num_workers是使用多进程加载的进程数,0代表不使用多进程;使用dataloader读取数据时,如果设置num_workers为0,也就是用主进程读取数据,模型训练程序运行正常。如果设置num_workers为其他任何一个大于0的整数,也就是使用子进程读取数据时,训练程序会卡住,卡在训练之前,GPU使用率和显存占用率都为0,导致图片读取不了而报错。
2、报错信息如下
AttributeError: 'NoneType' object has no attribute 'shape'
训练阶段报错,在datasets/sample/ctdet.py文件添加
file_name = self.coco.loadImgs(ids=[img_id])[0]['file_name']
self.img_dir = 'F:/CenterNet/data/headout/images/'
file_name = file_name + ".png"
img_path = os.path.join(self.img_dir, file_name)
之后在测试阶段也报报错,在test.py文件修改
第32行
img_id = self.images[index]
img_info = self.load_image_func(ids=[img_id])[0]['file_name']
# print(img_info)
self.img_dir = 'F:/CenterNet/data/headout/images/'
img_info = img_info + ".png"
img_path = os.path.join(self.img_dir, img_info)
第63行,num_workers改为0,同第一个问题
data_loader = torch.utils.data.DataLoader(
PrefetchDataset(opt, dataset, detector.pre_process),
batch_size=1, shuffle=False, num_workers=0, pin_memory=True)
第103行,这里要添加两次路径,第二处一开始没看到,找了好久好久才发现这里还要改
for ind in range(num_iters):
img_id = dataset.images[ind]
img_info = dataset.coco.loadImgs(ids=[img_id])[0]['file_name']
dataset.img_dir = 'F:/CenterNet/data/headout/images/'
img_info = img_info + ".png"
img_path = os.path.join(dataset.img_dir, img_info)
理由:这个错误是查了好多资料才发现的,报错原因是没有加载到图片,图片的路径不对,原来的self.img_dir定义了一个路径,但与本机的不符,所以在上面加一行,重新定义一下图片路径。
3、cocoapi报错 pycocotools
这个在配置centernet环境的时候用不到,但在训练的时候却需要,按照官方https://github.com/cocodataset/cocoapi的安装方法并不能成功,报错找不到对象;
在https://github.com/philferriere/cocoapi 上下载源码,这也是支持在windows系统的版本,并且要安装VS2017,之后在cmd上编译就可以了。
python setup.py install
4、测试的时候,运行test时,会将网络预测的测试集图片的结果保存为results.json ,然后与标签test.json进行比较来计算AP,然后我们发现,results里面目标的中心点坐标就为框的中心点坐标,而之前生成的test里面框的中心点坐标实际为框的左上角坐标,因此重新生成一下test.json,修改其标签信息与results相对应才可。
经过好多天的奋斗,也总算把centernet跑通了,了解的并不深入,希望可以和大家一起学习!!!