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

基于大核感知与非膨胀卷积的SPPF改进—融合UniRepLK的YOLOv8目标检测创新架构

在当前目标检测领域中,YOLO系列模型因其优异的速度-精度平衡能力而被广泛部署于工业界与科研场景。YOLOv8作为该系列的最新版本,在主干网络与特征金字塔结构上进行了多项优化,进一步提升了其实时性与鲁棒性。然而,其核心组件—SPPF(Spatial Pyramid Pooling Fast)模块仍采用传统池化操作,导致模型在复杂场景下对小目标和遮挡目标的识别能力受限。为解决这一问题,本文提出一种新型的ILK-SPPF(Improved Large Kernel SPPF)模块 ,将UniRepLKNet中的大kernel感知机制 引入YOLOv8架构中,通过非膨胀卷积 与结构重参数化策略 显著提升模型的感受野与上下文建模能力。

1. SPP与SPPF结构演进及在YOLO中的应用

空间金字塔池化(Spatial Pyramid Pooling, SPP )用于解决CNN输入尺寸固定的问题,并增强特征图的空间不变性。该结构在多个目标检测框架中得到应用,如Fast R-CNN、YOLOv3等。随着轻量化需求的增长,Ultralytics团队在YOLOv5 v6.0版本后引入了SPPF(Spatial Pyramid Pooling Fast)结构。相较于原始SPP采用并行不同窗口大小的最大池化,SPPF通过串行堆叠方式显著降低了计算量,在保持性能的同时提高了推理速度。

在这里插入图片描述

YOLOv8中,SPPF仍作为主干网络的重要组成部分,其主要作用包括:

  • 提升特征图的全局感知能力
  • 增强多尺度目标适应性
  • 优化特征金字塔的语义表达

然而,受限于其内部采用的标准池化操作(如5×5 max pool),SPPF在感受野扩展方面存在瓶颈,难以有效捕捉长距离依赖关系,尤其在面对小目标或遮挡目标时表现受限。

2. UniRepLKNet介绍

论文地址:https://arxiv.org/pdf/2311.15599
代码地址:https://github.com/AILab-CVC/UniRepLKNet

UniRepLKNet的架构设计:LarK块由本文提出的扩张重新参数块、SE块、前馈网络(FFN)和批量归一化(BN)层组成。SmaK块与LarK块的唯一区别在于前者使用深度可分离的3×3卷积层替代后者中的扩张重新参数块。各个阶段通过步幅为2的稠密3×3卷积层实现下采样块进行连接。
在这里插入图片描述
UniRepLKNetBlock原理图:
在这里插入图片描述

2.1 大卷积核CNN设计原则

近年来,大内核卷积(Large Kernel Convolution)因其能够直接扩大感受野、减少堆叠层数、增强空间建模能力而成为视觉模型设计的新趋势。尤其是在UniRepLKNet等工作中,作者验证了大kernel(如13×13)结合 非膨胀卷积 与结构重参数化 机制,在不牺牲效率的前提下可实现性能跃升。

2.1.1 局部结构设计:高效特征提取的基石

为在有限计算资源下最大化模型性能,本文在局部模块设计上采用以下策略:

  • SE注意力机制(Squeeze-and-Excitation):在通道维度引入动态权重分配机制,强化重要通道特征。
  • Bottleneck结构 :通过1×1卷积降维后再进行3×3卷积运算,降低计算开销。
  • Depthwise Separable Convolution :进一步压缩参数量与FLOPs,提高部署友好性。

这些结构在保证精度的前提下,为后续引入大kernel模块提供了“腾挪空间”。

2.1.2 重参数化策略:从多分支到单卷积的等价转换

为了兼顾训练灵活性与推理效率,本文借鉴UniRepLKNet的设计思想,提出了一个Dilated Reparam Block 子模块。其核心逻辑如下:

  • 在训练阶段,采用并行多分支结构 :
    • 一条路径为标准3×3深度可分离卷积
    • 另一条路径为膨胀卷积(Dilated Convolution)
  • 利用结构重参数化(Structural Re-parameterization),将上述多分支结构在推理阶段等价融合为一个单一的大kernel卷积(如7×713×13)
  • 数学上,小kernel + 膨胀卷积 等效大kernel + 非膨胀卷积

这种策略不仅提升了模型的表达能力,还避免了空洞卷积带来的网格效应(Grid Effect)和边缘响应失真问题。

2.1.3 卷积核尺寸选择与Scaling Law分析

在实际应用中,卷积核尺寸的选择需根据下游任务特性与整体网络架构进行权衡:

  • 对于本文的目标检测任务,实验表明13×13 kernel size已足够满足大多数场景下的感受野需求
  • 过大的kernel(如17×17以上)虽能进一步提升感受野,但会带来显著的计算负担,且边际收益递减

此外,针对模型缩放(Scaling)过程中的设计经验总结如下:

  • 在小型模型(如YOLO-Tiny级别)中,适当引入多个大kernel模块有助于快速提升模型容量
  • 当模型层级增加至Base级别(如36层)后,继续增加大kernel数量不再显著提升性能
  • 此时应优先采用高效的depthwise 3×3卷积 来提升特征抽象层次,而非盲目追求更大kernel

3. SPPF模型的创新机制与架构解析图

UniRepLKNetBlock和SPPF高效结合,进行创新:
在这里插入图片描述

3.1 SPPF引入YOLOv8

  1. ultralytics/nn下新建sppf文件包,并新建UniRepLKNet_SPPF.py加入UniRepLKNet_SPPF
import torch
import torch.nn as nn
import torch.nn.functional as F
from timm.models.layers import trunc_normal_, DropPath, to_2tuple
from functools import partial
import torch.utils.checkpoint as checkpoint
import numpy as np
from ultralytics.nn.modules import *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))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])class SPPF_UniRepLK(nn.Module):"""Spatial Pyramid Pooling - Fast (SPPF) layer for YOLOv5 by Glenn Jocher."""def __init__(self, c1, c2, k=5):  # equivalent to SPP(k=(5, 9, 13))super().__init__()c_ = c1 // 2  # hidden channelsself.cv1 = Conv(c1, c_, 1, 1)self.cv2 = Conv(c_ * 4, c2, 1, 1)self.m = nn.MaxPool2d(kernel_size=k, stride=1, padding=k // 2)self.UniRepLK = UniRepLKNetBlock(c_ * 4, kernel_size=k)def forward(self, x):"""Forward pass through Ghost Convolution block."""x = self.cv1(x)y1 = self.m(x)y2 = self.m(y1)return self.cv2(self.UniRepLK(torch.cat((x, y1, y2, self.m(y2)), 1)))
  1. ultralytics/nn/tasks.py注册SPPF_UniRepLK
from ultralytics.nn.sppf.UniRepLKNet_SPPF import SPPF_UniRepLK

在这里插入图片描述

修改def parse_model(d, ch, verbose=True): # model_dict, input_channels(3),加上 SPPF_UniRepLK

 if m in {Classify, Conv, ConvTranspose, GhostConv, Bottleneck, GhostBottleneck, SPP, SPPF, DWConv, Focus,BottleneckCSP, C1, C2, C2f, C3, C3TR, C3Ghost, nn.ConvTranspose2d, DWConvTranspose2d, C3x, SPPF_UniRepLK}: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(c2 * gw, 8)

在这里插入图片描述

  1. yolov8_SPPF_UniRepLK.yaml
# Ultralytics YOLO 🚀, AGPL-3.0 license
# YOLOv8 object detection model with P3-P5 outputs. For Usage examples see https://docs.ultralytics.com/tasks/detect# 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# YOLOv8.0n backbone
backbone:# [from, repeats, module, args]- [-1, 1, Conv, [64, 3, 2]]  # 0-P1/2- [-1, 1, Conv, [128, 3, 2]]  # 1-P2/4- [-1, 3, C2f, [128, True]]- [-1, 1, Conv, [256, 3, 2]]  # 3-P3/8- [-1, 6, C2f, [256, True]]- [-1, 1, Conv, [512, 3, 2]]  # 5-P4/16- [-1, 6, C2f, [512, True]]- [-1, 1, Conv, [1024, 3, 2]]  # 7-P5/32- [-1, 3, C2f, [1024, True]]- [-1, 1, SPPF_UniRepLK, [1024, 5]]  # 9# YOLOv8.0n head
head:- [-1, 1, nn.Upsample, [None, 2, 'nearest']]- [[-1, 6], 1, Concat, [1]]  # cat backbone P4- [-1, 3, C2f, [512]]  # 12- [-1, 1, nn.Upsample, [None, 2, 'nearest']]- [[-1, 4], 1, Concat, [1]]  # cat backbone P3- [-1, 3, C2f, [256]]  # 15 (P3/8-small)- [-1, 1, Conv, [256, 3, 2]]- [[-1, 12], 1, Concat, [1]]  # cat head P4- [-1, 3, C2f, [512]]  # 18 (P4/16-medium)- [-1, 1, Conv, [512, 3, 2]]- [[-1, 9], 1, Concat, [1]]  # cat head P5- [-1, 3, C2f, [1024]]  # 21 (P5/32-large)- [[15, 18, 21], 1, Detect, [nc]]  # Detect(P3, P4, P5)

4. 结论与未来展望

本文针对YOLOv8SPPF模块感受野受限的问题,提出了一种融合UniRepLK大核感知与非膨胀卷积的改进方案。通过引入多路径大核卷积、重参数化结构与通道注意力机制,显著提升了模型在复杂场景下的目标识别能力,尤其是在小目标检测方面表现出色。未来工作将进一步探索该模块在其他检测框架(如YOLO-NAS、RTMDet)中的泛化能力,并尝试结合Transformer结构实现更强大的全局建模能力。

相关文章:

基于大核感知与非膨胀卷积的SPPF改进—融合UniRepLK的YOLOv8目标检测创新架构

在当前目标检测领域中,YOLO系列模型因其优异的速度-精度平衡能力而被广泛部署于工业界与科研场景。YOLOv8作为该系列的最新版本,在主干网络与特征金字塔结构上进行了多项优化,进一步提升了其实时性与鲁棒性。然而,其核心组件—SPP…...

[Linux]从零开始的STM32MP157 Busybox根文件系统构建

一、前言 在上一篇教程中,已经教了大家如何使用Buildroot构建根文件系统,并且在最后我们已经完整的构建了一个可以运行的根文件系统。但是,Buildroot的集成度太高了,不利于小白理解根文件系统,所以本次教程&#xff0c…...

C++ RAII机制

RAII(Resource Acquisition Is Initialization)是一种编程范式,核心思想是:资源的生命周期与对象绑定——对象创建时获取资源,对象销毁时自动释放资源。这种机制通过构造函数和析构函数的配对执行,确保资源…...

spring中的@Value注解详解

一、核心功能与作用 Value是Spring框架中用于动态注入属性值的注解,支持从配置文件、环境变量、SpEL表达式等来源注入数据,实现代码与配置的解耦。 注入类型覆盖广泛 基本类型:字符串、数值(int/double)、布尔值等。 …...

模型欠拟合是什么?

模型的欠拟合:全面解析 一、定义与核心概念 欠拟合(Underfitting)是指模型在训练数据、验证数据和测试数据上均表现不佳的现象。其本质是模型过于简单或学习能力不足,无法捕捉数据中的潜在规律和复杂关系,导致泛化能力差。例如,用线性模型拟合非线性数据时,模型无法描…...

IC ATE集成电路测试学习——电流测试的原理和方法

电流测试 我们可以通过电流来判断芯片的工作状态时,首先先了解下芯片的电流是如何产生的。 静态电流 理论上,CMOS结构的芯片静态时几乎不耗电 CMOS基本结构:Pmos Nmos 串联当逻辑电平稳定时: ➜ 要么Pmos导通,Nmo…...

Wordpress头像无法加载太慢问题解决方式

Wordpress头像无法加载太慢问题解决方式 1、找到我们当前使用的主题目录中找到functions.php文件在文件最后面添加以下代码 if ( ! function_exists( get_cravatar_url ) ) {/***替换Gravatar头像为Cravatar头像** param string $url** return string*/function get_cravatar…...

《大模型微调实战:Llama 3.0全参数优化指南》

全参数微调(Full Parameter Fine-Tuning)是推动大模型适应垂直领域任务的核心技术,尤其对于Llama 3.0这类千亿级参数模型而言,其性能优化与场景适配能力直接决定了实际应用价值。然而,全参数微调面临计算成本高、内存占…...

ActiveMQ 生产环境问题排查与调优指南(二)

五、调优策略与实践 5.1 JVM 调优 JVM 调优对于提升 ActiveMQ 性能至关重要,合理的 JVM 配置可以使 ActiveMQ 更高效地利用系统资源,减少性能瓶颈。 设置合理的堆内存大小是 JVM 调优的关键步骤。堆内存是 JVM 中用于存储对象实例的区域,其…...

AugmentCode 非常昂贵的新定价

AugmentCode 现在的价格比 Cursor 和 Windsurf 的总和还要贵。 AugmentCode 曾是我开发工作流程的常用工具。出乎意料的是,他们改变了定价结构,让开发者们震惊不已。 原来的30 美元月费已经增长为50 美元月费,这是一个67%的增长。 改变我看法的不仅仅是价格上涨,还有他…...

Unity 红点系统

首先明确一个,即红点系统的数据结构是一颗树,并且红点的数据结构的初始化需要放在游戏的初始化中,之后再是对应的红点UI侧的注册,对应的红点UI在销毁时需要注销对红点UI的显示回调注册,但是不销毁数据侧的红点注册 - …...

Python-UV多环境管理

Python-UV多环境管理 Python使用UV进行环境管理,系统了解UV的使用 文章目录 Python-UV多环境管理 [toc]1-学习要点2-核心知识点3-UV多环境管理4-venv和uv脚本对比1-venv环境管理2-uv环境管理3-venv对比uv 1-学习要点 1-熟悉【UV环境管理】2-熟悉【UV和Venv脚本区别…...

多空短线决策+飞云分仓操盘,两个副图指标组合操盘技术,短线更精准有效

如上图,两个副图指标,第一个【短线多空决策】,第二个副图指标【飞云分仓操盘】,指标组合使用,精准性和有效性更加有效。 如上图,两个指标组合使用,我们选择第二个副图指标出现红色和紫色区域的标…...

istio in action之应用弹性与容错机制

在分布式系统中,服务间的依赖关系就像一张错综复杂的网络,任何一个节点的抖动都可能引发连锁反应。这也是为什么我们需要强调弹性,因为在分布式系统中,服务之间通过网络进行通信,这本身就引入了无数个潜在的失败点。我…...

将PyQt5设计的程序打包成.exe文件

打包教程 因为打包的机制是会把当前的解释器的包也打包上,而我的环境经常会有一些较大的包,比如torch之类的。所以这里会创建一个单独的环境。 conda create -n image_process python3.8 激活环境 conda activate image_process 现在先安装我需要安装…...

Java原生结合MQTTX---完成心跳对话(附带源码)

简言:✨当Java遇上MQTT:打造会"隔空传话"的魔法程序✨ 导语:想不想让两个Java程序像哈利波特里的双面镜一样实时对话?今天我们将用MQTT协议EMQX,在Ubuntu上搭建一个魔法邮局,再亲手编写会传信的…...

redis数据结构-06(LRANGE、LINDEX、LSET、LREM)

列表操作:LRANGE、LINDEX、LSET、LREM Redis 列表不仅仅是简单的数组;它们是一种强大的数据结构,可以高效地操作有序数据。本课将深入探讨使用 Redis 列表的四个基本命令: LRANGE 、 LINDEX 、 LSET 和 LREM 。掌握这些命令将使您…...

4.4 os模块

os模块: chdir:修改工作路径 --- 文件所在位置的标识 getcwd():返回当前路径,如果修改了则显示修改后的路径 curdir:获取当前目录的表示形式 cpu_count():返回当前cpu的线程数 getppid(): 获取当前进程编号 getppid():获取当前进程的父进…...

在 Windows 系统上选择与部署 DICOM 医学影像开发工具与库

🧑 博主简介:CSDN博客专家、CSDN平台优质创作者,高级开发工程师,数学专业,10年以上C/C++, C#, Java等多种编程语言开发经验,拥有高级工程师证书;擅长C/C++、C#等开发语言,熟悉Java常用开发技术,能熟练应用常用数据库SQL server,Oracle,mysql,postgresql等进行开发应用…...

MYSQL数据库集群高可用和数据监控平台(详细版)

项目说明 概述 该项目共分为2个子项目,由MYSQL集群高可用和数据监控平台两部分组成 MYSQL集群高可用属于云原生高级课数据库运维部分的知识 数据监控平台属于云原生拔高项目,旨在让学生增加知识面,提高项目实习经历,充实简历 …...

学习通刷课稳定版(美化面板+完全免费)

学习通刷 (美化面板完全免费) 安装教程方法一源码文件 方法二 提示结尾 安装教程 方法一 我们首先在浏览器打开脚本猫网站并获取该插件(浏览器以Edge为例) 脚本猫首页:https://scriptcat.org/zh-CN/ 第一步&#xff…...

python 实现sha加密

在Python中,SHA(Secure Hash Algorithm)是一种加密哈希函数,通常用于生成数据的哈希值。SHA算法是单向的,这意味着它只能用于加密(生成哈希值),而不能用于解密。因此,SHA…...

Linux epoll 详解:概念、使用、数据结构、流程及应用

epoll是什么? epoll 是从 Linux 2.6 起,Linux内核提供的一种高性能I/O事件通知机制,用于解决传统 select 和 poll 在处理大量并发连接时遍历、最大数量限制、频繁拷贝数据等问题。epoll 可以用来监听多个文件描述符(socket、管道…...

Kubernetes排错(十一):lsof命令实战场景

在Kubernetes生产环境中,lsof作为Linux系统的"透视眼",是排查容器级疑难杂症的必备工具。本文将深入解析其在容器化场景下的高阶用法,助你快速定位隐藏问题。 一、基础环境准备 1. 容器内安装lsof # 临时进入容器安装&#xff0…...

Java基础语法之循环结构

循环结构 1.定义 控制一段代码重复执行多次 2.分类 2.1 for循环 2.1.1 定义 控制一段代码反复执行很多次。 2.1.2 for循环格式 for (初始化语句; 循环条件; 迭代语句) { 循环体语句(重复执行的代码); }示例 // 输出3次HelloWorld for (int i 0; i < 3; i) { System…...

冒泡排序的原理

冒泡排序是一种简单的排序算法&#xff0c;它通过重复地遍历待排序的列表&#xff0c;比较相邻的元素并交换它们的位置来实现排序。具体原理如下&#xff1a; 冒泡排序的基本思想 冒泡排序的核心思想是通过相邻元素的比较和交换&#xff0c;将较大的元素逐步“冒泡”到列表的…...

AUTOSAR图解==>AUTOSAR_TR_InteractionWithBehavioralModels

AUTOSAR与行为模型交互详解 深入解析AUTOSAR软件组件与行为模型的交互关系与转换机制 目录 引言 1.1 AUTOSAR编辑工具概述 1.2 源起与目标 1.3 术语定义需求追溯AUTOSAR中行为建模的用例 3.1 软件组件的行为建模 3.2 软件组件描述到行为模型 3.3 行为模型到软件组件描述 3.4 组…...

GO语言内存管理结构

文章目录 1、内存分区1.1、栈&#xff08;Stack&#xff09;1.2、堆&#xff08;Heap&#xff09; 2、堆内存管理结构2.1、内存分配器&#xff08;MCache → MArena → MSpan → MHeap&#xff09;2.2、大小分类&#xff08;Size Class&#xff09;2.3、分配流程 3、垃圾回收&a…...

分享一些资料供大家学习

群里收集来的&#xff0c;自己感觉还是比较经典的&#xff0c;希望大家喜欢&#xff01;&#xff01;&#xff01; 20250428 夸克网盘分享一大波经典IT架构好货20250429夸克网盘分享精品文档-管理咨询师必备的思维模型20250430夸克网盘分享清华大学DeepSeek教程又来了《文科生A…...

RAGMCP基本原理说明和相关问题解惑

一、RAG架构原理和局限性 1.1 概念解释 RAG&#xff08;Retrieval-Augmented Generation&#xff09;&#xff1a;检索增强生成&#xff0c;让大模型接受外部输入后&#xff0c;总结输出 向量数据库&#xff1a;向量数据通常是高维空间中的点&#xff0c;代表复杂的数据结构…...

PyGame游戏开发(含源码+演示视频+开结题报告+设计文档)

前言&#xff1a; 大二小学期python课上基于pygame做的一个游戏小demo&#xff0c;当时老师花了一天讲解了下python基础语法后&#xff08;也是整个大学四年唯一学习python的时间&#xff09;&#xff0c;便让我们自学网课一周然后交项目&#xff0c;所以做的非常仓促&#xff…...

Git标签

Git标签 1. 添加标签 使用 tag 命令可以给某次 commit 提交的版本打上标签&#xff0c;相当于这个 commit id 的别名&#xff0c;在实践中&#xff0c;会使用 v1.0 之类的标签提示这是正式版的第一个版本。 git tag v1.0 [commit id]缺省输入 commit id会给最新的一次提交打…...

USB学习【6】USB传输错误的处理

1.前言 我们从物理层到信号层&#xff0c;到协议层&#xff0c;他们分别在不同的层面完成不同的功能。 总结一下&#xff1a; 物理层实现了高低电平的检测。 信号层更进一步&#xff0c;通过一些方法&#xff0c;实现了二进制的传输。 协议层&#xff0c;因为可以二进制传输了…...

深入解析 Vision Transformer (ViT) 与其在计算机视觉中的应用

在近年来&#xff0c;深度学习尤其在计算机视觉领域取得了巨大的进展&#xff0c;而 Vision Transformer&#xff08;ViT&#xff09;作为一种新的视觉模型&#xff0c;它的表现甚至在许多任务中超过了传统的卷积神经网络&#xff08;CNN&#xff09;&#xff0c;如 ResNet。在…...

《Go小技巧易错点100例》第三十一篇

本期分享&#xff1a; 1.Go struct内存对齐 2.使用空结构体(struct{})节省内存 Go struct内存对齐 在计算机系统中&#xff0c;CPU 访问内存时并不是逐字节读取的&#xff0c;而是以特定大小的块&#xff08;通常为 4/8 字节&#xff09;为单位进行读取。当数据的内存地址正…...

全栈项目实战:Vue3+Node.js开发博客系统

全栈项目实战&#xff1a;Vue3Node.js开发博客系统 一、项目架构设计 1. 技术栈选型 前端技术栈&#xff1a; Vue 3 Composition APITypeScriptPinia状态管理Vue Router 4Element Plus UI组件库Vite构建工具 后端技术栈&#xff1a; Node.js (Express/Koa)MongoDB (Mong…...

查看YOLO版本的三种方法

查看YOLO版本的三种方法&#xff1a; 一、通过命令行直接查询 使用Python交互式查询&#xff1a; from ultralytics import __version__ print(__version__) # 示例输出: 11.0.5二、检查PyTorch环境兼容性 import torch, ultralytics print(f"PyTorch: {torch.__versi…...

基于Docker的Bitwarden的私有本地部署

基于Docker的Bitwarden的私有本地部署 文章目录 基于Docker的Bitwarden的私有本地部署 本文首发地址 https://h89.cn/archives/355.html bitwarden 默认连接的是国外服务器 https://bitwarden.com/ &#xff0c;连接不是很稳定&#xff0c;也没有安全感&#xff0c;所以我选择了…...

点和体素哪个好

3D 深度学习中基于体素和基于点云的方法哪种更优&#xff1f;-腾讯云开发者社区-腾讯云 https://zhuanlan.zhihu.com/p/372497398 GitHub - open-mmlab/OpenPCDet: OpenPCDet Toolbox for LiDAR-based 3D Object Detection....

C++ STL编程 vector空间预留、vector高效删除、vector数据排序、vector代码练习

vector空间预留&#xff0c;作用是避免申请每次申请内存&#xff0c;提高运行效率。 对应的接口是 vector.reverse() vector的高效删除&#xff0c;对应的代码见下&#xff0c;一个时间复杂度是n&#xff0c;一个时间复杂度是1 #include<iostream> #include<vector…...

Android架构模式推荐及分析和MVC架构模式制作一个简单的底部tab切换

目录 主流架构模式对比 适用场景 MVP‌&#xff1a;团队协作开发,需要高可测试性的项目 MVC架构模式制作一个简单的底部tab切换 &#xff08;Model-View-Controller&#xff09;结构 代码 效果 主流架构模式对比 ‌对比维度‌‌MVC‌ ‌MVP‌ ‌MVVM‌ ‌MVI‌ ‌学习…...

【PVE】ProxmoxVE8虚拟机,存储管理(host磁盘扩容,qcow2/vmdk导入vm,vm磁盘导出与迁移等)

【PVE】ProxmoxVE8虚拟机&#xff0c;存储管理&#xff08;host磁盘扩容&#xff0c;qcow2/vmdk导入vm&#xff0c;vm磁盘导出与迁移等&#xff09; 文章目录 1、host 磁盘扩容2、qcow2/vmdk导入vm3、vm 磁盘导出与迁移 1、host 磁盘扩容 如何给host扩容磁盘&#xff0c;如增加…...

【JEECG 组件扩展】JSwitch开关组件扩展单个多选框样式

功能说明&#xff1a; 基于JeecgBoot开源框架&#xff0c;JSwitch开关组件扩展&#xff0c;支持单个多选样式。 效果展示&#xff1a; 使用示例&#xff1a; {field: JSwitch,component: JSwitch,label: JSwitch,},{field: JSwitchCheckBox,component: JSwitch,label: JSwitch…...

卷积神经网络-从零开始构建一个卷积神经网络

目录 一、什么是卷积神经网络CNN 1.1、核心概念 1.2、卷积层 二、什么是卷积计算 2.1、卷积计算的例子: 2.2、点积 2.3、卷积与点积的关系 2.4、Padding(填充) 2.4.1、Padding的主要作用 1、控制输出特征图尺寸 2、保留边缘信息 3. 支持深层网络训练 2.4.2、Str…...

Linux 常用命令集合

以下是一份 Linux 常用命令集合&#xff0c;涵盖文件操作、系统管理、网络管理、权限管理、进程管理等常见任务&#xff0c;并附上代码示例&#xff1a; 1. 文件与目录操作 命令作用示例ls列出目录内容ls -l&#xff08;详细列表&#xff09; ls -a&#xff08;显示隐藏文件&a…...

STM32f103 标准库 零基础学习之按键点灯(不涉及中断)

注意&#xff0c;此次代码不涉及中断&#xff0c;不涉及中断&#xff0c;不涉及中断 目录 1.初始化LED 2.初始化按键 3.粗略的延时函数 4.判断引脚电平 5.通过异或反转电平 开始 │ ├── 初始化LED&#xff08;GPIOA Pin1 推挽输出&#xff09; ├── 初始化按键&…...

【c++】【数据结构】二叉搜索树详解

目录 二叉搜索树的定义二叉搜索树的模拟实现查找函数循环版递归版 插入函数循环版递归版 删除函数循环版递归版 二叉搜索树的定义 二叉搜索树是一种特别的二叉树&#xff0c;是二叉树的搜索特化版。学过排序的都知道&#xff0c;在数组有序的情况下二分查找可以以极高的频率找…...

高精地图数据错误的侵权责任认定与应对之道

首席数据官高鹏律师团队 在自动驾驶与智慧交通快速发展的今天&#xff0c;高精地图作为核心基础设施&#xff0c;其数据准确性直接关系到公共安全。然而&#xff0c;技术并非完美&#xff0c;一旦因地图数据错误导致事故或损失&#xff0c;比如当自动驾驶汽车因高精地图数据错…...

Python训练营打卡——DAY22(2025.5.11)

复习日 学习参考如何使用kaggle平台&#xff0c;写下使用注意点&#xff0c;并对下述比赛提交代码 泰坦尼克号——来自灾难的机器学习 数据来源&#xff1a; kaggle泰坦里克号人员生还预测 挑战 泰坦尼克号沉没是历史上最臭名昭著的海难之一。 1912年4月15日&#xff0c;在被普…...

【计算机视觉】OpenCV实战项目 :Image_Cartooning_Web_App:基于深度学习的图像卡通化

Image_Cartooning_Web_App&#xff1a;基于深度学习的图像卡通化Web应用深度解析 1. 项目概述2. 技术原理与模型架构2.1 核心算法2.2 系统架构 3. 实战部署指南3.1 环境配置3.2 模型部署3.3 处理流程示例 4. 常见问题与解决方案4.1 模型加载失败4.2 显存溢出4.3 边缘伪影 5. 关…...