yolov5样本处理方式

类别不均衡是怎么处理的?

根据样本种类分布使用图像调用频率不同的方法解决。

1、将样本中的groundtruth读出来,存为一个列表;

2、统计训练样本列表中不同类别的矩形框个数,然后给每个类别按相应目标框数的倒数赋值,(数目越多的种类权重越小),形成按种类的分布直方图;

3、对于训练数据列表,每个epoch训练按照类别权重筛选出每类的图像作为训练数据,如使用
random.choice(population, weights=None, *, cum_weights=None, k=1)更改训练图像索引,可达到样本均衡的效果。
model.class_weights = labels_to_class_weights(dataset.labels, nc).to(device) * nc  # attach class weights # 根据labels初始化图片采样权重
# utils/general.py 
def labels_to_class_weights(labels, nc=80):
    # 这里的标签是整个数据集
    # Get class weights (inverse frequency) from training labels
    # labels是list。读取的是lables下的标签文件,[label,x,y,w,h]坐标是归一化后的坐标,将list的labels拼接为nparray数组形式
    if labels[0] is None:  # no labels loaded
        return torch.Tensor()

    labels = np.concatenate(labels, 0)  # labels.shape = (866643, 5) for COCO
    classes = labels[:, 0].astype(np.int)  # labels = [class xywh]
    # 统计类别的直方图,得到的结果就是每一个标签的个数
    weights = np.bincount(classes, minlength=nc)  # occurrences per class

    # Prepend gridpoint count (for uCE training)
    # gpi = ((320 / 32 * np.array([1, 2, 4])) ** 2 * 3).sum()  # gridpoints per image
    # weights = np.hstack([gpi * len(labels)  - weights.sum() * 9, weights * 9]) ** 0.5  # prepend gridpoints to start
    # 没有标签的类别将类别数由0改为1,防止下面取导数的时候出错
    weights[weights == 0] = 1  # replace empty bins with 1
    # 求各个类别标签数的导数,即标签越多,权重就越小
    weights = 1 / weights  # number of targets per class
    # 对权重归一化
    weights /= weights.sum()  # normalize
    # 从numpy.ndarray创建一个张量,返回的张量和ndarray共享同一内存。对张量的修改将反映在ndarray中,反之亦然。返回的张量是不能调整大小的。
    # 即将ndarray格式转换成tensor格式
    return torch.from_numpy(weights)

def labels_to_image_weights(labels, nc=80, class_weights=np.ones(80)):
    # Produces image weights based on class_weights and image contents
    # 统计每张图中标签的数量,并且把统计结果转换为ndarray格式
    class_counts = np.array([np.bincount(x[:, 0].astype(np.int), minlength=nc) for x in labels])
    # 每张图片对图中的每个标签的权重求和即为图片的权重
    image_weights = (class_weights.reshape(1, nc) * class_counts).sum(1)
    # index = random.choices(range(n), weights=image_weights, k=1)  # weight image sample
    return image_weights

train.py 中定义了是采用加权图像策略用于训练
在训练过程中,当设置参数–image_weights为True时,默认为false,会计算图像采集的权重,若图像权重越大,那么该图像被采样的概率也越大。后面遍历图像时,则按照重新采集的索引dataset.indices进行计算。(那么类别少的图片就会被重复采样,多的采样不完全吗???)

parser.add_argument('--image-weights', action='store_true', help='use weighted image selection for training')
for epoch in range(start_epoch, epochs):  # epoch ------------------------------------------------------------------
    model.train()

    # Update image weights (optional)
    if opt.image_weights:
        # Generate indices
        """
        如果设置进行图片采样策略,
        则根据前面初始化的图片采样权重model.class_weights以及maps配合每张图片包含的类别数
        model.class_weights越小,maps越大,cw越大。即标签数量越多,且标签的识别精度越高,赋予的标签的权重越小,从而解决类别不平衡的问题
        通过random.choices生成图片索引indices从而进行采样
        """

        if rank in [-1, 0]:
            cw = model.class_weights.cpu().numpy() * (1 - maps) ** 2 / nc  # class weights
            iw = labels_to_image_weights(dataset.labels, nc=nc, class_weights=cw)  # image weights
            # 利用random.choices根据图像的权重选取图片,每次选取和训练集相同的图片数。
            # 也就意味着训练集中的图片权重大的有的可能会被选取多次,权重小的可能一次都不会被选中用于训练
            dataset.indices = random.choices(range(dataset.n), weights=iw, k=dataset.n)  # rand weighted idx

然后dataloader.sampler.set_epoch(epoch)会根据重写的图片索引dataset.indices对图像进行采样。
(dataloader.sampler工作原理补充)

yolov5是如何划分正负样本的?如何解决正负样本不均衡的?

  1. 划分正负样本的具体代码实现在utils/loss.py中的ComputeLoss中,build_targets实现了anchor的匹配策略,该策略增加了训练的正样本的数量,解决正负样本比例不平衡的问题。

yolov5输出有3个预测分支,每个分支的每个网格有3个anchor与之对应

(1) 跨anchor预测
  yolov5中使用基于shape的策略,对于每一层,查找真实框所在网格对应的anchor,计算每个anchor与真实框的长宽比,如果最大的长宽比例小于hyp.yaml中的anchor_t=4,认为该真实框为正样本,符合条件的anchor保留下来预测回归,所以一个网格可以有0-3个anchor被保留为正样本。其余不符合长宽比的在该分支中认为是负样本。
(2) 跨分支预测
  每一个分支各自独立筛选正样本,互不影响。即在第一个预测分支中某个网格中被认为是正样本,保留了该层的anchor,则在另一个预测分支中,该位置对应的网格符合筛选条件条件,也会被认为是正样本,同样对应anchor也会被保留。这样就增加了正样本的数量。
(3) 跨网格预测
  筛选出符合条件的正样本,会计算该正样本中心点相对网格左上点和右下点的偏移。如果中心点与左上角的偏移小于0.5,则把与当前网格左边网格和上边网格也认为是正样本。具体做法,就是把当前网格的真实目标向左和向上偏移0.5网格。负责预测新网格的anchor和和原网格对应的anchor相同。这样做同样增加了正样本。

yolov5解决小目标做的努力

  1. 在计算objectness loss时,分别给不同输出分支分配了不同的权重。
    P3特征图尺寸最小,感受野最小,用于检测的目标最小,对应的lobj的权重为最大4.0,P5特征图尺寸最大,感受野最大,用于检测的目标最大,对应的lobj的权重为最小0.4.
# P3-P7 的特征点的数量比值为P3 : P4 : P5 = 4:1:0.25
self.balance = {3: [4.0, 1.0, 0.4]}.get(det.nl, [4.0, 1.0, 0.25, 0.06, .02])
lobj += obji * self.balance[i] 

模型训练时样本类别不均衡怎么办? labels_to_class_weights
https://www.cnblogs.com/xiaoheizi-12345/p/14458802.html

【参考】
1.云深安小生--YOLOV5代码理解——类权重系数和图像权重系数

你可能感兴趣的:(pytorch,python,深度学习)