当前位置: 首页 > news >正文

【YOLOv8】YOLOv8改进系列(10)----替换主干网络之UniRepLKNet

主页:HABUO🍁主页:HABUO

🍁YOLOv8入门+改进专栏🍁

🍁如果再也不能见到你,祝你早安,午安,晚安🍁


  【YOLOv8改进系列】: 

 

YOLOv8改进系列(2)----替换主干网络之FasterNet

YOLOv8改进系列(3)----替换主干网络之ConvNeXt V2

YOLOv8改进系列(4)----替换C2f之FasterNet中的FasterBlock替换C2f中的Bottleneck 

YOLOv8改进系列(5)----替换主干网络之EfficientFormerV2 

YOLOv8改进系列(6)----替换主干网络之VanillaNet

YOLOv8改进系列(7)----替换主干网络之LSKNet

YOLOv8改进系列(8)----替换主干网络之Swin Transformer 

YOLOv8改进系列(9)----替换主干网络之RepViT


目录

💯一、UniRepLKNet介绍

1. 简介

2. UniRepLKNet 架构设计

背景知识

研究方法

Dilated Reparam Block

3. 实验与结果

4. 关键结论

💯二、具体添加方法 

第①步:创建UniRepLKNet.py

第②步:修改task.py 

(1)引入创建的UniRepLKNet文件 

(2)修改_predict_once函数 

(3)修改parse_model函数

第③步:yolov8.yaml文件修改   

第④步:验证是否加入成功  


💯一、UniRepLKNet介绍

  • 论文题目:《UniRepLKNet: A Universal Perception Large-Kernel ConvNet for Audio, Video, Point Cloud, Time-Series and Image Recognition》
  • 论文地址:https://arxiv.org/pdf/2311.15599

1. 简介

论文介绍了一种名为 UniRepLKNet 的新型大核卷积神经网络(ConvNet),它在图像识别、音频、视频、点云、时间序列等多种模态的任务上表现出色,展示了卷积神经网络在多模态领域的巨大潜力。

2. UniRepLKNet 架构设计

背景知识

  • 大核卷积神经网络(ConvNet):近年来,大核卷积神经网络因其在图像识别等任务中的出色表现而受到广泛关注。然而,现有的大核 ConvNet 架构大多沿用传统 ConvNet 或 Transformer 的设计原则,针对大核 ConvNet 的架构设计仍待深入研究。

  • 多模态任务:Transformer 在多个模态的任务中表现出色,但卷积网络在非视觉领域的表现尚未充分挖掘。作者试图探索 ConvNet 在多模态任务中的潜力,尤其是那些传统上不擅长的领域,如音频和时间序列。

研究方法

  • 核心理念:利用大核的特性(能够“看宽而不必加深”)来设计架构,通过解耦大核卷积层的三种效果(扩大感受野、增加空间模式的抽象层次、提升模型的泛化能力),实现更高效的特征提取和更高的性能。

  • 架构指南

    1. 使用高效的结构(如 SE 块)增加模型深度。

    2. 使用提出的 Dilated Reparam Block 重新参数化大核卷积层,以提升性能且不增加推理成本。

    3. 根据下游任务决定核大小,通常在中高层使用大核。

    4. 在扩展模型深度时,添加的块应使用小核。

Dilated Reparam Block

  • 核心思想:通过并行的小核卷积层(包括扩张卷积)来增强大核卷积层,这些小核卷积层在训练时捕捉小尺度和稀疏模式,在推理时可以等效地合并到大核卷积层中,从而不增加推理成本。

  • 等效转换:通过转置卷积操作,将扩张卷积层的权重转换为非扩张的稀疏大核卷积层的权重,从而在推理时将整个块等效为一个单一的大核卷积层。


3. 实验与结果

  • 图像识别

    • 在 ImageNet 数据集上,UniRepLKNet 实现了 88.0% 的准确率。

    • 在 ADE20K 语义分割任务上,mIoU 达到 55.6%。

    • 在 COCO 目标检测任务上,box AP 达到 56.4%。

    • 与现有的大核 ConvNet(如 RepLKNet、SLaK)和强大的架构(如 ConvNeXt V2、FastViT、Swin V2)相比,UniRepLKNet 在准确性和效率上均表现出色。

  • 多模态任务

    • 时间序列预测:在大规模时间序列预测任务中,UniRepLKNet 击败了最新的 Transformer 定制模型,实现了最低的预测误差。

    • 音频识别:在 Speech Commands V2 数据集上,UniRepLKNet 达到了 98.5% 的准确率,且无需预训练。

    • 点云分析:在 ModelNet-40 数据集上,UniRepLKNet 实现了 93.2% 的总体准确率,超越了现有的 ConvNet 专业模型。

    • 视频识别:在 Kinetics-400 数据集上,UniRepLKNet 达到了 54.8% 的准确率,尽管与最先进模型仍有差距,但作为通用模型且无需预训练,表现已相当出色。


4. 关键结论

  • 大核的重要性:大核是解锁 ConvNet 在多模态任务中卓越性能的关键,尤其是在那些传统上不擅长的领域。

  • 架构设计的有效性:通过提出的架构指南和 Dilated Reparam Block,UniRepLKNet 在图像识别和多模态任务中均取得了领先性能,证明了其架构设计的有效性。

  • 通用感知能力:UniRepLKNet 展示了卷积网络在多模态任务中的通用感知能力,为未来在更多领域的应用提供了新的可能性。


💯二、具体添加方法 

第①步:创建UniRepLKNet.py

创建完成后,将下面代码直接复制粘贴进去:

import torch
import torch.nn as nn
import torch.nn.functional as F
from timm.layers import trunc_normal_, DropPath, to_2tuple
from functools import partial
import torch.utils.checkpoint as checkpoint
import numpy as np__all__ = ['unireplknet_a', 'unireplknet_f', 'unireplknet_p', 'unireplknet_n', 'unireplknet_t', 'unireplknet_s', 'unireplknet_b', 'unireplknet_l', 'unireplknet_xl']class GRNwithNHWC(nn.Module):""" GRN (Global Response Normalization) layerOriginally proposed in ConvNeXt V2 (https://arxiv.org/abs/2301.00808)This implementation is more efficient than the original (https://github.com/facebookresearch/ConvNeXt-V2)We assume the inputs to this layer are (N, H, W, C)"""def __init__(self, dim, use_bias=True):super().__init__()self.use_bias = use_biasself.gamma = nn.Parameter(torch.zeros(1, 1, 1, dim))if self.use_bias:self.beta = nn.Parameter(torch.zeros(1, 1, 1, dim))def forward(self, x):Gx = torch.norm(x, p=2, dim=(1, 2), keepdim=True)Nx = Gx / (Gx.mean(dim=-1, keepdim=True) + 1e-6)if self.use_bias:return (self.gamma * Nx + 1) * x + self.betaelse:return (self.gamma * Nx + 1) * xclass NCHWtoNHWC(nn.Module):def __init__(self):super().__init__()def forward(self, x):return x.permute(0, 2, 3, 1)class NHWCtoNCHW(nn.Module):def __init__(self):super().__init__()def forward(self, x):return x.permute(0, 3, 1, 2)#================== This function decides which conv implementation (the native or iGEMM) to use
#   Note that iGEMM large-kernel conv impl will be used if
#       -   you attempt to do so (attempt_to_use_large_impl=True), and
#       -   it has been installed (follow https://github.com/AILab-CVC/UniRepLKNet), and
#       -   the conv layer is depth-wise, stride = 1, non-dilated, kernel_size > 5, and padding == kernel_size // 2
def get_conv2d(in_channels, out_channels, kernel_size, stride, padding, dilation, groups, bias,attempt_use_lk_impl=True):kernel_size = to_2tuple(kernel_size)if padding is None:padding = (kernel_size[0] // 2, kernel_size[1] // 2)else:padding = to_2tuple(padding)need_large_impl = kernel_size[0] == kernel_size[1] and kernel_size[0] > 5 and padding == (kernel_size[0] // 2, kernel_size[1] // 2)# if attempt_use_lk_impl and need_large_impl:#     print('---------------- trying to import iGEMM implementation for large-kernel conv')#     try:#         from depthwise_conv2d_implicit_gemm import DepthWiseConv2dImplicitGEMM#         print('---------------- found iGEMM implementation ')#     except:#         DepthWiseConv2dImplicitGEMM = None#         print('---------------- found no iGEMM. use original conv. follow https://github.com/AILab-CVC/UniRepLKNet to install it.')#     if DepthWiseConv2dImplicitGEMM is not None and need_large_impl and in_channels == out_channels \#             and out_channels == groups and stride == 1 and dilation == 1:#         print(f'===== iGEMM Efficient Conv Impl, channels {in_channels}, kernel size {kernel_size} =====')#         return DepthWiseConv2dImplicitGEMM(in_channels, kernel_size, bias=bias)return nn.Conv2d(in_channels=in_channels, out_channels=out_channels, kernel_size=kernel_size, stride=stride,padding=padding, dilation=dilation, groups=groups, bias=bias)def get_bn(dim, use_sync_bn=False):if use_sync_bn:return nn.SyncBatchNorm(dim)else:return nn.BatchNorm2d(dim)class SEBlock(nn.Module):"""Squeeze-and-Excitation Block proposed in SENet (https://arxiv.org/abs/1709.01507)We assume the inputs to this layer are (N, C, H, W)"""def __init__(self, input_channels, internal_neurons):super(SEBlock, self).__init__()self.down = nn.Conv2d(in_channels=input_channels, out_channels=internal_neurons,kernel_size=1, stride=1, bias=True)self.up = nn.Conv2d(in_channels=internal_neurons, out_channels=input_channels,kernel_size=1, stride=1, bias=True)self.input_channels = input_channelsself.nonlinear = nn.ReLU(inplace=True)def forward(self, inputs):x = F.adaptive_avg_pool2d(inputs, output_size=(1, 1))x = self.down(x)x = self.nonlinear(x)x = self.up(x)x = F.sigmoid(x)return inputs * x.view(-1, self.input_channels, 1, 1)def fuse_bn(conv, bn):conv_bias = 0 if conv.bias is None else conv.biasstd = (bn.running_var + bn.eps).sqrt()return conv.weight * (bn.weight / std).reshape(-1, 1, 1, 1), bn.bias + (conv_bias - bn.running_mean) * bn.weight / stddef convert_dilated_to_nondilated(kernel, dilate_rate):identity_kernel = torch.ones((1, 1, 1, 1)).to(kernel.device)if kernel.size(1) == 1:#   This is a DW kerneldilated = F.conv_transpose2d(kernel, identity_kernel, stride=dilate_rate)return dilatedelse:#   This is a dense or group-wise (but not DW) kernelslices = []for i in range(kernel.size(1)):dilated = F.conv_transpose2d(kernel[:,i:i+1,:,:], identity_kernel, stride=dilate_rate)slices.append(dilated)return torch.cat(slices, dim=1)def merge_dilated_into_large_kernel(large_kernel, dilated_kernel, dilated_r):large_k = large_kernel.size(2)dilated_k = dilated_kernel.size(2)equivalent_kernel_size = dilated_r * (dilated_k - 1) + 1equivalent_kernel = convert_dilated_to_nondilated(dilated_kernel, dilated_r)rows_to_pad = large_k // 2 - equivalent_kernel_size // 2merged_kernel = large_kernel + F.pad(equivalent_kernel, [rows_to_pad] * 4)return merged_kernelclass DilatedReparamBlock(nn.Module):"""Dilated Reparam Block proposed in UniRepLKNet (https://github.com/AILab-CVC/UniRepLKNet)We assume the inputs to this block are (N, C, H, W)"""def __init__(self, channels, kernel_size, deploy, use_sync_bn=False, attempt_use_lk_impl=True):super().__init__()self.lk_origin = get_conv2d(channels, channels, kernel_size, stride=1,padding=kernel_size//2, dilation=1, groups=channels, bias=deploy,attempt_use_lk_impl=attempt_use_lk_impl)self.attempt_use_lk_impl = attempt_use_lk_impl#   Default settings. We did not tune them carefully. Different settings may work better.if kernel_size == 17:self.kernel_sizes = [5, 9, 3, 3, 3]self.dilates = [1, 2, 4, 5, 7]elif kernel_size == 15:self.kernel_sizes = [5, 7, 3, 3, 3]self.dilates = [1, 2, 3, 5, 7]elif kernel_size == 13:self.kernel_sizes = [5, 7, 3, 3, 3]self.dilates = [1, 2, 3, 4, 5]elif kernel_size == 11:self.kernel_sizes = [5, 5, 3, 3, 3]self.dilates = [1, 2, 3, 4, 5]elif kernel_size == 9:self.kernel_sizes = [5, 5, 3, 3]self.dilates = [1, 2, 3, 4]elif kernel_size == 7:self.kernel_sizes = [5, 3, 3]self.dilates = [1, 2, 3]elif kernel_size == 5:self.kernel_sizes = [3, 3]self.dilates = [1, 2]else:raise ValueError('Dilated Reparam Block requires kernel_size >= 5')if not deploy:self.origin_bn = get_bn(channels, use_sync_bn)for k, r in zip(self.kernel_sizes, self.dilates):self.__setattr__('dil_conv_k{}_{}'.format(k, r),nn.Conv2d(in_channels=channels, out_channels=channels, kernel_size=k, stride=1,padding=(r * (k - 1) + 1) // 2, dilation=r, groups=channels,bias=False))self.__setattr__('dil_bn_k{}_{}'.format(k, r), get_bn(channels, use_sync_bn=use_sync_bn))def forward(self, x):if not hasattr(self, 'origin_bn'):      # deploy modereturn self.lk_origin(x)out = self.origin_bn(self.lk_origin(x))for k, r in zip(self.kernel_sizes, self.dilates):conv = self.__getattr__('dil_conv_k{}_{}'.format(k, r))bn = self.__getattr__('dil_bn_k{}_{}'.format(k, r))out = out + bn(conv(x))return outdef merge_dilated_branches(self):if hasattr(self, 'origin_bn'):origin_k, origin_b = fuse_bn(self.lk_origin, self.origin_bn)for k, r in zip(self.kernel_sizes, self.dilates):conv = self.__getattr__('dil_conv_k{}_{}'.format(k, r))bn = self.__getattr__('dil_bn_k{}_{}'.format(k, r))branch_k, branch_b = fuse_bn(conv, bn)origin_k = merge_dilated_into_large_kernel(origin_k, branch_k, r)origin_b += branch_bmerged_conv = get_conv2d(origin_k.size(0), origin_k.size(0), origin_k.size(2), stride=1,padding=origin_k.size(2)//2, dilation=1, groups=origin_k.size(0), bias=True,attempt_use_lk_impl=self.attempt_use_lk_impl)merged_conv.weight.data = origin_kmerged_conv.bias.data = origin_bself.lk_origin = merged_convself.__delattr__('origin_bn')for k, r in zip(self.kernel_sizes, self.dilates):self.__delattr__('dil_conv_k{}_{}'.format(k, r))self.__delattr__('dil_bn_k{}_{}'.format(k, r))class UniRepLKNetBlock(nn.Module):def __init__(self,dim,kernel_size,drop_path=0.,layer_scale_init_value=1e-6,deploy=False,attempt_use_lk_impl=True,with_cp=False,use_sync_bn=False,ffn_factor=4):super().__init__()self.with_cp = with_cp# if deploy:#     print('------------------------------- Note: deploy mode')# if self.with_cp:#     print('****** note with_cp = True, reduce memory consumption but may slow down training ******')self.need_contiguous = (not deploy) or kernel_size >= 7if kernel_size == 0:self.dwconv = nn.Identity()self.norm = nn.Identity()elif deploy:self.dwconv = get_conv2d(dim, dim, kernel_size=kernel_size, stride=1, padding=kernel_size // 2,dilation=1, groups=dim, bias=True,attempt_use_lk_impl=attempt_use_lk_impl)self.norm = nn.Identity()elif kernel_size >= 7:self.dwconv = DilatedReparamBlock(dim, kernel_size, deploy=deploy,use_sync_bn=use_sync_bn,attempt_use_lk_impl=attempt_use_lk_impl)self.norm = get_bn(dim, use_sync_bn=use_sync_bn)elif kernel_size == 1:self.dwconv = nn.Conv2d(dim, dim, kernel_size=kernel_size, stride=1, padding=kernel_size // 2,dilation=1, groups=1, bias=deploy)self.norm = get_bn(dim, use_sync_bn=use_sync_bn)else:assert kernel_size in [3, 5]self.dwconv = nn.Conv2d(dim, dim, kernel_size=kernel_size, stride=1, padding=kernel_size // 2,dilation=1, groups=dim, bias=deploy)self.norm = get_bn(dim, use_sync_bn=use_sync_bn)self.se = SEBlock(dim, dim // 4)ffn_dim = int(ffn_factor * dim)self.pwconv1 = nn.Sequential(NCHWtoNHWC(),nn.Linear(dim, ffn_dim))self.act = nn.Sequential(nn.GELU(),GRNwithNHWC(ffn_dim, use_bias=not deploy))if deploy:self.pwconv2 = nn.Sequential(nn.Linear(ffn_dim, dim),NHWCtoNCHW())else:self.pwconv2 = nn.Sequential(nn.Linear(ffn_dim, dim, bias=False),NHWCtoNCHW(),get_bn(dim, use_sync_bn=use_sync_bn))self.gamma = nn.Parameter(layer_scale_init_value * torch.ones(dim),requires_grad=True) if (not deploy) and layer_scale_init_value is not None \and layer_scale_init_value > 0 else Noneself.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()def forward(self, inputs):def _f(x):if self.need_contiguous:x = x.contiguous()y = self.se(self.norm(self.dwconv(x)))y = self.pwconv2(self.act(self.pwconv1(y)))if self.gamma is not None:y = self.gamma.view(1, -1, 1, 1) * yreturn self.drop_path(y) + xif self.with_cp and inputs.requires_grad:return checkpoint.checkpoint(_f, inputs)else:return _f(inputs)def reparameterize(self):if hasattr(self.dwconv, 'merge_dilated_branches'):self.dwconv.merge_dilated_branches()if hasattr(self.norm, 'running_var') and hasattr(self.dwconv, 'lk_origin'):std = (self.norm.running_var + self.norm.eps).sqrt()self.dwconv.lk_origin.weight.data *= (self.norm.weight / std).view(-1, 1, 1, 1)self.dwconv.lk_origin.bias.data = self.norm.bias + (self.dwconv.lk_origin.bias - self.norm.running_mean) * self.norm.weight / stdself.norm = nn.Identity()if self.gamma is not None:final_scale = self.gamma.dataself.gamma = Noneelse:final_scale = 1if self.act[1].use_bias and len(self.pwconv2) == 3:grn_bias = self.act[1].beta.dataself.act[1].__delattr__('beta')self.act[1].use_bias = Falselinear = self.pwconv2[0]grn_bias_projected_bias = (linear.weight.data @ grn_bias.view(-1, 1)).squeeze()bn = self.pwconv2[2]std = (bn.running_var + bn.eps).sqrt()new_linear = nn.Linear(linear.in_features, linear.out_features, bias=True)new_linear.weight.data = linear.weight * (bn.weight / std * final_scale).view(-1, 1)linear_bias = 0 if linear.bias is None else linear.bias.datalinear_bias += grn_bias_projected_biasnew_linear.bias.data = (bn.bias + (linear_bias - bn.running_mean) * bn.weight / std) * final_scaleself.pwconv2 = nn.Sequential(new_linear, self.pwconv2[1])default_UniRepLKNet_A_F_P_kernel_sizes = ((3, 3),(13, 13),(13, 13, 13, 13, 13, 13),(13, 13))
default_UniRepLKNet_N_kernel_sizes = ((3, 3),(13, 13),(13, 13, 13, 13, 13, 13, 13, 13),(13, 13))
default_UniRepLKNet_T_kernel_sizes = ((3, 3, 3),(13, 13, 13),(13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3),(13, 13, 13))
default_UniRepLKNet_S_B_L_XL_kernel_sizes = ((3, 3, 3),(13, 13, 13),(13, 3, 3, 13, 3, 3, 13, 3, 3, 13, 3, 3, 13, 3, 3, 13, 3, 3, 13, 3, 3, 13, 3, 3, 13, 3, 3),(13, 13, 13))
UniRepLKNet_A_F_P_depths = (2, 2, 6, 2)
UniRepLKNet_N_depths = (2, 2, 8, 2)
UniRepLKNet_T_depths = (3, 3, 18, 3)
UniRepLKNet_S_B_L_XL_depths = (3, 3, 27, 3)default_depths_to_kernel_sizes = {UniRepLKNet_A_F_P_depths: default_UniRepLKNet_A_F_P_kernel_sizes,UniRepLKNet_N_depths: default_UniRepLKNet_N_kernel_sizes,UniRepLKNet_T_depths: default_UniRepLKNet_T_kernel_sizes,UniRepLKNet_S_B_L_XL_depths: default_UniRepLKNet_S_B_L_XL_kernel_sizes
}class UniRepLKNet(nn.Module):r""" UniRepLKNetA PyTorch impl of UniRepLKNetArgs:in_chans (int): Number of input image channels. Default: 3num_classes (int): Number of classes for classification head. Default: 1000depths (tuple(int)): Number of blocks at each stage. Default: (3, 3, 27, 3)dims (int): Feature dimension at each stage. Default: (96, 192, 384, 768)drop_path_rate (float): Stochastic depth rate. Default: 0.layer_scale_init_value (float): Init value for Layer Scale. Default: 1e-6.head_init_scale (float): Init scaling value for classifier weights and biases. Default: 1.kernel_sizes (tuple(tuple(int))): Kernel size for each block. None means using the default settings. Default: None.deploy (bool): deploy = True means using the inference structure. Default: Falsewith_cp (bool): with_cp = True means using torch.utils.checkpoint to save GPU memory. Default: Falseinit_cfg (dict): weights to load. The easiest way to use UniRepLKNet with for OpenMMLab family. Default: Noneattempt_use_lk_impl (bool): try to load the efficient iGEMM large-kernel impl. Setting it to False disabling the iGEMM impl. Default: Trueuse_sync_bn (bool): use_sync_bn = True means using sync BN. Use it if your batch size is small. Default: False"""def __init__(self,in_chans=3,num_classes=1000,depths=(3, 3, 27, 3),dims=(96, 192, 384, 768),drop_path_rate=0.,layer_scale_init_value=1e-6,head_init_scale=1.,kernel_sizes=None,deploy=False,with_cp=False,init_cfg=None,attempt_use_lk_impl=True,use_sync_bn=False,**kwargs):super().__init__()depths = tuple(depths)if kernel_sizes is None:if depths in default_depths_to_kernel_sizes:# print('=========== use default kernel size ')kernel_sizes = default_depths_to_kernel_sizes[depths]else:raise ValueError('no default kernel size settings for the given depths, ''please specify kernel sizes for each block, e.g., ''((3, 3), (13, 13), (13, 13, 13, 13, 13, 13), (13, 13))')# print(kernel_sizes)for i in range(4):assert len(kernel_sizes[i]) == depths[i], 'kernel sizes do not match the depths'self.with_cp = with_cpdp_rates = [x.item() for x in torch.linspace(0, drop_path_rate, sum(depths))]# print('=========== drop path rates: ', dp_rates)self.downsample_layers = nn.ModuleList()self.downsample_layers.append(nn.Sequential(nn.Conv2d(in_chans, dims[0] // 2, kernel_size=3, stride=2, padding=1),LayerNorm(dims[0] // 2, eps=1e-6, data_format="channels_first"),nn.GELU(),nn.Conv2d(dims[0] // 2, dims[0], kernel_size=3, stride=2, padding=1),LayerNorm(dims[0], eps=1e-6, data_format="channels_first")))for i in range(3):self.downsample_layers.append(nn.Sequential(nn.Conv2d(dims[i], dims[i + 1], kernel_size=3, stride=2, padding=1),LayerNorm(dims[i + 1], eps=1e-6, data_format="channels_first")))self.stages = nn.ModuleList()cur = 0for i in range(4):main_stage = nn.Sequential(*[UniRepLKNetBlock(dim=dims[i], kernel_size=kernel_sizes[i][j], drop_path=dp_rates[cur + j],layer_scale_init_value=layer_scale_init_value, deploy=deploy,attempt_use_lk_impl=attempt_use_lk_impl,with_cp=with_cp, use_sync_bn=use_sync_bn) for j inrange(depths[i])])self.stages.append(main_stage)cur += depths[i]self.output_mode = 'features'norm_layer = partial(LayerNorm, eps=1e-6, data_format="channels_first")for i_layer in range(4):layer = norm_layer(dims[i_layer])layer_name = f'norm{i_layer}'self.add_module(layer_name, layer)self.channel = [i.size(1) for i in self.forward(torch.randn(1, 3, 640, 640))]self.apply(self._init_weights)def _init_weights(self, m):if isinstance(m, (nn.Conv2d, nn.Linear)):trunc_normal_(m.weight, std=.02)if hasattr(m, 'bias') and m.bias is not None:nn.init.constant_(m.bias, 0)def forward(self, x):if self.output_mode == 'logits':for stage_idx in range(4):x = self.downsample_layers[stage_idx](x)x = self.stages[stage_idx](x)x = self.norm(x.mean([-2, -1]))x = self.head(x)return xelif self.output_mode == 'features':outs = []for stage_idx in range(4):x = self.downsample_layers[stage_idx](x)x = self.stages[stage_idx](x)outs.append(self.__getattr__(f'norm{stage_idx}')(x))return outselse:raise ValueError('Defined new output mode?')def switch_to_deploy(self):for m in self.modules():if hasattr(m, 'reparameterize'):m.reparameterize()class LayerNorm(nn.Module):r""" LayerNorm implementation used in ConvNeXtLayerNorm that supports two data formats: channels_last (default) or channels_first.The ordering of the dimensions in the inputs. channels_last corresponds to inputs withshape (batch_size, height, width, channels) while channels_first corresponds to inputswith shape (batch_size, channels, height, width)."""def __init__(self, normalized_shape, eps=1e-6, data_format="channels_last", reshape_last_to_first=False):super().__init__()self.weight = nn.Parameter(torch.ones(normalized_shape))self.bias = nn.Parameter(torch.zeros(normalized_shape))self.eps = epsself.data_format = data_formatif self.data_format not in ["channels_last", "channels_first"]:raise NotImplementedErrorself.normalized_shape = (normalized_shape,)self.reshape_last_to_first = reshape_last_to_firstdef forward(self, x):if self.data_format == "channels_last":return F.layer_norm(x, self.normalized_shape, self.weight, self.bias, self.eps)elif self.data_format == "channels_first":u = x.mean(1, keepdim=True)s = (x - u).pow(2).mean(1, keepdim=True)x = (x - u) / torch.sqrt(s + self.eps)x = self.weight[:, None, None] * x + self.bias[:, None, None]return xdef update_weight(model_dict, weight_dict):idx, temp_dict = 0, {}for k, v in weight_dict.items():if k in model_dict.keys() and np.shape(model_dict[k]) == np.shape(v):temp_dict[k] = vidx += 1model_dict.update(temp_dict)print(f'loading weights... {idx}/{len(model_dict)} items')return model_dictdef unireplknet_a(weights='', **kwargs):model = UniRepLKNet(depths=UniRepLKNet_A_F_P_depths, dims=(40, 80, 160, 320), **kwargs)if weights:model.load_state_dict(update_weight(model.state_dict(), torch.load(weights)))return modeldef unireplknet_f(weights='', **kwargs):model = UniRepLKNet(depths=UniRepLKNet_A_F_P_depths, dims=(48, 96, 192, 384), **kwargs)if weights:model.load_state_dict(update_weight(model.state_dict(), torch.load(weights)))return modeldef unireplknet_p(weights='', **kwargs):model = UniRepLKNet(depths=UniRepLKNet_A_F_P_depths, dims=(64, 128, 256, 512), **kwargs)if weights:model.load_state_dict(update_weight(model.state_dict(), torch.load(weights)))return modeldef unireplknet_n(weights='', **kwargs):model = UniRepLKNet(depths=UniRepLKNet_N_depths, dims=(80, 160, 320, 640), **kwargs)if weights:model.load_state_dict(update_weight(model.state_dict(), torch.load(weights)))return modeldef unireplknet_t(weights='', **kwargs):model = UniRepLKNet(depths=UniRepLKNet_T_depths, dims=(80, 160, 320, 640), **kwargs)if weights:model.load_state_dict(update_weight(model.state_dict(), torch.load(weights)))return modeldef unireplknet_s(weights='', **kwargs):model = UniRepLKNet(depths=UniRepLKNet_S_B_L_XL_depths, dims=(96, 192, 384, 768), **kwargs)if weights:model.load_state_dict(update_weight(model.state_dict(), torch.load(weights)))return modeldef unireplknet_b(weights='', **kwargs):model = UniRepLKNet(depths=UniRepLKNet_S_B_L_XL_depths, dims=(128, 256, 512, 1024), **kwargs)if weights:model.load_state_dict(update_weight(model.state_dict(), torch.load(weights)))return modeldef unireplknet_l(weights='', **kwargs):model = UniRepLKNet(depths=UniRepLKNet_S_B_L_XL_depths, dims=(192, 384, 768, 1536), **kwargs)if weights:model.load_state_dict(update_weight(model.state_dict(), torch.load(weights)))return modeldef unireplknet_xl(weights='', **kwargs):model = UniRepLKNet(depths=UniRepLKNet_S_B_L_XL_depths, dims=(256, 512, 1024, 2048), **kwargs)if weights:model.load_state_dict(update_weight(model.state_dict(), torch.load(weights)))return modelif __name__ == '__main__':inputs = torch.randn((1, 3, 640, 640))model = unireplknet_a('unireplknet_a_in1k_224_acc77.03.pth')res = model(inputs)[-1]model.switch_to_deploy()res_fuse = model(inputs)[-1]print(torch.mean(res_fuse - res))

第②步:修改task.py 

(1)引入创建的UniRepLKNet文件 

from ultralytics.nn.backbone.UniRepLKNet import *

(2)修改_predict_once函数 

 可直接将下述代码替换对应位置 

 def _predict_once(self, x, profile=False, visualize=False, embed=None):"""Perform a forward pass through the network.Args:x (torch.Tensor): The input tensor to the model.profile (bool):  Print the computation time of each layer if True, defaults to False.visualize (bool): Save the feature maps of the model if True, defaults to False.embed (list, optional): A list of feature vectors/embeddings to return.Returns:(torch.Tensor): The last output of the model."""y, dt, embeddings = [], [], []  # outputsfor idx, m in enumerate(self.model):if m.f != -1:  # if not from previous layerx = 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)if hasattr(m, 'backbone'):x = m(x)for _ in range(5 - len(x)):x.insert(0, None)for i_idx, i in enumerate(x):if i_idx in self.save:y.append(i)else:y.append(None)# print(f'layer id:{idx:>2} {m.type:>50} output shape:{", ".join([str(x_.size()) for x_ in x if x_ is not None])}')x = x[-1]else:x = m(x)  # runy.append(x if m.i in self.save else None)  # save output# if type(x) in {list, tuple}:#     if idx == (len(self.model) - 1):#         if type(x[1]) is dict:#             print(f'layer id:{idx:>2} {m.type:>50} output shape:{", ".join([str(x_.size()) for x_ in x[1]["one2one"]])}')#         else:#             print(f'layer id:{idx:>2} {m.type:>50} output shape:{", ".join([str(x_.size()) for x_ in x[1]])}')#     else:#         print(f'layer id:{idx:>2} {m.type:>50} output shape:{", ".join([str(x_.size()) for x_ in x if x_ is not None])}')# elif type(x) is dict:#     print(f'layer id:{idx:>2} {m.type:>50} output shape:{", ".join([str(x_.size()) for x_ in x["one2one"]])}')# else:#     if not hasattr(m, 'backbone'):#         print(f'layer id:{idx:>2} {m.type:>50} output shape:{x.size()}')if visualize:feature_visualization(x, m.type, m.i, save_dir=visualize)if embed and m.i in embed:embeddings.append(nn.functional.adaptive_avg_pool2d(x, (1, 1)).squeeze(-1).squeeze(-1))  # flattenif m.i == max(embed):return torch.unbind(torch.cat(embeddings, 1), dim=0)return x

(3)修改parse_model函数

可以直接把下面的代码粘贴到对应的位置中

def parse_model(d, ch, verbose=True):  # model_dict, input_channels(3)"""Parse a YOLO model.yaml dictionary into a PyTorch model.Args:d (dict): Model dictionary.ch (int): Input channels.verbose (bool): Whether to print model details.Returns:(tuple): Tuple containing the PyTorch model and sorted list of output layers."""import ast# Argsmax_channels = float("inf")nc, act, scales = (d.get(x) for x in ("nc", "activation", "scales"))depth, width, kpt_shape = (d.get(x, 1.0) for x in ("depth_multiple", "width_multiple", "kpt_shape"))if scales:scale = d.get("scale")if not scale:scale = tuple(scales.keys())[0]LOGGER.warning(f"WARNING ⚠️ no model scale passed. Assuming scale='{scale}'.")if len(scales[scale]) == 3:depth, width, max_channels = scales[scale]elif len(scales[scale]) == 4:depth, width, max_channels, threshold = scales[scale]if act:Conv.default_act = eval(act)  # redefine default activation, i.e. Conv.default_act = nn.SiLU()if verbose:LOGGER.info(f"{colorstr('activation:')} {act}")  # printif verbose:LOGGER.info(f"\n{'':>3}{'from':>20}{'n':>3}{'params':>10}  {'module':<60}{'arguments':<50}")ch = [ch]layers, save, c2 = [], [], ch[-1]  # layers, savelist, ch outis_backbone = Falsefor i, (f, n, m, args) in enumerate(d["backbone"] + d["head"]):  # from, number, module, argstry:if m == 'node_mode':m = d[m]if len(args) > 0:if args[0] == 'head_channel':args[0] = int(d[args[0]])t = mm = getattr(torch.nn, m[3:]) if 'nn.' in m else globals()[m]  # get moduleexcept:passfor j, a in enumerate(args):if isinstance(a, str):with contextlib.suppress(ValueError):try:args[j] = locals()[a] if a in locals() else ast.literal_eval(a)except:args[j] = an = n_ = max(round(n * depth), 1) if n > 1 else n  # depth gainif m in {Classify, Conv, ConvTranspose, GhostConv, Bottleneck, GhostBottleneck, SPP, SPPF, DWConv, Focus,BottleneckCSP, C1, C2, C2f, ELAN1, AConv, SPPELAN, C2fAttn, C3, C3TR,C3Ghost, nn.Conv2d, nn.ConvTranspose2d, DWConvTranspose2d, C3x, RepC3, PSA, SCDown, C2fCIB}:if args[0] == 'head_channel':args[0] = d[args[0]]c1, c2 = ch[f], args[0]if c2 != nc:  # if c2 not equal to number of classes (i.e. for Classify() output)c2 = make_divisible(min(c2, max_channels) * width, 8)if m is C2fAttn:args[1] = make_divisible(min(args[1], max_channels // 2) * width, 8)  # embed channelsargs[2] = int(max(round(min(args[2], max_channels // 2 // 32)) * width, 1) if args[2] > 1 else args[2])  # num headsargs = [c1, c2, *args[1:]]elif m in {AIFI}:args = [ch[f], *args]c2 = args[0]elif m in (HGStem, HGBlock):c1, cm, c2 = ch[f], args[0], args[1]if c2 != nc:  # if c2 not equal to number of classes (i.e. for Classify() output)c2 = make_divisible(min(c2, max_channels) * width, 8)cm = make_divisible(min(cm, max_channels) * width, 8)args = [c1, cm, c2, *args[2:]]if m in (HGBlock):args.insert(4, n)  # number of repeatsn = 1elif m is ResNetLayer:c2 = args[1] if args[3] else args[1] * 4elif m is nn.BatchNorm2d:args = [ch[f]]elif m is Concat:c2 = sum(ch[x] for x in f)elif m in frozenset({Detect, WorldDetect, Segment, Pose, OBB, ImagePoolingAttn, v10Detect}):args.append([ch[x] for x in f])elif m is RTDETRDecoder:  # special case, channels arg must be passed in index 1args.insert(1, [ch[x] for x in f])elif m is CBLinear:c2 = make_divisible(min(args[0][-1], max_channels) * width, 8)c1 = ch[f]args = [c1, [make_divisible(min(c2_, max_channels) * width, 8) for c2_ in args[0]], *args[1:]]elif m is CBFuse:c2 = ch[f[-1]]elif isinstance(m, str):t = mif len(args) == 2:m = timm.create_model(m, pretrained=args[0], pretrained_cfg_overlay={'file': args[1]},features_only=True)elif len(args) == 1:m = timm.create_model(m, pretrained=args[0], features_only=True)c2 = m.feature_info.channels()elif m in {unireplknet_a, unireplknet_f, unireplknet_p, unireplknet_n, unireplknet_t, unireplknet_s, unireplknet_b, unireplknet_l, unireplknet_xl}:m = m(*args)c2 = m.channelelse:c2 = ch[f]if isinstance(c2, list):is_backbone = Truem_ = mm_.backbone = Trueelse:m_ = nn.Sequential(*(m(*args) for _ in range(n))) if n > 1 else m(*args)  # modulet = str(m)[8:-2].replace('__main__.', '')  # module typem.np = sum(x.numel() for x in m_.parameters())  # number paramsm_.i, m_.f, m_.type = i + 4 if is_backbone else i, f, t  # attach index, 'from' index, typeif verbose:LOGGER.info(f"{i:>3}{str(f):>20}{n_:>3}{m.np:10.0f}  {t:<60}{str(args):<50}")  # printsave.extend(x % (i + 4 if is_backbone else i) for x in ([f] if isinstance(f, int) else f) ifx != -1)  # append to savelistlayers.append(m_)if i == 0:ch = []if isinstance(c2, list):ch.extend(c2)for _ in range(5 - len(ch)):ch.insert(0, 0)else:ch.append(c2)return nn.Sequential(*layers), sorted(save)

具体改进差别如下图所示: ​​​​

第③步:yolov8.yaml文件修改   

在下述文件夹中创立yolov8-unireplknet.yaml

​​

# Parameters
nc: 80  # number of classes
scales: # model compound scaling constants, i.e. 'model=yolov8n.yaml' will call yolov8.yaml with scale 'n'# [depth, width, max_channels]n: [0.33, 0.25, 1024]  # YOLOv8n summary: 225 layers,  3157200 parameters,  3157184 gradients,   8.9 GFLOPss: [0.33, 0.50, 1024]  # YOLOv8s summary: 225 layers, 11166560 parameters, 11166544 gradients,  28.8 GFLOPsm: [0.67, 0.75, 768]   # YOLOv8m summary: 295 layers, 25902640 parameters, 25902624 gradients,  79.3 GFLOPsl: [1.00, 1.00, 512]   # YOLOv8l summary: 365 layers, 43691520 parameters, 43691504 gradients, 165.7 GFLOPsx: [1.00, 1.25, 512]   # YOLOv8x summary: 365 layers, 68229648 parameters, 68229632 gradients, 258.5 GFLOPs# 0-P1/2
# 1-P2/4
# 2-P3/8
# 3-P4/16
# 4-P5/32# YOLOv8.0n backbone
backbone:# [from, repeats, module, args]- [-1, 1, unireplknet_a, []]  # 4- [-1, 1, SPPF, [1024, 5]]  # 5# YOLOv8.0n head
head:- [-1, 1, nn.Upsample, [None, 2, 'nearest']] # 6- [[-1, 3], 1, Concat, [1]]  # 7 cat backbone P4- [-1, 3, C2f, [512]]  # 8- [-1, 1, nn.Upsample, [None, 2, 'nearest']] # 9- [[-1, 2], 1, Concat, [1]]  # 10 cat backbone P3- [-1, 3, C2f, [256]]  # 11 (P3/8-small)- [-1, 1, Conv, [256, 3, 2]] # 12- [[-1, 8], 1, Concat, [1]]  # 13 cat head P4- [-1, 3, C2f, [512]]  # 14 (P4/16-medium)- [-1, 1, Conv, [512, 3, 2]] # 15- [[-1, 5], 1, Concat, [1]]  # 16 cat head P5- [-1, 3, C2f, [1024]]  # 17 (P5/32-large)- [[11, 14, 17], 1, Detect, [nc]]  # Detect(P3, P4, P5)

第④步:验证是否加入成功   

将train.py中的配置文件进行修改,并运行  


🏋不是每一粒种子都能开花,但播下种子就比荒芜的旷野强百倍🏋

🍁YOLOv8入门+改进专栏🍁


  【YOLOv8改进系列】: 

 

YOLOv8改进系列(2)----替换主干网络之FasterNet

YOLOv8改进系列(3)----替换主干网络之ConvNeXt V2

YOLOv8改进系列(4)----替换C2f之FasterNet中的FasterBlock替换C2f中的Bottleneck 

YOLOv8改进系列(5)----替换主干网络之EfficientFormerV2 

YOLOv8改进系列(6)----替换主干网络之VanillaNet

YOLOv8改进系列(7)----替换主干网络之LSKNet

YOLOv8改进系列(8)----替换主干网络之Swin Transformer 

YOLOv8改进系列(9)----替换主干网络之RepViT


相关文章:

【YOLOv8】YOLOv8改进系列(10)----替换主干网络之UniRepLKNet

主页&#xff1a;HABUO&#x1f341;主页&#xff1a;HABUO &#x1f341;YOLOv8入门改进专栏&#x1f341; &#x1f341;如果再也不能见到你&#xff0c;祝你早安&#xff0c;午安&#xff0c;晚安&#x1f341; 【YOLOv8改进系列】&#xff1a; YOLOv8改进系列&#xff0…...

mathtype一些用法总结

1.一个是公式旁边加入||&#xff0c;一般使用键盘直接打入的会比较小&#xff0c;mathtype中的会好看很多&#xff0c;打开这个栏目&#xff0c;会看到有很多。 2.另外是带^符号&#xff0c;在字符上面带没有办法直接带&#xff0c;所以可以在mathtype中先加帽子&#xff0c;然…...

1、SQL注入攻击的防范

原文地址: SQL注入攻击的防范 更多内容请关注&#xff1a;代码安全 PHP安全编码——书写安全的代码 1、SQL注入攻击的防范 提问 问题1&#xff1a;什么是SQL注入攻击&#xff1f; 问题2&#xff1a;有几种简单方法防范SQL注入攻击&#xff1f; 问题3&#xff1a;mys…...

核心知识——论文总结

引入 本文我们会针对论文中的核心内容进行总结&#xff0c;加深小伙伴对于Spark的理解。而通过Spark的论文&#xff0c;重点需要掌握理解如下内容&#xff1a; Spark 里核心的 RDD 是一个什么概念&#xff0c;它是通过什么方式来优化分布式数据处理的&#xff0c;它的设计思路…...

HTTP 核心知识点整理

1. HTTP 基础 ​定义&#xff1a;HTTP&#xff08;HyperText Transfer Protocol&#xff09;是应用层协议&#xff0c;基于 ​请求-响应模型&#xff0c;用于客户端&#xff08;浏览器&#xff09;与服务器之间的通信。​特点&#xff1a; ​无状态&#xff1a;每次请求独立&a…...

什么是矩阵账号

矩阵账号是指在同一平台或多个平台上&#xff0c;围绕同一品牌或个人&#xff0c;创建的多个相互关联、协同工作的账号组合。这些账号虽然独立&#xff0c;但在内容定位和运营策略上有所区分&#xff0c;同时又相互引流&#xff0c;共同形成一个网络结构&#xff0c;类似于矩阵…...

【6】VS Code 新建上位机项目---项目分层

【6】VS Code 新建上位机项目---项目分层 1 项目分层(layer)2 项目分层实现数据插入SQL3 项目分层实现 (实体类封装参数)4 项目分层的实现SQL查询数据1 项目分层(layer) 表示层(UI):与用户交互使用。比如按钮,输入信息等;业务层(BLL):传递数据,业务逻辑。根据用户需…...

EspressoSample深度解析:在CircleCI上高效运行Android UI测试

项目背景与简介 EspressoSample项目位于GitHub上的circleci/EspressoSample仓库&#xff0c;该项目旨在展示如何在CircleCI平台上配置和使用Espresso进行Android应用的UI测试。 项目结构与环境准备 项目结构 EspressoSample项目遵循典型的Android项目结构&#xff0c;包含a…...

【每日论文】MetaSpatial: Reinforcing 3D Spatial Reasoning in VLMs for the Metaverse

下载PDF或查看论文&#xff0c;请点击&#xff1a; LlamaFactory - huggingface daily paper - 每日论文解读 | LlamaFactory | LlamaFactory探索LlamaFactory&#xff0c;为你解读AI前沿技术文章&#xff0c;快速掌握最新技术动态https://www.llamafactory.cn/daily-paper/de…...

mac m4 Homebrew安装MySQL 8.0

1.使用Homebrew安装MySQL8 在终端中输入以下命令来安装MySQL8&#xff1a; brew install mysql8.0 安装完成后&#xff0c;您可以通过以下命令来验证MySQL是否已成功安装&#xff1a; 2.配置mysql环境变量 find / -name mysql 2>/dev/null #找到mysql的安装位置 cd /op…...

Java关于多态

多态 字面意思&#xff1a;对象的多种形态。 Student(子类)<-Person(父类)->Teacher(子类) Student snew Student(); 学生形态 对象 代表用new创建一个学生对象赋值给Student 类型&#xff0c;代表Student类型(学生对象)现在是学生形态。 有了多态之后&#xff…...

K8S学习之基础四十六:k8s中部署Kibana

部署kibana组件 上传kibina镜像到harbor 部署kibana组件&#xff0c;包括svc和deplomentvi kibana.yaml apiVersion: v1 kind: Service metadata:name: kibananamespace: kube-logginglabels:app: kibana spec:ports:- port: 5601selector:app: kibana --- apiVersion: apps/…...

如何快速对比两个不同的excel文件中的单元格的数据是否完全相同 并把不同的单元格的背景颜色更改为红色?

要快速对比两个不同的Excel文件中的单元格数据是否完全相同&#xff0c;并将不同的单元格背景颜色更改为红色&#xff0c;可以使用Excel的以下几种方法&#xff1a; 方法一&#xff1a;使用条件格式 打开两个Excel文件。将一个文件的内容复制到另一个文件的新工作表中&#x…...

基于Python+LanceDB实战向量搜索

本篇实战演示向量搜索的实现和示例。 预期效果 给出一个查询的字符串&#xff0c;通过向量搜索&#xff0c;在下面三个语句中搜索出关联性最大的那句。 "熊猫是中国的国宝&#xff0c;主要栖息在四川山区。","长城是古代中国建造的军事防御工事&#xff0c;全…...

多路转接epoll

目录 一、为什么epoll最高效&#xff1f; 二、epoll的三个系统调用 三、理解epoll模型 四、epoll的优点 五、epoll的使用示例 六、epoll的工作模式 ET模式和LT模式的对比 七、epoll的使用场景 总结 一、为什么epoll最高效&#xff1f; 按照 man 手册的…...

AI编程工具哪家强?对比Cusor、Copilot、Cline

前言 AI最先革谁的命&#xff1f;刚毕业参加工作的那个时候就在想是否可以开发一个程序让它自己写代码&#xff0c;在那个遥远的年代&#xff0c;这种想法仿佛就是天方夜谭。但是今天大模型的出现让理想成为了现实。回答前面的问题&#xff0c;AI最先革谁的命&#xff0c;最聪…...

[FPGA基础学习]实现流水灯与按键暂停

FPGA实现LED流水灯 1.vscode的安装和使用 vscode下载 Visual Studio Code - Code Editing. Redefined vscode插件&#xff08;Verilog-HDL/SystemVerilog&#xff09;下载 quartus绑定vscode 2.用6个LED完成周期为1秒的跑马灯效果 流水灯模块设计 时钟输入 DE2-115开发板…...

刷题记录(LeetCode 994.腐烂的橘子)

在给定的 m x n 网格 grid 中&#xff0c;每个单元格可以有以下三个值之一&#xff1a; 值 0 代表空单元格&#xff1b;值 1 代表新鲜橘子&#xff1b;值 2 代表腐烂的橘子。 每分钟&#xff0c;腐烂的橘子 周围 4 个方向上相邻 的新鲜橘子都会腐烂。 返回 直到单元格中没有…...

ECharts折线图源码合集1(共18个自定义图表),附视频讲解与代码下载

引言&#xff1a; 在数据可视化的世界里&#xff0c;ECharts凭借其丰富的图表类型和强大的配置能力&#xff0c;成为了众多开发者的首选。今天&#xff0c;我整理了18个自定义折线图图表&#xff0c;不仅对每个图表代码进行了精简优化&#xff0c;剥离冗余配置项&#xff0c;…...

SQL小菜之TOP N查找问题

前言 SQL的编写是后端面试中非常常见&#xff0c;其中TOP N查找问题也是高频出现的问题&#xff0c;今天我们来看两道SQL TOPN问题。 问题 我们有一张雇员表Employee&#xff1a; CREATE TABLE Employee (id int DEFAULT NULL,salary int DEFAULT NULL,department varchar(…...

蓝桥杯 临时抱佛脚 之 二分答案法与相关题目

二分答案法&#xff08;利用二分法查找区间的左右端点&#xff09; &#xff08;1&#xff09;估计 最终答案可能得范围 是什么 &#xff08;2&#xff09;分析 问题的答案 和 给定条件 之间的单调性&#xff0c;大部分时候只需要用到 自然智慧 &#xff08;3&#xff09;建…...

Css环形旋转立体感动画

Css环形旋转立体感动画 index.html <!DOCTYPE html> <html lang"en" > <head><meta charset"UTF-8"><title>Css环形旋转立体感动画</title><link rel"stylesheet" href"./style.css">&l…...

音乐极客指南:Melody高音质私有云音乐平台本地部署方案

文章目录 前言1. 添加镜像源2. 本地部署Melody3. 本地访问与使用演示4. 安装内网穿透5. 配置Melody公网地址6. 配置固定公网地址 前言 嘿&#xff0c;各位音乐爱好者们&#xff01;今天我要带大家玩个大招——在香橙派Zero3上搭建你的专属在线音乐平台&#xff0c;还能通过cpo…...

Microi吾码界面设计引擎之基础组件用法大全【内置组件篇·中】

&#x1f380;&#x1f380;&#x1f380; microi-pageengine 界面引擎系列 &#x1f380;&#x1f380;&#x1f380; 一、Microi吾码&#xff1a;一款高效、灵活的低代码开发开源框架【低代码框架】 二、Vue3项目快速集成界面引擎 三、Vue3 界面设计插件 microi-pageengine …...

# WebSocket 与 Socket.IO 对比与优化

核心概念对比 WebSocket 协议性质&#xff1a;HTML5 提供的全双工通信协议 (RFC 6455)连接方式&#xff1a;基于 TCP 的低层协议通信模式&#xff1a;持久化连接&#xff0c;服务端可主动推送协议升级&#xff1a;通过 HTTP 101 状态码切换协议 Socket.IO 协议性质&#xf…...

vue3中,route4,获取当前页面路由的问题

首先应用场景如下&#xff1a; 在main.js里面&#xff0c;引入的是路由的配置文件&#xff0c;如下&#xff1a; import {router} from /router; app.use(router); 路由配置文件router.js如下&#xff1a; import { createRouter, createWebHistory } from vue-router; imp…...

python将整个txt文件写入excel的一个单元格?

要将整个txt文件写入Excel的一个单元格&#xff0c;可以使用Python的openpyxl库来实现。以下是一个简单的示例代码&#xff1a; from openpyxl import Workbook# 读取txt文件内容 with open(file.txt, r) as file:txt_content file.read()# 创建一个新的Excel工作簿 wb Work…...

日志2333

Pss-9 这一关考察的是时间盲注 先练习几个常见命令语句&#xff1a; select sleep(5);--延迟5s输出结果 if &#xff08;1>0,ture,false&#xff09;;--输出‘ture’ /if &#xff08;1<0,ture,false&#xff09;;--输出‘false’ select ascii()/select ord()返回字…...

用Deepseek写扫雷uniapp小游戏

扫雷作为Windows系统自带的经典小游戏&#xff0c;承载了许多人的童年回忆。本文将详细介绍如何使用Uniapp框架从零开始实现一个完整的扫雷游戏&#xff0c;包含核心算法、交互设计和状态管理。无论你是Uniapp初学者还是有一定经验的开发者&#xff0c;都能从本文中获得启发。 …...

C++中的异常和智能指针

一、C中的异常 1.1C语言中关于错误的处理&#xff08;回顾&#xff09; 1.1.1处理一&#xff1a;文件中的错误码&#xff0c;错误信息 C语言中&#xff0c;文件打开成功则返回地址&#xff0c;不成功返回0 FILE* foutfopen("Test.txt","r"); cout<&…...

Selenium 简单入门操作示例

最简单的 Selenium 示例&#xff08;Python版&#xff09; 下面是一个完整的、最简单的 Selenium 操作示例&#xff0c;带你快速上手&#xff1a; from selenium import webdriver from selenium.webdriver.common.by import By import time# 1. 启动浏览器&#xff08;这里使…...

6.1 模拟专题:LeetCode 1576. 替换所有的问号

1. 题目链接 LeetCode 1576. 替换所有的问号 2. 题目描述 给定一个仅包含小写字母和问号 ? 的字符串 s&#xff0c;要求将所有 ? 替换为任意小写字母&#xff0c;使得替换后的字符串中 没有相邻的两个字符相同。 示例&#xff1a; 输入&#xff1a;s "?zs" →…...

前端知识点---用正则表达式判断邮箱(javascript)

// 全面的正则&#xff08;兼容大多数情况&#xff09; const emailRegex /^[a-zA-Z0-9._%-][a-zA-Z0-9.-]\.[a-zA-Z]{2,}$/;// 或直接使用浏览器内置验证 <input type"email" required>/&#xff1a;正则表达式的起始和结束标志。 ^&#xff1a;匹配字符串的…...

深度剖析 Spring 源码 性能优化:核心原理与最佳实践

深度剖析 Spring 源码 & 性能优化&#xff1a;核心原理与最佳实践 &#x1f680; Spring 框架 作为 Java 生态的核心技术&#xff0c;广泛应用于企业级开发。但很多开发者只会“用”Spring&#xff0c;而不深入其内部原理&#xff0c;导致无法高效排查问题 & 进行性能优…...

Axure RP9教程 :轮播图(动态面板) | 头部锁定

文章目录 引言I 轮播图操作步骤在画布中添加一个动态面板设置面板状态II 头部锁定将头部区域选中,右键组合或用Ctrl+G快捷键;将组合的头部区域,右键创建动态面板;引言 动态面板的功能十分强大,比如:拥有独立的内部坐标系,有多个状态; Banner的案例中会用到动态面板多个…...

rabbitmq承接MES客户端服务器

文章目录 背景整体架构概述方案详细步骤1. 数据库选型与搭建2. 设备端数据上传至数据库3. 搭建 RabbitMQ 服务器4. 数据同步模块&#xff08;数据库到 RabbitMQ&#xff09;5. MES 服务器从 RabbitMQ 接收数据6. 指令接收模块&#xff08;RabbitMQ 到设备端&#xff09; 7. MES…...

重学vue3(三):vue3基本语法及使用

组合式 API是vue3 的核心特性&#xff0c;替代 Vue2 的选项式 API&#xff0c;强调逻辑复用和代码组织。基本语法如下&#xff1a; <script setup> import { ref, reactive, computed, onMounted } from vue;// 1. 响应式数据 const count ref(0); // 基本类…...

算法 | 麻雀搜索算法原理,公式,改进算法综述,应用场景及matlab完整代码

一、麻雀搜索算法(SSA)原理 1. 算法基础 麻雀搜索算法(Sparrow Search Algorithm, SSA)是2020年提出的一种群体智能优化算法,灵感来源于麻雀群体的觅食与反捕食行为。算法将麻雀分为三类角色:发现者(Producer):适应度最高,负责探索全局最优区域;加入者(Follower)…...

0322-数据库与前后端的连接、数据库表的增删改查

前端 <!DOCTYPE html> <html> <head> <meta charset"UTF-8"> <title>Insert title here</title> <script srcjs/jquery-3.7.1.min.js></script> <script> //jquaryajax发起请求 //传参形式不同 post用data{}…...

详细介绍Qt中用于断言的宏 Q_ASSERT

Q_ASSERT 是 Qt 框架中用于调试的核心宏之一&#xff0c;其作用类似于标准 C/C 的 assert&#xff0c;但针对 Qt 的特性进行了优化。它用于在开发阶段验证程序的逻辑正确性&#xff0c;帮助开发者快速定位潜在的错误。 1.基本用法 Q_ASSERT(condition);功能&#xff1a;在调试…...

基于Python的自然语言处理系列(60):使用 LangChain 构建 Multi-Vector Retriever 进行文档检索

在 NLP 和 AI 领域&#xff0c;基于嵌入&#xff08;Embeddings&#xff09;进行文档检索已成为一种高效的解决方案。本文介绍如何使用 LangChain 构建 Multi-Vector Retriever&#xff0c;实现对长文档的分块索引和高效检索。 1. 环境准备 首先&#xff0c;我们需要安装相关…...

Dify 部署指南-离线版

Docker 部署 1、 访问 Docker 官网 (https://www.docker.com/) 获取安装包。 2、 上传 Docker 安装包 3、 进入解压目录&#xff0c;执行解压命令 tar xzvf docker-28、0.2、tgz4、 将解压文件中的 Docker 相关文件移动到 /usr/bin/ 目录 sudo cp docker/* /usr/bin/5、 创建…...

解决 Element UI 嵌套弹窗的状态管理问题!!!

解决 Element UI 嵌套弹窗的状态管理问题 &#x1f527; 问题描述 ❓ 在使用 Element UI 开发一个多层嵌套弹窗功能时&#xff0c;遇到了以下问题&#xff1a; 弹窗只能打开一次&#xff0c;第二次点击无法打开 &#x1f6ab;收到 Vue 警告&#xff1a;避免直接修改 prop 值…...

基于STM32单片机的智能手环/音乐播放/语音识别

基于STM32单片机的智能手环/音乐播放/语音识别 持续更新&#xff0c;欢迎关注!!! ** 基于STM32单片机的智能手环/音乐播放/语音识别 ** 21世纪&#xff0c;社会高速发展&#xff0c;生活物质越来越丰富&#xff0c;随着科技的进步&#xff0c;智能化成为了人们关注的焦点&am…...

NFC 智能门锁全栈解决方案:移动端、服务器、Web 管理平台

目录 一、系统整体架构 二、移动端 APP 开发 2.1 开发环境与基础准备 2.2 主要功能模块 2.3 示例代码&#xff08;Android/Kotlin 简化示例&#xff09; 三、后台服务开发 3.1 环境准备 3.2 主要功能 3.3 示例代码&#xff08;Node.js Express 简化示例&#xff09; …...

使用 Python 开发 MCP Server 及 Inspector 工具详解

使用 Python 开发 MCP Server 及 Inspector 工具详解 前言 模型上下文协议 (Model Context Protocol, MCP) 是一种新兴的协议&#xff0c;旨在让大型语言模型 (LLM) 更容易地与外部工具和服务集成。本文将介绍如何使用 Python 开发一个 MCP Server&#xff0c;并详细讲解如何使…...

论坛系统测试报告

一、项目背景 为论坛系统项目设计并进行自动化测试。论坛系统由六个页面构成&#xff1a;用户登录页、用户注册页、个人中心页面、我的帖子页面、帖子编辑页、帖子列表页以及帖子详情页。 通过使用selenium工具来定位到web中的元素&#xff0c;对获取到的元素进行自动化测试等操…...

Android一个APP里面最少有几个线程

Android应用启动时,默认会创建一个进程,该进程中最少包含5个系统自动创建的线程,具体如下: Main线程(主线程/UI线程) 负责处理用户交互、UI更新等核心操作,所有与界面相关的逻辑必须在此线程执行。若在此线程执行耗时操作(如网络请求),会导致界面卡顿甚至触发ANR(应…...

DML 数据操纵语言学习笔记

一、DML 核心概念体系 1.1 语言定位与边界 DML&#xff08;Data Manipulation Language&#xff09;作为 SQL 三大核心语言之一&#xff0c;专注于数据行级操作&#xff0c;区别于 DDL&#xff08;结构定义&#xff09;和 DCL&#xff08;权限控制&#xff09;。其核心指令包…...

7-Zip 功能介绍

7-Zip 是一款开源、高效的文件压缩与解压缩工具&#xff0c;支持多种格式&#xff0c;以高压缩率和灵活性著称。以下是其核心功能&#xff1a; 多格式支持 压缩 / 解压&#xff1a;支持 7z&#xff08;默认格式&#xff0c;压缩率极高&#xff09;、ZIP、RAR、GZIP、BZIP2、TAR…...