通过Center-Loss优化细粒度分类问题

举报
solin2020 发表于 2022/03/31 16:08:47 2022/03/31
【摘要】 细粒度分类问题细粒度分类是指对相似的类别进行分类,比如鸟的种类、车的款式等,在这些图像中,每种类别只有细微差异。如下图是21种麻雀的数据,每一列代表一个种类,每类展示了10张,我们可以发现这些麻雀的相似度非常高。在使用常规CNN网络进行特征提取后,从这些相似图像生成的特征通常也十分相似,这时如果只是简单的使用softmax交叉熵损失函数,很难将这些相似的特征区分开。Centor-Loss为了...

细粒度分类问题

细粒度分类是指对相似的类别进行分类,比如鸟的种类、车的款式等,在这些图像中,每种类别只有细微差异。如下图是21种麻雀的数据,每一列代表一个种类,每类展示了10张,我们可以发现这些麻雀的相似度非常高。在使用常规CNN网络进行特征提取后,从这些相似图像生成的特征通常也十分相似,这时如果只是简单的使用softmax交叉熵损失函数,很难将这些相似的特征区分开。

Centor-Loss

为了增大这些特征间的区分度,https://kpzhang93.github.io/papers/eccv2016.pdf 中提出了Center-Loss。这个损失函数的原理就是设置分类数个中心点,让不同类别的特征尽可能靠近各自的中心点,即希望类内距离变小、类间距离变大。公式如下,其中x指的是特征,c指的是中心,c会随着模型训练更新。

Centor-Loss的实现方式多种多样,Pytorch的一种实现方式如下:https://github.com/KaiyangZhou/pytorch-center-loss

class CenterLoss(nn.Module):
    """Center loss.

    Reference:
    Wen et al. A Discriminative Feature Learning Approach for Deep Face Recognition. ECCV 2016.

    Args:
        num_classes (int): number of classes.
        feat_dim (int): feature dimension.
    """
    def __init__(self, num_classes=10, feat_dim=2, use_gpu=True):
        super(CenterLoss, self).__init__()
        self.num_classes = num_classes
        self.feat_dim = feat_dim
        self.use_gpu = use_gpu

        if self.use_gpu:
            self.centers = nn.Parameter(torch.randn(self.num_classes, self.feat_dim).cuda())
        else:
            self.centers = nn.Parameter(torch.randn(self.num_classes, self.feat_dim))

    def forward(self, x, labels):
        """
        Args:
            x: feature matrix with shape (batch_size, feat_dim).
            labels: ground truth labels with shape (batch_size).
        """
        batch_size = x.size(0)
        distmat = torch.pow(x, 2).sum(dim=1, keepdim=True).expand(batch_size, self.num_classes) + \
                  torch.pow(self.centers, 2).sum(dim=1, keepdim=True).expand(self.num_classes, batch_size).t()
        distmat.addmm_(1, -2, x, self.centers.t())

        classes = torch.arange(self.num_classes).long()
        if self.use_gpu:
            classes = classes.cuda()
        labels = labels.unsqueeze(1).expand(batch_size, self.num_classes)
        mask = labels.eq(classes.expand(batch_size, self.num_classes))

        dist = distmat * mask.float()
        loss = dist.clamp(min=1e-12, max=1e+12).sum() / batch_size

        return loss

上述工程中使用mnist数据集做测试,特征降维展示如下图,上图是普通的softmax,下图是softmax+center-loss,可以明显观测到特征被区分的更明显了。

实验效果

Center-Loss最初是用在人脸分类任务中,开源项目大部分是在mnist数据集上的复现。那么Center-Loss在自然场景下的效果如何呢,下面进行了一个实验。

实验的数据来自CUB-200 数据集,选取了其中21种麻雀数据进行实验,其中训练集629张,测试集615张。

测试算法来自Pytorch官方提供的分类网络样例resnet50,https://github.com/pytorch/examples/blob/master/imagenet/main.py ,加载imagenet预训练的模型,学习率设为0.001,batch-size设为32,训练30个epoch。

在只使用常规损失函数的情况下,获得了73.6%的分类精度,最后一个卷积层特征的降维可视化如下。

将最后一个卷积层的特征与标签同时输入Center-Loss,计算损失值,按0.001的权重与正常的Softmax损失函数加权,然后再进行反向计算。

loss = softmax_loss(pred_output, target_label) + 0.001 * center_loss(feature, target_label)

此时,获得了75.7%的分类精度,最后一层特征的降维可视化如下。从图中圈出的类别来看,类内的距离确实被缩小了,某些类间的距离也确实被放大了,但是相比于mnist数据集的测试,效果不是那么明显,这是由于背景过于复杂造成的。

总结

使用Center-Loss,确实可以优化自然场景下的细粒度分类问题,但是随着背景复杂度的增加,优化效果会被削弱。

卷积特征可视化可以有效分析模型的性能,此功能即将上线ModelArts的模型评估模块,敬请期待。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。