大模型高效微调工具 Hugging Face PEFT

概述

HF PEFT是一个为大型预训练模型提供高效微调方法的Python库。它通过采用训练少量提示参数或使用低秩适应等重新参数化方法,减少微调时训练参数的数量。本文主要介绍了PEFT库的内容、与Transformers的集成、核心知识点如AutoPeftModels、PeftConfig、PeftType和TaskType,以及LoRA在文本生成和语音识别任务中的实战应用。

Hugging Face PEFT快速入门

PEFT库是什么?

PEFT 是一个为大型预训练模型提供多种高效微调方法的Python库。
微调传统范式是针对每个下游任务微调模型参数。大模型参数总量庞大,这种方式变得极其昂贵和不切实际。PEFT采用的高效做法是训练少量提示参数(Prompt Tuning)或使用低秩适应(LORA)等重新参数化方法来减少微调时训练参数的数量。

Hugging Face PEFT 库支持的模型和微调方法

选择这个不同的task,对应不同的任务。不同的下游任务,会有不同的模型来支持该下游任务。然后不同的模型内又存在各种各样的PEFT等高效微调的方法。
PEFT methonds
图示 PEFT methonds,来源于HuggingFace官网

PEFT与Transformers结合

既然PEFT是一个单独的Python库,如何与Transformers进行结合呢?
Transformer 预训练模型常见分类
图1 Transformer 预训练模型常见分类
由于现阶段的大模型几乎都是基于预训练的transformers,包括BERT、GPT、T5等预训练的transformer。
那这些神经网络最终怎么样落实到实际可用的代码里呢?
Transformers AutoModel 常见模型
图2 Transformers AutoModel 常见模型
底层依赖TensorFlow、Pytorch等等,高层次抽象则依赖transformers库内一些特定的抽象方法,例如AutoModel。AutoModel常见模型包括AutoModelForMaskedLM、AutoModelForCausalLM和AutoModelForSeq2SeqLM。

PEFT核心类定义与功能说明

Transformers Auto Classes 设计

AutoClasses 旨在通过全局统一的接口 from_pretrained() ,实现基于名称(路径)自动检索预训练权重(模型)、配置文件、词汇表等所有与模型相关的抽象。
Auto Class
图示 Auto Class
在transformers内需要做好模型抽象最重要的三个要素,即auto config、auto tokenizer和auto model。

PEFT AutoPeftModels与Adapters设计

AutoPeftModel通过从配置文件中自动推断任务类型来加载适当的PEFT模型。旨在以一行代码便捷加载一个PEFT模型,而无需担心需要哪个确切的模型、类或手动加载 PeftConfig。简单来说,它既保留了原来transformers里面对大模型的预训练的一套技术路线,比如统一接口、自动检索等。同时,它又不简简单单是一个代表模型,它还能接受这个PEFT,以及各种各样PEFT方法。
PEFT三类方法
图示 市场上主流的PEFT三类方法
目前市面上比较主流的一些PEFT方法主要包括三类,一类是adapter,即适配器;第二类是prefix-tuning为主的Soft Prompt方法;还有一类就是非常通用的LoRA。
根据Auto Class的三件套,即Auto Model、Auto Config和Auto Tokenizer。无论是经典大模型,还是PEFT等演变的模型,其输入端都是直接继承原始设计Auto Tokenizer;将原始的AutoModel变成AutoPeftModel;剩下部分继续沿用Auto Config的最初设计。因此,所有的adapters都可以沿用Auto Config的继承关系。

PEFT类型配置与PeftModel实例化

实例化
怎么样加载适配器?这个PEFT Config也设计有三类不同的抽象,即prompt learning config、PeftConfigMixin和PeftConfig。

  • PromptLearningConfig:基础的类型。PEFT有两大类方法,一类是LoRA ,另一类为Soft Prompt的方法。由于所有Soft Prompt方法都需要有一个基础类型,这个基础类型在PEFT库里就称为PromptLearningConfig。
  • PeftConfig:PeftConfig作为一个基类,具有两个重要参数,即peft_type,task_type。
  • PeftConfigMixin:PeftConfigMixin内置了很多配置,会与HuggingFace HUB做一些交互以及自定义功能插件等等。

PeftType | TaskType

整个流程可以理解为,task_type和peft_type能够自动检索出来下游任务,明确所需要使用的模型,然后这些模型会自动的去找所需要的一些配置config,从而简化问题的复杂性。
PEFT 无缝对接 Transformers Trainer 训练模型
图示 PEFT 无缝对接 Transformers Trainer 训练模型
Transformers trainer来训练模型,需要具备几个要素:第一,输入,即明确数据要在什么模型上训练;第二,训练参数;第三,数据。

实战PEFT库模型微调多种下游任务

LORA 低秩适配 OPT-6.7B 文本生成任务

PEFT 库微调工作原理与最佳实践(以 LORA 为例)
LoraModel
在 peft 中使用 LORA 非常简捷,借助 PeftModel 抽象,我们可以快速使用低秩适配器(LORA)到任意模型。通过使用 peft 中的 get_peft_model 工具函数来实现。

python">#从peft库导入Loraconfig和get peft model函数
from peft import LoraConfig,get_peft_model
#创建-个LoraConfig对象,用于设置LoRA(Low-Rank Adaptation)的配置参数
config = LoraConfig(r=8, # LORA的秩,影响LORA矩阵的大小lora_alpha=32,#LORA适应的比例因子#指定将LORA应用到的模型模块,通常是attention和全连接层的投影target_modules = ["q_proj","k_proj","v_proj", "out _proj","fc_in", "fc _out"],lora_dropout=0.05,# 在LORA模块中使用的dropout率bias="none",# 设置bias的使用方式,这里没有使用biastask_type="CAUSAL_LM" # 任务类型,这里设置为因果(自回归)语言模型
)    # 使用get_peft_model函数和给定的配置来获取一个PEFT模型
model = get_peft_model(model,config)# 打印出模型中可训练的参数
model.print_trainable_parameters()       

完整示例如下

如何使用最新的peft库和bitsandbytes来以8-bits加载大语言模型,并对其进行高效微调。
微调方法将依赖于一种名为“低秩适配器”(LoRA)的方法,与其说微调整个模型,不如理解为只需要微调这些适配器(Adapter)并在模型中正确加载它们。

1. 加载模型

加载Facebook opt-6.7b 模型,半精度(float16)模型权重大约需要13GB左右显存,而以以8-bits 加载,只需要大约7GB左右显存。

python">import osimport torch
import torch.nn as nn
import bitsandbytes as bnb
from transformers import GPT2Tokenizer, AutoConfig, OPTForCausalLMmodel_id = "facebook/opt-6.7b"model = OPTForCausalLM.from_pretrained(model_id, load_in_8bit=True)tokenizer = GPT2Tokenizer.from_pretrained(model_id)

2. PEFT 微调前的模型处理

在使用 peft 训练 int8 模型之前,需要进行一些预处理:

  • 将所有非 int8 模块转换为全精度(fp32)以保证稳定性;
  • 为输入嵌入层添加一个 forward_hook,以启用输入隐藏状态的梯度计算
  • 启用梯度检查点以实现更高效的内存训练

使用 peft 库预定义的工具函数 prepare_model_for_int8_training,便可自动完成以上模型处理工作。

python">from peft import prepare_model_for_int8_trainingmodel = prepare_model_for_int8_training(model)
python"># 获取当前模型占用的 GPU显存(差值为预留给 PyTorch 的显存)
memory_footprint_bytes = model.get_memory_footprint()
memory_footprint_mib = memory_footprint_bytes / (1024 ** 3)  # 转换为 GBprint(f"{memory_footprint_mib:.2f}GB")

输入模型为:
输出就结果

3. LoRA Adapter 配置

在 peft 中使用LoRA非常简捷,借助PeftModel抽象,我们可以快速使用低秩适配器(LoRA)到任意模型。通过使用 peft 中的 get_peft_model 工具函数来实现。

python"># 从peft库导入LoraConfig和get_peft_model函数
from peft import LoraConfig, get_peft_model# 创建一个LoraConfig对象,用于设置LoRA(Low-Rank Adaptation)的配置参数
config = LoraConfig(r=8,  # LoRA的秩,影响LoRA矩阵的大小lora_alpha=32,  # LoRA适应的比例因子# 指定将LoRA应用到的模型模块,通常是attention和全连接层的投影target_modules = ["q_proj", "k_proj", "v_proj", "out_proj", "fc_in", "fc_out"],lora_dropout=0.05,  # 在LoRA模块中使用的dropout率bias="none",  # 设置bias的使用方式,这里没有使用biastask_type="CAUSAL_LM"  # 任务类型,这里设置为因果(自回归)语言模型
)# 使用get_peft_model函数和给定的配置来获取一个PEFT模型
model = get_peft_model(model, config)# 打印出模型中可训练的参数
model.print_trainable_parameters()

打印待训练模型参数的实现逻辑:

python">def print_trainable_parameters(self,):"""Prints the number of trainable parameters in the model."""trainable_params = 0all_param = 0for _, param in model.named_parameters():all_param += param.numel()if param.requires_grad:trainable_params += param.numel()print(f"trainable params: {trainable_params} || all params: {all_param} || trainable%: {100 * trainable_params / all_param}")

4. 数据处理

python">from datasets import load_datasetdataset = load_dataset("Abirate/english_quotes")

输出结果

python">from datasets import ClassLabel, Sequence
import random
import pandas as pd
from IPython.display import display, HTMLdef show_random_elements(dataset, num_examples=10):assert num_examples <= len(dataset), "Can't pick more elements than there are in the dataset."picks = []for _ in range(num_examples):pick = random.randint(0, len(dataset)-1)while pick in picks:pick = random.randint(0, len(dataset)-1)picks.append(pick)df = pd.DataFrame(dataset[picks])for column, typ in dataset.features.items():if isinstance(typ, ClassLabel):df[column] = df[column].transform(lambda i: typ.names[i])elif isinstance(typ, Sequence) and isinstance(typ.feature, ClassLabel):df[column] = df[column].transform(lambda x: [typ.feature.names[i] for i in x])display(HTML(df.to_html()))show_random_elements(dataset["train"])

输出结果

python">tokenized_dataset = dataset.map(lambda samples: tokenizer(samples["quote"]), batched=True)
python">from transformers import DataCollatorForLanguageModeling# 数据收集器,用于处理语言模型的数据,这里设置为不使用掩码语言模型(MLM)
data_collator = DataCollatorForLanguageModeling(tokenizer, mlm=False)

5. 微调模型

python">from transformers import TrainingArguments, Trainermodel_dir = "models"training_args = TrainingArguments(output_dir=f"{model_dir}/{model_id}-lora",  # 指定模型输出和保存的目录per_device_train_batch_size=4,  # 每个设备上的训练批量大小learning_rate=2e-4,  # 学习率fp16=True,  # 启用混合精度训练,可以提高训练速度,同时减少内存使用logging_steps=20,  # 指定日志记录的步长,用于跟踪训练进度max_steps=100, # 最大训练步长# num_train_epochs=1  # 训练的总轮数)

添加 LoRA 模块后的模型如下
添加 LoRA 模块后的模型

python">trainer = Trainer(model=model,  # 指定训练时使用的模型train_dataset=tokenized_dataset["train"],  # 指定训练数据集args=training_args,data_collator=data_collator
)
python">model.use_cache = False
trainer.train()

输出结果

6. 保存 LoRA 模型

python">model_path = f"{model_dir}/{model_id}-lora-int8"#trainer.save_model(model_path)
model.save_pretrained(model_path)

7. 使用 LoRA 模型

python">lora_model = trainer.model
text = "Two things are infinite: "
inputs = tokenizer(text, return_tensors="pt").to(0)out = lora_model.generate(**inputs, max_new_tokens=48)
print(tokenizer.decode(out[0], skip_special_tokens=True))

输出结果
通过在 english_quotes 数据集上的少量微调(100 steps,不到1个epoch),LoRA 适配器恢复了阿尔伯特·爱因斯坦的名言警句。

LORA 低秩适配 OpenAI Whisper-Large-V2 语音识别任务

使用 LoRA 在OpenAI Whisper-large-v2模型上实现语音识别(ASR)任务的微调训练。此外,还可以结合int8量化进一步降低训练过程资源开销,同时保证了精度几乎不受影响。
原理图
图示: 实现原理图
完整的训练流程

  • 全局参数设置
  • 数据准备
    • 下载数据集:训练、验证和评估集
    • 预处理数据:降采样、移除不必要字段等
    • 数据抽样
    • 应用数据集处理(Dataset.map)
    • 自定义语音数据处理器
  • 模型准备
    • 加载和处理 int8 精度 Whisper-Large-v2 模型
    • LoRA Adapter 参数配置
    • 实例化 PEFT Model:peft_model = get_peft_model(model, config)
  • 模型训练
    • 训练参数配置Seq2SeqTrainingArguments
    • 实例化训练器Seq2SeqTrainer
    • 训练模型
    • 保存模型
  • 模型推理
    • 使用PeftModel加载LoRA微调后Whisper模型
    • 使用 Pipeline API 部署微调后Whisper实现中文语音识别任务

1. 全局参数设置

python">model_name_or_path = "openai/whisper-large-v2"
model_dir = "models/whisper-large-v2-asr-int8"language = "Chinese (China)"
language_abbr = "zh-CN"
task = "transcribe"
dataset_name = "mozilla-foundation/common_voice_11_0"batch_size=64

2. 数据准备

下载数据集 Common Voice,Common Voice 11.0 数据集包含许多不同语言的录音,总时长达数小时。
首先,初始化一个DatasetDict结构,并将训练集(将训练+验证拆分为训练集)和测试集拆分好,按照中文数据集构建配置加载到内存中:

python">from datasets import load_dataset, DatasetDictcommon_voice = DatasetDict()common_voice["train"] = load_dataset(dataset_name, language_abbr, split="train", trust_remote_code=True)
common_voice["validation"] = load_dataset(dataset_name, language_abbr, split="validation", trust_remote_code=True)common_voice["train"][0]

输出结果
预处理训练数据集

python">from transformers import AutoFeatureExtractor, AutoTokenizer, AutoProcessor# 从预训练模型加载特征提取器
feature_extractor = AutoFeatureExtractor.from_pretrained(model_name_or_path)# 从预训练模型加载分词器,可以指定语言和任务以获得最适合特定需求的分词器配置
tokenizer = AutoTokenizer.from_pretrained(model_name_or_path, language=language, task=task)# 从预训练模型加载处理器,处理器通常结合了特征提取器和分词器,为特定任务提供一站式的数据预处理
processor = AutoProcessor.from_pretrained(model_name_or_path, language=language, task=task)# 移除数据集中不必要的字段
common_voice = common_voice.remove_columns(["accent", "age", "client_id", "down_votes", "gender", "locale", "path", "segment", "up_votes"]
)

输出结果
降采样音频数据
对48kHz采样率进行采样的输入音频进行降采样以匹配模型预训练时使用的16kHZ采样率,因为Whisper模型是在16kHZ的音频输入上预训练。通过在音频列上使用cast_column方法,并将sampling_rate设置为16kHz来对音频进行降采样。下次调用时,音频输入将实时重新取样:

python">from datasets import Audiocommon_voice = common_voice.cast_column("audio", Audio(sampling_rate=16000))# sampling_rate 从 48KHZ 降为 16KHZ
common_voice["train"][0]

整合以上数据处理为一个函数
该数据预处理函数应该包括:

  • 通过加载音频列将音频输入重新采样为16kHZ。
  • 使用特征提取器从音频数组计算输入特征。
  • 将句子列标记化为输入标签。
python">def prepare_dataset(batch):audio = batch["audio"]batch["input_features"] = feature_extractor(audio["array"], sampling_rate=audio["sampling_rate"]).input_features[0]batch["labels"] = tokenizer(batch["sentence"]).input_idsreturn batch

数据抽样: 在 Whisper-Large-v2 上使用小规模数据进行演示训练,保持以下训练参数不变(batch_size=64)。使用 640 个样本训练,320个样本验证和评估,恰好使得1个 epoch 仅需10 steps 即可完成训练。

python">small_common_voice = DatasetDict()small_common_voice["train"] = common_voice["train"].shuffle(seed=16).select(range(640))
small_common_voice["validation"] = common_voice["validation"].shuffle(seed=16).select(range(320))

如果全量训练,则使用完整数据代替抽样。

python"># 抽样数据处理
tokenized_common_voice = small_common_voice.map(prepare_dataset)# 完整数据训练,尝试开启 `num_proc=8` 参数多进程并行处理(如阻塞无法运行,则不使用此参数)
tokenized_common_voice = common_voice.map(prepare_dataset, num_proc=8)

自定义语音数据整理器:定义了一个针对语音到文本(Seq2Seq)模型的自定义数据整理器类,特别适用于输入为语音特征、输出为文本序列的数据集。这个整理器(DataCollatorSpeechSeq2SeqWithPadding)旨在将数据点批量打包,将每个批次中的attention_mask填充到最大长度,以保持批处理中张量形状的一致性,并用-100替换填充值,以便在损失函数中被忽略。这对于神经网络的高效训练至关重要。

python">import torchfrom dataclasses import dataclass
from typing import Any, Dict, List, Union# 定义一个针对语音到文本任务的数据整理器类
@dataclass
class DataCollatorSpeechSeq2SeqWithPadding:processor: Any  # 处理器结合了特征提取器和分词器# 整理器函数,将特征列表处理成一个批次def __call__(self, features: List[Dict[str, Union[List[int], torch.Tensor]]]) -> Dict[str, torch.Tensor]:# 从特征列表中提取输入特征,并填充以使它们具有相同的形状input_features = [{"input_features": feature["input_features"]} for feature in features]batch = self.processor.feature_extractor.pad(input_features, return_tensors="pt")# 从特征列表中提取标签特征(文本令牌),并进行填充label_features = [{"input_ids": feature["labels"]} for feature in features]labels_batch = self.processor.tokenizer.pad(label_features, return_tensors="pt")# 使用-100替换标签中的填充区域,-100通常用于在损失计算中忽略填充令牌labels = labels_batch["input_ids"].masked_fill(labels_batch.attention_mask.ne(1), -100)# 如果批次中的所有序列都以句子开始令牌开头,则移除它if (labels[:, 0] == self.processor.tokenizer.bos_token_id).all().cpu().item():labels = labels[:, 1:]# 将处理过的标签添加到批次中batch["labels"] = labelsreturn batch  # 返回最终的批次,准备好进行训练或评估# 用给定的处理器实例化数据整理器
data_collator = DataCollatorSpeechSeq2SeqWithPadding(processor=processor)

3. 模型准备

加载预训练模型(int8 精度):使用 int8 精度加载预训练模型,进一步降低显存需求。

python">from transformers import AutoModelForSpeechSeq2Seqmodel = AutoModelForSpeechSeq2Seq.from_pretrained(model_name_or_path, load_in_8bit=True, device_map="auto")# 设置模型配置中的forced_decoder_ids属性为None
model.config.forced_decoder_ids = None  # 这通常用于指定在解码(生成文本)过程中必须使用的特定token的ID,设置为None表示没有这样的强制要求# 设置模型配置中的suppress_tokens列表为空
model.config.suppress_tokens = []  # 这用于指定在生成过程中应被抑制(不生成)的token的列表,设置为空列表表示没有要抑制的token

**PEFT 微调前的模型处理:**在使用 peft 训练 int8 模型之前,需要进行一些预处理:

  • 将所有非 int8 精度模块转换为全精度(fp32)以保证稳定性
  • 为输入嵌入层添加一个 forward_hook,以启用输入隐藏状态的梯度计算
  • 启用梯度检查点以实现更高效的内存训练

使用 peft 库预定义的工具函数 prepare_model_for_int8_training,便可自动完成以上模型处理工作。

python">from peft import prepare_model_for_int8_trainingmodel = prepare_model_for_int8_training(model)

LoRA Adapter 配置:在 peft 中使用LoRA非常简捷,借助 PeftModel抽象,可以快速使用低秩适配器(LoRA)到任意模型。通过使用 peft 中的 get_peft_model 工具函数来实现。

python">from peft import LoraConfig, PeftModel, LoraModel, LoraConfig, get_peft_model# 创建一个LoraConfig对象,用于设置LoRA(Low-Rank Adaptation)的配置参数
config = LoraConfig(r=4,  # LoRA的秩,影响LoRA矩阵的大小lora_alpha=64,  # LoRA适应的比例因子# 指定将LoRA应用到的模型模块,通常是attention和全连接层的投影。target_modules=["q_proj", "v_proj"],lora_dropout=0.05,  # 在LoRA模块中使用的dropout率bias="none",  # 设置bias的使用方式,这里没有使用bias
)# 使用get_peft_model函数和给定的配置来获取一个PEFT模型
peft_model = get_peft_model(model, config)# 打印 LoRA 微调训练的模型参数
peft_model.print_trainable_parameters()

4. 模型训练

Seq2SeqTrainingArguments训练参数:关于设置训练步数和评估步数

基于 epochs 设置:
num_train_epochs=3, # 训练的总轮数
evaluation_strategy=“epoch”, # 设置评估策略,这里是在每个epoch结束时进行评估
warmup_steps=50, # 在训练初期增加学习率的步数,有助于稳定训练。
基于 steps 设置:
max_steps=100, # 训练总步数
evaluation_strategy=“steps”,
eval_steps=25, # 评估步数

python">from transformers import Seq2SeqTrainingArguments# 设置序列到序列模型训练的参数
training_args = Seq2SeqTrainingArguments(output_dir=model_dir,  # 指定模型输出和保存的目录per_device_train_batch_size=batch_size,  # 每个设备上的训练批量大小learning_rate=1e-3,  # 学习率num_train_epochs=1,  # 训练的总轮数evaluation_strategy="epoch",  # 设置评估策略,这里是在每个epoch结束时进行评估# warmup_steps=50,  # 在训练初期增加学习率的步数,有助于稳定训练# fp16=True,  # 启用混合精度训练,可以提高训练速度,同时减少内存使用per_device_eval_batch_size=batch_size,  # 每个设备上的评估批量大小generation_max_length=128,  # 生成任务的最大长度logging_steps=10,  # 指定日志记录的步骤,用于跟踪训练进度remove_unused_columns=False,  # 是否删除不使用的列,以减少数据处理开销label_names=["labels"],  # 指定标签列的名称,用于训练过程中# evaluation_strategy="steps",# eval_steps=25,
)

实例化 Seq2SeqTrainer 训练器

python">from transformers import Seq2SeqTrainertrainer = Seq2SeqTrainer(args=training_args,model=peft_model,train_dataset=tokenized_common_voice["train"],eval_dataset=tokenized_common_voice["validation"],data_collator=data_collator,tokenizer=processor.feature_extractor,
)
peft_model.config.use_cache = Falsetrainer.train()

5. 保存 LoRA 模型(Adapter)

python">trainer.save_model(model_dir)

训练后的模型如下:
训练后的模型

6. 模型推理

python">model_dir = "models/whisper-large-v2-asr-int8"language = "Chinese (China)"
language_abbr = "zh-CN"
language_decode = "chinese"
task = "transcribe"

使用PeftModel加载 LoRA微调后 Whisper模型:使用PeftConfig加载LoRA Adapter配置参数,使用 PeftModel加载微调后Whisper模型。

python">from transformers import AutoModelForSpeechSeq2Seq, AutoTokenizer, AutoProcessor
from peft import PeftConfig, PeftModelpeft_config = PeftConfig.from_pretrained(model_dir)base_model = AutoModelForSpeechSeq2Seq.from_pretrained(peft_config.base_model_name_or_path, load_in_8bit=True, device_map="auto"
)peft_model = PeftModel.from_pretrained(base_model, model_dir)tokenizer = AutoTokenizer.from_pretrained(peft_config.base_model_name_or_path, language=language, task=task)
processor = AutoProcessor.from_pretrained(peft_config.base_model_name_or_path, language=language, task=task)
feature_extractor = processor.feature_extractor

使用 Pipeline API 部署微调后 Whisper 实现中文语音识别任务

python">test_audio = "data/audio/test_zh.flac"
from transformers import AutomaticSpeechRecognitionPipelinepipeline = AutomaticSpeechRecognitionPipeline(model=peft_model, tokenizer=tokenizer, feature_extractor=feature_extractor)forced_decoder_ids = processor.get_decoder_prompt_ids(language=language_decode, task=task)
python">
import torchwith torch.cuda.amp.autocast():text = pipeline(test_audio, max_new_tokens=255)["text"]

输出结果


http://www.ppmy.cn/server/101735.html

相关文章

Cesium天空盒子(Skybox)制作(js代码)和显示

介绍 在Cesium中&#xff0c;星空背景是通过天空盒子方式&#xff08;6张图片&#xff09;来显示的&#xff0c;原生的图片分辨率太低&#xff0c;本项目用于生成天空盒子的6张图片。最终生成的6个图片大小约为500kb(每个)&#xff0c;格式为jpg&#xff0c;总共的恒星数目约为…

【区块链+金融服务】链上华夏产业互联网平台 | FISCO BCOS应用案例

释放数据要素价值&#xff0c;FISCO BCOS 2024 应用案例征集 链上华夏产业互联网平台以区块链和物联网为基础&#xff0c;打造了银行准入的物流金融服务平台&#xff0c;打通贸易产业链中的 供应商、贸易商、采购商、物流企业、仓储、金融机构等各方&#xff0c;为各方提供一个…

openssl-devel安装出现krb5-libs安装错误的问题

1. 问题&#xff1a;今天在客户提供的机器上部署服务&#xff0c;在使用自建的 yum(自建的源包非常全面&#xff0c;在客户机器成功安装上百次) 源安装 openssl-devel 的过程中&#xff0c;出现了依赖krb5-libs升级安装错误的问题: --> Finished Dependency Resolution Err…

浅谈企业数字化转型的认知、价值及策略

2024年作为不寻常的一年&#xff0c;企业的经营环境发生了显著变化&#xff0c;复杂、不确定、不可预测成为常态。在新常态下&#xff0c;野蛮生长模式转向更务实的精耕细作。 同时&#xff0c;在诸多不确定的因素中&#xff0c;数字化加速推进的趋势是确定无疑的。数字化以前…

高校疫情防控web系统pf

TOC springboot365高校疫情防控web系统pf 第1章 绪论 1.1 课题背景 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播&#xff0c;搭配信息管理工具可以很好地为人们提供服务。所以各行…

git提交规范检查husky

一、Eslint 尤雨溪推荐的 prettierrc 配置&#xff0c;句尾不带分号 单引号。 尤雨溪推荐配置&#xff1a;vue-next/.prettierrc lint lint 是最著名的 C 语言工具之一&#xff0c;是由贝尔实验室 SteveJohnson 于 1979 在 PCC(PortableC Compiler) 基础上开发的静态代码分…

利用Python实现供应链管理中的线性规划与资源优化——手机生产计划2:利润最大化

目录 写在开头1.背景描述2. 模型构建思路3.实现代码3.1 数据准备3.2 进行建模3.3 结果解析 4.代码的优化写在最后 写在开头 在上篇文章中&#xff0c;我们探讨了如何利用生产约束条件实现成本的最小化&#xff0c;这为优化运营奠定了基础。然而&#xff0c;现实世界中的商业环…

同态加密和SEAL库的介绍(十)CKKS 参数心得 2

写在前面&#xff1a; 本篇继续上篇的测试&#xff0c;首先针对密文深度乘法情况&#xff0c;虽然密文乘法本就是应该尽量避免的&#xff08;时间和内存成本过高&#xff09;&#xff0c;更不用说深度乘法了&#xff0c;但是为了测试的完整性&#xff0c;还是做一下方便大家比对…

【JavaEE】深入探索SpringBoot的日志管理功能与实践应用

目录 SpringBoot 日志日志概述日志使用打印日志在程序中得到⽇志对象使用日志对象打印日志 ⽇志框架介绍(了解)⻔⾯模式(外观模式)SLF4J 框架介绍日志格式的说明⽇志级别日志级别的分类日志级别的使用 ⽇志配置配置⽇志级别⽇志持久化配置⽇志⽂件分割配置⽇志格式 更简单的⽇志…

Golang | Leetcode Golang题解之第342题4的幂

题目&#xff1a; 题解&#xff1a; func isPowerOfFour(n int) bool {return n > 0 && n&(n-1) 0 && n%3 1 }

Redis事务实现

Redis事务实现 是一个相对简单但功能强大的机制,它允许用户将多个命令打包在一起,一次性执行。以下是Redis事务实现的简要概述: 一、事务执行步骤 Redis事务的执行主要包含以下三个步骤: 开启事务: 客户端使用MULTI命令显式地开启一个事务。该命令的执行会将后续收到的…

go 反射浅谈

golang 的反射里面&#xff0c;一个实例有两部分&#xff1a;reflect.Type 和 reflect.Value 。reflect.Type 是不可以修改的&#xff0c;reflect.Value可以修改的。reflect.Type 可以通过 reflect.Value 得到&#xff0c;但是反过来则不行。我们先看几个例子&#xff0c;分别讲…

rust 编译时报错:type annotations needed for Box

如下图所示&#xff1a; 解决方法&#xff1a; 升级time的版本&#xff1a; cargo update -p time

Spring中AbstractAutowireCapableBeanFactory

AbstractAutowireCapableBeanFactory 是 Spring 框架中的一个抽象类&#xff0c;位于 org.springframework.beans.factory.support 包中。它实现了 AutowireCapableBeanFactory 接口&#xff0c;提供了一些通用的方法和逻辑&#xff0c;以支持 Spring 中的自动装配功能。 主要…

Elasticsearch(ES)常用命令

常用运维命令 一、基本命令1.1、查看集群的健康状态1.2、查看节点信息1.3、查看索引列表1.4、创建索引1.5、删除索引1.6、关闭索引1.7、打开索引1.8、查看集群资源使用情况&#xff08;各个节点的状态&#xff0c;包括磁盘&#xff0c;heap&#xff0c;ram的使用情况&#xff0…

进阶岛 - LMDeploy 量化部署进阶实践

一、显存计算方法 InternLM系列模型的显存使用主要2部分构成&#xff1a; 模型权重kv cache 以InternLM2.5-7b-chat为例&#xff0c;它的权重类型是bfloat16&#xff0c;即一个参数占用2字节的浮点数。 具体信息可以查看模型目录下的config.json文件。 因此&#xff0c;对于…

【STM32 FreeRTOS】任务

使用 RTOS 的实时应用程序可以被构建为一组独立的任务。每个任务在自己的上下文中执行&#xff0c;不依赖于系统内的其他任务或 RTOS 调度器本身。在任何时间点&#xff0c;应用程序中只能执行一个任务&#xff0c;实时 RTOS 调度器负责决定所要执行的任务。因此&#xff0c; R…

使用PowerShell自动化Windows系统管理任务

在信息技术快速发展的今天&#xff0c;系统管理的复杂性与日俱增。Windows操作系统作为全球最广泛使用的操作系统之一&#xff0c;各行各业都依赖其稳定性与功能。为了提高工作效率和降低人为错误&#xff0c;系统管理员亟需一种有效的工具来简化日常管理任务。在这方面&#x…

掌控移动安全:深入解析MDM与MAM

标题&#xff1a;掌控移动安全&#xff1a;深入解析MDM与MAM 在数字化时代&#xff0c;移动设备成为企业运营不可或缺的一部分。随之而来的&#xff0c;是对于移动设备管理&#xff08;MDM&#xff09;和移动应用管理&#xff08;MAM&#xff09;的需求日益增长。这两种技术是…

作业帮 TiDB 7.5.x 使用经验

作者&#xff1a; 是我的海 原文来源&#xff1a; https://tidb.net/blog/5f9784d3 近期在使用 TiDB 时遇到的一些小问题的梳理总结&#xff0c;大部分版本都在6.5.6和7.5.2 1、limit 导致的扫描量过大的优化 研发定时任务每天需要扫描大量数据&#xff0c;到时机器网卡被…