商汤、易车两段实习总结

大四的时候在易车公司实习了两个月左右,7月份-11月份在商汤实习了4个月左右,收获颇多,小编来总结下都干了些啥以及有什么收获吧。其实主要是对自己经历的一个总结以及对于未来一份实习的经验积累。(大佬可忽略),马上就要找暑期实习了,给自己加个油吧!!

商汤智慧城市CV算法岗位实习总结(2022.7.7-2022.11.7)

主要工作
  • 上衣长度分类任务
  • 准确率和召回率计算确定问题(未知属性实验)
  • 网安项目(特殊制服分类任务)

上衣长度分类任务

  1. 数据集及检查
    数据集格式为图像以及label对应的json文件
训练集测试集
赤膊136591302
短袖920816746
长袖2287903786
无法判断358553940

拿到数据集之后的步骤为:
(1)首先对于json文件进行检查,查看是否有同一个样本标注多个类别或者标注错误的现象,检查出来后需进行人工纠正。
(2)bad case分析:使用kestrel模型(预训练好的模型)进行测试,将分类错误的图像统计出来,并进行分析。
总结出的bad case主要有以下几类:
(1)图像质量低,模糊不清
(2)遮挡现象或者与手臂颜色接近
(3)行人处于骑行状态
(4)非人
2. 重新确定分类标签

                              赤膊、长袖、短袖、无法判断
  1. 网络训练
    backbone:resnet101
    框架:PAR
    训练得到的baseline精度为:
赤膊短袖长袖无法判断mF1
baseline+erase+flip0.8600.8510.7880.7510.812
baseline+erase+flip+color0.9270.8800.8280.8020.861
baseline+erase+flip+color+more iter+lr0.9640.9110.8660.8440.896
遇到的问题以及解决方法
  • 骑行状态下分类精度低的问题如何解决?
  • 类别不平衡的问题如何解决?
  • 能否改进网络进一步提高分类精度?

针对问题1:

解决方法:从业务线回流的数据中爬取了非机动车数据,尝试人工制作骑行数据集进行数据扩充。训练集增加骑手数据(长袖+短袖)30000张左右,测试集增加骑手数据(长袖+短袖)8000张左右。
加入新数据之前,与kestrel基线模型效果对比:
(1)骑手数据测试集表现
(2)通用测试集+骑手测试集表现

短袖(Our)长袖(Our)短袖(kestrel)短袖(kestrel)
P0.7610.9180.8550.935
R0.8510.8000.8890.871
F10.8030.8550.8720.902
赤膊(Our)短袖(Our)长袖(Our)无法判断(Our)赤膊(kestrel)短袖(kestrel)短袖(kestrel)无法判断(kestrel)
P0.9680.8510.9000.7680.9610.8810.9060.760
R0.9530.9030.8230.8000.9450.9040.8610.797
F10.9600.8770.8600.7830.9530.8930.8830.778

加入骑行数据进行训练微调之后,效果为:

短袖长袖骑手数据集(mF1)混合数据集(mF1)通用数据集(mF1)
baseline87.2090.2048.0887.6888.28
baseline+非机动车骑行数据90.0093.9950.3588.8688.63

结论:加入骑手数据微调后精度确实有提升。

针对问题2:

  1. 损失函数层面:
  • class weighted cross entrophy
    按照样本数量进行加权
  • OHEM loss
    算法的核心是选择一些hard examples(多样性和高损失的样本)作为训练的样本,针对性地改善模型学习效果。对于数据的类别不平衡问题,OHEM的针对性更强。
    OHEM loss代码:
class OhemCELoss(nn.Module):
    """
    Online hard example mining cross-entropy loss:在线难样本挖掘
    if loss[self.n_min] > self.thresh: 最少考虑 n_min 个损失最大的 pixel,
    如果前 n_min 个损失中最小的那个的损失仍然大于设定的阈值,
    那么取实际所有大于该阈值的元素计算损失:loss=loss[loss>thresh]。
    否则,计算前 n_min 个损失:loss = loss[:self.n_min]
    """
    def __init__(self, thresh, n_min, ignore_lb=255, *args, **kwargs):
        super(OhemCELoss, self).__init__()
        self.thresh = -torch.log(torch.tensor(thresh, dtype=torch.float)).cuda()     # 将输入的概率 转换为loss值
        self.n_min = n_min
        self.ignore_lb = ignore_lb
        self.criteria = nn.CrossEntropyLoss(ignore_index=ignore_lb, reduction='none')   #交叉熵
 
    def forward(self, logits, labels):
        N, C, H, W = logits.size()
        loss = self.criteria(logits, labels).view(-1)
        loss, _ = torch.sort(loss, descending=True)     # 排序
        if loss[self.n_min] > self.thresh:       # 当loss大于阈值(由输入概率转换成loss阈值)的像素数量比n_min多时,取所以大于阈值的loss值
            loss = loss[loss>self.thresh]
        else:
            loss = loss[:self.n_min]
        return torch.mean(loss)
  • Focal loss
    核心思想是在交叉熵损失函数(CE)的基础上增加了类别的不同权重以及困难(高损失)样本的权重(如下公式),以改善模型学习效果。
    在这里插入图片描述
    其中 α \alpha α值用于平衡正负样本的比例, γ \gamma γ值作为衰减系数。
    (1)对于正样本来说:
    p p p越大, − l o g ( p ) -log(p) log(p)越小,整体损失越小;相反, p p p越小, − l o g ( p ) -log(p) log(p)越大,整体损失越大
    (2)对于负样本来说:
    p p p越大, − l o g ( 1 − p ) -log(1-p) log(1p)越大,整体损失越大;相反, p p p越小, − l o g ( 1 − p ) -log(1-p) log(1p)越小,整体损失越小
    Focal loss代码:
def py_sigmoid_focal_loss(pred,
                          target,
                          weight=None,
                          gamma=2.0,
                          alpha=0.25,
                          reduction='mean',
                          avg_factor=None):
    pred_sigmoid = pred.sigmoid()
    target = target.type_as(pred)
    pt = (1 - pred_sigmoid) * target + pred_sigmoid * (1 - target)
    focal_weight = (alpha * target + (1 - alpha) *
                    (1 - target)) * pt.pow(gamma)
    loss = F.binary_cross_entropy_with_logits(
        pred, target, reduction='none') * focal_weight
    return loss
  1. 模型层面:
  • 采样+集成学习

(1)BalanceCascade
基本架构与EasyEnsemble相同,不同的地方在于每训练一个(Adaboost)分类器后就将正确分类的样本去掉,错误分类的样本放回到原样本空间中,通过调整阈值来筛选出分类错误的样本将其保留,阈值调整为使得模型错误率等于
在这里插入图片描述

(2)EasyEnsemble
Bagging体现于:每一次采样都使用Bagging的采样方法(Bootstrap)对多数类(数量较多的类)样本集进行采样,使其样本数等于少数类
Adaboost体现于:将多数类采样得到的样本集与少数类的样本集的全部样本组合在一起进行Adaboost模型的训练。
最终将T个Adaboost作为基模型进行Ensemble在这里插入图片描述

通常,在数据集噪声较小的情况下,可以用BalanceCascade,可以用较少的基分类器数量得到较好的表现(基于串行的集成学习方法,对噪声敏感容易过拟合)。噪声大的情况下,可以用EasyEnsemble,基于串行+并行的集成学习方法,bagging多个Adaboost过程可以抵消一些噪声影响。

  1. 数据增强方面:

(1)单样本增强

  • AutoAugmentation
    使用强化学习的搜索策略对数据增强空间进行搜索,每个增强操作有两个超参数:进行该操作的概率和图像增强的幅度(magnitude,这个表示数据增强的强度,比如对于旋转,旋转的角度就是增强幅度,旋转角度越大,增强越大。
    目前torchvision已经实现可以直接进行调用:
from torchvision.transforms import autoaugment, transforms
 
train_transform = transforms.Compose([
    transforms.RandomResizedCrop(crop_size, interpolation=interpolation),
    transforms.RandomHorizontalFlip(hflip_prob),
    # 这里policy属于torchvision.transforms.autoaugment.AutoAugmentPolicy,
    # 对于ImageNet就是 AutoAugmentPolicy.IMAGENET
    # 此时aa_policy = autoaugment.AutoAugmentPolicy('imagenet')
    autoaugment.AutoAugment(policy=aa_policy, interpolation=interpolation),
 transforms.PILToTensor(),
    transforms.ConvertImageDtype(torch.float),
    transforms.Normalize(mean=mean, std=std)
 ])

(2)多样本增强

  • MixUp
    原理比较好理解:
    在这里插入图片描述
    在这里插入图片描述
    代码:
def criterion(batch_x, batch_y, alpha=1.0, use_cuda=True):
   '''
   batch_x:批样本数,shape=[batch_size,channels,width,height]
   batch_y:批样本标签,shape=[batch_size]
   alpha:生成lam的beta分布参数,一般取0.5效果较好
   use_cuda:是否使用cuda
   
   returns:
   	mixed inputs, pairs of targets, and lam
   '''
   
   if alpha > 0:
   	#alpha=0.5使得lam有较大概率取01附近
       lam = np.random.beta(alpha, alpha)
   else:
       lam = 1
   batch_size = batch_x.size()[0]
   if use_cuda:
       index = torch.randperm(batch_size).cuda()
   else:
       index = torch.randperm(batch_size) #生成打乱的batch_size索引
   
   #获得混合的mixed_batchx数据,可以是同类(同张图片)混合,也可以是异类(不同图片)混合
   mixed_batchx = lam * batch_x + (1 - lam) * batch_x[index, :]
   
   """
   Example:
   假设batch_x.shape=[2,3,112,112],batch_size=2时,
   如果index=[0,1]的话,则可看成mixed_batchx=lam*[[0,1],3,112,112]+(1-lam)*[[0,1],3,112,112]=[[0,1],3,112,112],即为同类混合
   如果index=[1,0]的话,则可看成mixed_batchx=lam*[[0,1],3,112,112]+(1-lam)*[[1,0],3,112,112]=[batch_size,3,112,112],即为异类混合
   """
   batch_ya, batch_yb = batch_y, batch_y[index]
   return mixed_batchx, batch_ya, batch_yb, lam
def mixup_criterion(criterion, inputs, batch_ya, batch_yb, lam):
   return lam * criterion(inputs, batch_ya) + (1 - lam) * criterion(inputs, batch_yb)

(3)基于深度学习的数据增强
生成模型如变分自编码网络(Variational Auto-Encoding network, VAE)和生成对抗网络(Generative Adversarial Network, GAN),其生成样本的方法也可以用于数据增强。这种基于网络合成的方法相比于传统的数据增强技术虽然过程更加复杂, 但是生成的样本更加多样。

  1. 欠采样/过采样
    在实际操作中,对于每一个batchsize,按照代码原本的设置取到所有的样本的概率是相等的,比如假设数量多的类别为2400张,数量最少的只有100张,那么取到每一个样本的概率均为:1/(2400+100),我们现在改为按照类别存储样本,每一次随机选择类别,在每一个类别对应的样本中再进行选取,这样类别少的样本被选中的概率增加到1/2*1/100=1/200,通过此种方法可以达到相对平衡的训练过程,实验中发现对于极度不平衡的比例还是有效果的。

针对问题3:

  1. Dual attention
    Dual attention主要包括position attention module和channel attention module两部分,分别执行空间上的注意力机制和通道上的注意力机制,最终将两者的结果进行加和,如图所示:
    在这里插入图片描述
    代码实现如下:
class PAM_Module(Module):
    """ Position attention module"""

    # Ref from SAGAN
    def __init__(self, in_dim):
        super(PAM_Module, self).__init__()
        self.chanel_in = in_dim

        self.query_conv = Conv2d(in_channels=in_dim, out_channels=in_dim // 8, kernel_size=1)
        self.key_conv = Conv2d(in_channels=in_dim, out_channels=in_dim // 8, kernel_size=1)
        self.value_conv = Conv2d(in_channels=in_dim, out_channels=in_dim, kernel_size=1)
        self.gamma = Parameter(torch.zeros(1))

        self.softmax = Softmax(dim=-1)

    def forward(self, x):
        """
            inputs :
                x : input feature maps( B X C X H X W)
            returns :
                out : attention value + input feature
                attention: B X (HxW) X (HxW)
        """
        m_batchsize, C, height, width = x.size()
        proj_query = self.query_conv(x).view(m_batchsize, -1, width * height).permute(0, 2, 1)
        proj_key = self.key_conv(x).view(m_batchsize, -1, width * height)
        energy = torch.bmm(proj_query, proj_key)
        attention = self.softmax(energy)
        proj_value = self.value_conv(x).view(m_batchsize, -1, width * height)

        out = torch.bmm(proj_value, attention.permute(0, 2, 1))
        out = out.view(m_batchsize, C, height, width)

        out = self.gamma * out + x
        return out


class CAM_Module(Module):
    """ Channel attention module"""

    def __init__(self, in_dim):
        super(CAM_Module, self).__init__()
        self.chanel_in = in_dim

        self.gamma = Parameter(torch.zeros(1))
        self.softmax = Softmax(dim=-1)

    def forward(self, x):
        """
            inputs :
                x : input feature maps( B X C X H X W)
            returns :
                out : attention value + input feature
                attention: B X C X C
        """
        m_batchsize, C, height, width = x.size()
        proj_query = x.view(m_batchsize, C, -1)
        proj_key = x.view(m_batchsize, C, -1).permute(0, 2, 1)
        energy = torch.bmm(proj_query, proj_key)
        energy_new = torch.max(energy, -1, keepdim=True)[0].expand_as(energy) - energy
        attention = self.softmax(energy_new)
        proj_value = x.view(m_batchsize, C, -1)

        out = torch.bmm(attention, proj_value)
        out = out.view(m_batchsize, C, height, width)

        out = self.gamma * out + x
        return out

整体上来说很像在空间上的自注意力机制和通道上的自注意力机制结合,实验上证明还是有一定效果的。
3. Attribute Localization Module
在进行方法调研的时候,查阅到一篇属性分类的文章感觉很有启发,它的大概思想是从多个尺度上去定位到目标区域然后进行识别,其中用到了spatial transformer进行定位,之前对于这个模块没有太多了解,有兴趣的可以去看看:
https://blog.csdn.net/qq_39422642/article/details/78870629
主体框架为:
在这里插入图片描述
其中的属性定位模块为:
在这里插入图片描述
6. SENet(通道注意力机制)
代码:

from torch import nn
class SELayer(nn.Module):
    def __init__(self, channel, reduction=16):
        super(SELayer, self).__init__()
        self.avg_pool = nn.AdaptiveAvgPool2d(1)
        self.fc = nn.Sequential(
            nn.Linear(channel, channel // reduction, bias=False),
            nn.ReLU(inplace=True),
            nn.Linear(channel // reduction, channel, bias=False),
            nn.Sigmoid()
        )
 
    def forward(self, x):
        b, c, _, _ = x.size()
        y = self.avg_pool(x).view(b, c)
        y = self.fc(y).view(b, c, 1, 1)
        return x * y.expand_as(x)

在这里插入图片描述4. Label Smoothing
Label Smoothing Regularization(LSR)就是为了缓解由label不够soft而容易导致过拟合的问题,使模型对预测less confident,把预测值过度集中在概率较大类别上,把一些概率分到其他概率较小类别上。
实际上实现过程为:
在这里插入图片描述
label smoothing在什么情况下比较有效果呢?

  1. 真实场景下,尤其数据量大的时候 数据里是会有噪音的, 为了避免模型错误的学到这些噪音可以加入label smoothing
  2. 避免模型过于自信,有时候我们训练一个模型会发现给出相当高的confidence,但有时候我们不希望模型太自信了(可能会导致over-fit 等别的问题),希望提高模型的学习难度,也会引入label smoothing
  3. 分类的中会有一些模糊的case,比如图片分类,有些图片即像猫又像狗, 利用soft-target可以给两类都提供监督效果

未知属性实验

  • 根据要求的准确率确定相应的阈值(涉及到presicion/recall/F1)计算
  • 探究类别如果是多种未知类混杂在一起是否会对精度产生影响

precision/recall/F1/accuracy/计算方式为:
精确率
定义为预测为正样本中真正正样本所占的比例,可以写作:
在这里插入图片描述
召回率
定义为所有真实类别为正样本中预测为正样本的比例:
在这里插入图片描述
F1-score
精确率和召回率两个指标通常是此消彼长的,很难兼得,在大规模数据集合中相互制约,需要综合考虑,因此有F1指标的定义:
在这里插入图片描述
AUC/ROC曲线
在这里插入图片描述
TPR表示,在所有正样本中,被预测为正样本的比例
在这里插入图片描述
FPR表示,在所有的负样本中,被预测成正样本的比例
简单来说,在不同的分类阈值的设置之下,将FPR作为横坐标,TPR作为纵坐标构成的曲线为ROC曲线,而曲线下的面积为AUC(Area of Under Curve),分类质量可以用AUC来评估,其表示正例排在负例前面的概率。
Accurarcy
所有预测正确的样本除以样本总数:
在这里插入图片描述
网安特殊制服分类

  • 数据集来源
  • 模型训练

首先我们的任务是对于网络中搜索到的制服图片进行分类,那么我们的数据集来源必须从网上进行爬取得到,爬虫需要确定相应的关键词。可以部分可视化一下:
在这里插入图片描述
训练的框架采用UP框架,backbone分别用的resnet101和resnet18。实验中发现两者精度确实是有一定差距,另外因为爬虫数据较少,如果我们额外加入一些实际生活中监控拍到的制服数据,实验中发现效果反而下降,可能是由于域不同引起的。具体结果就不给大家展示了,所用策略和之前基本相同。

实习总结
  • 准确率、召回率、accurarcy、mF1计算
  • 一些常用的数据增强方法
  • 可以提升精度的注意力机制

易车CV算法岗位实习总结(2021.7.7-2021.9.7)

主要工作
  • 车辆颜色/朝向/结构分类
  • 车辆型号分类

颜色类别:13类
朝向分类: 8类
结构分类: 3类(局部外观,整车外观和内饰)
每个任务均尝试用了VGG和MobileNet进行实验,MobileNet更加轻量化,精度比VGG19略低,对于颜色分类任务来说,为了避免周围环境影响,用检测模型先把车辆检测出来再进行训练。

车辆型号分类
使用efficientNetv1_B7进行训练,取得了超越MobileNetv3的精度,主要面临的问题是类别数量极度不平衡。

实习总结
  • 初步地了解了整个任务的工作流程,从数据集的爬取,网络训练,模型调优均独立完成,对于当时大四的自己来说收获很多。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
商汤LoFTR是一种基于Transformer的视觉特征匹配算法,其主要用途是在图像拼接、图像配准、图像检索等领域进行特征匹配。下面是对商汤LoFTR源码的详细解释。 1. 代码结构 商汤LoFTR源码主要包含以下几个文件: - models.py:包含了特征提取器和特征匹配器的代码。 - utils.py:包含了一些用于数据处理和模型训练的辅助函数。 - datasets.py:包含了用于加载数据集的代码。 - train.py:包含了模型训练的代码。 - inference.py:包含了模型推理的代码。 2. 特征提取器 商汤LoFTR使用的特征提取器是一个基于Transformer的网络,由多个Encoder和Decoder组成。在商汤LoFTR中,Encoder和Decoder都是由多个Self-Attention层和全连接层组成的。 在Encoder中,Self-Attention层用于在输入序列中寻找相关的信息,并将其编码为一个固定长度的向量。全连接层用于将这些向量合并到一起,生成一个包含整个输入序列信息的向量。 在Decoder中,Self-Attention层用于在给定的查询序列中寻找与输入序列相关的信息,并将其编码为一个固定长度的向量。全连接层用于将这些向量合并到一起,生成一个包含整个查询序列信息的向量。 3. 特征匹配器 商汤LoFTR使用的特征匹配器是一个基于双向长短时记忆网络(BiLSTM)和点积注意力机制的网络。该模型输入两个特征向量序列,并输出两个序列中每个位置的相似度得分。 在特征匹配器中,BiLSTM用于对输入序列进行编码,并将其转换为一个更高维度的表示。点积注意力机制用于将两个特征序列中相似的位置进行匹配,生成相应的相似度得分。 4. 数据集 商汤LoFTR支持使用自定义数据集进行训练和测试。数据集可以包含多个图像,每个图像可以包含多个特征点。商汤LoFTR使用OpenCV库中的SIFT算法对图像进行特征点提取。 5. 模型训练 商汤LoFTR的模型训练分为两个阶段。 第一阶段是特征提取器的预训练。在此阶段,使用大量的无标签图像数据对特征提取器进行训练,以便使其能够从图像中提取出有用的特征。 第二阶段是特征匹配器的训练。在此阶段,使用有标签的图像对数据集对特征匹配器进行训练,以便使其能够将两个图像中的特征点进行匹配。 6. 模型推理 商汤LoFTR的模型推理主要分为两个步骤。 第一步是使用特征提取器对输入图像进行特征提取。在此过程中,商汤LoFTR使用OpenCV库中的SIFT算法对图像进行特征点提取,并将提取到的特征点通过特征提取器进行编码。 第二步是使用特征匹配器对两个输入图像中的特征点进行匹配,并输出每个特征点的匹配结果。 7. 总结 商汤LoFTR是一种基于Transformer的视觉特征匹配算法,其主要用途是在图像拼接、图像配准、图像检索等领域进行特征匹配。商汤LoFTR的源码结构清晰,可以通过自定义数据集进行训练和测试。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值