YOLOv8改进 | 2023 | SCConv空间和通道重构卷积(精细化检测,又轻量又提点)

news2025/1/13 7:52:30

一、本文介绍

本文给大家带来的改进内容是SCConv,即空间和通道重构卷积,是一种发布于2023.9月份的一个新的改进机制。它的核心创新在于能够同时处理图像的空间(形状、结构)和通道色彩、深度)信息,这样的处理方式使得SCConv在分析图像时更加精细和高效。这种技术不仅适用于复杂场景的图像处理,还能在普通的对象检测任务中提供更高的精确度(亲测在小目标检测和正常的物体检测中都有效提点)。SCConv的这种能力,特别是在处理大量数据和复杂图像时的优势。本文通过先介绍SCConv的基本网络结构和原理当大家对该卷积有一个大概的了解,然后教大家如何将该卷积添加到自己的网络结构中(值得一提的是该卷积的GFLOPs降低了0.3左右适合轻量化的读者) 

适用检测目标:所有的目标检测均有一定的提点

推荐指数:⭐⭐⭐⭐⭐

专栏回顾:YOLOv8改进系列专栏——本专栏持续复习各种顶会内容——科研必备    

训练结果对比图-> 

因为资源有限我发的文章都要做对比实验所以本次实验我只用了一百张图片检测的是火灾训练了一百个epoch,该结果只能展示出该机制有效,但是并不能产生决定性结果,因为具体的效果还要看你的数据集和实验环境所影响(这次找的数据集质量好像不太好效果波动很大)。  

大家可以看出mAP(50)提高了大概0.6左右(值得一提的是该卷积的GFLOPs降低了0.3左右适合轻量化的读者) 

44308abda9734a91ad908faca9a7fd5a.png

目录

一、本文介绍

二、网络结构讲解

2.1 SCConv的主要思想

2.2 空间重构单元(SRU)

2.3 通道重构单元(CRU)

三、SCConv代码

3.1 SCConv本地代码

3.2 在SCConv外层套用函数

3.3 修改了SCConv的C2f和Bottleneck模块

四、手把手教你添加SCConv和C2f_SCConv模块

4.1 SCConv的添加教程

4.2 SCConv的yaml文件和训练截图

4.2.1 SCConv的yaml文件

4.2.2 SCConv的训练过程截图 

五、SCConv可添加的位置

5.1 推荐SCConv可添加的位置 

5.2 图示SCConv可添加的位置 

六、本文总结


 二、网络结构讲解

51a53656d50a4c3d8715d8357595201d.png

论文地址:官方论文地址

代码地址:官方代码地址

107067b614d447b58528d6c435965dd2.png


2.1 SCConv的主要思想

SCConv(空间和通道重构卷积的高效卷积模块,以减少卷积神经网络(CNN)中的空间和通道冗余。SCConv旨在通过优化特征提取过程,减少计算资源消耗并提高网络性能。该模块包括两个单元:

1.空间重构单元(SRU):SRU通过分离和重构方法来减少空间冗余。

2.通道重构单元(CRU):CRU采用分割-变换-融合策略来减少通道冗余。

下面是SCConv的结构示意图->

c0aa4cd5b2f24a59b39a078abc29e91d.png

下面我将分别解释这两个单元->


2.2 空间重构单元(SRU)

空间重构单元(SRU)是SCConv模块的一部分,负责减少特征在空间维度上的冗余。SRU接收输入特征,并通过以下步骤处理:

1. 组归一化(Group Normalization):首先对输入特征进行归一化,以减少不同特征图之间的尺度差异。
2. 权重生成:通过应用归一化和激活函数,如Sigmoid,从归一化的特征图中生成权重。
3. 特征分离:根据生成的权重,对输入特征进行分离,形成多个子特征集。
4. 特征重构:最后,这些分离出来的特征集经过变换和重组,产生空间精炼的特征输出,以便进一步处理。

6c0b287f19104d6cad1a886d2fd587b9.png

上图展示了空间重构单元(SRU)的架构。SRU的工作流程如下:

1. 输入特征X:首先进行组归一化(GN)处理。
2. 分离:通过一系列的权重 eq?W_%7B1%7D, eq?W_%7B2%7D, ..., eq?W_%7BC%7D对特征进行加权,这些权重是通过输入特征的通道eq?%5Cgamma_1%2C%20%5Cgamma_2%2C%20...%2C%20%5Cgamma_c 经过归一化和非线性激活函数(如Sigmoid)计算得到的。
3. 重构:加权后的特征被分割成两个部分 eq?X_%7BW%7D%5E%7B1%7Deq?X_%7BW%7D%5E%7B2%7D,然后这两部分各自经过变换,最终通过加法和拼接操作重构,得到空间精炼特征eq?X_%7BW%7D

总结:这个单元的设计目的是为了减少输入特征的空间冗余,从而提高卷积神经网络处理特征的效率。


2.3 通道重构单元(CRU)

通道重构单元(CRU)是SCConv模块的一部分,旨在减少卷积神经网络特征的通道冗余。CRU对经过空间重构单元(SRU)处理后的特征进一步操作,通过以下步骤减少通道冗余:

f3d201d671a64fcbbea33a99438fb3d8.png

上图详细展示了通道重构单元(CRU)的架构,该单元从空间精炼特征 \( X^W \) 开始进行处理。CRU的工作流程包括以下几个步骤:

1. 分割(Split):特征 eq?X%5E%7BW%7D 被分割成两部分,通过不同比例的eq?%5Calphaeq?%281-%5Calpha%29 路径进行不同的1x1卷积处理。
2. 变换(Transform):通过全局卷积(GWC)和点卷积(PWC)进一步变换这两部分特征。
3. 融合(Fuse):两个变换后的特征 eq?Y_%7B1%7Deq?Y_%7B2%7D 经过池化和SoftMax加权融合,形成最终的通道精炼特征 eq?Y

总结:这种结构旨在通过细致地处理各个通道,减少不必要的信息,并提高网络的整体性能和效率。通过这一过程,CRU有效地提高了特征的表征效率,同时减少了模型的参数数量和计算成本。


三、SCConv代码

3.1 SCConv核心代码

该代码为SCConv的本体,使用方式请看章节四。

import torch
import torch.nn.functional as F
import torch.nn as nn


class GroupBatchnorm2d(nn.Module):
    def __init__(self, c_num: int,
                 group_num: int = 16,
                 eps: float = 1e-10
                 ):
        super(GroupBatchnorm2d, self).__init__()
        assert c_num >= group_num
        self.group_num = group_num
        self.weight = nn.Parameter(torch.randn(c_num, 1, 1))
        self.bias = nn.Parameter(torch.zeros(c_num, 1, 1))
        self.eps = eps

    def forward(self, x):
        N, C, H, W = x.size()
        x = x.view(N, self.group_num, -1)
        mean = x.mean(dim=2, keepdim=True)
        std = x.std(dim=2, keepdim=True)
        x = (x - mean) / (std + self.eps)
        x = x.view(N, C, H, W)
        return x * self.weight + self.bias


class SRU(nn.Module):
    def __init__(self,
                 oup_channels: int,
                 group_num: int = 16,
                 gate_treshold: float = 0.5,
                 torch_gn: bool = True
                 ):
        super().__init__()

        self.gn = nn.GroupNorm(num_channels=oup_channels, num_groups=group_num) if torch_gn else GroupBatchnorm2d(
            c_num=oup_channels, group_num=group_num)
        self.gate_treshold = gate_treshold
        self.sigomid = nn.Sigmoid()

    def forward(self, x):
        gn_x = self.gn(x)
        w_gamma = self.gn.weight / sum(self.gn.weight)
        w_gamma = w_gamma.view(1, -1, 1, 1)
        reweigts = self.sigomid(gn_x * w_gamma)
        # Gate
        w1 = torch.where(reweigts > self.gate_treshold, torch.ones_like(reweigts), reweigts)  # 大于门限值的设为1,否则保留原值
        w2 = torch.where(reweigts > self.gate_treshold, torch.zeros_like(reweigts), reweigts)  # 大于门限值的设为0,否则保留原值
        x_1 = w1 * x
        x_2 = w2 * x
        y = self.reconstruct(x_1, x_2)
        return y

    def reconstruct(self, x_1, x_2):
        x_11, x_12 = torch.split(x_1, x_1.size(1) // 2, dim=1)
        x_21, x_22 = torch.split(x_2, x_2.size(1) // 2, dim=1)
        return torch.cat([x_11 + x_22, x_12 + x_21], dim=1)


class CRU(nn.Module):
    '''
    alpha: 0<alpha<1
    '''

    def __init__(self,
                 op_channel: int,
                 alpha: float = 1 / 2,
                 squeeze_radio: int = 2,
                 group_size: int = 2,
                 group_kernel_size: int = 3,
                 ):
        super().__init__()
        self.up_channel = up_channel = int(alpha * op_channel)
        self.low_channel = low_channel = op_channel - up_channel
        self.squeeze1 = nn.Conv2d(up_channel, up_channel // squeeze_radio, kernel_size=1, bias=False)
        self.squeeze2 = nn.Conv2d(low_channel, low_channel // squeeze_radio, kernel_size=1, bias=False)
        # up
        self.GWC = nn.Conv2d(up_channel // squeeze_radio, op_channel, kernel_size=group_kernel_size, stride=1,
                             padding=group_kernel_size // 2, groups=group_size)
        self.PWC1 = nn.Conv2d(up_channel // squeeze_radio, op_channel, kernel_size=1, bias=False)
        # low
        self.PWC2 = nn.Conv2d(low_channel // squeeze_radio, op_channel - low_channel // squeeze_radio, kernel_size=1,
                              bias=False)
        self.advavg = nn.AdaptiveAvgPool2d(1)

    def forward(self, x):
        # Split
        up, low = torch.split(x, [self.up_channel, self.low_channel], dim=1)
        up, low = self.squeeze1(up), self.squeeze2(low)
        # Transform
        Y1 = self.GWC(up) + self.PWC1(up)
        Y2 = torch.cat([self.PWC2(low), low], dim=1)
        # Fuse
        out = torch.cat([Y1, Y2], dim=1)
        out = F.softmax(self.advavg(out), dim=1) * out
        out1, out2 = torch.split(out, out.size(1) // 2, dim=1)
        return out1 + out2


class ScConv(nn.Module):
    def __init__(self,
                 op_channel: int,
                 group_num: int = 4,
                 gate_treshold: float = 0.5,
                 alpha: float = 1 / 2,
                 squeeze_radio: int = 2,
                 group_size: int = 2,
                 group_kernel_size: int = 3,
                 ):
        super().__init__()
        self.SRU = SRU(op_channel,
                       group_num=group_num,
                       gate_treshold=gate_treshold)
        self.CRU = CRU(op_channel,
                       alpha=alpha,
                       squeeze_radio=squeeze_radio,
                       group_size=group_size,
                       group_kernel_size=group_kernel_size)

    def forward(self, x):
        x = self.SRU(x)
        x = self.CRU(x)
        return x


if __name__ == '__main__':
    x = torch.randn(1, 32, 16, 16)
    model = ScConv(32)
    print(model(x).shape)


3.2 在SCConv外层套用函数代码

因为以上的代码不能够直接使用在我们的YOLOv8中会报错而且参数对不上,我对其外层嵌套了一个模块。 

class SCConv_yolov8(nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size=1, stride=1, g=1, dilation=1):
        super().__init__()
        self.conv = Conv(in_channels, out_channels, k=1)

        self.RFAConv = ScConv(out_channels)

        self.bn = nn.BatchNorm2d(out_channels)

        self.gelu = nn.GELU()

    def forward(self, x):
        x = self.conv(x)

        x = self.RFAConv(x)

        x = self.gelu(self.bn(x))
        return x


3.3 修改了SCConv的C2f和Bottleneck模块

class Bottleneck_SCConv(nn.Module):
    """Standard bottleneck."""

    def __init__(self, c1, c2, shortcut=True, g=1, k=(3, 3), e=0.5):
        """Initializes a bottleneck module with given input/output channels, shortcut option, group, kernels, and
        expansion.
        """
        super().__init__()
        c_ = int(c2 * e)  # hidden channels
        self.cv1 = Conv(c1, c_, k[0], 1)
        self.cv2 = SCConv_yolov8(c_, c2, k[1], 1, g=g)
        self.add = shortcut and c1 == c2

    def forward(self, x):
        """'forward()' applies the YOLO FPN to input data."""
        return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x))


class C2f_SCConv(nn.Module):
    """Faster Implementation of CSP Bottleneck with 2 convolutions."""
    def __init__(self, c1, c2, n=1, shortcut=False, g=1, e=0.5):
        """Initialize CSP bottleneck layer with two convolutions with arguments ch_in, ch_out, number, shortcut, groups,
        expansion.
        """
        super().__init__()
        self.c = int(c2 * e)  # hidden channels
        self.cv1 = Conv(c1, 2 * self.c, 1, 1)
        self.cv2 = Conv((2 + n) * self.c, c2, 1)  # optional act=FReLU(c2)
        self.m = nn.ModuleList(Bottleneck_SCConv(self.c, self.c, shortcut, g, k=((3, 3), (3, 3)), e=1.0) for _ in range(n))

    def forward(self, x):
        """Forward pass through C2f layer."""
        x = self.cv1(x)
        x = x.chunk(2, 1)
        y = list(x)
        # y = list(self.cv1(x).chunk(2, 1))
        y.extend(m(y[-1]) for m in self.m)
        return self.cv2(torch.cat(y, 1))

    def forward_split(self, x):
        """Forward pass using split() instead of chunk()."""
        y = list(self.cv1(x).split((self.c, self.c), 1))
        y.extend(m(y[-1]) for m in self.m)
        return self.cv2(torch.cat(y, 1))


四、手把手教你添加SCConv和C2f_SCConv模块

4.1 SCConv的添加教程

添加教程这里不再重复介绍、因为专栏内容有许多,添加过程又需要截特别图片会导致文章大家读者也不通顺如果你已经会添加注意力机制了,可以跳过本章节,如果你还不会,大家可以看我下面的文章,里面详细的介绍了拿到一个任意机制(C2f、Conv、Bottleneck、Loss、DetectHead)如何添加到你的网络结构中去。

这个卷积也可以放在C2f和Bottleneck中进行使用可以即插即用,个人觉得放在Bottleneck中效果比较好。

添加教程->YOLOv8改进 | 如何在网络结构中添加注意力机制、C2f、卷积、Neck、检测头


4.2 SCConv的yaml文件和训练截图

4.2.1 SCConv的yaml文件

下面的配置文件为我修改的SCConv的位置。

# 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 GFLOPs
  s: [0.33, 0.50, 1024]  # YOLOv8s summary: 225 layers, 11166560 parameters, 11166544 gradients,  28.8 GFLOPs
  m: [0.67, 0.75, 768]   # YOLOv8m summary: 295 layers, 25902640 parameters, 25902624 gradients,  79.3 GFLOPs
  l: [1.00, 1.00, 512]   # YOLOv8l summary: 365 layers, 43691520 parameters, 43691504 gradients, 165.7 GFLOPs
  x: [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, [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_SCConv, [256]]  # 15 (P3/8-small)

  - [-1, 1, Conv, [256, 3, 2]]
  - [[-1, 12], 1, Concat, [1]]  # cat head P4
  - [-1, 3, C2f_SCConv, [512]]  # 18 (P4/16-medium)

  - [-1, 1, Conv, [512, 3, 2]]
  - [[-1, 9], 1, Concat, [1]]  # cat head P5
  - [-1, 3, C2f_SCConv, [1024]]  # 21 (P5/32-large)

  - [[15, 18, 21], 1, Detect, [nc]]  # Detect(P3, P4, P5)


4.2.2 SCConv的训练过程截图 

下面是添加了SCConv的训练截图。

下面的是将SCConv机制添加到了C2f和Bottleneck。

(最近有人说我改的代码是没有发全的,我不知道这群人是怎么说出这种话的,希望大家如果用我的代码成功的可以在评论区支持一下,我也好发更多的改进毕竟免费给大家看。同时有问题皆可在评论区留言我看到都会回复) 

bffb59f35cec47e5ae19b71e10294b4b.png​​​


五、SCConv可添加的位置

5.1 推荐SCConv可添加的位置 

SCConv是一种即插即用的模块,其可以添加的位置有很多,添加的位置不同效果也不同,所以我下面推荐几个添加的位,置大家可以进行参考,当然不一定要按照我推荐的地方添加。

  1. 残差连接中:在残差网络的残差连接中加入SCConv

  2. Neck部分:YOLOv8的Neck部分负责特征融合,这里添加修改后的C2f_SCConv可以帮助模型更有效地融合不同层次的特征。

  3. 检测头中的卷积:在最终的输出层前加入SCConv可以使模型在做出最终预测之前,更加集中注意力于最关键的特征。

文字大家可能看我描述不太懂,大家可以看下面的网络结构图中我进行了标注。


5.2 图示SCConv可添加的位置 

2949694815404620bdfb5875286c8e73.png​​​


六、本文总结

到此本文的正式分享内容就结束了,在这里给大家推荐我的YOLOv8改进有效涨点专栏,本专栏目前为新开的平均质量分98分,后期我会根据各种最新的前沿顶会进行论文复现,也会对一些老的改进机制进行补充,目前本专栏免费阅读(暂时,大家尽早关注不迷路~),如果大家觉得本文帮助到你了,订阅本专栏,关注后续更多的更新~

专栏回顾:YOLOv8改进系列专栏——本专栏持续复习各种顶会内容——科研必备

3d51a0611af1442f833362eaf18fbae2.gif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1274505.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

中国毫米波雷达产业分析5——毫米波雷达应用案例介绍

一、上海某区康养标杆工程 项目甲方&#xff1a;上海某康养中心 项目地点&#xff1a;上海徐汇区 项目时间&#xff1a;2023年8月 供应商&#xff1a;南京苗米科技有限公司 &#xff08;一&#xff09;项目需求 该康养社区集中收治了区内75岁以上老龄化人群和部分阿尔茨海默…

RubyMine 2023 年下载、安装、使用教程,详细图解

大家好&#xff0c;今天为大家带来的是RubyMine 2023 年下载、安装、使用教程&#xff0c;详细图解。 文章目录 1 RubyMine 简介2 RubyMine 下载、安装教程RubyMine 下载RubyMine 安装 3 RubyMine 汉化4. 常用快捷键一级必会二级进阶 1 RubyMine 简介 RubyMine 是一个为 Ruby …

CRM系统:让企业商机管理变得轻松愉快

传统企业的经常出现团队分工不合理、实施过程不可见、进度难以把控等情况。这样不仅会让项目实施周期变长&#xff0c;还会导致客户满意度降低&#xff0c;给企业的发展带来了不好的影响。因此&#xff0c;进行商机管理至关重要。那么&#xff0c;CRM系统如何进行企业的商机阶段…

做热衷的事情,看向往的风景,遇见更多美好,早安

①‍ ʍօʀռɨռɢ ☼ (˘͈ᵕ ˘͈❀) ♡ ༘⋆ 岁月覆盖成长&#xff0c;而你愈发完满&#xff1b; 做热衷的事情&#xff0c;看向往的风景。 每天醒来将微笑别在衣襟&#xff0c; 就会遇见更多的美好事物。早安&#x1f324;️ ②生活就是这样&#xff0c;边失去边补偿&…

Redis7--基础篇5(管道、发布订阅)

管道是什么 管道(pipeline)可以一次性发送多条命令给服务端&#xff0c;服务端依次处理完完毕后&#xff0c;通过一条响应一次性将结果返回&#xff0c;通过减少客户端与redis的通信次数来实现降低往返延时时间。pipeline实现的原理是队列&#xff0c;先进先出特性就保证数据的…

【数据结构】—AVL树(C++实现)

&#x1f3ac;慕斯主页&#xff1a;修仙—别有洞天 &#x1f49c;本文前置知识&#xff1a; 搜索二叉树 ♈️今日夜电波&#xff1a;Letter Song—ヲタみん 1:36━━━━━━️&#x1f49f;──────── 5:35 …

TikTok美食狂潮:短视频如何塑造食物文化新趋势

短视频不仅成为分享美食的平台&#xff0c;更是塑造了一种全新的食物文化趋势。本文将深入探讨TikTok如何通过短视频影响食物文化&#xff0c;并推动美食体验的创新。 创意美食视频的崛起 传统的美食呈现方式通常通过图片或文字&#xff0c;而短视频带来了全新的美食呈现方式。…

ESP32-Web-Server编程- 使用表格(Table)实时显示设备信息

ESP32-Web-Server编程- 使用表格&#xff08;Table&#xff09;实时显示设备信息 概述 上节讲述了通过 Server-Sent Events&#xff08;以下简称 SSE&#xff09; 实现在网页实时更新 ESP32 Web 服务器的传感器数据。 本节书接上会&#xff0c;继续使用 SSE 机制在网页实时显…

(2)(2.2) Lightware SF45/B(350度)

文章目录 前言 1 安装SF45/B 2 连接自动驾驶仪 3 通过地面站进行配置 4 参数说明 前言 Lightware SF45/B 激光雷达(Lightware SF45/B lidar)是一种小型扫描激光雷达&#xff08;重约 50g&#xff09;&#xff0c;扫描度可达 350 度&#xff0c;扫描范围 50m。 1 安装SF45…

CRM系统:实现精细化的客户管理,提升客户满意度

近年来&#xff0c;CRM系统在国内企业的普及度逐渐提高&#xff0c;越来越多的企业选择使用CRM系统来管理客户关系&#xff0c;优化业务流程。那么&#xff0c;CRM系统到底有什么魔力&#xff0c;让众多企业青睐呢&#xff1f;下面我们来说说&#xff0c;为什么建议使用CRM系统…

同一个公众号下的同一个用户,openid不一致?

背景 公众号授权页面&#xff0c;前端采用的snsapi_userinfo&#xff0c;在用户尚未点击“获取完整性服务”的时候&#xff0c;服务端通过前端的code拿到了一个openid。在用户点击了“获取完整性服务”之后&#xff0c;服务端通过前端的code拿到了另一个openid。同一个用户在同…

计算机网络之Socket编程

文章目录 前言一、Socket编程二、TCP套接字编程三、UDP套字编程总结 前言 TCP、UDP套接字编程 一、Socket编程 应用进程使用传输层提供的服务才能够交换报文&#xff0c;实现应用协议&#xff0c;实现应用 TCP/IP&#xff1a;应用进程使用Socket API访问传输服务地点&#xff…

11-30 SpringBoot

内嵌的tomcat tomcat的依赖 对于tomcat其实还是一个jar包 spring是一个IOC容器 tomcat的核心对象交给Spring容器 调用核心对象方法 启动Tomcat 1.添加依赖 tomcat-embed-core&#xff0c;叫做tomcat内嵌核心。就是这个东西把tomcat功能引入到了我们的程序中的 排除tomcat&a…

改造python3中的http.server为简单的文件下载服务

改造 修改python3中的http.server.SimpleHTTPRequestHandler&#xff0c;实现简单的文件上传下载服务 simple_http_file_server.py&#xff1a; # !/usr/bin/env python3import datetime import email import html import http.server import io import mimetypes import os …

游戏反Frida注入检测方案

在游戏安全对抗过程中&#xff0c;有不少外挂的实现基于对游戏内存模块进行修改&#xff0c;这类外挂通常会使用内存修改器&#xff0c;除此之外&#xff0c;还有一种门槛相对更高、也更难检测的「注入挂」。 据FairGuard游戏安全数据统计&#xff0c;在游戏面临的众多安全风险…

uniapp微信小程序实现地图展示控件

最终实现效果&#xff1a; 地图上展示控件&#xff0c;并可以点击。 目录 一、前言 二、在地图上展示控件信息 点击后可进行绘制面图形 1.使用cover-view将控件在地图上展示 2.设置控件样式&#xff0c;使用好看的图标 3.控件绑定点击事件 一、前言 原本使用的是control…

应用于智慧城管的AI边缘盒子+AI算法一体化解决方案

智慧城管支持十几种城市违规违法场景的识别&#xff0c;覆盖着市容环境、街面秩序、宣传广告、市政设施等类别&#xff0c;能够在很大程度上引导责任单位进行自动整改和自治&#xff0c;积极引导市民加强自我约束、自我教育、自我管理&#xff0c;努力增强市民参与城市管理的责…

Maya 2024(3D建模、动画和渲染软件)

Maya 2024是一款非常强大的3D建模、动画和渲染软件&#xff0c;它提供了许多新功能和改进&#xff0c;以帮助建模师、动画师和渲染师更加高效地进行创作。 在建模方面&#xff0c;Maya 2024引入了Symmetry&#xff08;对称&#xff09;功能&#xff0c;可以在网格两侧生成均匀…

(分类)KNN算法- 参数调优

在此专栏的上一篇文章的基础上&#xff0c;进行交叉实验获取最佳的K值 上一篇文章&#xff1a;KNN算法案例-鸢尾花分类 数据拆分的过程&#xff1a; 交叉验证&#xff08;Cross Validation&#xff09; 是一种在机器学习中广泛使用的模型评估和参数调优方法。在训练模型时&…

设计模式精讲:掌握工厂方法与抽象工厂的精髓

设计模式精讲&#xff1a;掌握工厂方法与抽象工厂的精髓 一、引言&#xff1a;如何学习设计模式&#xff1f;二、工厂方法&#xff08;也叫工厂模式&#xff09;2.1、代码结构2.2、符合的设计原则2.3、小结 三、抽象工厂3.1、代码结构3.2、符合的设计原则3.3、小结 总结 一、引…