YOLOv8改进 | 卷积模块 | SAConv可切换空洞卷积
秋招面试专栏推荐 :深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转
💡💡💡本专栏所有程序均经过测试,可成功执行💡💡💡
专栏目录 :《YOLOv8改进有效涨点》专栏介绍 & 专栏目录 | 目前已有40+篇内容,内含各种Head检测头、损失函数Loss、Backbone、Neck、NMS等创新点改进——点击即可跳转
许多现代目标检测器通过使用“观察和思考两次”的机制展现了卓越的性能。我们在目标检测的主干设计中探讨了这种机制。在宏观层面上,提出了递归特征金字塔(Recursive Feature Pyramid),它将额外的反馈连接从特征金字塔网络整合到底向上的主干层中。在微观层面上,提出了可切换空洞卷积(Switchable Atrous Convolution),它用不同的空洞率对特征进行卷积,并使用切换函数收集结果。将它们结合起来就得到了DetectoRS,它显著提高了目标检测的性能。 文章在介绍主要的原理后,将手把手教学如何进行模块的代码添加和修改,并将修改后的完整代码放在文章的最后,方便大家一键运行,小白也可轻松上手实践。以帮助您更好地学习深度学习目标检测YOLO系列的挑战。
目录
1. 原理
2. 将PConv添加到YOLOv8代码
2.1 PConv代码实现
2.2 更改init.py文件
2.3 新增yaml文件
2.4 注册模块
2.5 执行程序
3. 完整代码分享
4. GFLOPs
5. 进阶
6. 总结
1. 原理
论文地址:DetectoRS: Detecting Objects with Recursive Feature Pyramid and Switchable Atrous Convolutio——点击即可跳转
官方代码:官方代码仓库——点击即可跳转
可切换空洞卷积 (SAC) 是一种复杂的卷积技术,用于增强深度学习模型的性能,特别是在对象检测和分割等任务中。以下是根据提供的文档对其主要原理的细分:
空洞卷积
空洞卷积,也称为扩张卷积,用于增加过滤器的视野,而不会增加参数数量或计算量。这是通过在连续的过滤器值之间引入零来实现的。插入这些零的速率称为空洞速率 ( r )。对于大小为 的过滤器,有效内核大小变为 ( k + (k-1)(r-1) )。这允许网络捕获多尺度信息,这对于检测不同大小的物体特别有用。
可切换空洞卷积 (SAC)
SAC 以空洞卷积为基础,引入了一种在卷积操作期间动态切换不同空洞率的机制。其核心思想是允许卷积层根据输入特征自适应地选择适当的空洞率。这种适应性有助于模型更好地处理同一图像中不同尺度的对象。
SAC 的组件
SAC 由三个主要组件组成:主 SAC 组件和两个附加在 SAC 组件之前和之后的全局上下文模块。
-
主 SAC 组件:这是实际发生可切换空洞卷积的核心部分。它涉及两个具有不同空洞率的卷积操作的加权组合。
SAC 的数学公式如下: 其中:
-
( x ) 是输入。
-
和
是卷积运算的权重。
-
( r ) 是空洞率。
-
是一个开关函数,实现为一个平均池化层,具有 5x5 内核,后跟一个 1x1 卷积层,确定两个卷积运算之间的平衡。
-
全局上下文模块:这些模块在 SAC 操作前后为特征添加了图像级上下文,增强了模型理解图像全局结构的能力。
SAC的优势
-
多尺度检测:通过动态切换不同的空洞率,SAC 使模型能够更好地检测各种尺寸的物体。
-
参数效率:SAC 在不增加额外参数的情况下增加了感受野,同时保持了计算效率。
-
适应性:切换功能允许卷积层根据输入进行适应,使模型更加灵活,能够处理不同的图像和物体尺度。
实现示例

骨干网络(例如 ResNet)中的每个 3x3 卷积层都转换为 SAC,然后执行具有不同空洞率的卷积的加权组合。
综上所述,可切换空洞卷积结合了空洞卷积和动态适应性的优点,增强了深度学习模型,提高了其处理不同物体尺度图像的能力,同时保持参数和计算方面的效率。
2. 将PConv添加到YOLOv8代码
2.1 PConv代码实现
关键步骤一:将下面代码粘贴到在/ultralytics/ultralytics/nn/modules/conv.py中,并在该文件的__all__中添加“SAConv”
class ConvAWS2d(nn.Conv2d):def __init__(self,in_channels,out_channels,kernel_size,stride=1,padding=0,dilation=1,groups=1,bias=True):super().__init__(in_channels,out_channels,kernel_size,stride=stride,padding=padding,dilation=dilation,groups=groups,bias=bias)self.register_buffer('weight_gamma', torch.ones(self.out_channels, 1, 1, 1))self.register_buffer('weight_beta', torch.zeros(self.out_channels, 1, 1, 1))def _get_weight(self, weight):weight_mean = weight.mean(dim=1, keepdim=True).mean(dim=2,keepdim=True).mean(dim=3, keepdim=True)weight = weight - weight_meanstd = torch.sqrt(weight.view(weight.size(0), -1).var(dim=1) + 1e-5).view(-1, 1, 1, 1)weight = weight / stdweight = self.weight_gamma * weight + self.weight_betareturn weightdef forward(self, x):weight = self._get_weight(self.weight)return super()._conv_forward(x, weight, None)def _load_from_state_dict(self, state_dict, prefix, local_metadata, strict,missing_keys, unexpected_keys, error_msgs):self.weight_gamma.data.fill_(-1)super()._load_from_state_dict(state_dict, prefix, local_metadata, strict,missing_keys, unexpected_keys, error_msgs)if self.weight_gamma.data.mean() > 0:returnweight = self.weight.dataweight_mean = weight.data.mean(dim=1, keepdim=True).mean(dim=2,keepdim=True).mean(dim=3, keepdim=True)self.weight_beta.data.copy_(weight_mean)std = torch.sqrt(weight.view(weight.size(0), -1).var(dim=1) + 1e-5).view(-1, 1, 1, 1)self.weight_gamma.data.copy_(std)class SAConv2d(ConvAWS2d):def __init__(self,in_channels,out_channels,kernel_size,s=1,p=None,g=1,d=1,act=True,bias=True):super().__init__(in_channels,out_channels,kernel_size,stride=s,padding=autopad(kernel_size, p),dilation=d,groups=g,bias=bias)self.switch = torch.nn.Conv2d(self.in_channels,1,kernel_size=1,stride=s,bias=True)self.switch.weight.data.fill_(0)self.switch.bias.data.fill_(1)self.weight_diff = torch.nn.Parameter(torch.Tensor(self.weight.size()))self.weight_diff.data.zero_()self.pre_context = torch.nn.Conv2d(self.in_channels,self.in_channels,kernel_size=1,bias=True)self.pre_context.weight.data.fill_(0)self.pre_context.bias.data.fill_(0)self.post_context = torch.nn.Conv2d(self.out_channels,self.out_channels,kernel_size=1,bias=True)self.post_context.weight.data.fill_(0)self.post_context.bias.data.fill_(0)self.bn = nn.BatchNorm2d(out_channels)self.act = nn.SiLU() if act is True else (act if isinstance(act, nn.Module) else nn.Identity())def forward(self, x):# pre-contextavg_x = torch.nn.functional.adaptive_avg_pool2d(x, output_size=1)avg_x = self.pre_context(avg_x)avg_x = avg_x.expand_as(x)x = x + avg_x# switchavg_x = torch.nn.functional.pad(x, pad=(2, 2, 2, 2), mode="reflect")avg_x = torch.nn.functional.avg_pool2d(avg_x, kernel_size=5, stride=1, padding=0)switch = self.switch(avg_x)# sacweight = self._get_weight(self.weight)out_s = super()._conv_forward(x, weight, None)ori_p = self.paddingori_d = self.dilationself.padding = tuple(3 * p for p in self.padding)self.dilation = tuple(3 * d for d in self.dilation)weight = weight + self.weight_diffout_l = super()._conv_forward(x, weight, None)out = switch * out_s + (1 - switch) * out_lself.padding = ori_pself.dilation = ori_d# post-contextavg_x = torch.nn.functional.adaptive_avg_pool2d(out, output_size=1)avg_x = self.post_context(avg_x)avg_x = avg_x.expand_as(out)out = out + avg_xreturn self.act(self.bn(out))
可切换空洞卷积 (SAconv) 通过动态调整卷积层中的空洞率来增强图像处理,从而实现更有效的多尺度特征提取。 SAconv 处理图像的主要工作流程概述:
SAconv 的主要工作流程
-
输入图像: 该过程从输入到神经网络的输入图像开始。
-
初始卷积层: 图像首先经过几个标准卷积层,提取边缘、纹理和基本形状等低级特征。这些层通常具有固定的内核大小和步长值。
-
可切换空洞卷积 (SAC) 模块: 核心组件 SAC 模块取代了网络主干中的传统卷积层(例如 ResNet)。以下是 SAC 操作的详细分解:
-
特征提取: 输入特征 ( x ) 首先通过两个不同的卷积操作进行处理,权重分别为 ( w ) 和
,其中
表示对权重的调整。这些卷积具有不同的空洞率,使它们能够捕获多个尺度的特征。
-
切换函数: 切换函数 S(x) 确定两个卷积之间的平衡。它通常实现为具有 5x5 内核的平均池化层,后跟 1x1 卷积层。切换函数的输出是一组权重,用于平衡两个卷积的贡献。
-
加权组合: SAC 的最终输出是两个卷积的加权组合:
这里,
表示标准卷积,
表示速率为 ( r ) 的空洞卷积。
-
全局上下文模块: 在 SAC 模块之前和之后,使用全局上下文模块来合并图像级上下文。这些模块通常涉及全局平均池化和全连接层等操作,以捕获图像的整体结构。这有助于细化特征并为后续层提供更好的上下文。
-
中间层: SAC 模块和全局上下文模块的输出被馈送到网络的进一步层,其中可能包括额外的卷积、规范化和激活函数。这些层继续细化和处理 SAC 模块提取的特征。
-
输出层: 最后,处理后的特征到达输出层,生成所需的结果。这可能是分类标签、分割掩码或用于对象检测的边界框,具体取决于网络设计用于的任务。
工作流程说明
在提供的文档中,图 4 显示了集成到 ResNet 架构中的 SAC 模块的示例。在此图中,ResNet 主干中的每个 3x3 卷积层都被 SAC 模块替换。此修改允许网络根据输入特征动态调整其感受野,从而提高需要多尺度特征检测的任务的性能。
2.2 更改init.py文件
关键步骤二:修改modules文件夹下的__init__.py文件,先导入函数
然后在下面的__all__中声明函数
2.3 新增yaml文件
关键步骤三:在 \ultralytics\ultralytics\cfg\models\v8下新建文件 yolov8_SAConv.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 GFLOPs# YOLOv8.0n backbone
backbone:# [from, repeats, module, args]- [ -1, 1, SAConv2d, [ 64, 3, 2 ] ] # 0-P1/2- [ -1, 1, SAConv2d, [ 128, 3, 2 ] ] # 1-P2/4- [ -1, 3, C2f, [ 128, True ] ]- [ -1, 1, SAConv2d, [ 256, 3, 2 ] ] # 3-P3/8- [ -1, 6, C2f, [ 256, True ] ]- [ -1, 1, SAConv2d, [ 512, 3, 2 ] ] # 5-P4/16- [ -1, 6, C2f, [ 512, True ] ]- [ -1, 1, SAConv2d, [ 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, [ 256 ] ] # 15 (P3/8-small)- [ -1, 1, SAConv2d, [ 256, 3, 2 ] ]- [ [ -1, 12 ], 1, Concat, [ 1 ] ] # cat head P4- [ -1, 3, C2f, [ 512 ] ] # 18 (P4/16-medium)- [ -1, 1, SAConv2d, [ 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)
温馨提示:因为本文只是对yolov8基础上添加模块,如果要对yolov8n/l/m/x进行添加则只需要指定对应的depth_multiple 和 width_multiple。
# YOLOv8n
depth_multiple: 0.33 # model depth multiple
width_multiple: 0.25 # layer channel multiple
max_channels: 1024 # max_channels# YOLOv8s
depth_multiple: 0.33 # model depth multiple
width_multiple: 0.50 # layer channel multiple
max_channels: 1024 # max_channels# YOLOv8l
depth_multiple: 1.0 # model depth multiple
width_multiple: 1.0 # layer channel multiple
max_channels: 512 # max_channels# YOLOv8m
depth_multiple: 0.67 # model depth multiple
width_multiple: 0.75 # layer channel multiple
max_channels: 768 # max_channels# YOLOv8x
depth_multiple: 1.33 # model depth multiple
width_multiple: 1.25 # layer channel multiple
max_channels: 512 # max_channels
2.4 注册模块
关键步骤四:在parse_model函数中进行注册,添加SAConv,
2.5 执行程序
在train.py中,将model的参数路径设置为yolov8_SAConv.yaml的路径
建议大家写绝对路径,确保一定能找到
from ultralytics import YOLO# Load a model
# model = YOLO('yolov8n.yaml') # build a new model from YAML
# model = YOLO('yolov8n.pt') # load a pretrained model (recommended for training)model = YOLO(r'/projects/ultralytics/ultralytics/cfg/models/v8/yolov8_PConv.yaml') # build from YAML and transfer weights# Train the model
model.train(batch=16)
🚀运行程序,如果出现下面的内容则说明添加成功🚀
3. 完整代码分享
https://pan.baidu.com/s/1z2KWa9guFsyHTETM9gXdPA?pwd=kbu5
提取码: kbu5
4. GFLOPs
关于GFLOPs的计算方式可以查看:百面算法工程师 | 卷积基础知识——Convolution
未改进的YOLOv8nGFLOPs
改进后的GFLOPs
5. 进阶
可以与其他的注意力机制或者损失函数等结合,进一步提升检测效果
6. 总结
可切换空洞卷积 (SAConv) 可动态调整卷积层中的空洞率,通过基于输入特征平衡其贡献的切换函数组合不同的空洞卷积,使网络能够更有效地捕获多尺度特征。这种适应性增强了网络检测不同大小物体的能力,并提高了物体检测和分割等任务的性能,而无需添加额外的参数。
相关文章:

YOLOv8改进 | 卷积模块 | SAConv可切换空洞卷积
秋招面试专栏推荐 :深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 💡💡💡本专栏所有程序均经过测试,可成功执行💡💡💡 专栏目录 :《YOLOv8改进有效…...

使用Python下载并合并HLS视频片段
下载和合并视频片段的实用方法 在日常工作中,我们经常会遇到需要从网上下载视频并将其合并成一个完整视频的需求。本文将介绍如何使用 Python 下载多个视频片段,并使用 ffmpeg 将这些片段合并成一个完整的视频文件。以下是具体步骤和代码实现。 完整代…...

常见的九种二极管
常见的九种二极管 文章目录 常见的九种二极管1、普通二极管2、光电二极管(LED)3、变容二级管4、发光二极管5、恒流二极管6、快恢复二极管(FRD)7、肖特基二极管8、瞬态电压抑制二极管(TVS)9、齐纳二极管(稳压࿰…...

竞赛选题 python的搜索引擎系统设计与实现
0 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 python的搜索引擎系统设计与实现 🥇学长这里给一个题目综合评分(每项满分5分) 难度系数:3分工作量:5分创新点:3分 该项目较为新颖ÿ…...

大模型技术方向夏令营1期-对话分角色要素提取挑战赛
#AI夏令营 #Datawhale #夏令营 一、 baseline 跑通 Baseline 本身挑战性有限,关键是熟悉 LLM-centric 相关任务 coding 层面的流程方法,比如: 大模型 API(这里为科大讯飞 Spark)调用token消耗的理解如何调用大模型实现针对给定…...

类和对象(封装、继承、多态、友元)
c面相对象的三大特性为:封装、继承、多态 c 认为万事万物都皆为对象,对象上有其属性和行为 一、类和对象(封装) (一)封装的意义 封装是c面相对象的三大特性之一 封装的意义: 将属性和行为…...

关于Yolov8我踩过的那些坑
按照报错频次梳理: 致命反斜杠‘\’ 调用模型时,我喜欢‘copy relative location’,然后win系统默认反斜杠! 就导致路径读取错误!各种报错!! debug到崩溃然后发现是斜杠的问题,本吗喽…...

Linux——shell原理和文件权限
1.shell原理 在我们使用云服务器时,需要通过shell进行使用,而shell则是一种外壳程序。 我们提到过,大部分的指令实际上就是文件,当用户需要执行某种功能时,由于用户不擅长和操作系统直接交互(操作复杂&…...

网络工程师需要熟悉Docker吗?我觉得不需要精通,但是得懂基础
你好,这里是网络技术联盟站,我是瑞哥。 Docker,这个字眼大家不陌生吧,不过作为网络工程师可能平时接触不到,如果在看文章的是运维人员,那么70%以上的运维人员都会跟Docker打交道。即使网工用不到ÿ…...

c++初级-2-引用
文章目录 引用一、引用的定义二、引用做函数参数三、引用作为返回对象四、引用的本质五、常量引用 引用 即给一个变量起别名。 一、引用的定义 int a 10;//引用int& b a;cout << "a " << a << endl;cout << "b " <&l…...

如何清理电脑内存?让电脑运行如飞!
电脑内存(RAM)的清理对于维持系统的流畅运行至关重要。随着使用时间的增加,系统内存会被各种应用程序和后台进程占用,导致系统响应变慢,甚至出现卡顿现象。通过有效地清理内存,可以提升电脑的性能ÿ…...

[数据集][目标检测]人员状态跑睡抽烟打电话跌倒检测数据集4943张5类别
数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):4943 标注数量(xml文件个数):4943 标注数量(txt文件个数):4943 标注…...

Java8 - Stream API 处理集合数据
Java 8的Stream API提供了一种功能强大的方式来处理集合数据,以函数式和声明式的方式进行操作。Stream API允许您对元素集合执行操作,如过滤、映射和归约,以简洁高效的方式进行处理。 下面是Java 8 Stream API的一些关键特性和概念ÿ…...

漫步5G-A City,一份独属于上海的浪漫
作家亨利詹姆斯曾写道,“城市漫步,让我接触到了这个世界上最好的东西”。 用漫无目的地行走,来体验和观察一座城市,上海凭借丰富多元的文化特质,成为citywalk这种浪漫生活方式的流行地。 无论你是漫步在美术馆、画廊林…...

SpringBoot 如何处理跨域请求?你说的出几种方法?
引言:在现代的Web开发中,跨域请求(Cross-Origin Resource Sharing,CORS)是一个常见的挑战。随着前后端分离架构的流行,前端应用通常运行在一个与后端 API 不同的域名或端口上,这就导致了浏览器的…...

OV SSL证书年度成本概览:为企业安全护航的经济之选
在当今数字化时代,企业网站不仅是品牌展示的窗口,更是与客户沟通的桥梁。然而,随着网络威胁的不断升级,保护网站安全成为了企业不可忽视的任务。SSL证书,特别是OV SSL证书,因其对企业身份的严格验证&#x…...

歌尔气压计SPA06-003在无人机的创新应用
随着科技的不断进步,各类智能设备的功能日益强大,其中气压计作为一种能够测量大气压力的传感器,已被广泛应用于多种领域。歌尔气压计以其高精度、低功耗的特点,在无人机和智能手表上的应用尤为突出,为这两个领域的产品…...

python3多文件操作
1 介绍 有两个.py文件,分别为main.py和util.py,执行main.py时,调用util.py当中的函数。 main.py内容如下, import util if __name__ "__main__":a [3.0,4.0]length util.get_length_from_vec(a)print(f"leng…...

312. 戳气球
312. 戳气球 题目链接:312. 戳气球 代码如下: //参考链接:https://leetcode.cn/problems/burst-balloons/solutions/336390/chuo-qi-qiu-by-leetcode-solution class Solution { public:int maxCoins(vector<int>& nums) {int nnums.size()…...

深入理解C++中的锁
目录 1.基本互斥锁(std::mutex) 2.递归互斥锁(std::recursive_mutex) 3.带超时机制的互斥锁(std::timed_mutex) 4.带超时机制的递归互斥锁(std::recursive_timed_mutex) 5.共享…...

压缩pdf文件大小,压缩pdf文件大小软件哪个好
在数字化时代,PDF文件因其卓越的跨平台兼容性和稳定性而成为工作与学习的好帮手。然而,当PDF文件体积过大时,传输和存储便成了一项挑战。别担心,本文将为你揭秘如何快速压缩PDF文件,让你的文档轻装上路! 压…...

难道 Java 已经过时了?
当一门技术已经存在许多年了,它可能会失去竞争力,而后黯然退场,默默地离开,这对大部分的人来说就已经算是过时了。 Java 于 1995 年正式上线,至今已经走过了 27 个年头,在众多编程技术里算是年龄比较大的语…...

华为OD机考题(HJ32 密码截取)
前言 经过前期的数据结构和算法学习,开始以OD机考题作为练习题,继续加强下熟练程度。有需要的可以同步练习下。 描述 Catcher是MCA国的情报员,他工作时发现敌国会用一些对称的密码进行通信,比如像这些ABBA,ABA&…...

【高考志愿】测绘科学与技术
目录 一、专业介绍 1.1 专业概述 1.2 专业方向 1.3 课程内容 二、就业前景 三、报考注意事项 四、测绘科学与技术专业排名 五、职业规划与未来发展 高考志愿选择测绘科学与技术专业,对于许多有志于空间信息技术领域发展的学生来说,无疑是一个极具…...

SpringBoot异步接口实现 提升吞吐量
前言 Servlet 3.0之前:HTTP请求由单一线程处理。Servlet 3.0之后:支持异步处理,提高系统吞吐量。 SpringBoot 异步接口实现方式 AsyncContext:Servlet层级,不常用。Callable:使用java.util.concurrent.C…...

C语言快速学习笔记
学习网站:C 语言教程 | 菜鸟教程 (runoob.com)C 语言教程 | 菜鸟教程 (runoob.com)C 语言教程 | 菜鸟教程 (runoob.com) 这个网站知识完整,讲解清晰。 在线C语言编程工具:菜鸟教程在线编辑器 (runoob.com) 国外学习网站:C语言介…...

如何选择易用性高的项目管理软件?
随着项目管理在各行各业的广泛应用,选择一款易用性高的项目管理软件变得越来越重要。易用性高的软件可以帮助企业提高工作效率,降低管理成本,同时还能提升团队之间的协作能力。那么,如何选择一款易用性高的项目管理软件呢…...

vue3基于uni-app 封装小程序request请求
const BASE_URL https://47.122.26.142; // 替换为你的 API 基础 URL const token uni.getStorageSync(token);const request (url: string, method: any, data {}, headers {}) > {return new Promise((resolve, reject) > {uni.request({url: ${BASE_URL}${url},m…...

YOLO在目标检测与视频轨迹追踪中的应用
YOLO在目标检测与视频轨迹追踪中的应用 引言 在计算机视觉领域,目标检测与视频轨迹追踪是两个至关重要的研究方向。随着深度学习技术的飞速发展,尤其是卷积神经网络(CNN)的广泛应用,目标检测与视频轨迹追踪的性能得到…...

版本控制系统:Git 纯应用(持续更新)
基本操作 ctrl上行键:上次代码 本地仓库:Git init 新建文件:touch xxxx.xxx 查看状态:Git status 文件从工作区——暂存区:Git add ./文件名(.是通配符代表所有) 暂存区——仓库:Git commit -m &…...