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

【论文阅读笔记】TOOD: Task-aligned One-stage Object Detection

论文代码:https://github.com/fcjian/TOOD

文章目录

  • 论文小结
  • 论文简介
  • 论文方法
    • Task-aligned Head(T-Head)
      • T-Head伪代码解释
    • Task Alignment Learning(TAL)
      • Task-aligned Sample Assignment
      • Task-aligned Loss
  • 论文实验
    • 消融实验

论文小结

  本文的目标,主要是解决不同任务之间预测的不对齐问题。任务不对齐,简单来说,就是分类的最佳anchor(point)和回归的最佳anchor(point)不一定是同一个,亦或者同个grid point的分类和回归所预测的实例对象不是同一个。

  为了解决这个问题,作者从模型结构的检测头或者训练策略中的标签分配中出发,分别设计了T-HeadTAL两个能相互结合的方案。其中TAL被后续文章和实践中较多使用。

  TAL的主要思路就是不事先赋予无法改变的标签,而是结合分类的预测 s \mathcal{s} s 和回归的预测生成的IoU分数 u \mathcal{u} u来动态生成本次学习的标签。因此,TAL(Task Alignment Learning)中会有一个learning的说法。

  本文的对比实验和消融实验室未充分训练的对比,大致训练12个epoch来对比的。

论文简介

  由于分类和定位学习机制的差异,两个任务学习到的特征空间分布可能不同。当两个任务分支单独预测时,会导致一定程度的不对齐。如下图 1 1 1所示,上面行是ATSS算法预测的结果,下面行是本文TOOD算法预测的结果。图中黄色框是餐桌的label,分类任务的最佳位置是红色色块,其边框预测为红框;回归任务的最佳位置是绿色色块。从图 1 1 1可以容易看出,在原有方法训练管道得到的结果,可能会出现分类任务和定位任务的不对齐问题。

  在原先的方法(比如FCOS和ATSS)的认知中,对象的几何中心附近更容易预测对象(anchor-based在grid上,anchor-point),给予靠近中心的正样本分配更高的分数,更高的权重。这种启发式的方法取得很好的效果,但可能带来两个局限性:

  1. 分类和定位的独立性。对象实例有重叠时,分类目标和定位目标不匹配;
  2. 任务不可知标签分配。标签都是按照定位的几何中心分配的,但即使是定位问题,几何中心都不一定是最合适预测的。更何况标签的分配没有考虑分类任务的概率图(probably map)。分类和定位的最佳anchor通常是不一致的,并且依据目标的形状和特种有较大差异。因此很难对两个任务作出准确而一致的预测。

  为了解决分类任务和定位任务的不对齐问题,本文的贡献是提出了T-head和TAL两个方法。

  T-head,大致是为了增加两个任务之间的交互,以及增强检测器学习对齐的能力。总得来说,就是设计了一个新的检测头。

  TAL方法,目标是让两个任务的最佳anchor尽可能接近。其做法是设计一个简单的分配方案和任务对齐损失。样本分配通过每个anchor的任务对齐难度来收集训练的正负样本。而任务对其损失则在训练过程中逐渐统一预测分类和定位的最佳anchor。
  基本做法如下图所示,产生了cls和loc预测,再获得对齐指标,放入TAL中,进行标签分配和反向传播。

论文方法

  网络的整体设计也是按照“backbone - neck - head”结构来的。为简单和方便,TOOD在每个位置使用 1 1 1个anchor(anchor point/box)。如上图 2 2 2所示,T-Head和TAL可以协调地共同作用。原架构如下图 3 ( a ) 3(a) 3(a)所示,所提出的T-head如下图 3 ( b ) 3(b) 3(b)所示。

Task-aligned Head(T-Head)

  T-Head的目标是增加分类任务和定位任务的交互,以及增加两个任务之间的预测对齐能力。

  T-Head的架构图如上图 3 ( b ) 3(b) 3(b)所示,先通过多个卷积来堆叠任务交互特征,如公式(1)所示,然后再经过 2 2 2个TAP(Task-aligned Predictor),用于对齐分类和定位。TAP的架构图如上图 3 ( c ) 3(c) 3(c)所示。
X k i n t e r = { δ ( c o n v k ( X f p n ) ) , k = 1 ,     ∀ k ∈ { 1 , 2 , . . . , N } δ ( c o n v k ( X k − 1 i n t e r ) ) , k > 1 (1) X_k^{inter}=\begin{cases}\delta(conv_k(X^{fpn})),k=1, \ \ \ \ \forall k\in\{1,2,...,N\} \\ \delta(conv_k(X_{k-1}^{inter})),k>1\end{cases}\tag{1} Xkinter={δ(convk(Xfpn)),k=1    k{1,2,...,N}δ(convk(Xk1inter))k>1(1)

  由于TAP是一条单独的分支,任务交互特征不可避免地会在两个不同任务之间引入一定程度的特征冲突,所以作者提出来layer attention机制。通过在level级别动态计算任务特定特征,来鼓励任务分解,如公式(2)、(3),(4)。
X k t a s k = w ⋅ X k i n t e r , ∀ k ∈ { 1 , 2 , . . . , N } , (2) X_k^{task} = \mathcal{w}\cdot X_k^{inter}, \forall k\in \{1,2,...,N\}, \tag{2} Xktask=wXkinter,k{1,2,...,N},(2)
  下面公式中的 δ \delta δ是全局池化层(GAP);
w = σ ( f c 2 ( δ ( f c 1 ( x i n t e r ) ) ) ) (3) \mathcal{w} = \sigma(fc_2(\delta(fc_1(x^{inter})))\tag{3}) w=σ(fc2(δ(fc1(xinter))))(3)
  下面公式中的 δ \delta δ是ReLU非线性层;
Z t a s k = c o n v 2 ( δ ( c o n v 1 ( X t a s k ) ) ) (4) Z^{task}=conv_2(\delta(conv_1(X^{task})))\tag{4} Ztask=conv2(δ(conv1(Xtask)))(4)

  如上图 3 ( c ) 3(c) 3(c)所示,对于预测的分类分数 P ∈ R H × W × 80 P\in\mathbb{R}^{H\times W \times 80} PRH×W×80,从交互特征中,学习一个空间概率图(spatial probability map) M ∈ R H × W × 1 M\in\mathbb{R}^{H\times W \times 1} MRH×W×1来调整分类预测,完成对齐: P a l i g n = P × M (5) P^{align}=\sqrt{P\times M} \tag{5} Palign=P×M (5)

  同样的,对于预测的边框对象 B ∈ R H × W × 4 B\in\mathbb{R}^{H\times W \times 4} BRH×W×4,从交互特征中学习一个空间偏差图(spatial offset maps) O ∈ R H × W × 8 \Omicron\in\mathbb{R}^{H\times W \times 8} ORH×W×8来调整每个位置的bbox,完成对齐。 B a l i g n ( i , j , c ) = B ( i + O ( i , j , 2 × c ) , j + O ( i , j , 2 × c + 1 ) , c ) (6) B^{align}(i,j,c)=B(i+\Omicron(i,j,2\times c),j+\Omicron(i,j,2\times c+1), c)\tag6 Balign(i,j,c)=B(i+O(i,j,2×c),j+O(i,j,2×c+1),c)(6)

   O \Omicron O M M M从交互特征学习的公式如下: M = c o n v 2 ( δ ( c o n v 1 ( X i n t e r ) ) ) (7) M=conv_2(\delta(conv1(X^{inter})))\tag7 M=conv2(δ(conv1(Xinter)))(7) O = c o n v 4 ( δ ( c o n v 3 ( X i n t e r ) ) ) (8) \Omicron=conv_4(\delta(conv3(X^{inter})))\tag8 O=conv4(δ(conv3(Xinter)))(8)

T-Head伪代码解释

  依据作者的描述是能够平衡学习两个任务交互特征,实际上思路大致是在neck之后先使用统一的管道来tune特征,就像早期的cls head与reg head未解耦时的状态。然后使用一些启发性的架构,比如channel attention来“解耦”cls特征和reg特征,channel attention的权重初步由全局池化层(GAP)得到,再通过卷积对该权重进行学习(类似于AsConv),作为attention的自适应权重。在得到分类和回归的推理结果上,作者也有一些启发性的设计。比如,分类任务首先预测一个分类分数,然后再预测一个分类概率相结合;回归任务首先预测一个bbox的xywh,再预测一个offset来进行调整。

feat_0 = feat_fpn
feat_{i} = leaky_relu(bn(Conv(feat_{i-1})))			                    # use for both cls task and reg task.
feat = torch.cat(feat_{i,...,n})weight = GAP(feat)
weight_cls = sigmoid(conv2(relu(conv1(weight)))				            # 从这儿解耦分类和回归,conv1/2/3/4表示不同卷积
weight_reg = sigmoid(conv4(relu(conv3(weight)))feat_cls = channel_attention(weight_cls, feat)
feat_reg = channel_attention(weight_reg, feat)# get cls prediction
cls_sigmoid = Conv3(256 -> num_anchors * 80)[feat_cls]                  # input is feat_cls
cls_prob = Conv1(256*6 -> 64)[feat] => relu => Conv3(64 -> 1)           # input is feat
cls_scores = \sqrt(cls_sigmoid.sigmoid() * cls_prob.sigmoid())# get reg prediction
reg_dist = Conv3(256 -> num_anchors * 4)[feat_reg].exp()                # input is feat_reg
reg_bbox = dis2bbox(reg_dist)
reg_offset = Conv1(256*6 -> 64)[feat] => relu => Conv3(64 -> 8)         # input is feat
bbox_pred = deform_Conv2d(reg_bbox, reg_offset)		                    # a library from mmlab/mmcv,add reg_offset for reg_bbox map. details see the formule.

Task Alignment Learning(TAL)

  在TAL中,主要有两点创新:

  1. 动态选择最适合的anchor(在一个设计好的指标下);
  2. 它同时考虑anchor分配和权重,包括一个样本分配策略和专门为调整两个任务而设计的新Loss。

  anchor分配策略应该有如下 2 2 2个规则:(1)一个对齐良好的anchor应该同时能预测一个高的分类分数和一个精确的定位;(2)没对齐的anchor应该有交底的分数,随后被NMS抑制。

Task-aligned Sample Assignment

  设定分类分数为 s s s,预测和GT的IoU值为 u u u,设计anchor级的对齐指标如下面公式,这样能同时衡量分类和定位的预测质量: t = s α × u β (9) t=s^\alpha\times u^\beta\tag9 t=sα×uβ(9)

  对于每个实例,依据 t t t值进行排序,选择最大值的 m m m个anchors作为正样本,其他作为负样本。因此,每个训练迭代中,标签的分配都是动态赋予的

Task-aligned Loss

  分类目标上,作者使用 t t t值代替正样本anchor中的二元标签
  但作者也发现,随着 α \alpha α β \beta β的上升, t t t值标签就会变小,进而导致无法收敛。所以作者将 t t t进行正则化,标记为 t ^ \hat{t} t^,来代替正样本anchor中的二元标签。 t ^ \hat{t} t^的正则化应该遵循两项原则:(1)确保硬实例都能够高效地被学习(硬是难易样本的说法,比如Focal loss中的hard sample,此时所有的正anchor都只有很小的 t t t值标签);(2)根据预测框的精度来保持实例之间的等级。
  因此,作者采用了一个简单的实例级的正则化 t ^ \hat{t} t^方法: t ^ \hat{t} t^的最大值等于每个实例的最大IoU值。(实际上就是换了个标签分配方案,可能为了方便写论文)。此时,经过BCE(Binary Cross Entropy)的损失函数为: L c l s _ p o s = ∑ i = 1 N p o s B C E ( s i , t ^ i ) (10) L_{cls\_{pos}}=\sum_{i=1}^{N_{pos}}BCE(s_i, \hat{t}_i)\tag{10} Lcls_pos=i=1NposBCE(si,t^i)(10)

  在分类任务上,使用focal loss,分类损失如下:其中 γ \gamma γ是focal loss的超参数。 L c l s = ∑ i = 1 N p o s ∣ t ^ i − s i ∣ γ B C E ( s i , t ^ i ) + ∑ j = 1 N n e g s j γ B C E ( s j , 0 ) (11) L_{cls}=\sum_{i=1}^{N_{pos}}|\hat{t}_i-s_i|^\gamma BCE(s_i, \hat{t}_i) + \sum_{j=1}^{N_{neg}}s_j^\gamma BCE(s_j, 0)\tag{11} Lcls=i=1Npost^isiγBCE(si,t^i)+j=1NnegsjγBCE(sj,0)(11)

  在定位任务上,作者通过关注对齐良好的anchors(具有较大的 t t t值),来提高任务对齐和回归精度,同时减少边框回归过程中不对齐anchors的影响。

  基于 t ^ \hat{t} t^来为每个anchor的bbox的loss重新分配权重。使用的损失函数为GIoU Loss,回归的损失公式如下: L r e g = ∑ i = 1 N p o s t ^ i L G I o U ( b i , b i ˉ ) L_{reg}=\sum_{i=1}^{N_{pos}}\hat{t}_iL_{GIoU}(b_i, \bar{b_i}) Lreg=i=1Npost^iLGIoU(bi,biˉ)

论文实验

  COCO数据集,trainval135k为训练集,minival set为验证集。

  TOOD的backbone(ResNet-50,ResNet-101,ResNeXt-101-64x4d)都是在ImageNet上进行的预训练,检测头采用的是anchor-free的设计。本文实验中,anchor-based的组和anchor-free的性能相似。T-Head的连续卷积层数量 N = 6 N=6 N=6,Focal Loss的超参数 γ = 2 \gamma=2 γ=2

消融实验

  消融实验中,使用的backbone为ResNet-50,默认训练周期为 12 12 12个epochs(没有收敛完全)。

  下表1展示了T-head的消融实验结果,能涨AP 0.7 − 1.9 0.7-1.9 0.71.9

  TAL的消融实验如下表所示:

  Anchor-based和Anchor-free的消融实验如下:两者性能接近。

   α \alpha α β \beta β的消融实验如下表所示: α = 1.0 \alpha=1.0 α=1.0 β = 6 \beta=6 β=6的情况下,得到的性能最好。

  TOOD与其他一阶目标检测算法的对比结果如下:其中每个模型使用不同分辨率( 480 − 800 480-800 480800)训练,训练 24 24 24个epochs。

  TOOD整体结构的消融实验如下表所示:TOOD的设计 比 T-Head + ATSS 以及平行head + TAL的指标都好,表明T-head和TAL具有相辅相成的互补性。

相关文章:

【论文阅读笔记】TOOD: Task-aligned One-stage Object Detection

论文代码:https://github.com/fcjian/TOOD 文章目录 论文小结论文简介论文方法Task-aligned Head(T-Head)T-Head伪代码解释 Task Alignment Learning(TAL)Task-aligned Sample AssignmentTask-aligned Loss 论文实验消…...

类中的特殊内容

仿照string类&#xff0c;自己手动实现 My_string #include <iostream> #include <string.h> using namespace std;class My_string { private:int len;int size;char *ptr; public:My_string():size(15),len(0){ptrnew char[size];ptr[0]\0;}My_string(const char…...

network request to https://registry.npmjs.org/xxx failed, reason: connect ETIM

目录&#xff1a; 1、问题描述2、解决方案3、npm镜像仓库替换 1、问题描述 npm install 时&#xff0c;报错&#xff1a;npm ERR! network request to https://registry.npmjs.org/postcss-pxtorem failed, reason: connect ETIMEDOU npm ERR! code ETIMEDOUT npm ERR! errno…...

MQ入门(二):java客户端SpringAMQP

目录 1.SpringAMQP 1.1.导入demo工程 1.2.快速入门 1.2.1.消息发送 1.2.2.消息接收 1.2.3.测试 1.3.WorkQueues模型 1.4.交换机类型 1.4.1.Fanout交换机 1.4.2.Direct交换机 1.4.3.Topic交换机 1.5.声明队列和交换机 1.5.1.基于注解声明 1.6.消息转换器 1.6.1.测…...

软技能与AI技术的融合

一、引言 ----  随着人工智能&#xff08;AI&#xff09;和生成式人工智能&#xff08;AIGC&#xff09;如ChatGPT、Midjourney、Claude等大语言模型的迅速崛起&#xff0c;AI辅助编程工具已经变得越来越普遍。这不仅意味着程序员的工作方式正在发生深刻的变革&#xff0c;同…...

在视频上绘制区域:使用Vue和JavaScript实现交互式画布

在数字时代&#xff0c;交互式媒体内容的创建和消费变得越来越普遍。特别是视频内容&#xff0c;它不仅提供了视觉信息&#xff0c;还允许用户与之互动&#xff0c;从而增强了用户体验。本文将介绍如何使用Vue.js框架和JavaScript创建一个交互式组件&#xff0c;该组件允许用户…...

31. RabbitMQ顺序消费

1. 前言 上个小节中我们介绍了 RabbitMQ 中如何防止消息丢失,即保证消息发送的 At Least Once 性质,除此之外,如何防止消息被重复消费,即保证消息消费的 Exactly Once 性质,也是业务逻辑中需要考虑的问题。 2. 消息消费顺序 面试官提问:业务中使用了 RabbitMQ 消息队列…...

BERT-BiLSTM-CRF模型实战

文章目录 BERT-BiLSTM-CRF模型项目结构数据预处理运行环境使用方法关于BERT-BiLSTM-CRF参考文章BERT-BiLSTM-CRF模型 使用谷歌的BERT模型在BiLSTM-CRF模型上进行预训练用于中文命名实体识别。 项目结构 bert_bilstm_crf_ner_pytorchtorch_nerbert-base-chinese --…...

npm 安装 与 切换 淘宝镜像

一、镜像源 npm默认镜像源是国外的&#xff0c;安装依赖速度较慢&#xff0c;使用国内的镜像源速度会快一些。 1、设置淘宝镜像源&#xff1a; #最新地址 淘宝 NPM 镜像站喊你切换新域名啦! npm config set registry https://registry.npm.taobao.org&#xff08;弃用了&…...

在Windows系统上安装的 Arrow C++ 库

在Windows系统上安装的 Arrow C 库 正文第一步第二步第三步第四步注: 检查是否安装成功 吐槽 正文 第一步 git clone gitgithub.com:apache/arrow.git第二步 打开powershell (好像cmd也可以,不过我试了powershell中不报错,cmd中报错,不是很清楚为什么) 打开arrow的目录 cd …...

格雷母线电缆头安装方法视频-武汉正向科技

正向科技|格雷母线电缆头怎么处理&#xff1f; 正向科技格雷母线采用整体热压工艺生产&#xff0c;一次成型&#xff0c;防护等级 IP67&#xff0c;用在直线或环形位移检测&#xff0c;抗污染能力强&#xff0c;防水、油、灰尘、蒸汽等&#xff0c;能在强粉尘、高温的环境下稳定…...

统信服务器操作系统【Cron定时任务服务】

Cron定时任务服务服务介绍、服务管理、服务配置 文章目录 一、功能概述二、功能介绍1. Cron 服务管理2.Cron 服务管理3.Cron 服务配置run-parts一、功能概述 cron是一个可以用来根据时间、日期、月份、星期的组合来 调度对周期性任务执行的守护进程。利用 cron 所提供的功能,可…...

微前端中的路由加载流程

1. 初始化基座应用 基座应用&#xff1a;基座应用是微前端架构中的主应用&#xff0c;负责管理和协调各个子应用的加载和卸载。 初始化&#xff1a;基座应用在启动时会初始化路由配置&#xff0c;注册各个子应用的路由。 2. 注册子应用 子应用需要向基座应用注册自己的路由和…...

Axure大屏可视化模板:跨领域数据分析平台原型案例

随着信息技术的飞速发展&#xff0c;数据可视化已成为各行各业提升管理效率、优化决策过程的重要手段。Axure作为一款强大的原型设计工具&#xff0c;其大屏可视化模板在农业、园区、城市、企业数据可视化、医疗等多个领域得到了广泛应用。本文将通过几个具体案例&#xff0c;展…...

机器学习(1)——线性回归、线性分类与梯度下降

文章目录 线性回归线性分类线性可分数据线性不可分数据逻辑回归支持向量机 梯度下降批量梯度下降随机梯度下降批量随机梯度下降 线性回归 概述&#xff1a; 在一元线性回归中&#xff0c;我们假设目标变量y与特征变量x存在线性关系&#xff0c;模型表达式为&#xff1a; y …...

完整的端到端的中文聊天机器人

这段代码是一个完整的端到端的中文聊天机器人的实现,包括数据处理、模型训练、预测和图形用户界面(GUI),下面是对各个部分功能的详细说明: 1. 导入必要的库 import os os.environ[CUDA_LAUNCH_BLOCKING] = 1import torch import torch.nn as nn import torch.optim as o…...

【有啥问啥】Stackelberg博弈方法:概念、原理及其在AI中的应用

Stackelberg博弈方法&#xff1a;概念、原理及其在AI中的应用 1. 什么是Stackelberg博弈&#xff1f; Stackelberg博弈&#xff08;Stackelberg Competition&#xff09;是一种不对称的领导者-追随者&#xff08;Leader-Follower&#xff09;博弈模型&#xff0c;由德国经济学…...

【UI自动化】前言

系列文章目录 【UI自动化】前言 自动化不能代替手工测试&#xff0c;自动化都是以手工测试为基础&#xff0c;自动化测试实现的步骤要依赖手工&#xff1b; 文章目录 系列文章目录【UI自动化】前言 自动化测试的类型自动化解决的问题什么是UI测试测试分类一、使用UI自动化的…...

Unity对象池的高级写法 (Plus优化版)

唐老师关于对物体分类的OOD的写法确实十分好&#xff0c;代码也耦合度也低&#xff0c;但是我有个简单的写法同样能实现一样的效果&#xff0c;所以我就充分发挥了一下主观能动性 相较于基本功能&#xff0c;这一版做出了如下改动 1.限制了对象池最大数量&#xff0c;多出来的…...

vue3<script setup>中computed

在 Vue 3 中&#xff0c;<script setup> 语法糖是 Composition API 的一种简化写法&#xff0c;它允许你更简洁地编写组件逻辑。在 <script setup> 中使用 computed 与在普通 <script> 标签中使用 Composition API 的方式类似&#xff0c;但通常我们会借助 i…...

iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘

美国西海岸的夏天&#xff0c;再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至&#xff0c;这不仅是开发者的盛宴&#xff0c;更是全球数亿苹果用户翘首以盼的科技春晚。今年&#xff0c;苹果依旧为我们带来了全家桶式的系统更新&#xff0c;包括 iOS 26、iPadOS 26…...

基于服务器使用 apt 安装、配置 Nginx

&#x1f9fe; 一、查看可安装的 Nginx 版本 首先&#xff0c;你可以运行以下命令查看可用版本&#xff1a; apt-cache madison nginx-core输出示例&#xff1a; nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...

STM32F4基本定时器使用和原理详解

STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

Keil 中设置 STM32 Flash 和 RAM 地址详解

文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...

关于 WASM:1. WASM 基础原理

一、WASM 简介 1.1 WebAssembly 是什么&#xff1f; WebAssembly&#xff08;WASM&#xff09; 是一种能在现代浏览器中高效运行的二进制指令格式&#xff0c;它不是传统的编程语言&#xff0c;而是一种 低级字节码格式&#xff0c;可由高级语言&#xff08;如 C、C、Rust&am…...

LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf

FTP 客服管理系统 实现kefu123登录&#xff0c;不允许匿名访问&#xff0c;kefu只能访问/data/kefu目录&#xff0c;不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...

LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》

这段 Python 代码是一个完整的 知识库数据库操作模块&#xff0c;用于对本地知识库系统中的知识库进行增删改查&#xff08;CRUD&#xff09;操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 &#x1f4d8; 一、整体功能概述 该模块…...

C#中的CLR属性、依赖属性与附加属性

CLR属性的主要特征 封装性&#xff1a; 隐藏字段的实现细节 提供对字段的受控访问 访问控制&#xff1a; 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性&#xff1a; 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑&#xff1a; 可以…...

Rust 开发环境搭建

环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行&#xff1a; rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu ​ 2、Hello World fn main() { println…...

什么是VR全景技术

VR全景技术&#xff0c;全称为虚拟现实全景技术&#xff0c;是通过计算机图像模拟生成三维空间中的虚拟世界&#xff0c;使用户能够在该虚拟世界中进行全方位、无死角的观察和交互的技术。VR全景技术模拟人在真实空间中的视觉体验&#xff0c;结合图文、3D、音视频等多媒体元素…...