參數高效微調PEFT(三)快速入門LoRA、AdaLoRA

參數高效微調PEFT(三)快速入門LoRA、AdaLoRA

  • 我們已經了解了HuggingFace中peft庫的幾種高效微調方法。

參數高效微調PEFT(一)快速入門BitFit、Prompt Tuning、Prefix Tuning

參數高效微調PEFT(二)快速入門P-Tuning、P-Tuning V2

  • 今天我們繼續了解大火的高效微調方法LoRA以及改進的AdaLoRA。
  • 另外,QLoRA是模型量化 (Quantilization) 與LoRA的結合,我們會在后面低精度微調時(微調Chat GLM3的7B模型)進行介紹。
  • 注意:我們到目前都是以單精度FP32加載模型,模型本身占用的顯存大小并沒有改變。

1 LoRA

  • 將小型網絡模塊添加到PLMs中,保持基礎模型保持不變的情況下僅針對每個任務微調這些模塊,可以用于所有任務。
  • 這樣,只需引入和更新少量任務特定的參數,就可以適配下游的任務,大大提高了預訓練模型的實用性。如:Adapter tuning、Prefix tuning、Prompt Tuning等。
  • 這類方法雖然大大減少了內存消耗,但是這些方法存在一些問題。
    • 比如:Adapter tuning引入了推理延時;
    • Prefix tuning或Prompt tuning直接優化Prefix和Prompt是非單調的,比較難收斂,并且消耗了輸入的token。
  • LoRA訓練完成后,可以將兩個低秩矩陣與原始模型中的權重進行合并,合并后的模型與原始模型無異,避免了推理期間Prompt系列方法帶來的額外計算量

1.1 LoRA簡介

  • 論文地址:LORA: LOW-RANK ADAPTATION OF LARGE LANGUAGE MODELS (2106)

  • LORA的核心思想就是通過低秩分解來模擬參數的改變量,從而以極小的參數量來實現大模型的間接訓練。

    • 預訓練模型中存在一個極小的內在維度,這個內在維度是發揮核心作用的地方。
    • 在微調的過程中,權重的更新依然也有如此特點,即也存在一個內在維度 (內在秩)。
  • 如下圖所示,可訓練層維度和預訓練模型層維度一致為d,先將維度d通過全連接層降維至r,再從r通過全連接層映射回d維度。其中,r<<d,r是矩陣的秩,這樣矩陣計算就從 d × d d × d d×d變為 d × r + r × d d × r + r × d d×r+r×d,參數量減少很多。

    • 在下游任務訓練時,固定模型的其他參數,只優化新增的兩個矩陣的權重參數,將PLM跟新增的通路兩部分的結果加起來作為最終的結果(兩邊通路的輸入、輸出維度都是一致的),即 h = W x + B A x h=Wx+BAx h=Wx+BAx
    • 第一個矩陣的A的權重參數會通過高斯函數初始化(注意:A矩陣不能初始化為零矩陣);
    • 第二個矩陣的B的權重參數則會初始化為零矩陣,這樣能保證訓練開始時新增的通路 B A = 0 BA=0 BA=0,從而對模型結果沒有影響。

在這里插入圖片描述

  • 訓練完成后,可以將兩個低秩矩陣與原始模型中的權重進行合并,合并后的模型與原始模型無異,避免了推理期間Prompt系列方法帶來的額外計算量

  • 我們知道Transformer的權重矩陣包括Attention模塊里用于計算query,key,value的Wq、Wk、Wv、多頭attention的Wo以及MLP層的權重矩陣。如下圖,LoRA只應用于Attention模塊中的4種權重矩陣,而且通過消融實驗發現同時調整 Wq 和 Wv 會產生最佳結果。

在這里插入圖片描述

  • 如下圖所示,可以發現保證權重矩陣的種類的數量比起增加隱藏層維度r更為重要,增加r并不一定能覆蓋更加有意義的子空間。

在這里插入圖片描述

  • 通常情況下,r選擇為4,8,16即可,peft庫中默認為8。

在這里插入圖片描述

  • 在眾多數據集上LoRA在只訓練極少量參數的前提下,最終在性能上能和全量微調匹配,甚至在某些任務上優于全量微調。

1.2 LoRA源碼分析

我們在peft庫默認配置下(LoraConfig(task_type=TaskType.CAUSAL_LM)),進行源碼分析。

from peft import LoraConfig, TaskType, get_peft_model
config = LoraConfig(task_type=TaskType.CAUSAL_LM)
model = get_peft_model(model, config)

LoRA的代碼主要分為三個部分:初始化、推理和參數合并。

1.2.1 LoRA初始化分析

我們先看下LoRA初始化,默認設置下,LoRA為線性層class Linear(nn.Linear, LoRALayer)

  • LoRA僅支持nn.Linear、nn.Embedding和nn.Conv2d,微調線性層是常見的做法。

  • 通過MAPPING找到PeftModelForCausalLM進行初始化

# peft\mapping.pydef get_peft_model(model: PreTrainedModel, peft_config: PeftConfig, adapter_name: str = "default") -> PeftModel:......# 1、判斷任務類型 如果不是['SEQ_CLS', 'SEQ_2_SEQ_LM', 'CAUSAL_LM', 'TOKEN_CLS', 'QUESTION_ANS', 'FEATURE_EXTRACTION']里類型 而且 不是prompt_learningif peft_config.task_type not in MODEL_TYPE_TO_PEFT_MODEL_MAPPING.keys() and not peft_config.is_prompt_learning:return PeftModel(model, peft_config, adapter_name=adapter_name)# 2、prompt_learningif peft_config.is_prompt_learning:peft_config = _prepare_prompt_learning_config(peft_config, model_config)# 3、通過mapping找到peft.peft_model.PeftModelForCausalLMreturn MODEL_TYPE_TO_PEFT_MODEL_MAPPING[peft_config.task_type](model, peft_config, adapter_name=adapter_name)
  • 然后我們會進入PeftModelForCausalLM的初始化,此時會調用父類PeftModel的初始化方法
# peft\peft_model.py
class PeftModelForCausalLM(PeftModel):def __init__(self, model, peft_config: PeftConfig, adapter_name="default"):# 調用父類PeftModel的初始化方法super().__init__(model, peft_config, adapter_name)self.base_model_prepare_inputs_for_generation = self.base_model.prepare_inputs_for_generation......
  • 父類PeftModel的初始化中,會進行LoraModel的初始化;在LoraModel中,會進行父類BaseTuner的初始化
# peft\peft_model.py
class PeftModel(PushToHubMixin, torch.nn.Module):def __init__(self, model: PreTrainedModel, peft_config: PeftConfig, adapter_name: str = "default"):super().__init__()self.base_model = modelself.config = getattr(self.base_model, "config", {"model_type": "custom"})self.modules_to_save = Noneself.peft_config = {}self.active_adapter = adapter_nameself.peft_type = peft_config.peft_typeif not peft_config.is_prompt_learning:# 不是prompt_learning,我們進入此分支self.peft_config[adapter_name] = peft_config# 通過PEFT_TYPE_TO_MODEL_MAPPING我們獲取peft.tuners.lora.LoraModel# 然后會進入LoraModel的初始化self.base_model = PEFT_TYPE_TO_MODEL_MAPPING[peft_config.peft_type](self.base_model, self.peft_config, adapter_name)self.set_additional_trainable_modules(peft_config, adapter_name)else:self.add_adapter(adapter_name, peft_config)......# peft\tuners\lora.py
class LoraModel(BaseTuner):def __init__(self, model, config, adapter_name) -> None:# 進行BaseTuner的初始化super().__init__(model, config, adapter_name)    .....    
  • 在父類BaseTuner中,會調用inject_adapter方法。
  • inject_adapter中遍歷每一個key,調用_create_and_replace,
  • target默認為線性層,會調用_create_new_module方法,返回一個new_module,然后將舊的module替換為new_module ,即加了LoRA后的module。
  • create_new_module會進行new_module = Linear(adapter_name, in_features, out_features, bias=bias, **kwargs),即peft\tuners\lora.py中Linear的初始化。
# peft\tuners\tuners_utils.py
class BaseTuner(nn.Module, ABC):def __init__(self, model, peft_config: Union[PeftConfig, dict[str, PeftConfig]], adapter_name: str) -> None:super().__init__()self.model = model......# 會掉用inject_adapter方法self.inject_adapter(self.model, adapter_name)# Copy the peft_config in the injected model.self.model.peft_config = self.peft_config......     # peft\tuners\lora.pydef inject_adapter(self, model: nn.Module, adapter_name: str):peft_config = self.peft_config[adapter_name]is_target_modules_in_base_model = Falsekey_list = [key for key, _ in model.named_modules()]model_config = getattr(model, "config", {"model_type": "custom"})if hasattr(model_config, "to_dict"):model_config = model_config.to_dict()# 獲取高效微調的默認設置項peft_config = self._prepare_adapter_config(peft_config, model_config)# 遍歷每一個keyfor key in key_list:is_target_modules_in_base_model = True# 例如,key= 'transformer.h.0.self_attention.query_key_value'# parent = BloomAttention(#  (query_key_value): Linear(in_features=64, out_features=192, bias=True)#  (dense): Linear(in_features=64, out_features=64, bias=True)#  (attention_dropout): Dropout(p=0.0, inplace=False)# )# target = Linear(in_features=64, out_features=192, bias=True)# target_name = 'query_key_value'parent, target, target_name = _get_submodules(model, key)optionnal_kwargs = {"loaded_in_8bit": getattr(model, "is_loaded_in_8bit", False),"loaded_in_4bit": getattr(model, "is_loaded_in_4bit", False),"current_key": key,}# self._create_and_replace(peft_config, adapter_name, target, target_name, parent, **optionnal_kwargs)......# peft\tuners\lora.pydef _create_and_replace(self,lora_config,adapter_name,target,target_name,parent,**optionnal_kwargs,):......# TODO: better deal with thatif isinstance(target, LoraLayer) and isinstance(target, torch.nn.Conv2d):target.update_layer_conv2d(adapter_name,lora_config.r,lora_config.lora_alpha,lora_config.lora_dropout,lora_config.init_lora_weights,)......else:# target默認為線性層,會進入此分支new_module = self._create_new_module(lora_config, adapter_name, target, **kwargs)   # 此方法會將原始module進行替換,替換為加上lora后的self._replace_module(parent, target_name, new_module, target)                    
# 高效微調的默認設置項
LoraConfig(peft_type=<PeftType.LORA: 'LORA'>           # peft的類型, auto_mapping=None, base_model_name_or_path='', revision=None, task_type=<TaskType.CAUSAL_LM: 'CAUSAL_LM'> # 任務類型, inference_mode=False, r=8                                # 秩大小,一般4,8,16,小數據集一般設置更小的r(1,2), target_modules=['query_key_value'] # 指定應用lora的目標模塊,Bloom模型默認為query_key_value,可以使用正則, lora_alpha=8         # 尺度縮放參數,ΔW按α/r縮放,即scaling[adapter_name]=lora_alpha/r,默認為1, lora_dropout=0.0     # lora層的dropout比率, fan_in_fan_out=False, bias='none'          # 偏差可以是“無”、“全部”或“lora_only”。如果是“all”或“lora_only”,則相應的偏差將在訓練期間更新, modules_to_save=None # 全量微調時,模型的layer名稱, init_lora_weights=True, layers_to_transform=None, layers_pattern=None
)
  • Linear初始化中,重要的代碼就是update_layer

  • update_layer中,就會初始化秩為r的可訓練參數A和B

  • new_module = Linear(in_features=64, out_features=192, bias=True(lora_dropout): ModuleDict((default): Identity())(lora_A): ModuleDict((default): Linear(in_features=64, out_features=8, bias=False))(lora_B): ModuleDict((default): Linear(in_features=8, out_features=192, bias=False))(lora_embedding_A): ParameterDict()(lora_embedding_B): ParameterDict()
    )
    
  • 上面就是Linear初始化后的模塊,即new_module。初始化后,就會將之前的module進行替換。

# 替換前
BloomAttention((query_key_value): Linear(in_features=64, out_features=192, bias=True)(dense): Linear(in_features=64, out_features=64, bias=True)(attention_dropout): Dropout(p=0.0, inplace=False)
)# 通過下面代碼進行替換
# peft\tuners\lora.py中的_create_and_replace方法
new_module = self._create_new_module(lora_config, adapter_name, target, **kwargs)
self._replace_module(parent, target_name, new_module, target)# 替換后
BloomAttention((query_key_value): Linear(in_features=64, out_features=192, bias=True(lora_dropout): ModuleDict((default): Identity())(lora_A): ModuleDict((default): Linear(in_features=64, out_features=8, bias=False))(lora_B): ModuleDict((default): Linear(in_features=8, out_features=192, bias=False))(lora_embedding_A): ParameterDict()(lora_embedding_B): ParameterDict())(dense): Linear(in_features=64, out_features=64, bias=True)(attention_dropout): Dropout(p=0.0, inplace=False)
)
  • 上面就是替換前后BloomAttention模塊的結構。
# peft\tuners\lora.py
class Linear(nn.Linear, LoraLayer):# Lora implemented in a dense layerdef __init__(self,adapter_name: str,in_features: int,out_features: int,r: int = 0,lora_alpha: int = 1,lora_dropout: float = 0.0,fan_in_fan_out: bool = False,  # Set this to True if the layer to replace stores weight like (fan_in, fan_out)is_target_conv_1d_layer: bool = False,**kwargs,):init_lora_weights = kwargs.pop("init_lora_weights", True)nn.Linear.__init__(self, in_features, out_features, **kwargs)LoraLayer.__init__(self, in_features=in_features, out_features=out_features)# Freezing the pre-trained weight matrixself.weight.requires_grad = Falseself.fan_in_fan_out = fan_in_fan_outif fan_in_fan_out:self.weight.data = self.weight.data.Tnn.Linear.reset_parameters(self)# 重要代碼self.update_layer(adapter_name, r, lora_alpha, lora_dropout, init_lora_weights)self.active_adapter = adapter_nameself.is_target_conv_1d_layer = is_target_conv_1d_layer......
 def update_layer(self, adapter_name, r, lora_alpha, lora_dropout, init_lora_weights):self.r[adapter_name] = rself.lora_alpha[adapter_name] = lora_alphaif lora_dropout > 0.0:# dropoutlora_dropout_layer = nn.Dropout(p=lora_dropout)else:# 默認設置lora_dropout_layer = nn.Identity()self.lora_dropout.update(nn.ModuleDict({adapter_name: lora_dropout_layer}))# Actual trainable parametersif r > 0:# 如果秩大于0,就初始化秩為R的可訓練參數A和Bself.lora_A.update(nn.ModuleDict({adapter_name: nn.Linear(self.in_features, r, bias=False)}))self.lora_B.update(nn.ModuleDict({adapter_name: nn.Linear(r, self.out_features, bias=False)}))# 指定lora_alpha參數,用于平衡LORA 和 基礎模型的貢獻# 這里scaling默認為1self.scaling[adapter_name] = lora_alpha / rif init_lora_weights:self.reset_lora_parameters(adapter_name)self.to(self.weight.device)        

1.2.2 前向過程

  • 前向過程中,最終會調用BloomForCausalLM的前向傳播方法。
LoraModel((model): BloomForCausalLM((transformer): BloomModel((word_embeddings): Embedding(250880, 64)(word_embeddings_layernorm): LayerNorm((64,), eps=1e-05, elementwise_affine=True)(h): ModuleList((0-1): 2 x BloomBlock((input_layernorm): LayerNorm((64,), eps=1e-05, elementwise_affine=True)(self_attention): BloomAttention(# 在BloomAttention的query_key_value中,使用LoRA進行微調(query_key_value): Linear(in_features=64, out_features=192, bias=True(lora_dropout): ModuleDict((default): Identity())(lora_A): ModuleDict((default): Linear(in_features=64, out_features=8, bias=False))(lora_B): ModuleDict((default): Linear(in_features=8, out_features=192, bias=False))(lora_embedding_A): ParameterDict()(lora_embedding_B): ParameterDict())(dense): Linear(in_features=64, out_features=64, bias=True)(attention_dropout): Dropout(p=0.0, inplace=False))(post_attention_layernorm): LayerNorm((64,), eps=1e-05, elementwise_affine=True)(mlp): BloomMLP((dense_h_to_4h): Linear(in_features=64, out_features=256, bias=True)(gelu_impl): BloomGelu()(dense_4h_to_h): Linear(in_features=256, out_features=64, bias=True))))(ln_f): LayerNorm((64,), eps=1e-05, elementwise_affine=True))(lm_head): Linear(in_features=64, out_features=250880, bias=False))
)
  • 在BloomAttention中,會調用peft\tuners\lora.py中Linear的前向傳播(如下代碼)。
  • 注意:self.lora_A和self.lora_B類型為ModuleDict,這是因為LoRA有高級用法,我們以后再介紹:
    • 一個主模型,可以使用多個適配器(默認self.active_adapter=default)
    • 可以切換適配器
    • 可以禁用適配器,獲取原始結果
    # peft\tuners\lora.pydef forward(self, x: torch.Tensor):previous_dtype = x.dtypeif self.active_adapter not in self.lora_A.keys():return F.linear(x, transpose(self.weight, self.fan_in_fan_out), bias=self.bias)if self.disable_adapters:if self.r[self.active_adapter] > 0 and self.merged:self.unmerge()result = F.linear(x, transpose(self.weight, self.fan_in_fan_out), bias=self.bias)# 不禁用adapters,且秩r > 0,且不合并   elif self.r[self.active_adapter] > 0 and not self.merged:# 1、result = torch.Size([1, 48, 192])result = F.linear(x, transpose(self.weight, self.fan_in_fan_out), bias=self.bias)x = x.to(self.lora_A[self.active_adapter].weight.dtype)# 2、核心代碼# x = torch.Size([1, 48, 64])# self.lora_A['default'] = Linear(in_features=64, out_features=8, bias=False)# x經過self.lora_A,torch.Size([1, 48, 8])# self.lora_B['default'] = Linear(in_features=8, out_features=192, bias=False)# x經過self.lora_B,torch.Size([1, 48, 192])# 然后result相加合并,即h = Wx + BAxresult += (self.lora_B[self.active_adapter](self.lora_A[self.active_adapter](self.lora_dropout[self.active_adapter](x)))* self.scaling[self.active_adapter])else:result = F.linear(x, transpose(self.weight, self.fan_in_fan_out), bias=self.bias)result = result.to(previous_dtype)return result

1.3 LoRA輕量微調bloom模型

同樣,我們只需要在加載原模型后、配置訓練器前加peft的代碼即可。

from peft import LoraConfig, TaskType, get_peft_modelconfig = LoraConfig(task_type=TaskType.CAUSAL_LM# , target_modules=".*\.1.*query_key_value" 指定要添加LoRA的目標模塊(支持正則)# , modules_to_save=["word_embeddings"] 全量微調時,模型的layer名稱, modules_to_save=None
)model = get_peft_model(model, config)# 打印可訓練參數
model.print_trainable_parameters()trainable params: 786,432 || all params: 346,555,392 || trainable%: 0.22692822508443325
  • 配置訓練器、模型訓練及推理和參數高效微調PEFT(一)快速入門BitFit、Prompt Tuning、Prefix Tuning中2.1一樣。
  • 顯存消耗情況:
(base) root@autodl-container-adbc11ae52-f2ebff02:~# nvidia-smi   
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 525.89.02    Driver Version: 525.89.02    CUDA Version: 12.0     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|                               |                      |               MIG M. |
|===============================+======================+======================|
|   0  NVIDIA GeForce ...  On   | 00000000:41:00.0 Off |                  N/A |
| 35%   59C    P2   143W / 250W |   2810MiB / 11264MiB |     31%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------++-----------------------------------------------------------------------------+
| Processes:                                                                  |
|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
|        ID   ID                                                   Usage      |
|=============================================================================|
+-----------------------------------------------------------------------------+

1.4 模型保存

LoRA訓練完成后,可以將兩個低秩矩陣與原始模型中的權重進行合并,合并后的模型與原始模型無異,避免了推理期間Prompt系列方法帶來的額外計算量

from transformers import AutoModelForCausalLM, AutoTokenizerfrom peft import PeftModel# 1、加載基礎模型
model_path = r'/root/autodl-fs/models/langboat/bloom-389m-zh'model = AutoModelForCausalLM.from_pretrained(model_path, low_cpu_mem_usage=True)
tokenizer = AutoTokenizer.from_pretrained(model_path)# 2、加載PeftModel
p_model = PeftModel.from_pretrained(model, model_id="./chatbot/checkpoint-500/")# 3、模型合并
merge_model = p_model.merge_and_unload()# 4、完整模型保存,此時大小就很大了,下次加載時候可以用AutoModelForCausalLM直接加載
merge_model.save_pretrained("./chatbot/merge_model")

2 AdaLoRA

2.1 AdaLoRA簡介

  • 論文地址:ADAPTIVE BUDGET ALLOCATION FOR PARAMETER EFFICIENT FINE-TUNING(23.03)

  • LoRA可以達到與完全微調幾乎相當的性能,但是也存在一些問題。

    • LoRA需要預先指定每個增量矩陣的本征秩 r 相同,忽略了在微調預訓練模型時,權重矩陣的重要性在不同模塊和層之間存在顯著差異
    • 并且只訓練了Attention,沒有訓練FFN,事實上FFN更重要。
  • 如下圖a所示,將可微調參數全部放在FFN的效果要好于放在attention矩陣中的效果;如下圖b所示,同時微調高層參數的效果會比微調底層參數的效果更好。因此,作者提出了AdaLoRA,它根據權重矩陣的重要性得分,在權重矩陣之間自適應地分配參數預算。

在這里插入圖片描述

  • AdaLORA主要包含兩個模塊:

    • (i) SVD形式參數更新(SVD-based adaptation):直接將增量矩陣Δ參數化為SVD的形式,避免了在訓練過程中進行SVD計算帶來的資源消耗;

    在這里插入圖片描述

    • (ii) 基于重要程度的參數分配(Importance-aware rank allocation): 裁剪一些冗余的奇異值。

      具體原理可以參考:AdaLoRA(Adaptive LoRA)詳解

2.2 AdaLoRA輕量微調bloom模型

  • 這里我們沒有分析AdaLoRA的源碼,直接進行輕量微調,有興趣的可以分析下源碼。

  • 同樣,我們只需要在加載原模型后、配置訓練器前加peft的代碼即可。

from peft import get_peft_model, TaskType, AdaLoraConfigconfig = AdaLoraConfig(task_type=TaskType.CAUSAL_LM, r=8, lora_alpha=8, lora_dropout=0, target_modules=["query_key_value"])model = get_peft_model(model, config)# 打印可訓練參數
model.print_trainable_parameters()trainable params: 1,179,936 || all params: 346,948,920 || trainable%: 0.3400892557901607
  • 配置訓練器、模型訓練及推理和參數高效微調PEFT(一)快速入門BitFit、Prompt Tuning、Prefix Tuning中2.1一樣。
  • 顯存消耗情況:
(base) root@autodl-container-adbc11ae52-f2ebff02:~/autodl-tmp/transformers-code/03-PEFT# nvidia-smi  
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 525.89.02    Driver Version: 525.89.02    CUDA Version: 12.0     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|                               |                      |               MIG M. |
|===============================+======================+======================|
|   0  NVIDIA GeForce ...  On   | 00000000:41:00.0 Off |                  N/A |
| 33%   54C    P2   119W / 250W |   2816MiB / 11264MiB |     32%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------++-----------------------------------------------------------------------------+
| Processes:                                                                  |
|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
|        ID   ID                                                   Usage      |
|=============================================================================|
+-----------------------------------------------------------------------------+

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/19631.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/19631.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/19631.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

MyBatis基礎理解教程,詳細分步基礎查詢表數據練習(通俗易懂、實時更新)

一、MyBatis是什么 MyBatis 是一個持久層框架&#xff0c;簡化JDBC開發&#xff0c;它提供了一個從 Java 應用程序到 SQL 數據庫的橋梁&#xff0c;用于數據的存儲、檢索和映射。MyBatis 支持基本的 SQL 操作、高級映射特性以及與 Maven 等構建工具的集成。 二、持久層是什么…

IDEA增加.gitignore文件后的處理

IDEA增加 .gitignore 文件后&#xff0c;但還是被 git 跟蹤了。 我的文件已經被添加到 .gitignore 中&#xff0c;但仍然被 Git 跟蹤&#xff0c; 文件被修改后commint中就會存在此文件。 原因: 文件已經被提交過了 如果文件在添加到 .gitignore 之前已經被提交到 Git 倉庫中,…

Spring boot集成通義千問大模型

Spring boot集成通義千問大模型 背景 我在用idea進行java開發時發現了通義靈碼這款免費的智能代碼補全插件&#xff0c;用了一段時間了&#xff0c;感覺很不錯。就想著在自己的項目中也能集成通義千問大模型實現智能回答&#xff0c;畢竟對接openai需要解決網絡問題&#xff…

戰略合作 | 竹云賦能雁塔區數字經濟高質量發展

2024年5月30日&#xff0c;由西安市數據局指導&#xff0c;中共西安市雁塔區委、西安市雁塔區人民政府主辦的 “雁塔區企業數字化轉型發展大會” 在西安開幕。 本次活動以“數智雁塔&#xff0c;引領未來”為主題&#xff0c;特邀業內150余位政府、數字化服務企業、傳統行業企…

Kubernetes 之 DaemonSet 基本原理

Kubernetes 之 DaemonSet 基本原理 DaemonSet 定義 DaemonSet 確保全部&#xff08;或者某些&#xff09;節點上運行一個 Pod 的副本。 當有節點加入集群時&#xff0c; 也會為他們新增一個 Pod 。 當有節點從集群移除時&#xff0c;這些 Pod 也會被回收。刪除 DaemonSet 將會…

先導微型數控桌面式加工中心

隨著數控技術、傳感器技術、人工智能等技術的不斷發展&#xff0c;制造業的快速發展和技術的不斷進步&#xff0c;小型五軸加工中心的性能將不斷提升&#xff0c;五軸聯動技術作為解決異性復雜零件高效優質加工問題的重要手段&#xff0c;使其具有更廣泛的應用前景。小型五軸加…

【啟明智顯分享】國產自主ZX7981P Wi-Fi6 5G-CPE開發板有哪些優勢?

在當前競爭激烈的智能設備市場中&#xff0c;高性能與低功耗的開發板已然成為各大產品追求的關鍵優勢。 今天我們從國產自主研發的ZX7981P Wi-Fi6 5G-CPE開發板的特點出發&#xff0c;分析他是否滿足市場追求的特點。 主要特點&#xff1a; 1. 強大配置&#xff0c;穩定可靠 …

5.30 學習總

刷題記錄(Codeforces Round 947 &#xff08;Div. 1 Div. 2&#xff09;B,C題)和Codeforces Round 948 &#xff08;Div. 2&#xff09;B題 一.B. 378QAQ and Mochas Array B. 378QAQ and Mochas Array time limit per test 1 second memory limit per test 256 megabytes in…

長難句5.30

Researchers measured people’s cortisol, which is a stress marker, while they were at work and while they were at home and found it higher at what is supposed to be a place of refuge. 研究人員測量了人們在工作中和在家里的皮質醇(壓力的一種標志)&#xff0c;結…

在 JavaScript 中循環遍歷數組的多種方法

在JavaScript編程中,遍歷數組是一個非常常見的操作。根據不同的需求和JavaScript的不同版本,我們有多種方法來完成這一操作。本文將介紹幾種有效的方法,包括現代的和傳統的方式,同時分析每一種方法的優缺點。 1. 使用 for...of 語法 for...of 是在 ECMAScript 2015(ES6)…

Spring Boot集成statemachine快速入門demo

1.什么是statemachine&#xff1f; Spring Statemachine 是應用程序開發人員在 Spring 應用程序中使用狀態機概念的框架&#xff0c;從設計層面分析&#xff1a;狀態機目的是解決復雜的狀態管理流程&#xff0c;保證程序單一原則和開閉原則&#xff1b;業務角度分析&#xff1…

【面試】什么是Java虛擬機

目錄 1. 說明2. 關鍵點 1. 說明 1.Java虛擬機&#xff08;Java Virtual Machine&#xff0c;簡稱JVM&#xff09;是運行所有Java程序的抽象計算機&#xff0c;是Java語言的運行環境。2.JVM是Java平臺無關性的關鍵&#xff0c;它允許Java程序在任何支持JVM的硬件和操作系統上運…

【大數據面試題】34 手寫一個 Flink SQL 樣例

一步一個腳印,一天一道大數據面試題 博主希望能夠得到大家的點贊收,藏支持!非常感謝~ 點贊,收藏是情分,不點是本分。祝你身體健康,事事順心! 我們來看看 Flink SQL大概流程和樣例: 流程: 1.創建 流處理環境 StreamExecutionEnvironment env 2.創建 表環境 StreamTab…

為啥裝了erlang,還報錯erl: command not found?

轉載說明&#xff1a;如果您喜歡這篇文章并打算轉載它&#xff0c;請私信作者取得授權。感謝您喜愛本文&#xff0c;請文明轉載&#xff0c;謝謝。 問題背景&#xff1a; 在一臺不通外網的服務器上裝rabbitmq&#xff0c;然后在啟動的時候&#xff0c;遇到了報錯 “/usr/lib/…

C#中使用Mapster

Mapster是一個開源的.NET對象映射庫&#xff0c;它提供了一種簡單而強大的方式來處理對象之間的映射。 多個映射框架的性能對比&#xff1a; 第一步安裝Mapster 使用方法 public class Test {public string name { get; set; }public string sex { get; set; }public string…

C語言數據結構(超詳細講解)| 二叉樹的實現

二叉樹 引言 在計算機科學中&#xff0c;數據結構是算法設計的基石&#xff0c;而二叉樹&#xff08;Binary Tree&#xff09;作為一種基礎且廣泛應用的數據結構&#xff0c;具有重要的地位。無論是在數據庫索引、內存管理&#xff0c;還是在編譯器實現中&#xff0c;二叉樹都…

記錄Win11安裝打印機驅動過程

1. 首先下載打印機對應型號的驅動 可以從這里下載&#xff1a;打印機驅動,打印機驅動下載 - 打印機驅動網 2. 下載 3. 打開控制面板-->設備和打印機 找到目標打印機添加設備即可 新增打印紙張尺寸

B站稿件生產平臺高可用建設分享

背景 B站作為國內領先的內容分享平臺&#xff0c;其核心功能之一便是支持UP主們創作并分享各類視頻內容。UP主稿件系統作為B站內容生產的關鍵環節&#xff0c;承擔著從內容創作到發布的全過程管理。為了滿足不同創作者的需求&#xff0c;B站提供了多種投稿渠道&#xff0c;包括…

方差分析的七種類型

方差分析&#xff08;ANOVA&#xff09;是一種用于檢驗兩個以上樣本均數差別的顯著性統計方法。根據不同的研究設計和數據類型&#xff0c;方差分析可以分為以下7種類型。 一、單因素方差分析 ①單因素方差分析說明 單因素方差分析用于研究一個定類數據&#xff08;自變量&am…

【原創教程】MES服務器與成品打標機控制說明

1 實現的功能及應用的場合 MES即制造執行系統(manufacturing execution system,簡稱MES),即在加強MRP計劃的執行功能,把MRP計劃同車間作業現場控制,通過執行系統聯系起來。 MES是一個生產管理智能化的一個系統,是用于生產時記錄數據、產量等信息的智能管理系統。 該項…