YOLOv5代码解析——yolo.py
yolo.py的主要功能是构建模型。
1、最主要的函数是parse_model,用于解析yaml文件,并根据解析的结果搭建网络。这个函数的注释如下:
def parse_model(d, ch): # model_dict, input_channels(3)"""解析模型文件,并搭建网络结构主要实现功能:更新当前层args,计算c2(当前层的输出channel) => 使用当前层的参数搭建当前层 => 生成layers+save:params d: model_dict:params ch: 记录模型每一层的输出channel,初始 ch=[3],后边会删除:return nn.Sequential(*layers): 网络的每一层的层结构:return sorted(save): 把所有层结构中from不是-1的值记下,并排序[4,6,10,14,17,20,23]"""# Parse a YOLOv5 model.yaml dictionaryLOGGER.info(f"\n{'':>3}{'from':>18}{'n':>3}{'params':>10} {'module':<40}{'arguments':<30}")# 可以在yaml文件中指定激活函数,如何使用待定anchors, nc, gd, gw, act = d['anchors'], d['nc'], d['depth_multiple'], d['width_multiple'], d.get('activation')if act:Conv.default_act = eval(act) # redefine default activation, i.e. Conv.default_act = nn.SiLU()LOGGER.info(f"{colorstr('activation:')} {act}") # print# 三个检测头的参数:3*(20+5) = 75(VOC)na = (len(anchors[0]) // 2) if isinstance(anchors, list) else anchors # number of anchors = 3no = na * (nc + 5) # number of outputs = anchors * (classes + 5)############################## 开始搭建网络 #################################### layers保存每一层的层结构# save 记录下所有层结构中from不是-1的结构序号# c2:保存当前层输出的channellayers, save, c2 = [], [], ch[-1] # layers, savelist, ch out# from(当前输入来自哪些层) number(当前的层数) module(当前层类别) args(当前层参数)for i, (f, n, m, args) in enumerate(d['backbone'] + d['head']): # from, number, module, args# 得到当前层的真实类名 m = Focus -> <class 'models.common.Focus'>m = eval(m) if isinstance(m, str) else m # eval stringsfor j, a in enumerate(args):# 处理eval函数中出现变量未定义的情况(NameError)# 如果a是一个字符串类型(str),则将其作为表达式进行求值,得到结果。如果a不是字符串类型,则直接使用a的值。# 把结果赋值给args[j],以此实现动态地根据字符串表达式来更新args参数列表with contextlib.suppress(NameError):args[j] = eval(a) if isinstance(a, str) else a # eval strings# n当前层数 gd depth_multiple n = n_ = max(round(n * gd), 1) if n > 1 else n # depth gainif m in {Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, SPPF, DWConv, MixConv2d, Focus, CrossConv,BottleneckCSP, C3, C3TR, C3SPP, C3Ghost, nn.ConvTranspose2d, DWConvTranspose2d, C3x}:# c1当前层的输出channel c2当前层的输出channel ch 记录所有层的输出channelc1, c2 = ch[f], args[0]# 确保c2*gw能够被8整除,如果不能返回一个能够被8整除的最接近于c2*gw的数# 如果不最后一层的output,就控制宽度,最后一层的channel必须是noif c2 != no: # if not outputc2 = make_divisible(c2 * gw, 8)# 在初始args上更新,加入当前层的输入channelargs = [c1, c2, *args[1:]] # [in_channel,out_channel,*args[1:]]if m in {BottleneckCSP, C3, C3TR, C3Ghost, C3x}:# 在第二个位置上插入bottleneck的个数nargs.insert(2, n) # number of repeats n = 1 # 恢复默认值1elif m is nn.BatchNorm2d:# 返回上一层的输出channelargs = [ch[f]]elif m is Concat:# 把f中的输出累加到这层的channelc2 = sum(ch[x] for x in f)# TODO: channel, gw, gdelif m in {Detect, Segment}:# 在args中加入三个Detect层的输出channelargs.append([ch[x] for x in f])if isinstance(args[1], int): # number of anchors # 几乎不执行args[1] = [list(range(args[1] * 2))] * len(f)if m is Segment:args[3] = make_divisible(args[3] * gw, 8)elif m is Contract: # 几乎不使用c2 = ch[f] * args[0] ** 2elif m is Expand: # 几乎不使用c2 = ch[f] // args[0] ** 2else:# Unsample args不变c2 = ch[f]# 调用m(类)根据参数args创建当前层的module并赋值给m_,创建数量为n,m_ = nn.Sequential(*(m(*args) for _ in range(n))) if n > 1 else m(*args) # module# 打印一些基本信息t = str(m)[8:-2].replace('__main__.', '') # module typenp = 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(f'{i:>3}{str(f):>18}{n_:>3}{np:10.0f} {t:<40}{str(args):<30}') # print# 把所有层结构中from不是-1的值记下[6,4,14,10,17,20,23]save.extend(x % i for x in ([f] if isinstance(f, int) else f) if x != -1) # append to savelist# 把当前层结构module加入到layers中layers.append(m_)if i == 0:ch = [] # 去除输入channel# 把当前层输出的channel加入chch.append(c2)return nn.Sequential(*layers), sorted(save)
parse_model在DetectionModel的__init__函数中调用。
# 调用parse_modelself.model, self.save = parse_model(deepcopy(self.yaml), ch=[ch]) # model, savelistself.names = [str(i) for i in range(self.yaml['nc'])] # default namesself.inplace = self.yaml.get('inplace', True)
2、Detect类用于构建最后的detect层,在parse_model函数中调用
# 构建Detect层,把feature map通过一个卷积操作和公式计算到需要的shape,为后边计算loss和NMS做准备。
class Detect(nn.Module):# YOLOv5 Detect head for detection modelsstride = None # strides computed during builddynamic = False # force grid reconstructionexport = False # export modedef __init__(self, nc=80, anchors=(), ch=(), inplace=True): # detection layer"""detection layer相当于yolov3的YOLOLayer层:params nc: number of class:params anchors:传入3个feature map上的所有anchor的大小(P3,P4,P5):params ch:[128,256,512] 3个输出feanture map的chaannel"""super().__init__()self.nc = nc # number of classesself.no = nc + 5 # number of outputs per anchorself.nl = len(anchors) # number of detection layersself.na = len(anchors[0]) // 2 # number of anchors 每个feature map的anchor个数self.grid = [torch.empty(0) for _ in range(self.nl)] # init grid self.anchor_grid = [torch.empty(0) for _ in range(self.nl)] # init anchor grid # 模型中需要保存的参数有两种:一种是需要使用optimizer更新的,一种是不需要被更新的称为buffer# buffer的参数更新在forward,而optim.step只能更新nn.parameter类型的参数# anchor.shape = shape(nl,na,2)self.register_buffer('anchors', torch.tensor(anchors).float().view(self.nl, -1, 2)) # shape(nl,na,2)# 对每个输出feature map都调用一次conv1*1self.m = nn.ModuleList(nn.Conv2d(x, self.no * self.na, 1) for x in ch) # output conv# 默认为True,默认不使用AWS Inferentia加速self.inplace = inplace # use inplace ops (e.g. slice assignment)def forward(self, x):""":return train:一个tensor list存放三个元素[bs, anchor_num, grid_w, grid_h, xywh+classes]以VOC为例,[1, 3, 80, 80, 25] [1, 3, 40, 40, 25] [1, 3, 20, 20, 25]inference:0 preds [1, 19200+4800+1200, 25] = [bs, anchor_num*grid_w*grid_h, xywh+classes]1 train_out :一个tensor list存放三个元素[bs, anchor_num, grid_w, grid_h, xywh+classes][1, 3, 80, 80, 25] [1, 3, 40, 40, 25] [1, 3, 20, 20, 25]"""z = [] # inference outputfor i in range(self.nl): # 对3个feature map分别进行处理x[i] = self.m[i](x[i]) # convbs, _, ny, nx = x[i].shape # x(bs,255,20,20) to x(bs,3,20,20,85)# [bs, 75, 80, 80] to [bs, 3, 25, 80, 80] to [bs, 3, 80, 80, 25]x[i] = x[i].view(bs, self.na, self.no, ny, nx).permute(0, 1, 3, 4, 2).contiguous()if not self.training: # inference# inference 返回的不是归一化后的网格的偏移量,需要加上网格的位置,得到最终的预测坐标,再送入NMS# 构建网络就是为了记录每个grid的网格坐标,方便后边使用# dynamic默认为falseif self.dynamic or self.grid[i].shape[2:4] != x[i].shape[2:4]:self.grid[i], self.anchor_grid[i] = self._make_grid(nx, ny, i)if isinstance(self, Segment): # (boxes + masks)xy, wh, conf, mask = x[i].split((2, 2, self.nc + 1, self.no - self.nc - 5), 4)xy = (xy.sigmoid() * 2 + self.grid[i]) * self.stride[i] # xywh = (wh.sigmoid() * 2) ** 2 * self.anchor_grid[i] # why = torch.cat((xy, wh, conf.sigmoid(), mask), 4)else: # Detect (boxes only)xy, wh, conf = x[i].sigmoid().split((2, 2, self.nc + 1), 4)xy = (xy * 2 + self.grid[i]) * self.stride[i] # xywh = (wh * 2) ** 2 * self.anchor_grid[i] # why = torch.cat((xy, wh, conf), 4)# z是一个teensor list,三个元素,分别是[1,19200,25] [1, 4800, 25], [1, 1200, 25]z.append(y.view(bs, self.na * nx * ny, self.no))return x if self.training else (torch.cat(z, 1), ) if self.export else (torch.cat(z, 1), x)def _make_grid(self, nx=20, ny=20, i=0, torch_1_10=check_version(torch.__version__, '1.10.0')):"""生成网格和锚框的张量,网格形状由ny和nx居多,锚框形状由self.anchors[i]和self.stride[i]决定:params nx: 网格宽度:params ny: 网格高度 :params i: 锚框索引:params torch_1_10:判断torch版本是否大于1.10.0:return grid::return anchor_grid:"""d = self.anchors[i].device # 锚框的devicet = self.anchors[i].dtype # 锚框的数据类型# self.na 每个feature map的anchor的个数shape = 1, self.na, ny, nx, 2 # grid shape# y是长度为ny的张量,x是长度为nx的张量,y和x分别表示网格的纵坐标和横坐标y, x = torch.arange(ny, device=d, dtype=t), torch.arange(nx, device=d, dtype=t)# 如果torch_1_10为True,表示torch版本大于等于1.10.0,代码使用torch.meshgrid函数生成网格坐标,采用'ij'索引方式。# 否则,代码使用torch.meshgrid函数生成网格坐标,采用默认的索引方式yv, xv = torch.meshgrid(y, x, indexing='ij') if torch_1_10 else torch.meshgrid(y, x) # torch>=0.7 compatibility# [ny, nx, 2] to [1, self.na, ny, nx, 2] - 0.5 # 以此得到网格的偏移量grid = torch.stack((xv, yv), 2).expand(shape) - 0.5 # add grid offset, i.e. y = 2.0 * x - 0.5anchor_grid = (self.anchors[i] * self.stride[i]).view((1, self.na, 1, 1, 2)).expand(shape)return grid, anchor_grid
3、DetectionModel类继承自BaseModel类,用于构建模型,使用时定义了一个全局变量model指向这个类,在其他文件中使用时直接调用model。
class BaseModel(nn.Module):# YOLOv5 base modeldef forward(self, x, profile=False, visualize=False):return self._forward_once(x, profile, visualize) # single-scale inference, traindef _forward_once(self, x, profile=False, visualize=False):""":params x: 输入图像:params profile: True 可以做一些性能评估:params visualize: True 可以做一些特征可视化"""# y: 存放着self.save = True 的每一层的输出,因为后边层结构concat要用到# dt:在profile中做性能评估时使用y, dt = [], [] # outputs# 前向推理每一层结构 # m.i = index m.f = from m.type = 类名 m.mp = number of parms for m in self.model:# 4个concat操作和1个detect操作if m.f != -1: # if not from previous layer# concat: m.f=[-1,6] x就有两个元素,一个是上一层的输出,另一个是index层的输出x = y[m.f] if isinstance(m.f, int) else [x if j == -1 else y[j] for j in m.f] # from earlier layers# 打印日志信息,FLOPS、timeif profile:self._profile_one_layer(m, x, dt)x = m(x) # run# 存放着self.save的每一层的输出y.append(x if m.i in self.save else None) # save outputif visualize:feature_visualization(x, m.type, m.i, save_dir=visualize)return xdef _profile_one_layer(self, m, x, dt):c = m == self.model[-1] # 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 fuse(self): # fuse model Conv2d() + BatchNorm2d() layers"""用在detect.py和val.py中fuse model conv2d() + batch norm"""LOGGER.info('Fusing layers... ')for m in self.model.modules():if isinstance(m, (Conv, DWConv)) and hasattr(m, 'bn'):m.conv = fuse_conv_and_bn(m.conv, m.bn) # update convdelattr(m, 'bn') # remove batchnormm.forward = m.forward_fuse # update forwardself.info()return selfdef info(self, verbose=False, img_size=640): # print model informationmodel_info(self, verbose, img_size)def _apply(self, fn):# Apply to(), cpu(), cuda(), half() to model tensors that are not parameters or registered buffersself = super()._apply(fn)m = self.model[-1] # Detect()if isinstance(m, (Detect, Segment)):m.stride = fn(m.stride)m.grid = list(map(fn, m.grid))if isinstance(m.anchor_grid, list):m.anchor_grid = list(map(fn, m.anchor_grid))return selfclass DetectionModel(BaseModel):# YOLOv5 detection modeldef __init__(self, cfg='yolov5s.yaml', ch=3, nc=None, anchors=None): # model, input channels, number of classes"""params cfg: 配置文件params ch: input channelparam nc: number of classesparams anchor: 一般是none"""super().__init__()if isinstance(cfg, dict):self.yaml = cfg # model dictelse: # is *.yamlimport yaml # for torch hubself.yaml_file = Path(cfg).namewith open(cfg, encoding='ascii', errors='ignore') as f:self.yaml = yaml.safe_load(f) # model dict# Define modelch = self.yaml['ch'] = self.yaml.get('ch', ch) # input channelsif nc and nc != self.yaml['nc']:LOGGER.info(f"Overriding model.yaml nc={self.yaml['nc']} with nc={nc}")self.yaml['nc'] = nc # override yaml valueif anchors:LOGGER.info(f'Overriding model.yaml anchors with anchors={anchors}')self.yaml['anchors'] = round(anchors) # override yaml value# 调用parse_model 创建网络模型# self.model 初始化的整个网络结构# self.save 所有层结构中from不等于-1的序号self.model, self.save = parse_model(deepcopy(self.yaml), ch=[ch]) # model, savelist# default class names ['0', '1', '2', '3', '4'.......]self.names = [str(i) for i in range(self.yaml['nc'])] # default namesself.inplace = self.yaml.get('inplace', True)# Build strides, anchors# 获取Detect 模块的stride(相对于输入图像的下采样率)和anchors在当前Detect输出的feature map的尺度m = self.model[-1] # Detect()if isinstance(m, (Detect, Segment)):s = 256 # 2x min stridem.inplace = self.inplaceforward = lambda x: self.forward(x)[0] if isinstance(m, Segment) else self.forward(x)# 计算三个feature map的下采样率m.stride = torch.tensor([s / x.shape[-2] for x in forward(torch.zeros(1, ch, s, s))]) # forward# 检查anchor顺序是否与stride顺序是否一致check_anchor_order(m)# 求出相对于当前feature map的anchor大小 [10,13]/8=[1.25,1.625]m.anchors /= m.stride.view(-1, 1, 1)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):# 是否在测试时使用Test Time Augmentation(TTA)if augment:return self._forward_augment(x) # augmented inference, None# 默认执行前向推理# single-scale inference, train # _forward_once在BaseModel中实现return self._forward_once(x, profile, visualize) # single-scale inference, traindef _forward_augment(self, x):"""Test Time Augmentation(TTA) """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):# scale_img缩放图片尺寸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]) # save# descaleyi = 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 _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 _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 _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:5 + m.nc] += math.log(0.6 / (m.nc - 0.99999)) if cf is None else torch.log(cf / cf.sum()) # clsmi.bias = torch.nn.Parameter(b.view(-1), requires_grad=True)
使用语句
Model = DetectionModel # retain YOLOv5 'Model' class for backwards compatibility
相关文章:

YOLOv5代码解析——yolo.py
yolo.py的主要功能是构建模型。 1、最主要的函数是parse_model,用于解析yaml文件,并根据解析的结果搭建网络。这个函数的注释如下: def parse_model(d, ch): # model_dict, input_channels(3)"""解析模型文件,并…...

4种feature classification在代码的实现上是怎么样的?Linear / MLP / CNN / Attention-Based Heads
具体的分类效果可以看:【Arxiv 2023】Diffusion Models Beat GANs on Image Classification 1、线性分类器 (Linear, A) 使用一个简单的线性层,通常与一个激活函数结合使用。 import torch.nn as nnclass LinearClassifier(nn.Module):def __init__(se…...

最新Unity DOTS Physics物理引擎碰撞事件处理
最近DOTS发布了正式的版本,同时基于DOTS的理念实现了一套高性能的物理引擎,今天我们给大家分享和介绍一下这个物理引擎的碰撞事件处理以及核心相关概念。 Unity.Physics物理引擎的主要流程与Pipeline Unity.Physics物理引擎做仿真迭代计算的时候主要通过以下步骤来…...

springboot集成websocket全全全!!!
一、界面展示 二、前置了解 1.什么是websocket WebSocket是一种在单个TCP连接上进行全双工通信的持久化协议。 全双工协议就是客户端可以给我们服务器发数据 服务器也可以主动给客户端发数据。 2.为什么有了http协议 还要websocket 协议 http协议是一种无状态,非…...

SpringMVC:整合 SSM 中篇
文章目录 SpringMVC - 04整合 SSM 中篇一、优化二、总结三、说明注意: SpringMVC - 04 整合 SSM 中篇 一、优化 在 spring-dao.xml 中配置 dao 接口扫描,可以动态地实现 dao 接口注入到 Spring 容器中。 优化前:手动创建 SqlSessionTempl…...

oracle即时客户端(Instant Client)安装与配置
之前的文章记录了oracle客户端和服务端的下载与安装,内容参见: 在Windows中安装Oracle_windows安装oracle 如果不想安装oracle客户端(或者是电脑因为某些原因无法安装oracle客户端),还想能够连接oracle远程服务&#…...

POP3协议详解
基本介绍 POP3是一种用于从邮件服务器获取电子邮件的协议。它允许邮件客户端连接到邮件服务器,检索服务器上存储的邮件,并将邮件下载到客户端设备上。POP3的工作原理如下: 连接和身份验证: 邮件客户端通过TCP/IP连接到邮件服务器…...

电子病历编辑器源码,提供电子病历在线制作、管理和使用的一体化电子病历解决方案
概述: 电子病历是指医务人员在医疗活动过程中,使用医疗机构信息系统生成的文字、符号、图表、图形、数据、影像等数字化信息,并能实现存储、管理、传输和重现的医疗记录,是病历的一种记录形式。 医院通过电子病历以电子化方式记录患者就诊的信息,包括&…...

WT2605C高品质音频蓝牙语音芯片:外接功放实现双声道DAC输出的优势
在音频处理领域,双声道DAC输出能够提供更为清晰、逼真的音效,增强用户的听觉体验。针对这一需求,唯创知音的WT2605C高品质音频蓝牙语音芯片,通过外接功放实现双声道DAC输出,展现出独特的应用优势。 一、高品质音频处理…...

IntelliJ IDEA 2023.3 最新版如何如何配置?IntelliJ IDEA 2023.3 最新版试用方法
🌷🍁 博主猫头虎(🐅🐾)带您 Go to New World✨🍁 🦄 博客首页——🐅🐾猫头虎的博客🎐 🐳 《面试题大全专栏》 🦕 文章图文…...

如何查看内存卡使用记录-查看的设备有:U盘、移动硬盘、MP3、SD卡等-供大家学习研究参考
主要功能 USB Viewer(USB移动存储设备使用记录查看器)可用于查看本机的USB移动存储设备使用记录。可查看的设备有:U盘、移动硬盘、MP3、SD卡……等。 可用于兵器、航空、航天、政府、军队等对保密要求较高的单位,可在计算机保…...

九、W5100S/W5500+RP2040之MicroPython开发<HTTPOneNET示例>
文章目录 1. 前言2. 平台操作流程2.1 创建设备2.2 创建数据流模板 3. WIZnet以太网芯片4. 示例讲解以及使用4.1 程序流程图4.2 测试准备4.3 连接方式4.4 相关代码4.5 烧录验证 5. 注意事项6. 相关链接 1. 前言 在这个智能硬件和物联网时代,MicroPython和树莓派PICO正…...

在 Laravel 中,清空缓存大全
在 Laravel 中,清空缓存通常涉及到清除应用程序中的缓存文件和数据库查询缓存。以下是一些常用的清空缓存方法: 1. 清除路由缓存: Laravel 的路由缓存可以提高应用程序的性能,但在开发过程中,你可能需要频繁地更改路…...

【贪心】单源最短路径Python实现
文章目录 [toc]问题描述Dijkstra算法Dijkstra算法的正确性贪心选择性质最优子结构性质 Dijkstra算法应用示例时间复杂性Python实现 个人主页:丷从心 系列专栏:贪心算法 问题描述 给定一个带权有向图 G ( V , E ) G (V , E) G(V,E),其中每…...

Spark Shell的简单使用
简介 Spark shell是一个特别适合快速开发Spark原型程序的工具,可以帮助我们熟悉Scala语言。即使你对Scala不熟悉,仍然可以使用这个工具。Spark shell使得用户可以和Spark集群交互,提交查询,这便于调试,也便于初学者使用…...

Springsecurty【2】认证连接MySQL
1.前期准备 基于Spring Initializr创建SpringBoot项目(基于SpringBoot 2.7.12版本),实现与MyBatisPlus的项目整合。分别导入:CodeGenerator和MyBatisPlusConfig。 CodeGenerator:用于MybatisPlus代码生成;…...

.Net 访问电子邮箱-LumiSoft.Net,好用
序言: 网上找了很多关于.Net如何访问电子邮箱的方法,但是大多数都达不到想要的需求,只有一些 收发邮件。因此 花了很大功夫去看 LumiSoft.Net.dll 的源码,总算做出自己想要的结果了,果然学习诗人进步。 介绍ÿ…...

谷粒商城-商品服务-新增商品功能开发(商品图片无法展示问题没有解决)
在网关配置路由 - id: member_routeuri: lb://gulimemberpredicates:- Path/api/gulimember/**filters:- RewritePath/api/(?<segment>.*),/$\{segment}并将所有逆向生成的工程调式出来 获取分类关联的品牌 例如:手机(分类)-> 品…...

Open3D 点云数据处理基础(Python版)
Open3D 点云数据处理基础(Python版) 文章目录 1 概述 2 安装 2.1 PyCharm 与 Python 安装 2.3 Anaconda 安装 2.4 Open3D 0.13.0 安装 2.5 新建一个 Python 项目 3 点云读写 4 点云可视化 2.1 可视化单个点云 2.2 同一窗口可视化多个点云 2.3…...

使用vue-qr,报错in ./node_modules/vue-qr/dist/vue-qr.js
找到node_modules—>vue-qr/dist/vue-qr.js文件,搜…e,将…去掉,然后重新运行项目。...

百川2大模型微调问题解决
之前用https://github.com/FlagAlpha/Llama2-Chinese微调过几个模型,总体来说llama2的生态还是比较好的,过程很顺利。微调百川2就没那么顺利了,所以简单做个记录 1. 数据准备,我的数据是单轮对话,之前微调llama2已经按…...

MySQL的事务-原子性
MySQL的事务处理具有ACID的特性,即原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。 1. 原子性指的是事务中所有操作都是原子性的,要…...

D3839|完全背包
完全背包: 首先01背包的滚动数组中的解法是内嵌的循环是从大到小遍历,为了保证每个物品仅被添加一次。 for(int i 0; i < weight.size(); i) { // 遍历物品for(int j bagWeight; j > weight[i]; j--) { // 遍历背包容量dp[j] max(dp[j], dp[j…...

Java之Synchronized与锁升级
Synchronized与锁升级 一、概述 在多线程并发编程中 synchronized 一直是元老级角色,很多人都会称呼它为重量级锁。但是,随着 Java SE 1.6 对 synchronized 进行了各种优化之后,有些情况下它就并不那么重了。 本文详细介绍 Java SE 1.6 中为…...

kitex出现:open conf/test/conf.yaml: no such file or directory
open conf/test/conf.yaml: no such file or directory https://github.com/cloudwego/cwgo/issues/120 https://github.com/cloudwego/cwgo/issues/29 在使用Kitex生成的代码中,单元测试时回报错,如标题所示。出现该错的原因是,biz/servic…...

sql server多表查询
查询目标 现在有学生表和学生选课信息表,stu和stuSelect,stu中包含学生用户名、名字,stuSelect表中包含学生用户名,所选课程名 学生表: nameusername李明Li Ming李华Li Hua 学生选课表: usernameCourse…...

如何利用PPT绘图并导出清晰图片
在写论文的过程中,免不了需要绘图,但是visio等软件绘图没有在ppt上绘图比较熟练,尤其流程图结构图. 但是ppt导出的图片也不够清晰,默认分辨率是96dpi,而杂志投稿一般要求至300dpi。解决办法如下: 1.打开注…...

1.倒排索引 2.逻辑斯提回归算法
1.倒排索引 https://help.aliyun.com/zh/open-search/retrieval-engine-edition/introduction-to-inverted-indexes 倒排索引(Inverted Index)是一种数据结构,用于快速查找包含某个特定词或词语的文档。它主要用于全文搜索引擎等应用&#…...

Kafka消费者组
消费者总体工作流程 Consumer Group(CG):消费者组,由多个consumer组成。形成一个消费者组的条件,是所有消费者的groupid相同。 • 消费者组内每个消费者负责消费不同分区的数据,一个分区只能由一个组内消费…...

四. 基于环视Camera的BEV感知算法-BEVDepth
目录 前言0. 简述1. 算法动机&开创性思路2. 主体结构3. 损失函数4. 性能对比总结下载链接参考 前言 自动驾驶之心推出的《国内首个BVE感知全栈系列学习教程》,链接。记录下个人学习笔记,仅供自己参考 本次课程我们来学习下课程第四章——基于环视Cam…...