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://xiahunao.cn/news/3245204.html

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

相关文章

C++客户端Qt开发——常用控件QWidget

四、常用控件 属性 作用 enabled 设置控件是否可使用.true 表⽰可用,false 表示禁用 geometry 位置和尺寸,包含x,y,width,height四个部分 其中坐标是以⽗元素为参考进行设置的. windowTitle 设置widget标题 windowIcon 设置widget图标 windowO…

Window中 Redis下载安装

Redis7.2.3连接: 我用夸克网盘分享了「redis-windows-7.2.3.zip」,点击链接即可保存。打开「夸克APP」,无需下载在线播放视频,畅享原画5倍速,支持电视投屏。 链接:https://pan.quark.cn/s/4dfb0497707a 在安…

Java读写t5557卡源码

T5557卡是美国Atmel公司生产的多功能非接触式射频卡芯片,属于125KHz的低频卡,在国内有广大的应用市场。该芯片共有330bit(比特)的EPROM(分布为10个区块, 每个区块33bit)。0页的块0是被保留用于设置T5557操作模式的参数配置块。第0页第7块可以作用户数据块…

完善kset_uevent_ops结构体

1、struct kset_uevent_ops 2、实验 #include<linux/module.h> #include<linux/init.h>

win10删除鼠标右键选项-360工具

鼠标右键菜单时&#xff0c;发现里面的选项特别多&#xff0c;找一下属性&#xff0c;半天找不到。删除一些不常用的选项&#xff0c;让右键菜单变得干净整洁。 1、打开360安全卫士&#xff0c;点击功能大全&#xff0c;搜索"右键管理" 2、点击右键管理 3、找到对应的…

SpringCache介绍

SpringCache是Spring提供的缓存框架。提供了基于注解的缓存功能。 SpringCache提供了一层抽象&#xff0c;底层可以切换不同的缓存实现&#xff08;只需要导入不同的Jar包即可&#xff09;&#xff0c;如EHCache&#xff0c;Caffeine&#xff0c;Redis。 2个重要依赖已经导入&a…

C++ 高精度时钟获取当前时间 std::chrono::high_resolution_clock::now

C 高精度时钟获取当前时间 std::chrono::high_resolution_clock::now 1. std::chrono::high_resolution_clock::now1.1. Parameters1.2. Return value1.3. Example 2. std::chrono::milliseconds3. std::chrono::microseconds3.1. Example References 1. std::chrono::high_res…

OpenCV 棋盘格相机标定(保姆版)

目录 一、概述 1.1标定原理 1.2实现步骤 1.3应用场景 二、代码 2.1 cv2.calibrateCamera函数 2.1.1输入参数 2.1.2输出参数 2.2完整代码 三、实现效果 3.1处理图像 3.2内参与畸变系数 一、概述 使用 OpenCV 进行相机标定&#xff0c;通常需要拍摄多张包含棋盘格标定…

第一次参加数学建模竞赛新手小白备赛经验贴

2024年暑假已经来临&#xff0c;下半年的数学建模竞赛非常多&#xff0c;许多同学可能是第一次参赛&#xff0c;对于如何准备感到迷茫和无从下手。在这种情况下&#xff0c;我们将分享一些备赛的小技巧&#xff0c;帮助大家在这个暑假更好的入门&#xff0c;即便是零基础的小白…

Python面试宝典第14题:背包问题

题目 现有编号从 0 到 n - 1 的 n 个背包&#xff0c;给你两个下标从 0 开始的整数数组 capacity 和 rocks 。第 i 个背包最大可以装 capacity[i] 块石头&#xff0c;当前已经装了 rocks[i] 块石头&#xff08;0 < rocks[i] < capacity[i]&#xff09;。另给你一个整数 a…

牛客周赛 Round 51 (C++)

目录 A-小红的同余_牛客周赛 Round 51 (nowcoder.com) 思路&#xff1a; 代码&#xff1a; B-小红的三倍数_牛客周赛 Round 51 (nowcoder.com) 思路&#xff1a; 代码&#xff1a; C-小红充电_牛客周赛 Round 51 (nowcoder.com) 思路&#xff1a; 代码&#xff1a; …

SHOT(方向直方图)

Salti等人在2014年提出一种表面匹配的局部三维描述子SHOT。Salti等人将现有三维局部特征描述方法分为两类&#xff0c;即基于特征的描述方法与基于直方图的描述方法&#xff0c;并分析了两种方法的优势&#xff0c;提出基于特征的局部特征描述方法要比后者在特征的描述能力上更…

基于视觉工具箱和背景差法的行人检测,行走轨迹跟踪,人员行走习惯统计matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 (完整程序运行后无水印) 在三维图中&#xff0c;幅度越大&#xff0c;则表示人员更习惯的行走路线。 2.算法运行软件版本 matlab2022a 3.部分核…

【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第一篇 嵌入式Linux入门篇-第二十九章 NFS服务器的搭建和使用

i.MX8MM处理器采用了先进的14LPCFinFET工艺&#xff0c;提供更快的速度和更高的电源效率;四核Cortex-A53&#xff0c;单核Cortex-M4&#xff0c;多达五个内核 &#xff0c;主频高达1.8GHz&#xff0c;2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT…

VS2022配置Qt环境

文章目录 前言VS2022写Qt的好处下载插件前提条件离线下载在线安装配置VS For Qt 创建项目总结 前言 在许多开发环境中&#xff0c;Visual Studio 2022&#xff08;VS2022&#xff09;和Qt都是非常重要的工具。VS2022是微软开发的一款强大的集成开发环境&#xff08;IDE&#x…

前缀和算法——部分OJ题详解

&#xff08;文章的题目解释可能存在一些问题&#xff0c;欢迎各位小伙伴私信或评论指点&#xff08;双手合十&#xff09;&#xff09; 关于前缀和算法 前缀和算法解决的是“快速得出一个连续区间的和”&#xff0c;以前求区间和的时间复杂度是O(N)&#xff0c;使用前缀和可…

STM32智能农业灌溉系统教程

目录 引言环境准备智能农业灌溉系统基础代码实现&#xff1a;实现智能农业灌溉系统 4.1 数据采集模块 4.2 数据处理与决策模块 4.3 通信与网络系统实现 4.4 用户界面与数据可视化应用场景&#xff1a;农业灌溉管理与优化问题解决方案与优化收尾与总结 1. 引言 智能农业灌溉系…

react基础样式控制

行内样式 <div style{{width:500px, height:300px,background:#ccc,margin:200px auto}}>文本</div> class类名 注意&#xff1a;在react中使用class类名必须使用className 在外部src下新建index.css文件写入你的样式 .fontcolor{color:red } 在用到的页面引入…

基于springboot和mybatis的RealWorld后端项目实战二之实现tag接口

修改pom.xml 新增tag数据表 SET FOREIGN_KEY_CHECKS0;-- ---------------------------- -- Table structure for tags -- ---------------------------- DROP TABLE IF EXISTS tags; CREATE TABLE tags (id bigint(20) NOT NULL AUTO_INCREMENT,name varchar(255) NOT NULL,PR…

IP地址定位与智慧城市和智能交通

智慧城市和智能交通是现代城市发展的关键领域&#xff0c;通过先进技术提升城市管理和居民生活质量。IP地址定位在交通监控、智能路灯管理等方面发挥了重要作用&#xff0c;本文将深入探讨其技术实现及应用。 交通监控与优化 通过IP地址连接交通传感器和摄像头&#xff0c;可…