从图像标注开始,用 Byzer 加 Xtreme1 完成图像实例分割训练

2022-11-12 13:49:26 浏览数 (1)

该文需要将于 2022年11月发布的 Byzer 2.4.0 以及最新版本的 Byzer Notebook来支持,尽情期待。

背景

要完整的支持深度学习,需要一个很长的 Pipeline,通常我们的工作起步于标注平台, 尽管Byzer 也可以作为标注平台的上游,比如对图片和视频做一个统一的处理(诸如缩放成统一大小等),然后再放到标注平台里。

相比直接使用标注工具诸如 Lableimg 以及 Pytorch 等框架, 使用 Xtreme1 和 Byzer 则更适合形成一个完整和顺畅的工作流,我们会在文章中体会到这一点的。

另外,通过该文,我们可以看到 Byzer 作为胶水语言,可以很好的衔接多种工具,完成复杂的 Pipeline。

环境

你需要一个 Linux 环境,最好有 GPU。然后安装如下三个软件:

  1. Xtreme1 标注平台 安装文档参考: https://github.com/basicai/xtreme1
  2. Byzer Notebook 安装文档 Byzer Notebook 安装
  3. Byzer-lang 执行引擎 Byzer-lang 安装

标注

Xtreme1 最快捷的体验方式是 Docker ,启动后,需要先自助注册一个账号,然后登录。

点击图中的红框,进入数据集界面。

点击右上角的创建数据集,然后上传一个 zip 格式打包的图片数据集就可以了。我这里取名为 balloon, 里面有60张图片。

我标注了两张,只是为了做演示。标注完成后,就可以选择右上角的 Export:

导出后右下角,可以看到一个导出成功的图表,其实这里导出的是一个 json 文件,里面有标注信息以及图片 的地址。

实际上,这个标注文件以及原始的图片,都在 Minio上,该存储是 Xtreme1 自带的一个对象存储。Byzer 可以直接访问这个存储,所以无需下载和手动写代码去拉取图片。

加载、保存标注数据

自助注册和登录 Byzer Notebook后,因为需要访问 Minio 对象存储,我们需要有个驱动,可以在 Byzer Notebook 里执行插件安装的命令:

该插件比较大,下载时间较长。

接着安装 Xtreme1 数据源插件:

安装完成后,可以给 Minio 设置连接信息:

注意, endpoint 需要修改成一个实际的地址。

用户可以登录到 Minio 看看目录结构以及随意找一张图片的地址:

然后使用 Byzer Notebook 加载该图片,看看是不是能访问 Minio:

上面图的输出说明Byzer 已经可以访问 Minio了。

现在我们来加载下刚刚标注的数据。因为我只标注了两张,我们看看加载完后是不是数量是对的:

注意加载的路径是一个json文件,该文件存储在 Mino上, Byzer 会生成一个表,该表包含图片名称,图片标注信息,以及图片二进制三个字段。

如果图片很多,用户可以通过将标注的所有数据保存到数据湖,可以加速后续的访问。注意,这是个可选项。在Byzer 中你只要使用 save 语法即可完成。

从这里我们可以看到,我们可以轻松的把非结构化数据以及对应的标注信息以表结构的形态进行保存。

转换成 Coco 标注格式 并且使用 detectron2 进行训练

这里用户需要在安装 Byzer 的机器上提供一个合适的 Python 环境,我们推荐使用conda, 在下面的示例中,我们使用一个名称叫 ray-1.12.0 的。需要至少包含如下几个依赖包:

  1. pyjava
  2. byzer-cocodataset
  3. pytorch
  4. detectron2

然后在 Byzer Notebook 新建一个 Python 的 Cell:

第一个 input 框填写的是数据集对应的表,也就是前面我们用 load 语法得到的数据集。 schema 为 file 表示最后我们会输出一个模型表,虽然对应的模型是目录,但是Byzer 也可以将其转化表来存储。我们来看下完整代码:

代码语言:javascript复制
#%python
#%input=new_ballon_dataset
#%output=out
#%schema=file
#%runIn=driver
#�taMode=model
#�che=true
#%env=source /opt/miniconda3/bin/activate ray-1.12.0


from pyjava.api.mlsql import RayContext,PythonContext
from tech.mlsql.plugin.ds.coco import create_coco_format_json

import torch, detectron2
import os

## Some basic setup:
## Setup detectron2 logger
import detectron2
from detectron2.utils.logger import setup_logger
setup_logger()


## import some common detectron2 utilities
from detectron2 import model_zoo
from detectron2.engine import DefaultPredictor
from detectron2.config import get_cfg
from detectron2.utils.visualizer import Visualizer
from detectron2.data.datasets import register_coco_instances
from detectron2.engine import DefaultTrainer


context:PythonContext = context
ray_context = RayContext.connect(globals(),None)

rows = ray_context.collect()

create_coco_format_json(rows,"/tmp/new_ballon_dataset2")

TORCH_VERSION = ".".join(torch.__version__.split(".")[:2])
CUDA_VERSION = torch.__version__.split(" ")[-1]
print("torch: ", TORCH_VERSION, "; cuda: ", CUDA_VERSION)
print("detectron2:", detectron2.__version__)


cfg = get_cfg()
## add project-specific config (e.g., TensorMask) here if you're not running a model in detectron2's core library
cfg.merge_from_file(model_zoo.get_config_file("COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml"))
cfg.MODEL.ROI_HEADS.SCORE_THRESH_TEST = 0.5  # set threshold for this model
## Find a model from detectron2's model zoo. You can use the https://dl.fbaipublicfiles... url as well
cfg.MODEL.WEIGHTS = model_zoo.get_checkpoint_url("COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml")
predictor = DefaultPredictor(cfg)

register_coco_instances("new_ballon_dataset", {}, "/tmp/new_ballon_dataset2/annotations/coco.json", "/tmp/new_ballon_dataset2/images")


cfg = get_cfg()
cfg.merge_from_file(model_zoo.get_config_file("COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml"))
cfg.DATASETS.TRAIN = ("new_ballon_dataset",)
cfg.DATASETS.TEST = ()
cfg.DATALOADER.NUM_WORKERS = 2
cfg.MODEL.WEIGHTS = model_zoo.get_checkpoint_url("COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml")  # Let training initialize from model zoo
cfg.SOLVER.IMS_PER_BATCH = 2  ## This is the real "batch size" commonly known to deep learning people
cfg.SOLVER.BASE_LR = 0.00025  ## pick a good LR
cfg.SOLVER.MAX_ITER = 300    ## 300 iterations seems good enough for this toy dataset; you will need to train longer for a practical dataset
cfg.SOLVER.STEPS = []        ## do not decay learning rate
cfg.MODEL.ROI_HEADS.BATCH_SIZE_PER_IMAGE = 128   ## The "RoIHead batch size". 128 is faster, and good enough for this toy dataset (default: 512)
cfg.MODEL.ROI_HEADS.NUM_CLASSES = 1  ## only has one class (ballon). (see https://detectron2.readthedocs.io/tutorials/datasets.html#update-the-config-for-new-datasets)
## NOTE: this config means the number of classes, but a few popular unofficial tutorials incorrect uses num_classes 1 here.

os.makedirs(cfg.OUTPUT_DIR, exist_ok=True)
trainer = DefaultTrainer(cfg) 
trainer.resume_or_load(resume=False)
trainer.train()

model_path = os.path.join(cfg.OUTPUT_DIR, "model_final.pth") 
model_binary = [item for item in streaming_tar.build_rows_from_file(model_path)]

context.build_result(model_binary)

这里值得关注的是, Byzer-python 仅仅关注输入和输出,输入主要是数据集,这里是指我们前面加载的表,然后通过 byzer-cocodataset 库中的 create_coco_format_json 方法将其转换为 Coco 数据集,然后就可以使用 detectron2 做训练了,最后将模型保存后,重新输出成表,后续方便保存到诸如数据湖中。

总结

在这里我们没有演示如何使用 Byzer 进行模型注册并且支持 API,流,批中的使用,感兴趣的同学可以参考诸如 祝威廉:如何基于 Byzer 使用深度学习快速开发一个图片分类应用 之类的文章。

在本篇文章中, Byzer 使用简单的语法即可读取标注数据,并且将其转化为标准数据集,进而使用 Python中的detectron2 进行处理。

0 人点赞