赞
踩
一、安装
- # 创建环境名为mmdet
- conda create -n mmdet python=3.7
- # 激活环境mmdet
- conda activate mmdet
- # 安装pytorch1.6
- # 安装torchvision0.7.0
- # 安装cuda,此处注意cuda版本要对应上或电脑已经安装了更高的版本,cuda版本向下兼容,电脑安装最新的cuda并把驱动升级到最新。
- conda install pytorch==1.6.0 torchvision==0.7.0 cudatoolkit=10.2 -c pytorch
- # 安装对应版本的mmcv-full,这个是官方已经给编译过的,安装时注意版本与上一步相同。cu102为cudatoolkit10.2,torch1.6.0为pytorch1.6.0。对应不上安装时看不出来,用的时候必报错,而且找不到原因。而且这是官方编译好的,意味着不能瞎改pytorch版本。
- pip install mmcv-full==1.4.6 -f https://download.openmmlab.com/mmcv/dist/cu102/torch1.6.0/index.html
- # 安装mmdet,安装检测模块的需要的包
- pip install mmdet
- # 安装mmrotate,安装旋转检测模块需要的包,这个不用mmrotate可不安
- pip install mmrotate
- # 也可以用另一种方法安装mmrotate
- git clone https://github.com/open-mmlab/mmrotate.git
- cd mmrotate
- pip install -r requirements/build.txt
- pip install -v -e .

1.报错不要慌,领悟每个命令行作用的同时,看看版本对没对上,csdn好多博文版本没对上或者用mim安装导致各种报错。
2.安装失败,这只是一种可能,看看是否安装了VS2019 C++buildtool,因为之前安装pycocotool的时候因为没安装这个工具导致安装不上。安装这个工具即使不需要,也没有任何害处,可能将来会用到。
二、demo演示文件测试效果
进入image_demo.py文件,读一读。
- # ....
- def parse_args():
- parser = ArgumentParser()
- parser.add_argument('img', help='Image file')
- parser.add_argument('config', help='Config file')
- parser.add_argument('checkpoint', help='Checkpoint file')
- # ....
稍加修改,让配置参数时,更加规整而且配置时一一对应,更加严谨。
- # ....
- def parse_args():
- parser = ArgumentParser()
- parser.add_argument('--img', help='Image file')
- parser.add_argument('--config', help='Config file')
- parser.add_argument('--checkpoint', help='Checkpoint file')
- # ....
pycharm中配置参数:1.图片路径2.模型路径3.权重路径;此处的模型与权重最好时完全对应上。
- --img
- D:\\Project\\mmdetection-master\\demo\\demo.jpg
- --config
- D:\\Project\\mmdetection-master\\configs\\faster_rcnn\\faster_rcnn_r50_fpn_1x_coco.py
- --checkpoint
- D:\\Project\\mmdetection-master\\faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth
报个小错,无伤大雅。小小警告,一般都是告诉我xx已经淘汰了;被xx替代了;建议替换等等。
结果出来了,意味着你的环境配置已经问题不大了,后面如果缺组件,在现在的环境内pip install xxx即可。
三、简单的口罩检测——训练自己的数据集
1.首先准备好数据集——一些未标注的图片
2.用labelme标注软件进行标注
labelme安装很简单,在本环境安装就行。
- # 安装pyqt5
- pip install pyqt5
- # 安装labelme
- pip install labelme
- # 运行labelme
- labelme
标注过程过于简单,不赘述。注意:
(1)不要乱改标注后的json文件名,要一一对应。
(2)矩形框标注从左上到右下符合图片坐标的规定。
3.json to coco,格式转换。
运行一下脚本,注意输入文件位置与输出文件位置。
- import os
- import json
- import numpy as np
- import glob
- import shutil
- import cv2
- from sklearn.model_selection import train_test_split
-
- np.random.seed(41)
-
- classname_to_id = {
- "mask": 0, #改成自己的类别
- "person": 1
- }
-
-
- class Lableme2CoCo:
-
- def __init__(self):
- self.images = []
- self.annotations = []
- self.categories = []
- self.img_id = 0
- self.ann_id = 0
-
- def save_coco_json(self, instance, save_path):
- json.dump(instance, open(save_path, 'w', encoding='utf-8'), ensure_ascii=False, indent=1) # indent=2 更加美观显示
-
- # 由json文件构建COCO
- def to_coco(self, json_path_list):
- self._init_categories()
- for json_path in json_path_list:
- obj = self.read_jsonfile(json_path)
- self.images.append(self._image(obj, json_path))
- shapes = obj['shapes']
- for shape in shapes:
- annotation = self._annotation(shape)
- self.annotations.append(annotation)
- self.ann_id += 1
- self.img_id += 1
- instance = {}
- instance['info'] = 'spytensor created'
- instance['license'] = ['license']
- instance['images'] = self.images
- instance['annotations'] = self.annotations
- instance['categories'] = self.categories
- return instance
-
- # 构建类别
- def _init_categories(self):
- for k, v in classname_to_id.items():
- category = {}
- category['id'] = v
- category['name'] = k
- self.categories.append(category)
-
- # 构建COCO的image字段
- def _image(self, obj, path):
- image = {}
- from labelme import utils
- img_x = utils.img_b64_to_arr(obj['imageData'])
- h, w = img_x.shape[:-1]
- image['height'] = h
- image['width'] = w
- image['id'] = self.img_id
- image['file_name'] = os.path.basename(path).replace(".json", ".jpg")
- return image
-
- # 构建COCO的annotation字段
- def _annotation(self, shape):
- # print('shape', shape)
- label = shape['label']
- points = shape['points']
- annotation = {}
- annotation['id'] = self.ann_id
- annotation['image_id'] = self.img_id
- annotation['category_id'] = int(classname_to_id[label])
- annotation['segmentation'] = [np.asarray(points).flatten().tolist()]
- annotation['bbox'] = self._get_box(points)
- annotation['iscrowd'] = 0
- annotation['area'] = 1.0
- return annotation
-
- # 读取json文件,返回一个json对象
- def read_jsonfile(self, path):
- with open(path, "r", encoding='utf-8') as f:
- return json.load(f)
-
- # COCO的格式: [x1,y1,w,h] 对应COCO的bbox格式
- def _get_box(self, points):
- min_x = min_y = np.inf
- max_x = max_y = 0
- for x, y in points:
- min_x = min(min_x, x)
- min_y = min(min_y, y)
- max_x = max(max_x, x)
- max_y = max(max_y, y)
- return [min_x, min_y, max_x - min_x, max_y - min_y]
- #训练过程中,如果遇到Index put requires the source and destination dtypes match, got Long for the destination and Int for the source
- #参考:https://github.com/open-mmlab/mmdetection/issues/6706
- if __name__ == '__main__':
- labelme_path = "./labelme-data/maskdataset"
- saved_coco_path = "./labelme-data/coco-format"
- print('reading...')
- # 创建文件
- if not os.path.exists("%scoco/annotations/" % saved_coco_path):
- os.makedirs("%scoco/annotations/" % saved_coco_path)
- if not os.path.exists("%scoco/images/train2017/" % saved_coco_path):
- os.makedirs("%scoco/images/train2017" % saved_coco_path)
- if not os.path.exists("%scoco/images/val2017/" % saved_coco_path):
- os.makedirs("%scoco/images/val2017" % saved_coco_path)
- # 获取images目录下所有的joson文件列表
- print(labelme_path + "/*.json")
- json_list_path = glob.glob(labelme_path + "/*.json")
- print('json_list_path: ', len(json_list_path))
- # 数据划分,这里没有区分val2017和tran2017目录,所有图片都放在images目录下
- train_path, val_path = train_test_split(json_list_path, test_size=0.1, train_size=0.9)
- print("train_n:", len(train_path), 'val_n:', len(val_path))
-
- # 把训练集转化为COCO的json格式
- l2c_train = Lableme2CoCo()
- train_instance = l2c_train.to_coco(train_path)
- l2c_train.save_coco_json(train_instance, '%scoco/annotations/instances_train2017.json' % saved_coco_path)
- for file in train_path:
- # shutil.copy(file.replace("json", "jpg"), "%scoco/images/train2017/" % saved_coco_path)
- img_name = file.replace('json', 'jpg')
- temp_img = cv2.imread(img_name)
- try:
- cv2.imwrite("{}coco/images/train2017/{}".format(saved_coco_path, img_name.split('\\')[-1].replace('png', 'jpg')), temp_img)
- except Exception as e:
- print(e)
- print('Wrong Image:', img_name )
- continue
- print(img_name + '-->', img_name.replace('png', 'jpg'))
-
- for file in val_path:
- # shutil.copy(file.replace("json", "jpg"), "%scoco/images/val2017/" % saved_coco_path)
- img_name = file.replace('json', 'jpg')
- temp_img = cv2.imread(img_name)
- try:
- cv2.imwrite("{}coco/images/val2017/{}".format(saved_coco_path, img_name.split('\\')[-1].replace('png', 'jpg')), temp_img)
- except Exception as e:
- print(e)
- print('Wrong Image:', img_name)
- continue
- print(img_name + '-->', img_name.replace('png', 'jpg'))
-
- # 把验证集转化为COCO的json格式
- l2c_val = Lableme2CoCo()
- val_instance = l2c_val.to_coco(val_path)
- l2c_val.save_coco_json(val_instance, '%scoco/annotations/instances_val2017.json' % saved_coco_path)
-

路径分布
instances_train2017.json节取
- {
- "info": "spytensor created",
- "license": [
- "license"
- ],
- "images": [
- {
- "height": 737,
- "width": 1024,
- "id": 0,
- "file_name": "19.jpg"
- },
- ...
- ],
- "annotations": [
- {
- "id": 0,
- "image_id": 0,
- "category_id": 0,
- "segmentation": [
- [
- 52.74809160305344,
- 350.9083969465649,
- 191.6793893129771,
- 457.0152671755725
- ]
- ],
- "bbox": [
- 52.74809160305344,
- 350.9083969465649,
- 138.93129770992365,
- 106.1068702290076
- ],
- "iscrowd": 0,
- "area": 1.0
- },
- ...
- ],
- "categories": [
- {
- "id": 0,
- "name": "mask"
- },
- {
- "id": 1,
- "name": "person"
- }
- ]
- }

在 json 文件中有三个必要的键:
images
: 包含多个图片以及它们的信息的数组,例如 file_name
、height
、width
和 id
。
annotations
: 包含多个实例标注信息的数组。
categories
: 包含多个类别名字和 ID 的数组。
4.对应自己的数据集去修改源码的类别
因为采用的时coco格式,故去修改源码中coco(80个类别)的类别,改成自己数据集的两个类别。
1.修改第一处
mmdet\core\evaluation\class_names.py
- # ...
- def coco_classes():
- # return [
- # 'person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train',
- # 'truck', 'boat', 'traffic_light', 'fire_hydrant', 'stop_sign',
- # 'parking_meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep',
- # 'cow', 'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella',
- # 'handbag', 'tie', 'suitcase', 'frisbee', 'skis', 'snowboard',
- # 'sports_ball', 'kite', 'baseball_bat', 'baseball_glove', 'skateboard',
- # 'surfboard', 'tennis_racket', 'bottle', 'wine_glass', 'cup', 'fork',
- # 'knife', 'spoon', 'bowl', 'banana', 'apple', 'sandwich', 'orange',
- # 'broccoli', 'carrot', 'hot_dog', 'pizza', 'donut', 'cake', 'chair',
- # 'couch', 'potted_plant', 'bed', 'dining_table', 'toilet', 'tv',
- # 'laptop', 'mouse', 'remote', 'keyboard', 'cell_phone', 'microwave',
- # 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase',
- # 'scissors', 'teddy_bear', 'hair_drier', 'toothbrush'
- # ]
- return [
- 'mask', 'person',
- ]
- # ...

把80类注释掉,改成自己的类别,不改就会出现类别的检测错误,mask检测成person,person检测成bicycle。
2.修改第二处
mmdet\datasets\coco.py
- class CocoDataset(CustomDataset):
-
- # CLASSES = ('person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus',
- # 'train', 'truck', 'boat', 'traffic light', 'fire hydrant',
- # 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog',
- # 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe',
- # 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee',
- # 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat',
- # 'baseball glove', 'skateboard', 'surfboard', 'tennis racket',
- # 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl',
- # 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot',
- # 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch',
- # 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop',
- # 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave',
- # 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock',
- # 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush')
- #
- # PALETTE = [(220, 20, 60), (119, 11, 32), (0, 0, 142), (0, 0, 230),
- # (106, 0, 228), (0, 60, 100), (0, 80, 100), (0, 0, 70),
- # (0, 0, 192), (250, 170, 30), (100, 170, 30), (220, 220, 0),
- # (175, 116, 175), (250, 0, 30), (165, 42, 42), (255, 77, 255),
- # (0, 226, 252), (182, 182, 255), (0, 82, 0), (120, 166, 157),
- # (110, 76, 0), (174, 57, 255), (199, 100, 0), (72, 0, 118),
- # (255, 179, 240), (0, 125, 92), (209, 0, 151), (188, 208, 182),
- # (0, 220, 176), (255, 99, 164), (92, 0, 73), (133, 129, 255),
- # (78, 180, 255), (0, 228, 0), (174, 255, 243), (45, 89, 255),
- # (134, 134, 103), (145, 148, 174), (255, 208, 186),
- # (197, 226, 255), (171, 134, 1), (109, 63, 54), (207, 138, 255),
- # (151, 0, 95), (9, 80, 61), (84, 105, 51), (74, 65, 105),
- # (166, 196, 102), (208, 195, 210), (255, 109, 65), (0, 143, 149),
- # (179, 0, 194), (209, 99, 106), (5, 121, 0), (227, 255, 205),
- # (147, 186, 208), (153, 69, 1), (3, 95, 161), (163, 255, 0),
- # (119, 0, 170), (0, 182, 199), (0, 165, 120), (183, 130, 88),
- # (95, 32, 0), (130, 114, 135), (110, 129, 133), (166, 74, 118),
- # (219, 142, 185), (79, 210, 114), (178, 90, 62), (65, 70, 15),
- # (127, 167, 115), (59, 105, 106), (142, 108, 45), (196, 172, 0),
- # (95, 54, 80), (128, 76, 255), (201, 57, 1), (246, 0, 122),
- # (191, 162, 208)]
- CLASSES = ('mask', 'person')
-
- PALETTE = [(220, 20, 60), (119, 11, 32)]

类别和颜色做一下修改。
3.配置文件修改
生成自己的配置文件:因为项目自带的配置文件由于模块化设计,有继承关系,参数不能在一个文件上修改,配置参数很麻烦。采用一种方法:先把要用的模型的配置文件在train中作为配置参数运行一遍,会在work_dir文件中找到一个完整的配置文件。
1.复制想要的模型的配置文件绝对路径。
2.将绝对路径复制放进pycharm配置参数
3.运行后在work_dir中找到并改名
4.修改输出类别数量,coco数据集80类,自己数据集2类。num_classes
- # ...
- bbox_head=dict(
- type='DeformableDETRHead',
- num_query=300,
- num_classes=80,
- in_channels=2048,
- sync_cls_avg_factor=True,
- as_two_stage=False,
- # ...
- # ...
- bbox_head=dict(
- type='DeformableDETRHead',
- num_query=300,
- num_classes=2,
- in_channels=2048,
- sync_cls_avg_factor=True,
- as_two_stage=False,
- # ...
5.修改训练集和验证集路径
- # ...
- train=dict(
- type='CocoDataset',
- ann_file='D:\\Project\\mmdetection-master\\mmdet\\data\\labelme-data\\coco-formatcoco\\annotations\\instances_train2017.json',
- img_prefix='D:\\Project\\mmdetection-master\\mmdet\\data\\labelme-data\\coco-formatcoco\\images\\train2017',
- # ...
-
- # ...
- val=dict(
- type='CocoDataset',
- ann_file='D:\\Project\\mmdetection-master\\mmdet\\data\\labelme-data\\coco-formatcoco\\annotations\\instances_val2017.json',
- img_prefix='D:\\Project\\mmdetection-master\\mmdet\\data\\labelme-data\\coco-formatcoco\\images\\val2017',
- # ...
6.加上预训练模型
load_from = 'D:\\Project\\mmdetection-master\\deformable_detr_r50_16x2_50e_coco_20210419_220030-a12b9512.pth'
7.修改训练的配置
batch size和num_workers,这个算法很吃内存,batch size=1
- # ...
- data = dict(
- samples_per_gpu=1,
- workers_per_gpu=1,
- # ...
修改这一块,50个epoch
- evaluation = dict(interval=10, metric='bbox')
- checkpoint_config = dict(interval=50)
- log_config = dict(interval=10, hooks=[dict(type='TextLoggerHook')])
- custom_hooks = [dict(type='NumClassCheckHook')]
- dist_params = dict(backend='nccl')
- log_level = 'INFO'
- load_from = 'D:\Project\mmdetection-master\deformable_detr_r50_16x2_50e_coco_20210419_220030-a12b9512.pth'
- resume_from = None
- workflow = [('train', 1)]
- opencv_num_threads = 0
- mp_start_method = 'fork'
- auto_scale_lr = dict(enable=False, base_batch_size=32)
8.重新编译文件,修改完 class_names.py 和 voc.py 之后一定要重新编译代码(运行python setup.py install,要不报错AssertionError: The `num_classes` (80) in Shared2FCBBoxHead of MMDataParallel does not matche。
9.开始训练
电脑配置不够,内存爆了,一顿操作猛如虎,一看结果250,以后拿个简单的模型试一试,但是过程是可以借鉴的。
换Faster r-cnn,同样的思路,再用demo检测一下。
- --img
- D:\\Project\\mmdetection-master\\demo\\mask.jpg
- --config
- D:\\Project\\mmdetection-master\\configs\\faster_rcnn\\my_faster_rcnn_r50_fpn_1x_coco.py
- --checkpoint
- D:\\Project\\mmdetection-master\\tools\\work_dirs\\faster_rcnn_r50_fpn_1x_coco\\epoch_30.pth
这么少的数据集,能有这个效果,已经不错了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。