Bag of Tricks and A Strong Baseline for Deep Person Re-identification(论文阅读笔记)(2019CVPR)

一.论文介绍

        本文是CVPR2019报告的文章,主要是将对reid有效的方法和技巧进行收集和评价。该模型仅使用了全局特征(global feature)。

二.论文的目的与贡献

(一)目的

        本文目的为reid提供baseline,使其他研究人员了解reid,例如:如何评判,有什么技巧等。为reid提供了一个标准,使得后续的发展更加规范。

(二)贡献

         1) 我们为ReID收集了一些有效的训练技巧。其中,我们设计了一种新的neck结构,称为BNNeck。此外,我们还对两个广泛使用的数据集评估了每个技巧的改进。
         2)  我们提供了一个强大的ReID baseline,在Market1501上实现了94.5%和85.9%的mAP。值得注意的是,这些结果是用ResNet50 backbone提供的全局特性得到的。据我们所知,这是全局特征亲自获得的最佳性能。
         3)作为补充,我们评估了图像size和batch size(批量)数量对ReID模型性能的影响。

三.标准baseline

        我们遵循广泛使用的开放源码作为我们的标准baseline。标准baseline的backbone(基础网络)为ResNet50[5]。在训练阶段,pipeline(步骤集合)包括以下步骤:

1,我们在ImageNet上初始化带有预训练参数的ResNet50,并将全连接层的维度更改为N, N表示训练数据集中的行人身份数。


2,我们随机抽取每个人的P个身份和K个图像作为训练样本。最后batch-size B = P*K。本文设P = 16, K = 4。注:P个ID,每个ID四张图片


3,我们将每个图像的大小调整为256 *128像素,并将调整后的图像填充10个像素,填充值为0。然后随机裁剪成256 *128的矩形图像。

4,每幅图像水平翻转的概率为0.5。


5,每个图像被解码成32位浮点原始像素值在[0,1]。然后分别减去0.485、0.456、0.406,再除以0.229、0.224、0.225,对RGB通道进行归一化。注:这里的解码成32位浮点在[0,1]的意思是除以255,进行一个压缩而不是概率论中的标准化。而后面的RGB通道进行归一化才是进行理解中的正态分布标准化。


6,该模型输出ReID特征为 f 和 ID 预测 logits p。

注:这句话的意思是,模型的输出包含两部分:ReID特征(记作f)和ID预测的logits(记作p)。

ReID特征(Re-Identification features)是模型从输入图像中提取的特征,这些特征被用来区分不同的个体。在人脸识别或者行人重识别等任务中,ReID特征通常会被用来计算两个图像之间的相似度,以判断它们是否属于同一个个体。

ID预测的logits是模型对每个可能的身份的预测得分。在分类任务中,这些得分通常会被送入一个softmax函数,得到每个身份的预测概率。在训练阶段,这些预测概率会被用来计算损失函数,以指导模型的优化。

所以,这句话的意思是,模型的输出既包含了用于区分个体的ReID特征,也包含了用于预测身份的logits。

举个例子:

假设我们的数据集中有1000个不同的人,那么ID预测的logits就会是一个长度为1000的向量。每个元素代表模型预测图像属于对应身份的得分。例如,如果logits是[0.1, -0.2, 0.3, ..., 0.2],那么模型预测图像属于第一个身份的得分是0.1,属于第二个身份的得分是-0.2,以此类推。

ReID特征则是一个更高维度的向量,它包含了模型从图像中提取出的特征。这些特征被用来区分不同的个体。例如,ReID特征可能包含了人脸的形状、眼睛的颜色等信息。具体的维度和内容取决于模型的设计。就是网络出来还没进入全连接层的那个输出。在论文的代码中为global_feat。

所以,如果我们将一张人的图像输入到模型中,模型可能会输出类似下面的结果:

{
    "reid_features": [0.1, 0.2, 0.3, ..., 0.1],  # ReID特征
    "id_logits": [0.1, -0.2, 0.3, ..., 0.2]  # ID预测的logits
}

7,ReID特征 f 用于计算triplet loss[6]。采用ID预测logits p计算交叉熵损失。triplet loss的margin设为0.3。

本论文中的triplet loss

class TripletLoss(object):
    """Modified from Tong Xiao's open-reid (https://github.com/Cysu/open-reid).
    Related Triplet Loss theory can be found in paper 'In Defense of the Triplet
    Loss for Person Re-Identification'."""

    def __init__(self, margin=None):
        self.margin = margin
        if margin is not None:
            self.ranking_loss = nn.MarginRankingLoss(margin=margin)
        else:
            self.ranking_loss = nn.SoftMarginLoss()

    def __call__(self, global_feat, labels, normalize_feature=False):
        if normalize_feature:
            global_feat = normalize(global_feat, axis=-1)
        dist_mat = euclidean_dist(global_feat, global_feat)
        dist_ap, dist_an = hard_example_mining(
            dist_mat, labels)
        y = dist_an.new().resize_as_(dist_an).fill_(1)
        if self.margin is not None:
            loss = self.ranking_loss(dist_an, dist_ap, y)
        else:
            loss = self.ranking_loss(dist_an - dist_ap, y)
        return loss, dist_ap, dist_an

==================6.7 还未写完
8,采用Adam方法对模型进行优化。初始学习率设置为0.00035,在第40个epoch和第70个epoch分别降低0.1。总共有120个训练epoches。

四.warmup 学习率

在深度学习中,学习率预热(Learning Rate Warmup)是一种常见的训练策略。在训练开始的几个epoch中,学习率从一个较小的值逐渐增加到预设的初始学习率。这种策略可以帮助模型在训练初期更稳定地学习,避免梯度爆炸或消失。

class WarmupLR(torch.optim.lr_scheduler._LRScheduler):
    def __init__(self, optimizer, warmup_epochs, total_epochs, last_epoch=-1):
        self.warmup_epochs = warmup_epochs
        self.total_epochs = total_epochs
        super(WarmupLR, self).__init__(optimizer, last_epoch)

    def get_lr(self):
        if self.last_epoch < self.warmup_epochs:
            return [base_lr * (self.last_epoch / self.warmup_epochs) for base_lr in self.base_lrs]
        else:
            return [base_lr * (1.0 - (self.last_epoch - self.warmup_epochs) / (self.total_epochs - self.warmup_epochs)) for base_lr in self.base_lrs]

以上为简化的伪代码,仅供学习使用。

在这个例子中,WarmupLR 是一个学习率调度器,它在前 warmup_epochs 个epoch中线性地增加学习率,然后在剩余的epoch中线性地降低学习率。

学习进度的比较。使用warmup学习策略,学习率在前10个epoch线性增长。

五.随机擦除增强

随机擦除(Random Erasing)是一种数据增强技术,主要用于计算机视觉任务中。这种方法的主要思想是在图像中随机选择一个矩形区域并将其像素值设置为随机值,以此来增加模型的鲁棒性。

以下是一个使用PyTorch实现的随机擦除的例子

``python
class RandomErasing(object):
    def __init__(self, probability = 0.5, sl = 0.02, sh = 0.4, r1 = 0.3, r2 = 1/0.3, mean=[0.4914, 0.4822, 0.4465]):
        self.probability = probability
        self.mean = mean
        self.sl = sl
        self.sh = sh
        self.r1 = r1
        self.r2 = r2

    def __call__(self, img):
        if random.uniform(0, 1) > self.probability:
            return img

        for attempt in range(100):
            area = img.size()[1] * img.size()[2]
            target_area = random.uniform(self.sl, self.sh) * area
            aspect_ratio = random.uniform(self.r1, self.r2)

            h = int(round(math.sqrt(target_area * aspect_ratio)))
            w = int(round(math.sqrt(target_area / aspect_ratio)))

            if w < img.size()[2] and h < img.size()[1]:
                x1 = random.randint(0, img.size()[1] - h)
                y1 = random.randint(0, img.size()[2] - w)
                if img.size()[0] == 3:
                    img[0, x1:x1+h, y1:y1+w] = self.mean[0]
                    img[1, x1:x1+h, y1:y1+w] = self.mean[1]
                    img[2, x1:x1+h, y1:y1+w] = self.mean[2]
                else:
                    img[0, x1:x1+h, y1:y1+w] = self.mean[0]
                return img

        return img

在这个例子中,`RandomErasing` 类定义了一个可以对图像进行随机擦除的操作。在 `__call__` 方法中,首先根据预设的概率决定是否对图像进行擦除。如果决定进行擦除,那么就随机选择一个矩形区域,并将该区域的像素值设置为预设的均值。

六.标签平滑

标签平滑(Label Smoothing)是一种在训练深度学习模型时常用的技巧,主要用于防止模型过拟合和提高模型的泛化能力。

在没有使用标签平滑的情况下,我们通常会将目标标签设为"硬"标签,即对于每个样本,其真实类别的标签为1,其他类别的标签为0。但这种方式可能会导致模型对训练数据过拟合,因为模型会尽可能地将每个样本的预测值靠近其真实标签。

标签平滑的思想是将"硬"标签替换为"软"标签,即对于每个样本,其真实类别的标签仍为1,但其他类别的标签不再是0,而是一个较小的正数。这样可以防止模型过于自信,因为即使模型将某个样本错误地分类为其他类别,其损失也不会太大。

以下是一个使用PyTorch实现的标签平滑的例子:

```python
class LabelSmoothingLoss(nn.Module):
    def __init__(self, classes, smoothing=0.1, dim=-1):
        super(LabelSmoothingLoss, self).__init__()
        self.confidence = 1.0 - smoothing
        self.smoothing = smoothing
        self.cls = classes
        self.dim = dim

    def forward(self, pred, target):
        pred = pred.log_softmax(dim=self.dim)
        with torch.no_grad():
            true_dist = torch.zeros_like(pred)
            true_dist.fill_(self.smoothing / (self.cls - 1))
            true_dist.scatter_(1, target.data.unsqueeze(1), self.confidence)
        return torch.mean(torch.sum(-true_dist * pred, dim=self.dim))
```

在这个例子中,`LabelSmoothingLoss` 类定义了一个可以进行标签平滑的损失函数。在 `forward` 方法中,首先对预测值进行log softmax操作,然后创建一个与预测值形状相同的张量,并将其所有元素设置为 `smoothing / (classes - 1)`,然后将真实标签对应的位置的值设置为 `confidence`,最后计算并返回损失值。

ID embedding (IDE)[25]网络是person ReID的基本baseline。IDE的最后一层是一个全连接层,输出图像的 ID 预测logits。隐藏神经元大小等于行人数N 。给定一个图像,我们定义 y 为ground-truth ID标签, 为类别 i 的ID 行人logits。交叉熵损失计算为:

    由于分类的类别是由人的ID决定的,本文将这种损失函数称为ID loss。

    然而,由于测试集的人id没有出现在训练集中,所以可以将ReID看作是一次性的学习任务,因此防止ReID模型对训练 id 进行过拟合非常重要。在[17]中提出的标签平滑(LS)是一种广泛用于防止分类任务过拟合的方法。它将结构改为:

(作者举了个例子,加入原始的label是[0,0,1,0,0,0],平滑参数设置为0.1,则平滑之后的label就会变成[0.02,0.02,0.9,0.02,0.02,0.02],计算损失时由交叉熵换回原始的相对熵。经过标签平滑之后,网络的过拟合程度也会被抑制一点。)

 (笔者注:但在其他博客中,标签平滑不是这样定义的:y' = (1 - epsilon)*y + epsilon/N。(即,假设N= 5为五分类,样本真实标签为 y = [0,0,1,0,0],epsilon = 0.1(平滑参数)。 y' 即作者论文中的 qi,为 :y' = (1-0.1)*[0,0,1,0,0] + 0.1/5  = 0.9 * [0,0,1,0,0] + 0.02 = [0,0,0.9,0,0] + 0.02 = [0.02,0.02,0.92,0.02,0.02])。

    其中为一个小常数,鼓励模型不要太相信训练集。在本研究中,设为0.1。当训练集不是很大时,LS可以显著提高模型的性能。

七.损失函数

结合了多个损失函数。具体来说,它包括了交叉熵损失、三元组损失(Triplet Loss),以及中心损失(Center Loss)。这种组合损失函数在许多视觉识别任务中非常有用,尤其是在需要学习特征表示的场景,如人脸识别、行人重识别等。

以下是根据提供的代码片段,对id_loss函数的解释和实现:

  1. 交叉熵损失 (F.cross_entropy(score, target)):用于计算模型输出(score)和真实标签(target)之间的交叉熵损失,这是分类任务中常用的损失函数。

  2. 三元组损失 (triplet(feat, target)[0]):用于学习特征空间中的相对距离,使得相同类别的样本之间的距离小于不同类别样本之间的距离。triplet函数返回一个元组,其中第一个元素是损失值。

  3. 中心损失 (cfg.SOLVER.CENTER_LOSS_WEIGHT * center_criterion(feat, target)):用于减少类内变异,通过将每个类别的特征向量拉向该类别的中心。cfg.SOLVER.CENTER_LOSS_WEIGHT是中心损失的权重,用于调整其在总损失中的贡献度。

这个组合损失函数的目的是同时优化分类性能和特征表示的质量,通过结合交叉熵损失、三元组损失和中心损失来实现。这种方法在需要精细判别能力的任务中特别有效,因为它不仅关注于正确分类,还试图确保模型学习到的特征具有良好的判别性和聚类性质。

关于损失函数和总结性的,没什么想补充的,看Bag of Tricks and A Strong Baseline for Deep Person Re-identification(论文阅读笔记)(2019CVPR)-CSDN博客
                      

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吊肩三角裤

你的鼓励是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值