CLIP-Adapter: Better Vision-Language Models with Feature Adapters 论文解读
abstract
大规模对比视觉-语言预训练在视觉表示学习方面取得了显著进展。与传统的通过固定一组离散标签训练的视觉系统不同,(Radford et al., 2021) 引入了一种新范式,该范式在开放词汇环境中直接学习将图像与原始文本对齐。在下游任务中,通常需要精心设计的文本提示来进行零样本预测。为避免复杂的提示工程,(Zhou et al., 2021) 提出了上下文优化方法,利用少量样本学习连续向量作为任务特定的提示。在本文中,我们展示了除了提示调优之外,还有一条实现更优视觉-语言模型的替代路径。提示调优是针对文本输入的,而我们提出的 CLIP-Adapter 则通过在视觉或语言分支上应用特征适配器来进行微调。具体而言,CLIP-Adapter 采用了额外的瓶颈层来学习新特征,并通过残差式特征融合与原始预训练特征相结合。因此,CLIP-Adapter 能够在保持简单设计的同时超越上下文优化。我们在各种视觉分类任务上进行了实验和广泛的消融研究,证明了我们方法的有效性。
introduction
视觉理解任务(如分类任务【Krizhevsky et al., 2012; He et al., 2016; Howard et al., 2017; Dosovitskiy et al., 2021; Touvron et al., 2021; Gao et al., 2021a; Mao et al., 2021】、目标检测【Ren et al., 2015; Carion et al., 2020; Gao et al., 2021b】和语义分割【Long et al., 2015】)已经因更优的架构设计和大规模高质量数据集而显著改善。然而,为每个视觉任务收集高质量大规模数据集非常耗费人力和成本,难以扩展。为了解决这个问题,视觉领域普遍采用了“预训练-微调”的范式,即先在如 ImageNet【Krizhevsky et al., 2012】这样的超大规模数据集上预训练模型,再在各种下游任务上进行微调。然而,这种方法在许多下游任务上仍需大量标注数据来进行微调。
最近,对比语言-图像预训练(Contrastive Language-Image Pretraining,CLIP)【Radford et al., 2021】被提出,它通过利用大规模噪声图文对的对比学习来解决视觉任务。CLIP 无需任何标注即可在各种视觉分类任务中取得令人振奋的性能(即零样本迁移),其方法是将视觉类别嵌入到合适的手工设计模板中作为提示。
尽管基于提示的零样本迁移学习显示出了良好的性能,但设计优质的提示依然是一个需要大量时间和领域知识的工程问题。为了解决这一问题,上下文优化(Context Optimization, CoOp)【Zhou et al., 2021】进一步提出通过少量样本学习连续的软提示,以替代精心设计的硬提示。CoOp 在零样本 CLIP 和线性探针 CLIP 的设置下,实现了显著的少样本分类性能提升,展现了提示调优在大规模预训练视觉-语言模型上的潜力。
本文提出了一种不同的方法,通过特征适配器而非提示调优来更好地适应视觉-语言模型。与 CoOp 使用软提示优化不同,我们只在轻量化的额外特征适配器上进行微调。由于 CLIP 过参数化以及缺乏足够的训练样本,直接对整个 CLIP 模型进行微调会导致特定数据集的过拟合
,并且训练过程因涉及所有 CLIP 层的正向与反向传播而非常缓慢。受到参数高效迁移学习中适配器模块【Houlsby et al., 2019】的启发,我们提出了 CLIP-Adapter,它只需微调少量额外权重,而不是优化 CLIP 的所有参数。
CLIP-Adapter 采用轻量化的瓶颈架构,通过减少参数数量来防止少样本学习中的潜在过拟合问题。同时,CLIP-Adapter 在以下两个重要方面不同于 Houlsby 等人的方法:
- CLIP-Adapter 仅在视觉或语言主干网络的最后一层后添加两个额外的线性层,而原始适配器模块则插入语言主干网络的所有层中;
- CLIP-Adapter 通过残差连接将原始的零样本视觉或语言嵌入与相应的微调特征进行混合。通过这种“残差式融合”,CLIP-Adapter 能够同时利用存储在原始 CLIP 中的知识以及从少样本训练样本中学到的新知识。
我们的贡献可以总结如下:
- 提出 CLIP-Adapter,通过残差式特征融合实现高效的少样本迁移学习。
- 与 CoOp 相比,CLIP-Adapter 在保持设计简单的同时,实现了更优的少样本分类性能,证明了其作为提示调优的有力替代方案。
- 在 11 个分类数据集上对 CLIP-Adapter 进行了广泛的消融研究,以分析其特性。代码将在以下网址公开:
https://github.com/gaopengcuhk/CLIP-Adapter。
- 过参数化(Over - parameterization)
- 定义:过参数化是指模型的参数数量远远超过了训练数据所包含的信息量。在CLIP这个案例中,它有大量的参数。例如,CLIP模型的架构可能包含许多层的神经网络,每层都有众多的神经元,这些神经元对应的权重等参数数量巨大。
- 后果:过多的参数使得模型具有很强的表达能力,它可以拟合非常复杂的函数。但这也带来了问题,模型可能会过度关注训练数据中的噪声或者一些不重要的细节。就好像一个记忆力超强的学生,他不仅记住了知识的重点,还把一些无关紧要的细节(如书本上印刷的小瑕疵等类似噪声)也记住了。
- 微调缺乏足够的训练样本
- 定义:这意味着用于训练CLIP模型的数据量相对其庞大的参数数量来说是不够的。如果把模型比作一个饥饿的人,那么训练样本就是食物,食物量太少,无法满足这个“人”的需求。
2 相关工作
2.1 模型微调
深度神经网络对数据有很高的需求。然而,收集和标注大量高质量数据的成本非常高,对于某些特殊领域甚至是不可能的。“预训练-微调”范式为不同的计算机视觉【Krizhevsky et al., 2012; Simonyan and Zisserman, 2015; He et al., 2016】和自然语言处理【Kenton and Toutanova, 2019; Dong et al., 2019; Conneau et al., 2020】任务提供了一个良好的解决方案,并且已经被广泛应用多年。
为了在下游任务中实现数据高效的微调,适配器模块(adapter modules)【Houlsby et al., 2019】被提出,其通过冻结主干网络的权重并在每个 Transformer 层中插入可学习的线性层实现数据高效的迁移学习。不同于传统适配器模块,本文提出的 CLIP-Adapter 通过对 CLIP 生成的特征嵌入或分类器权重应用简单的残差变换层来实现功能优化。依靠残差连接和瓶颈线性层,CLIP-Adapter 在少样本学习环境下可以显著提高 CLIP 的性能,并且优于最近提出的 CoOp 方法。
为了缓解分布转移(distribution shifting)
下的性能差距,WiSE-FT【Wortsman et al., 2021】提出了一种后置集成(post-ensemble)方法来提升 CLIP 的分布外鲁棒性
。虽然 WiSE-FT 在微调过程中冻结了图像分支的权重,CLIP-Adapter 则可以同时应用于图像和文本分支,并通过一个可学习的门控比率动态平衡和混合来自原始特征和 CLIP-Adapter 输出的知识
。
- 分布转移(Distribution Shifting)
- 定义:在机器学习和数据处理的背景下,分布转移是指训练数据和测试数据(或者在模型实际应用中的数据)的概率分布发生了变化。例如,假设我们训练一个图像分类模型来识别不同种类的动物,训练数据中的动物图像是在自然环境下拍摄的,颜色、角度等特征具有一定的分布规律。但在实际应用中,模型遇到的可能是经过艺术加工(如漫画风格)的动物图像,此时数据的分布就发生了转移。
- 影响:这种分布的变化会导致模型性能下降,因为模型是基于训练数据的分布来学习特征和模式的,当新数据的分布不同时,模型可能无法准确地进行判断。
- 可学习的门控比率动态平衡和混合来自原始特征和CLIP - Adapter输出的知识
- 原始特征和CLIP - Adapter输出的知识:CLIP模型本身会输出原始的特征表示,这些特征包含了模型对输入数据(如视觉 - 语言数据)的初步理解。CLIP - Adapter是一种改进的模块,它也会输出经过处理后的特征。这两种特征都有各自的价值。
- 门控比率(Gating Ratio):这是一个可学习的参数,就像是一个可以调节的阀门。它可以控制来自原始特征和CLIP - Adapter输出特征的比例。
- 动态平衡和混合:在模型的运行过程中,这个门控比率不是固定不变的,而是可以根据数据的情况和模型的学习过程动态调整。例如,在某些数据样本上,可能原始CLIP特征更有用,门控比率就会调整为让更多的原始特征通过;而在另一些情况下,CLIP - Adapter输出的特征可能更具优势,门控比率就会倾向于它,从而实现对两种知识的动态平衡和混合,以得到更好的特征表示用于后续的任务,如分类等。
- 分布外鲁棒性(Out - of - Distribution Robustness)
- 定义:鲁棒性(Robustness)是指系统(在这里是机器学习模型)在面对异常情况或者不确定性时仍能保持良好性能的能力。分布外鲁棒性则是指模型在面对与训练数据分布不同(即分布外)的数据时的鲁棒性。
- 重要性:在实际应用中,我们很难保证模型遇到的数据都和训练数据的分布完全一致。具有良好的分布外鲁棒性的模型,在遇到新的、未曾在训练中出现过的情况(如数据分布转移)时,依然能够给出相对合理的结果。例如,一个具有高分布外鲁棒性的图像分类模型,即使面对风格迥异的图像,也能尽可能准确地进行分类,而不是完全失效。
2.2 提示设计
提示设计(Prompt Design)【Liu et al., 2021a】因 GPT 系列模型的成功而受到广泛关注【Radford et al., 2019; Brown et al., 2020】。GPT-3 展示了一种全新的能力:通过在大规模数据集上训练的大型自回归语言模型,可以在无需微调基础架构的情况下,以零样本或少样本的方式执行各种 NLP 任务。随着这一全新的“预训练-提示-预测”(pre-train, prompt, and predict)范式的提出,最近涌现了多种提示设计方法。其中一种方法聚焦于提示工程,通过挖掘或生成适当的离散提示
【Jiang et al., 2020; Shin et al., 2020; Gao et al., 2021c】。
相比之下,连续提示(continuous prompts)
绕过了预训练语言模型的限制,并被应用于 NLP 任务【Li and Liang, 2021; Liu et al., 2021b; Lester et al., 2021; Gu et al., 2021】。受 GPT-3 的启发,CLIP 在 4 亿对图像-文本配对数据上训练了一个大规模的对比学习模型,并展现了基于提示的零样本视觉分类的潜力。在以 CLIP 作为骨干网络的基础上,CoOp【Zhou et al., 2021】和 CPT【Yao et al., 2021】进一步表明,优化连续提示在视觉任务中的表现可以远远优于手动设计的离散提示。
本文展示,提示调优并非实现更优视觉-语言模型的唯一路径。通过微调少量参数,同样可以以更简单的设计实现与提示调优相当甚至更好的视觉任务性能。
- 离散提示(Discrete Prompts)
- 定义:离散提示是一种在自然语言处理(NLP)等任务中使用的提示方式,它是由离散的、明>确的符号(如单词、短语等)组成的提示。这些提示通常是通过挖掘或者人工生成的。
- 举例:在文本分类任务中,如果要判断一段文本是关于体育还是科技,离散提示可能是像“体育相关词汇”(如“比赛”“运动员”)和“科技相关词汇”(如“芯片”“软件”)这样的单词或短语集合。研究人员通过挖掘大量文本找到这些与不同类别相关的词汇,作为提示来引导模型进行分类。就像是给模型一个明确的清单,让它去文本中寻找这些清单上的内容来做出判断。
- 应用场景和限制:离散提示在一些任务中很有效,特别是当我们能够明确地找到与任务相关的特定词汇或短语时。然而,它的局限性在于受到预训练语言模型词汇表和语言结构的限制。例如,模型可能只能处理它预训练时见过的词汇作为提示,而且很难灵活地组合这些离散提示来适应复杂多变的任务场景。
- 连续提示(Continuous Prompts)
- 定义:连续提示是一种相对更灵活的提示方式,它不是由离散的符号组成,而是通过一些连续的向量表示来绕过预训练语言模型的限制。可以将其看作是在一个连续的向量空间中进行操作的提示。
- 举例:假设我们把语言模型的输入空间看作是一个多维的向量空间,连续提示就是这个空间中的一些向量。这些向量可以通过一定的数学运算(如线性组合等)来动态地调整和生成适合不同任务的提示。例如,在情感分析任务中,连续提示可能是一个经过调整的向量,这个向量能够引导模型对文本中的情感倾向进行判断,而且这个向量可以根据不同的文本风格、主题等因素进行动态变化。
- 应用场景和优势:连续提示的优势在于它能够更灵活地适应各种任务。因为它是在连续的空间中操作,所以可以通过学习和调整来生成更适合特定任务的提示,而不像离散提示那样受到词汇和固定结构的限制。它能够更好地利用模型的参数和表示能力,从而在一些视觉任务(如以CLIP为骨干网络的视觉分类任务)等中表现出优于离散提示的性能。
2.3 视觉-语言模型
探索视觉和语言之间的交互是人工智能的核心研究课题之一。过去,基于注意力的方法主导了视觉-语言任务,例如自下而上的和自上而下的注意力【Anderson et al., 2018】、BAN【Kim et al., 2018】、Intra-Inter【Gao et al., 2019】以及 MCAN【Yu et al., 2019】。受 BERT【Kenton and Toutanova, 2019】成功的启发,ViLBERT【Lu et al., 2019】、LXMERT【Tan and Bansal, 2019】、UNITER【Chen et al., 2020】和 Oscar【Li et al., 2020】进一步推动了多模态推理的研究。
最近,CLIP【Radford et al., 2021】和 ALIGN【Jia et al., 2021】展现了视觉-语言对比表征学习的强大能力。它们无需微调便在一系列视觉任务中取得了惊人的结果。为进一步缩小 CLIP 和监督训练之间的差距,CoOp 提出了连续提示优化方法,用以改善视觉分类任务的性能。
与 CoOp 从提示设计角度改进视觉-语言模型不同,本文提出的 CLIP-Adapter 通过轻量化特征适配器的简单微调方法探索了另一种改进途径。
3 我们的方法
本节中,我们介绍所提出的 CLIP-Adapter。在 3.1 节,我们从分类器权重生成的角度回顾了 CLIP 和 CoOp。在 3.2 节,我们详细阐述了 CLIP-Adapter 的设计。在 3.3 节,我们提供了 CLIP-Adapter 的几种变体。
3.1 少样本学习的分类器权重生成
首先回顾深度神经网络用于图像分类的基本框架:给定一张图像 I ∈ R H × W × 3 I \in \mathbb{R}^{H \times W \times 3} I∈RH×W×3,其中 H H H 和 W W W 分别表示图像的高度和宽度,一个由基本组件(例如 CNN、Transformer[Vaswani et al., 2017]或两者的混合)级联组成的神经网络主干模型会将 I I I 转换为一个特征表示 f ∈ R D f \in \mathbb{R}^D f∈RD,其中 D D D 是特征的维度。为了执行分类,图像特征向量 f f f 与分类器权重矩阵 W ∈ R D × K W \in \mathbb{R}^{D \times K} W∈RD×K 相乘,其中 K K K 表示类别的数量。矩阵乘法后,可以得到一个 K K K-维的 logit(未归一化概率)。Softmax 函数将 logit 转换为 K K K 个类别上的概率向量 p ∈ R K p \in \mathbb{R}^K p∈RK。整个过程可表示为以下公式:
f = Backbone ( I ) , p i = exp ( W i T f ) / τ ∑ j = 1 K exp ( W j T f ) / τ ( 1 ) f = \text{Backbone}(I), \quad p_i = \frac{\exp(W_i^T f)/\tau}{\sum_{j=1}^{K} \exp(W_j^T f)/\tau}(1) f=Backbone(I),pi=∑j=1Kexp(WjTf)/τexp(WiTf)/τ(1)
其中, τ \tau τ 表示 Softmax 的温度超参数, W i W_i Wi 表示类别 i i i 的原型权重向量, p i p_i pi 表示类别 i i i 的概率。
与监督训练不同,本文关注的是在少样本场景下的图像分类。通过少量样本从头训练主干网络和分类器容易导致特定数据集的过拟合,并可能在测试集上表现大幅下降。通常,少样本学习的典型范式是先在大规模数据集上预训练主干网络,然后通过以下方式将学习到的知识迁移到下游任务中:直接进行零样本预测或进一步在少样本样本上进行微调。
CLIP 遵循零样本迁移风格:它首先通过在大规模的噪声图文对数据上进行对比学习来预训练视觉主干和文本编码器,随后直接进行图像分类,而无需任何微调。对于一个包含 K K K 个类别及其自然语言名称 { C 1 , C 2 , … , C K } \{C_1, C_2, \dots, C_K\} {C1,C2,…,CK} 的下游图像分类数据集,CLIP 将每个类别名称 C i C_i Ci 放入预定义的硬提示模板 H H H 中。然后,语言特征提取器将生成的提示编码为分类器权重 W i W_i Wi。我们将分类器权重生成过程表示为:
W i = BERT ( Tokenizer ( [ H ; C i ] ) ) ( 2 ) W_i = \text{BERT}(\text{Tokenizer}([H; C_i])) (2) Wi=BERT(Tokenizer([H;Ci]))(2)
另一方面,CoOp 创建了一组随机初始化的可学习软标记 S ∈ R L × D S \in \mathbb{R}^{L \times D} S∈RL×D,其中 L L L 是软标记序列的长度。软标记序列 S S S 与每个类别名称 C i C_i Ci 拼接,从而形成提示。整个过程表示为:
W i = BERT ( [ S ; Tokenizer ( C i ) ] ) ( 3 ) W_i = \text{BERT}([S; \text{Tokenizer}(C_i)]) (3) Wi=BERT([S;Tokenizer(Ci)])(3)
对于 CLIP 和 CoOp,生成的分类器权重 W i ( i = 1 , … , K ) W_i \ (i = 1, \dots, K) Wi (i=1,…,K) 可以通过前述公式(公式 1)计算类别 i i i 的预测概率 p i p_i pi。
3.2 CLIP-Adapter
与 CoOp 的提示调优不同,本文提出了一种替代框架,通过微调额外的特征适配器实现更优的视觉-语言模型少样本图像分类性能。我们认为,传统广泛采用的“预训练-微调”范式在少样本环境下难以成功微调整个 CLIP 主干网络,原因是其参数量庞大且缺乏足够的训练样本。因此,我们提出了 CLIP-Adapter,它仅在 CLIP 的语言和图像分支中添加少量可学习的瓶颈线性层,同时在少样本微调中保持原始 CLIP 主干网络冻结。
然而,仅通过额外的层进行简单的微调可能仍然会导致对少样本数据的过拟合。为了解决过拟合问题并提高 CLIP-Adapter 的鲁棒性,我们进一步采用残差连接,将微调得到的知识与原始 CLIP 主干中的知识动态融合。
具体来说,给定输入图像 I I I 和类别的自然语言名称集合 { C i } i = 1 K \{C_i\}_{i=1}^K {Ci}i=1K,通过公式 (1) 和 (2) 可从原始 CLIP 主干网络中计算得到图像特征 f f f 和分类器权重 W W W。随后,引入两个可学习的特征适配器 A v ( ⋅ ) A_v(\cdot) Av(⋅) 和 A t ( ⋅ ) A_t(\cdot) At(⋅),分别包含两层线性变换,用于转换 f f f 和 W W W。为了避免遗忘预训练 CLIP 中编码的原始知识,特征适配器采用了残差连接。我们引入两个常数 α \alpha α 和 β \beta β 作为“残差比率”,用于调整保留原始知识的程度以优化性能。特征适配器的公式如下:
A v ( f ) = ReLU ( f T W 1 v ) W 2 v ( 4 ) A_v(f) = \text{ReLU}(f^T W_1^v) W_2^v (4) Av(f)=ReLU(fTW1v)W2v(4)
A t ( W ) = ReLU ( W T W 1 t ) W 2 t ( 5 ) A_t(W) = \text{ReLU}(W^T W_1^t) W_2^t (5) At(W)=ReLU(WTW1t)W2t(5)
通过残差连接将微调捕获的新知识与原始特征相加:
f ∗ = α A v ( f ) T + ( 1 − α ) f ( 6 ) f^* = \alpha A_v(f)^T + (1 - \alpha) f (6) f∗=αAv(f)T+(1−α)f(6)
W ∗ = β A t ( W ) T + ( 1 − β ) W ( 7 ) W^* = \beta A_t(W)^T + (1 - \beta) W (7) W∗=βAt(W)T+(1−β)W(7)
在获得新的图像特征 f ∗ f^* f∗ 和分类器权重 W ∗ W^* W∗ 后,我们仍通过公式 (1) 计算类别概率向量 P = { p i } i = 1 K P = \{p_i\}_{i=1}^K P={pi}i=1K,并预测图像类别为概率最高的类 i ∗ = arg max i p i i^* = \arg\max_i p_i i∗=argmaxipi。
在少样本训练中,特征适配器 A v ( ⋅ ) A_v(\cdot) Av(⋅) 和 A t ( ⋅ ) A_t(\cdot) At(⋅) 的权重通过交叉熵损失进行优化:
L = − ∑ i = 1 K y i log ( y ^ i ) L = -\sum_{i=1}^{K} y_i \log(\hat{y}_i) L=−i=1∑Kyilog(y^i)
其中, N N N 为训练样本总数;当类别 i i i 等于真实类别标签 i ∗ i^* i∗ 时, y i = 1 y_i = 1 yi=1,否则 y i = 0 y_i = 0 yi=0; y ^ i = p i \hat{y}_i = p_i y^i=pi 是类别 i i i 的预测概率; θ = { W 1 v , W 2 v , W 1 t , W 2 t } \theta = \{W_1^v, W_2^v, W_1^t, W_2^t\} θ={W1v,W2v,W1t,W2t} 表示所有可学习的参数。
3.3 CLIP-Adapter 的变体
CLIP-Adapter 有三种结构变体:
- 仅微调图像分支的特征适配器,而保持文本分支冻结;
- 仅微调文本分支的特征适配器,而保持图像分支冻结;
- 同时微调 CLIP 主干的图像和文本分支。
对于超参数 α \alpha α 和 β \beta β,我们观察到不同的数据集具有不同的最优取值。手动选择这些超参数既耗时又繁琐。因此,我们还探索了以可微分方式学习 α \alpha α 和 β \beta β,即将它们设置为可学习的参数。通过这种方式, α \alpha α 和 β \beta β 可以通过超网络 Q Q Q 动态地从视觉特征 f f f 或分类器权重 W W W 中预测:
α , β = Q ( f , W ) \alpha, \beta = Q(f, W) α,β=Q(f,W)
4 实验
4.1 少样本学习
4.1.1 训练设置
根据 CLIP【Radford et al., 2021】和 CoOp【Zhou et al., 2021】的实验设置,我们选择了 11 个图像分类数据集来验证 CLIP-Adapter 的有效性:
- ImageNet【Deng et al., 2009】
- StanfordCars【Krause et al., 2013】
- UCF101【Soomro et al., 2012】
- Caltech101【Fei-Fei et al., 2004】
- Flowers102【Nilsback and Zisserman, 2008】
- SUN397【Xiao et al., 2010】
- DTD【Cimpoi et al., 2014】
- EuroSAT【Helber et al., 2019】
- FGVCAircraft【Maji et al., 2013】
- OxfordPets【Parkhi et al., 2012】
- Food101【Bossard et al., 2014】
具体而言,我们在少样本场景下(1、2、4、8 和 16 个样本)训练 CLIP-Adapter,并在完整的测试集上测试微调后的模型性能。所有实验均在一台 Nvidia A100 GPU 上完成。
如果未作特别说明,我们默认采用 CLIP-Adapter 的第一种变体,即仅微调图像特征而冻结分类器权重。换句话说,CLIP-Adapter 仅在视觉适配器上实现。激活文本适配器的其他变体的结果在 4.1.5 节 中呈现。
我们与 CoOp 使用相同的训练超参数,包括每批 32 个样本的批大小以及 1×10⁻⁵ 的学习率,但对残差比率 α \alpha α 进行了超参数搜索,并在每个数据集上报告搜索空间内的最佳性能。视觉主干网络(视觉编码器)采用 ResNet-50【He et al., 2016】,分类器权重生成器(文本编码器)采用 BERT【Kenton and Toutanova, 2019】。视觉和文本瓶颈层的隐藏嵌入维度均设置为 256,为原始嵌入维度的四分之一。
与 CoOp 中可学习的连续提示不同,CLIP-Adapter 使用简单的手工设计硬提示作为文本输入,与 CLIP 相同。对于通用类别的图像数据集(例如 ImageNet),我们采用硬提示模板 “a photo of a {CLASS}”;对于细粒度分类数据集,我们为模板指定相应的领域关键词以获得更好的性能,例如 EuroSAT 的模板为 “a centered satellite photo of {CLASS}”,其他细粒度数据集的模板以此类推。
4.1.2 基线模型
我们将 CLIP-Adapter 与以下三个基线模型进行比较:
- Zero-shot CLIP【Radford et al., 2021】
- Linear probe CLIP【Radford et al., 2021】
- CoOp【Zhou et al., 2021】
在实现中,CLIP-Adapter 与 Zero-shot CLIP 共享相同的手工硬提示以保证公平比较。CoOp 使用可学习的连续向量替代离散标记,因此可以在提示模板的多个位置放置类别标记(例如前、中、后)。我们选择 CoOp 的最佳性能变体,即将类别标记放在 16 标记软提示的末尾,并在不同类别之间共享上下文。
Linear probe CLIP 在其视觉编码器上训练了一个额外的线性分类器,并以少样本训练方式运行。与 CLIP-Adapter 的瓶颈适配器不同,后者以动态和残差方式微调图像特征和分类器权重。
4.1.3 性能比较与分析
主要结果如图 2 所示。从左上角显示的 11 个数据集的平均准确率来看,CLIP-Adapter 在所有不同的少样本训练设置下都明显优于其他三个基线模型,证明了其卓越的少样本学习能力。特别是在 1-shot 或 2-shot 等极端条件下,CLIP-Adapter 相较于基线模型实现了更大的性能提升,表明其在数据匮乏的训练场景中具有更好的泛化能力。
与 Zero-shot CLIP【Radford et al., 2021】相比,CLIP-Adapter 在所有 11 个数据集上都取得了显著的性能提升。在 16-shot 训练设置下,各数据集的绝对性能提升如图 3 所示。对于前五个细粒度数据集(从 EuroSAT 到 FGVCAircraft),CLIP-Adapter 的性能提升范围为 20% 到 50%。在更具挑战性和通用性的 Caltech101 和 ImageNet 等数据集上,性能提升相对较小。而对于 OxfordPets 和 Food101,CLIP-Adapter 的提升有限,因为 Zero-shot CLIP 的原始结果已经非常优秀。
与 Linear probe CLIP【Radford et al., 2021】相比,CLIP-Adapter 展示了全面的性能优势。在 1-shot 和 2-shot 训练设置下,Linear probe CLIP 的性能几乎达不到 Zero-shot CLIP 的水平,但 CLIP-Adapter 总是能够超越 Zero-shot CLIP 并大幅超过 Linear probe CLIP。例如,在 OxfordPets 数据集上,1-shot 和 2-shot 的绝对性能提升分别为 53.6% 和 42.16%;在 ImageNet 数据集上,分别为 37.17% 和 27.58%。
与 CoOp【Zhou et al., 2021】相比,尽管 CoOp 已经相较于 Zero-shot CLIP 实现了显著提升,CLIP-Adapter 在所有数据集和不同的少样本设置中仍表现优越。值得注意的是,CLIP-Adapter 从完全不同的角度(即微调)处理少样本学习,而非 CoOp 的提示调优。这表明,使用带有残差连接的轻量化适配器微调预训练的视觉-语言模型,可以实现比提示工程【Liu et al., 2021a】更好的性能。
4.1.4 对最优残差比率的观察
有趣的是,我们发现最佳残差比率 α \alpha α 在某种程度上反映了“预训练-微调”范式下不同数据集的特性。预训练数据集与微调数据集之间的语义差距越大,CLIP-Adapter 就需要从新适配的特征中学习更多的知识,而不是依赖于原始 CLIP 的输出,从而导致更大的最佳残差比率;反之亦然。
对于专用领域的细粒度数据集(例如 EuroSAT 的卫星图像和 DTD 的纹理图像),最佳残差比率通常在 0.6 到 0.8 的范围内。而对于综合性和通用性的图像数据集(例如 Caltech-101 和 ImageNet),最佳值通常约为 0.2。
4.1.5 含文本适配器的变体
在这里,我们研究了 3.3 节 中提到的 CLIP-Adapter 的另外两种变体:
- 微调文本适配器,同时冻结视觉适配器;
- 同时微调文本和视觉适配器。
与其为每个数据集手动选择残差比率,我们利用可学习参数 α \alpha α 和 β \beta β,因为这种方法更高效,并且可以获得令人满意的性能。我们在四个数据集上对比了它们的性能,这些数据集分为两类:细粒度数据集(EuroSAT 和 DTD)以及通用数据集(Caltech101 和 ImageNet)。如图 4 所示,文本适配器和视觉适配器都能显著提升分类准确率,相较于 Zero-shot CLIP 表现出色。
此外,仅采用视觉适配器优于仅采用文本适配器。这表明,对于少样本图像分类,调整图像特征比调整文本特征更重要,因为预训练数据集与微调数据集之间的视觉特征语义差距通常大于文本特征的语义差距。令人意外的是,同时使用两个适配器的性能并未超过仅使用视觉适配器的性能。这表明,文本适配器和视觉适配器可能会捕获冗余信息,甚至彼此冲突。
4.2 特征流形的可视化
我们使用 t-SNE【Van der Maaten and Hinton, 2008】对以下模型在 EuroSAT 数据集上训练后的特征流形进行了可视化:CLIP、CoOp、不带残差连接的 CLIP-Adapter,以及带残差连接的 CLIP-Adapter。t-SNE 的可视化结果如图 5 所示,其中数字 0 到 9 分别表示以下类别:
- AnnualCrop(年作物)
- Forest(森林)
- Herbaceous Vegetation Land(草本植被地)
- Highway or Road(公路或道路)
- Industrial Buildings(工业建筑)
- Pasture Land(牧场)
- Permanent Crop Land(多年作物地)
- Residential Buildings(住宅建筑)
- River(河流)
- Sea or Lake(海洋或湖泊)
在高维分类空间中,子图 (d) 中带残差连接的 CLIP-Adapter 展现了更为明显的类别特征分离效果。对于一些容易混淆的类别,例如公路或道路(红色点)、多年作物地(粉色点)和牧场(棕色点),与其他方法相比,CLIP-Adapter 在检测同类图像流形的相似性方面表现更为出色。
总之,实验结果证明,在少样本训练场景下,CLIP-Adapter 在学习更优特征流形方面具有良好的效果。
4.3 消融研究
在本节中,我们对 CLIP-Adapter 进行了一系列消融研究。我们选择性能最优的变体(仅激活视觉适配器),并选取两个数据集 —— DTD 和 ImageNet —— 作为细粒度和通用数据集的代表来进行实验。
4.3.1 瓶颈层维度
我们首先通过改变瓶颈层的隐藏维度进行消融实验。结果如表 1 所示,其中 (D) 表示原始图像特征的维度。当将隐藏维度从 (D) 减少到 (D/32) 时,我们观察到过小或过大的中间维度都会显著降低模型性能。最佳瓶颈维度为 (D/4),它能够在保留足够语义信息的同时避免冗余。
4.3.2 残差比率
此外,我们对残差比率 α \alpha α 进行了消融研究。从表 2 可以看出,细粒度数据集 DTD 的最佳残差比率为 0.6,而通用数据集 ImageNet 的最佳残差比率为 0.2。这验证了我们在 4.1.4 节 中的观察,即适配细粒度数据集需要从新知识中学习更多内容,而通用数据集则相反,更依赖于原始知识。
需要注意的是,当 α = 0 \alpha = 0 α=0 时,相当于 Zero-shot CLIP,因为没有学习任何新知识。当 α = 1.0 \alpha = 1.0 α=1.0 时,分类完全依赖于适配特征(CLIP-Adapter w/o Res)。然而,这并不是最佳选择,因为 CLIP-Adapter 在这种情况下容易出现过拟合。
结合表 2 和图 5,我们可以得出残差连接在 CLIP-Adapter 中的优势:
- 避免少样本训练中的过拟合,并通过利用零样本知识提高 CLIP-Adapter 的泛化能力;
- 在少样本微调中保留学习更优图像特征或分类器权重的自由度。
5 结论与未来工作
我们提出了 CLIP-Adapter 作为一种少样本图像分类中提示调优方法的替代方案。CLIP-Adapter 通过仅微调少量额外的瓶颈层,重新激活了“预训练-微调”范式。为了进一步提升泛化能力,我们引入了以残差比率为参数的残差连接,动态融合了零样本知识与新适配特征。
根据实验结果,CLIP-Adapter 在不同的少样本设置下,在 11 个图像分类数据集上均优于竞争性基线模型。广泛的消融研究验证了我们方法的设计,并证明了 CLIP-Adapter 在学习更优特征流形方面的能力。
未来,我们计划将 CLIP-Adapter 扩展到更多的视觉-语言应用中。此外,我们还将尝试将 CLIP-Adapter 与软提示(soft prompts)结合,以进一步释放 CLIP 主干网络的潜力。
相关文章:
CLIP-Adapter: Better Vision-Language Models with Feature Adapters 论文解读
abstract 大规模对比视觉-语言预训练在视觉表示学习方面取得了显著进展。与传统的通过固定一组离散标签训练的视觉系统不同,(Radford et al., 2021) 引入了一种新范式,该范式在开放词汇环境中直接学习将图像与原始文本对齐。在下游任务中,通…...
D74【 python 接口自动化学习】- python 基础之HTTP
day74 http基础定义 学习日期:20241120 学习目标:http定义及实战 -- http基础介绍 学习笔记: HTTP定义 HTTP 是一个协议(服务器传输超文本到浏览器的传送协议),是基于 TCP/IP 通信协议来传递数据&…...
维护表空间和数据文件(一)
学习目标 定义表空间和数据文件的用途创建表空间管理表空间使用Oracle管理文件(OMF)创建和管理表空间获取表空间信息 表空间和数据文件 Oracle逻辑上将数据存储在表空间中,物理上将数据存储在数据文件中。 Tablespaces: 一次只…...
H.265流媒体播放器EasyPlayer.js H5流媒体播放器关于如何查看手机端的日志信息并保存下来
现今流媒体播放器的发展趋势将更加多元化和个性化。人工智能的应用将深入内容创作、用户体验优化等多个方面,带来前所未有的个性化体验。 EasyPlayer.js H.265流媒体播放器属于一款高效、精炼、稳定且免费的流媒体播放器,可支持多种流媒体协议播放&#…...
Apple Vision Pro开发003-PolySpatial2.0新建项目
unity6.0下载链接:Unity 实时开发平台 | 3D、2D、VR 和 AR 引擎 一、新建项目 二、导入开发包 com.unity.polyspatial.visionos 输入版本号 2.0.4 com.unity.polyspatial(单独导入),或者直接安装 三、对应设置 其他的操作与之前的版本相同…...
解决 npm xxx was blocked, reason: xx bad guy, steal env and delete files
问题复现 今天一位朋友说,vue2的老项目安装不老依赖,报错内容如下: npm install 451 Unavailable For Legal Reasons - GET https://registry.npmmirror.com/vab-count - [UNAVAILABLE_FOR_LEGAL_REASONS] vab-count was blocked, reas…...
leetcode 面试150之 156.LUR 缓存
请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类: LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -…...
Vue 动态给 data 添加新属性深度解析:问题、原理与解决方案
在 Vue 中,动态地向 data 中添加新的属性是一个常见的需求,但它也可能引发一些问题,尤其是关于 响应式更新 和 数据绑定 的问题。Vue 的响应式系统通过 getter 和 setter 来追踪和更新数据,但 动态添加新属性 时,Vue 并不会自动为这些新属性创建响应式链接。 1. 直接向 V…...
Unity类银河战士恶魔城学习总结(P141 Finalising ToolTip优化UI显示)
【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili 教程源地址:https://www.udemy.com/course/2d-rpg-alexdev/ UI部分暂时完结!!! 本章节优化了UI中物品描述的显示效果,技能描述的显示效果 并且可以批…...
面试:请阐述MySQL配置文件my.cnf中参数log-bin和binlog-do-db的作用
大家好,我是袁庭新。星球里的小伙伴去面试,面试官问:MySQL配置文件my.cnf中参数log-bin和binlog-do-db的作用?一脸懵逼~不知道该如何回答。 在MySQL的配置文件my.cnf中,log-bin和binlog-do-db是与二进制日志…...
监控报警系统的指标、规则与执行闭环
随笔 从千万粉丝“何同学”抄袭开源项目说起,为何纯技术死路一条? 数据源的统一与拆分 监控报警系统的指标、规则与执行闭环 java 老矣,尚能饭否? 一骑红尘妃子笑,无人知是荔枝来! 有所依 我们如何知道系统交易…...
玩转数字与运算:用C语言实现24点游戏的扑克牌魅力
✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏…...
动态反馈控制器(DFC)和 服务率控制器(SRC);服务率和到达率简单理解
目录 服务率和到达率简单理解 服务率 到达率 排队论中的应用 论文解析:队列等待成本动态感知控制模型 动态反馈和队列等待成本意识: 服务速率调整算法: 动态反馈控制器(DFC)和 服务率控制器(SRC) SRC公式4的原理 算力资源分配系统中的调整消耗 举例说明 服务…...
Flutter-Web首次加载时添加动画
前言 现在web上线后首次加载会很慢,要5秒以上,并且在加载的过程中界面是白屏。因此想在白屏的时候放一个加载动画 实现步骤 1.找到web/index.html文件 2.添加以下<style>标签内容到<head>标签中 <style>.loading {display: flex;…...
stl 实现非容器类型元素和容器元素比较
在 C 标准模板库(STL)中,有许多算法可以接受自定义的比较函数(Compare)。这些算法通常涉及排序、查找、合并、集合操作等场景,允许用户通过 Compare 函数指定如何比较两个元素。 自定义compare的算法 排序…...
ChatGPT 桌面版发布了,如何安装?
本章教程教大家如何进行安装。 一、下载安装包 官网地址地址:https://openai.com/chatgpt/desktop/ 支持Windows和MacOS操作系统 二、安装步骤 Windows用户下载之后,会有一个exe安装包,点击运行安装即可。 注意事项,如果Windows操…...
【动手学电机驱动】STM32-FOC(8)MCSDK Profiler 电机参数辨识
STM32-FOC(1)STM32 电机控制的软件开发环境 STM32-FOC(2)STM32 导入和创建项目 STM32-FOC(3)STM32 三路互补 PWM 输出 STM32-FOC(4)IHM03 电机控制套件介绍 STM32-FOC(5&…...
JavaWeb后端开发知识储备2
目录 1.HttpClient 2.微信小程序开发 3.Spring Cache 4.Spring Task 4.1cron表达式 4.2入门案例 1.HttpClient 简单来说,HttpClient可以通过编码的方式在Java中发送Http请求 2.微信小程序开发 微信小程序的开发本质上是前端开发,对于后端程序员来…...
Java Stream API - 高效数据处理的核心工具_01
文章目录 概述:高效数据处理的核心工具1. 流的创建1.1 从集合创建流1.2 从数组创建流1.3 直接创建流 2. 中间操作:流的转换和处理2.1 map():映射操作2.2 filter():过滤操作2.3 flatMap():扁平化映射操作2.4 sorted()&a…...
【计算机网络】网段划分
一、为什么有网段划分 IP地址 网络号(目标网络) 主机号(目标主机) 网络号: 保证相互连接的两个网段具有不同的标识 主机号: 同一网段内,主机之间具有相同的网络号,但是必须有不同的主机号 互联网中的每一台主机,都要隶属于某一个子网 -&…...
HTML和CSS 表单、表格练习
HTML和CSS 表格练习 <!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>HTML表格练习</title>…...
ByteBuffer模拟拆包输出消息字符串
以下代码模拟网络编程中的粘包现象,用\n进行分割消息块 源码 public static void main(String[] args) {ByteBuffer byteBuffer1 ByteBuffer.allocate(60) ;byteBuffer1.put("Hello World\nWhat is you name?\nI am Licky!\nHo".getBytes());splice(byt…...
Java FastJson 踩坑记录
newtonsoft.json 第一次用。java 转的json给newtonsoft.json解析,一直解析不出来。 直到写这个文章的时候,我都还觉得是newtonsoft.json和fastjson都有问题。 先看java JSONField(name"RankValue") public long Rank11000; JSONField(na…...
深入理解 Java 阻塞队列:使用场景、原理与性能优化
在并发编程中,线程安全的队列是解决线程间任务传递和调度的关键工具之一。阻塞队列(BlockingQueue)作为一种线程安全的队列,实现了在并发环境下对共享数据的安全访问,广泛应用于生产者-消费者模型、任务调度和多线程计…...
Python常用高阶函数:map()、filter()、reduce()
Python常用高阶函数:map()、filter()、reduce() 高阶函数是一类以函数作为参数或者返回值的函数,能够显著提高代码的简洁性和灵活性。在Python中,map()、filter()和reduce()是三种非常常用的高阶函数,它们常被用来对列表或其他可…...
多目标优化算法:多目标极光优化算法(MOPLO)求解ZDT1、ZDT2、ZDT3、ZDT4、ZDT6,提供完整MATLAB代码
一、极光优化算法 极光优化算法(Polar Lights Optimization, PLO)是2024年提出的一种新型的元启发式优化算法,它从极光这一自然现象中汲取灵感。极光是由太阳风中的带电粒子在地球磁场的作用下,与地球大气层中的气体分子碰撞而产…...
【大数据学习 | Spark-Core】关于distinct算子
只有shuffle类的算子能够修改分区数量,这些算子不仅仅存在自己的功能,比如分组算子groupBy,它的功能是分组但是却可以修改分区。 而这里我们要讲的distinct算子也是一个shuffle类的算子。即可以修改分区。 scala> val arr Array(1,1,2,…...
ShuffleNet:一种为移动设备设计的极致高效的卷积神经网络
摘要 https://arxiv.org/pdf/1707.01083 我们介绍了一种名为ShuffleNet的计算效率极高的卷积神经网络(CNN)架构,该架构专为计算能力非常有限的移动设备(例如10-150 MFLOPs)而设计。新架构利用两种新操作:逐…...
AIGC-------AIGC在社交媒体内容生成中的应用
AIGC在社交媒体内容生成中的应用 引言 随着人工智能生成内容(AIGC)的快速发展,社交媒体平台上的内容创作方式发生了巨大变化。AIGC使得内容创作的门槛大大降低,从而让更多的人能够参与到社交媒体内容的创作中,同时也使…...
提取图像中的高频信息
三种方法 1. 傅里叶变换提取高频和低频【有损】2. 傅里叶变换提取振幅和相位【无损】3. 小波变换【不涉及恢复代码】代码1.代码2代码3 1. 傅里叶变换提取高频和低频【有损】 环境:集群210.30.98.11效果: 2. 傅里叶变换提取振幅和相位【无损】 环境:集…...
js函数声明
在 JavaScript 中,函数是一等公民(first-class citizen),这意味着函数可以作为变量、参数和返回值使用。JavaScript 提供了多种定义函数的方式,以下是几种常见的方法: 1. 函数声明(Function De…...
语言模型中的多模态链式推理
神经网络的公式推导 简介摘要引言多模态思维链推理的挑战多模态CoT框架多模态CoT模型架构细节编码模块融合模块解码模块 实验结果运行代码补充细节安装包下载Flan-T5数据集准备rougenltkall-MiniLM-L6-v2运行 简介 本文主要对2023一篇论文《Multimodal Chain-of-Thought Reason…...
【Java 解释器模式】实现高扩展性的医学专家诊断规则引擎
🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/literature?__c1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,…...
CTF之密码学(Polybius密码)
棋盘密码,也称为Polybius密码或方格密码,是一种基于替换的加密方法。以下是对棋盘密码的详细解析: 一、加密原理 棋盘密码使用一个5x5的方格棋盘,其中填充了26个英文字母(通常i和j被视为同一个字母并放在同一个格子中…...
java excel 导入各种踩坑
在 Java 中处理 Excel 导入时,常见的问题(即“踩坑”)很多,下面列举了处理 Excel 导入时可能遇到的一些问题,并给出了解决方案和优化技巧。 1. POI 库与版本问题 Apache POI 是处理 Excel 的常用库,但是不…...
优化表单交互:在 el-select 组件中嵌入表格显示选项
介绍了一种通过 el-select 插槽实现表格样式数据展示的方案,可更直观地辅助用户选择。支持列配置、行数据绑定及自定义搜索,简洁高效,适用于复杂选择场景。完整代码见GitHub 仓库。 背景 在进行业务开发选择订单时,如果单纯的根…...
js版本之ES5特性简述【String、Function、JSON、其他】(二)
目录 String相关方法 string.charAt() string.charCodeAt() string.concat() string.match() string.search() string.replace() string.split() string.trim() string.slice() string.substr() string.substring() Function相关方法 arguments.length function…...
【redis】哈希类型详解
哈希类型详解 一、哈希类型的介绍二、哈希类型的常用命令2.1 HSET2.2 HGET2.3 HEXISTS2.4 HDEL2.5 HKEYS2.6 HAVLS2.7 HGETALL2.8 HMGET2.9 HLEN2.10 HSETNX2.11 HINCRBY2.12 HINCRBYFLOAT 三、哈希类型命令小结四、哈希类型内部编码五、哈希类型应用场景 一、哈希类型的介绍 …...
每日练题之动态规划(子序列问题讲解 1.最长递增子序列 2.摆动序列)
前言: 需要对「子序列」和「子数组」这两个概念进行区分; 子序列(subsequence):子序列并不要求连续,但是我们调出来的顺序必须和原数组的顺序相同。例如:序列 [4, 6, 5] 是 [1, 2, 4, 3, 7, 6,…...
JSON 性能测试 - WastJson 性能也很快
WAST 是一个高性能 Java 工具集库包,包括 JSON、YAML、CSV、HttpClient、JDBC 和 EL 引擎. WastJson 无论是小中大文本各种数据类型等性能都没有明显的短板,除了推广外可以说是六边形战士,更多测试参考 wast-jmh-test: wast性能测试 (并非所…...
Windows 软件之 FFmpeg
文章目录 前言1 FFmpeg 视频处理1.1 编解码1.2 其它视频编辑命令1.3 视频抽帧 2 FFmpeg 音频处理3 FFmpeg 图片处理3.1 编解码3.2 拼接图片3.3 图片合成视频 附录1:mediainfo.ps1 前言 FFmpeg 是一套可以用来记录、转换数字音频、视频,并能将其转化为流的…...
接口的扩展
1. 接口中新增的方法 JDK7之前接口中只能定义抽象方法。 JDK8的新特性:接口中可以定义有方法体的方法。(默认、静态) JDK9的新特性:接口中可以定义有私有方法体的方法。 有方法体的方法:接口升级时,为了兼容…...
Vue ECharts 基本数据图表绘制详解:让数据飞起来
1. 引言 1.1 什么是数据可视化 大家好,欢迎来到数据可视化的世界!如果你以为数据就是冷冰冰的数字,那你就大错特错了。数据,可是有灵魂的!只要给它一副好看的外衣,比如我们今天要聊的图表,它们…...
目录遍历漏洞-CVE-2021-41773
目录 简介 原理 例子 Apache路径穿越漏洞 环境搭建 漏洞原理 漏洞利用 简介 目录遍历漏洞(也称为路径遍历漏洞)是一种由于Web服务器或Web应用程序对用户输入的文件名称的安全性验证不足而导致的安全漏洞。 原理 目录遍历漏洞允许攻击者在未授权…...
ajax (一)
什么是 AJAX [ˈeɪdʒks] ? 概念:AJAX是浏览器与服务器进行 数据通信 的技术,动态数据交互 怎么用AJAX? 1. 先使用 axios [k‘sio ʊ s] 库, 与服务器进行 数据通信 ⚫ 基于 XMLHttpRequest 封装、代码简单、月下载量在 1…...
cocos creator 3.8 物理碰撞器Collider+刚体RigidBody 8
遇到一个朋友,你来就行的朋友,我过去了,管吃管住,这样的朋友真的很难求。 最近离职了,很难想象,一份策划书一天能给你改n次,一周能郁闷,上一个功能没搞完,让你搞下一个功…...
[Python3学习笔记-基础语法] Python3 基础语法
本篇文章详细介绍Python3的基础语法,主要包括编码、标识符、Python保留字、注释、行缩进、多行语句、Number类型、字符串、空行、print打印等。 这些是Python最基础的东西,掌握好了才能更好的学习后续的内容。 有兴趣共同结伴学习Python的朋友࿰…...
自制游戏:监狱逃亡
第一个游戏,不喜勿喷: #include<bits/stdc.h> #include<windows.h> using namespace std; int xz; int ruond_1(int n){if(xz1){printf("撬开了,但站在你面前的是俄罗斯内务部特种部队的奥摩大帝,你被九把加…...
Linux的开发工具(三)
条件编译 预处理本质:对代码进行裁剪 像网易云音乐有vip和普通用户,可以通过条件编译来,这样只用写一份代码,也只用维护一份代码,是vip就走vip代码,不是就普通用户代码,条件编译来动态裁剪。 …...
飞书会话消息左右排列
飞书会话消息左右排列 1. 飞书登录后,点击头像,弹出菜单有个按钮设置 2. 3....