【深度学习】详解 BEiT

news2024/11/23 15:52:24


目录

摘要 

一、引言

二、方法

2.1 图像表示

2.1.1 图像 patch

2.1.2 视觉 token

2.2 主干网络:图像 Transformer

2.3 预训练 BEiT:掩码图像建模

2.4 从变分自动编码器的角度来看

2.5 预训练设置 

2.6 在下游视觉任务微调 BEiT

三、实验

3.1 图像分类

3.2 语义分割

3.3 消融实验

四、相关工作

五、总结


  • GitHub: unilm/beit at master · microsoft/unilm · GitHub

摘要 

        我们引入了一个自监督视觉表示模型 BEIT,它表示 Bidirectional Encoder representation from Image Transformers。在 NLP 领域开发的BERT 之后,我们提出了一个掩码图像建模 (MIM) 任务来预训练视觉 Transformer。具体来说,在我们的预训练中,每幅图像都有两个视图 (views),即图像 patches (如 16×16 pixels) 和视觉 tokens (即离散 tokens)。我们首先将原始图像 “tokenize” 为视觉 token。然后,随机 mask 一些图像 patches,并将它们输入主干 Transformer。预训练的优化目标 (objective) 是基于损坏的图像 patches 恢复原始的视觉 tokens。在对 BEIT 进行预训练后,我们通过在经预训练的编码器上附加任务层,直接微调下游任务上的模型参数。对图像分类和语义分割的实验结果表明,我们的模型相比以往的预训练方法取得了具有竞争力的结果 (competitive results)。


一、引言

        Transformer 在 CV 领域取得了良好的性能。然而,实证研究表明,视觉 Transformer 比 CNN 需要更多的训练数据。为了解决渴求数据 (data-hungry) 的问题,自监督预训练 是利用大规模图像数据的一个很有前途的解决方案。人们已经为视觉 Transformer 的探索了几种方法,如对比学习 和 自蒸馏

        与此同时,BERT 在 NLP 取得了巨大成功。其 掩码语言建模 (MLM) 任务首先随机 mask 文本中的部分 tokens,再根据已损坏 (corrupted) 文本的 Transformer 编码结果恢复 masked tokens。在 BERT 的激励下,我们转向 auto-encoding 的思想来预训练视觉 Transformer,这尚未被视觉社区很好地研究。对图像数据直接应用 BERT 风格的预训练具有挑战性。首先,没有现存的词表 (vocabulary) 可以用于视觉 Transformer 的输入单元,即图像 patches。因此,不能简单地使用一个 softmax 分类器来预测所有可能的候选 masked patches。相比之下,语言词表 (vocabulary),如 words 和 BPE,都有良好地定义了 (well-defined),缓解了 auto-encoding 预测。一个直接的替代方法是将任务视为一个回归问题,它预测 masked patches 的 raw pixels。然而,这种像素级恢复任务往往会浪费 对预训练的 短距离依赖关系和高频细节的建模能力。我们的目标是克服视觉 Transformer 预训练的上述问题。

图 1:BEiT 预训练概览
在预训练前,通过 autoencoding 风格的重建学习 “图像 tokenizer”,根据已学习的词表 (vocabulary),图像被 tokenized 成离散的视觉 tokens (id)。在预训练时,每幅图像都有两个 views,即图像 patches 和视觉 tokens。我们随机 mask 一定比例的图像 patches (图中灰色 patches),并替换为特殊的 mask 嵌入 [M]。然后这些 patches 被输入到一个主干视觉 Transformer。该预训练任务旨在基于被损坏图像的编码向量来预测原始图像的视觉 tokens。

        在这项工作中,我们引入了一个自监督的视觉表示模型 BEiT,它代表 Bidirectional Encoder representation from Image Transformers (有别于后来同时具有编码器-解码器且 masked tokens 放在解码器的 MAE)。受BERT 的启发,我们提出了一个预训练任务,即 掩码图像建模 (MIM)。如图 1 所示,MIM 对每个图像使用两个视图 (views),即图像 patches 和视觉 tokens。我们将图像分割成一个 patches grid 作为主干 Transformer 的输入表示。此外,我们 将图像 “tokenize” 为离散的视觉 tokens,这获取自离散的 VAE 的潜在代码 (latent codes)。在预训练过程中,我们随机 mask 一定比例的图像 patches,并将已损坏的输入提供给 Transformer。该模型学习恢复原始图像的视觉 tokens,而非 masked patches 的 raw pixels (BEiT 恢复 tokens (图 1 中的 index),MAE 恢复 pixels)。

        我们实施自监督学习,然后微调图像分类和语义分割这两个下游任务。实验结果表明,BEiT 的性能优于 从头开始的训练 以往的强自监督模型。此外,BEiT 是对有监督的预训练的补充。通过 使用 ImageNet 标签的中间 (intermediate) 微调,可以进一步提高 BEiT 的性能。消融研究表明,我们提出的技术对 BERT 式的图像数据预训练的有效性至关重要。除 性能 外,收敛速度 和 微调稳定性 的改善也降低了最终任务的训练成本。此外,我们还证明了 自监督 BEiT 可以通过预训练学习合理的语义区域,释放 (unleashing) 图像中丰富的监督信号

        我们的贡献总结如下:

  • 我们提出了一个掩码图像建模 (MIM) 任务,以自监督的方式预训练视觉 Transformer。我们还从变分自编码器的角度提供了一个理论解释。
  • 我们对 BEiT 预训练,并对下游任务进行广泛的微调实验,如图像分类和语义分割。
  • 我们提出自监督 BEiT 的自注意机制来学习区分语义区域和对象边界 (semantic regions & object boundaries),尽管无需任何人类注释。

二、方法

        给定一个输入图像 x,BEiT 将其编码为 经上下文化 (contextualized) 的向量表示。如图 1 所示,BEiT 通过自监督学习方式的掩码图像建模 (MIM) 任务进行预训练。MIM 旨在恢复基于编码向量的 masked image patches。对于下游任务 (如图像分类和语义分割),我们在经预训练的 BEiT 上添加任务层,并对特定数据集上的参数进行微调。


2.1 图像表示

        在我们的方法中,图像有两个表示的 views,即图像 patch 和视觉 token,二者分别在预训练中作为输入和输出表示


2.1.1 图像 patch

        2D 图像被 splited 为一个序列的 patches,以便于标准 Transformer 能够接受图像数据。形式上 (formally),将图像 x \in \mathbb{R}^{H \times W \times C} reshape 为 N = HW / P^2 个 patches x^p \in \mathbb{R}^{N \times (P^2 C)},其中 C 为通道数,(H, W) 为输入图像分辨率,(P, P) 为每个 patch 的分辨率。图像 patches \{ x_i^p \}^N_{i=1}被 flattened 成向量并被线性投影,类似 BERT 的词嵌入。图像 patches 保留 raw pixels,并在 BEiT 中用作输入特征。

        实验中,每幅 224×224 图像被 splited 成 14×14 的图像 patches grid (N = 14 \times 14),每个 grid 表示的 patch 尺寸为 16×16 (P = 16)。


2.1.2 视觉 token

        类似于自然语言,图像被表示为基于 “image tokenizer” 获取的离散 token 序列,而非 raw pixels。具体来说,图像 x \in \mathbb{R}^{H \times W \times C} 被 tokenized 为 z = [z_1, ... , z_N] \in \nu^{h \times w},其中 词表 (vocabulary) \nu = \{ 1, ..., \left | \nu \right | \} 包含离散的 token indices

        按照 (Zero-shot text-to-image generation),我们使用 通过离散变分自编码器 (dVAE) 学习到的图像 tokenizer。在视觉 token 的学习过程中,有 tokenizer 和 decoder 这两个模块。tokenizer q_{\phi } (z | x) 根据据 视觉代码本 (codebook) / 词表 (vocabulary) 将图像像素 x 映射为离散的 tokens zdecoder p_{\psi } (x | z) 学习基于视觉 token z 重建输入图像 x。重建的优化目标 (objective) 可以写成 \mathbb{E}_{z \sim q_\phi (z | x)} [log p_\psi (x | z)]由于潜在的视觉tokens 是离散的,模型训练是不可微的。因此,Gumbel-softmax 被用于训练模型。此外,在 dVAE 训练过程中,一个 uniform 先验 被加到 q_\phi 上。

        每幅图像被 tokenize 成 14×14 的视觉 tokens grid。注意,一幅图像的视觉 tokens 数和图像 patches 数相同词表 (vocabulary) 大小设置为 |\nu | = 8192。本工作中,直接用 (Zero-shot text-to-image generation) 中的公开可用的图像 tokenizer (https://github.com/openai/DALL-E),还将它与附录 C 中重新实现的 tokenizer 进行了比较。


2.2 主干网络:图像 Transformer

        按照 ViT,我们将标准 Transformer 用作主干网络,以便于结果能够直接和以往工作在网络架构方面进行比较。

        Transformer 的输入是一个图像 patches 序列\{ x_i^p \}^N_{i=1}。然后,patches 经线性投影得到 patch 嵌入Ex_i^p,其中投影矩阵 E \in \mathbb{R} ^ {(P^2 C) \times D}。此外,我们不但预先往输入序列加入 (prepend) 一个 特殊的 token [S],而且加入了 标准的可学习 1D 位置嵌入 E_{pos} \in \mathbb{R}^{N \times D}。从而,输入向量 H_0 = [e_{[s]}, Ex_i^p, ..., Ex_N^p] + E_{pos} 被馈入 Transformer。编码器包含了 L 层 Transformer blocks H^l = Transformer(H^{l-1})l = 1, ... , L。最后一层编码器输出 H^{L} = [h^L_{[s]}, h^L_1, ... , h^L_N] 即为 经编码的图像 patches 表示 (共 N + 1 个向量),其中 h^L_i 是 i 个图像 patch 的向量


2.3 预训练 BEiT:掩码图像建模

        我们提出了一个 掩码图像建模 (MIM) 任务:随机 mask 一定百分比的图像 patches,然后预测与 masked patches 对应的视觉 tokens

图 1:BEiT 预训练概览
在预训练前,通过 autoencoding 风格的重建学习 “图像 tokenizer”,根据已学习的词表 (vocabulary),图像被 tokenized 成离散的视觉 tokens (id)。在预训练时,每幅图像都有两个 views,即图像 patches 和视觉 tokens。我们随机 mask 一定比例的图像 patches (图中灰色 patches),并替换为特殊的 mask 嵌入 [M]。然后这些 patches 被输入到一个主干视觉 Transformer。该预训练任务旨在基于被损坏图像的编码向量来预测原始图像的视觉 tokens。

        图 1 展示了我们的方法的概览。如 2.1 节所示,给定一个输入图像 x,将其 split 为 N 个图像 patches (\{ x_i^p \}^N_{i=1}),并一一 tokenize 为 N 个视觉 tokens (\{ z_i \}^N_{i=1})。然后,随机 mask 约 40% (掩码率为 0.4) 的图像 patches,其中 masked 的位置表示为 M \in \{1, ..., N\}^{0.4N} (如图 1 M \in \{ 2, 3, 6, 7 ,14 \})。接着,用一个可学习的嵌入 e_{[M]} \in \mathbb{R}^{D} 来替换 masked patches (用于训练)。然后如 2.2 节所述,将已损坏 (被 masked) 的图像 patches x^M = \{ x^p_i : i \notin M \}^N_{i=1} \bigcup \{ e_{[M]} : i \in M \}^N_{i=1} 馈入 L 层 Transformer 中,得到的最后隐层向量 \{ h^L_i \}^N_{i=1} 被视为输入 patch 的编码表示 (如图 1 中的 5 个 BEiT Encoder 灰色输出)。对于每个 mask 位置 \{ h^L_i : i \in M \}^N_{i=1},使用 softmax 分类器 (其实是 FC+Softmax 构成的 MIM Head) 来预测相应的视觉 tokens p_{MIM} (z' | x^M) = softmax_{z'} (W_c h_i^L+b_c),其中 x^M 是已损坏 (被 masked) 的图像 patches,W_c \in \mathbb{R}^{\left | \nu \right | \times D} 且 b_c \in \mathbb{R} ^ {\left | \nu \right |}。预训练的 objectives 是最大化 已损坏图像中 正确的视觉 tokens z_i 的对数似然 (log-likelihood)。

        其中,D 为训练语料库 (corpus),M 代表随机 masked 的位置 (如图 1 中的M \in \{ 2, 3, 6, 7 ,14 \}),x^M 为根据M来 masked 的已损坏图像 (如图 1 左下角的图)。

        本工作中 使用 blockwise masking,而非随机为 masked 位置 M 选择 patches。如算法 1 所示,每次都会 mask 一个 block 的图像 patches每个 block 的 patch 数最小设为 16。然后,随机选择 masking block 的高宽比 (aspect ratio)。重复上述 2 个步骤,直到获得足够的 masked patches,即 0.4N (N 为图像 patches 总数,0.4 为掩码率)。

        MIM 主要受到 MLM 的启发,MLM 是 NLP 中最成功的预训练 objective 之一。此外,blockwise (或 n-gram) masking 也被广泛应用于 BERT-like 模型。然而,直接使用像素级 auto-encoding (即恢复 masked patches 的像素) 进行视觉预训练,会 pushes 模型聚焦于短程依赖和高频细节BEiT 通过预测离散视觉 tokens 来克服上述问题,并将细节 summarizes 高级抽象。第 3.3 节的消融研究表明,BEiT 明显优于像素级 auto-encoding


2.4 从变分自动编码器的角度来看

        BEiT 预训练 可视为 变分自动编码器 (variational autoencoder) 训练。设 x为原始图像,\widetilde{x} 为 masked 图像,z 为视觉 tokens。考虑到对数似然 p(x | \widetilde{x}) 的证据下界 (ELBO),即从其损坏的版本中恢复原始图像:

  1. q_{\phi }(z | x) 表示使用图像 tokenizer 基于 输入图像 获取 视觉 tokens
  2. p_{\psi }(x | z) 表示 基于 输入视觉 tokens 解码 原始图像
  3. p_{\theta}(z | \widetilde{x}) 表示 基于 masked 图像 恢复 视觉 tokens,此即 MIM 的预训练任务

        我们遵循二阶段过程来学习模型。在第一阶段,获取图像 tokenizer 作为离散变分自动编码器。特别地,第一阶段使用一个 uniform 先验来最小化 Visual Token Reconstruction 损失,如公式 (2) 所示。在第二阶段,学习先验 p_{\theta},同时保持 q_{\phi } 和 p_{ \psi } 固定。将 q_{\phi }(z | x) 简化为具有最有可能的视觉 token 的单点 (one-point) 分布 \widehat{z_i} = \textrm{argmax}_{z} \; q_{\phi }(z | x),则公式 (2) 可重写为:

        其中,第二项是 BEiT 的预训练 objectives。


2.5 预训练设置 

        BEiT 的架构遵循 ViT-Base,以进行公平比较。我们使用 12 层 Transformer,隐层大小为 768,注意力头数为 12。FFN 的中间尺寸 (intermediate size) 为 3072。默认输入 patch size 为 16×16。直接用已训练好的图像 tokenizer。视觉 token 词表大小 (vocabulary) 为 8192

        我们在 ImageNet-1K 训练集上预训练,IN1K 包含约 120 万张图像。数据增广策略 包括:随机调整尺寸的裁剪、水平翻转、颜色抖动 (color jittering)。注意,我们 并未使用这些标签用于自监督学习。实验中使用了 224×224 的分辨率。因此,输入被 split 成 14×14 个图像 patches,以及相同数量的视觉 tokens。最多随机 mask 75 个 patches (掩码率约 40%,masked patches 数:14×14×0.4 = 78.4 ≈ 75)。

        预训练约 500k steps (即 800 个 epochs),batch size 为 2k。采用 β1 = 0.9, β2 = 0.999 的 Adam 优化。学习率为 1.5e-3,预热 10 个 epochs,使用余弦学习率衰减策略,权重衰减为 0.05。采用 rate = 0.1 的 stochastic depth (Deep networks with stochastic depth:训练时每个 batch 随机 dropout 网络的一些 layers,测试时用完整网络),并禁用 dropout。使用 16 张 Nvidia Telsa V100 32GB GPU,500k steps 的训练约需 5 天。

        我们发现 适当的初始化对于稳定 Transformer 很重要,特别是对于大规模预训练。我们首先在一个小范围内随机初始化所有参数,如[−0.02, 0.02]。然后,对于第 l 层 Transformer,我们用 1 / \sqrt{2l}  rescale 自注意力模块和 FFN 的输出矩阵 (即每个子层内的最后一个线性投影)。


2.6 在下游视觉任务微调 BEiT

        预训练 BEiT 后,我们在 Transformer 末尾追加了一个任务层,并微调下游任务的参数,就像 BERT。以图像分类和语义分割为例。在 BEiT 的其他视觉任务上利用 预训练然后微调 的范式是很简单的。

        图像分类。对于图像分类,直接使用一个简单的线性分类器作为任务层。具体地,使用平均池化来聚合表示,并将全局提供给 softmax 分类器。类别概率计算为 \textrm{softmax} ( \textrm{avg} ( \{ h^L_i \}^N_{i=1} W_c ) ),其中 h_i^L 是第 i 个图像 patch 的最终编码向量,W_c \in \mathbb{R}^{D \times C} 是一个参数矩阵,C 是类别/标签数。通过更新 BEiT 和 softmax 分类器的参数,来最大化有标签 (labeled) 数据的似然 (likehood)。

        语义分割。对于语义分割,遵循 SETRPUP 中使用的任务层。具体地,使用经预训练的 BEiT 作为主干编码器,然后合并几个反卷积层 (deconv) 作为解码器来产生分割。该模型也类似于图像分类被端到端微调。

        中间微调。经过自监督的预训练,我们可以在数据丰富的中间数据集 (即本工作中的 ImageNet-1K) 上进一步训练 BEiT,然后在目标下游任务上微调模型 (可以理解为三阶段:自监督预训练 → 中间数据集微调 → 下游任务微调)。这种中间微调 (intermediate fine-tuning) 是 NLP 中 BERT 微调的常见做法。我们直接遵循 BEIT 的方法。


三、实验

        我们对图像分类和语义分割进行了完全微调实验。此外,我们提出了预训练的各种消融研究,并分析了由 BEiT 学习到的表示。我们还在附录D 中报告了 ImageNet 上的 linear probes。


3.1 图像分类

        图像分类任务将输入图像分为不同的类别。我们在 ILSVRC-2012 ImageNet 数据集上评估 BEiT,使用 1k 个类别和 130 万张图像。在微调实验中,我们直接遵循 DeiT 的大多数超参数来进行公平比较。与从头开始的训练相比,我们 减少了微调 epochs,因为 BEiT 已经被预训练过了。因此,我们使用了一个 较大的学习率与 layer-wise decay。详细的超参数总结在附录 H 中。

        表 1 报告了图像分类的 top-1 准确率。我们将 BEiT 与通过 随机初始化有监督预训练 和以前的 自监督学习 方法训练的视觉 Transformer 进行了比较。除 iGPT 有 1.36B 的参数外,所有的比较模型都是 base-size。预训练在 ImiageNet 上进行,除了 ViT-JFT300M 是在谷歌内部的300M 图像上预训练的。

        与随机初始化训练的模型相比,我们发现预训练 BEiT 显著提高了在两个数据集上的性能。BEiT 提高了在 ImageNet 上的性能,显示了在丰富资源设置下的有效性。

        此外,我们还将 BEiT 与之前用于 Transformer 的 SOTA 自监督方法进行了比较,如 DINO 和 MoCo v3。BEiT 在 ImageNet 微调上优于以前的模型。其中,iGPT-1.36B 使用了更多的参数 (即 1.36B vs 86M),而 ViT-JFT300M 在更大的语料库上预训练 (即 300M vs 1.3M),而 其他模型在 ImageNet-1K 上对 ViT-Base 进行预训练。iGPT-1.36B 和 ViT-JFT300M 是最具可比性 (most comparable) 的方法,它们也遵循了视觉 Transformer 的自动编码预训练。具体来说,iGPT 使用聚类图像 tokens 作为图像 GPT 或图像 BERT 的输入和输出。相比之下,BEiT 使用图像 patches 作为输入来保留原始像素,并使用离散的视觉 tokens 作为预测 bottleneck (中间表示的意思?)ViT-JFT300 预测每个 masked patch 的平均 3-bit 颜色,而不是通过离散的 VAE 学习到的视觉 tokens。我们还以多任务学习的方式对 BEiT 和 DINO 的自监督任务进行了预训练,详见附录 E。

        此外,我们还使用 中间微调 评估了 BEiT。换言之,首先以自监督的方式预训练 BEiT,然后基于 ImageNet 的有标签数据微调预训练模型 (最后有需要再微调下游任务)。结果表明,BEiT 是对有监督预训练的补充,在 ImageNet 上进行中间微调后获得了额外的增益

        微调到 384×384 的分辨率在对 224×224 的分辨率微调后,我们用 384×384 的图像额外微调了 10 个 epochs。我们遵循 DeiT 的标准的高分辨率设置,除了使用更少的 epochs。注意,224×224 和 384×384 图像 保持相同的 patch size。因此,对于更高的分辨率,Transformer 的输入序列长度会更长。表 1 显示,更高的分辨率使 ImageNet 上的 BEiT 结果提高了1+ 个点。更重要的是,在 ImageNet-1K 上进行预训练的BEiT-384 在使用相同的输入分辨率时,甚至优于使用 ImageNet-22K 的有监督预训练 ViT-384。

        可扩展到更大的尺寸。我们进一步将 BEiT 扩展到大尺寸 (与 ViT-L 相同)。如表 1 所示,在从头开始训练时,在 ImageNet 上的 ViT384-L 比 ViT-384 更差。该结果验证了 视觉 Transformer 的 data-hungry 问题。在 ImageNet-22K 上进行有监督的预训练则部分缓解了这个问题,其中 ViT384-L 最终比 ViT-384 高出 1.2。相比之下,BEIT-L 比 BEIT 好 2.0,BEIT384-L 比 BEIT384 好 1.7。换句话说,将 BEiT 从 base 扩展到 large 的收益比使用 ImageNet-22K 进行有监督预训练的收益更大。更重要的是,比较 BEiT-384 和在 ImageNet-22K 上进行有监督预训练的ViT-384,随着从 base (即 0.6) 到 large (即 1.1),BEiT 的改进变得更大。结果表明,对于非常大的模型 (如 1B 或 10B),BEiT 倾向于更有用,特别是当有标签数据不足以对如此大的模型进行有监督预训练时

        收敛曲线。图 2 比较了 从头开始训练 和 预训练然后微调 范式的收敛曲线。我们发现,微调 BEiT 不仅获得 更好的性能,而且比从头训练DeiT 收敛得快得多。此外,微调 BEiT 可以在极少的 epochs 内达到合理的数字。


3.2 语义分割

        略


3.3 消融实验

        我们进行了消融研究来分析 BEiT 中各组件的贡献。通过图像分类 (ImageNet) 和语义分割 (ADE20K) 对这些模型进行了评估。我们将消融研究的默认预训练 steps 设为 300 个 epochs,占之前实验中使用的总 steps 的 37.5%。

        表 4 报告了各种模型变体的结果。 

        首先,通过随机采样 masked 位置来消融 blockwise masking,发现 blockwise masking 对两种任务都是有益的,特别是语义分割

        其次,我们 通过预测 masked patches 的 raw pixels 来减少视觉 tokens 的使用,即,预训练任务成为恢复 masked patches 的像素回归问题。我们提出的 掩码图像建模 (MIM) 任务显著优于朴素像素级自动编码。与表 1 的结果相比,两个任务的消融结果比从头训练视觉 Transformer 。结果表明,视觉 tokens 的预测是 BEiT 的关键组件

        第三,我们 减少了视觉 tokens 和 blockwise masking 的使用。我们发现,blockwise masking 对像素级自动编码更有帮助,从而缓解了短距离依赖的痛苦。

        第四,恢复所有的视觉 tokens 会损害下游任务的性能

        第五,我们比较了不同训练 steps 下的 BEiT。对模型进行更长时间的预训练可以进一步提高下游任务的性能。


四、相关工作

        略


五、总结

        我们为视觉 Transformer 引入了一个自监督的预训练框架,在下游任务上实现了强大的微调结果,如图像分类和语义分割。我们表明,所提出的方法对于图像 Transformer 的 BERT-like 预训练 (即具有 masked 输入的自动编码) 的良好工作至关重要。我们还提出了自动获得关于语义区域的知识的有趣属性,而不使用任何人类标注的数据。在未来,我们希望在数据大小和模型大小方面扩大 BEiT 预训练。此外,我们将以更统一的方式进行多模态预训练,对文本和图像使用相似的 objectives 和共享的架构。

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

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

相关文章

谁还说我没表情包用?马上用Python采集上万张个表情包

前言 今天来表演一手 采集全网表情包图片 虽然我现在的wx表情包已经996个了,但是我还在存表情包哈哈,多了就继续删 现在跟人聊天,不发个表情包,我都觉得不对劲,怪难受的 索性今天就来,给你们分享一下&a…

Vue3:分析elementplus表格第一列序号hover变多选框实现思路

灵感来自Vue el-table 表格第一列序号与复选框hover切换 源码是通过Vue2elementui去实现的,本篇是通过Vue3elementplus实现,所以在代码上面有些许不同,但函数名一致 实现思路: ①通过表头是多选框,我们可以判定这一…

9.1、面向对象编程

文章目录面向对象编程简介面向对象编程面向对象编程的三大特性对象和类封装练习继承什么是继承重写父类方法多继承私有属性和私有方法多态项目案例:栈和队列的封装栈的封装队列的封装python是面向对象的编程语言 面向对象编程简介 “面向过程”(Procedure Oriente…

Java并发编程—synchronized

文章目录synchronized 的底层实现原理监视器锁对象的锁的获取过程如下:monitorexit:加synchronized锁前后对比synchronized的作用synchronized的三种主要用法synchronized为什么是 非公平锁?————————————————————————…

大数据项目 --- 电商数仓(一)

这个项目实在数据采集基础使用的,需要提前复习之前学的东西,否则的话就是很难继续学习.详见博客数据项目一 ---数据采集项目.大数据项目 --- 数据采集项目_YllasdW的博客-CSDN博客大数据第一个项目笔记整理https://blog.csdn.net/m0_47489229/article/details/127477626 目录 …

Android 基于物理特性动画 —— 弹簧动画

在安卓开发中我们可以通过动画添加视觉提示,向用户通知应用中的动态。当界面状态发生改变时(例如有新内容加载或有新操作可用时),动画尤其有用。动画还为应用增加了优美的外观,使其拥有更高品质的外观和风格。 首先来…

Java并发编程—并发和并行、线程上下文

文章目录并发和并行并发和并行的区别上下文切换相关问题为什么循环次数少的情况下,单线程快?什么时候需要用多线程?线程上下文切换消耗的时长?用什么测试的线程上下文?面试回答下面的工具会加分:如何减少上…

DQL简介

学习笔记之DQL 数据查询语言,用来查询数据库中表的记录。 查询关键字:select 基本查询 1查询多个字段 select 字段1,字段2,字段3.. from 表名; select * from 表名;2设置别名 select 字段1 [别名1],字段2[别名2]... from 表名;3…

233搞懂HMM(隐马尔可夫)

文章目录2条性质3个参数3个问题维特比算法参考资料有向图模型,主要用于时序数据建模,在语音识别,自然语言处理等领域,以及在知识图谱命名实体识别中的序列标注,有广泛应用。 HMM模型由两部分组成, 观测变量…

spring boot 应用mybatis

Mybatis入门: Mybatis入门_做测试的喵酱的博客-CSDN博客 目录 一、spring boot 应用mybatis 核心 二、举例: 2.1 背景 2.2 项目结构: 2.3 依赖包 pom 2.4 项目配置文件application.yml 2.5 实例层entity 2.6 mybatis的mapper层 2.7 spring boot…

Android—过渡按钮的简单实现

Android—过渡按钮的简单实现前言准备工作登录页面(activity_main.xml)登录成功页面(activity_new.xml)主要代码给登录按钮设置监听事件(MainActivity.xml)点击登录按钮出现加载动画(TransitionButton.java)当isSuccessful判断为true时(MainActivity.xml)加载动画结束时切入跳转…

C语言笔记-16-Linux基础-文件元数据

C语言笔记-16-Linux基础-文件元数据 文章目录C语言笔记-16-Linux基础-文件元数据前言一、概述二、ln 硬连接三、软连接四、stat 获取元数据总结前言 自学笔记,没有历史知识铺垫(省略百度部分)C语言笔记-16-Linux基础-文件元数据 一、概述 文…

Kaggle泰坦尼克号-决策树Top 3%-0基础代码详解

Titanic Disaster Kaggle,里的经典入门题目,因为在学决策树所以找了一个实例学习了一下,完全萌新零基础,所以基本每一句都做了注释。 原文链接:Titanic: Simple Decision Tree model score(Top 3%) | Kaggle 目录 1.…

SolidWorks如何绘制环形波纹垫片

环形波纹垫片主要用于螺纹式固定件或者防滑螺纹固定中,那这个环形垫片一般怎么用SolidWorks制作呢?首先我们观察到这样的垫片是上下此起彼伏的波纹状,厚度一般1MM左右,制作起来还是有点小难度,但是通过仔细观察,我们可以看到它的大概走向,如图 也就是特征就是这边凹下去…

获取Android签名MD5的方式

形而上者谓之道,形而下者谓之器 我们在申请百度云/腾讯云等第三方的各种服务时,经常会遇到需要提供包名和签名MD5的情况。这里特地总结一下: 1. 获取MD5的一般方式 1.1 有签名文件(.keystore)的情况下: keytool -list -v -keystore XXX.key…

【沐风老师】3DMAX一键生成圣诞树建模插件使用教程

圣诞节快到了,给大家分享一款3DMax一键生成圣诞树模型插件: 3DMAX一键生成圣诞树建模插件,可以生成定制和随机两种3D圣诞树模型,并自动赋予材质和贴图。 【安装方法】 方法一:解压后直接拖动插件脚本文件到3dMax窗口…

使用springboot实现jsonp|jsonp的实现|JSONP的实现使用springboot

1、服务端&#xff1a; 1.1、项目目录&#xff1a; 1.2、pom文件&#xff1a; <?xml version"1.0" encoding"UTF-8"?><project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instan…

从一到无穷大 #3 对象存储.浅谈

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。 本作品 (李兆龙 博文, 由 李兆龙 创作)&#xff0c;由 李兆龙 确认&#xff0c;转载请注明版权。 文章目录引言Windows Azure StorageNosql&#xff1a;TiKV为例总结引言 天才的开源精神对于普…

67-94-hive-函数-开窗函数-常用函数-udf自定义函数

67-hive-函数&#xff1a; UDF:一进一出&#xff0c;普通函数 UDAF:多进一出&#xff0c;聚合函数 UDTF&#xff1a;一进多出&#xff0c;炸裂函数 一、多指的是输入数据的行数。一行变多行&#xff0c;多行变一行。 函数 #查看系统自带的函数 hive> show functions; …

Docker以标准方式安装部署Redis

Docker安装redis的命令很简单&#xff0c;但是很多都是半成品的命令&#xff0c;说白了&#xff0c;就是自己玩玩&#xff0c;一个demo级别的redis而已。 本篇文章以最全的命令方式安装部署Redis。 注意&#xff1a; 本篇只是单机版的&#xff0c;只是公司测试环境使用&…