yolov5详解(二):通过yaml文件构建完整模型
依然拿yolov5l v6.0版本来讲解
1. yaml文件
以下是yolov5l.yaml文件内容
# YOLOv5 🚀 by Ultralytics, GPL-3.0 license# Parameters
nc: 80 # number of classes
depth_multiple: 1.0 # model depth multiple
width_multiple: 1.0 # 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][[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2[-1, 1, Conv, [128, 3, 2]], # 1-P2/4[-1, 3, C3, [128]],[-1, 1, Conv, [256, 3, 2]], # 3-P3/8[-1, 6, C3, [256]],[-1, 1, Conv, [512, 3, 2]], # 5-P4/16[-1, 9, C3, [512]],[-1, 1, Conv, [1024, 3, 2]], # 7-P5/32[-1, 3, C3, [1024]],[-1, 1, SPPF, [1024, 5]], # 9]# YOLOv5 v6.0 head
head:[[-1, 1, Conv, [512, 1, 1]],[-1, 1, nn.Upsample, [None, 2, 'nearest']],[[-1, 6], 1, Concat, [1]], # cat backbone P4[-1, 3, C3, [512, False]], # 13[-1, 1, Conv, [256, 1, 1]],[-1, 1, nn.Upsample, [None, 2, 'nearest']],[[-1, 4], 1, Concat, [1]], # cat backbone P3[-1, 3, C3, [256, False]], # 17 (P3/8-small)[-1, 1, Conv, [256, 3, 2]],[[-1, 14], 1, Concat, [1]], # cat head P4[-1, 3, C3, [512, False]], # 20 (P4/16-medium)[-1, 1, Conv, [512, 3, 2]],[[-1, 10], 1, Concat, [1]], # cat head P5[-1, 3, C3, [1024, False]], # 23 (P5/32-large)[[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)]
nc:分类的类别数量;
depth_multiple:每一层的深度,最终的层数需要乘上这个系数取整;
width_multiple:每一层的输出通道数,最终的输出通道同样需要乘上这个系数;
anchors:有三个尺度的anchor最为预测的候选框,每一个尺度对应三个anchor;
backbone:
…
head:
…
backbone,head中为列表元素,每一个列表元素对应是一层结构,其中包含四个元素为:[from, number, module, args]
举个例子如:[-1, 1, Conv, [512, 1, 1]]
from=-1,表示当前层的输入为上一层的输出;
number=1,表示当前层只重复一次(depth_multiple=1的时候);
module=Conv,表示已经定义好的Conv类,其已经定义好了,当前Conv是在common.py中定义的执行的是ConvBNSilu操作,具体可到代码里看;
args=[512, 1, 1],是Conv这个类必要的三个参数,具体一会看代码
2. yolo.py代码
class Model就是构建的模型,其主要问题都已经在代码中注释,可以自己去debug看一下结果。
import torch
import thop
from common import *
from copy import deepcopy
import yaml
from utils import make_divisible, check_anchor_order, initialize_weights, scale_img, feature_visualization, time_sync, model_info
import logging
import mathlogging.basicConfig(level=logging.INFO)
LOGGER = logging.getLogger(__name__)""" 代码仍然是官方的代码,增加了一些注释去理解,删除一些没有用到的模块,这里仍然使用yolov5l 结构"""class Detect(nn.Module):stride = None # strides computed during buildonnx_dynamic = False # ONNX export parameter""" head 中的 detect层,用来输出最后预测结果 """def __init__(self, nc=80, anchors=(), ch=(), inplace=True):super().__init__()self.nc = ncself.no = nc + 5self.nl = len(anchors) # 有多少个检测检测头,一般三个就是20*20, 40*40,80*80 三个尺度self.na = len(anchors[0]) // 2 # 目前也是3self.grid = [torch.zeros(1)] * self.nl # 初始化grid cellself.anchor_grid = [torch.zeros(1)] * self.nl # init anchor gridself.register_buffer('anchors', torch.tensor(anchors).float().view(self.nl, -1, 2)) # shape(nl,na,2)self.m = nn.ModuleList(nn.Conv2d(x, self.no * self.na, 1) for x in ch) # 用于输出的三个卷积self.inplace = inplacedef forward(self, x):"""x : 每一个检测头的输入,是一个列表[xx,xx,xx]"""z = [] # inference outputfor i in range(self.nl):x[i] = self.m[i](x[i]) # convbs, _, ny, nx = x[i].shape # x(bs,255,20,20)# (bs, 3, 20, 20, 85)x[i] = x[i].view(bs, self.na, self.no, ny, nx).permute(0, 1, 3, 4, 2).contiguous() # to x(bs,3,20,20,85)if not self.training: #inferenceif self.grid[i].shape[2:4] != x[i].shape[2:4] or self.onnx_dynamic:self.grid[i], self.anchor_grid[i] = self._make_grid(nx, ny, i)# (bs,3,20,20,85)y = x[i].sigmoid()if self.inplace:# xywh 相对于预测值的转换,这个跟v3 公式不太一样 stride 下采样倍数[8,16,32] 因为实际预测的值是归一化后的结果y[..., 0:2] = (y[..., 0:2] * 2. - 0.5 + self.grid[i]) * self.stride[i] #xyy[..., 2:4] = (y[..., 2:4] * 2) ** 2 * self.anchor_grid[i] # whelse: # for YOLOv5 on AWS Inferentia https://github.com/ultralytics/yolov5/pull/2953 可以不用管,针对于亚马逊的一个部署的改进xy = (y[..., 0:2] * 2. - 0.5 + self.grid[i]) * self.stride[i] # xywh = (y[..., 2:4] * 2) ** 2 * self.anchor_grid[i] # why = torch.cat((xy, wh, y[..., 4:]), -1)# (bs, 3*20*20, 85)z.append(y.view(bs, -1, self.no))return x if self.training else (torch.cat(z, 1), x) # [(bs, 3*20*20, 85), (bs, 3*40*40, 85), ...] inference 三个检测头结果catdef _make_grid(self, nx=20, ny=20, i=0):d = self.anchors[i].deviceyv, xv = torch.meshgrid([torch.arange(ny).to(d), torch.arange(nx).to(d)]) # 生成二维网络 都是20*20# 网格生成grid = torch.stack((xv, yv), 2).expand((1, self.na, ny, nx, 2)).float() #(1, 3, ny, nx, 2) 对应网格(x,y)# (1, self.na=3, ny, nx, 2) 每一个grid cell对应的3个anchor大小anchor_grid = (self.anchors[i].clone() * self.stride[i]).view((1, self.na, 1, 1, 2)).expand((1, self.na, ny, nx, 2)).float()return grid, anchor_gridclass Model(nn.Module):def __init__(self, cfg='yolov5l.yaml', ch=3, nc=None, anchors=None): # model, input channels, number of classessuper(Model, self).__init__()# 加载yaml文件with open(cfg, errors='ignore') as f:self.yaml = yaml.safe_load(f) # model dict# 获取ch, nc , anchorsch = self.yaml['ch'] = self.yaml.get('ch', ch)if nc and nc != self.yaml['nc']:LOGGER.info(f"Overriding model.yaml nc={self.yaml['nc']} with nc={nc}")self.yaml['nc'] = ncif anchors:LOGGER.info(f'Overriding model.yaml anchors with anchors={anchors}')self.yaml['anchors'] = round(anchors)# 构建模型结构model, 以及存着哪些层的输出会作为其他层的输入[6, 4, 14, 10, 17, 20, 23]self.model, self.save = paras_model(deepcopy(self.yaml), [ch])self.names = [str(i) for i in range(self.yaml['nc'])] # default names[0,1,2,...,79]# 加速推理的,默认True不使用,# AWS Inferentia Inplace compatiability https://github.com/ultralytics/yolov5/pull/2953self.inplace = self.yaml.get('inplace', True)# build strides, anchorsm = self.model[-1] # # Detect()if isinstance(m, Detect):s = 256 # 2x min stridem.inplace = self.inplace# 获取最终输出feature map 尺度相对于原图尺度下采样倍数[8,16,32] 对应小中大三种尺度的anchor, 目的给anchors做归一化m.stride = torch.tensor([s / x.shape[-2] for x in self.forward(torch.zeros(1, ch, s, s))]) # forwardm.anchors /= m.stride.view(-1, 1, 1)# 检查anchor顺序与stride顺序是否一致check_anchor_order(m)self.stride = m.strideself._initialize_biases() # only run once 初始化权重偏置参数# Init weights, biasesinitialize_weights(self)self.info()LOGGER.info('')def forward(self, x, augment=False, profile=False, visualize=False):# 使用默认参数 # 默认执行 正常前向推理if augment:return self._forward_augment(x) # augmented inference, Nonereturn self._forward_once(x, profile, visualize) # single-scale inference, train# 推理时是否采用数据增强上下flip/左右flipdef _forward_augment(self, x):img_size = x.shape[-2:] # height, widths = [1, 0.83, 0.67] # scalesf = [None, 3, None] # flips (2-ud, 3-lr)y = [] # outputsfor si, fi in zip(s, f):xi = scale_img(x.flip(fi) if fi else x, si, gs=int(self.stride.max()))yi = self._forward_once(xi)[0] # forward# cv2.imwrite(f'img_{si}.jpg', 255 * xi[0].cpu().numpy().transpose((1, 2, 0))[:, :, ::-1]) # saveyi = self._descale_pred(yi, fi, si, img_size)y.append(yi)y = self._clip_augmented(y) # clip augmented tailsreturn torch.cat(y, 1), None # augmented inference, traindef _forward_once(self, x, profile=False, visualize=False):y, dt = [], [] # outputs y存放self.save中每一层的输出,dt在profile打印评估# 开始构建模型for m in self.model:if m.f != -1: # if not from previous layer# 这里的m.f是一个列表,表示来自哪几层作为输入,如[-1,6]则是上一层和第六层作为输入构建新的x, 此时x列表, 只有concat和Detect层是接受列表作为输入的x = y[m.f] if isinstance(m.f, int) else [x if j == -1 else y[j] for j in m.f] # from earlier layersif profile:self._profile_one_layer(m, x, dt)x = m(x) # runy.append(x if m.i in self.save else None) # save output# 做了一些可if visualize:feature_visualization(x, m.type, m.i, save_dir=visualize)return xdef _profile_one_layer(self, m, x, dt):c = isinstance(m, Detect) # is final layer, copy input as inplace fixo = thop.profile(m, inputs=(x.copy() if c else x,), verbose=False)[0] / 1E9 * 2 if thop else 0 # FLOPst = time_sync()for _ in range(10):m(x.copy() if c else x)dt.append((time_sync() - t) * 100)if m == self.model[0]:LOGGER.info(f"{'time (ms)':>10s} {'GFLOPs':>10s} {'params':>10s} {'module'}")LOGGER.info(f'{dt[-1]:10.2f} {o:10.2f} {m.np:10.0f} {m.type}')if c:LOGGER.info(f"{sum(dt):10.2f} {'-':>10s} {'-':>10s} Total")def _clip_augmented(self, y):# Clip YOLOv5 augmented inference tailsnl = self.model[-1].nl # number of detection layers (P3-P5)g = sum(4 ** x for x in range(nl)) # grid pointse = 1 # exclude layer counti = (y[0].shape[1] // g) * sum(4 ** x for x in range(e)) # indicesy[0] = y[0][:, :-i] # largei = (y[-1].shape[1] // g) * sum(4 ** (nl - 1 - x) for x in range(e)) # indicesy[-1] = y[-1][:, i:] # smallreturn ydef _descale_pred(self, p, flips, scale, img_size):# de-scale predictions following augmented inference (inverse operation)if self.inplace:p[..., :4] /= scale # de-scaleif flips == 2:p[..., 1] = img_size[0] - p[..., 1] # de-flip udelif flips == 3:p[..., 0] = img_size[1] - p[..., 0] # de-flip lrelse:x, y, wh = p[..., 0:1] / scale, p[..., 1:2] / scale, p[..., 2:4] / scale # de-scaleif flips == 2:y = img_size[0] - y # de-flip udelif flips == 3:x = img_size[1] - x # de-flip lrp = torch.cat((x, y, wh, p[..., 4:]), -1)return pdef _initialize_biases(self, cf=None): # initialize biases into Detect(), cf is class frequency# https://arxiv.org/abs/1708.02002 section 3.3# cf = torch.bincount(torch.tensor(np.concatenate(dataset.labels, 0)[:, 0]).long(), minlength=nc) + 1.m = self.model[-1] # Detect() modulefor mi, s in zip(m.m, m.stride): # fromb = mi.bias.view(m.na, -1) # conv.bias(255) to (3,85)b.data[:, 4] += math.log(8 / (640 / s) ** 2) # obj (8 objects per 640 image)b.data[:, 5:] += math.log(0.6 / (m.nc - 0.99)) if cf is None else torch.log(cf / cf.sum()) # clsmi.bias = torch.nn.Parameter(b.view(-1), requires_grad=True)def info(self, verbose=True, img_size=640): # print model informationmodel_info(self, verbose, img_size)def paras_model(d, ch):"""Args:d: yaml dictch: 输入通道数Returns: model, save"""LOGGER.info('\n%3s%18s%3s%10s %-40s%-30s' % ('', 'from', 'n', 'params', 'module', 'arguments'))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 anchorsno = na * (nc + 5) # number of outputs = anchors * (classes + 5) 每一个grid cell预测的数量layers, save, c2 = [], [], ch[-1] # layers, savelist, ch out, ch记录是每一层的输出通道数是多少# cong yaml 文件构建模型 构建每一层的输入参数列表argsfor i, (f, n, m, args) in enumerate(d['backbone'] + d['head']): # from, number, module, argsm = eval(m) if isinstance(m, str) else m # 赋予表达式for j, a in enumerate(args):try:args[j] = eval(a) if isinstance(a, str) else aexcept NameError:pass# 实际层数 要乘上 depth_multiple,然后四舍五入取整n = n_ = max(round(n * gd), 1) if n > 1 else n # depth gain# 实际上 当前版本只有Conv Bottleneck SPPF C3, 其他在common.py中让其为Noneif m in [Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, SPPF, DWConv, MixConv2d, Focus, CrossConv,BottleneckCSP, C3, C3TR, C3SPP, C3Ghost]:c1, c2 = ch[f], args[0] # 当前层,输入输出通道,f有可能是列表# 实际输出通道数 要乘上width_multiple / 8 向上取整之后在乘8,有点绕,在l版本中等于自己本身if c2 != no: # if not output 最终输出层不需要做系数相乘c2 = make_divisible(c2 * gw, 8)args = [c1, c2, *args[1:]] # 构成层的输入参数 c1,c2,k,s,p 对于Conv# C3 层参数,需要额外插入重复的bottleneckif m in [BottleneckCSP, C3, C3TR, C3Ghost]:args.insert(2, n) # number of repeatsn = 1 # 对于C3 重复的是bottleneck 而不是整个C3,所以n=1# BN层参数只有上一层的通道数,事实上,BN层作为Conv的一部分,没有单独的BN层elif m is nn.BatchNorm2d:args = [ch[f]]elif m is Concat:c2 = sum([ch[x] for x in f]) # 在common里也注释过了,Concat实际上是把输入通道数在一起elif m is Detect:args.append([ch[x] for x in f])if isinstance(args[1], int): # number of anchorsargs[1] = [list(range(args[1] * 2))] * len(f)# 以下在当前版本没使用elif m is Expand:c2 = ch[f] // args[0] ** 2# nn.Upsampleelse:c2 = ch[f]# 按照yaml 从上到下构建每一层模型m_ = nn.Sequential(*[m(*args) for _ in range(n)]) if n > 1 else m(*args)t = str(m)[8:-2].replace('__main__.', '') # moudel type# print(str(m), t) <class 'common.Conv'> common.Convnp = sum([x.numel() for x in m_.parameters()]) # # number paramsm_.i, m_.f, m_.type, m_.np = i, f, t, np # attach index, 'from' index, type, number paramsLOGGER.info('%3s%18s%3s%10.0f %-40s%-30s' % (i, f, n_, np, t, args)) # printsave.extend(x % i for x in ([f] if isinstance(f, int) else f) if x != -1) # append to savelist# print(save) # [6, 4, 14, 10, 17, 20, 23] 记录哪些层是作为其他层的输入layers.append(m_)if i == 0:ch = []ch.append(c2)return nn.Sequential(*layers), sorted(save)if __name__ == '__main__':from torchinfo import summarynet = Model('yolov5l.yaml')summary(net, input_size=(1, 3, 640, 640), depth=4)
可以执行代码看一下模型结果,完整的代码放在github上了,可以clone下来执行,看一下啊模型结构。可以看到最后的结果是和上一节画的模型结果是完全一样的。
Model [1, 25200, 85] –
├─Sequential: 1-1 – –
│ └─Conv: 2-1 [1, 64, 320, 320] –
│ │ └─Conv2d: 3-1 [1, 64, 320, 320] 6,912
│ │ └─BatchNorm2d: 3-2 [1, 64, 320, 320] 128
│ │ └─SiLU: 3-3 [1, 64, 320, 320] –
│ └─Conv: 2-2 [1, 128, 160, 160] –
│ │ └─Conv2d: 3-4 [1, 128, 160, 160] 73,728
│ │ └─BatchNorm2d: 3-5 [1, 128, 160, 160] 256
│ │ └─SiLU: 3-6 [1, 128, 160, 160] –
│ └─C3: 2-3 [1, 128, 160, 160] –
│ │ └─Conv: 3-7 [1, 64, 160, 160] –
│ │ │ └─Conv2d: 4-1 [1, 64, 160, 160] 8,192
│ │ │ └─BatchNorm2d: 4-2 [1, 64, 160, 160] 128
│ │ │ └─SiLU: 4-3 [1, 64, 160, 160] –
│ │ └─Sequential: 3-8 [1, 64, 160, 160] –
│ │ │ └─Bottleneck: 4-4 [1, 64, 160, 160] 41,216
│ │ │ └─Bottleneck: 4-5 [1, 64, 160, 160] 41,216
│ │ │ └─Bottleneck: 4-6 [1, 64, 160, 160] 41,216
│ │ └─Conv: 3-9 [1, 64, 160, 160] –
│ │ │ └─Conv2d: 4-7 [1, 64, 160, 160] 8,192
│ │ │ └─BatchNorm2d: 4-8 [1, 64, 160, 160] 128
│ │ │ └─SiLU: 4-9 [1, 64, 160, 160] –
│ │ └─Conv: 3-10 [1, 128, 160, 160] –
│ │ │ └─Conv2d: 4-10 [1, 128, 160, 160] 16,384
│ │ │ └─BatchNorm2d: 4-11 [1, 128, 160, 160] 256
│ │ │ └─SiLU: 4-12 [1, 128, 160, 160] –
│ └─Conv: 2-4 [1, 256, 80, 80] –
│ │ └─Conv2d: 3-11 [1, 256, 80, 80] 294,912
│ │ └─BatchNorm2d: 3-12 [1, 256, 80, 80] 512
│ │ └─SiLU: 3-13 [1, 256, 80, 80] –
│ └─C3: 2-5 [1, 256, 80, 80] –
│ │ └─Conv: 3-14 [1, 128, 80, 80] –
│ │ │ └─Conv2d: 4-13 [1, 128, 80, 80] 32,768
│ │ │ └─BatchNorm2d: 4-14 [1, 128, 80, 80] 256
│ │ │ └─SiLU: 4-15 [1, 128, 80, 80] –
│ │ └─Sequential: 3-15 [1, 128, 80, 80] –
│ │ │ └─Bottleneck: 4-16 [1, 128, 80, 80] 164,352
│ │ │ └─Bottleneck: 4-17 [1, 128, 80, 80] 164,352
│ │ │ └─Bottleneck: 4-18 [1, 128, 80, 80] 164,352
│ │ │ └─Bottleneck: 4-19 [1, 128, 80, 80] 164,352
│ │ │ └─Bottleneck: 4-20 [1, 128, 80, 80] 164,352
│ │ │ └─Bottleneck: 4-21 [1, 128, 80, 80] 164,352
│ │ └─Conv: 3-16 [1, 128, 80, 80] –
│ │ │ └─Conv2d: 4-22 [1, 128, 80, 80] 32,768
│ │ │ └─BatchNorm2d: 4-23 [1, 128, 80, 80] 256
│ │ │ └─SiLU: 4-24 [1, 128, 80, 80] –
│ │ └─Conv: 3-17 [1, 256, 80, 80] –
│ │ │ └─Conv2d: 4-25 [1, 256, 80, 80] 65,536
│ │ │ └─BatchNorm2d: 4-26 [1, 256, 80, 80] 512
│ │ │ └─SiLU: 4-27 [1, 256, 80, 80] –
│ └─Conv: 2-6 [1, 512, 40, 40] –
│ │ └─Conv2d: 3-18 [1, 512, 40, 40] 1,179,648
│ │ └─BatchNorm2d: 3-19 [1, 512, 40, 40] 1,024
│ │ └─SiLU: 3-20 [1, 512, 40, 40] –
│ └─C3: 2-7 [1, 512, 40, 40] –
│ │ └─Conv: 3-21 [1, 256, 40, 40] –
│ │ │ └─Conv2d: 4-28 [1, 256, 40, 40] 131,072
│ │ │ └─BatchNorm2d: 4-29 [1, 256, 40, 40] 512
│ │ │ └─SiLU: 4-30 [1, 256, 40, 40] –
│ │ └─Sequential: 3-22 [1, 256, 40, 40] –
│ │ │ └─Bottleneck: 4-31 [1, 256, 40, 40] 656,384
│ │ │ └─Bottleneck: 4-32 [1, 256, 40, 40] 656,384
│ │ │ └─Bottleneck: 4-33 [1, 256, 40, 40] 656,384
│ │ │ └─Bottleneck: 4-34 [1, 256, 40, 40] 656,384
│ │ │ └─Bottleneck: 4-35 [1, 256, 40, 40] 656,384
│ │ │ └─Bottleneck: 4-36 [1, 256, 40, 40] 656,384
│ │ │ └─Bottleneck: 4-37 [1, 256, 40, 40] 656,384
│ │ │ └─Bottleneck: 4-38 [1, 256, 40, 40] 656,384
│ │ │ └─Bottleneck: 4-39 [1, 256, 40, 40] 656,384
│ │ └─Conv: 3-23 [1, 256, 40, 40] –
│ │ │ └─Conv2d: 4-40 [1, 256, 40, 40] 131,072
│ │ │ └─BatchNorm2d: 4-41 [1, 256, 40, 40] 512
│ │ │ └─SiLU: 4-42 [1, 256, 40, 40] –
│ │ └─Conv: 3-24 [1, 512, 40, 40] –
│ │ │ └─Conv2d: 4-43 [1, 512, 40, 40] 262,144
│ │ │ └─BatchNorm2d: 4-44 [1, 512, 40, 40] 1,024
│ │ │ └─SiLU: 4-45 [1, 512, 40, 40] –
│ └─Conv: 2-8 [1, 1024, 20, 20] –
│ │ └─Conv2d: 3-25 [1, 1024, 20, 20] 4,718,592
│ │ └─BatchNorm2d: 3-26 [1, 1024, 20, 20] 2,048
│ │ └─SiLU: 3-27 [1, 1024, 20, 20] –
│ └─C3: 2-9 [1, 1024, 20, 20] –
│ │ └─Conv: 3-28 [1, 512, 20, 20] –
│ │ │ └─Conv2d: 4-46 [1, 512, 20, 20] 524,288
│ │ │ └─BatchNorm2d: 4-47 [1, 512, 20, 20] 1,024
│ │ │ └─SiLU: 4-48 [1, 512, 20, 20] –
│ │ └─Sequential: 3-29 [1, 512, 20, 20] –
│ │ │ └─Bottleneck: 4-49 [1, 512, 20, 20] 2,623,488
│ │ │ └─Bottleneck: 4-50 [1, 512, 20, 20] 2,623,488
│ │ │ └─Bottleneck: 4-51 [1, 512, 20, 20] 2,623,488
│ │ └─Conv: 3-30 [1, 512, 20, 20] –
│ │ │ └─Conv2d: 4-52 [1, 512, 20, 20] 524,288
│ │ │ └─BatchNorm2d: 4-53 [1, 512, 20, 20] 1,024
│ │ │ └─SiLU: 4-54 [1, 512, 20, 20] –
│ │ └─Conv: 3-31 [1, 1024, 20, 20] –
│ │ │ └─Conv2d: 4-55 [1, 1024, 20, 20] 1,048,576
│ │ │ └─BatchNorm2d: 4-56 [1, 1024, 20, 20] 2,048
│ │ │ └─SiLU: 4-57 [1, 1024, 20, 20] –
│ └─SPPF: 2-10 [1, 1024, 20, 20] –
│ │ └─Conv: 3-32 [1, 512, 20, 20] –
│ │ │ └─Conv2d: 4-58 [1, 512, 20, 20] 524,288
│ │ │ └─BatchNorm2d: 4-59 [1, 512, 20, 20] 1,024
│ │ │ └─SiLU: 4-60 [1, 512, 20, 20] –
│ │ └─MaxPool2d: 3-33 [1, 512, 20, 20] –
│ │ └─MaxPool2d: 3-34 [1, 512, 20, 20] –
│ │ └─MaxPool2d: 3-35 [1, 512, 20, 20] –
│ │ └─Conv: 3-36 [1, 1024, 20, 20] –
│ │ │ └─Conv2d: 4-61 [1, 1024, 20, 20] 2,097,152
│ │ │ └─BatchNorm2d: 4-62 [1, 1024, 20, 20] 2,048
│ │ │ └─SiLU: 4-63 [1, 1024, 20, 20] –
│ └─Conv: 2-11 [1, 512, 20, 20] –
│ │ └─Conv2d: 3-37 [1, 512, 20, 20] 524,288
│ │ └─BatchNorm2d: 3-38 [1, 512, 20, 20] 1,024
│ │ └─SiLU: 3-39 [1, 512, 20, 20] –
│ └─Upsample: 2-12 [1, 512, 40, 40] –
│ └─Concat: 2-13 [1, 1024, 40, 40] –
│ └─C3: 2-14 [1, 512, 40, 40] –
│ │ └─Conv: 3-40 [1, 256, 40, 40] –
│ │ │ └─Conv2d: 4-64 [1, 256, 40, 40] 262,144
│ │ │ └─BatchNorm2d: 4-65 [1, 256, 40, 40] 512
│ │ │ └─SiLU: 4-66 [1, 256, 40, 40] –
│ │ └─Sequential: 3-41 [1, 256, 40, 40] –
│ │ │ └─Bottleneck: 4-67 [1, 256, 40, 40] 656,384
│ │ │ └─Bottleneck: 4-68 [1, 256, 40, 40] 656,384
│ │ │ └─Bottleneck: 4-69 [1, 256, 40, 40] 656,384
│ │ └─Conv: 3-42 [1, 256, 40, 40] –
│ │ │ └─Conv2d: 4-70 [1, 256, 40, 40] 262,144
│ │ │ └─BatchNorm2d: 4-71 [1, 256, 40, 40] 512
│ │ │ └─SiLU: 4-72 [1, 256, 40, 40] –
│ │ └─Conv: 3-43 [1, 512, 40, 40] –
│ │ │ └─Conv2d: 4-73 [1, 512, 40, 40] 262,144
│ │ │ └─BatchNorm2d: 4-74 [1, 512, 40, 40] 1,024
│ │ │ └─SiLU: 4-75 [1, 512, 40, 40] –
│ └─Conv: 2-15 [1, 256, 40, 40] –
│ │ └─Conv2d: 3-44 [1, 256, 40, 40] 131,072
│ │ └─BatchNorm2d: 3-45 [1, 256, 40, 40] 512
│ │ └─SiLU: 3-46 [1, 256, 40, 40] –
│ └─Upsample: 2-16 [1, 256, 80, 80] –
│ └─Concat: 2-17 [1, 512, 80, 80] –
│ └─C3: 2-18 [1, 256, 80, 80] –
│ │ └─Conv: 3-47 [1, 128, 80, 80] –
│ │ │ └─Conv2d: 4-76 [1, 128, 80, 80] 65,536
│ │ │ └─BatchNorm2d: 4-77 [1, 128, 80, 80] 256
│ │ │ └─SiLU: 4-78 [1, 128, 80, 80] –
│ │ └─Sequential: 3-48 [1, 128, 80, 80] –
│ │ │ └─Bottleneck: 4-79 [1, 128, 80, 80] 164,352
│ │ │ └─Bottleneck: 4-80 [1, 128, 80, 80] 164,352
│ │ │ └─Bottleneck: 4-81 [1, 128, 80, 80] 164,352
│ │ └─Conv: 3-49 [1, 128, 80, 80] –
│ │ │ └─Conv2d: 4-82 [1, 128, 80, 80] 65,536
│ │ │ └─BatchNorm2d: 4-83 [1, 128, 80, 80] 256
│ │ │ └─SiLU: 4-84 [1, 128, 80, 80] –
│ │ └─Conv: 3-50 [1, 256, 80, 80] –
│ │ │ └─Conv2d: 4-85 [1, 256, 80, 80] 65,536
│ │ │ └─BatchNorm2d: 4-86 [1, 256, 80, 80] 512
│ │ │ └─SiLU: 4-87 [1, 256, 80, 80] –
│ └─Conv: 2-19 [1, 256, 40, 40] –
│ │ └─Conv2d: 3-51 [1, 256, 40, 40] 589,824
│ │ └─BatchNorm2d: 3-52 [1, 256, 40, 40] 512
│ │ └─SiLU: 3-53 [1, 256, 40, 40] –
│ └─Concat: 2-20 [1, 512, 40, 40] –
│ └─C3: 2-21 [1, 512, 40, 40] –
│ │ └─Conv: 3-54 [1, 256, 40, 40] –
│ │ │ └─Conv2d: 4-88 [1, 256, 40, 40] 131,072
│ │ │ └─BatchNorm2d: 4-89 [1, 256, 40, 40] 512
│ │ │ └─SiLU: 4-90 [1, 256, 40, 40] –
│ │ └─Sequential: 3-55 [1, 256, 40, 40] –
│ │ │ └─Bottleneck: 4-91 [1, 256, 40, 40] 656,384
│ │ │ └─Bottleneck: 4-92 [1, 256, 40, 40] 656,384
│ │ │ └─Bottleneck: 4-93 [1, 256, 40, 40] 656,384
│ │ └─Conv: 3-56 [1, 256, 40, 40] –
│ │ │ └─Conv2d: 4-94 [1, 256, 40, 40] 131,072
│ │ │ └─BatchNorm2d: 4-95 [1, 256, 40, 40] 512
│ │ │ └─SiLU: 4-96 [1, 256, 40, 40] –
│ │ └─Conv: 3-57 [1, 512, 40, 40] –
│ │ │ └─Conv2d: 4-97 [1, 512, 40, 40] 262,144
│ │ │ └─BatchNorm2d: 4-98 [1, 512, 40, 40] 1,024
│ │ │ └─SiLU: 4-99 [1, 512, 40, 40] –
│ └─Conv: 2-22 [1, 512, 20, 20] –
│ │ └─Conv2d: 3-58 [1, 512, 20, 20] 2,359,296
│ │ └─BatchNorm2d: 3-59 [1, 512, 20, 20] 1,024
│ │ └─SiLU: 3-60 [1, 512, 20, 20] –
│ └─Concat: 2-23 [1, 1024, 20, 20] –
│ └─C3: 2-24 [1, 1024, 20, 20] –
│ │ └─Conv: 3-61 [1, 512, 20, 20] –
│ │ │ └─Conv2d: 4-100 [1, 512, 20, 20] 524,288
│ │ │ └─BatchNorm2d: 4-101 [1, 512, 20, 20] 1,024
│ │ │ └─SiLU: 4-102 [1, 512, 20, 20] –
│ │ └─Sequential: 3-62 [1, 512, 20, 20] –
│ │ │ └─Bottleneck: 4-103 [1, 512, 20, 20] 2,623,488
│ │ │ └─Bottleneck: 4-104 [1, 512, 20, 20] 2,623,488
│ │ │ └─Bottleneck: 4-105 [1, 512, 20, 20] 2,623,488
│ │ └─Conv: 3-63 [1, 512, 20, 20] –
│ │ │ └─Conv2d: 4-106 [1, 512, 20, 20] 524,288
│ │ │ └─BatchNorm2d: 4-107 [1, 512, 20, 20] 1,024
│ │ │ └─SiLU: 4-108 [1, 512, 20, 20] –
│ │ └─Conv: 3-64 [1, 1024, 20, 20] –
│ │ │ └─Conv2d: 4-109 [1, 1024, 20, 20] 1,048,576
│ │ │ └─BatchNorm2d: 4-110 [1, 1024, 20, 20] 2,048
│ │ │ └─SiLU: 4-111 [1, 1024, 20, 20] –
│ └─Detect: 2-25 [1, 25200, 85] –
│ │ └─ModuleList: 3-65 – –
│ │ │ └─Conv2d: 4-112 [1, 255, 80, 80] 65,535
│ │ │ └─Conv2d: 4-113 [1, 255, 40, 40] 130,815
│ │ │ └─Conv2d: 4-114 [1, 255, 20, 20] 261,375
Total params: 46,563,709
Trainable params: 46,563,709
Non-trainable params: 0
Total mult-adds (G): 54.50
Input size (MB): 4.92
Forward/backward pass size (MB): 1193.51
Params size (MB): 186.25
Estimated Total Size (MB): 1384.68
相关文章:
yolov5详解(二):通过yaml文件构建完整模型
依然拿yolov5l v6.0版本来讲解 1. yaml文件 以下是yolov5l.yaml文件内容 # YOLOv5 🚀 by Ultralytics, GPL-3.0 license# Parameters nc: 80 # number of classes depth_multiple: 1.0 # model depth multiple width_multiple: 1.0 # layer channel multiple …...
8月8日学习笔记 python基础
1.环境 python2, python3 yum list installed|grep python yum -y install python3 # 最新安装3.12可以使⽤源码安装,教程是在第⼀个星期pdf python3 --version 3.6.8 #进⼊到python的编辑状态 python3 # 如果直接输⼊python,也会进⼊到pyth…...
电动自行车出海黑马Avento独立站拆解(上)丨出海笔记
这次我们来拆解一个电动自行车的独立站 为什么选电动自行车? 因为全球疫情,带来出行问题——避免聚集,大家都减少了公共交通工具,而改为自行车,电动自行车...... 君不见疫情之后无论是出行自行车,还是健…...
Gerrit 使用教程
一、Gerrit简介 Gerrit,一种开放源代码的代码审查软件,使用网页界面。利用网页浏览器,同一个团队的程序员,可以相互审阅彼此修改后的代码,决定是否能够提交,退回或是继续修改。它使用版本控制系统Git作为底…...
sudu提权命令账号安全控制(su命令)执行单个命令并返回原用户、执行多个命令并返回原用户、保持当前环境变量、配置文件/etc/sudoers
su命令 su 命令是 Linux 和 Unix 系统中用于切换用户身份的命令。它允许一个用户变成另一个用户并以该用户的权限运行命令或启动新的 shell 会话。 基本语法 su [选项] [用户名] 用途: su[选项][-][用户[arg]…] 将有效用户id和组id更改为user的id。 A merely-im…...
【线性代数】【二】2.7 矩阵的秩
文章目录 前言一、向量组的秩二、矩阵的秩三、矩阵的可逆性与秩总结 前言 在前面的内容中,我们已经陆陆续续地给出了秩的概念。本文可以看成是对以往概念与性质的总结,那专门针对秩进行分析。 一、向量组的秩 在笔记2.2中,我们学习了极大线…...
计算机网络部分基础知识
网络协议的意义 单台主机内部的设备之间需要发送和接收消息,那么和相隔很远的两台主机之间发送消息有什么区别呢?两台主机通过网络发送消息,相当于两个网卡设备之间进行通信,最大的区别在于距离变长了。而距离变长带来的结果就是&…...
WESWOO合作的出海企业(一)
分享一些我们在shopify开发上合作的品牌介绍1. **韶音科技(SHOKZ)**: - WESWOO为韶音科技设计了多个产品页面,如OPENFIT、OPENSWIMPRO等,这些页面展示了产品特点、滑动特效、比较功能等,并通过品牌VI统一&a…...
vue 项目中 使用vxe-grid 表格中给表格的表头设置特殊的格式 , 并且给指定的列文字设置颜色
项目场景: 相关背景: vue 项目中 使用vxe-grid 表格中给表格的表头设置特殊的格式,并为指定的列文字设置颜色 实现方案: 具体实现方法及步骤: 一、给表格的表头设置特殊的格式 实现方式一: :header-row-s…...
基于SpringBoot的企业资产管理系统
TOC springboot117基于SpringBoot的企业资产管理系统 系统概述 1.1 研究背景 智慧养老是面向居家老人、社区及养老机构的传感网系统与信息平台,并在此基础上提供实时、快捷、高效、低成本的,物联化、互联化、智能化的养老服务。 随着科技进步&#…...
ps快捷键,学习
ps快捷键图片变的特别大,归位,ctrl0背景图层锁住 选中图层,点击顶部图层,新建,背景图层,确定,就解开了,想在锁住,在点一次...
python代码模拟服务器实验2:IO多路复用select
实验代码的环境是在windows,和linux是有差别的 在Windows系统上,select模块需要传递特定的对象类型,而不是文件描述符。在Unix-like系统上,文件描述符是一个整数,而在Windows上,select期望得到的是socket对…...
修改ubuntu的终端显示语言为英文,界面保持为中文
修改ubuntu的终端显示语言为英文,界面保持为中文 sudo nano /etc/default/locale LANGzh_CN.UTF-8nano ~/.bashrc 在文件未尾加入下列两行 export LANGen_US.UTF-8 export LANGUAGEen在终端执行 source ~/.bashrc之后提示语言就变成英文了...
重塑园区生态,引领产业智慧化新飞跃
中服云智慧园区平台基于工业物联网平台,在园区场景中集中运用云计算、物联网、大数据、人工智能、数字孪生、边缘计算等新一代信息技术。秉承产业主导、业务主导、效率主导的理念,通过一体化子系统集成、智慧化业务管理、可视化运营分析、人性化客户服务…...
WSL 忘记ubuntu的密码
文章目录 1. 以管理员身份打开 PowerShel2.输入命令 wsl.exe -d Ubuntu-20.04 --user root3.输入命令 passwd username 修改用户密码,username即待重置的用户的名称 1. 以管理员身份打开 PowerShel 2.输入命令 wsl.exe -d Ubuntu-20.04 --user root 注意版本号是自…...
github项目-创建一个新分支
在远程仓库创建一个分支实际上是在本地创建一个分支,然后将该分支推送到远程仓库。这是因为在 Git 中,您不能直接在远程仓库创建分支,而需要先在本地创建分支,然后将该分支推送到远程仓库。 以下是创建并推送新分支到远程仓库的步…...
Java设计模式中介者模式的优势与局限性分析
Java设计模式中介者模式的优势与局限性分析 一、引言 在软件工程中,设计模式是一种经过验证的解决方案,用于解决软件开发中常见的问题。设计模式的使用可以提高代码的复用性、可维护性和可扩展性。中介者模式(Mediator Pattern)…...
一、软件工程概述
软件工程概述 1. 软件的概念和特点2. 软件危机的产生3. 软件工程的概念和发展过程4. 软件工程知识体系与职业道德 1. 软件的概念和特点 软件定义 软件程序数据文档。 软件生存周期 问题定义:要解决的问题是什么?可行性分析:对于上阶段所确定…...
第六天:java设计模式、GUI编程与面向对象设计原则
第六天:设计模式、GUI编程与面向对象设计原则 1. 设计模式概述 设计模式的定义:回顾设计模式的定义,即解决特定设计问题的通用解决方案。常见设计模式:了解并掌握几种常见的设计模式,如单例模式、工厂模式、策略模式…...
解读RPA自动化流程机器人
RPA全称Robotic Process Automation,即机器人流程自动化,基于人工智能和自动化技术,能够将大量重复、规则明确的日常事务操作实现自动化处理,通常被形象地称为“数字员工”。本文金智维将深入探讨RPA的主要价值和应用领域…...
Redis17-服务端优化
目录 持久化配置 慢查询 什么是慢查询 如何查看慢查询 命令及安全配置 内存配置 集群优化 持久化配置 Redis的持久化虽然可以保证数据安全,但也会带来很多额外的开销,因此持久化请遵循下列建议: 用来做缓存的Redis实例尽量不要开启持…...
Web语义化及实际应用
你好同学,我是沐爸,欢迎点赞、收藏和关注!今天一起了解下Web语义化及其应用吧! 是什么? 使用合适的标签、属性,让页面能“说话“,让人和机器都能快速理解网页内容。 为什么? 有…...
Linux系统调试课:CPUFreq 中央处理器频率调节技术
文章目录 一、CPUFreq组成二、用户接口三、设备树配置沉淀、分享、成长,让自己和他人都能有所收获!😄 📢中央处理器频率调节(Central Processing Unit frequency,CPUFreq)技术可以降低ARM芯片的功耗,例如在系统对任务压力较小时,通过调整处理器工作频率与输入电压的…...
C++之模版初阶
目录 前言 1.泛型编程 2.函数模版 2.1函数模版概念 2.2函数模版格式 2.3函数模版的原理 2.4函数模版的实例化 2.5模版参数的匹配原则 3.类模版 3.1类模版的定义格式 3.2类模版的实例化 结束语 前言 前面我们学习了C的类与对象和内存管理,接下来我们继续学习…...
飞桨paddle API函数scatter详解
飞桨的scatter函数,是通过基于 updates 来更新选定索引 index 上的输入来获得输出,具体官网api文档见: scatter-API文档-PaddlePaddle深度学习平台 官网给的例子如下: >>> import paddle>>> x paddle.to_tens…...
RCE漏洞复现
PHP命令执行常用函数 回调函数必须是命令执行和代码执行的函数,有两个条件 必须是函数,而且需要有函数运行的参数 危害:可以直接删除文件,添加文件,甚至可以添加用户 system --执行外部程序,并且显示输…...
Qt QTabWidget之创建标签页的多页面切换
QTabWidget 用来分页显示 重要函数: 1.void setTabText(int, QString); //设置页面的名字. 2.void setTabToolTip(QString); //设置页面的提示信息. 3.void setTabEnabled(bool); //设置页面是否被激活. 4.void setTabPosition(QTabPosition::South); //设置页面名字的位置. 5.…...
【RISC-V设计-14】- RISC-V处理器设计K0A之打印输出
【RISC-V设计-14】- RISC-V处理器设计K0A之打印输出 文章目录 【RISC-V设计-14】- RISC-V处理器设计K0A之打印输出1.简介2.验证用例3.软件代码4.链接脚本5.编译脚本6.仿真结果6.1 复位结束6.2 运行成功6.3 终端打印 7.总结 1.简介 本文将详细阐述如何利用 printf 来打印字符串…...
时序预测|基于变分模态分解-时域卷积-双向长短期记忆-注意力机制多变量时间序列预测VMD-TCN-BiLSTM-Attention
时序预测|基于变分模态分解-时域卷积-双向长短期记忆-注意力机制多变量时间序列预测VMD-TCN-BiLSTM-Attention 文章目录 前言时序预测|基于变分模态分解-时域卷积-双向长短期记忆-注意力机制多变量时间序列预测VMD-TCN-BiLSTM-Attention 一、VMD-TCN-BiLSTM-Attention模型1. **…...
Python知识点:如何使用Godot与Python进行游戏脚本编写
在Godot中使用Python进行游戏脚本编写,你需要通过一个插件来实现,因为Godot原生支持的脚本语言是GDScript、VisualScript和C#。这个插件被称为Godot-Python,它允许你在Godot引擎中使用Python编写脚本。以下是详细的步骤指导你如何配置和使用G…...
老网站做成适合手机端的网站怎么做/网址搜索引擎
当定义 没有初始化式 的变量(如int i;)时,系统 有可能 会为我们进行隐式的初始化。至于系统是否帮我们隐式初始化变量,以及为变量赋予一个怎样的初始值,这要取决于该 变量的类型 以及我们在 何处定义的该变量 。1】内置…...
外包加工网可信吗/seo推广软件怎样
我已经创建了一个相机应用程序,我想让我的应用程序在所有4个可能的方向转换,并相应地更新相机预览.因为我已经使用我从以下复制的以下方法:Android – Camera preview is sidewayspublic void updateCameraDisplay(int w, int h) {// set preview size and make any…...
外贸人才网论坛/dz论坛seo设置
总结以供自用,如果转载请指明出处:https://blog.csdn.net/qq_36387683TensorFlow是谷歌基于DistBelief进行研发的第二代人工智能学习系统,其命名来源于本身的运行原理。Tensor(张量)意味着N维数组,Flow&…...
佛山企业网站建设服务/网络营销成功的原因
解说linux启动流程 一:概述 关于linux的系统启动流程我们可以从下面图片中的流程一步一步展开,其实linux系统的启动过程中,我们可以比喻为一个接力赛,计算机的不同模块负责这个接力赛中接力棒的交接(为了更好的理解&a…...
个人工作室如何做网站/舆情信息报送
在教材3.4节中两个问题(最近对问题、凸包问题)中任意选择一个问题,编程实现用蛮力法求解。 具体算法参考教材40-42页。#include <stdio.h> #include <stdlib.h> #include <math.h> int bestPoints(int n) { int d1000,…...
七合一小程序saas平台/培训seo
由于低版本浏览器不支持css3 animation,因此我们需要根据浏览器来选择不同的动画引擎。如果浏览器支持css3 animation,那么就使用此动画引擎,如果不支持,就使用javascript的动画引擎。 首先,我们看一下判定条件&#x…...