基于大核感知与非膨胀卷积的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×7或13×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
- 在
ultralytics/nn
下新建spp
f文件包,并新建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)))
- 在
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)
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. 结论与未来展望
本文针对YOLOv8中SPPF模块感受野受限的问题,提出了一种融合UniRepLK大核感知与非膨胀卷积的改进方案。通过引入多路径大核卷积、重参数化结构与通道注意力机制,显著提升了模型在复杂场景下的目标识别能力,尤其是在小目标检测方面表现出色。未来工作将进一步探索该模块在其他检测框架(如YOLO-NAS、RTMDet)中的泛化能力,并尝试结合Transformer结构实现更强大的全局建模能力。
相关文章:
基于大核感知与非膨胀卷积的SPPF改进—融合UniRepLK的YOLOv8目标检测创新架构
在当前目标检测领域中,YOLO系列模型因其优异的速度-精度平衡能力而被广泛部署于工业界与科研场景。YOLOv8作为该系列的最新版本,在主干网络与特征金字塔结构上进行了多项优化,进一步提升了其实时性与鲁棒性。然而,其核心组件—SPP…...
[Linux]从零开始的STM32MP157 Busybox根文件系统构建
一、前言 在上一篇教程中,已经教了大家如何使用Buildroot构建根文件系统,并且在最后我们已经完整的构建了一个可以运行的根文件系统。但是,Buildroot的集成度太高了,不利于小白理解根文件系统,所以本次教程,…...
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/ 第一步ÿ…...
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 # 临时进入容器安装࿰…...
Java基础语法之循环结构
循环结构 1.定义 控制一段代码重复执行多次 2.分类 2.1 for循环 2.1.1 定义 控制一段代码反复执行很多次。 2.1.2 for循环格式 for (初始化语句; 循环条件; 迭代语句) { 循环体语句(重复执行的代码); }示例 // 输出3次HelloWorld for (int i 0; i < 3; i) { System…...
冒泡排序的原理
冒泡排序是一种简单的排序算法,它通过重复地遍历待排序的列表,比较相邻的元素并交换它们的位置来实现排序。具体原理如下: 冒泡排序的基本思想 冒泡排序的核心思想是通过相邻元素的比较和交换,将较大的元素逐步“冒泡”到列表的…...
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、栈(Stack)1.2、堆(Heap) 2、堆内存管理结构2.1、内存分配器(MCache → MArena → MSpan → MHeap)2.2、大小分类(Size Class)2.3、分配流程 3、垃圾回收&a…...
分享一些资料供大家学习
群里收集来的,自己感觉还是比较经典的,希望大家喜欢!!! 20250428 夸克网盘分享一大波经典IT架构好货20250429夸克网盘分享精品文档-管理咨询师必备的思维模型20250430夸克网盘分享清华大学DeepSeek教程又来了《文科生A…...
RAGMCP基本原理说明和相关问题解惑
一、RAG架构原理和局限性 1.1 概念解释 RAG(Retrieval-Augmented Generation):检索增强生成,让大模型接受外部输入后,总结输出 向量数据库:向量数据通常是高维空间中的点,代表复杂的数据结构…...
PyGame游戏开发(含源码+演示视频+开结题报告+设计文档)
前言: 大二小学期python课上基于pygame做的一个游戏小demo,当时老师花了一天讲解了下python基础语法后(也是整个大学四年唯一学习python的时间),便让我们自学网课一周然后交项目,所以做的非常仓促ÿ…...
Git标签
Git标签 1. 添加标签 使用 tag 命令可以给某次 commit 提交的版本打上标签,相当于这个 commit id 的别名,在实践中,会使用 v1.0 之类的标签提示这是正式版的第一个版本。 git tag v1.0 [commit id]缺省输入 commit id会给最新的一次提交打…...
USB学习【6】USB传输错误的处理
1.前言 我们从物理层到信号层,到协议层,他们分别在不同的层面完成不同的功能。 总结一下: 物理层实现了高低电平的检测。 信号层更进一步,通过一些方法,实现了二进制的传输。 协议层,因为可以二进制传输了…...
深入解析 Vision Transformer (ViT) 与其在计算机视觉中的应用
在近年来,深度学习尤其在计算机视觉领域取得了巨大的进展,而 Vision Transformer(ViT)作为一种新的视觉模型,它的表现甚至在许多任务中超过了传统的卷积神经网络(CNN),如 ResNet。在…...
《Go小技巧易错点100例》第三十一篇
本期分享: 1.Go struct内存对齐 2.使用空结构体(struct{})节省内存 Go struct内存对齐 在计算机系统中,CPU 访问内存时并不是逐字节读取的,而是以特定大小的块(通常为 4/8 字节)为单位进行读取。当数据的内存地址正…...
全栈项目实战:Vue3+Node.js开发博客系统
全栈项目实战:Vue3Node.js开发博客系统 一、项目架构设计 1. 技术栈选型 前端技术栈: Vue 3 Composition APITypeScriptPinia状态管理Vue Router 4Element Plus UI组件库Vite构建工具 后端技术栈: Node.js (Express/Koa)MongoDB (Mong…...
查看YOLO版本的三种方法
查看YOLO版本的三种方法: 一、通过命令行直接查询 使用Python交互式查询: 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/ ,连接不是很稳定,也没有安全感,所以我选择了…...
点和体素哪个好
3D 深度学习中基于体素和基于点云的方法哪种更优?-腾讯云开发者社区-腾讯云 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空间预留,作用是避免申请每次申请内存,提高运行效率。 对应的接口是 vector.reverse() vector的高效删除,对应的代码见下,一个时间复杂度是n,一个时间复杂度是1 #include<iostream> #include<vector…...
Android架构模式推荐及分析和MVC架构模式制作一个简单的底部tab切换
目录 主流架构模式对比 适用场景 MVP:团队协作开发,需要高可测试性的项目 MVC架构模式制作一个简单的底部tab切换 (Model-View-Controller)结构 代码 效果 主流架构模式对比 对比维度MVC MVP MVVM MVI 学习…...
【PVE】ProxmoxVE8虚拟机,存储管理(host磁盘扩容,qcow2/vmdk导入vm,vm磁盘导出与迁移等)
【PVE】ProxmoxVE8虚拟机,存储管理(host磁盘扩容,qcow2/vmdk导入vm,vm磁盘导出与迁移等) 文章目录 1、host 磁盘扩容2、qcow2/vmdk导入vm3、vm 磁盘导出与迁移 1、host 磁盘扩容 如何给host扩容磁盘,如增加…...
【JEECG 组件扩展】JSwitch开关组件扩展单个多选框样式
功能说明: 基于JeecgBoot开源框架,JSwitch开关组件扩展,支持单个多选样式。 效果展示: 使用示例: {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 常用命令集合,涵盖文件操作、系统管理、网络管理、权限管理、进程管理等常见任务,并附上代码示例: 1. 文件与目录操作 命令作用示例ls列出目录内容ls -l(详细列表) ls -a(显示隐藏文件&a…...
STM32f103 标准库 零基础学习之按键点灯(不涉及中断)
注意,此次代码不涉及中断,不涉及中断,不涉及中断 目录 1.初始化LED 2.初始化按键 3.粗略的延时函数 4.判断引脚电平 5.通过异或反转电平 开始 │ ├── 初始化LED(GPIOA Pin1 推挽输出) ├── 初始化按键&…...
【c++】【数据结构】二叉搜索树详解
目录 二叉搜索树的定义二叉搜索树的模拟实现查找函数循环版递归版 插入函数循环版递归版 删除函数循环版递归版 二叉搜索树的定义 二叉搜索树是一种特别的二叉树,是二叉树的搜索特化版。学过排序的都知道,在数组有序的情况下二分查找可以以极高的频率找…...
高精地图数据错误的侵权责任认定与应对之道
首席数据官高鹏律师团队 在自动驾驶与智慧交通快速发展的今天,高精地图作为核心基础设施,其数据准确性直接关系到公共安全。然而,技术并非完美,一旦因地图数据错误导致事故或损失,比如当自动驾驶汽车因高精地图数据错…...
Python训练营打卡——DAY22(2025.5.11)
复习日 学习参考如何使用kaggle平台,写下使用注意点,并对下述比赛提交代码 泰坦尼克号——来自灾难的机器学习 数据来源: kaggle泰坦里克号人员生还预测 挑战 泰坦尼克号沉没是历史上最臭名昭著的海难之一。 1912年4月15日,在被普…...
【计算机视觉】OpenCV实战项目 :Image_Cartooning_Web_App:基于深度学习的图像卡通化
Image_Cartooning_Web_App:基于深度学习的图像卡通化Web应用深度解析 1. 项目概述2. 技术原理与模型架构2.1 核心算法2.2 系统架构 3. 实战部署指南3.1 环境配置3.2 模型部署3.3 处理流程示例 4. 常见问题与解决方案4.1 模型加载失败4.2 显存溢出4.3 边缘伪影 5. 关…...