LLM微调

文章目录

  • 一. 常见微调分类
    • 1.1 全量微调(FFT:Full Fine-tuning)
    • 1.2 参数高效微调(PEFT:Parameter-Efficient Fine-Tuning)
    • 1.3 指令微调(IFT:Instructional Fine-tuning)
      • 1.3.1 Hard prompt
      • 1.3.2 Soft prompt
  • 二. 常见微调方法
    • 2.1 Prefix-tuning
    • 2.2 Prompt-tuning
    • 2.3 P-tuning v1
    • 2.4 P-tunning v2
    • 2.4 Lora

一. 常见微调分类

1.1 全量微调(FFT:Full Fine-tuning)

  全量微调是对预训练模型的所有参数进行微调,即预训练模型的所有层和参数均被会更新和优化,从而适应目标任务的需求。需要注意,与预训练一样,全量微调需要足够的内存和计算来存储和处理训练过程中的所有梯度、优化器和其它需要更新的部分。全量微调一般可以获得更好的模型性能。
  这种微调方法通常适用于任务和预训练模型之间存在较大差异的情况,或者任务需要模型具有高度灵活性和自适应能力的情况。

1.2 参数高效微调(PEFT:Parameter-Efficient Fine-Tuning)

  为了降低微调时的资源成本,及提升微调效率。研究人员提出了PEFT方法。旨在通过最小化微调参数的数量和计算复杂度,来提高预训练模型在新任务上的性能。常见PEFT方法可分为以下三类:

  • Freeze method : 冻结模型的一些layers,只更新非冻结layers的模型参数,从而降低微调参数的数量与计算复杂度。

  • Additive method : 向预训练模型添加新的层或在某些层上拼接。然后微调时只更拼接网络结构的参数。

  • Reparametrization-based method : 重新参数化方法,些方法的思想是使用低秩表征来最小化可训练参数的数量。

    注: PEFT的Freeze method 可理解为与全量微调对应的部分微调,但Additive method与Reparametrization-based method是否可归为部分微调,这个主要取决于考虑的模型主体是PLM还是微调后的整体模型,以PLM为基准,这两个方法就不算是部分微调。为了不把文章写的复杂,这里没有列出部分微调这个分类。

1.3 指令微调(IFT:Instructional Fine-tuning)

  FFT与PEFT是在从参数更新的层面上来考虑模型的微调,还是有一种提高模型在各种任务上表现的策略是指令微调。这涉及到使用示例来训练机器学习模型,展示模型应该如何响应查询。用于微调大型语言模型的数据集必须符合你的指令目的。使用指令微调时,其模型参数的更新可以是FFT或PEFT。与IFT相关的概念有CoT,in-context learning等, 这篇blog主要把重点放到参数重新上,所以这些概念不做展开。

  例如,如果你想提高模型的摘要能力,你应该构建一个包含摘要指令和相应摘的数据集。在翻译任务中,应包含“请将下面的文本翻译成英文”等指令。这些提示有助于让模型以新的专业方式“思考”,并服务于特定任务。

   上面例子中“请将下面的文本翻译成英文”及类似的“请对下文做出摘要”等提示,我们统称Hard prompt, 与之对应的是Soft prompt。

1.3.1 Hard prompt

  是一个人类可理解的文本字符串,可由任何语言文字组成,直接拼接在模型原始输入之前。从模型角度来看,hard prompt 并没有对PLM做任何的修改,也没没有增加新的参数,所以使用hard prompt微调时,本质是更新PLM本身的参数。因此受PLM参数化的限制 。

   举个例子,在情感分类任务中,我们要判断“《功夫》这个电影是周星弛主演的,无厘头式的幽默,我很喜欢。”这句话的情感极性,我们怎么让一个语言模型来判断这个极性呢?我们可以如下图这样在输入后面接入一个引导的句子“这个电影太[MASK]了”,这个引导的句子里明显缺少了一个形容词,我们让模型把这个容易词自动补全,我们就可以根据这个形容词来判断极性了。

在这里插入图片描述
从这里我们可以看出,如果说finetune是为了使用预训练模型适配下游任务,那prompt就是为了使下游任务适配预训练模型。这种下游任务适配预训练模型的做法可大幅减少预训练模型在下游任务的应用成本,甚至做到不对预训练模型做修改就能使用。

1.3.2 Soft prompt

  通常是在向量空间优化出来的prompt,直接面向模型,人类无法直接理解。且,soft prompt 通常会在PLM模型外部添加相关的网络结构做为prompt的参数,因此,soft prompt 的微调不会更新PLM模型的参数。
  举个例子,如prefix tuning 中,在autoregressive 任务中,在PML所有layer之前拼接一个prefix,在微调时,只更新prefix的参数。

二. 常见微调方法

2.1 Prefix-tuning

论文地址:https://arxiv.org/abs/2101.00190

  prefix-tuning的中文表达是前缀微调,在实现时,prefix-tuning是在PLM前部拼接一小段可学习的向量(virtual tokens)作为Prefix(这里的“前部”是指PLM网络结构每一层的前部,拼接后,PLM网络的层数是不变的), 且在微调模型的过程中只优化拼接的Prefix,而不需要优化整个模型的参数(训练的时候只更新Prefix部分的参数,而PLM中的其他部分参数不更新)。对于不同的任务和模型结构需要不同的Prefix:

  • 在autoregressive LM 前添加prefix: z = [ P R E F I X ; x ; y ] z=[PREFIX;x;y] z=[PREFIX;x;y]
  • 在encoder和decoder前添加prefix: z = [ P R E F I X ; x ; P R E F I X ′ ; y ] z=[PREFIX;x;{PREFIX}^{'};y] z=[PREFIX;x;PREFIX;y]
    可以参考下图来理解。
    在这里插入图片描述

  在原始论文的4.2 节中有表述,直接更新Prefix的参数会导致训练不稳定和性能下降的情况,所以在Prefix前增加了一层MLP, 此MLP与Prefix同row dimension相同,columns dimension 不同。训练之后,MLP直接舍弃,只保留Prefix的参数即可。

  在原始论文的 7.2 节中,对prefix的拼接进行了消融实验,实验证明,PLM的所有层均拼接prefix能取得更好的结果。因此,我们提到prefix-tuning算法,默认是所有层都增加prefix。

  看到这里,如果没有基础的话,可能还不清楚prefix到底是怎么回事儿,这里我画了一幅图展开一下。
在这里插入图片描述

  从上图中,我们可以看出,当一个PreTrainModel在使用Prefix算法微调时,其实是在PreTrainModel之外增加了一个PrefixEncoder模块,这个模块用来生成Prefix, 而这个Prefix本质就是一个学习后的Embedding。PrefixEncoder会生成多个Prefix (past_key_values_1, past_key_values_2, …), 至于具体生成多少,取决于PreTrainModel的层数,这个层数指的是decoder的层数(以gpt类模型为例),如上图,这个层数为24。Prefix在传入decoder后,在attention函数中被拼接到当前hidden_states之前。

PrefixEnocder 源码(出自huggingface PEFT库)

class PrefixEncoder(torch.nn.Module):def __init__(self, config):super().__init__()self.prefix_projection = config.prefix_projectiontoken_dim = config.token_dimnum_layers = config.num_layersencoder_hidden_size = config.encoder_hidden_sizenum_virtual_tokens = config.num_virtual_tokensif self.prefix_projection and not config.inference_mode:# Use a two-layer MLP to encode the prefixself.embedding = torch.nn.Embedding(num_virtual_tokens, token_dim)self.transform = torch.nn.Sequential(torch.nn.Linear(token_dim, encoder_hidden_size),torch.nn.Tanh(),torch.nn.Linear(encoder_hidden_size, num_layers * 2 * token_dim),)else:self.embedding = torch.nn.Embedding(num_virtual_tokens, num_layers * 2 * token_dim)def forward(self, prefix: torch.Tensor):if self.prefix_projection:prefix_tokens = self.embedding(prefix)past_key_values = self.transform(prefix_tokens)else:past_key_values = self.embedding(prefix)return past_key_values

注: 上文的prefix其实是属于soft prompt 也称为 continuous prompt,与之对应的是 hard prompt 亦称为 discrete prompt。下面对hard prompt 和 soft prompt 分别做简单介绍。

2.2 Prompt-tuning

论文地址: https://arxiv.org/abs/2104.08691

   该方法可以看作是Prefix Tuning的简化版本,它给每个任务定义了自己的Prompt,然后拼接到数据上作为输入,具体的理解可参考下图。
在这里插入图片描述

   从上图我们可以看出,prompt tuning的encoder相比于prefix 的 encoder少了一个两层的MLP结构,只有一个embedding方法。拼接的方式是直接与原始PreTrainModel的Embedding进行拼接,然后进入到PreTrainModel的decoder stack中。没有其它操作。相比于prefix的每个encoder都进行拼接,需要训练的参数规则减少了10倍以上(现在的模型encoder动则几十层)。
下面是hugging face peft库中的源码, 核心代码就几行:

class PromptEmbedding(torch.nn.Module):def __init__(self, config, word_embeddings):super().__init__()total_virtual_tokens = config.num_virtual_tokens * config.num_transformer_submodulesself.embedding = torch.nn.Embedding(total_virtual_tokens, config.token_dim)if config.prompt_tuning_init == PromptTuningInit.TEXT and not config.inference_mode:# 此处为初始化self.enbedding的参数,省略...def forward(self, indices):# Just get embeddingsprompt_embeddings = self.embedding(indices)return prompt_embeddings
  • 多任务同时训练
       论文中指出,Prompt tuning 不必像fine tuning那样,对每个下游任务都使用全量模型做一次微调,有几个下游任务就保存几份模型参数,推理时也要使用特定的模型副本对相应的任务做推理。在Prompt tuning中,所有的任务均可以一起进行微调,Prompt tuning 只会为每个任务保存一个prompt。推理时,一个batch中可以有多个下游任务的数据。如下图所示。
    在这里插入图片描述

  • 性能参数规模逼近全量微调
       原始论文的Introduction段落阐述了随着模型参数规模的增加,Prompt Tuning 的效果会逼近全量微调。具体表现见下图。
    在这里插入图片描述

  • prompt 长度的影响
       论文的3.2节,阐述了prompt长度的影响,prompt的长度在20左右时的表现已经不错(超过20之后,继续增加Prompt token长度,对模型的性能提升不明显),同样的,这个gap也会随着模型参数规模的提升而减小(即对于超大规模模型而言,即使 Prompt token 长度很短,对性能也不会有太大的影响)。具体表现见下图。
    在这里插入图片描述

  • Prompt 参数初始化
       在论文的3.2节中探讨了 Prompt token 的初始化方法和长度对于模型性能的影响。通过消融实验结果发现,与随机初始化和使用样本词汇表初始化相比,Prompt Tuning采用“class label”初始化模型的效果更好。不过随着模型参数规模的提升,这种gap最终会消失。具体表现见下图
    在这里插入图片描述

  • Prompt Ensembing
       论文的第6节,提出了 Prompt Ensembling,也就是在一个Batch中同时训练同一个任务的不同 prompt(即采用多种不同方式询问同一个问题),这样相当于训练了不同模型,比模型集成的成本小很多。模型规模很大时,有很大的优势。

   原始论文中主要是在T5上做了相关实验,且最主要的性能如果要接近FFT,参数规模足够大是前提,包括embedding参数的初始化,也与参数规模有关,因些使用此方法时,要注意所使用的模型的参数规模。甜品级及以下的模型使用就不要使用这个方法了。

2.3 P-tuning v1

论文地址:https://arxiv.org/abs/2103.10385 v2
该方法的核心思想是使用可微的virtual token替换discrete tokens,且仅加入到输入层,并使用prompt encoder(BiLSTM+MLP)对virtual token进行编码学习。下图是论文中的框架示意图。
在这里插入图片描述

  • P-Tuning 算法原理 (出自论文2.2节)
       给定 M M M为一个预训练模型,hidden size为 h h h, 词表大小为 [ V ] [V] [V], { x i , y i } \{x_i,y_i\} {xi,yi} 为已经标注好的一个NLU数据集,其中 x 0 : n = { x 0 , x 1 , . . . , x n } x_{0:n} = \{x_0,x_1,...,x_n\} x0:n={x0,x1,...,xn}为一个由离散token组成的输入, y ∈ Y y \in Y yY 为标签集合。我们的目标是估计 f M ( x ) = p ^ ( y ∣ x ) f_{M(x)}=\hat{p}(y|x) fM(x)=p^(yx)的分类条件概率,其中 M M M的参数经过微调或冻结。
       Prompt最初是以离散token的形式提出的(Schick and Schütze,2020)。设 [ D i ] [D_i] [Di]为离散porompt的token。每个prompt都可以描述为一个模板 T = { [ D 0 : i ] , x , [ D ( i + 1 ) : j ] , y , [ D ( j + 1 ) : k ] } T =\{[D_{0:i}],x,[D_{(i+1):j}],y,[D_{(j+1):k}]\} T={[D0:i],x,[D(i+1):j],y,[D(j+1):k]},它可以将token数据(包括输入 x x x 和标签 y y y)组织成一个文本token序列,这样就可以将任务重新表述为 对输入文本的空白地方进行填空。例如,对于预测一个国家首都的任务(LAMA-TREx P36),prompt可以是“[INPUT] 的首都是 [LABEL]”。对于一段标注数据“(英国,伦敦)”,重新表述的文本将是“英国的首都是 [MASK]。”,其中“[MASK]”应该预测为给定的标签“伦敦”。离散prompt和离散数据一起映射到输入嵌入中:
    { e ( D 0 ) . . . e ( D i ) , e ( x 0 ) , . . . , e ( x n ) , . . . , e ( D k ) } \{e(D_0)...e(D_i), e(x_0), ..., e(x_n), ..., e(D_k)\} {e(D0)...e(Di),e(x0),...,e(xn),...,e(Dk)}
    根据预训练的嵌入层, e ∈ R ∣ V ∣ × d e \in R|V |×d eRV×d
       这种离散提示往往极不稳定,可能不是反向传播的最佳选择。因此,我们提出了 P-Tuning,它使用连续prompt嵌入来改进和稳定prompt。令 [ P i ] [P_i] [Pi] 为第 i i i 个连续提示嵌入。P-Tuning 的提示模板如下:
    T = { [ P 0 : i ] , x , [ P ( i + 1 ) : j ] , y , [ P ( j + 1 ) : k ] } T = \{[P_{0:i}],x,[P_{(i+1):j}],y,[P_{(j+1):k}]\} T={[P0:i],x,[P(i+1):j],y,[P(j+1):k]}
    P-Tuning 利用额外的嵌入函数 f : [ P i ] → h i f : [P_i] → h_i f:[Pi]hi将模板映射到
    { h 0 , . . . , h i , e ( x ) , h i + 1 , . . . , h j , e ( y ) , h j + 1 , . . . , h k } \{h_0,...,h_i,e(x),h_{i+1},...,h_j,e(y),h_{j+1},...,h_k\} {h0,...,hi,e(x),hi+1,...,hj,e(y),hj+1,...,hk}

    最后,我们更新embeddings { P i } i = 1 k \{P_i\}^k_{i=1} {Pi}i=1k 以优化任务损失函数(在p-tunning中,embedding 会被更新)。值得注意的是,我们还可以将离散prompt与连续的prompt连接起来( 如下图中input embedding 即包含 e ( x ) e(x) e(x)也包含 h i h_i hi ),这种方法效果更好,并在我们的整个实验中都采用了这种方法。P-Tuning 适用于冻结和微调语言模型。

关于上面几个公式可以参考下图来理解:
在这里插入图片描述

  • Prompt Encoder(出自论文2.3节)
      在上述框架中,我们使用映射函数 f f f 将可训练嵌入 { P i } \{P_i\} {Pi} 映射到模型输入 { h i } \{h_i\} {hi}。直觉是,与使用独立的可学习嵌入相比,使用映射函数可以更方便地对不同提示嵌入之间的依赖关系进行建模。在我们的实现中,我们使用轻量级神经网络来制定函数 f f f。具体来说,我们尝试使用长短期记忆 (LSTM) 网络、多层感知器 (MLP) 和第 3 节中的恒等映射函数。

      这一段落关于Prompt Encoder的说明,我感觉略显笼统,通过这段话我并没有看出PromptEncoder到底是怎么实现的,于是乎我又翻阅了GPT understands, too 的v1版本,在v1版本里对PromptEncoder有较详细的描述,且我又在清华的官网查了p-tuning的实现代码,在当前时间点(2024/06/20),清华的官方实现的代码与v1版本中的描述是相同的。所以下面按v1版本中的描述补充一下理解。

    Prompt Encoder 由一个使用ReLU做为激活函数的双层MLP及BiLSTM组成,对于任意时刻的 h i h_i hi有:
    h i = M L P ( [ h i → : h i ← ] = M L P ( [ L S T M ( h 0 : i ) : L S T M ( h i : m ) ] ) \begin{aligned} h_i &= MLP([ \mathop{h_i} \limits ^{\rightarrow}: \mathop{h_i} \limits ^{\leftarrow}] \\ &= MLP([LSTM(h_{0:i}):LSTM(h_{i:m})]) \end{aligned} hi=MLP([hi:hi]=MLP([LSTM(h0:i):LSTM(hi:m)])

    下面贴上清华官网的P-tuning PromptEncoder代码:

import torch
import torch.nn as nnclass PromptEncoder(torch.nn.Module):def __init__(self, template, hidden_size, tokenizer, device, args):super().__init__()self.device = deviceself.spell_length = sum(template)self.hidden_size = hidden_sizeself.tokenizer = tokenizerself.args = args# ent embeddingself.cloze_length = templateself.cloze_mask = [[1] * self.cloze_length[0]  # first cloze+ [1] * self.cloze_length[1]  # second cloze+ [1] * self.cloze_length[2]  # third cloze]self.cloze_mask = torch.LongTensor(self.cloze_mask).bool().to(self.device)self.seq_indices = torch.LongTensor(list(range(len(self.cloze_mask[0])))).to(self.device)# embeddingself.embedding = torch.nn.Embedding(len(self.cloze_mask[0]), self.hidden_size).to(self.device)# LSTMself.lstm_head = torch.nn.LSTM(input_size=self.hidden_size,hidden_size=self.hidden_size // 2,num_layers=2,dropout=self.args.lstm_dropout,bidirectional=True,batch_first=True)self.mlp_head = nn.Sequential(nn.Linear(self.hidden_size, self.hidden_size),nn.ReLU(),nn.Linear(self.hidden_size, self.hidden_size))print("init prompt encoder...")def forward(self):input_embeds = self.embedding(self.seq_indices).unsqueeze(0)output_embeds = self.mlp_head(self.lstm_head(input_embeds)[0]).squeeze()return output_embeds
  • 结论
    相同参数规模下,如果进行全参数微调,Bert在NLU任务上的效果,超过GPT很多;但是在P-Tuning下,GPT可以取得超越Bert的效果。如下图。
    在这里插入图片描述

2.4 P-tunning v2

原始论文:P-Tuning v2: Prompt Tuning Can Be Comparable to Fine-tuning Universally Across Scales and Tasks
论文地址:https://arxiv.org/abs/2110.07602

之前的Prompt Tuning和P-Tuning v1 等方法存在两个主要的问题:
第一, 缺乏模型参数规模和任务通用性。

  • 缺乏规模通用性:Prompt Tuning论文中表明当模型规模超过100亿个参数时,提示优化可以与全量微调相媲美。但是对于那些较小的模型(从100M到1B),提示优化和全量微调的表现有很大差异,这大大限制了提示优化的适用性。
  • 缺乏任务普遍性:尽管Prompt Tuning和P-tuning在一些 NLU 基准测试中表现出优势,但提示调优对序列标记任务(即序列标注)的有效性尚未得到验证。

第二,缺少深度提示优化,在Prompt Tuning和P-tuning中,连续提示只被插入transformer第一层的输入embedding序列中,在接下来的transformer层中,插入连续提示的位置的embedding是由之前的transformer层计算出来的,这可能导致两个可能的优化挑战。

  • 由于序列长度的限制,可调参数的数量是有限的。
  • 输入embedding对模型预测只有相对间接的影响。

这些问题在P-tuning v2得到了改进。

P-Tuning v2主要是基于P-tuning和prefix-tuning技术,引入Deep Prompt Encoding和Multi-task Learning等策略进行优化的。

在这里插入图片描述
如上图(b)所示,不同层的提示被作为前缀token添加。P-Tuning v2的这种做法带来了两个显著优点:

  • 更多的可调任务特定参数:P-Tuning v2拥有更多的可调任务特定参数(从0.01%到0.1%-3%),这不仅增加了每个任务的处理能力,而且在参数效率上更优。
  • 深层提示对模型预测的直接影响:添加到更深层的提示对模型预测有更直接的影响。

为了达到最佳性能,P-Tuning v2在优化和实现方面有一些有用的细节:(原始论文3.3节)

  • 重参数化(Reparameterization):先前的研究通常使用多层感知机(MLP)这样的重参数化编码器来转换可训练向量,但对于NLU任务来说MLP的有效性取决于任务和数据集。对于某些数据集(如RTE和CoNLL04),MLP带来了明显的改进;但对于其他数据集(例如,BoolQ和CoNLL12),MLP对结果的影响微小甚至负面。

  • 提示词长度(Prompt Length): 提示词长度在P-Tuning v2中扮演着关键角色。研究发现,通常简单的分类任务更倾向于较短的Prompt(少于20个);而复杂的序列标注任务则更适合较长的Prompt(大约100个)。不同的NLU任务通常在不同的提示词长度下达到最佳性能。

  • 多任务学习(Multi-task Learning): 多任务学习通过共享连续提示,在针对个别任务进行微调之前,联合优化多个任务。多任务学习对P-Tuning v2来说不是必选项,但可以通过提供更好的初始化来进一步提升性能(Gu等人,2021)。

  • 分类头(Classification Head): 使用语言建模头(language modeling head)来预测类别化标签(Verbalizers)一直是P-Tuning的核心操作,但在完整数据设置下这不是必需的,且与序列标注不兼容。P-Tuning v2改为在BERT中的token之上应用一个随机初始化的分类头(见上图b)。

在这里插入图片描述

2.4 Lora

  todo ..

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

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

相关文章

Docker存储目录问题,如何修改Docker默认存储位置?(Docker存储路径、Docker存储空间)etc/docker/daemon.json

文章目录 如何更改docker默认存储路径?版本1(没测试)版本2(可行)1. 停止 Docker 服务:2. 创建新的存储目录:3. 修改 Docker 配置文件:4. 移动现有的 Docker 数据:5. 重新…

Uniapp自定义动态加载组件(2024.7更新)

1.本次介绍如何使用uniapp实现自定义动态加载Loading的组件,可以gif格式,也可以mp4格式等; 编写自定义Loading组件(CustomLoader.vue);组件中含有“动态接收图片路径”,“10秒超时未false则自动断开关闭Loading”;在全…

【JavaScript 算法】广度优先搜索:层层推进的搜索策略

🔥 个人主页:空白诗 文章目录 一、算法原理二、算法实现三、应用场景四、优化与扩展五、总结 广度优先搜索(Breadth-First Search, BFS)是一种用于遍历或搜索图或树数据结构的算法。该算法从起始节点开始,逐层向外扩展…

小程序-2(WXML数据模板+WXSS模板样式+网络数据请求)

目录 1.WXML数据模板 数据绑定 事件绑定 小程序中常用的事件 事件对象的属性列表 target和currentTarget的区别 bindtap的语法格式 在事件处理事件中为data中的数据赋值 事件传参与数据同步 事件传参 bindinput的语法绑定事件 文本框和data的数据同步 条件渲染 w…

SpringCloud | 单体商城项目拆分(微服务)

为什么要进行微服务拆分? 在平常的商城项目中,我们一般的项目结构模块都是将各种业务放在同一个项目文件夹,比如像: 用户,购物车,商品,订单,支付等业务都是放在一起,这样…

线上观看 3 万+!「智能运维MeetUp」精彩回顾,探讨智能体构建新方向

龙蜥社区“走进系列”第 11 期走进中兴通讯-智能可观测运维技术 MeetUp 于成都圆满结束,由中兴通讯联合龙蜥社区系统运维联盟(SOMA)(以下简称“联盟”)共同举办。本次活动现场汇聚了阿里云、谐云科技、乘云数字、中兴通…

MySQL数据库day7.11

一,SQL概述 1.1 SQL语句语法 MySQL 数据库的 SQL 语句不区分大小写,关键字建议使用大写, 以分号结尾。例如: SELECT * FROM user; 使用 /**/ 、 -- 、 # 的方式完成注释 /* 多行注释 */ -- 单行注释 # 单行注释 SELECT * FRO…

计算机硬件---如何更新自己电脑的BLOS

1找官网 例如“我使用的是HP(惠普)品牌的电脑”我只需要在浏览器上搜索“惠普官网”或“惠普-blos更新” 就可以看到,来自官网中更新blos的信息 2.有些品牌要查序列号该怎么办呢? 有许多方法可以查询,例如&#xf…

android13 frameworks里面常用的保存信息或者版本判断的方法

总纲 android13 rom 开发总纲说明 目录 1.前言 2. 数据库 2.1 代码读取用法参考 3.prop 属性配置 3.1 property的key值有哪些特点 4.区别 5. 其他数据存储 6.彩蛋 1.前言 frameworks 不像我们一般开发app那样,很多应用保存的方法都无法使用。这里记录我们系统rom开…

关于java的反射

❓❓❓反射是啥呀相信许多学java的同学非常困惑在学的时候,总是感觉懂了却又没懂或者直接忽略过去了,那么本文就带大家探讨一下什么是反射在java中以及它的机制和运用。 ⭐️什么是反射: 首先我们知道一些知识: 维基百科的解释 …

springboot项目 导入 maven坐标 错误 Could not transfer artifact XXX

1.报错原因 当时导入的是 redis坐标 ,导入jar 包报错(当时是网速太慢了,一直卡着不动 就关了 idea 重新下载)结果报错 之前的redis 项目都可以的,网上找了一下 都没解决 2.解决办法 既然说不能传输, 就说…

有用的工具

一、appuploader Appuploader home -- A tool improve ios develop efficiency such as submit ipa to appstore and manage ios certificate这是一款p12证书查看的工具, 需要建立一个apple ID专用密码:Manage your Apple ID

redis其他类型和配置文件

很多博客只讲了五大基本类型,确实,是最常用的,而且百分之九十的程序员对于Redis只限于了解String这种最常用的。但是我个人认为,既然Redis官方提供了其他的数据类型,肯定是有相应的考量的,在某些特殊的业务…

C++相关概念和易错语法(22)(final、纯虚函数、继承多态难点)

1.final final在继承和多态中都可以使用,在继承中是指不想将自己被继承,在多态中是指不想该函数被重写,比较简单,下面是一些使用例子。 2.纯虚函数 当我们需要抽象一个类的时候,我们就需要用到纯虚函数。所谓抽象的类…

如何设计统计量及相关假设检验

一、如何设置H0和H1假设 谁做H0,谁做H1,在统计学的假设检验里是有约定俗成的规定的。即:status quo(默认/现状)是H0,而新观点或试图challenge现状的是H1。H1也叫research hypothesis,所以我们做…

【多个Python版本存在,使用pip+不同版本安装库时,windows弹出打开方式窗口的解决方法】

问题描述 电脑上存在python3.9,3.10,3.11,安装顺序也是先安装3.9,然后3.10,最后3.11,那么直接使用pip安装,会装在3.11的位置,经过搜索可以通过pip版本,比如pip3.9 insta…

如何在勒索软件攻击中幸存下来:最佳备份实践、勒索拦截方案

无论身处什么业务或行业,数据都是您业务的关键资产。没有针对数据进行安全可靠的备份保护,您将会受到许多“可能性”的威胁,无论数据丢失是由于在键盘上洒了饮料还是遭受到了勒索软件的攻击。 为了确保业务不被中断,企业数据不会…

Python: 初识Python

文章目录 1. Python的背景知识1.1 Python是咋来的?1.2 Python的特点1.3 Python能干啥?1.4 Python的缺点 2. 搭建Python环境2.1 安装Python2.2 安装PyCharm2.3 用pycharm编写python程序 1. Python的背景知识 1.1 Python是咋来的? 由Guido van Rossum于1989年圣诞节为打发无…

一个用于管理多个 Node.js 版本的安装和切换开源工具

大家好,今天给大家分享一个用于管理多个Node.js版本的工具 NVM(Node Version Manager),它允许开发者在同一台机器上安装和使用不同版本的Node.js,解决了版本兼容性问题,为开发者提供了极大的便利。 在开发环…

路网双线合并单线——ArcGISpro 解决方法

路网双线合并成单线是一个在地图制作、交通规划以及GIS分析中常见的需求。双线路网定义:具有不同流向、不同平面结构的道路。此外,车道数较多的道路(例如,双黄实线车道数大于4的道路)也可以视为双线路网,本…