ᕕ( ᐛ )ᕗ Wu555's blog

配置文件解析

一些可读的玩意儿_yolov5_segment

data/hyps

hyp超参数配置文件

 lr0 : 0.01   #初始学习率 (SGD=1E-2, Adam=1E-3) 
 lrf : 0.01   #最终的 OneCycleLR 学习率 (lr0 * lrf) 
 momentum: 0.937   # SGD 动量/Adam beta1 
 weight_decay : 0.0005   #优化器权重衰减 5e-4 
 warmup_epochs : 3.0   # warmup epochs (fractions ok) 
 warmup_momentum : 0.8   #预热初始动量 
 warmup_bias_lr : 0.1   #预热初始偏差 lr 
 box : 0.05   # box loss gain 
 cls : 0.5   # cls 损失增益 
 cls_pw : 1.0   # cls BCELoss positive_weight 
 obj : 1.0   # obj loss gain(按像素缩放) 
 obj_pw : 1.0   # obj BCELoss positive_weight 
 iou_t : 0.20   # IoU训练阈值 
 anchor_t : 4.0   #锚倍阈值 
 #anchors:3 # 每个输出层的锚点(0 忽略) 
 fl_gamma : 0.0   #focal loss gamma (efficientDet default gamma=1.5) 
 hsv_h : 0.015   #图像 HSV-Hue 增强(分数) 
 hsv_s : 0.7   #图像 HSV-Saturation 增强(分数) 
 hsv_v : 0.4   #图像 HSV 值增强(分数) 
 degree : 0.0   #图像旋转 (+/- deg) 
 translate : 0.1   #图像翻译(+/- 分数) 
 scale : 0.5   #图像比例(+/- 增益) 
 shear:0.0   #图像剪切(+/- 度) 
 perspective : 0.0   #图像透视(+/- 分数),范围 0-0.001 
 flipud : 0.0   #图像上下翻转(概率) 
 fliplr : 0.5   #图像左右翻转(概率) 
 mosaic: 1.0   #图像马赛克(概率) 
 mixup : 0.0   #图像混合(概率) 
 copy_paste : 0.0   #段复制粘贴(概率) 
  1. yolov5/data/hyps/hyp.scratch-low.yaml(YOLOv5 COCO训练从头优化,数据增强低)
  2. yolov5/data/hyps/hyp.scratch-mdeia.yaml(数据增强中)
  3. yolov5/data/hyps/hyp.scratch-high.yaml(数据增强高)

默认使用的都是low,倒数第三行mosaic值设置为0即可关闭mosaic数据增强

train.py

所在行数 参数 含义 解释
465 weights 模型的权重 .pt文件,存储了模型的所有参数
466 cfg config,模型配置文件 .yaml文件,存储模型各层的形状和类别
473 resume 中断后继续 中断后继续
481 image-weights image-weights 设为True时,计算图像采集的权重,若图像权重越大,那么该图像被采样的概率也越大
483 multi-scale 是否多尺度训练图片 设为True时,将图片放缩成多个尺寸,能够得到不同尺度的特征信息,但速度慢。
484 single-cls single class,单类别训练 设为True时,把多类别标签都视为同一种标签进行训练。
485 optimizer 优化器 默认SGD,有3种可选择’SGD’, ‘Adam’, ‘AdamW’
491 quad 是否使用四元数据加载器 一个实验性功能参数,允许小尺寸图片训练时获得高尺寸训练的优势
493 label-smoothing 标签平滑 label-smoothing
495 freeze 冻结 冻结网络的指定层,冻结的层的权重在训练过程中不会改变
497 seed seed 固定训练的随机性,玄学1017

魔改

使用Shufflenetv2 ,论文:https://arxiv.org/abs/1807.11164

  1. common.py中添加以下代码:
# ---------------------------- ShuffleBlock start -------------------------------

# 通道重排,跨group信息交流
def channel_shuffle(x, groups):
    batchsize, num_channels, height, width = x.data.size()
    channels_per_group = num_channels // groups

    # reshape
    x = x.view(batchsize, groups,
               channels_per_group, height, width)

    x = torch.transpose(x, 1, 2).contiguous()

    # flatten
    x = x.view(batchsize, -1, height, width)

    return x


class conv_bn_relu_maxpool(nn.Module):
    def __init__(self, c1, c2):  # ch_in, ch_out
        super(conv_bn_relu_maxpool, self).__init__()
        self.conv = nn.Sequential(
            nn.Conv2d(c1, c2, kernel_size=3, stride=2, padding=1, bias=False),
            nn.BatchNorm2d(c2),
            nn.ReLU(inplace=True),
        )
        self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)

    def forward(self, x):
        return self.maxpool(self.conv(x))


class Shuffle_Block(nn.Module):
    def __init__(self, inp, oup, stride):
        super(Shuffle_Block, self).__init__()

        if not (1 <= stride <= 3):
            raise ValueError('illegal stride value')
        self.stride = stride

        branch_features = oup // 2
        assert (self.stride != 1) or (inp == branch_features << 1)

        if self.stride > 1:
            self.branch1 = nn.Sequential(
                self.depthwise_conv(inp, inp, kernel_size=3, stride=self.stride, padding=1),
                nn.BatchNorm2d(inp),
                nn.Conv2d(inp, branch_features, kernel_size=1, stride=1, padding=0, bias=False),
                nn.BatchNorm2d(branch_features),
                nn.ReLU(inplace=True),
            )

        self.branch2 = nn.Sequential(
            nn.Conv2d(inp if (self.stride > 1) else branch_features,
                      branch_features, kernel_size=1, stride=1, padding=0, bias=False),
            nn.BatchNorm2d(branch_features),
            nn.ReLU(inplace=True),
            self.depthwise_conv(branch_features, branch_features, kernel_size=3, stride=self.stride, padding=1),
            nn.BatchNorm2d(branch_features),
            nn.Conv2d(branch_features, branch_features, kernel_size=1, stride=1, padding=0, bias=False),
            nn.BatchNorm2d(branch_features),
            nn.ReLU(inplace=True),
        )

    @staticmethod
    def depthwise_conv(i, o, kernel_size, stride=1, padding=0, bias=False):
        return nn.Conv2d(i, o, kernel_size, stride, padding, bias=bias, groups=i)

    def forward(self, x):
        if self.stride == 1:
            x1, x2 = x.chunk(2, dim=1)  # 按照维度1进行split
            out = torch.cat((x1, self.branch2(x2)), dim=1)
        else:
            out = torch.cat((self.branch1(x), self.branch2(x)), dim=1)

        out = channel_shuffle(out, 2)

        return out


# ---------------------------- ShuffleBlock end --------------------------------
  1. yolo.py中注册conv_bn_relu_maxpool, Shuffle_Block两个模块
  2. 新建yolov5s-shufflenetv2-seg.yaml文件为:
# YOLOv5 🚀 by Ultralytics, AGPL-3.0 license

# Parameters

nc: 80  # number of classes

depth_multiple: 0.33  # model depth multiple

width_multiple: 0.50  # layer channel multiple

anchors:

  - [10,13, 16,30, 33,23]  # P3/8

  - [30,61, 62,45, 59,119]  # P4/16

  - [116,90, 156,198, 373,326]  # P5/32

  

# YOLOv5 v6.0 backbone

backbone:

  # [from, number, module, args]

  # Shuffle_Block: [out, stride]

  [[ -1, 1, conv_bn_relu_maxpool, [ 32 ] ], # 0-P2/4

   [ -1, 1, Shuffle_Block, [ 128, 2 ] ],  # 1-P3/8

   [ -1, 3, Shuffle_Block, [ 128, 1 ] ],  # 2

   [ -1, 1, Shuffle_Block, [ 256, 2 ] ],  # 3-P4/16

   [ -1, 7, Shuffle_Block, [ 256, 1 ] ],  # 4

   [ -1, 1, Shuffle_Block, [ 512, 2 ] ],  # 5-P5/32

   [ -1, 3, Shuffle_Block, [ 512, 1 ] ],  # 6

  ]

  

# YOLOv5 v6.0 head

head:

  [[-1, 1, Conv, [256, 1, 1]],

   [-1, 1, nn.Upsample, [None, 2, 'nearest']],

   [[-1, 4], 1, Concat, [1]],  # cat backbone P4

   [-1, 1, C3, [256, False]],  # 10

  

   [-1, 1, Conv, [128, 1, 1]],

   [-1, 1, nn.Upsample, [None, 2, 'nearest']],

   [[-1, 2], 1, Concat, [1]],  # cat backbone P3

   [-1, 1, C3, [128, False]],  # 14 (P3/8-small)

  

   [-1, 1, Conv, [128, 3, 2]],

   [[-1, 11], 1, Concat, [1]],  # cat head P4

   [-1, 1, C3, [256, False]],  # 17 (P4/16-medium)

  

   [-1, 1, Conv, [256, 3, 2]],

   [[-1, 7], 1, Concat, [1]],  # cat head P5

   [-1, 1, C3, [512, False]],  # 20 (P5/32-large)

  

   [[14, 17, 20], 1, Segment, [nc, anchors, 32, 256]],  # Detect(P3, P4, P5)

  ]

激活函数

  1. 在common.py中导入需要更换的激活函数 比如Hard-Swish,则 from utils.activations import Hardswish
  2. 注释掉默认激活函数,更换为Hardswish即可

其他激活函数同理:

# self.act = nn.Identity() if act is True else (act if isinstance(act, nn.Module) else nn.Identity()) 
# self.act = nn.Tanh() if act is True else (act if isinstance(act, nn.Module) else nn.Identity()) 
# self.act = nn.Sigmoid() if act is True else (act if isinstance(act, nn.Module) else nn.Identity()) 
# self.act = nn.ReLU() if act is True else (act if isinstance(act, nn.Module) else nn.Identity()) 
# self.act = nn.LeakyReLU(0.1) if act is True else (act if isinstance(act, nn.Module) else nn.Identity()) 
# self.act = nn.Hardswish() if act is True else (act if isinstance(act, nn.Module) else nn.Identity()) 
# self.act = nn.SiLU() if act is True else (act if isinstance(act, nn.Module) else nn.Identity()) 
# self.act = Mish() if act is True else (act if isinstance(act, nn.Module) else nn.Identity()) 
# self.act = FReLU(c2) if act is True else (act if isinstance(act, nn.Module) else nn.Identity()) 
# self.act = AconC(c2) if act is True else (act if isinstance(act, nn.Module) else nn.Identity()) 
# self.act = MetaAconC(c2) if act is True else (act if isinstance(act, nn.Module) else nn.Identity()) 
# self.act = SiLU_beta(c2) if act is True else (act if isinstance(act, nn.Module) else nn.Identity()) 
# self.act = FReLU_noBN_biasFalse(c2) if act is True else (act if isinstance(act, nn.Module) else nn.Identity())
# self.act = FReLU_noBN_biasTrue(c2) if act is True else (act if isinstance(act, nn.Module) else nn.Identity()) 

参考链接: