maskrcnn食用手册

maskrcnn食用手册

Step1. 配置环境及安装

我的基础环境:

系统:ubuntu16.04
内核:Linux 4.15.0-45-generic
python版本:3.5.2

安装依赖项

pip install ninja yacs cython matplotlib opencv-python pillow sklearn tqdm utils
安装python3-tk

PyTorch from a nightly release. Installation instructions can be found in https://pytorch.org/get-started/locally/
按照官网给的指令安装

安装torchvision

pip install torchvision

安装pycocotools、apex

cd $INSTALL_DIR
git clone https://github.com/cocodataset/cocoapi.git
cd cocoapi/PythonAPI
python setup.py build_ext install

cd $INSTALL_DIR
git clone https://github.com/NVIDIA/apex.git
cd apex
python setup.py install --cuda_ext --cpp_ext

N卡加速

cuda:
download: https://developer.nvidia.com/cuda-toolkit-archive
installation guide: https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html

sudo dpkg -i cuda-repo-ubuntu1604<<>>
sudo apt-key add /var/cuda-repo-<<>>/7fa2af80.pub
sudo apt-get update
sudo apt-get install cuda

安装完成后,将以下内容加到~/.bashrc最后

export PATH=/usr/local/cuda-9.0/bin:$PATH
export LD_LIBRARY_PATH=/usr/local/cuda-9.0/lib64:$LD_LIBRARY_PATH

检查cuda安装是否成功:

nvcc -V

若输出cuda版本信息,代表正常

#编译并测试设备 deviceQuery:
cd /usr/local/cuda-9.2/samples/1_Utilities/deviceQuery
sudo make
./deviceQuery

#编译并测试带宽 bandwidthTest:
cd ../bandwidthTest
sudo make
./bandwidthTest

若这两个测试的最后结果都是Result = PASS,说明cuda安装成功。

若已有其他版本cuda,可选择安装多个版本。安装时需要指定版本,如安装cuda10.0:

sudo apt-get install cuda-10-0

注意修改.bashrc
切换默认的cuda版本:

sudo rm -rf cuda
sudo ln -s /usr/local/cuda- /usr/local/cuda

cudnn(optional):
download (need a nvidia account): https://developer.nvidia.com/rdp/cudnn-archive
安装:如果下载的文件是solitairetheme8格式,执行

cp  cudnn--linux-x64-v.solitairetheme8 cudnn--linux-x64-v.tgz

执行:

tar -xvf cudnn-<<>>
sudo cp cuda/include/cudnn.h /usr/local/cuda/include/
sudo cp cuda/lib64/libcudnn* /usr/local/cuda/lib64/
sudo chmod a+r /usr/local/cuda/include/cudnn.h
sudo chmod a+r /usr/local/cuda/lib64/libcudnn*

查看已安装版本:

cat /usr/local/cuda/include/cudnn.h | grep CUDNN_MAJOR -A 2

安装cudnn的Runtime Library , Develop Library , Code Samples and User Guide:

sudo dpkg -i *.deb

安装maskrcnn-benchmark

cd $INSTALL_DIR
git clone https://github.com/facebookresearch/maskrcnn-benchmark.git
cd maskrcnn-benchmark

python setup.py build develop

unset INSTALL_DIR

到此,maskrcnn-benchmark安装完成。

Step2. 测试

maskrcnn提供了测试用模型,该模型共提供了80种物品的识别,而且精度也是比较好的,可以通过以下代码执行(首次执行需要联网下载模型):

cd $INSTALL_DIR/maskrcnn-benchmark/demo
sudo python3 webcam.py

如果你的电脑自带或已连接摄像头,它将调取默认摄像头,基于模型对视频做物品的识别,并将识别结果显示在屏幕上。

Step3. 使用

训练自己的模型

官方给的模型再好,大部分情况下还是不能满足我们的使用需求,所以这时就需要我们自己训练模型,用于我们特定的任务。

1.准备、标记训练集

首先准备出我们待识别物品的图片,最好是多角度的。然后把它放到一个文件夹里

安装工具labelme:

pip install labelme

打开labelme:

labelme

选择放图片的文件夹,载入图片。对每张图片上待辨识的物品,点击Create Polygons,将每个待识别的物品用多边形描绘出闭合边框,闭合后打上标签。当该图片上的所有待识别物品都已经打好标签,点击Save保存,就会将该图片的信息保存为一个同名的json文件。

2.生成coco训练集

将刚刚整个文件夹命名为’labelme’,下载或复制代码到labelme上层:
代码参考:https://github.com/spytensor/prepare_detection_dataset

#https://github.com/spytensor/prepare_detection_dataset
#coding:utf-8
import os
import json
import numpy as np
import glob
import shutil
from sklearn.model_selection import train_test_split
np.random.seed(41)

#0为背景

classname_to_id = {"vita_tea": 1, "biscuit": 2, "crisps": 3, "chocolate": 4, "lemon_tea": 5, "coke_cola": 6, "chew_gum": 7}

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):
        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]


if __name__ == '__main__':
    labelme_path = "./labelme/"
    saved_coco_path = "./"
    # 创建文件
    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目录下所有的json文件列表
    json_list_path = glob.glob(labelme_path + "/*.json")
    # 数据划分,这里没有区分val2017和train2017目录,所有图片都放在images目录下
    train_path, val_path = train_test_split(json_list_path, test_size=0.12)
    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)
    for file in val_path:
        shutil.copy(file.replace("json","jpg"),"%scoco/images/val2017/"%saved_coco_path)

    # 把验证集转化为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)

其中需要修改的地方就是最开始的classname_to_id那个字典,需要按照示例的形式将标签与序号对应起来,完成后执行代码,就会在代码同目录下生成一个coco文件夹,这就是我们需要的coco数据集。

3.修改配置文件

在maskrcnn-benchmark下创建文件夹datasets,将coco整个文件夹放入datasets中。

在maskrcnn-benchmark/maskrcnn-benchmark/paths_catalog.py中有训练集的名字、图片路径和生成的注解。这里需要把路径修改到刚刚的coco文件夹位置。这里建议都用绝对路径,一般文件没找到的就是相对路径的锅。

接下来在maskrcnn-benchmark/config下有一些配置文件,我比较常用的是e2e_mask_rcnn_R_101_FPN_1x.yaml,如果电脑配置不太好的话可以改用e2e_mask_rcnn_R_50_FPN_1x.yaml。这里也有一些东西需要增加或修改,这边贴一个我用的配置,有注释的地方是需要注意的

MODEL:
  META_ARCHITECTURE: "GeneralizedRCNN"
  # 如果是新开始的训练,WEIGHT置空即可。如果接着训练这里要给出模型的路径  
  WEIGHT: ‘’
  BACKBONE:
    CONV_BODY: "R-101-FPN"
  RESNETS:
    BACKBONE_OUT_CHANNELS: 256
  RPN:
    USE_FPN: True
    ANCHOR_STRIDE: (4, 8, 16, 32, 64)
    PRE_NMS_TOP_N_TRAIN: 2000
    PRE_NMS_TOP_N_TEST: 1000
    POST_NMS_TOP_N_TEST: 1000
    FPN_POST_NMS_TOP_N_TEST: 1000
  ROI_HEADS:
    USE_FPN: True
  ROI_BOX_HEAD:
    POOLER_RESOLUTION: 7
    POOLER_SCALES: (0.25, 0.125, 0.0625, 0.03125)
    POOLER_SAMPLING_RATIO: 2
    FEATURE_EXTRACTOR: "FPN2MLPFeatureExtractor"
    PREDICTOR: "FPNPredictor"
    # 这里要给出待辨识的物体数+1(因为有背景)
    NUM_CLASSES: 4
  ROI_MASK_HEAD:
    POOLER_SCALES: (0.25, 0.125, 0.0625, 0.03125)
    FEATURE_EXTRACTOR: "MaskRCNNFPNFeatureExtractor"
    PREDICTOR: "MaskRCNNC4Predictor"
    POOLER_RESOLUTION: 14
    POOLER_SAMPLING_RATIO: 2
    RESOLUTION: 28
    SHARE_BOX_FEATURE_EXTRACTOR: False
  MASK_ON: True
DATASETS
  # 这里给出训练集的名字,要和paths_catalog.py的名字对应起来
  # 同时要保留括号里的最后一个逗号
  TRAIN: ("coco_2017_train",)
  TEST: ("coco_2017_val",)
DATALOADER:
  NUM_WORKERS: 0
  SIZE_DIVISIBILITY: 32
SOLVER
  # 基础学习率,如果模型不收敛(loss是nan)就要把这里改小一点
  # 如果太小会导致训练进度非常缓慢
  BASE_LR: 0.002
  WEIGHT_DECAY: 0.0001
  STEPS: (60000, 80000)
  # 这是最大迭代次数,训练这么多轮之后会自动停止
  MAX_ITER: 100000
  # 这里是每批训练的图片数。如果爆显存了(什么什么overflow)就把这里改小
  IMS_PER_BATCH: 1
  # 这是存档点,就是每训练多少轮存一次当前模型
  CHECKPOINT_PERIOD: 1000
# 这是存档和最终模型的保存路径,可以随意设置
OUTPUT_DIR: "/home/syq/github/maskrcnn-benchmark/weight

其实还会遇到一些错误,不过看得懂英文应该都可以改掉。我记得还有一个Syntax Error是因为一个地方前面多了一个f,删掉就好了

4.训练

接下来就可以开始训练了。我一般习惯把这个文件放在tools/下面,因为不会和使用时的配置文件搞混。要引用这个配置文件的内容,可以在train_net.py中config_files部分的default处填上这个文件的路径,或者直接在命令中给出

sudo python3 ./tools/train_net.py --config-file ./tools/config_files/e2e_mask_rcnn_R_101_FPN_1x.yaml

训练当中可以强制停止,已经过的存档点模型将会保存到预设路径下,没有保存的进度将会丢失,之后仍可以通过载入旧模型继续训练。

5.测试

复制一份配置文件到./demo/下,把路径改为刚训练好的模型的路径,并且在predictor.py中把CATEGORIES修改为你训练的标签(在存放模型的地方有一个文件给出了标签的顺序,按照那个顺序填入标签),要保留__background标签。
然后就可以运行webcam.py,并引入这个配置文件来实际测试训练模型的效果如何。

Step4. 更多

在上面的步骤中,我们只能得到一张分隔好的图片,如果要借助分割信息来做一些自动化的工作,就必须知道图片上有哪些物品,可能还需要知道它们在哪里。

要达成这个目的,我们需要从原来的代码中将这项信息return回来。
./demo/predictor.py中,194行的run_on_opencv_image(self, image)函数中的top_predictions就是我们需要的信息。在217行的return语句中,我们将它连同result一起return回来,即将return语句修改为

return result, top_predictions

同时需要修改webcam.py来显示这些信息或者对其做进一步的分析和操作。这里因为我不太想对源文件做改动,所以重写了该文件,有一些不必要的也略去了,仅供参考。

# my_predictor_camera.py
# coding:utf-8
from maskrcnn_benchmark.config import cfg
from predictor import COCODemo
import argparse
import torch
import time
import cv2
import os

config_file = "/home/syq/github/maskrcnn-benchmark/demo/config_files/e2e_mask_rcnn_R_101_FPN_1x_caffe2.yaml"

# update the config options with the config file
cfg.merge_from_file(config_file)
# manual override some options
cfg.merge_from_list(["MODEL.DEVICE", "cuda"]);

coco_demo = COCODemo(
    cfg,
    min_image_size = 800,
    confidence_threshold = 0.7,
)

capture = cv2.VideoCapture(0)
while True:
    start_time = time.time()
    ret, img = capture.read()
    img = cv2.flip(img, 1)
    composite, top_predictions = coco_demo.run_on_opencv_image(img)
    scores = top_predictions.get_field("scores").tolist()
    boxes = top_predictions.bbox
    labels = top_predictions.get_field("labels").tolist()
    for score, box, label in zip(scores, boxes, labels):
        box = box.to(torch.int64)
        top_left, bottom_right = box[:2].tolist(), box[2:].tolist()
        print(label, score, [top_left, bottom_right])
    print("Time: {:.2f} s / img".format(time.time() - start_time))
    cv2.imshow("COCO detections", composite)
    if cv2.waitKey(1) == 27:
       break  # esc to quit

cv2.destroyAllWindows()

这里的 coco_demo.run_on_opencv_image(img)返回结果改为:composite和top_predictions,这就是我们新拿到手的信息。经过这里的处理,我们可以对每帧图片中的每个物品的编号、坐标、识别概率打印到终端中,也可以通过编号、编号和标签的对应关系拿到物品的标签,以开展更多的用途。

你可能感兴趣的:(python,深度学习,神经网络,机器学习,pytorch)