超快语义分割 | PP-LiteSeg集速度快、精度高、易部署等优点于一身,必会模型!!!(二)

简介: 超快语义分割 | PP-LiteSeg集速度快、精度高、易部署等优点于一身,必会模型!!!(二)

3本文方法


3.1 Flexible and Lightweight Decoder

一般来说,编码器利用一系列分成几个阶段的层来提取层次特征。对于从low-level到high-level的特征,通道的数量逐渐增加,特征的空间尺寸逐渐减小。该设计平衡了各阶段的计算成本,保证了编码器的效率。

解码器也有几个阶段,负责融合和上采样特征。虽然特征的空间大小从high-level增加到low-level,但最近的轻量级模型中的解码器在所有level上都保持相同特征通道。因此,low-level阶段的计算成本远远大于high-level的计算成本,这带来了low-level阶段的计算冗余。

图3

为了提高解码器的效率,本文提出了一种灵活的轻量级解码器(FLD)。如图3所示,FLD逐渐将特征的通道从high-level减少到low-level层次。FLD可以很容易地调整计算成本,以实现编码器和解码器之间更好的平衡。虽然FLD中的特征通道在减少,但实验表明,PP-LiteSeg与其他方法相比,依然具有竞争力的精度。

3.2 Unified Attention Fusion Module

如上所述,融合多层次特征是实现高分割精度的关键。除了element-wise summation和concatenation方法外,研究人员还提出了几种方法,如SFNet、FaPN和AttaNet。在这项工作中提出了一个统一的注意力融合模块(UAFM),它应用通道和空间注意力来丰富融合特征表示。

1、UAFM Framework

图4(a)

如图4(a)所示,UAFM利用一个注意力模块来产生权重,并通过Mul和Add操作将输入特性与相融合。

详细地说,输入特征被表示为和。是深层模块的输出,而是编码器的对应模块。请注意,它们有相同的通道数量。

UAFM首先利用双线性插值操作将上采样到相同大小,而上采样特征记为。然后,注意力模块以和作为输入,产生权重。

请注意,注意力模块可以是一个插件,如空间注意力模块、通道注意力模块等。

然后,获得注意力加权后,分别对和进行element-wise Mul

最后,UAFM对注意力加权后的特征进行element-wise Add,并输出融合特征。这里将把上述过程表述为公式1:

image.png

class UAFM(nn.Layer):
    """
    The base of Unified Attention Fusion Module.
    Args:
        x_ch (int): The channel of x tensor, which is the low level feature.
        y_ch (int): The channel of y tensor, which is the high level feature.
        out_ch (int): The channel of output tensor.
        ksize (int, optional): The kernel size of the conv for x tensor. Default: 3.
        resize_mode (str, optional): The resize model in unsampling y tensor. Default: bilinear.
    """
    def __init__(self, x_ch, y_ch, out_ch, ksize=3, resize_mode='bilinear'):
        super().__init__()
        self.conv_x = layers.ConvBNReLU(
            x_ch, y_ch, kernel_size=ksize, padding=ksize // 2, bias_attr=False)
        self.conv_out = layers.ConvBNReLU(
            y_ch, out_ch, kernel_size=3, padding=1, bias_attr=False)
        self.resize_mode = resize_mode
    def check(self, x, y):
        assert x.ndim == 4 and y.ndim == 4
        x_h, x_w = x.shape[2:]
        y_h, y_w = y.shape[2:]
        assert x_h >= y_h and x_w >= y_w
    def prepare(self, x, y):
        x = self.prepare_x(x, y)
        y = self.prepare_y(x, y)
        return x, y
    def prepare_x(self, x, y):
        x = self.conv_x(x)
        return x
    def prepare_y(self, x, y):
        y_up = F.interpolate(y, paddle.shape(x)[2:], mode=self.resize_mode)
        return y_up
    def fuse(self, x, y):
        out = x + y
        out = self.conv_out(out)
        return out
    def forward(self, x, y):
        """
        Args:
            x (Tensor): The low level feature.
            y (Tensor): The high level feature.
        """
        self.check(x, y)
        x, y = self.prepare(x, y)
        out = self.fuse(x, y)
        return out

2、Spatial Attention Module

image.png图4(b)

空间注意力模块的动机是利用空间间关系来产生一个权重,该权重表示输入特征中每个像素的重要性。如图4(b)所示,给定输入特征,即和,首先沿着通道轴进行平均和最大化操作生成4个特征,其中维度为。然后,将这4个特征concat到一个特征上。对于concat的特征,将卷积和sigmoid运算应用于输出。空间注意力模块的公式如式2所示:

image.png

此外,空间注意力模块还可以灵活地实现,例如去除最大池化操作以降低计算成本。

Paddle实现如下:

class UAFM_SpAtten(UAFM):
    """
    The UAFM with spatial attention, which uses mean and max values.
    Args:
        x_ch (int): The channel of x tensor, which is the low level feature.
        y_ch (int): The channel of y tensor, which is the high level feature.
        out_ch (int): The channel of output tensor.
        ksize (int, optional): The kernel size of the conv for x tensor. Default: 3.
        resize_mode (str, optional): The resize model in unsampling y tensor. Default: bilinear.
    """
    def __init__(self, x_ch, y_ch, out_ch, ksize=3, resize_mode='bilinear'):
        super().__init__(x_ch, y_ch, out_ch, ksize, resize_mode)
        self.conv_xy_atten = nn.Sequential(
            layers.ConvBNReLU(
                4, 2, kernel_size=3, padding=1, bias_attr=False),
            layers.ConvBN(
                2, 1, kernel_size=3, padding=1, bias_attr=False))
    def fuse(self, x, y):
        """
        Args:
            x (Tensor): The low level feature.
            y (Tensor): The high level feature.
        """
        atten = helper.avg_max_reduce_channel([x, y])
        atten = F.sigmoid(self.conv_xy_atten(atten))
        out = x * atten + y * (1 - atten)
        out = self.conv_out(out)
        return out

3、Channel Attention Module

image.png图4(c)

通道注意力模块的关键概念是利用通道间的关系来产生一个权重,这表明了每个通道在输入特征中的重要性。如图4(c)所示,所提出的通道注意力模块利用平均池化和最大池化操作来压缩输入特征的空间维数。

此过程使用维度生成4个特性。然后,它将这4个特征沿着通道轴连接起来,并执行卷积和sigmoid运算,以产生一个权重α。简而言之,通道注意力模块的过程可以表述为公式3:

image.png

Paddle实现如下:

class UAFM_ChAtten(UAFM):
    """
    The UAFM with channel attention, which uses mean and max values.
    Args:
        x_ch (int): The channel of x tensor, which is the low level feature.
        y_ch (int): The channel of y tensor, which is the high level feature.
        out_ch (int): The channel of output tensor.
        ksize (int, optional): The kernel size of the conv for x tensor. Default: 3.
        resize_mode (str, optional): The resize model in unsampling y tensor. Default: bilinear.
    """
    def __init__(self, x_ch, y_ch, out_ch, ksize=3, resize_mode='bilinear'):
        super().__init__(x_ch, y_ch, out_ch, ksize, resize_mode)
        self.conv_xy_atten = nn.Sequential(
            layers.ConvBNAct(
                4 * y_ch,
                y_ch // 2,
                kernel_size=1,
                bias_attr=False,
                act_type="leakyrelu"),
            layers.ConvBN(
                y_ch // 2, y_ch, kernel_size=1, bias_attr=False))
    def fuse(self, x, y):
        """
        Args:
            x (Tensor): The low level feature.
            y (Tensor): The high level feature.
        """
        atten = helper.avg_max_reduce_hw([x, y], self.training)
        atten = F.sigmoid(self.conv_xy_atten(atten))
        out = x * atten + y * (1 - atten)
        out = self.conv_out(out)
        return out

3.3 Simple Pyramid Pooling Module

图5

如图5所示,提出了一个简单的金字塔池化模块(SPPM)。

  • 首先利用金字塔池化模块来融合输入特征(金字塔池化模块有3个全局平均池化操作,bin大小分别为1×1、2×2和4×4)。
  • 然后,在输出特征之后,再进行卷积和上采样操作。对于卷积操作,kernel大小为1×1,输出通道小于输入通道。
  • 最后,上采样的特征,并应用卷积运算来产生细化的特征。

与原始的PPM相比,SPPM减少了中间通道和输出通道,删除了shortcut,并用add操作替换了cat操作。因此,SPPM更有效,也更适合用于实时模型。

Paddle实现如下:

class PPContextModule(nn.Layer):
    """
    Simple Context module.
    Args:
        in_channels (int): The number of input channels to pyramid pooling module.
        inter_channels (int): The number of inter channels to pyramid pooling module.
        out_channels (int): The number of output channels after pyramid pooling module.
        bin_sizes (tuple, optional): The out size of pooled feature maps. Default: (1, 3).
        align_corners (bool): An argument of F.interpolate. It should be set to False
            when the output size of feature is even, e.g. 1024x512, otherwise it is True, e.g. 769x769.
    """
    def __init__(self,
                 in_channels,
                 inter_channels,
                 out_channels,
                 bin_sizes,
                 align_corners=False):
        super().__init__()
        self.stages = nn.LayerList([
            self._make_stage(in_channels, inter_channels, size)
            for size in bin_sizes
        ])
        self.conv_out = layers.ConvBNReLU(
            in_channels=inter_channels,
            out_channels=out_channels,
            kernel_size=3,
            padding=1)
        self.align_corners = align_corners
    def _make_stage(self, in_channels, out_channels, size):
        prior = nn.AdaptiveAvgPool2D(output_size=size)
        conv = layers.ConvBNReLU(
            in_channels=in_channels, out_channels=out_channels, kernel_size=1)
        return nn.Sequential(prior, conv)
    def forward(self, input):
        out = None
        input_shape = paddle.shape(input)[2:]
        for stage in self.stages:
            x = stage(input)
            x = F.interpolate(
                x,
                input_shape,
                mode='bilinear',
                align_corners=self.align_corners)
            if out is None:
                out = x
            else:
                out += x
        out = self.conv_out(out)
        return out

3.4 模型架构

image.png

所提的PP-LiteSeg的体系结构如上图所示。

PP-LiteSeg主要由3个模块组成:encoder, aggregationdecoder

首先,给定一个输入图像,PP-Lite利用一个通用的轻量级网络作为编码器来提取层次特征。

image.png表1

选择STDCNet是因为其出色的性能。STDCNet有5个阶段,每个阶段的stride=2,所以最终的特征大小是输入图像的1/32。

如表1所示,提供了2个版本的PP-LiteSeg,即PP-LiteSeg-T和PP-LiteSeg-B,其中的编码器分别为STDC1和STDC2。PPLiteSeg-B具有较高的分割精度,而PP-LiteSeg-T的推理速度更快。值得注意的是,将SSLD方法应用于编码器的训练,得到了增强的预训练权重,有利于分割训练的收敛。

其次,PP-LiteSeg采用SPPM对随机依赖进行建模。SPPM以编码器的输出特征作为输入,生成一个包含全局上下文信息的特征。

最后,PP-LiteSeg利用提出的FLD逐步融合多层次特征并输出得到的图像。

FLD由2个UAFM和一个分割头组成。为了提高效率,在UAFM中采用了空间注意力模块。

每个UAFM以2个特征作为输入,即由编码器各阶段提取的low-level特征,由SPPM或更深的融合模块生成的high-level特征。后者的UAFM输出融合的特征,下采样比为1/8。

在分割head中执行Conv-BN-Relu操作,将1/8个下采样特征的通道减少到类的数量。采用上采样操作将特征大小扩展到输入图像大小,并采用argmax操作预测每个像素的标签。并采用Online Hard Example Mining交叉熵损失对模型进行了优化。

损失函数的Paddle实现如下:

import paddle
from paddle import nn
import paddle.nn.functional as F
from paddleseg.cvlibs import manager
@manager.LOSSES.add_component
class OhemCrossEntropyLoss(nn.Layer):
    """
    Implements the ohem cross entropy loss function.
    Args:
        thresh (float, optional): The threshold of ohem. Default: 0.7.
        min_kept (int, optional): The min number to keep in loss computation. Default: 10000.
        ignore_index (int64, optional): Specifies a target value that is ignored
            and does not contribute to the input gradient. Default ``255``.
    """
    def __init__(self, thresh=0.7, min_kept=10000, ignore_index=255):
        super(OhemCrossEntropyLoss, self).__init__()
        self.thresh = thresh
        self.min_kept = min_kept
        self.ignore_index = ignore_index
        self.EPS = 1e-5
    def forward(self, logit, label):
        """
        Forward computation.
        Args:
            logit (Tensor): Logit tensor, the data type is float32, float64. Shape is
                (N, C), where C is number of classes, and if shape is more than 2D, this
                is (N, C, D1, D2,..., Dk), k >= 1.
            label (Tensor): Label tensor, the data type is int64. Shape is (N), where each
                value is 0 <= label[i] <= C-1, and if shape is more than 2D, this is
                (N, D1, D2,..., Dk), k >= 1.
        """
        if len(label.shape) != len(logit.shape):
            label = paddle.unsqueeze(label, 1)
        # get the label after ohem
        n, c, h, w = logit.shape
        label = label.reshape((-1, ))
        valid_mask = (label != self.ignore_index).astype('int64')
        num_valid = valid_mask.sum()
        label = label * valid_mask
        prob = F.softmax(logit, axis=1)
        prob = prob.transpose((1, 0, 2, 3)).reshape((c, -1))
        if self.min_kept < num_valid and num_valid > 0:
            # let the value which ignored greater than 1
            prob = prob + (1 - valid_mask)
            # get the prob of relevant label
            label_onehot = F.one_hot(label, c)
            label_onehot = label_onehot.transpose((1, 0))
            prob = prob * label_onehot
            prob = paddle.sum(prob, axis=0)
            threshold = self.thresh
            if self.min_kept > 0:
                index = prob.argsort()
                threshold_index = index[min(len(index), self.min_kept) - 1]
                threshold_index = int(threshold_index.numpy()[0])
                if prob[threshold_index] > self.thresh:
                    threshold = prob[threshold_index]
                kept_mask = (prob < threshold).astype('int64')
                label = label * kept_mask
                valid_mask = valid_mask * kept_mask
        # make the invalid region as ignore
        label = label + (1 - valid_mask) * self.ignore_index
        label = label.reshape((n, 1, h, w))
        valid_mask = valid_mask.reshape((n, 1, h, w)).astype('float32')
        loss = F.softmax_with_cross_entropy(
            logit, label, ignore_index=self.ignore_index, axis=1)
        loss = loss * valid_mask
        avg_loss = paddle.mean(loss) / (paddle.mean(valid_mask) + self.EPS)
        label.stop_gradient = True
        valid_mask.stop_gradient = True
        return avg_loss


4实验


4.1 消融实验

通过消融实验,验证了所提模块的有效性。实验在比较中选择PP-LiteSeg-B2,并使用相同的训练和推理配置。Baseline模型为无该模块的PP-LiteSeg-B2,而解码器中的特征通道数为96个,融合方法为 element-wise summation

image.png

表3

通过表3可以发现,PP-LiteSeg-B2中的FLD使mIoU提高了0.17%。添加SPPM和UAFM也提高了分割精度,而推理速度略有降低。基于提出的3个模块,PP-LiteSeg-B2以102.6FPS速度达到78.21mIoU。mIoU与Baseline模型相比提高了0.71%。

图6

图6提供了定性的比较。可以观察到,当逐个添加FLD、SPPM和UAFM时,预测的图像更符合GT。总之,本文提出的模块对于语义分割是有效的。

4.2 Cityscapes

表2

表2给出了各种方法的模型信息、输入分辨率、mIoU和FPS。图1提供了分割精度和推理速度的直观比较。

实验结果表明,所提出的PP-LiteSeg方法在精度和速度之间实现了最先进的权衡。

具体来说,PP-LiteSeg-T1以273.6FPS速度达到了72.0%的mIoU,这意味着最快的推理速度和竞争精度。

PPLiteSeg-B2的分辨率为768×1536,达到了最好的精度,即验证集的78.2%mIoU,测试集的77.5%mIoU。此外,使用与STDC-Seg相同的编码器和输入分辨率,PPLiteSeg显示出更好的性能。

4.3 CamVid

为了进一步证明PP-LiteSeg的能力,作者还在CamVid数据集上进行了实验。与其他工作类似,训练和推理的输入分辨率是960×720。

表4

如表4所示,PP-LiteSeg-T达到222.3FPS,比其他方法快12.5%以上。PP-LiteSeg-B的精度最好(75.0%mIoU/154.8FPS)。

总的来说,比较显示PP-LiteSeg在Camvid上实现了精度和速度之间的最先进的权衡。


5参考


[1].PP-LiteSeg: A Superior Real-Time Semantic Segmentation Model


6推荐阅读


CVPR2022 oral | MetaFormer才是探索Transformer的源泉,衍生PoolFormer速度喜人

CVPR2022 | 在线Re-Param | OREPA让AI训练速度进一步加快,精度略胜RepVGG!

深度可分离ViT | SepViT | 深度可分离卷积造就深度可分离Transformer

相关文章
|
自然语言处理 算法 数据挖掘
自蒸馏:一种简单高效的优化方式
背景知识蒸馏(knowledge distillation)指的是将预训练好的教师模型的知识通过蒸馏的方式迁移至学生模型,一般来说,教师模型会比学生模型网络容量更大,模型结构更复杂。对于学生而言,主要增益信息来自于更强的模型产出的带有更多可信信息的soft_label。例如下右图中,两个“2”对应的hard_label都是一样的,即0-9分类中,仅“2”类别对应概率为1.0,而soft_label
自蒸馏:一种简单高效的优化方式
|
1月前
|
机器学习/深度学习 人工智能 算法
RLCM:康奈尔大学推出文本到图像一致性模型优化框架,支持快速生成与任务特定奖励优化
RLCM 是康奈尔大学推出的基于强化学习的文本到图像生成模型优化框架,支持快速训练与推理,能够根据任务特定奖励函数生成高质量图像。
52 12
RLCM:康奈尔大学推出文本到图像一致性模型优化框架,支持快速生成与任务特定奖励优化
|
1月前
|
人工智能 物联网 Python
VMix:即插即用!字节联合中科大推出增强模型生成美学质量的开源适配器,支持多源输入、高质量视频处理
VMix 是一款创新的即插即用美学适配器,通过解耦文本提示和交叉注意力混合控制,显著提升图像生成的美学质量,支持多源输入和高质量视频处理。
77 11
VMix:即插即用!字节联合中科大推出增强模型生成美学质量的开源适配器,支持多源输入、高质量视频处理
|
4月前
|
机器学习/深度学习 弹性计算 自然语言处理
前端大模型应用笔记(二):最新llama3.2小参数版本1B的古董机测试 - 支持128K上下文,表现优异,和移动端更配
llama3.1支持128K上下文,6万字+输入,适用于多种场景。模型能力超出预期,但处理中文时需加中英翻译。测试显示,其英文支持较好,中文则需改进。llama3.2 1B参数量小,适合移动端和资源受限环境,可在阿里云2vCPU和4G ECS上运行。
219 1
|
5月前
|
UED
代码分割的优势和劣势分别是什么?
代码分割的优势和劣势分别是什么?
|
9月前
|
算法
【免费】面向多微网网络结构设计的大规模二进制矩阵优化算法
【免费】面向多微网网络结构设计的大规模二进制矩阵优化算法
|
9月前
|
人工智能 自然语言处理 测试技术
论文介绍:LLMLingua-2——面向高效忠实任务无关性提示压缩的数据蒸馏方法
【5月更文挑战第2天】LLMLingua-2是一种针对大型语言模型(LLMs)的数据蒸馏方法,旨在实现高效且忠实的提示压缩。通过从LLMs中提取知识,该方法在压缩提示的同时保持关键信息,提高模型泛化能力和效率。采用Transformer编码器,LLMLingua-2将提示压缩转化为标记分类问题,确保压缩后的提示忠实度并减少延迟。实验表明,该方法在多个数据集上优于基线,并在压缩延迟上取得显著改进,但也存在泛化能力和扩展性限制。论文链接:https://arxiv.org/abs/2403.12968
177 5
|
9月前
|
机器学习/深度学习 人工智能
论文介绍:PreFLMR——扩展细粒度晚期交互多模态检索器以提升知识视觉问答性能
【5月更文挑战第3天】PreFLMR是扩展的细粒度晚期交互多模态检索器,用于提升知识视觉问答(KB-VQA)性能。基于FLMR,PreFLMR结合大型语言模型和检索增强生成,增强准确性与效率。通过M2KR框架全面评估,PreFLMR展示出色性能,尤其在E-VQA和Infoseek等任务。然而,其在预训练阶段未充分训练知识密集型任务,且仍有优化训练方法和数据集混合比例的空间。[论文链接](https://arxiv.org/abs/2402.08327)
235 1
|
机器学习/深度学习
结合亲和力提高了 28.7 倍,基于端到端贝叶斯语言模型的方法设计大型、多样化的高亲和力抗体库
结合亲和力提高了 28.7 倍,基于端到端贝叶斯语言模型的方法设计大型、多样化的高亲和力抗体库
149 0
|
机器学习/深度学习 编解码 自动驾驶
超快语义分割 | PP-LiteSeg集速度快、精度高、易部署等优点于一身,必会模型!!!(一)
超快语义分割 | PP-LiteSeg集速度快、精度高、易部署等优点于一身,必会模型!!!(一)
240 0