乐趣区

关于后端:使用EasyCV-Mask2Former轻松实现图像分割

简介:EasyCV 能够轻松预测图像的宰割谱以及训练定制化的宰割模型。本文次要介绍如何应用 EasyCV 实现实例宰割、全景宰割和语义宰割,及相干算法思维。作者:贺弘 谦言 临在导言图像宰割 (Image Segmentation) 是指对图片进行像素级的分类,依据分类粒度的不同能够分为语义宰割 (Semantic Segmentation)、实例宰割(Instance Segmentation)、全景宰割(Panoptic Segmentation) 三类。图像宰割是计算机视觉中的次要钻研方向之一,在医学图像剖析、主动驾驶、视频监控、加强事实、图像压缩等畛域有重要的利用价值。咱们在 EasyCV 框架中对这三类宰割 SOTA 算法进行了集成,并提供了相干模型权重。通过 EasyCV 能够轻松预测图像的宰割谱以及训练定制化的宰割模型。本文次要介绍如何应用 EasyCV 实现实例宰割、全景宰割和语义宰割,及相干算法思维。应用 EasyCV 预测宰割图 EasyCV 提供了在 coco 数据集上训练的实例宰割模型和全景宰割模型以及在 ADE20K 上训练的语义宰割模型,参考 EasyCV quick start(https://github.com/alibaba/Ea…)实现依赖环境的配置后,能够间接应用这些模型实现对图像的宰割谱预测,相干模型链接在 reference 中给出。实例宰割预测因为该示例中的 mask2fromer 算法应用了 Deformable attention (在 DETR 系列算法中应用该算子能够无效晋升算法收敛速度和计算效率),须要额定对该算子进行编译 cd thirdparty/deformable_attention
python setup.py build install 通过 Mask2formerPredictor 预测图像实例宰割图 import cv2
from easycv.predictors.segmentation import Mask2formerPredictor

predictor = Mask2formerPredictor(model_path=’mask2former_instance_export.pth’,task_mode=’instance’)
img = cv2.imread(‘000000123213.jpg’)
predict_out = predictor([‘000000123213.jpg’])
instance_img = predictor.show_instance(img, **predict_out[0])
cv2.imwrite(‘instance_out.jpg’,instance_img)输入后果如下图:

全景宰割预测通过 Mask2formerPredictor 预测图像全景宰割图 import cv2
from easycv.predictors.segmentation import Mask2formerPredictor

predictor = Mask2formerPredictor(model_path=’mask2former_pan_export.pth’,task_mode=’panoptic’)
img = cv2.imread(‘000000123213.jpg’)
predict_out = predictor([‘000000123213.jpg’])
pan_img = predictor.show_panoptic(img, **predict_out[0])
cv2.imwrite(‘pan_out.jpg’,pan_img)输入后果如下图:

语义宰割预测通过 Mask2formerPredictor 预测图像语义宰割图 import cv2
from easycv.predictors.segmentation import Mask2formerPredictor

predictor = Mask2formerPredictor(model_path=’mask2former_semantic_export.pth’,task_mode=’semantic’)
img = cv2.imread(‘000000123213.jpg’)
predict_out = predictor([‘000000123213.jpg’])
semantic_img = predictor.show_panoptic(img, **predict_out[0])
cv2.imwrite(‘semantic_out.jpg’,semantic_img)

示例图片起源:cocodataset 在阿里云机器学习平台 PAI 上应用 Mask2Former 模型 PAI-DSW(Data Science Workshop)是阿里云机器学习平台 PAI 开发的云上 IDE,面向各类开发者,提供了交互式的编程环境。在 DSW Gallery 中(链接),提供了各种 Notebook 示例,不便用户轻松上手 DSW,搭建各种机器学习利用。咱们也在 DSW Gallery 中上架了 Mask2Former 进行图像宰割的 Sample Notebook(见下图),欢送大家体验!

Mask2Former 算法解读上述例子中采纳的模型是基于 Mask2former 实现的,Mask2former 是一个对立的宰割架构,可能同时进行语义宰割、实例宰割以及全景宰割,并且获得 SOTA 的后果,在 COCO 数据集上全景宰割精度 57.8 PQ,实例宰割精度达 50.1 AP,在 ADE20K 数据集上语义宰割精度达 57.7 mIoU。

核心思想 Mask2Former 采纳 mask classification 的模式来进行宰割,即通过模型去预测一组二值 mask 再组合成最终的宰割图。每个二值 mask 能够代表类别或实例,就能够实现语义宰割、实例宰割等不同的宰割工作。在 mask classsification 工作中,一个比拟外围的问题是如何去找到一个好的模式学习二值 Mask。如先前的工作 Mask R-CNN 通过 bounding boxes 来限度特色区域,在区域内预测各自的宰割谱。这种形式也导致 Mask R-CNN 只能进行实例宰割。Mask2Former 参考 DETR 的形式,通过一组固定数量的特征向量 (object query) 去示意二值 Mask,通过 Transformer Decoder 进行解码去预测这一组 Mask。(ps:对于 DETR 的解读能够参考:基于 EasyCV 复现 DETR 和 DAB-DETR,Object Query 的正确打开方式)在 DETR 系列的算法中,有一个比拟重要的缺点是在 Transformer Decoder 中的 cross attention 中会对全局的特色进行解决,导致模型很难关注到真正想要关注的区域,会升高模型的收敛速度和最终的算法精度。对于这个问题 Mask2former 提出了 Transformer Decoder with mask attention,每个 Transformer Decoder block 会去预测一个 attention mask 并以 0.5 为阈值进行二值化,而后将这个 attentino mask 作为下一个 block 的输出,让 attention 模块计算时只关注在 mask 的前景局部。模型构造

Mask2Former 由三个局部组成:Backbone(ResNet、Swin Transformer)从图片中抽取低分辨率特色 Pixel Decoder 从低分辩率特色中逐渐进行上采样解码,取得从低分辨率到高分辨率的特色金字塔,循环的作为 Transformer Decoder 中 V、K 的输出。通过多尺度的特色来保障模型对不同尺度的指标的预测精度。其中一层的 Trasformer 代码如下所示(ps:为了进一步减速模型的收敛速度,在 Pixel Decoder 中采纳了 Deformable attention 模块):class MSDeformAttnTransformerEncoderLayer(nn.Module):

def __init__(self,
             d_model=256,
             d_ffn=1024,
             dropout=0.1,
             activation='relu',
             n_levels=4,
             n_heads=8,
             n_points=4):
                 super().__init__()

                 # self attention
                 self.self_attn = MSDeformAttn(d_model, n_levels, n_heads, n_points)
                 self.dropout1 = nn.Dropout(dropout)
                 self.norm1 = nn.LayerNorm(d_model)

                 # ffn
                 self.linear1 = nn.Linear(d_model, d_ffn)
                 self.activation = _get_activation_fn(activation)
                 self.dropout2 = nn.Dropout(dropout)
                 self.linear2 = nn.Linear(d_ffn, d_model)
                 self.dropout3 = nn.Dropout(dropout)
                 self.norm2 = nn.LayerNorm(d_model)

@staticmethod
def with_pos_embed(tensor, pos):
    return tensor if pos is None else tensor + pos

def forward_ffn(self, src):
    src2 = self.linear2(self.dropout2(self.activation(self.linear1(src))))
    src = src + self.dropout3(src2)
    src = self.norm2(src)
    return src

def forward(self,
            src,
            pos,
            reference_points,
            spatial_shapes,
            level_start_index,
            padding_mask=None):
                # self attention
                src2 = self.self_attn(self.with_pos_embed(src, pos), reference_points, src,
                    spatial_shapes, level_start_index, padding_mask)
                src = src + self.dropout1(src2)
                src = self.norm1(src)

                # ffn
                src = self.forward_ffn(src)

                return srcTransformer Decoder with mask attention 通过 Object query 和 Pixel Decoder 中失去的 Multi-scale feature 去逐层去 refine 二值 mask 图,失去最终的后果。其中外围的 mask cross attention,会将前一层的预测的 mask 作为 MultiheadAttention 的 atten_mask 输出,以此来将注意力的计算限度在这个 query 关注的前景中。具体实现代码如下:class CrossAttentionLayer(nn.Module):

def __init__(self,
             d_model,
             nhead,
             dropout=0.0,
             activation='relu',
             normalize_before=False):
    super().__init__()
    self.multihead_attn = nn.MultiheadAttention(d_model, nhead, dropout=dropout)

    self.norm = nn.LayerNorm(d_model)
    self.dropout = nn.Dropout(dropout)

    self.activation = _get_activation_fn(activation)
    self.normalize_before = normalize_before

    self._reset_parameters()

def _reset_parameters(self):
    for p in self.parameters():
        if p.dim() > 1:
            nn.init.xavier_uniform_(p)

def with_pos_embed(self, tensor, pos: Optional[Tensor]):
    return tensor if pos is None else tensor + pos

def forward_post(self,
                 tgt,
                 memory,
                 memory_mask: Optional[Tensor] = None,
                 memory_key_padding_mask: Optional[Tensor] = None,
                 pos: Optional[Tensor] = None,
                 query_pos: Optional[Tensor] = None):
    tgt2 = self.multihead_attn(query=self.with_pos_embed(tgt, query_pos),
        key=self.with_pos_embed(memory, pos),
        value=memory,
        attn_mask=memory_mask,
        key_padding_mask=memory_key_padding_mask)[0]
    tgt = tgt + self.dropout(tgt2)
    tgt = self.norm(tgt)

    return tgt

def forward_pre(self,
                tgt,
                memory,
                memory_mask: Optional[Tensor] = None,
                memory_key_padding_mask: Optional[Tensor] = None,
                pos: Optional[Tensor] = None,
                query_pos: Optional[Tensor] = None):
    tgt2 = self.norm(tgt)
    tgt2 = self.multihead_attn(query=self.with_pos_embed(tgt2, query_pos),
        key=self.with_pos_embed(memory, pos),
        value=memory,
        attn_mask=memory_mask,
        key_padding_mask=memory_key_padding_mask)[0]
    tgt = tgt + self.dropout(tgt2)

    return tgt

def forward(self,
            tgt,
            memory,
            memory_mask: Optional[Tensor] = None,
            memory_key_padding_mask: Optional[Tensor] = None,
            pos: Optional[Tensor] = None,
            query_pos: Optional[Tensor] = None):
    if self.normalize_before:
        return self.forward_pre(tgt, memory, memory_mask,
                                memory_key_padding_mask, pos, query_pos)
    return self.forward_post(tgt, memory, memory_mask,
                             memory_key_padding_mask, pos, query_pos)Tricks1.efficient multi-scale strategy 在 pixel decoder 中会解码失去尺度为原图 1 /32、1/16、1/ 8 的特色金字塔顺次作为对应 transformer decoder block 的 K、V 的输出。参照 deformable detr 的做法,对每个输出都加上了 sinusoidal positional embedding 和 learnable scale-level embedding。按分辨率从低到高的循序顺次输出,并循环 L 次。2.PointRend 通过 PointRend 的形式来节俭训练过程中的内存耗费,次要体现在两个局部 a. 在应用匈牙利算法匹配预测 mask 和真值标签时,通过平均采样的 K 个点集代替残缺的 mask 图来计算 match cost b. 在计算损失时依照 importance sampling 策略采样的 K 个点集代替残缺的 mask 图来计算 loss(ps 试验证实基于 pointreind 形式来计算损失可能无效晋升模型精度)3.Optimization improvements 更换了 self-attention 和 cross-attention 的程序。self-attention->cross-attention 变成 cross-attention->self-attention。让 query 变成可学习的参数。让 query 进行监督学习能够起到相似 region proposal 的作用。通过试验能够证实可学习的 query 能够产生 mask proposal。去掉了 transformer deocder 中的 dropout 操作。通过试验发现这个操作会升高精度。复现精度实例宰割及全景宰割在 COCO 上的复现精度,试验在单机 8 卡 A100 环境下进行(ps : 对于实例宰割复现精度问题在官网 repo issue 46 中有提及)ModelPQBox mAPMask mAPmemorytrain_timemask2former_r50_instance_official  43.7  mask2former_r50_8xb2_epoch50_instance 46.0943.2613G3day2hmask2former_r50_panoptic_official51.9 41.7  mask2former_r50_8xb2_epoch50_panoptic51.6444.8141.8813G3day4h 语义宰割在 ADE20K 数据集上进行复现 ModelmIoUtrain memorytrain_timemask2former_r50_semantic_official47.2  mask2former_r50_8xb2_e127_samantic47.035.6G15h35m 应用 EasyCV 训练宰割模型对于特定场景的宰割,能够应用 EasyCV 框架和相应数据训练定制化的宰割模型。这里以实例宰割为例子,介绍训练流程。一、数据筹备目前 EasyCV 反对 COCO 模式的数据格式,咱们提供了示例 COCO 数据用于疾速走通流程。wget http://pai-vision-data-hz.oss-cn-zhangjiakou.aliyuncs.com/data/small_coco_demo/small_coco_demo.tar.gz && tar -zxf small_coco_demo.tar.gz

mkdir -p data/ && mv small_coco_demo data/coco 二、模型训练在 EasyCV 的 config 文件夹下,咱们提供了 mask2former 的数据处理和模型训练及验证的配置文件(configs/segmentation/mask2former/mask2former_r50_8xb2_e50_instance.py), 依据须要批改预测的类别、数据门路。执行训练命令,如下所示:# 单机八卡
python -m torch.distributed.launch –nproc_per_node=8 –master_port 11111 tools/train.py \

                                    configs/segmentation/mask2former/mask2former_r50_8xb2_e50_instance.py \
                                    --launcher pytorch \
                                    --work_dir experiments/mask2former_instance \
                                    --fp16 模型导出,将 config 文件保留到模型中,以便在 predictor 中失去模型和数据处理的配置,导出后的模型就可间接用于宰割图的预测。python tools/export.py configs/segmentation/mask2former/mask2former_r50_8xb2_e50_instance.py epoch_50.pth mask2former_instance_export.pthReference 实例宰割模型:http://pai-vision-data-hz.oss-cn-zhangjiakou.aliyuncs.com/EasyCV/modelzoo/segmentation/mask2former_r50_instance/mask2former_instance_export.pth 全景宰割模型:http://pai-vision-data-hz.oss-cn-zhangjiakou.aliyuncs.com/EasyCV/modelzoo/segmentation/mask2former_r50_panoptic/mask2former_pan_export.pth 语义宰割模型:http://pai-vision-data-hz.oss-cn-zhangjiakou.aliyuncs.com/EasyCV/modelzoo/segmentation/mask2former_r50_semantic/mask2former_semantic_export.pthEasyCV 往期分享 EasyCV 开源地址:https://github.com/alibaba/EasyCVEasyCV DataHub 提供多畛域视觉数据集下载,助力模型生产 https://zhuanlan.zhihu.com/p/572593950EasyCV 带你复现更好更快的自监督算法 -FastConvMAE https://zhuanlan.zhihu.com/p/566988235 基于 EasyCV 复现 DETR 和 DAB-DETR,Object Query 的正确打开方式 https://zhuanlan.zhihu.com/p/543129581 基于 EasyCV 复现 ViTDet:单层特色超过 FPN https://zhuanlan.zhihu.com/p/528733299MAE 自监督算法介绍和基于 EasyCV 的复现 https://zhuanlan.zhihu.com/p/515859470EasyCV 开源|开箱即用的视觉自监督 +Transformer 算法库 https://zhuanlan.zhihu.com/p/50521999ENDEasyCV 会继续进行 SOTA 论文复现进行系列的工作介绍,欢送大家关注和应用,欢送大家各种维度的反馈和改良倡议以及技术探讨,同时咱们非常欢送和期待对开源社区建设感兴趣的同行一起参加共建。原文链接:https://click.aliyun.com/m/1000364647/ 本文为阿里云原创内容,未经容许不得转载。
退出移动版