使用 Label Studio 与 MMDetection 训练目标检测 AI

标签和训练需要一些粘合剂

目录

当我 训练目标检测AI 一段时间之前 - LabelImg 是一个非常有用的工具, 但从 Label Studio 导出到 COCO 格式 不被 MMDetection 框架接受…

它需要一些工具和脚本来使所有内容正常工作。

topimage

在这里列出缺失的部分和一些脚本, 其中一些我在互联网上找到,其他是我自己写的。

基本步骤

准备、训练和使用AI涉及以下步骤:

  1. 获取源数据(用于目标检测和分类的图像)
  2. 标注图像并准备数据集
  3. 开发新模型或寻找合适的现有模型
  4. 训练模型,有时需要进行超参数调优
  5. 使用模型对新图像进行预测(推理)

在这里,我将给出如何使用 Label Studio 标注数据(步骤2), 以及如何使用 mmdetection 和 torchvision 进行训练(步骤4), 并简要介绍推理(步骤5)。

Label Studio

它有一些开源的 LabelImg 程序的根源, 但现在以一种非常集中的方式开发和维护。 当然,它也有企业版。

尽管如此,它仍然可以用于自托管,这非常不错。

配置和运行

可以通过多种方式安装和运行 Label Studio, 例如 pip 包, 或者 docker compose 容器组。 在这里,我使用单个 docker 容器。

准备源文件夹

mkdir ~/ls-data
sudo chown -R 1001:1001 ~/ls-data10

本地存储配置

mkdir ~/ai-local-store
mkdir ~/ai-local-labels

# 设置一些额外权限

/ai-local-store 中保存图像文件,/ai-local-labels - 同步的标签。

启动 docker 容器

docker run -it -p 8080:8080 \
    -e LABEL_STUDIO_HOST=http://your_ip_address:8080/ \
    -e LABEL_STUDIO_LOCAL_FILES_SERVING_ENABLED=true \
    -e LABEL_STUDIO_LOCAL_FILES_DOCUMENT_ROOT=/ai-local-store \
    -e DATA_UPLOAD_MAX_NUMBER_FILES=10000000 \
    -v /home/somename/ls-data:/label-studio/data \
    -v /home/somename/ai-local-store:/ai-local-store \
    -v /home/somename/ai-local-labels:/ai-local-labels \
    heartexlabs/label-studio:latest \
    label-studio \
    --log-level DEBUG

LABEL_STUDIO_HOST - 因为 LS webui 重定向。 DATA_UPLOAD_MAX_NUMBER_FILES … Django 上传文件数限制为 100,这对 Label Studio 影响非常糟糕,所以需要提供这个新限制。 所有其他配置在 Label Studio 文档 中都有详细说明。

导入配置。在项目设置中的云存储中添加本地文件类型的源存储,类似于:

topimage

如果你计划同步图像(我相信是的),请不要忘记勾选“将每个存储桶对象视为源文件”,而不是 json。 如果你已经为这些图像在单独的 json 中有一些标签,只需配置这个云存储。 不要点击 同步。 然后导入 json。

为目标云存储和 ai-local-labels 配置相同的内容 - 如果你想要同步它们。

将预标注数据导入 Label Studio

我喜欢 COCO json 格式。还有 Pascal VOC。 但它们与 Label Studio 不直接兼容,因此需要先转换为 LS 专有格式。

但在此之前,可能需要过滤数据集。你可能只需要其中的一些标签,而不是全部。 我喜欢来自 coco-manager 的 filter.py 脚本:https://github.com/immersive-limit/coco-manager/blob/master/filter.py

python filter.py --input_json instances_train2017.json --output_json filtered.json --categories person dog cat

好的,现在安装转换器。像官方站点推荐的那样:

python -m venv env
source env/bin/activate
git clone https://github.com/heartexlabs/label-studio-converter.git
cd label-studio-converter
pip install -e . 

从 coco 转换并设置正确文件夹

label-studio-converter import coco -i your-input-file.json -o output.json

通过点击 Label Studio 的导入按钮导入 output.json。

标注

在这里进行了大量极具创意的工作。

导出

在 Label Studio 中点击导出按钮并选择 COCO 导出格式后,查看这个文件中的图像名称。 如果你在导入标签之前没有覆盖图像基础路径,它们看起来会像这样:

  "images": [
    {
      "width": 800,
      "height": 600,
      "id": 0,
      "file_name": "\/data\/local-files\/?d=\/iteration1001\/123.jpg"
    },

或者如果你同步了外部云存储,它们看起来会像这样:

  "images": [
    {
      "width": 800,
      "height": 600,
      "id": 0,
      "file_name": "http:\/\/localhost:8080\/data\/local-files\/?d=iteration1001\/123.jpg"
    },

这些并不是非常理想。我们想要的是这样的:

  "images": [
    {
      "width": 800,
      "height": 600,
      "id": 0,
      "file_name": "iteration1001/123.jpg"
    },

为了解决文件名问题,我使用了漂亮的脚本。 它们会覆盖 result.json 文件, 所以如果你需要事先备份 - 请自行处理:

sed -i -e 's/\\\/data\\\/local-files\\\/?d=\\\///g' ~/tmp/result.json
sed -i "s%http:\\\/\\\/localhost:8080\\\/data\\\/local-files\\\/?d=%%" ~/tmp/result.json
sed -i "s%http:\\\/\\\/your_ip_address:8080\\\/data\\\/local-files\\\/?d=%%" ~/tmp/result.json

备份 Label Studio 数据和数据库

小心地停止你的 Label Studio docker 容器, 然后运行类似以下命令:

cp ~/ls-data ~/all-my-backups
cp ~/ai-local-store ~/all-my-backups
cp ~/ai-local-labels ~/all-my-backups

合并

有时需要将多个数据集合并为一个,特别是如果你运行了多个迭代。

我使用了 COCO-merger 工具。安装并使用 -h 参数运行后:

python tools/COCO_merger/merge.py -h

COCO Files Merge Usage

python -m COCO_merger.merge --src Json1.json Json2.json --out OUTPUT_JSON.json

Argument parser

usage: merge.py [-h] --src SRC SRC --out OUT

Merge two annotation files to one file

optional arguments:
  -h, --help     show this help message and exit
  --src SRC SRC  Path of two annotation files to merge
  --out OUT      Path of the output annotation file

是的,只能合并两个文件。所以如果你有10次迭代,需要额外努力。但我还是喜欢它。

MMDetection

topimage

分割数据集

为了将数据集分割为训练和测试,我使用了 COCOSplit 工具。

git clone https://github.com/akarazniewicz/cocosplit.git
cd cocosplit
pip install -r requirements

它并不太复杂:

$ python cocosplit.py -h
usage: cocosplit.py [-h] -s SPLIT [--having-annotations]
                    coco_annotations train test

将 COCO 注解文件分割为训练和测试集。

位置参数:
  coco_annotations      COCO 注解文件的路径。
  train                 存储 COCO 训练注解的位置
  test                  存储 COCO 测试注解的位置

可选参数:
  -h, --help            显示帮助信息并退出
  -s SPLIT              分割比例;一个在 (0, 1) 之间的数字
  --having-annotations  忽略所有没有注解的图像。只保留至少有一个注解的这些图像
  --multi-class         在保留训练和测试集中的类别分布的同时,分割多类别数据集

运行 coco 分割:

python cocosplit.py --having-annotations \
  --multi-class \
  -s 0.8 \
  source_coco_annotations.json \
  train.json \
  test.json

请记住在数据集 json 的开头添加 licenses 属性,位于第一个 “{” 之后。 这个分割工具真的需要它。

  "licenses": [],

配置

是的,模型配置是 复杂的

但 mask-rcnn 相当快,检测率也相当合理。 有关配置详细信息,请参见此处:https://mmdetection.readthedocs.io/en/latest/user_guides/train.html#train-with-customized-datasets

# 新配置继承一个基础配置以突出必要的修改
_base_ = '/home/someusername/mmdetection/configs/mask_rcnn/mask-rcnn_r50-caffe_fpn_ms-poly-1x_coco.py'

# 我们还需要更改头部的 num_classes 以匹配数据集的注解
model = dict(
    roi_head=dict(
        bbox_head=dict(num_classes=3),
        mask_head=dict(num_classes=3)))

# 修改与数据集相关的设置
data_root = '/home/someusername/'
metainfo = {
    'classes': ('MyClass1', 'AnotherClass2', 'AndTheLastOne3'),
    'palette': [
        (220, 20, 60),
        (20, 60, 220),
        (60, 220, 20),
    ]
}
train_dataloader = dict(
    batch_size=1,
    dataset=dict(
        data_root=data_root,
        metainfo=metainfo,
        ann_file='train.json',
        data_prefix=dict(img='')))
val_dataloader = dict(
    dataset=dict(
        data_root=data_root,
        metainfo=metainfo,
        ann_file='test.json',
        data_prefix=dict(img='')))
test_dataloader = val_dataloader

# 修改与指标相关的设置
val_evaluator = dict(ann_file=data_root+'test.json')
test_evaluator = val_evaluator

# 我们可以使用预训练的 Mask RCNN 模型以获得更高的性能
load_from = 'https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r50_caffe_fpn_mstrain-poly_3x_coco/mask_rcnn_r50_caffe_fpn_mstrain-poly_3x_coco_bbox_mAP-0.408__segm_mAP-0.37_20200504_163245-42aa3d00.pth'

# 如果你喜欢长电影
# 默认值在这里如果我记得正确是 12
train_cfg = dict(max_epochs=24) 

如果不需要掩码,可以参考这里:https://mmdetection.readthedocs.io/en/latest/user_guides/single_stage_as_rpn.html

训练

假设你的模型配置在 /home/someusername/myproject/models/configs/mask-rcnn_r50-caffe_fpn_ms-poly-1x_v1.0.py 中。 训练脚本是标准调用 mmdetection 工具:

cd ~/mmdetection
python tools/train.py \
    /home/someusername/myproject/models/configs/mask-rcnn_r50-caffe_fpn_ms-poly-1x_v1.0.py \
    --work-dir /home/someusername/myproject/work-dirs/my-object-detector-v1.0-mask-rcnn_r50-caffe_fpn_ms-poly-1x

推理

一些文档在这里:https://mmdetection.readthedocs.io/en/latest/user_guides/inference.html

from mmdet.apis import DetInferencer

inferencer = DetInferencer(
    model='/home/someusername/myproject/models/configs/mask-rcnn_r50-caffe_fpn_ms-poly-1x_v1.0.py',
    weights='/home/someusername/myproject/work-dirs/my-object-detector-v1.0-mask-rcnn_r50-caffe_fpn_ms-poly-1x/epoch_12.pth')

# 为单个文件运行:
# inferencer('demo/demo.jpg', out_dir='/home/someusername/myproject/test-output/1.0/', show=True)

# 或者为整个文件夹
inferencer('/home/someusername/myproject/test-images/', out_dir='/home/someusername/myproject/test-output/1.0/', no_save_pred=False)

有用的链接

希望这能以某种方式帮助你。

其他有用的阅读请参见: