【论文阅读】《Visual Prompt Tuning》

Abstract.

目前调整预训练模型的工作方式包括更新所有骨干参数,即全面微调。本文介绍了视觉提示调整(VPT),作为大规模视觉变换器模型全面微调的高效替代方案。VPT 从高效调整大型语言模型的最新进展中汲取灵感,只在输入空间中引入少量(少于模型参数的 1%)可训练参数,同时保持模型主干冻结。通过对各种下游识别任务的广泛实验,我们发现与其他参数高效调整协议相比,VPT 能显著提高性能。最重要的是,在模型容量和训练数据规模方面,VPT 在很多情况下甚至优于完全微调,同时降低了每个任务的存储成本。代码见GitHub - KMnP/vpt: ❄️🔥 Visual Prompt Tuning [ECCV 2022] https://arxiv.org/abs/2203.12119。

1 Introduction

对于各种识别应用来说,目前最准确的结果都是通过调整在海量数据或原始数据上预先训练的大型基础模型获得的,这一发现反映了自然语言处理(NLP)的发展[6]。乍一看,这是一个成功的故事:只需利用最新、最好的基础模型,就能在多个识别问题上取得快速进展。然而,在实践中,如何将这些大型模型适应下游任务也是一个挑战。最明显(通常也是最有效)的适应策略是根据手头的任务对预先训练好的模型进行端到端的全面微调。然而,这种策略需要为每个任务存储和部署一份单独的骨干参数副本。这是一个昂贵且通常不可行的提议,尤其是对于基于 Transformer 的现代架构而言,这种架构比卷积神经网络(ConvNet)要大得多,例如 ViT-Huge [19](6.32 亿个参数)与 ResNet-50 [31](2500 万个参数)。因此,我们不禁要问,从效果和效率的角度来看,怎样才能让大型预训练 Transformers 适应下游任务?

一种直截了当的方法是求助于我们已经完善的其他策略,使 ConvNets 适应新任务,如图 1(a)。一种流行的方法是只微调参数的子集,如分类器头部 [56,36,11] 或偏置项 [8]。之前的研究还探讨了在骨干网中添加额外的残差块(或适配器)[68,87]。我们也可以为Transformers实施类似的策略。不过,一般来说,这些策略的精确度都低于完全微调。

我们在本文中探索了一条不同的路径。我们不改变或微调预训练Transformer本身,而是修改Transformer的输入。我们从最近在 NLP 中的提示技术[50,48,45,51]中汲取灵感,提出了一种简单高效的新方法来调整Transformer模型,以适应下游视觉任务(图 1(b)),即视觉提示调整(VPT)。我们的方法只在输入空间中引入少量特定任务的可学习参数,同时在下游训练过程中冻结整个预训练Transformer骨干。在实践中,这些附加参数只需预置到每个Transformer层的输入序列中,并在微调过程中与线性头一起学习。

在使用经过预训练的 ViT 主干网的 24 项横跨不同领域的下游识别任务中,VPT 战胜了所有其他迁移学习基线,甚至在 20 种情况下超过了完全微调,同时保持了为每项任务存储的参数显著减少(不到主网参数的 1%)的优势(图 1(c))。这一结果表明了视觉提示的独特优势:而在 NLP 中,提示调整只有在特定情况下才能与完全微调性能相媲美[45]。VPT 在低数据量条件下尤其有效,而且在不同数据量条件下都能保持优势。最后,VPT 在各种Transformer规模和设计(ViTBase/Large/Huge,Swin)中都具有竞争力。综上所述,我们的研究结果表明,VPT 是适应不断增长的视觉骨干网的最有效方法之一。

2 Related Work

Transformer 模型 [73] 在 NLP [17,66,7] 中取得了巨大成功。Transformer 架构的成功还延伸到了各种计算机视觉任务中,包括图像分类 [19,52]、物体检测 [9,49]、语义和全视角分割 [71,89,78]、视频理解 [25,79,21] 和少镜头学习 [18],超越了以往最先进的方法。Transformer也被广泛应用于最近的自监督预训练方法中[11,30,3]。与 ConvNets 相比,Transformer性能优越,规模更大,因此如何有效地将Transformer应用于不同的视觉任务仍是一个重要的未决问题。我们提出的 VPT 提供了一条充满希望的前进道路。

针对 ConvNets [92]背景下的视觉任务,转移学习(Transfer learning)已被广泛研究,并引入了许多技术,包括侧调整 [87]、残差适配器 [67]、偏差调整 [8]等(side tuning [87], residual adapter [67], bias tuning [8], etc. )。相对而言,人们对视觉变换器适配的关注较少,上述方法在这种全新架构上的表现如何仍是未知数。另一方面,鉴于大规模预训练的基于Transformer的语言模型(LM)[17,66,7]占据主导地位,许多方法[29,28,35]已被提出,以针对不同的下游 NLP 任务[77,76]有效地微调 LM。其中,我们在实验中重点关注以下两种具有代表性的方法,以进行基准测试: Adapters [64] 和 BitFit [5]。

适配器 [34] 在每个Transformer层内插入额外的轻量级模块。一个适配器模块一般由一个线性下投影、一个非线性激活函数、一个线性上投影和一个残差连接组成 [63,64]。文献[8]建议在微调 ConvNets 时更新偏置项,冻结其余骨干参数,而不是插入新模块。BitFit [3] 将这一技术应用于 Transformers,并验证了其对 LM 调整的有效性。我们的研究表明,与上述两种在 NLP 中广为流传的方法相比,VPT 在针对视觉任务调整 Transformer 模型方面的性能普遍有所提高。

提示(Prompting )[50]最初是指在输入文本中预先添加语言指令,以便预先训练的 LM 能够 "理解 "任务。在人工选择提示的情况下,GPT-3 对下游迁移学习任务显示出很强的泛化能力,即使是在少镜头或零镜头的情况下也是如此[7]。除了关于如何构建更好的提示文本的后续工作[70,37]之外,最近的工作还提出将提示视为特定任务的连续向量,并在微调过程中通过梯度直接对其进行优化,即提示微调( Prompt Tuning )[48,45,51]。与完全微调相比,它的性能相当,但参数存储量却少 1000 倍。虽然最近也有人将提示技术应用于视觉语言模型[65,91,39,84,22],但提示技术仍局限于文本编码器的输入。由于视觉和语言模式之间的差异,我们在本文中提出:同样的方法能否成功应用于图像编码器?我们是第一项解决这个问题的研究(参见相关的并行研究 [69,80,14,2]),并通过广泛的实验研究了视觉提示的通用性和可行性,这些实验跨越了多个领域和骨干架构的多种识别任务。

3 Approach

我们提出了视觉提示调整(VPT)技术,用于调整大型预训练视觉Transformer模型。VPT 向 Transformer 的输入空间注入少量可学习参数,并在下游训练阶段保持主干冻结。整体框架如图 2 所示。我们首先在第 3.1 节中定义术语,然后在第 3.2 节中正式描述 VPT。

3.1 Preliminaries

对于有 N 层的普通视觉Transformer (ViT)[19],输入图像被分成 m 个固定大小的补丁\{I_j\in \mathbb{R} ^{3\times h\times w}|j\in \mathbb{N} ,1\le j\le m\}h,w 分别为图像补丁的高度和宽度。然后,首先用位置编码将每个补丁嵌入 d 维潜在空间:

我们将图像补丁嵌入集合 \mathbf{E} _i=\{e_{i}^{j}\in \mathbb{R}^d|j\in \mathbb{N},1\le j \le m \}表示为第(i+1)次Transformer 层 (L_{i+1}) 的输入。加上一个额外的可学习分类标记([CLS]),整个 ViT 可表述为: 

 其中,x_i\in \mathbb{R}_ d表示[CLS] ^,L_{i+1 }^,输入空间的嵌入。[\cdot, \cdot ]表示序列长度维度上的堆叠和串联,即[x_i,\mathbf{E}_i ]\in \mathbb{R} ^{(1+m)\times d}。每个层L_i多头自注意网络(MSA)和前馈网络(FFN)以及层规范(LayerNorm)[1] 和残差连接(residual connections)[31]组成。神经分类头用于将最后一层的[CLS]嵌入\mathbf{ x} _N 映射到预测的类别概率分布\mathbf{y}中。

3.2 Visual-Prompt Tuning (VPT)

给定一个预先训练好的 Transformer 模型,我们在嵌入层之后的输入空间中引入一组维度为 d 的 p 个连续嵌入,即提示。在微调过程中,只有特定任务的提示才会被更新,而 Transformer 骨架则会被冻结。根据所涉及的Transformer层数,我们的方法有两种变体,即 VPT-浅层(SHALLOW)和 VPT-深层(DEEP),如图 2 所示。

VPT-Shallow.  提示仅插入第一个Transformer层 L_1。每个提示标记都是一个可学习的 d 维向量。\mathbf{P} = \{\mathbf{p}^k\in\mathbb{ R}^d | k\in \mathbb{N} , 1\le k\le p\},浅层提示的 ViT 为:

其中,\mathbf{Z}_i\in\mathbb{ R}^{p\times d}表示i个Transformer层计算的特征[\mathbf{x}_i,\mathbf{Z}_i,\mathbf{E}_i]\in \mathbb{R}^{(1+p+m)×d }表示第 i 个Transformer层计算的特征。红色和蓝色分别表示可学习参数和冻结参数。值得注意的是,对于 ViT 来说,\mathbf{x} _N与提示符的位置无关,因为它们是在位置编码后插入的,例如,[\mathbf{x}_0,\mathbf{P},\mathbf{E}_0][\mathbf{x}_0,\mathbf{E}_0,\mathbf{P}]在数学上是等价的。这同样适用于 VPT-Deep。 

VPT-Deep.  每个Transformer层的输入空间都会引入提示。对于第 (i+1)L_{i+1},我们将可学习的输入提示集合表示为\mathbf{P}_i = \{\mathbf{p}^k_i\in\mathbb{ R}^d | k\in \mathbb{N} , 1\le k\le m\}。深度提示 ViT 的公式为 

Storing Visual Prompts.  VPT 在存在多个下游任务的情况下大有裨益。我们只需为每个任务存储学习到的提示和分类头,并重新使用预先训练好的 Transformer 模型的原始副本,从而大大降低了存储成本。例如,给定的 ViT-Base 有 8600 万 (M) 个参数,d = 768,50 个浅提示和深提示会产生额外的p\times d = 50\times768 = 0.038MN\times p\times d =0.46M参数,分别只占 ViT-Base 所有参数的 0.04% 和 0.53%。 

4 Experiments

我们利用预先训练好的 Transformer 骨干网,对 VPT 在各种规模的下游识别任务中的应用进行了评估。在第 4.1 节中,我们首先介绍了我们的实验设置,包括预训练骨干和下游任务,并简要介绍了其他迁移学习方法。然后,我们在第 4.2 节中展示了我们方法的有效性和实用性。我们还系统地研究了不同的设计选择会如何影响性能(第 4.3 节),从而加深了对我们方法的理解。

4.1 Experiment Setup

Pre-trained Backbones. 我们试验了视觉领域的两种变换器架构:Vision Transformers (ViT) [19] 和 Swin Transformers (Swin [52])。本节中的所有骨干都是在 ImageNet-21k [16] 上预先训练的。我们沿用了最初的配置,例如划分的图像斑块数、[CLS] 的存在等。更多详情见附录 A。

Baselines.  我们将 VPT 的两个变体与其他常用的微调协议进行了比较: 

(a) Full: 全面更新所有主干和分类头参数。

(b) Methods that focus on the classification head.  它们将预先训练好的骨干网视为特征提取器,其权重在调整过程中是固定的:

  • – Linear:  只使用线性层作为分类头。
  • – Partial-k:  微调骨干层的最后 k 层,同时冻结其他层,如 [85,88,60,30] 所采用的方法。它重新定义了骨干层和分类头的边界。
  • – Mlp-k: 使用具有k层的多层感知器(MLP)作为分类头,而不是线性层。

(c) Methods that update a subset backbone parameters or add new trainable parameters to backbone during fine-tuning:

  • – Sidetune [87]: 训练一个 "侧 "网络,在输入头部之前,在预训练特征和侧调特征之间进行线性插值。
  • – Bias [8,5]: 只对预训练骨干网的偏置项进行微调。
  • – Adapter [34,63,64]:  在Transformers 层内插入具有残差连接的新 MLP 模块。

Downstream Tasks.  我们在以下两个数据集集合上进行了实验:

FGVC 由 5 个基准精细视觉分类任务组成,包括 CUB-200-2011 [75]、NABirds [72]、Oxford Flowers [59]、Stanford Dogs [41] 和 Stanford Cars [23]。如果某个数据集只公开了训练集和测试集,我们会随机将训练集分成训练集(90%)和测试集(10%),并根据测试集来选择超参数。

VTAB-1k [86] 包含 19 种不同的视觉分类任务,分为三组: 自然类--任务包含使用标准相机拍摄的自然图像;专业类--任务包含通过专业设备拍摄的图像,如医疗和卫星图像;结构类--任务需要几何理解能力,如物体计数。VTAB 的每个任务都包含 1000 个训练示例。按照文献[86],我们使用所提供的 800-200 个训练集分拆数据来确定超参数,并使用全部训练数据进行最终评估。我们报告了三次运行中测试集的平均准确率。 

我们报告了 FGVC 数据集的平均准确率,以及 VTAB 中三组数据的平均准确率。每项任务的单独结果以及上述任务的图像示例见附录 D。

4.2 Main Results

表 1 列出了对预先训练的 ViT-B/16 进行微调的结果。表 1 列出了对预先训练的 ViT-B/16 在 4 个不同下游任务组中的平均值进行微调的结果,并将 VPT 与其他 7 个微调协议进行了比较。我们可以看到

  1. 在 4 个问题类别中的 3 个(24 个任务中的 20 个)上,VPT-Deep 的表现优于 Full(表 1(a)),同时所使用的模型参数总数也少得多(1.18× vs. 24.02×)。因此,即使不考虑存储问题,VPT 也是在视觉中适配较大Transformers的一种有前途的方法。需要注意的是,这一结果与 NLP 中的类似研究形成了鲜明对比,在 NLP 中,提示调整与完全微调相匹配,但并未超过完全微调[45]。
  2. 在所有任务组中,VPT-Deep 均优于所有其他参数高效调整协议(表 1(b,c)),这表明 VPTdeep 是存储受限环境中的最佳微调策略。
  3. 在表 1(b)中,VPT-shallow 虽然比 VPT-deep 次优,但仍比面向头部的调优方法有不小的性能提升。1(b) 表明,如果存储限制严重,VPT-shallow 是部署多任务微调模型的一个值得选择的方法。

VPT on different downstream data size.  我们研究了训练数据量对 FGVC 任务准确性的影响(VTAB 仅有 1k 个训练示例)。我们在 10% 到 80% 之间改变训练数据,并对所有方法进行比较。同样的预训练 ViT-B 用于下游训练。图 3 显示了每种方法在不同训练数据规模下的任务平均结果。

图 3 显示,在各种数据规模下,VPT-deep 均优于所有其他基线方法。深入挖掘后,使用较少可训练参数的方法,即 VPT、Linear、Adapter、Bias,在低数据量时比 Full 更占优势。然而,当线性和适配器有更多训练数据时,这一趋势就会逆转。相比之下,VPT-deep 在不同的训练数据量下仍持续优于 Full。虽然 Bias 也有类似的优势,但它的表现仍略逊于 VPT-deep (图 3 右)。

VPT on different backbone scales.  图 4 显示了 VTAB-1k 在 3 种不同骨干网规模下的性能:ViT-Base/Large/Huge。在所有 3 种骨干网选择和 VTAB-1k 的 3 个子组中,VPT-deep 都明显优于 Linear 和 VPT-shallow。更重要的是,随着模型规模的扩大,VPT-deep 相对于 Full 的优势依然存在,即在 Natural 和 Structured 组上,VPT-deep 明显优于 Full,而在 Specialized 组上,VPT-deep 的性能几乎与 Full 相当。

VPT on hierarchical Transformers.  我们将 VPT 扩展到 Swin [52],它在局部移动窗口内采用 MSA,并在更深的层上合并补丁嵌入。为简单起见,在不失一般性的前提下,我们以最直接的方式实现 VPT:在局部窗口内关注提示,但在补丁合并阶段忽略提示。实验在 ImageNet-21k 监督预训练 Swin-Base 上进行。对于 VTAB 表 2 中的所有三个子组,VPT 仍然优于其他参数有效的微调方法(b、c)。在这种情况下,Full 的总体准确率得分最高(但总参数代价高昂)。

令人惊讶的是,VPT-deep 与 VPT-shallow 相比,对 Natural 的优势有所减弱: VPT-shallow 的准确度得分略高于完全微调。

4.3 Ablation on Model Design Variants

我们在有监督的 ImageNet-21k 预训练 ViT-Base 上消融了不同的模型设计选择,并在 VTAB 上对它们进行了评估。1. 更多信息请参见附录 B。

Prompt Location.  VPT 与其他方法的一个重要区别是,在Transformers 层的输入中引入了额外的可学习参数。图 5 展示了在输入空间中插入提示的方式和位置的不同选择,以及它们对最终性能的影响。

Prepend(前置) or Add?  另一种方法是直接将提示元素添加到这些嵌入中,并保持Transformers 的输入序列长度不变,而不是像第 3.2 节中描述的那样,将提示元素预先添加到图像补丁嵌入\mathbf{E} _i 的序列中。虽然这种变体在某些情况下(如 VTAB-Natural)比 Full 更有竞争力,但在深层和浅层设置中,其性能一般都会落后于默认的 Prepend。关于这一现象的更多讨论见附录 B。

Latent or pixel space?  我们可以在公式(1)中嵌入层之前的像素层中引入提示,即 Prepend-pixel 和 Concat-channel,而不是将提示作为潜向量插入第一个Transformers 层。图 5 显示,这两种变体的自适应性能都有所下降。例如,在 VTAB-Natural 上,在投影层之前预置浅层提示(Prepend-pixel)的准确率比默认在嵌入空间预置(Prepend)下降了 6.9%。如果我们将一个新通道连接到输入图像上(Concat-channel),性能会进一步下降(在 VTAB-Natural 上准确率甚至会下降 30%)。这些观察结果表明,在 Transformers 的潜在输入空间中,提示符更容易学习与任务相关的浓缩信号。

Prompt Length.  与完全微调相比,这是调整 VPT 所需的唯一额外超参数。为便于参考,我们还消减了其他两个基线的个别附加超参数,即 Mlp 的层数和 Adapter 的缩减率。如图 6 所示,不同任务的最佳提示长度各不相同。值得注意的是,即使只有一个提示符,VPT-deep 仍然明显优于其他两个基线,并且在 VTABStructured 和 Natural 上与完全微调相比仍然具有竞争力甚至更好。

Prompt Depth.  图 7 显示了插入提示符的层数。每个变体都报告了使用 Val 集选择的最佳提示长度。一般来说,VPT 的性能与提示深度呈正相关。然而,如果我们从上到下插入提示语,准确率就会下降,这表明Transformers较早层的提示语比较晚层的提示语更重要

Final Output.  按照 ViT 的原始配置,我们使用 [CLS] 的最终嵌入(即 xN)作为分类头输入,这也是 ViT 实验中的默认设置。如图 8 所示,如果我们使用图像补丁输出嵌入的平均池化 EN 作为最终输出(Image-pool),结果基本保持不变(例如,VTAB-Specialized 为 82.4,VTAB-Specialized 为 82.3)。但是,如果池化涉及最终提示输出 ZN(提示池和全局池),准确率可能会下降 8 个百分点。

5 Analysis and Discussion

Visualization.   图 9 显示了 VTAB 中 3 个任务(SVNH [58]、EuroSAT [32]、Clevr/count [38])的 xN 的 t-SNE [55] 可视化图,即最后一个变换层之后、分类头之前的 [CLS] 嵌入图,每个测试准确率(%)子组一个。所有图表都表明,VPT-deep 可以实现线性可分离表示,同时使用的参数比 Full 更少。我们还观察到,与只对第一层输入插入提示的 VPT-shallow 相比,每个转换器层的额外可调参数(VPT-deep)提高了性能。有趣的是,在 Clevr/count(图 9(c))上,VPT-deep 和 Full 恢复了任务的底层流形结构(图像中物体的计数与街道编号或景观识别),而 VPT-shallow 和 Linear 则不同。

Apply VPT to more vision tasks.  我们通过使用 Transformer 模型 SETR-PUP [89]评估 ADE20K [90]语义分割任务,探索了 VPT 在视觉分类之外的可行性。它在 ViT 骨干上添加了一个标准 ConvNet 头,以执行分割。事实上的方法仍然是将预训练的骨干网与 ConvNet 头一起进行完全微调(Full)。我们还采用了另外两种方案进行比较:只更新头部层(Head Only),更新头部层和骨干层中的偏置向量(Bias)。表 3 3 中,我们报告了有多尺度推断和无多尺度推断的 val mIoU 结果。虽然参数效率协议无法与 Full 协议竞争,但 VPT 仍可与 Bias 协议媲美。值得注意的是,VPT 提供的结果与完全微调的最先进 ConvNet 模型(DeepLab v3+ [10])相比具有竞争力,而调整的参数(分别为 15M 和 64M)却少得多。

Apply VPT to more pre-training methods. 除了使用标注数据预先训练的骨干外,我们还尝试了两种自监督目标: MAE [30] 和 MoCo v3 [11]。表 4 表 4 报告了 VTAB-1k 和 ViTB 的结果。我们注意到,VPT 的两个变体都超过了线性,但其他技术之间的比较则不那么有说服力。就 MAE 而言,其他参数效率高的方法(如 Partial-1)优于 VPT 和 Linear。就 MoCo v3 而言,VPT 不再保持最佳性能,但与其他方法相比仍有竞争力。这表明,这两种自监督 ViT 与前几节中的监督 ViT 有本质区别。究竟为什么会出现这些差异以及这些差异是如何产生的,这些都还是未解之谜。

Apply VPT to ConvNets.   我们研究了在 ConvNets 的输入空间中添加可训练参数的想法:在输入图像的高度和宽度上填充p个可学习的提示像素。虽然这一操作看似非常规,但由于没有明显的解决方案来添加与 Transformer 类似的位置不变提示,因此我们采用了这种方法来实现 VPT。事实上,这种方法在对抗性攻击文献 [20] 中已有过探索。我们实验中的p值比之前的工作小两个数量级:例如,5 比 263。最重要的是,我们从迁移学习的角度提出了这一想法。更多讨论见附录 C。

表 5 分别列出了 ConvNeXt-B [53](在 ImageNet21k 上进行预训练)和 ResNet-50 [31](在 ImageNet-1k 上进行预训练)的结果。VPT 在较大的 ConvNet 骨干 ConvNeXt-B 中运行良好,准确率高于其他稀疏调整协议(b、c),在 19 个案例中有 8 个优于 Full。然而,在较小的 ConvNet(ResNet50)中,VPT 的优势逐渐减弱,因为在所有 19 项 VTAB-1k 任务中,VPT 都没有明显的胜出者。

6 Conclusion

我们介绍了视觉提示调整(Visual Prompt Tuning),这是一种利用大型视觉转换器模型完成各种下游任务的新型参数高效方法。VPT 在输入空间中引入针对特定任务的可学习提示,同时保持预训练的主干固定不变。我们的实验表明,VPT 可以超越其他微调协议(通常包括完全微调),同时显著降低存储成本。我们的实验还提出了一些耐人寻味的问题:不同预训练目标的视觉变形器的微调动态,以及如何以高效的方式转移到更广泛的视觉识别任务中。因此,我们希望我们的工作能激励未来的研究,探索如何更好地挖掘大型基础模型在视觉领域的潜力。

图 1. 视觉提示调整(VPT)与其他迁移学习方法的对比。(a) 当前的迁移学习协议根据调整范围进行分组: 完全微调、面向头部和面向骨干的方法。(b) VPT 在输入空间中增加了额外参数。(c) 不同方法在适应预训练 ViT-B 主干网的各种下游分类任务上的表现,并标注了平均值和标准偏差。在 24 个案例中,VPT 在 20 个案例中的表现优于完全微调,而使用的所有模型参数不到 1%。

图 2. 我们提出的视觉提示调整概述。我们探索了两种变体:(a) 在每个Transformer 编码器层的输入中预先插入一组可学习的参数(VPT-deep);(b) 仅在第一层输入中插入提示参数(VPTshallow)。在下游任务的训练过程中,只更新提示和线性头的参数,而整个Transformer 编码器被冻结。 

图 3. 不同下游数据规模的性能比较,5 个 FGVC 任务的平均值。VPT-deep 与线性(左)、适配器(中)和偏置(右)进行了比较。高亮区域显示了 VPT-deep 与比较方法之间的精度差异。为便于参考,所有图中都显示了 VPT-shallow 的结果。标记的大小与可调参数的对数比例成正比 

 图 4. 在 3 个 VTAB 任务组中,不同模型尺度(ViT-B、ViT-L 和 ViT-H)的 VPT 与 Full 的对比。高亮区域显示了 VPT 深度微调与完全微调(Full)之间的准确率差异。标记的大小与可训练参数的对数比例成正比。

图 5. 根据提示位置进行消融。我们在顶部说明了不同的位置选择,并在底部展示了结果。为便于比较,两条蓝色虚线分别代表默认 VPT-深和 VPT-浅的性能。 

图 6. 消融对提示音长度的影响。我们改变了 VPT-deep 的提示次数,并显示了每个 VTAB 分组的平均结果。为便于参考,还显示了每个任务的 VPT-deep 最佳结果的平均值。

图 7. 消融对提示语深度的影响。i → j 表示插入提示的转换器层索引。第 1 层是指最靠近输入的一层。ViT-B 共有 12 层 

图 8. 最终输出的消融情况。顶部是不同策略的图示,底部是不同策略的结果。为便于比较,蓝色虚线代表默认 VPT-深层消融的性能。 

图 9 测试集中 3 个 VTAB 任务的最终 [CLS] 嵌入 xN 的 t-SNE 可视化(来自表 1)。1. VPT 可以在不更新主干参数的情况下生成线性可分离特征 

图 10. 所有评估分类任务的数据集示例

图 11. 扩展输入序列的效果。上部是不同策略的图示,下部是不同策略的结果。为便于比较,深蓝和浅蓝两条线分别代表默认 VPT-deep 和 VPT-shallow 的性能 

图 12. 共享提示的效果。顶部是不同策略的图示,底部是不同策略的结果。为便于比较,蓝色虚线表示默认 VPT-deep 

图 13. 提示初始化的效果。为便于比较,两条蓝色虚线分别代表默认 VPT-deep 和 VPT-shallow 的性能

 图 14. 提示深度实验对提示长度的敏感性。我们为每种变体选择了最佳的提示长度。i → j 表示插入提示的转换器层索引。第 1 层是指最靠近输入的一层。ViT-B 共有 12 层

图 15. 五次运行集合的性能。我们还报告了五次运行的平均值和最佳值。每列中的最佳性能以粗体标出 

图 16. 在每项 VTAB 任务中,VPT-deep 的性能是否优于其他方法的非配对单尾不等方差 t 检验(韦尔奇 t 检验)。结果表明,在大多数情况下,VPT-deep 都明显优于其他微调方案(P < 0.05)。 

图 17. 不同微调超参数的效果。在 VTABSpecialized: KITTI/Distance 任务进行了评估。其他调整方法的阴影为灰色 

图 18. 训练(左)和推理(右)期间 GPU 的峰值内存和延迟(ms/img)。为便于比较,灰色虚线代表完全微调时的延迟和内存。

图 19. VPT-deep 与 VPT-prefix 的对比:推理过程中 GPU 内存(左)和延迟(右)的峰值。为便于比较,灰色虚线代表完全微调的延迟和内存。 

图 20. 下游数据大小对每个 FGVC 任务的影响。标记大小与可调参数的对数比例成正比 

图 21. 更多 VTAB 任务的最终 [CLS] 嵌入 xN 的 t-SNE 可视化。我们将目标类别少于或等于 20 个的任务纳入可视化范围 

表 1. 在有监督的 ImageNet-21k 上预先训练的 ViT-B/16。对于每种方法和每个下游任务组,我们报告了与 Full 相比的平均测试准确率得分和 (-) 中的获胜次数。"总参数 "表示所有 24 个下游任务所需的总参数。"范围 "表示每种方法的调整范围。"额外参数 "表示除了预训练的主干和线性头之外的额外参数。除全精细外,所有方法中的最佳结果均以粗体标出。在 24 个案例中,VPT 在可训练参数明显较少的情况下,有 20 个案例优于完全微调法

表 2. 不同的Transformer 架构: Swin-B 以受监督的 ImageNet-21k 为骨干进行了预训练。对于每种方法和每个下游任务组,我们报告了与 Full 相比的平均测试准确率得分和(-)中的获胜次数。总参数 "一栏表示所有 19 个下游任务所需的总参数。除 Full 外,所有方法的最佳结果均以粗体显示

表 3. 语义分割: ADE20k [90] 与 SETR [89] 在 ViT-L 上的验证结果。除 Full 外,所有方法中的最佳 mIoU 分数均以粗体标出。还包括完全微调 ResNet-101 [10] 的结果。SS/MS:单尺度/多尺度推理

表 4. 不同的预训练目标: MAE [30] 和以 ViT-B 为骨干的 MoCo v3 [11]。对于每种方法和每个下游任务组,我们报告了与 Full 相比的平均测试准确率得分和(-)中的获胜次数。"总参数 "表示所有 24 个下游任务所需的总参数。除 Full 外,所有方法的最佳结果均以粗体显示

表 5. 将 VPT 应用于 ConvNets: ResNet-50 和 ConvNeXt-Base。对于每种方法和每个下游任务组,我们报告了与 Full 相比的平均测试准确率得分和(-)中的获胜次数。"总参数 "表示所有 19 个下游任务所需的总参数。除 Full 外,所有方法的最佳结果均以粗体显示

 表 6. 所评估的每种微调方法的实施细节。⋆:我们观察到,在 24 项评估任务中的 6 项任务中,VPT-shallow 有时能从更大的基础 LR 中获益,在这些任务中,我们从 {1000.0,500.0,250.0,100.0} 开始搜索。

表 7. 所评估的各种数据集的规格。⋆:我们随机抽取了 train 和 val 数据集,因为没有公开的拆分数据。

表 8. 本文中使用的不同预训练骨架的规格。参数(M)是特征提取器的参数。"批量大小 "列显示了线性/部分/{完全、偏差、适配器}/VPT(p < 100)/VPT(p ≥ 100)的批量大小。/ VPT (p < 100) / VPT (p ≥ 100)。所有骨干都在分辨率为 224×224 的 ImageNet [16] 上进行了预训练

表 9. 将带偏差的 VPT 与第 4.2 节中预先训练的 ViT-B 结合。对于每种方法和每个下游任务组,我们报告了与 Full 相比的平均测试准确率得分和(-)中的获胜次数。混合方法与其 VPT 对应方法之间的差异用不同颜色表示

表 10. 关于 VPT-deep 在 19 项 VTAB 任务中的表现是否优于其他方法的非参数配对单尾 t 检验(Wilcoxon 符号秩检验)。结果表明,VPT-deep 在统计上确实明显优于其他微调方案(P < 0.05)

表 11. 在有监督的 ImageNet-21k 上预先训练的 ViT-B/16,微调后的分辨率为 384×384。我们还包括图像分辨率为 224×224, p = 380 的 VPT,因此有效图像分辨率为 384×384。对于每种方法和每个下游任务组,我们都报告了平均测试准确率得分和(-)中与 Full 相比的获胜次数。"总参数 "表示所有 24 个下游任务所需的总参数。除 Full 外,所有方法的最佳结果均以粗体显示

表 12. 使用在有监督的 ImageNet-21k 上预先训练的 ViT-B/16 的成本分析。我们报告了每种方法和每个下游任务组在训练和推理时的延迟(ms/img)和 GPU 内存使用峰值(GB)。"调整参数 "表示所需的可学习参数分数。"范围 "表示每种方法的调整范围。"额外参数 "表示除了预训练的骨干和线性头之外的额外参数。所有实验均使用相同的 A100 GPU

表 13. 表 1 中针对 VTAB-1k 的每个任务微调结果。1 中 VTAB-1k 使用预训练 ViT-B/16 的每个任务微调结果

表 14. 表 1 中五项 FGVC 任务的每个任务微调结果。1 中针对五项 FGVC 任务的预训练 ViT-B/16

附录

A Implementation Details

我们使用PyTorch[62]在NVIDIA A100-40 GB GPU上实现所有实验。

A.1 Classification Experiments

VPT.  我们使用每个数据集的验证集来寻找最佳提示长度 p,见第 3.2 节。提示符长度是我们调整的唯一一个针对 VPT 的超参数。对于 Transformer 主干网,p的取值范围分别为{1,5,10,50,100,200};对于 ViT 和 Swin,p的取值范围分别为{1,5,10,50}。对于这两种架构而言,p的最大选择范围大致接近每个 MSA 中的图像片段标记数(ViT:196;Swin:49)。我们还对 VPT-deep 采用了 0.1 的dropout率。对于 ConvNets,p 的范围为 {1、3、5、7、9、11}。每个提示都采用 xavier 统一初始化方案[26]随机初始化。我们沿用了原有的 "骨干网 "设计方案,例如是否存在分类标记[CLS],或是否使用最终的[CLS]嵌入作为分类头输入。

Adapter.  适配器 [34] 在每个Transformer 层内插入额外的轻量级模块。一个适配器模块通常由一个线性向下投影(缩减率为r)、一个非线性激活函数和一个线性向上投影以及一个残差连接组成。文献[63,64]对所有可能的配置进行了详尽的研究,发现只有在 FFN "Add & LayerNorm "子层之后插入适配器的效果最好。因此,我们在自己的实施中也采用了这种设置。我们在{8, 64, 256}范围内扫描了缩减率r

Augmentation and other hyper-parameters.  在训练过程中,我们采用了标准的图像增强策略:使用 ImageNet 平均值和标准偏差进行归一化处理,将五个 FGVC 数据集的尺寸随机调整为 224×224,并随机进行水平翻转,将 VTAB-1k 套件的尺寸调整为 224×224。表 6 总结了我们使用的优化配置。按照文献[56]的方法,我们使用每个任务的验证集进行网格搜索,以找到特定的超参数、学习率和权重衰减值。根据线性缩放规则[42,27,11,30],学习率设定为base\_lr×b/256,其中 b是特定模型使用的批次大小,base\_lr从表 6 中指定的范围内选择。每个实验的最优超参数值见附录 D。

Datasets and pre-trained backbones specifications.   表 7 和表 8 总结了本文中使用的分类数据集和所有预训练骨干的统计数据和详细信息。图 10 包括所有 24 个评估分类任务的图像示例。

A.2 Semantic Segmentation Experiments

ADE20K [90] 是一个具有挑战性的场景解析基准,包含 150 个细粒度标签。训练集和验证集分别包含 20,210 张和 2,000 张图像。我们在实现过程中使用了公共代码库 MMSegmentation [15]。

SETR [89] 是一种使用 ViT 作为编码器的竞争性分割框架。PUP 是一种渐进式上采样策略,由连续卷积层和双线性上采样操作组成。根据 MMSegmentation 的再现,在多种解码器选择中,PUP 的效果最好,因此我们在实现过程中也使用了它。

在 SETR-PUP 中应用 VPT 时,我们只在 SETR 的 ViT 编码器主干中插入提示。对于解码器来说,只有图像补丁嵌入才被用作输入,而提示嵌入则被丢弃。与识别任务一样,在训练过程中只学习 PUP 解码头和提示,ViT 主干被冻结。

对于完全微调,我们使用与 MMSegmentation 相同的超参数。对于 HeadOnly、Bias 和 VPT,我们使用学习率 {0.05, 0.005, 0.0005, 0.001} 的超参数扫描。所有方法的最佳学习率均为 0.005。我们扫描了提示长度 p∈{1, 5, 10, 50, 100, 200}。对于 VPT,我们还将学习率乘数改为 1.0,而不是默认的 10.0,因此解码器头和提示符共享相同的学习率。其他超参数与完全微调相同。

B Extended Analysis

Effect of expanding input sequence length.  如表 1 所示。如表 1 所示,通过使用可学习的提示语扩展输入序列,VPT 在 24 个评估任务中的 20 个任务上取得了比 Full 更好的性能。为了研究 VPT 的优势是否归功于其扩大的输入序列长度,我们又对两个变体进行了实验:(1) 在微调阶段保持提示语冻结(提示语固定)。(2) 只调整 [CLS] 标记([CLS]-Learned)。从图 11 中我们可以看出,更新提示嵌入(提示-已学习)的效果显著,而提示-固定的效果与线性效果相当。这表明,VPT 的最终性能主要来自学习的提示嵌入,而不是扩大的序列长度。更新 [CLS] 标记与更新 1 个提示符([CLS] vs. Learnedp=1)的效果类似,但仍然落后于默认设置,在默认设置中,我们根据 val 集手动选择最佳的提示符数量。

Sharing prompts.  在图 12 中,我们通过在Transformer 层内(Shared-intra)、所有层间(Shared-inter)以及Transformer 中插入的所有提示(Shared-all)设置相同的提示嵌入参数,来检验共享提示参数的效果。我们可以看到 (1) 在层内共享提示(Shared-intra)的性能与使用一个提示(Defaultp=1)的性能相当,甚至略胜一筹,这进一步证明了扩展输入序列的价值。(2) 虽然 Shared-intra 的表现总体上不如 Default,但令人惊讶的是,在使用相似数量的可训练参数时,Shared-inter 的表现略微优于我们的默认 VPT-deep(所有 VTAB 任务的参数总数:1.14× vs 1.14×): Shared-inter 和默认值的参数总数分别为 1.14× 和 1.13×)。仔细研究发现,Shared-inter 的最佳提示长度 p 一般大于 Default,即所有 VTAB 任务的平均提示长度:Shared-inter 与 Default 分别为 64.58 与 60.94。(3) 在层间和层内共享相同的提示嵌入(Shared-all)会降低性能,但在三个 VTAB 分组中仍然超过了线性探测结果。

Prompt initialization.  在 NLP 中,如 [45] 所示,更复杂的提示初始化可使提示调整受益匪浅。我们研究了视觉提示是否也是这种情况。我们利用下游目标类别的原型表示,从而用列举输出空间的嵌入对提示进行初始化。由于我们希望模型能在给定测试示例的情况下生成接近于这些原型表征之一的输出嵌入,因此以这种方式初始化提示可能会给模型一些关于目标类别的提示,从而有助于改进优化过程。

具体来说,我们使用下流数据集训练拆分的每个目标类别中的平均最终[CLS]嵌入。给定具有N层的预训练 ViT 和具有 c个目标类别的下流训练集,对于每个训练示例,我们计算最终的 [CLS] 嵌入,\mathbf{x}_N\in \mathbb{R}^d。然后我们对每个CLS目标类中的这些嵌入进行平均,以得到\left\{\hat{\mathbf{x}}_{N,}^{k} \in \mathbb{R}^{d} \mid k \in \mathbb{N}, 1 \leq k \leq c\right\}。设置提示长度p = c,对于 VPT-shallow,我们用\left\{\hat{\mathbf{x}}_{N}^{k} \right\}_{k=1}^{k=c}初始化\mathbf{P},并且用\left\{\hat{\mathbf{x}}_{N}^{k} \right\}_{k=1}^{k=c}初始化每个\mathbf{P} _i,其中i = 0, 1, . ,N - 1,表示 VPT-DEEP。

在图 13 中,我们比较了使用上述初始化策略(CLS)和默认随机初始化(Random)的微调性能。我们还报告了在微调阶段固定提示(--fixed)的结果。如图 13 所示,令人惊讶的是,我们的默认随机初始化(随机)总体上效果最好,在没有上述额外预处理步骤(CLS)的情况下,在 VTAB 的不同分组中效果一致。CLS 在 "Natural "分组和 "Specialized  "分组中的效果相当。

Prompt depth vs. prompt length.  在图 7 中,我们删除了插入提示的层数。对于每个提示深度变体,图 7 报告了使用每个任务的最佳提示长度(图 14 中的"- → -(最佳)")得出的结果。在这里,我们采用了另一种设置,即在所有其他提示深度变体中使用 1 → 12 的最佳提示长度。比较"-→-(最佳)"和"-→-",我们发现不同深度的提示符长度对提示符的敏感度不同,尤其是在只插入九层提示符的情况下(3→12,12→3)。

Combine VPT with Bias Tuning.  我们在主论文中的实验表明,"偏置 "是一种具有竞争力的参数效率调整基线(例如,表 1(c))。1(c)). 基于这一观察结果,我们探索了另一种方案,即同时更新提示和预训练骨干网中的偏置项,保持骨干网中的其他内容不变(VPT+Bias)。如表 9 所示 如表 9 所示,出乎我们意料的是,将偏置项与 VPT 结合在一起并没有产生更优的结果,甚至在所有 3 个任务分组中都削弱了 VPT-deep。这表明这两种方法并不一定是互补的。

Prompt ensembling.  [45] 证明了 prompt 在模型集合中的效率。对于 k 个模型的集合,我们只需要存储学习到的提示向量,而不需要存储整个微调模型参数的 k 份副本(例如,ViT-H 的 k×2.5GB)。此外,在推理过程中,给定一个测试实例,只需执行一次前向传递,并使用专门设计的批次,复制原始数据但使用不同的提示。 

鉴于这些优势,我们还研究了 VPT 在提示语组合方面的有效性。我们针对每个 VTAB 任务使用不同的随机种子训练 5 个不同的提示,使用的预训练 ViT-B 骨干和超参数与表 1 中的相同。1. 图 15 显示,VPT-deep 的集合效果优于平均水平,甚至优于最好的单提示方法,也优于包括 Full 在内的其他集合微调方法。

Test of statistical significance.  我们对 VPT-deep 在 19 项 VTAB 任务中的表现是否优于其他微调方法进行了非参数配对单尾 t 检验(Wilcoxon 符号秩检验 [82])(零假设 H0 表示 VPT-deep 和备用基线方法之间的平均 VTAB 表现差异为零。备择假设 H1 表明,VPT-deep 在 VTAB 上的表现优于基线方法)。表 10 表 10 列出了每种测试的 p 值,每种比较方法的观察数均为 19(我们使用 19 个 VTAB 任务和所有微调方法的 5 次运行的平均准确率分数)。在所有比较的微调方案中,VPT-deep 的改进都具有显著的统计学意义(p < 0.05)。

我们还对每个 VTAB 任务的单次运行(观察次数 = 5)进行了不等方差的非配对单尾 t 检验(韦尔奇 t 检验 [81])(H0 表示 VPT-deep 和其他基线方法在特定 VTAB 任务中的表现相同,而 H1 表示 VPT-deep 在特定 VTAB 任务中的表现优于其他基线方法)。图 16 显示了每个任务中每对 <VPT-deep, 基线方法> 的 p 值。在 19×8 = 152 个案例中,我们拒绝了 127 个案例的 H0(p < 0.05)。与 Full 方法相比,VPT-deep 在 19 项任务中的 11 项任务上取得了统计意义上的显著提高。

Effect of different fine-tuning hyper-parameters.   在图 17 中,我们展示了不同微调协议在不同微调超参数(包括学习率和权重衰减)上的表现。对于我们提出的 VPT-deep,我们还消减了提示长度 p 的不同选择,这是唯一需要手动调整的超参数。所有实验都是在 KITTI/Distance 任务(VTAB-Specialized)的估值集上进行评估的。我们观察到 Linear 和 VPT 的不同行为。这两种方法在微调阶段都会冻结主干参数。一般来说,线性探测对权重衰减值更为敏感,而 VPT 则同时受学习率和权重衰减值的影响。提示长度较大的 VPT 对学习率的选择也不太敏感。

Effect of image resolution.   最初的 ViT 论文[19]发现,使用更高的图像分辨率(384×384)进行微调有利于下游识别任务。本文介绍的所有识别实验都是在 224×224 分辨率下进行微调的。如表 11 所示。如表 11 所示,我们使用与表 1 相同的设置重新运行了 VTAB 实验,但分辨率由 384×384 改为 224×224。1 中的相同设置重新运行 VTAB 实验,但分辨率为 384,而不是默认的 224。我们可以看到,在所有参数高效调整协议中,VPT-deep 仍然取得了最佳性能,甚至在 19 项任务中的 15 项任务上优于完全微调。虽然总体而言,图像分辨率的提高并没有带来更好的完全微调性能,但它确实略微提升了 VPT-deep 的性能。

表 11 中另一个有趣的观察结果是,在使用 224 微调分辨率和更大的 p = 380 值时,VPT 可以达到与使用 384 分辨率的 Full 算法相似甚至更好的性能,同时使用相同的输入序列长度和更少的可训练参数。

Empirical computational cost.  VPT 可能存在的一个限制是Transformers需要额外的输入序列长度。理论上,MSA 的复杂度是输入序列长度的二次方,但由于硬件细节(如车道宽度和高速缓存大小)的影响,实际速度可能并非如此[19]。在表 在表 12 和图 18 中,我们研究了所有微调协议的经验计算成本(即延迟)以及训练和推理时间的 GPU 内存使用峰值。所有实验都使用相同的 A100 GPU,训练和推理的批量大小均为 64。我们可以看到,序列长度的理论二次缩放几乎没有发生在 VPT 上。例如,长度增加一倍(p = 200 对 m = 198)基本上只会导致 2 倍(而不是 4 倍)的推理延迟和 GPU 内存峰值(在完全微调的情况下)。对于训练而言,减少提示次数将大大减少延迟。

在测试期间,VPT 的一种等效实现方式是直接将参数预置到 Transformer [48] 自我关注模块内部的键和值数组中(VPT-prefix)。虽然我们发现这种实现方式并不能提高 VTAB 数据集的准确率,但却降低了推理过程中的计算成本。图 19 显示了不同 p 值下的对比情况。VPT-prefix 可以大大减少测试时间延迟和 GPU 内存峰值,尤其是当 p 变大时。

C Further Discussion

VPT vs. Adversarial Reprogramming (AR).  不同之处在于 (1) AR 文献[20]中注入输入空间的学习参数数量是我们的近 20 倍(264k 对 13k)。VPT 的参数效率明显更高;(2) AR 在 ConvNet 中显示了其有效性,而 VPT 可以应用于更广泛的架构,包括 ViT 和 Swin。此外,VPT 的通用性更强,可以深入到预训练骨干网的更深层(图 2),而 AR 仅适用于 ConvNet 的第一输入层。(3) 另一个区别是,我们的设置同时更新提示和分类头,而 AR [20] 直接使用预训练的分类头。我们的设置更具通用性,可应用于具有更广泛预训练目标的模型(如 MAE [30],它不包括预训练分类头)和更广泛的视觉任务(如分割)。

Visual prompt vs. textual prompt.  我们的论文还发现了视觉提示和文本提示之间的差异:我们表明,在 24 个案例中,VPT 甚至在 20 个案例中优于全模型微调,这与 NLP 的相关工作[45]不谋而合。我们还发现,图 13 中的随机初始化提示效果更好,而较早层的提示更重要(图 7 和 14),这也与 NLP 方面的观察结果不同[45,51]。这些差异表明,视觉提示可能与文本提示有本质区别,因此需要进一步研究。延迟(毫秒/图像) 完全微调 延迟(毫秒/图像) 完全微调

D Supplementary Results

Numerical results of Table 1.  表 13 和表 14 列出了表 1 中评估的 24 个分类任务的每个任务结果。

Per-task results on training data ablations.   图 20 展示了五个 FGVC 数据集的每个任务结果。我们观察到与图 3 类似的趋势:在中小型数据机制中,所有参数效率方法的性能都优于完全微调方法,而在五项 FGVC 任务中,VPTdeep 在各种数据规模下的性能始终优于完全微调方法。

More t-SNE visualizations.  在图 21 中,我们展示了更多的 t-SNE 可视化效果,与图 9 类似,适用于所有小于或等于 20 个目标类别的 VTAB 数据集。

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

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

相关文章

软件测试——面试八股文(入门篇)

今天给大家分享软件测试面试题入门篇&#xff0c;看看大家能答对几题 一、 请你说一说测试用例的边界 参考回答&#xff1a; 边界值分析法就是对输入或输出的边界值进行测试的一种黑盒测试方法。通常边界值分析法是作为对等价类划分法的补充&#xff0c;这种情况下&#xff…

IAR全面支持芯驰科技E3系列车规MCU产品E3119/E3118

中国上海&#xff0c;2024年7月11日 — 全球领先的嵌入式系统开发软件解决方案供应商IAR与全场景智能车芯引领者芯驰科技宣布进一步扩大合作&#xff0c;最新版IAR Embedded Workbench for Arm已全面支持芯驰科技的E3119/E3118车规级MCU产品。IAR与芯驰科技有着悠久的合作历史&…

线程池及其底层工作原理

一、线程池是什么 线程池就是事先将多个线程对象放到一个容器中&#xff0c;当使用的时候就不用 new 线程而是直接去池中拿线程即可&#xff0c;节省了开辟子线程的时间&#xff0c;提高的代码执行效率在 JDK 的 java.util.concurrent.Executors 中提供了生成多种线程池的静态方…

分页stater

自定义aop,以添加注解的方法为切入点&#xff0c;对目标方法做一层增强 PageXAop代码如下&#xff1a; package cn.smart.pagex.aop;import com.github.pagehelper.PageHelper; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.ProceedingJoinPoint; import org.a…

漏洞复现 | Showdoc反序列化

非常简单的一个靶场 靶场地址&#xff1a;https://hack.zkaq.cn/ 打开靶场&#xff0c;弹出了这种登录框&#xff0c;这也成为了后面的一个坑点&#xff0c;记住这个登录框。 看到了注册功能&#xff0c;showdoc有注册功能我们就不用尝试前台SQL注入了&#xff0c;直接注册…

Verilog基础:简单标识符和转义标识符

相关阅读 Verilog基础https://blog.csdn.net/weixin_45791458/category_12263729.html?spm1001.2014.3001.5482 标识符(identifier)是一个为了引用而给一个对象起的名字。一个标识符可以是一个简单标识符&#xff0c;也可以是一个转义标识符。本文将对两者进行详细阐述。 简…

Nuxt.js 错误侦探:useError 组合函数

title: Nuxt.js 错误侦探&#xff1a;useError 组合函数 date: 2024/7/14 updated: 2024/7/14 author: cmdragon excerpt: 摘要&#xff1a;文章介绍Nuxt.js中的useError组合函数&#xff0c;用于统一处理客户端和服务器端的错误&#xff0c;提供statusCode、statusMessage和…

【C++】—— 初识C++

【C】—— 初识C 一、什么是 C二、C 的发展历史三、C 版本更新四、C 的重要性五、C 在工作领域中的运用六、C 书籍推荐&#xff1a; 一、什么是 C C语言 是结构化和模块化的语言&#xff0c;适合处理较小规模的程序。对于复杂的问题&#xff0c;规模较大的程序&#xff0c;需要…

k8s快速部署一个网站

1&#xff09;使用Deployment控制器部署镜像&#xff1a; kubectl create deployment web-demo --imagelizhenliang/web-demo:v1 kubectl get deployment,pods[rootk8s-matser ~]# kubectl get pods NAME READY STATUS RESTARTS A…

STM32 BootLoader 刷新项目 (四) 通信协议

STM32 BootLoader 刷新项目 (四) 通信协议 文章目录 STM32 BootLoader 刷新项目 (四) 通信协议1. 通信流程2. 支持指令3. 通信流程4. 指令结构5. 操作演示 前面几章节&#xff0c;我们已经介绍了BootLoader的整体程序框架&#xff0c;方案设计&#xff0c;以及STM32CubdeMX的配…

数据结构(4.0)——串的定义和基本操作

串的定义(逻辑结构) 串&#xff0c;即字符串(String)是由零个或多个字符组成的有序数列。 一般记为Sa1a2....an(n>0) 其中&#xff0c;S是串名&#xff0c;单引号括起来的字符序列是串的值;ai可以是字母、数字或其他字符&#xff1b;串中字符的个数n称为串的长度。n0时的…

常开常闭液位传感器怎么选

在选择常开常闭传感器时&#xff0c;关键是根据其工作原理和应用需求来进行合适的选择&#xff0c;以确保系统的正常运行和效率。常开和常闭传感器的设计在信号输出时有明显差异&#xff0c;因此在不同的控制系统中选择合适的类型至关重要。 常开传感器的特点是在没有检测到目…

Nginx的访问限制与访问控制

访问限制 访问限制是一种防止恶意访问的常用手段&#xff0c;可以指定同一IP地址在固定时间内的访问次数&#xff0c;或者指定同一IP地址在固定时间内建立连接的次数&#xff0c;若超过网站指定的次数访问将不成功。 请求频率限制配置 请求频率限制是限制客户端固定时间内发…

C#小结:未能找到类型或命名空间名“xxx”(是否缺少 using 指令或程序集引用?)

方案一&#xff1a;移除这些失效的引用&#xff0c;下载对应版本的dll&#xff0c;重新添加引用 方案二&#xff1a;项目右键属性-调整目标框架版本&#xff08;一般是降低版本&#xff09; 方案三&#xff1a;调整编译顺序&#xff1a; 项目A&#xff1a;引用1、引用2 &…

鸿蒙架构之AOP

零、主要内容 AOP 简介ArkTs AOP 实现原理 JS 原型链AOP实现原理 AOP的应用场景 统计类&#xff1a; 方法调用次数统计、方法时长统计防御式编程&#xff1a;参数校验代理模式实现 AOP的注意事项 一、AOP简介 对于Android、Java Web 开发者来说&#xff0c; AOP编程思想并不…

最值得推荐的10款Windows软件!

AI视频生成&#xff1a;小说文案智能分镜智能识别角色和场景批量Ai绘图自动配音添加音乐一键合成视频播放量破百万https://aitools.jurilu.com/1.音乐播放器——Dopamine Dopamine是一款音乐播放器&#xff0c;设计简洁美观。它支持多种音频格式&#xff0c;包括wav、mp3、ogg…

亚马逊IP关联是什么?要怎么解决呢?

亚马逊不仅提供了广泛的商品和服务&#xff0c;也是许多企业和个人选择的电子商务平台。然而&#xff0c;与亚马逊相关的IP关联问题&#xff0c;特别是在网络安全和运营管理方面&#xff0c;经常成为使用亚马逊服务的用户和商家关注的焦点。通过了解亚马逊IP关联的含义、可能的…

MMLab-dataset_analysis

数据分析工具 这里写目录标题 数据分析工具dataset_analysis.py数据可视化分析 benchmark.pybrowse_coco_json.pybrowse_dataset.pyOptimize_anchors mmyolo、mmsegmentation等提供了数据集分析工具 dataset_analysis.py 数据采用coco格式数据 根据配置文件分析全部数据类型或…

pico+unity手柄和摄像机控制初级设置

1、摄像头配置 摄像头模式、floor是追踪原点类型&#xff08;将根据设备检测到地面的高度来计算追踪原点&#xff09;&#xff0c; Device 模式时&#xff0c;为通常理解的 Eye 模式&#xff0c;不会将根据设备检测到地面的高度来计算追踪原点 选择floor时&#xff0c;修改相…

K8S ingress 初体验 - ingress-ngnix 的安装与使用

准备环境 先把 google 的vm 跑起来… gatemanMoreFine-S500:~/projects/coding/k8s-s/service-case/cloud-user$ kubectl get nodes NAME STATUS ROLES AGE VERSION k8s-master Ready control-plane,master 124d v1.23.6 k8s-no…