自然语言处理(七):来自Transformers的双向编码器表示(BERT)

来自Transformers的双向编码器表示(BERT)

BERT(Bidirectional Encoder Representations from Transformers)是一种预训练的自然语言处理模型,由Google于2018年提出。它是基于Transformer模型架构的深度双向(双向指同时考虑上下文信息)表示学习模型。

BERT的目标是通过在大规模文本语料上进行自监督学习来学习通用的语言表示。在预训练阶段,BERT使用了两个主要任务:掩码语言模型(Masked Language Model,MLM)和下一句预测(Next Sentence Prediction,NSP)。

在掩码语言模型任务中,BERT会在输入句子中随机掩盖一些词,并尝试预测这些掩盖的词。这个任务使得模型能够通过上下文来理解词语之间的关系,同时也能够学习到句子级别的表示。

在下一句预测任务中,BERT会输入两个句子,并预测这两个句子是否是连续的。这个任务有助于模型学习到句子之间的关联性和推理能力。

通过这两个任务的预训练,BERT能够学习到丰富的句子级别和词级别的语义表示。在实际应用中,BERT的预训练模型可以用来进行下游任务的微调,比如文本分类、命名实体识别、句子相似度等。

BERT的主要特点包括以下几点:

  1. 双向性:BERT通过使用Transformer的编码器结构,能够同时考虑上下文信息,使模型能够更好地理解句子中的每个词的语义。

  2. 预训练-微调架构:BERT先在大规模文本语料上进行预训练,然后通过微调在具体任务上进行优化。这种架构使得模型能够在不同的任务上灵活应用,并且不需要从零开始训练。

  3. 多层表示:BERT模型由多个Transformer编码器层组成,每个层都生成了丰富的句子和词级别的表示,使得模型能够处理不同层次的语义信息。

  4. 预训练规模:BERT的预训练使用了大规模的文本语料,其中包括了互联网上的大量文本数据,这使得模型能够学习到更通用的语言表示。

我们已经介绍了几种用于自然语言理解的词嵌入模型。在预训练之后,输出可以被认为是一个矩阵,其中每一行都是一个表示预定义词表中词的向量。事实上,这些词嵌入模型都是与上下文无关的。让我们先来说明这个性质。

文章内容来自李沐大神的《动手学深度学习》并加以我的理解,感兴趣可以去https://zh-v2.d2l.ai/查看完整书籍


文章目录

  • 来自Transformers的双向编码器表示(BERT)
  • 从上下文无关到上下文敏感
  • 从特定于任务到不可知任务
  • BERT:把两个最好的结合起来
  • 输入表示
    • 预训练任务
      • 掩蔽语言模型
      • 下一句预测(Next Sentence Prediction)
    • 整合代码


从上下文无关到上下文敏感

例如,word2vec和GloVe都将相同的预训练向量分配给同一个词,而不考虑词的上下文(如果有的话)。形式上,任何词元 x x x的上下文无关表示是函数 f ( x ) f(x) f(x),其仅将 x x x作为其输入。考虑到自然语言中丰富的多义现象和复杂的语义,上下文无关表示具有明显的局限性。例如,在“a crane is flying”(一只鹤在飞)和“a crane driver came”(一名吊车司机来了)的上下文中,“crane”一词有完全不同的含义;因此,同一个词可以根据上下文被赋予不同的表示。

这推动了“上下文敏感”词表示的发展,其中词的表征取决于它们的上下文。因此,词元 x x x的上下文敏感表示是函数 f ( x , c ( x ) ) f(x,c(x)) f(x,c(x)),其取决于 x x x及其上下文 c ( x ) c(x) c(x)。流行的上下文敏感表示包括TagLM(language-model-augmented sequence tagger,语言模型增强的序列标记器) (Peters et al., 2017)、CoVe(Context Vectors,上下文向量) (McCann et al., 2017)和ELMo(Embeddings from Language Models,来自语言模型的嵌入) (Peters et al., 2018)。

例如,通过将整个序列作为输入,ELMo是为输入序列中的每个单词分配一个表示的函数。具体来说,ELMo将来自预训练的双向长短期记忆网络的所有中间层表示组合为输出表示。然后,ELMo的表示将作为附加特征添加到下游任务的现有监督模型中,例如通过将ELMo的表示和现有模型中词元的原始表示(例如GloVe)连结起来。一方面,在加入ELMo表示后,冻结了预训练的双向LSTM模型中的所有权重。另一方面,现有的监督模型是专门为给定的任务定制的。利用当时不同任务的不同最佳模型,添加ELMo改进了六种自然语言处理任务的技术水平:情感分析、自然语言推断、语义角色标注、共指消解、命名实体识别和问答。

从特定于任务到不可知任务

尽管ELMo显著改进了各种自然语言处理任务的解决方案,但每个解决方案仍然依赖于一个特定于任务的架构。然而,为每一个自然语言处理任务设计一个特定的架构实际上并不是一件容易的事。GPT(Generative Pre Training,生成式预训练)模型为上下文的敏感表示设计了通用的任务无关模型 (Radford et al., 2018)。GPT建立在Transformer解码器的基础上,预训练了一个用于表示文本序列的语言模型。当将GPT应用于下游任务时,语言模型的输出将被送到一个附加的线性输出层,以预测任务的标签。与ELMo冻结预训练模型的参数不同,GPT在下游任务的监督学习过程中对预训练Transformer解码器中的所有参数进行微调。GPT在自然语言推断、问答、句子相似性和分类等12项任务上进行了评估,并在对模型架构进行最小更改的情况下改善了其中9项任务的最新水平。

然而,由于语言模型的自回归特性,GPT只能向前看(从左到右)。在“i went to the bank to deposit cash”(我去银行存现金)和“i went to the bank to sit down”(我去河岸边坐下)的上下文中,由于“bank”对其左边的上下文敏感,GPT将返回“bank”的相同表示,尽管它有不同的含义。

语言模型的自回归特性是指在生成文本时,模型依次预测下一个词语的概率,并将其作为输入的一部分来生成后续的词语序列。也就是说,模型通过先前生成的词语来预测下一个词语,然后将其添加到生成的文本中,形成一个逐步生成的过程,这种方式被称为自回归(autoregressive)。
自回归语言模型的基本思想是基于马尔可夫假设,即当前词语的生成仅依赖于前面的有限个词语。具体来说,给定一个上下文序列(先前生成的词语),语言模型通过条件概率来预测下一个词语的概率分布。这个条件概率可以表示为:
P ( w t ∣ w 1 , w 2 , . . . , w t − 1 ) P(w_t | w_1, w_2, ..., w_{t-1}) P(wtw1,w2,...,wt1)
其中, w t w_t wt表示第t个位置的词语, w 1 , w 2 , . . . , w t − 1 w_1, w_2, ..., w_{t-1} w1,w2,...,wt1表示前面已经生成的词语序列。
为了生成文本,语言模型可以使用一种称为贪婪搜索(greedy search)的策略,即每次选择概率最高的词语作为下一个词语生成。或者,也可以使用一些其他的生成策略,比如束搜索(beam search),以获得更多可能的生成序列。
语言模型的自回归特性使得它能够生成连贯的文本,保持上下文的连续性,并且能够在生成过程中考虑语法、语义和上下文信息。这使得自回归语言模型在机器翻译、文本生成、语音识别等任务中得到广泛应用。
然而,自回归语言模型也存在一些限制,比如生成速度较慢、无法并行计算等。为了克服这些问题,近年来出现了一些非自回归的生成模型,如BERT、GPT-2、GPT-3等,它们使用了预训练的方式来学习语言表示,可以同时生成整个序列,提高了生成速度和效率。

BERT:把两个最好的结合起来

如我们所见,ELMo对上下文进行双向编码,但使用特定于任务的架构;而GPT是任务无关的,但是从左到右编码上下文。BERT(来自Transformers的双向编码器表示)结合了这两个方面的优点。它对上下文进行双向编码,并且对于大多数的自然语言处理任务 (Devlin et al., 2018)只需要最少的架构改变。通过使用预训练的Transformer编码器,BERT能够基于其双向上下文表示任何词元。在下游任务的监督学习过程中,BERT在两个方面与GPT相似。首先,BERT表示将被输入到一个添加的输出层中,根据任务的性质对模型架构进行最小的更改,例如预测每个词元与预测整个序列。其次,对预训练Transformer编码器的所有参数进行微调,而额外的输出层将从头开始训练。下图描述了ELMo、GPT和BERT之间的差异。
在这里插入图片描述
BERT进一步改进了11种自然语言处理任务的技术水平,这些任务分为以下几个大类:(1)单一文本分类(如情感分析)、(2)文本对分类(如自然语言推断)、(3)问答、(4)文本标记(如命名实体识别)。从上下文敏感的ELMo到任务不可知的GPT和BERT,它们都是在2018年提出的。概念上简单但经验上强大的自然语言深度表示预训练已经彻底改变了各种自然语言处理任务的解决方案。

在本章的其余部分,我们将深入了解BERT的训练前准备。

输入表示

在自然语言处理中,有些任务(如情感分析)以单个文本作为输入,而有些任务(如自然语言推断)以一对文本序列作为输入。BERT输入序列明确地表示单个文本和文本对。当输入为单个文本时,BERT输入序列是特殊类别词元“”、文本序列的标记、以及特殊分隔词元“”的连结。当输入为文本对时,BERT输入序列是“”、第一个文本序列的标记、“”、第二个文本序列标记、以及“”的连结。我们将始终如一地将术语“BERT输入序列”与其他类型的“序列”区分开来。例如,一个BERT输入序列可以包括一个文本序列或两个文本序列。

为了区分文本对,根据输入序列学到的片段嵌入 e A e_A eA e b e_b eb分别被添加到第一序列和第二序列的词元嵌入中。对于单文本输入,仅使用 e A e_A eA

下面的get_tokens_and_segments将一个句子或两个句子作为输入,然后返回BERT输入序列的标记及其相应的片段索引。

#@save
def get_tokens_and_segments(tokens_a, tokens_b=None):"""获取输入序列的词元及其片段索引"""tokens = ['<cls>'] + tokens_a + ['<sep>']# 0和1分别标记片段A和Bsegments = [0] * (len(tokens_a) + 2)if tokens_b is not None:tokens += tokens_b + ['<sep>']segments += [1] * (len(tokens_b) + 1)return tokens, segments

BERT选择Transformer编码器作为其双向架构。在Transformer编码器中常见是,位置嵌入被加入到输入序列的每个位置。然而,与原始的Transformer编码器不同,BERT使用可学习的位置嵌入。总之, 下图表明BERT输入序列的嵌入是词元嵌入、片段嵌入和位置嵌入的和。
在这里插入图片描述
下面的BERTEncoder类类似于之前实现的TransformerEncoder类。与TransformerEncoder不同,BERTEncoder使用片段嵌入和可学习的位置嵌入

#@save
class BERTEncoder(nn.Module):"""BERT编码器"""def __init__(self, vocab_size, num_hiddens, norm_shape, ffn_num_input,ffn_num_hiddens, num_heads, num_layers, dropout,max_len=1000, key_size=768, query_size=768, value_size=768,**kwargs):super(BERTEncoder, self).__init__(**kwargs)self.token_embedding = nn.Embedding(vocab_size, num_hiddens)self.segment_embedding = nn.Embedding(2, num_hiddens)self.blks = nn.Sequential()for i in range(num_layers):self.blks.add_module(f"{i}", d2l.EncoderBlock(key_size, query_size, value_size, num_hiddens, norm_shape,ffn_num_input, ffn_num_hiddens, num_heads, dropout, True))# 在BERT中,位置嵌入是可学习的,因此我们创建一个足够长的位置嵌入参数self.pos_embedding = nn.Parameter(torch.randn(1, max_len,num_hiddens))def forward(self, tokens, segments, valid_lens):# 在以下代码段中,X的形状保持不变:(批量大小,最大序列长度,num_hiddens)X = self.token_embedding(tokens) + self.segment_embedding(segments)X = X + self.pos_embedding.data[:, :X.shape[1], :]for blk in self.blks:X = blk(X, valid_lens)return X

关于这里的段嵌入:
这里的段嵌入用于区分第一句还是第二句,所以segment_embedding的第一个参数是2

假设词表大小为10000,为了演示BERTEncoder的前向推断,让我们创建一个实例并初始化它的参数。

vocab_size, num_hiddens, ffn_num_hiddens, num_heads = 10000, 768, 1024, 4
norm_shape, ffn_num_input, num_layers, dropout = [768], 768, 2, 0.2
encoder = BERTEncoder(vocab_size, num_hiddens, norm_shape, ffn_num_input,ffn_num_hiddens, num_heads, num_layers, dropout)

我们将tokens定义为长度为8的2个输入序列,其中每个词元是词表的索引。使用输入tokens的BERTEncoder的前向推断返回编码结果,其中每个词元由向量表示,其长度由超参数num_hiddens定义。此超参数通常称为Transformer编码器的隐藏大小(隐藏单元数)。

tokens = torch.randint(0, vocab_size, (2, 8))
segments = torch.tensor([[0, 0, 0, 0, 1, 1, 1, 1], [0, 0, 0, 1, 1, 1, 1, 1]])
encoded_X = encoder(tokens, segments, None)
encoded_X.shape

在这里插入图片描述

预训练任务

BERTEncoder的前向推断给出了输入文本的每个词元和插入的特殊标记“”及“”的BERT表示。接下来,我们将使用这些表示来计算预训练BERT的损失函数。预训练包括以下两个任务:掩蔽语言模型和下一句预测。

掩蔽语言模型

语言模型使用左侧的上下文预测词元。为了双向编码上下文以表示每个词元,BERT随机掩蔽词元并使用来自双向上下文的词元以自监督的方式预测掩蔽词元。此任务称为掩蔽语言模型。

在这个预训练任务中,将随机选择15%的词元作为预测的掩蔽词元。要预测一个掩蔽词元而不使用标签作弊,一个简单的方法是总是用一个特殊的“”替换输入序列中的词元。然而,人造特殊词元“”不会出现在微调中。为了避免预训练和微调之间的这种不匹配,如果为预测而屏蔽词元(例如,在“this movie is great”中选择掩蔽和预测“great”),则在输入中将其替换为:

80%时间为特殊的““词元(例如,“this movie is great”变为“this movie is”;

10%时间为随机词元(例如,“this movie is great”变为“this movie is drink”);

10%时间内为不变的标签词元(例如,“this movie is great”变为“this movie is great”)。

请注意,在15%的时间中,有10%的时间插入了随机词元。这种偶然的噪声鼓励BERT在其双向上下文编码中不那么偏向于掩蔽词元(尤其是当标签词元保持不变时)。

我们实现了下面的MaskLM类来预测BERT预训练的掩蔽语言模型任务中的掩蔽标记。预测使用单隐藏层的多层感知机(self.mlp)。在前向推断中,它需要两个输入:BERTEncoder的编码结果和用于预测的词元位置。输出是这些位置的预测结果。

#@save
class MaskLM(nn.Module):"""BERT的掩蔽语言模型任务"""def __init__(self, vocab_size, num_hiddens, num_inputs=768, **kwargs):super(MaskLM, self).__init__(**kwargs)self.mlp = nn.Sequential(nn.Linear(num_inputs, num_hiddens),nn.ReLU(),nn.LayerNorm(num_hiddens),nn.Linear(num_hiddens, vocab_size))def forward(self, X, pred_positions):num_pred_positions = pred_positions.shape[1]pred_positions = pred_positions.reshape(-1)#转为一维数组batch_size = X.shape[0]batch_idx = torch.arange(0, batch_size)# 假设batch_size=2,num_pred_positions=3# 那么batch_idx是np.array([0,0,0,1,1,1])batch_idx = torch.repeat_interleave(batch_idx, num_pred_positions)masked_X = X[batch_idx, pred_positions]masked_X = masked_X.reshape((batch_size, num_pred_positions, -1))mlm_Y_hat = self.mlp(masked_X)return mlm_Y_hat

假设 pred_positions 的形状为 (batch_size, num_pred_positions),其中 batch_size 表示批次大小,num_pred_positions 表示每个样本中被屏蔽的 token 的数量。

为了演示MaskLM的前向推断,我们创建了其实例mlm并对其进行了初始化。回想一下,来自BERTEncoder的正向推断encoded_X表示2个BERT输入序列。我们将mlm_positions定义为在encoded_X的任一输入序列中预测的3个指示。mlm的前向推断返回encoded_X的所有掩蔽位置mlm_positions处的预测结果mlm_Y_hat。对于每个预测,结果的大小等于词表的大小。

mlm = MaskLM(vocab_size, num_hiddens)
mlm_positions = torch.tensor([[1, 5, 2], [6, 1, 5]])
mlm_Y_hat = mlm(encoded_X, mlm_positions)
mlm_Y_hat.shape

在这里插入图片描述

输入的encoded_X为(2,8,768),mlm_positions为(2,3),即num_pred_positions=3,pred_positions为(1,6),batch_idx经过复制为[0,0,0,1,1,1],故mask_X取出了6个768维度的词嵌入,再将其变化为(2,3,768),最后放入MLP中变为(2,3,10000)

通过掩码下的预测词元mlm_Y的真实标签mlm_Y_hat,我们可以计算在BERT预训练中的遮蔽语言模型任务的交叉熵损失。

mlm_Y = torch.tensor([[7, 8, 9], [10, 20, 30]])
loss = nn.CrossEntropyLoss(reduction='none')
mlm_l = loss(mlm_Y_hat.reshape((-1, vocab_size)), mlm_Y.reshape(-1))
mlm_l.shape

在这里插入图片描述

下一句预测(Next Sentence Prediction)

尽管掩蔽语言建模能够编码双向上下文来表示单词,但它不能显式地建模文本对之间的逻辑关系。为了帮助理解两个文本序列之间的关系,BERT在预训练中考虑了一个二元分类任务——下一句预测。在为预训练生成句子对时,有一半的时间它们确实是标签为“真”的连续句子;在另一半的时间里,第二个句子是从语料库中随机抽取的,标记为“假”。

下面的NextSentencePred类使用单隐藏层的多层感知机来预测第二个句子是否是BERT输入序列中第一个句子的下一个句子。由于Transformer编码器中的自注意力,特殊词元“”的BERT表示已经对输入的两个句子进行了编码。因此,多层感知机分类器的输出层(self.output)以X作为输入,其中X是多层感知机隐藏层的输出,而MLP隐藏层的输入是编码后的“”词元。

#@save
class NextSentencePred(nn.Module):"""BERT的下一句预测任务"""def __init__(self, num_inputs, **kwargs):super(NextSentencePred, self).__init__(**kwargs)self.output = nn.Linear(num_inputs, 2)def forward(self, X):# X的形状:(batchsize,num_hiddens)return self.output(X)

我们可以看到,NextSentencePred实例的前向推断返回每个BERT输入序列的二分类预测。

encoded_X = torch.flatten(encoded_X, start_dim=1)
# NSP的输入形状:(batchsize,num_hiddens)
nsp = NextSentencePred(encoded_X.shape[-1])
nsp_Y_hat = nsp(encoded_X)
nsp_Y_hat.shape

在这里插入图片描述
还可以计算两个二元分类的交叉熵损失。

nsp_y = torch.tensor([0, 1])
nsp_l = loss(nsp_Y_hat, nsp_y)
nsp_l.shape

在这里插入图片描述

值得注意的是,上述两个预训练任务中的所有标签都可以从预训练语料库中获得,而无需人工标注。原始的BERT已经在图书语料库 (Zhu et al., 2015)和英文维基百科的连接上进行了预训练。这两个文本语料库非常庞大:它们分别有8亿个单词和25亿个单词。

整合代码

在预训练BERT时,最终的损失函数是掩蔽语言模型损失函数和下一句预测损失函数的线性组合。现在我们可以通过实例化三个类BERTEncoder、MaskLM和NextSentencePred来定义BERTModel类。前向推断返回编码后的BERT表示encoded_X、掩蔽语言模型预测mlm_Y_hat和下一句预测nsp_Y_hat。

#@save
class BERTModel(nn.Module):"""BERT模型"""def __init__(self, vocab_size, num_hiddens, norm_shape, ffn_num_input,ffn_num_hiddens, num_heads, num_layers, dropout,max_len=1000, key_size=768, query_size=768, value_size=768,hid_in_features=768, mlm_in_features=768,nsp_in_features=768):super(BERTModel, self).__init__()self.encoder = BERTEncoder(vocab_size, num_hiddens, norm_shape,ffn_num_input, ffn_num_hiddens, num_heads, num_layers,dropout, max_len=max_len, key_size=key_size,query_size=query_size, value_size=value_size)self.hidden = nn.Sequential(nn.Linear(hid_in_features, num_hiddens),nn.Tanh())self.mlm = MaskLM(vocab_size, num_hiddens, mlm_in_features)self.nsp = NextSentencePred(nsp_in_features)def forward(self, tokens, segments, valid_lens=None,pred_positions=None):encoded_X = self.encoder(tokens, segments, valid_lens)if pred_positions is not None:mlm_Y_hat = self.mlm(encoded_X, pred_positions)else:mlm_Y_hat = None# 用于下一句预测的多层感知机分类器的隐藏层,0是“<cls>”标记的索引nsp_Y_hat = self.nsp(self.hidden(encoded_X[:, 0, :]))return encoded_X, mlm_Y_hat, nsp_Y_hat

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

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

相关文章

DHTMLX Gantt 8.0.5 Crack -甘特图

8.0.5 2023 年 9 月 1 日。错误修复版本 修复 修复通过gantt.getGanttInstance配置启用扩展而触发的错误警告修复启用skip_off_time配置时gantt.exportToExcel()的不正确工作示例查看器的改进 8.0.4 2023 年 7 月 31 日。错误修复版本 修复 修复数据处理器不跟踪资源数据…

【算法】反悔贪心

文章目录 反悔贪心力扣题目列表630. 课程表 III871. 最低加油次数LCP 30. 魔塔游戏2813. 子序列最大优雅度 洛谷题目列表P2949 [USACO09OPEN] Work Scheduling GP1209 [USACO1.3] 修理牛棚 Barn RepairP2123 皇后游戏&#xff08;&#x1f6b9;省选/NOI− TODO&#xff09; 相关…

【SpringMVC】实现增删改查(附源码)

目录 引言 一、前期准备 1.1.搭建Maven环境 1.2.导入pom.xml依赖 1.3.导入配置文件 ①jdbc.properties ②generatorConfig.xml ③log4j2.xml ④spring-mybatis.xml ⑤spring-context.xml ⑥spring-mvc.xml ⑦修改web.xml文件 二、逆向生成增删改查 2.1.导入相关u…

Window安装Node.js npm appium Appium Desktop

Window安装Node.js npm appium appium Desktop 1.安装nodejs 参考链接&#xff1a; https://blog.csdn.net/weixin_42064877/article/details/131610918 1)打开浏览器&#xff0c;并前往 Node.js 官网 https://nodejs.org/ ↗。 2)在首页中&#xff0c;您可以看到当前 Node.…

JS中 bind()的用法,call(),apply(),bind()异同点及使用,如何手写一个bind()

✨什么是bind() bind()的MDN地址 bind() 方法创建一个新函数&#xff0c;当调用该新函数时&#xff0c;它会调用原始函数并将其 this 关键字设置为给定的值&#xff0c;同时&#xff0c;还可以传入一系列指定的参数&#xff0c;这些参数会插入到调用新函数时传入的参数的前面。…

ElasticSearch第二讲:ES详解 - ElasticSearch基础概念

ElasticSearch第二讲&#xff1a;ES详解 - ElasticSearch基础概念 在学习ElasticSearch之前&#xff0c;先简单了解下ES流行度&#xff0c;使用背景&#xff0c;以及相关概念等。本文是ElasticSearch第二讲&#xff0c;ElasticSearch的基础概念。 文章目录 ElasticSearch第二讲…

G. The Morning Star

Problem - G - Codeforces 思路&#xff1a;想了挺长时间的&#xff0c;一直没想到一个简便的方法在瞎搞。我们发现对于某个点来说&#xff0c;其他的点如果能够跟他匹配&#xff0c;那么一定在这8个方向上&#xff0c;而同时这8个方向其实对应这4条直线&#xff0c;假设点为(x…

云服务器与内网穿透有什么区别?哪个好用?

云服务器与内网穿透有什么区别&#xff0c;哪个好用&#xff1f;如何在自己公网IP云主机上部署搭建P2P穿透&#xff1f;这里给大家汇总介绍一下&#xff0c;供大家共同学习了解。 云服务器的一些特点&#xff1a; 需要数据上云场景时&#xff0c;通常可以选择使用云服务器。 …

Yarn资源调度器

文章目录 一、Yarn资源调度器1、架构2、Yarn工作机制3、HDFS、YARN、MR关系4、作业提交之HDFS&MapReduce 二、Yarn调度器和调度算法1、先进先出调度器&#xff08;FIFO&#xff09;2、容量调度器&#xff08;Capacity Scheduler&#xff09;3、公平调度器&#xff08;Fair …

[Rust GUI]0.10.0版本iced代码示例 - progress_bar

-1 字体支持 iced0.10.0 仅支持指定系统内置字体(iced默认字体中文会乱码) iced0.10.0 手动加载字体的功能已经砍了&#xff0c;想手动加载就用0.9.0版本&#xff0c;文档0.9.0版本 想显示中文则需要运行在一个自带字体的Windows系统上。而且这个字体最好不要钱。 (Windows闲着…

PyCharm集成开发环境安装、启动与设置

作为非开发工程师职业,大家多多少少都会对编程有抵触,其实没有必要对Python有太大的“戒心" ,把Python当做你的一个工具就可以了。——扎克伯格 一、Python的定义&#xff1a; Python是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。Python的设计具有…

Edge官方鼠标手势

前言 日期&#xff1a;2023年8月 Edge浏览器目前已自带官方的鼠标手势功能&#xff0c;若要使用首先将浏览器更新至最新版&#xff0c;下文介绍使用方法。 官方鼠标手势 前提 更新Edge至最新版&#xff0c;并关闭其它鼠标手势扩展。 开启鼠标手势 打开Edge浏览器的设置&…

技术分析需谨慎,各位投资者应该这样做

技术市场分析中存在许多工具&#xff0c;其中之一便是烛台模式。然而对于这些模式和指标&#xff0c;FPmarkets澳福和各位投资者应持谨慎的态度&#xff0c;因为它们仅仅展示了一种可能的结果&#xff0c;而无法确保其绝对准确。 关于蜡烛图交易的提示&#xff0c;包括Maruboz…

反转字符串 反转字符串 || 反转字符串 |||

思想总结&#xff1a;首先将字符串转变为字符数组&#xff0c;再进行遍历并反转字符。 1.反转字符串 代码&#xff1a; class Solution {public void reverseString(char[] s) {reverse(s,0,s.length); //左闭右开}public static void reverse(char[] ch,int i,int j) { 翻转函…

springboot之二:整合junit进行单元测试+整合redis(本机、远程)+整合mybatis

资源地址&#xff1a; 整合junit的代码&#xff1a;https://download.csdn.net/download/zhiaidaidai/88291527 整合redis的代码&#xff1a;https://download.csdn.net/download/zhiaidaidai/88291536 整合mybatis的代码&#xff1a;https://download.csdn.net/download/zh…

DGA行为转变引发了对网络安全的担忧

Akamai的研究人员发现&#xff0c;在域名系统(DNS)流量数据中&#xff0c;动态种子域生成算法(DGA)家族的行为发生了令人担忧的变化。这一发现揭示了恶意行为者如何调整他们的策略来延长他们的指挥与控制(C2)通信通道的寿命&#xff0c;以保护他们的僵尸网络。 从技术角度来看…

云数据库知识学习——云数据库产品、云数据库系统架构

一、云数据库产品 1.1、云数据库厂商概述 云数据库供应商主要分为三类。 ① 传统的数据库厂商&#xff0c;如 Teradata、Oracle、IBM DB2 和 Microsoft SQL Server 等。 ② 涉足数据库市场的云供应商&#xff0c;如 Amazon、Google、Yahoo!、阿里、百度、腾讯…

【Linux】编辑器 vim

1、vim的基本概念 vi/vim【一款文本编辑器】vim【一款多模式编辑器】vi/vim 的区别简单点来说&#xff0c;它们都是多模式编辑器&#xff0c;不同的是 vim 是 vi 的升级版本&#xff0c;它不仅兼容vi的所有指令&#xff0c;而且还有一些新的特性在里面。例如语法加亮&#xff0…

linux 网络接口的子接口的配置

参考&#xff1a; https://blog.csdn.net/baidu_38803985/article/details/104653205 在 Linux 中&#xff0c;网络接口通常以ethX的形式命名&#xff0c;其中X代表接口的编号&#xff0c;例如eth0代表第一个网络接口&#xff0c;eth1代表第二个&#xff0c;依此类推。虚拟子接…

【PyQT5教程】-02-UI组件

1.按钮 QtWidgets模块提供了多种按钮类&#xff0c;让你可以轻松地创建各种类型的按钮 1.1 QPushButton&#xff08;普通按钮&#xff09; QPushButton是PyQt5中最常见的按钮类型之一&#xff0c;用于触发动作或执行操作。通过信号与槽机制&#xff0c;你可以将按钮的点击事…