语义分割(Semantic Segmentation)是计算机视觉中的一种图像理解任务:将图像中的每一个像素分配到一个预定义的类别标签,从而实现对图像按语义区域进行像素级划分。其中有一些较强可尝试的模型和方案,可以在对应场景需要时尝试。

SegFormer

SegFormer是一种较为轻量的语义分割模型,他的思路是将传统的CNN分割网络的倒金字塔结构保留,然后引入注意力,这主要是靠MiT实现的。MiT靠Overlap Patch Embedding实现倒金字塔的降分辨率操作,然后使用MiT Transformer Layer进行注意力和FFN,他对注意力和FFN进行了修改,使用Efficient Self-Attention和Mix-FFN。其中Efficient Self-Attention就是将KV进行了降采样,使用带步长的卷积核堆叠,将KV的Token数下降到较低水平,来降低注意力开销。然后是Mix-FFN,他在第一个Linear后加了3x3 Depthwise Convolution来进行局部空间信息交互。一方面这个DWConv在这里提供了局部空间信息交互,另一方面他还提供了一定的Patch空间信息。在SegFormer里面,他还去掉了Attention的位置编码,因为ViT中一般使用的位置编码是绝对位置编码,他不利于扩展输入图片大小,所以他去掉了,而这里的DWConv就补了一定空间信息。

SegFormer的Encoder一般是有四层Layer,分别下采样到1/4、1/8、1/16、1/32。而且其中为了降低注意力的开销的步长卷积堆叠数也会依次降低,因为在Layer中已经进行了下采样,具体为8、4、2、1个Conv。SegFormer的Decoder十分简单,因为Encoder的各个Layer输出会导致特征的channel数不断增大,他的Decoder第一步就是统一各个Layer输出的channel,然后他再统一将各个Layer输出的尺寸upsample到1/4,然后concat之后完全展平,最后直接一个Linear映射到class维进行分类。他的特点就是轻量,因此在Benchmark上分数并不是很高,适合做快速实验以及做Baseline。

graph TD
    Image[Input Image] --> MiT
    subgraph MiT Encoder
        MiT --> L1[Stage 1: 1/4]
        L1 --> L2[Stage 2: 1/8]
        L2 --> L3[Stage 3: 1/16]
        L3 --> L4[Stage 4: 1/32]
    end
    L1 --> MLP1[MLP]
    L2 --> MLP2[MLP]
    L3 --> MLP3[MLP]
    L4 --> MLP4[MLP]
    MLP1 --> Concat[Concat]
    MLP2 --> Concat
    MLP3 --> Concat
    MLP4 --> Concat
    Concat --> Linear[Linear Classification]
    Linear --> SegMap[Segmentation Map]

UPerNet

UPerNet是一种多尺度语义分割Decoder/Head。因此他不是一种具体模型,但是他可以用来作为进阶Decoder使用,接在各种Backbone后。

UPerNet接受像SegFormer那样的分层特征。在最高层特征上,他会进行PPM(Pyramid Pooling Module),使用不同核大小的Mean Pool,例如:

  • 1x1
  • 2x2
  • 3x3
  • 6x6

然后获取对应Pool结果之后再upsample回高层特征的size,然后直接将这些与原始的最高层特征concat,然后用卷积融合进去或者一个与初始的最高层特征的shape相同的特征。PPM能给最高级语义特征增加不同尺度的全局Context。

然后就是FPN。对于上面的最高层语义特征进行PPM获得的产物和其他层的特征,我们对他们分别进行一次channel统一,然后依次将最高层特征与更低一层的特征upsample的结果进行相加,然后用3x3 Conv融合获得新的融合特征,然后让这个新的融合特征与下一层特征相加然后融合,获得各层的融合特征,最后将它们相连之后再进行一次卷积融合,然后用一个Linear层将最后一维映射到class维上。

相比于SegFormer的这种简单的Decoder,UPerNet很适合用来作为下一步,测试Decoder是否是瓶颈项来提升分数。

graph TD
    subgraph Backbone
        C1[C1: 1/4]
        C2[C2: 1/8]
        C3[C3: 1/16]
        C4[C4: 1/32]
    end

    C4 --> PPM[PPM]
    PPM --> FPN_C4

    C3 --> Conv1x1_3[1x1 Conv]
    Conv1x1_3 --> FPN_C3

    C2 --> Conv1x1_2[1x1 Conv]
    Conv1x1_2 --> FPN_C2

    C1 --> Conv1x1_1[1x1 Conv]
    Conv1x1_1 --> FPN_C1

    FPN_C4 --> Up1[Upsample]
    Up1 --> Add1((+))
    FPN_C3 --> Add1
    Add1 --> Conv3x3_3[3x3 Conv]
    Conv3x3_3 --> FPN_Out3

    FPN_Out3 --> Up2[Upsample]
    Up2 --> Add2((+))
    FPN_C2 --> Add2
    Add2 --> Conv3x3_2[3x3 Conv]
    Conv3x3_2 --> FPN_Out2

    FPN_Out2 --> Up3[Upsample]
    Up3 --> Add3((+))
    FPN_C1 --> Add3
    Add3 --> Conv3x3_1[3x3 Conv]
    Conv3x3_1 --> FPN_Out1

    FPN_Out1 --> Up4[Upsample to 1/4]
    FPN_Out2 --> Up5[Upsample to 1/4]
    FPN_Out3 --> Up6[Upsample to 1/4]
    FPN_C4 --> Up7[Upsample to 1/4]

    Up4 --> Concat[Concat]
    Up5 --> Concat
    Up6 --> Concat
    Up7 --> Concat

    Concat --> FinalConv[Conv + Linear]
    FinalConv --> Pred[Prediction]

Mask2Former

Mask2Former也是一种分割Decoder,他统一了语义分割、实例分割、全景分割。它由Backbone Encoder,Pixel Decoder还有Transformer Decoder。他对Encoder的要求与上面的其他的分割头一样,要求输出多层特征,典型层次还是1/4、1/8、1/16、1/32,然后这些分层特征会先经过Pixel Decoder。

其中1/8、1/16、1/32会进入到一个分支,1/4进入另一个分支。对于前三个,他们进行1x1 Conv将channel统一到256之后加入2D Position Embedding和Learnable Level Embedding然后将他们展平都作为Token,然后进入6层MSDeformAttn(Multi-Scale Deformable Attention)。这里并非Transformer式的Attn,而是一种独特的方式来降低消耗。对于每个Query Token,他对每个注意力Head,每个Level,采样4个Token进行注意力计算,因此需要 Head×Level×4×2\mathrm{Head} \times \mathrm{Level} \times 4 \times 2 个位置信息,他通过一个Linear,将每个Token的256映射出对应需要的维度,这里的2指的是他的2D位置信息。当位置信息非标准Token位置的时候,他并非舍入,而是用附近的Token双线性插值来解决,同时在这套操作中他给每个Token的2D位置都加了0.5,来表示每个Patch的中心位置。获取了这些Sample Offsets之后,他还要获取对于每个Token的Attention Weights,同样通过Linear映射出来。然后进行注意力计算。

zqm=∑l=1L∑k=1KAmlqkFl(pq+Δpmlqk) z_q^m = \sum_{l=1}^{L} \sum_{k=1}^{K} A_{mlqk} F_l (p_q + \Delta p_{mlqk})

其中 Δpmlqk\Delta p_{mlqk} 正是Sample Offsets,而 AmlqkA_{mlqk} 就是进行了Softmax保证权重总和为1,这里的 FlF_l 正是双线性插值。他的最后输出就是通过Split将Level和Size维度恢复回来的特征,这些Level和Size信息在他一开始Flatten之前就存储了。

然后其中1/4的分支,也先用1x1 Conv,让他的channel变成256,然后将上面的这里的MSDeformAttn输出的1/8特征上采样到1/4,然后与上层特征相加,然后用3x3 Conv结合,然后再经过一个1x1 Conv保证输出的channel为256,最后就获得了Mask Feature。

然后是Transformer Decoder,他有100个可学习的Query Feature和100个可学习的Query Embedding,第一层对Query Feature进行LayerNorm之后通过一个三层MLP得到每个Query的256维嵌入,然后与Pixel Decoder的Mask Feature进行内积获得100个Query各自的Mask,然后按照这一层要Query的层次特征进行Mask Bilinear Interpolation Resize到对应Size,然后以0.5为阈值进行Mask构建。然后他就开始计算Mask Attention,原本说的Query Embedding就会加在Q上,K就是层次特征加上位置信息,V就是层次特征,并且加上上面的Mask,然后再接上标准Attention和FFN,然后就到了下一层。经过上一层信息交互的Query Feature再次构建Mask,只不过这次的要Query的层次特征变成了更底层的那一个,即1/32、1/16、1/8这样每层被Query。然后他的Class Head就是取每层后的Query Feature进行预测,对每个Query预测一个Class,并用3层MLP预测对应的Mask。再加上一般他会让第一层之前还没做交互的Query Feature进行一次预测,也就是 Layer+1 次预测,一般是10次,也就是9层,意味着这些层次特征一般会被Query 3次。最后取真的预测Mask的时候,他只用最后一层的预测。在推理阶段,对于每个像素,将每个Query预测的类别概率与其对应的Mask概率相乘,得到每个类别在该像素上的得分,然后将所有Query对同一类别的贡献求和,最后取得分最大的类别作为该像素的最终预测。

Mask2Former的分割效果一般强于UPerNet,通过和较强的Backbone组合,他能达到分割的SOTA水平,例如与DINOv2和他的Adapter结合,即使冻结DINO,也能达到SOTA,或者与Swin Transformer等等结合等,也能获得很好的效果。

graph TD
    subgraph Backbone
        C1[1/4]
        C2[1/8]
        C3[1/16]
        C4[1/32]
    end

    subgraph Pixel Decoder
        C2 --> Enc[MSDeformAttn x6]
        C3 --> Enc
        C4 --> Enc
        Enc -->|仅 1/8 层| Up1[Upsample to 1/4]
        C1 --> Lat[1x1 Conv]
        Lat --> Add((+))
        Up1 --> Add
        Add --> Fuse[3x3 Conv + 1x1 Conv]
        Fuse --> MaskFeat[Mask Features]
    end

    subgraph Transformer Decoder
        Q[100 Learnable Queries] --> MLP[3层 MLP]
        MLP --> Dot((与 Mask Features 内积))
        MaskFeat --> Dot
        Dot --> Mask[Mask, 0.5 二值化]
        Mask -->|作为 attention mask| MCA[Masked Cross-Attention]
        Enc -->|K/V, 轮流 query 1/32, 1/16, 1/8| MCA
        MCA --> FFN[Self-Attention + FFN]
        FFN --> Q
    end

    Q --> ClassHead[Class Head]
    Q --> MaskHead[Mask Head]
    MaskFeat --> MaskHead
    MaskHead --> Pred[最终 Mask 预测]