2.1【Pytorch版(torch-cuda版)Mask-RCNN训练⾃⼰的数据集】
写在前⾯:由于课程试验要求,需要基于pytorch实现maskrcnn,so最近⼜跑了⼀下pytorch版的maskrcnn,官⽅已经给出了详细的教程,虽然说⽀持cpu推理,但是不⽀持cpu训练啊,奈何⼿头上只有⼀个cpu本,也没有nvida显卡,只有intel的集显,so整理⼀波本次训练maskrcnn的过程。
这篇blog是按照常规的torch版的maskrcnn的训练教程写的,理论上,所依赖的是torch-cuda版本,后续还有⼀篇是基于torch-cpu版本的。因为在试验过程中先踩了这部分的坑,所以写在前⾯。(再次提醒,如果电脑和本⼈⼀样只有intel集显的话,下⾯的⼀系列步骤对成功在电脑上跑通maskrcnn没有任何帮助,本⼈的下⼀篇blog会提到如何不⽤cuda在cpu本下跑maskrcnn。这篇blog仅仅是为了⽅便疫情过后可以回到实验室继续搞,提前做好记录。)
环境:
Ubuntu16.04
torch == 1.5.0+cu92
连衣裙款式torchvision == 0.6.0+cu92
这⾥要注意,torch版本>=0.3.0即可,使⽤的torch和torchvision是匹配的,且都是cuda版本,如何选择这两个的匹配版本,请看:
具体操作流程见我的另⼀篇blog,⾥⾯有提到:
⼀、下载官⽅demo并配置环境
先去官⽹将代码下载下来 github/facebookresearch/maskrcnn-benchmark
cd maskrcnn-benchmark-master
sudo python3 setup.py build develop
笔者现有打包好的pycharm虚拟环境中包含了⼤部分需要配置安装的模块,so最初笔者是缺什么模块补什么模块,折腾了⼀番还是有问题,最终屈服了,直接运⾏上述命令,bingo。
安装好setup中要求的环境之后,可以根据官⽹的教程进⾏测试。
cd demo炒丝瓜的做法
# by default, it runs on the GPU
# for best results, use min-image-size 800
python webcam.py --min-image-size 800
# can also run it on the CPU
python webcam.py --min-image-size 300 MODEL.DEVICE cpu
# or change the model that you want to use
python webcam.py --config-file../configs/caffe2/e2e_mask_rcnn_R_101_FPN_1x_caffe2.yaml --min-image-size 300 MODEL.DEVICE cpu
# in order to see the probability heatmaps, pass --show-mask-heatmaps
python webcam.py --min-image-size 300--show-mask-heatmaps MODEL.DEVICE cpu
# for the keypoint demo
python webcam.py --config-file../configs/caffe2/e2e_keypoint_rcnn_R_50_FPN_1x_caffe2.yaml --min-image-size 300 MODEL.DEVICE cpu
简单的⽤前两种测试⼀下就可以了,在测试过程中可能会提⽰你缺少某些模块,对应安装就可以了。(如何解决python安装模块慢的问题,可以参看我的另⼀篇blog,,不得不说,⼯具选得好,效率刷刷得往上彪)
⾄此,倘若还缺少apex库,建议通过github下载,然后再进⾏安装,因为本⼈直接通过pip安装后,后续运⾏demo的时候还会报错,保险起见,采⽤前者。
github/NVIDIA/apex
cd apex-master
sudo python3 setup.py install
⼆、数据准备及模型配置
Step1:转换数据格式
笔者是采⽤labelme来标注的,需要对格式进⾏转换,转为coco格式,转换代码如下:
# -*- coding:utf-8 -*-
# !/usr/bin/env python
import argparse
import json
import matplotlib.pyplot as plt
from labelme import utils
import skimage.io as io
import sys
ve('/opt/ros/kinetic/lib/python2.7/dist-packages')
import cv2
import numpy as np
import glob
import PIL.Image常常的近义词是什么
ry import Polygon#adthedocs.io/en/latest/manual.html#geometric-objects
class labelme2coco(object):
def__init__(self,labelme_json=[],save_json_path='/home/eden/Downloads/maskrcnn-benchmark/datasets/val2020.json'): '''
:param labelme_json: 所有labelme的json⽂件路径组成的列表
:param save_json_path: json保存位置
'''
self.labelme_json=labelme_json#所有的json⽂件
self.save_json_path=save_json_path#输出⽂件new.json的路径
self.images=[]
self.categories=[]
self.annotations=[]
# self.data_coco = {}
self.label=[]
self.annID=1
self.height=0
self.width=0
self.save_json()
#我的数据⽤label标注的名称格式是:000001.jpg、
def data_transfer(self):
for num,json_file in enumerate(self.labelme_json):
with open(json_file,'r')as fp:
data = json.load(fp)# 加载json⽂件
self.images.append(self.image(data,num))
for shapes in data['shapes']:
label=shapes['label'].split('_')
if label[0]not in self.label:
self.categories.append(self.categorie(label))
self.label.append(label[0])
points=shapes['points']
self.annotations.append(self.annotation(points,label,num))
self.annID+=1
感冒通 打一成语def image(self,data,num):
image={}
历史典故img = utils.img_b64_to_arr(data['imageData'])# 解析原图⽚数据
# img=io.imread(data['imagePath']) # 通过图⽚路径打开图⽚
# img = cv2.imread(data['imagePath'], 0)
height, width = img.shape[:2]
img =None
image['height']=height
image['width']= width
image['id']=num+1
image['file_name']= data['imagePath'].split('/')[-1]
self.height=height
self.height=height
self.width=width
return image
def categorie(self,label):
categorie={}
categorie['supercategory']= label[0]
categorie['id']=len(self.label)+1# 0 默认为背景
categorie['name']= label[0]
return categorie
def annotation(self,points,label,num):
annotation={}
annotation['segmentation']=[list(np.asarray(points).flatten())]
poly = Polygon(points)
annotation['iscrowd']=0
annotation['image_id']= num+1
area_ =round(poly.area,6)
annotation['area']= area_
# annotation['bbox'] = bbox(points)) # 使⽤list保存json⽂件时报错(不知道为什么)
# list(map(int,a[1:-1].split(','))) a=annotation['bbox'] 使⽤该⽅式转成list
annotation['bbox']=list(map(bbox(points)))
annotation['category_id']= atid(label)
annotation['id']= self.annID
return annotation
def getcatid(self,label):
for categorie in self.categories:
if label==categorie['name']:
return categorie['id']
return-1
def getbbox(self,points):
# img = np.zeros([self.height,self.width],np.uint8)
# cv2.polylines(img, [np.asarray(points)], True, 1, lineType=cv2.LINE_AA) # 画边界线
# cv2.fillPoly(img, [np.asarray(points)], 1) # 画多边形内部像素值为1
polygons = points
mask = self.polygons_to_mask([self.height,self.width], polygons)
return self.mask2box(mask)
def mask2box(self, mask):
'''从mask反算出其边框
mask:[h,w] 0、1组成的图⽚
1对应对象,只需计算1对应的⾏列号(左上⾓⾏列号,右下⾓⾏列号,就可以算出其边框)
'''
# np.where(mask==1)
index = np.argwhere(mask ==1)
rows = index[:,0]
clos = index[:,1]
# 解析左上⾓⾏列号
left_top_r = np.min(rows)# y
left_top_c = np.min(clos)# x伽罗的历史原型是谁
# 解析右下⾓⾏列号
right_bottom_r = np.max(rows)
right_bottom_c = np.max(clos)
return[left_top_c, left_top_r, right_bottom_c-left_top_c, right_bottom_r-left_top_r]# [x1,y1,w,h] 对应COCO的bbox格式
def polygons_to_mask(self,img_shape, polygons):
mask = np.zeros(img_shape, dtype=np.uint8)
mask = PIL.Image.fromarray(mask)
xy =list(map(tuple, polygons))
PIL.ImageDraw.Draw(mask).polygon(xy=xy, outline=1, fill=1)
mask = np .array (mask , dtype =bool )
return mask
def data2coco (self ):
data_coco ={}
data_coco ['images']=self .images
data_coco ['categories']=self .categories
data_coco ['annotations']=self .annotations
return data_coco
def save_json (self ):
self .data_transfer ()
self .data_coco = self .data2coco ()
# 保存json ⽂件
json .dump (self .data_coco , open (self .save_json_path , 'w'), indent =4) # indent=4 更加美观显⽰
labelme_json =[]
for i in range (1,71):#遍历所有的labelme 标准的json ,载⼊并转换
ind ='/home/eden/Mask_RCNN-master/data/train_data/json/'+str (i ).zfill (6)+'.json'
labelme_json .append (ind )
lab = labelme2coco (labelme_json )#调⽤labelme2coco 类
print ('Saved to :',lab .save_json_path )#保存
我的数据的名称格式是:000001.jpg、000002.jpg…。⼀般的数据格式是 ⽗类_⼦类_***.jpg,倘若你的数据格式是这样的,主要修改这个函数的代码。
def data_transfer(self):
主要⽤来修改label的截断以符合⾃⼰的数据格式,同时还要注意对应修改该函数下的label
def categorie(self,label):
转换为之后会在当前⽬录下⽣成⼀个新的json⽂件,该json⽂件满⾜coco格式(注:上述代码⽣成的coco json⽂件并不包含area参数,实验说明即使json⽂件中没有area参数也不影响后续正常训练。)
关于coco 数据格式的⼀些资料:
对coco 数据集的详细解读:
Step2:配置数据格式
接下来进⼊到maskrcnn-benchmark-master下的maskrcnn_benchmark⽂件夹,新建、⽂件夹,
在datasets⽂件夹下继续新建⼀个名为coco的⽂件夹,在coco⽂件夹下新建三个⽂件夹,名称分别为、、,
(其实没有必要严格的按照这个格式来,实际上只是为了和⽬前的⼀些数据格式保持⼀致,只要后⾯对
数据集路径的修改都严格的改成⾃⼰的路径就可以了。)
annotations⽂件夹下存放两个json⽂件,分别为train2020.json和val2020.json(这两个⽂件就是经过上述格式转换demo得到的,其中所对应的图⽚是train2020和val2020⽂件夹下的图⽚)
图⽚数据整理好了之后,接下⾥就是配置模型⽂件了。
插⼊⼀个常识:有时在训练时为了⽅便,直接将训练集和验证集使⽤同⼀个数据集,这样做并不可取。理由见该博⽂:
Step3:配置模型⽂件
datasets myconfig annotations train 2020val 2020
1. 在新建的myconfig⽂件下将./maskrcnn-benchmark-master/configs⾥想要训练的.yaml配置⽂件复制过去,把并且把
./maskrcnn-benchmark-master/maskrcnn_benchmark/
config⽂件夹下的__pycache__和paths_catalogs.py复制到到myconfig⽂件夹下,本⽂使⽤的是e2e_mask_rcnn_fbnet.yaml。
2. 修改maskrcnn_benchmark/utils下的checkpoint.py,注释65和68两⾏(self.optimizer.load_state…和self.scheduler.load_…)
3. 修改paths_catalogs.py⽂件,将训练样本和验证样本的路径修改为⾃⼰的数据路径:
接下来修改.yaml模型配置参数,主要修改NUM_CLASSES,DATASETS中的train和test ,模型保存⽂件OUTPUT_DIR以及
PATHS_CATALOG
我的训练类别只有⼀类,所以NUM_CLASSES=2
DATASETS如上,这⾥要注意的时,即使你的训练或测试只有⼀个数据样本,后⾯的逗号也不可以去掉。
最后加上OUTPUT_DIR和PATHS_CATALOG。其他的关于batch size、学习率等等,依照个⼈实际情况进⾏配置即可。
三、训练
戏剧性的转折来了,理论上来说到此为⽌,只要在⽂件跟⽬录下运⾏:
python3 tools/train_net.py --config-file=.yaml⽂件的路径
这个时候就已经开始训练了,但⽆奈的是,本⼈安装的是torch-cpu版本,所以会显⽰如下错误,
这是因为apex依赖于cuda,本⼈电脑也没有nvida显卡,所以也没有安装cuda版本的torch,通过⼀番搜寻发现,有⽹友说即便如此,只要安装cuda版本的torch和torchvision也是可以正常运⾏的,由于时间关系,重新搭建⼀个虚拟环境再下载⼀⼤堆的安装包时间很长(主要是本⼈硬件垃圾,⽽且⽹速也差劲),这⼀⽅法就没有尝试,待疫情过后到实验室再尝试吧。如果你的电脑可安装cuda,那么可继续按照下⾯的来,如果像我⼀样,只有intel集显的话,请看下⼀篇blog中提到的⼀种在cpu下训练maskrcnn的⽅法。
本篇blog主要参考资料:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论