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

news2024/11/29 20:47:39

来自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和B
    segments = [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.coloradmin.cn/o/975330.html

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

相关文章

DOM 简介 | 深入了解DOM

目录 一、DOM是什么 二、DOM的访问 三、DOM节点类型 四、DOM的分级 今天我们将了解WEB编程中一个重要的概念DOM&#xff08;Document Object Model&#xff09;文档对象模型&#xff0c;它帮助我们使用JavaScript&#xff08;或其他编程语言&#xff09;操纵文档。 一、DO…

java IDEA文件路径分层级

如下图这样 在设置里找到Compact Middle Packages&#xff0c;去掉勾选就行了

MEMS传感器的原理与构造——单片式硅陀螺仪

一、前言 机械转子式陀螺仪在很长的一段时间内都是唯一的选项&#xff0c;也正是因为它的结构和原理&#xff0c;使其不再适用于现代小型、单体、集成式传感器的设计。常规的机械转子式陀螺仪包括平衡环、支撑轴承、电机和转子等部件&#xff0c;这些部件需要精密加工和…

如何建设一个安全运营中心(SOC)?

然信息安全管理问题主要是个从上而下的问题&#xff0c;不能指望通过某一种工具来解决&#xff0c;但良好的安全技术基础架构能有效的推动和保障信息安全管理。随着国内行业IT应用度和信息安全管理水平的不断提高&#xff0c;企业对于安全管理的配套设施如安全运营中心&#xf…

PMD 检查java代码:在条件语句中避免使用硬编码的字面量(AvoidLiteralsInIfCondition )

https://docs.pmd-code.org/pmd-doc-6.55.0/pmd_rules_java_errorprone.html#avoidliteralsinifcondition 在条件语句中&#xff0c;避免避免使用硬编码的字面量。可以将字面量声明为有描述意义的静态成员或者私有成员&#xff0c;提升可维护性。默认忽略"-1" 和&qu…

Spring IoC 的工作流程

概况 IOC 是什么 Bean 的声明方式 IOC 的工作流程 IOC 是什么 IOC 的全称是 Inversion Of Control, 也就是控制反转&#xff0c;它的核心思想是把对象的管理权限交给容器。 应用程序如果需要使用到某个对象实例&#xff0c;直接从 IOC 容器中去获取就行&#xff0c;这样设计的好…

CSP 202303-1 田地丈量

样例输入 4 10 10 0 0 5 5 5 -2 15 3 8 8 15 15 -2 10 3 15 样例输出 44 答题 首先写一个计算面积的函数&#xff0c;既然大小固定就省去了比较&#xff0c;然后是将在范围之外的矩阵给忽略掉&#xff0c;接下来将碰到的矩阵大小缩小为范围之内的&#xff0c;累加即可 #in…

剪辑App的MMKV应用优化实践

作者 | 我爱吃海米 导读 移动端开发中&#xff0c;IO密集问题在很多时候没有得到充足的重视和解决&#xff0c;贸然的把IO导致的卡顿放到异步线程&#xff0c;可能会导致真正的问题被掩盖&#xff0c;前人挖坑后人踩。其实首先要想的是&#xff0c;数据存储方式是否合理&#x…

阿里云服务器2核4G5M配置一年和五年价格明细表

阿里云2核4G服务器5M带宽可以选择轻量应用服务器或云服务器ECS&#xff0c;轻量2核4G4M带宽服务器297元一年&#xff0c;2核4G云服务器ECS可以选择计算型c7、c6或通用算力型u1实例等&#xff0c;买5年可以享受3折优惠&#xff0c;阿腾云分享阿里云服务器2核4G5M带宽五年费用表&…

数字城市:科技革命下的未来之城

随着科技的不断进步&#xff0c;数字城市已经成为了未来城市发展的关键趋势。数字城市是指利用先进的信息技术、互联网和大数据等工具&#xff0c;将城市各个方面进行数字化、智能化、互联化的发展模式。它不仅仅是一种技术&#xff0c;更是一种对城市管理、发展和居民生活方式…

基于Springcloud微服务框架 +VUE框架开发的智慧工地系统源码

建筑行业快速发展&#xff0c;各建筑工程的建设规模在不断扩大&#xff0c;各岗位工作人员的工作内容所涉及的方面也越来越广泛。随着信息技术水平不断提高,人工记录的方式已经不能够满足大项目的管理要求&#xff0c;就此&#xff0c;创造出一种新型的施工管理技术——智慧工地…

题①拷贝构造相关笔试题

问&#xff1a;此代码中有几次构造&#xff0c;几次拷贝构造&#xff1f; W f&#xff08;W u&#xff09; {W v(u);W w v;return w; } int main() {w x;w y f(x);return 0;解析&#xff1a;一次构造&#xff0c;四次拷贝构造。 再来一题 W f&#xff08;W u&#xff09;…

《VulnHub》Empire:Breakout

VulnHub 1&#xff1a;靶场信息2&#xff1a;打靶2.1&#xff1a;情报收集&威胁建模2.2&#xff1a;漏洞分析&渗透攻击 3&#xff1a;总结3.1&#xff1a;命令&工具3.1.1&#xff1a;Nmap 3.2&#xff1a;关键技术 VulnHub 打靶记录。官网&#xff1a;https://www.…

F#奇妙游(28):ADT中简单值的F#实现

简单值的ADT 在领域建模中&#xff0c;我们尝尝会遇到一些简单的值&#xff0c;比如人的名字、人的编号、物品的代码。如果过早进行程序设计&#xff0c;这些值很容易就会变成程序设计语言中的基本量&#xff0c;string、int这些&#xff0c;就比如人的标号和物品的编号&#…

第十五课 状语从句

文章目录 前言一、时间状语从句时间状语从句&#xff0c;主语谓语宾语 或者 主语谓语宾语时间状语从句时间状语从句&#xff0c;主语系动词表语 或者 主语系动词表语时间状语从句1、when,while,as 引导的时间状语从句when主语谓语&#xff08;宾语&#xff09;状语when主语系动…

混合查询多家快递,快速掌握物流信息

在现代社会&#xff0c;快递服务已成为我们日常生活的重要组成部分。无论是购物还是文件传递&#xff0c;我们都需要快递服务的帮助。然而&#xff0c;不同的快递公司需要不同的查询方法&#xff0c;这无疑增加了我们的查询难度。因此&#xff0c;有没有一种方法可以让我们一次…

RuntimeError: ANTLR version mismatch

规则引擎源码&#xff1a; nemonik/Intellect: DSL and Rules Engine For Python (github.com) 运行程序 Example.py 时报错&#xff1a; RuntimeError: ANTLR version mismatch: The recognizer has been generated with API V0, but this runtime does not support this. …

svn checkout 报 ‘svn: E000061: 执行上下文错误: Connection refused‘

问题 svn: E170013svn: E000061 ➜ svn svn checkout https://xxx.xxx.xxx.xxx:9443/svn/project-xxx/ svn: E170013: Unable to connect to a repository at URL https://xxx.xxx.xxx.xxx:9443/svn/project-xxx svn: E000061: 执行上下文错误: Connection refused链接在浏览…

收入下降,亏损扩大,利润率急剧恶化,蔚来仍充满风险

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 蔚来第二季度财报分析 猛兽财经从蔚来&#xff08;NIO&#xff09;2023年第二季度财报中&#xff0c;获得的最大收获并不是该公司的收入下降或亏损扩大&#xff0c;而是由于价格竞争加剧&#xff0c;中国电动汽车行业整体上…

5700A福禄克FLUKE 5700A多功能校准器

181/2461/8938Fluke 5700A/5720A 高精度多功能校准器 5700A: 世界级标准产品 通过不断的改进、提高&#xff0c;5700A已经演变为5700A系列II。这是福禄克公司生产的、经过大量测试证明、极为可靠的、高精度校准器。5700A已经在全世界的范围被看作是校准器的标准&#xff0c;具有…