YOLOV5——Model之parse_model(d, ch)

train.py

model = Model(cfg or ckpt['model'].yaml, ch=3, nc=nc, anchors=hyp.get('anchors')).to(device)

参数:

  • ch 输入通道
  • nc 类别数目
  • anchors 导入hyp中的anchors

yolo.py

class Model(nn.Module):
  • 解析yaml文件,定义模型
  • 初始化模型权重
  • 前向推理

以下均以默认Yolov5文件为例

一、解析文件

parse_model(deepcopy(self.yaml), ch=[ch])

参数:

  • self.yaml=yolov5s.yaml
  • ch=[3] 输入通道数,将其变为一个list用于记录每一层的输出通道数,如[32,64,……],第一层输出32个,第二层输出64。

1.1定义部分参数

def parse_model(d, ch):  # model_dict, input_channels(3)
    LOGGER.info(f"\n{'':>3}{'from':>18}{'n':>3}{'params':>10}  {'module':<40}{'arguments':<30}")
    anchors, nc, gd, gw = d['anchors'], d['nc'], d['depth_multiple'], d['width_multiple']
    na = (len(anchors[0]) // 2) if isinstance(anchors, list) else anchors  # number of anchors
    no = na * (nc + 5)  # number of outputs = anchors * (classes + 5)

参数

  • gddepth_multiple 对模块的深度进行缩放,即缩小n
  • gdwidth_multiple
  • na anchors的数量,len(anchors[0])=6,na=3
  • no 输出数量=锚框数量×(类别数+4个偏移量+1个置信度)

1.2 把txt的字符串参数转为数字

    layers, save, c2 = [], [], ch[-1]  # layers, savelist, ch out
    for i, (f, n, m, args) in enumerate(d['backbone'] + d['head']):  # from, number, module, args
        m = eval(m) if isinstance(m, str) else m  # eval strings
        for j, a in enumerate(args):
            try:
                args[j] = eval(a) if isinstance(a, str) else a  # eval strings
            except NameError:
                pass

参数:

  • layers 存储解析到的model的layer
  • c2 输入通道数
  # [from, number, module, args]
  [[-1, 1, Conv, [64, 6, 2, 2]],  # 0-P1/2
  • f 输入层的序号
  • n 这个参数下的conv的数量
  • module 模块的类别,如有Conv, C3, SPPF等
  • args 参数

1.3 根据不同module解析

    n = n_ = max(round(n * gd), 1) if n > 1 else n  # depth gain
    if m in (Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, SPPF, DWConv, MixConv2d, Focus, CrossConv,
             BottleneckCSP, C3, C3TR, C3SPP, C3Ghost, nn.ConvTranspose2d, DWConvTranspose2d, C3x):
        c1, c2 = ch[f], args[0]
        if c2 != no:  # if not output
            c2 = make_divisible(c2 * gw, 8)

        args = [c1, c2, *args[1:]]
        if m in [BottleneckCSP, C3, C3TR, C3Ghost, C3x]:
            args.insert(2, n)  # number of repeats
            n = 1
    elif m is nn.BatchNorm2d:
        args = [ch[f]]
    elif m is Concat:
        c2 = sum(ch[x] for x in f)
    elif m is Detect:
        args.append([ch[x] for x in f])
        if isinstance(args[1], int):  # number of anchors
            args[1] = [list(range(args[1] * 2))] * len(f)
    elif m is Contract:
        c2 = ch[f] * args[0] ** 2
    elif m is Expand:
        c2 = ch[f] // args[0] ** 2
    else:
        c2 = ch[f]
 n = n_ = max(round(n * gd), 1) if n > 1 else n  # depth gain
  • gd缩放该module的深度,如果n>1,则进行缩放,若缩放后不足1个,则取1,若缩放后n>1,则四舍五入;如果n<1,那就是0,不能让它变成1,就直接取0。
        if m in (Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, SPPF, DWConv, MixConv2d, Focus, CrossConv,
                 BottleneckCSP, C3, C3TR, C3SPP, C3Ghost, nn.ConvTranspose2d, DWConvTranspose2d, C3x):
            c1, c2 = ch[f], args[0]
            if c2 != no:  # if not output
                c2 = make_divisible(c2 * gw, 8) #如果c2不是最终输出通道数,则按gw缩小其宽度

            args = [c1, c2, *args[1:]] #修改args,如从[64,6,2,2]->[3,32,6,2,2]
            if m in [BottleneckCSP, C3, C3TR, C3Ghost, C3x]:
                args.insert(2, n)  # number of repeats 把缩放后的C3模块数目插入第三位,agrs=[输入,输出,宽度]
                n = 1

参数:

  • c1 输入通道数,c2输出通道数。如c1=3,c2=64。
  • gw 缩小网络宽度(即输出通道数)
  • make_divisible 让最终的网络宽度是8的倍数,向下取最近的
  • args = [c1, c2, *args[1:]]
    将args从[原始输出通道数,卷积核大小,步长,padding]
    改为[输入通道数,缩放后的输出通道数,卷积核大小,步长,padding]
  • *args[1:]即从args的第二位开始切片
m_.i, m_.f, m_.type, m_.np = i, f, t, np 

m_.i 层序列号
m_.f 从哪层来,-1指上一层
m_.type 类别,‘models.common.C3’
m_.np参数数量

save.extend(x % i for x in ([f] if isinstance(f, int) else f) if x != -1)  # append to savelist

如果输入不是从上一层来,就记录该层到save这个list中

        layers.append(m_)
        if i == 0:
            ch = []
        ch.append(c2)
  • 把创建好的module(type如为’models.common.C3’)添加到layer的list中
  • 如果是第一层则初始化ch(该之前的[3]为[],因为不要输入),再在后续中,逐渐增加各层输出通道
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值