如何微调 Llama 3 进行序列分类?

节前,我们星球组织了一场算法岗技术&面试讨论会,邀请了一些互联网大厂朋友、参加社招和校招面试的同学.

针对算法岗技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何准备、面试常考点分享等热门话题进行了深入的讨论。

汇总合集:

  • 《大模型面试宝典》(2024版) 发布!
  • 圈粉无数!《PyTorch 实战宝典》火了!!!

大型语言模型以其文本生成能力而闻名。在预训练期间,它们接受了数百万个标记的训练。这将有助于大型语言模型理解英文文本并在生成期间生成有意义的完整标记。

自然语言处理中的另一个常见任务是序列分类任务。在此,我们将给定的序列分类为不同的类别。这可以通过 prompt 使用大型语言模型简单地完成,但这可能只是有时有效。

我们可以调整大型语言模型以针对给定的输入为每个类别输出一组概率。本指南将展示如何训练此类 LLM 并使用微调的 Llama 3 模型。

在这里插入图片描述

导入库

在本指南中,我们将在 Kaggle 中工作。第一步是下载必要的库,我们需要这些库来微调Llama 3进行序列分类。让我们运行以下代码:

!pip install -q transformers accelerate trl bitsandbytes datasets evaluate huggingface-cli 
!pip install -q peft scikit-learn
下载库

我们首先下载以下库:

  • Transformers: 这是来自 HuggingFace 的一个库,我们可以使用它来下载、创建应用程序和微调深度学习模型,包括大型语言模型。
  • 加速: 这又是来自 HuggingFace 的一个库,可以加快在 GPU 上运行的大型语言模型的推理速度。
  • Trl: 这是 HuggingFace 的一个 Python 包,我们可以使用它来微调 HuggingFace 中心上提供的深度学习模型。有了这个 TRL 库,我们甚至可以微调大型语言模型。
  • bitsandbytes: LLM 占用的内存非常高,因此我们可以在低 RAM GPU 中直接使用它们。我们将大型语言模型量化为较低的精度,以便我们能够将它们放入 GPU 中,为此,我们需要 bitsandbytes 库。
  • 数据集: 这是来自 HuggingFace 的 Python 库,我们可以用它下载属于不同深度学习和机器学习类别的各种开源数据集,包括图像分类、文本生成、文本摘要等。
  • 评估: 我们将使用这个库来评估训练前后的模型。
  • Huggingface-cli: 这是必需的,因为我们必须登录 HuggingFace 才能使用 Llama3 模型。
  • peft: 使用我们正在使用的 GPU,不可能训练大型语言模型的所有参数。相反,我们只能训练这些参数的一个子集,这可以使用 peft 库来完成。
  • Scikit-learn: 这个库包含许多不同的机器学习和深度学习工具。我们将使用该库作为误差指标,比较训练前后的大型语言模型。

之后,尝试登录 HuggingFace 中心。为此,我们将使用 huggingface-cli 工具。此代码如下所示:

!huggingface-cli login --token $YOUR_HF_TOKEN
代码解释

在这里,我们使用附加的 – token 选项调用 huggingface-cli 的登录选项。在这里,我们提供 HuggingFace 令牌以登录 HuggingFace。要获取 HuggingFace 令牌,请转到此链接。如下图所示,您可以通过单击“新令牌”或使用现有令牌来创建访问令牌。只需复制该令牌并将其粘贴到 YOUR_HF_TOKEN 位置即可。

在这里插入图片描述

加载数据集

接下来,我们加载数据集进行训练。为此,我们使用以下代码:

from datasets import load_datasetdataset = load_dataset("ag_news")
  • 我们首先从数据集库中导入 load_dataset 函数
  • 然后我们使用数据集名称“ag_news”调用load_dataset函数

运行此命令将把 ag_news 数据集下载到 dataset 变量中。ag_news 数据集如下图所示:

在这里插入图片描述

这是一个新闻分类数据集。新闻分为不同的类别,例如世界、体育、商业和科学/技术。现在,让我们看看每个类别的示例数量是否相等,或者是否存在类别不平衡。

import pandas as pddf = pd.DataFrame(dataset['train'])df.label.value_counts(normalize=True)

在这里插入图片描述

代码解释
  • 这里我们首先导入 pandas 库
  • ag_news 数据集包含训练集和测试集。以及 DatasetDict 类型的数据集变量。为了方便使用,我们将其转换为 pandas DataFrame
  • 然后我们在数据框的“标签”列上调用 value_counts() 函数,并将 normalize 设置为 True

运行此代码会产生以下输出。我们可以检查所有 4 个标签是否具有相同的比例,这意味着每个类别在数据集中都有相同数量的示例。数据集很大,所以我们只需要其中的一部分。因此,我们使用以下代码从此数据框中抽取一些数据:

# Splitting the dataframe into 4 separate dataframes based on the labels
label_1_df = df[df['label'] == 0]
label_2_df = df[df['label'] == 1]
label_3_df = df[df['label'] == 2]
label_4_df = df[df['label'] == 3]# Shuffle each label dataframe
label_1_df = label_1_df.sample(frac=1).reset_index(drop=True)
label_2_df = label_2_df.sample(frac=1).reset_index(drop=True)
label_3_df = label_3_df.sample(frac=1).reset_index(drop=True)
label_4_df = label_4_df.sample(frac=1).reset_index(drop=True)# Splitting each label dataframe into train, test, and validation sets
label_1_train = label_1_df.iloc[:2000]
label_1_test = label_1_df.iloc[2000:2500]
label_1_val = label_1_df.iloc[2500:3000]label_2_train = label_2_df.iloc[:2000]
label_2_test = label_2_df.iloc[2000:2500]
label_2_val = label_2_df.iloc[2500:3000]label_3_train = label_3_df.iloc[:2000]
label_3_test = label_3_df.iloc[2000:2500]
label_3_val = label_3_df.iloc[2500:3000]label_4_train = label_4_df.iloc[:2000]
label_4_test = label_4_df.iloc[2000:2500]
label_4_val = label_4_df.iloc[2500:3000]# Concatenating the splits back together
train_df = pd.concat([label_1_train, label_2_train, label_3_train, label_4_train])
test_df = pd.concat([label_1_test, label_2_test, label_3_test, label_4_test])
val_df = pd.concat([label_1_val, label_2_val, label_3_val, label_4_val])# Shuffle the dataframes to ensure randomness
train_df = train_df.sample(frac=1).reset_index(drop=True)
test_df = test_df.sample(frac=1).reset_index(drop=True)
val_df = val_df.sample(frac=1).reset_index(drop=True)
  • 我们的数据包含 4 个标签。因此,我们创建 4 个数据框,每个数据框由一个标签组成
  • 然后,我们通过调用 sample 函数来打乱每个标签
  • 然后,我们将每个标签数据框分成 3 个部分,分别称为训练、测试和有效数据框。对于训练,我们提供 2000 个标签,对于测试和验证,我们各提供 500 个标签
  • 现在,我们通过 pd.concat() 函数将所有标签的训练数据框合并为一个训练数据框
  • 我们对测试和验证数据框也做了同样的事情
  • 最后,我们再次对 train_df、test_df 和 valid_df 进行混洗,以确保它们的随机性
检查价值很重要

为了确认,让我们检查训练数据框中每个标签的值计数。代码如下:

train_df.label.value_counts()

在这里插入图片描述

Pandas DataFrames 到 DatasetDict

因此,我们可以检查训练数据框是否对四个标签都具有相同的示例。在将它们发送到训练之前,我们需要将这些 Pandas DataFrames 转换为 HuggingFace 训练库接受的 DatasetDict。为此,我们使用以下代码:

from datasets import DatasetDict, Dataset# Converting pandas DataFrames into Hugging Face Dataset objects:
dataset_train = Dataset.from_pandas(train_df)
dataset_val = Dataset.from_pandas(val_df)
dataset_test = Dataset.from_pandas(test_df)# Combine them into a single DatasetDict
dataset = DatasetDict({'train': dataset_train,'val': dataset_val,'test': dataset_test
})
dataset

在这里插入图片描述

代码解释
  • 首先,我们从数据集库中导入 DatasetDict 类
  • 然后我们将 Pandas DataFrames 中的 train_df、test_df 和 val_df 分别转换为 HuggingFace Dataset 类型
  • 最后,我们将所有的train、test、val HuggingFace数据集合并起来,创建最终的DatasetDict类型变量,并将其存储在数据集变量中

从输出中我们可以看到,DatasetDict 包含 3 个数据集,分别是训练、测试和验证数据集。其中每个数据集仅包含 2 列:一列是文本,另一列是标签。

在这里,在我们的数据集中,每个类别的比例是相同的。在实际情况中,这可能只是有时是正确的。因此,当类别不平衡时,我们需要采取适当的措施,以便 LLM 不会更加重视包含更多示例的标签。为此,我们计算类别权重。

类别权重告诉我们必须赋予每个类别多大的重要性;类别权重越大,该类别的重要性就越大。如果我们的数据集不平衡,我们可以为标签提供更多的类别权重,使用更少的示例,从而赋予它更大的重要性。为了获得这些类别权重,我们可以取数据集中类别标签(值计数)比例的倒数。此代码如下:

import torchclass_weights=(1/train_df.label.value_counts(normalize=True).sort_index()).tolist()
class_weights=torch.tensor(class_weights)
class_weights=class_weights/class_weights.sum()
class_weights

在这里插入图片描述

代码解释
  • 因此,我们首先取类标签值计数的倒数
  • 然后,我们将它们从列表类型转换为 torch 张量类型
  • 然后我们通过将 class_weights 除以 class_weights 的总和来对其进行归一化

从输出中我们可以看到,所有类别的类别权重都是相等的;这是因为所有类别都有相同数量的示例。

模型加载-量化

在本节中,我们将下载并准备模型进行训练。首先是下载模型。我们无法使用完整模型,因为我们正在处理一个小型 GPU;因此,我们将对其进行量化。此代码如下:

from transformers import BitsAndBytesConfig, AutoModelForSequenceClassificationquantization_config = BitsAndBytesConfig(load_in_4bit = True, bnb_4bit_quant_type = 'nf4',bnb_4bit_use_double_quant = True, bnb_4bit_compute_dtype = torch.bfloat16 
)model_name = "meta-llama/Meta-Llama-3-8B"model = AutoModelForSequenceClassification.from_pretrained(model_name,quantization_config=quantization_config,num_labels=4,device_map='auto'
)
代码解释
  • 我们从 transformers 库中导入 BitsAndBytesConfig 和 AutoModelForSequenceClassification 类。
  • 我们必须定义量化配置来为模型创建量化。为此,我们将创建一个 BitsAndBytesConfig 实例并为其提供不同的量化参数。
  • load_in_4bit:设置为 True,表示我们希望将模型量化为 4 位精度
  • bnb_4bit_quant_type:这是我们希望使用的量化类型,我们将使用推荐的 Normal Float(又名 NF4)
  • bnb_4bit_compute_dtype:这是执行 GPU 计算的数据类型。这通常是 torch.float32 / torch.float16 / torch.bfloat16,在我们的示例中,基于 GPU,我们使用 torch.bfloat16
  • bnb_4bit_use_double_quant:设置为True时,将通过量化量化常数进一步减少内存占用
  • 接下来,我们为 model_name 变量提供将要微调的模型名称,这里是 Meta 新推出的 Llama 3 8B
  • 然后,我们创建 AutoModelForSequenceClassification 类的实例,并赋予它模型名称和量化配置
  • 我们还使用了另一个名为 num_labels 的变量,并将其设置为 4。AutoModelForSequenceClassification 所做的是删除 Llama 3 LLM 的最后一层,并将其替换为线性层
  • 我们将这个线性层的输出设置为 4;这是因为我们的数据集中有 4 个类标签
  • 最后,我们将 device_map 设置为“auto”,这样模型就可以加载到 GPU

因此,运行上述代码将从 HuggingFace 中心下载 Llama 3 8B 大型语言模型,根据我们为其提供的 quantization_config 对其进行量化,然后将 LLM 的输出头替换为具有 4 个神经元的线性头作为输出,并将模型推送到 GPU。接下来,我们将为模型创建一个 LoRA 配置,以仅训练一部分参数。此代码如下:

LoRA 配置

from peft import LoraConfig, prepare_model_for_kbit_training, get_peft_modellora_config = LoraConfig(r = 16, lora_alpha = 8,target_modules = ['q_proj', 'k_proj', 'v_proj', 'o_proj'],lora_dropout = 0.05, bias = 'none',task_type = 'SEQ_CLS'
)model = prepare_model_for_kbit_training(model)
model = get_peft_model(model, lora_config)
代码解释
  • 我们首先从 peft 库导入 LoraConfig、prepare_model_for_kbit_training 和 get_peft_model
  • 然后,我们实例化一个 LoraConfig 类并赋予它不同的参数,其中包括
  • r:这定义了我们将要训练的参数矩阵的秩。我们将其设置为 16
  • lora_alpha:这是基于 LoRA 的训练的超参数。通常将其设置为 r 值的一半
  • target_modules:这是一个列表,我们指定应该在哪里添加基于 LoRA 的训练。为此,我们选择所有注意层,如 K、Q、V 和输出投影
  • lora_dropout:我们将其设置为 0.05,这将随机丢弃神经元,以避免发生过度拟合
  • bias:如果设置为 true,那么偏差项也会随训练权重一起添加
  • task_type:因为我们正在训练分类数据集,并已将分类层添加到 LLM,所以我们将保留这个“SEQ_CLS”
  • 然后,我们调用 prepare_model_for_kbit_training() 函数,将模型提供给该函数。此函数对量化模型进行预处理以进行训练
  • 最后,我们通过提供模型和 LoraConfig 来调用 get_peft_model() 函数

运行此程序后,get_peft_model 将采用模型并通过包装模型和 LoRA 配置来准备使用PEFT 方法(如本例中的LoRA)进行训练。

模型测试 – 预训练

在本节中,我们将在模型训练之前在测试数据上测试 Llama 3 模型。为此,我们将首先下载标记器。此代码如下:

from transformers import AutoTokenizermodel_name = "meta-llama/Meta-Llama-3-8B"
tokenizer = AutoTokenizer.from_pretrained(model_name, add_prefix_space=True)tokenizer.pad_token_id = tokenizer.eos_token_id
tokenizer.pad_token = tokenizer.eos_token
代码解释
  • 在这里,我们从 transformers 库中导入 AutoTokenizer 类
  • 我们通过调用 AutoTokenizer 类的 from_pretrained() 函数并向其传递模型名称来实例化一个 tokenizer
  • 然后我们将 tokenizer 的 pad_token 设置为 eos_token,pad_token_id 也是如此
model.config.pad_token_id = tokenizer.pad_token_id
model.config.use_cache = False
model.config.pretraining_tp = 1

接下来,我们甚至通过将模型的 pad token ID 设置为 tokenizer 的 pad token ID 来编辑模型配置,并且不使用缓存。现在,我们将测试数据提供给模型并收集输出:

sentences = test_df.text.tolist()batch_size = 32  all_outputs = []for i in range(0, len(sentences), batch_size):batch_sentences = sentences[i:i + batch_size]inputs = tokenizer(batch_sentences, return_tensors="pt", padding=True, truncation=True, max_length=512)inputs = {k: v.to('cuda' if torch.cuda.is_available() else 'cpu') for k, v in inputs.items()}with torch.no_grad():outputs = model(**inputs)all_outputs.append(outputs['logits'])final_outputs = torch.cat(all_outputs, dim=0)
test_df['predictions']=final_outputs.argmax(axis=1).cpu().numpy()
代码解释
  • 首先,我们将测试 DataFrame 的文本列中的元素转换为句子列表,并将其存储在变量 sentence 中。
  • 然后,我们定义一个批次大小来表示一批模型的输入;这里,我们将这个大小设置为 32。
  • 然后,我们创建一个空的 all_outputs 列表来存储模型将生成的输出
  • 我们开始遍历句子变量,将步长设置为我们定义的批量大小。
  • 因此,在每次迭代中,我们都会分批对输入的句子进行标记。
  • 然后,我们将这些标记化的句子移动到运行模型的设备上,可以是 GPU 或 CPU。
  • 最后,我们通过将输入传递给模型并将输出逻辑附加到 all_outputs 列表来执行模型推理。然后我们将所有这些输出连接起来以形成最终的输出张量。

运行此代码会将模型结果存储在一个变量中。我们将这些预测添加到新列中的测试 DataFrame 中。我们取每个输出的 argmax;这为我们提供了 final_outputs 列表中每个输出概率最高的标签。现在,我们需要评估 LLM 生成的输出,我们可以通过以下代码进行评估:

from sklearn.metrics import accuracy_score, confusion_matrix
from sklearn.metrics import balanced_accuracy_score, classification_reportdef get_metrics_result(test_df):y_test = test_df.labely_pred = test_df.predictionsprint("Classification Report:")print(classification_report(y_test, y_pred))print("Balanced Accuracy Score:", balanced_accuracy_score(y_test, y_pred))print("Accuracy Score:", accuracy_score(y_test, y_pred))get_metrics_result(test_df)

在这里插入图片描述

代码解释
  • 我们首先从 sklearn 库导入 accuracy_score、balanced_accuracy_score 和 classification_report。
  • 然后我们定义一个名为 get_metrics_result() 的函数,它接受数据框并输出结果。
  • 在这个函数中,我们首先将预测和实际标签存储在一个变量中。
  • 然后,我们将这些实际值和预测值提供给分类报告、accuracy_score 和 balance_accuracy_score,并打印它们。
  • 处理不平衡数据时,balance_accuracy_score 很有用。

运行该程序产生了以下结果。我们可以看到,我们的准确率为 0.23,这非常低。该模型的准确率、召回率和 f1 分数也非常低;它们甚至没有达到 50% 以上的百分比。在训练模型后对它们进行测试将让我们了解模型的训练效果。

在开始训练之前,我们需要对数据进行预处理,然后再将其发送到模型。为此,我们使用以下代码:

def data_preprocesing(row):return tokenizer(row['text'], truncation=True, max_length=512)tokenized_data = dataset.map(data_preprocesing, batched=True, 
remove_columns=['text'])
tokenized_data.set_format("torch")
代码解释
  • 我们定义一个名为 data_preprocessing() 的函数,它需要一行数据
  • 在其中,我们将该行的文本内容传递给标记器,并将截断设置为 true,最大长度设置为 512 个标记
  • 然后我们创建 tokenized_data,通过将此函数映射到我们创建的数据集,并在映射后删除文本列,因为我们只需要模型期望的标记
  • 最后,我们将这些标记化数据转换为 torch 格式

现在,datasetdict 中的每个数据集都包含三个特征/列,即标签、input_id 和 Attention_masks。使用上述预处理函数为每个文本生成 input_ids 和 Attention_masks。在训练时,我们需要一个数据整理器来批量处理数据。为此,我们使用以下代码:

from transformers import DataCollatorWithPaddingcollate_fn = DataCollatorWithPadding(tokenizer=tokenizer)
  • 在这里,我们从 transformers 库中导入 DataCollat​​orWithPadding 类
  • 然后,我们通过赋予它 tokenizer 来实例化该类
  • 此 collat​​e_fn 将填充输入批次,使其长度等于该批次中的最大输入长度

这将确保批处理中的所有输入具有相同的长度,这对于加快训练速度至关重要。因此,我们使用特殊标记(如填充标记)将输入统一填充到最长序列长度,从而允许同时进行批处理。

Finetune Llama 3:模型训练和训练后评估

在开始训练之前,我们需要一个误差度量来评估它。大型语言模型的默认误差度量是负对数似然损失。但在这里,因为我们正在修改 LLM 以使其成为序列分类工具,所以我们需要重新定义在训练时测试模型所需的误差度量:

def compute_metrics(evaluations):predictions, labels = evaluationspredictions = np.argmax(predictions, axis=1)return {'balanced_accuracy' : balanced_accuracy_score(predictions, labels),'accuracy':accuracy_score(predictions,labels)}
  • 在这里,我们定义一个函数 compute_metrics,它接受一个包含预测和标签的元组
  • 然后,从给定的预测中,我们通过 np.argmax() 函数提取概率最高的索引
  • 最后,我们返回一个包含平衡准确度和原始准确度分数的字典

因为我们要使用自定义指标,所以我们甚至定义了一个自定义训练器来训练我们的 LLM,这是必要的,因为我们在这里使用类权重。为此,代码将是

class CustomTrainer(Trainer):def __init__(self, *args, class_weights=None, **kwargs):super().__init__(*args, **kwargs)if class_weights is not None:self.class_weights = torch.tensor(class_weights, dtype=torch.float32).to(self.args.device)else:self.class_weights = Nonedef compute_loss(self, model, inputs, return_outputs=False):labels = inputs.pop("labels").long()outputs = model(**inputs)logits = outputs.get('logits')if self.class_weights is not None:loss = F.cross_entropy(logits, labels, weight=self.class_weights)else:loss = F.cross_entropy(logits, labels)return (loss, outputs) if return_outputs else loss
代码解释
  • 在这里,我们定义一个自定义训练器类,该类继承自 HuggingFace 的 Trainer 类
  • 此类实现了一个 init 函数,其中我们定义,如果提供了 class_weights,则将 class_weights 分配为实例变量之一,否则将其分配给 None
  • 在分配之前,我们将 class_weights 转换为 torch.tensor,并将 dtype 更改为 float32
  • 然后我们定义 Trainer 类的 compute_loss 函数,这是执行反向传播所必需的
  • 首先,我们从输入中提取标签并将其转换为 long 数据类型
  • 然后我们将输入提供给模型,模型接受这些输入并生成类别的概率;我们从这些输出中获取对数
  • 然后我们调用交叉熵损失,因为我们正在处理多个标签分类,并给它模型输出logits和标签。如果存在类权重,我们甚至会将它们提供给模型
  • 最后我们按要求返回这些损失和输出

训练论点

现在,我们将定义我们的训练参数。代码如下

training_args = TrainiAgrumentsngArguments(output_dir = 'sentiment_classification',learning_rate = 1e-4,per_device_train_batch_size = 8,per_device_eval_batch_size = 8,num_train_epochs = 1,logging_steps=1,weight_decay = 0.01,evaluation_strategy = 'epoch',save_strategy = 'epoch',load_best_model_at_end = True,report_to="none"
)
代码解释
  • 我们实例化 TrainingArguments 类的一个对象。为此,我们传递如下参数
  • output_dir:这是我们想要保存模型的地方。我们可以在这里提供路径
  • learning_rate:这里我们给出训练时应用的学习率
  • per_device_train_batch_size:在这里,我们设置训练时训练数据的批量大小
  • per_device_eval_batch_size; 在这里,我们设置测试/评估数据的评估批次大小
  • num_train_epochs:在这里,我们给出了训练 LLM 所需的训练周期数
  • 日志记录步骤:在这里,我们告诉记录结果的频率
  • weight_decay:权重衰减多少
  • save_strategy:设置为 epoch,表示每个 epoch 都会保存模型权重
  • evaluation_strategy:设置为 epoch,表示每个 epoch 都会对模型进行评估
  • load_best_model_at_end:赋予其 True 值将加载具有最佳参数的模型,从而提供最佳结果

将物体传递给训练员

这将创建我们的 TrainingArguments 对象。现在,我们准备将其传递给我们创建的 Trainer。此代码如下

trainer = CustomTrainer(model = model,args = training_args,train_dataset = tokenized_datasets['train'],eval_dataset = tokenized_datasets['val'],tokenizer = tokenizer,data_collator = collate_fn,compute_metrics = compute_metrics,class_weights=class_weights,
)train_result = trainer.train()
代码解释
  • 我们首先创建之前创建的 CustomTrainer() 类的对象
  • 为此,我们给出了带有自定义 Sequential Head 的 Llama 3 模型,训练参数
  • 我们甚至将标记化的训练数据和评估数据与标记器一起传递
  • 我们甚至提供了整理器功能,以便在训练 LLM 时进行批处理
  • 最后,我们给出我们创建的度量函数和类权重,如果我们有标签不平衡的数据,这将有所帮助

现在我们已经创建了训练器对象。现在我们调用训练器对象的 .train() 函数来启动训练过程,并将结果存储在 train_result 中

在这里插入图片描述

代码解释
  • 上面我们检查训练是否进行了 1000 步。这是因为我们有 8000 个训练数据,并且每次在每个步骤中我们发送 8 个样本;因此我们总共有 1000 步
  • 训练持续了 2 小时 36 分钟,以便模型迭代一个时期的整个训练数据
  • 我们可以看到模型的训练损失为 1.12,验证损失为 0.29
  • 该模型在验证数据上表现出色,准确率达到 93%

现在,让我们尝试进行评估,在测试数据上测试新训练的模型:

def generate_predictions(model,df_test):sentences = df_test.text.tolist()batch_size = 32  all_outputs = []for i in range(0, len(sentences), batch_size):batch_sentences = sentences[i:i + batch_size]inputs = tokenizer(batch_sentences, return_tensors="pt", padding=True, truncation=True, max_length=512)inputs = {k: v.to('cuda' if torch.cuda.is_available() else 'cpu') for k, v in inputs.items()}with torch.no_grad():outputs = model(**inputs)all_outputs.append(outputs['logits'])final_outputs = torch.cat(all_outputs, dim=0)df_test['predictions']=final_outputs.argmax(axis=1).cpu().numpy()generate_predictions(model,test_df)
get_performance_metrics(test_df)

在这里插入图片描述

代码解释
  • 在这里,我们创建一个与我们创建的函数非常相似的函数
  • 在这个函数中,我们将测试数据框中的文本列转换为句子列表,然后运行一个步长等于批处理大小的 for 循环
  • 在这个 for 循环中,我们获取句子的批号,将它们发送到 tokenizer 进行标记,然后将它们推送到 GPU
  • 然后,我们将这个标记列表插入模型并从中获取概率列表
  • 最后,我们得到每个输出中最高概率的索引,并将索引保​​存回测试数据框中
  • 这个 test_df 返回到 get_performance_metric 函数,该函数接收这个数据框并输出结果

运行此代码会产生以下结果。我们看到模型的准确率有了很大的提升。其他指标,如精度、召回率和 f1 分数也从初始值有所增加。总体准确率从训练前的 0.23 提高到训练后的 0.93,即训练后模型提高了 0.7,即 70%。由此,我们可以了解到,大型语言模型非常适合用作序列分类器

结论

总之,对大型语言模型Llama 3进行序列分类的微调涉及几个详细步骤,从准备数据集到量化模型以在有限的硬件上进行高效训练。通过利用 HuggingFace 的各种库并实施 Prompt Engineering 和 LoRA 配置等技术,可以有效地训练这些模型以完成新闻分类等特定任务。本指南演示了从初始设置和数据预处理到模型训练和评估的整个过程,突出了 LLM 在自然语言处理任务中的多功能性和强大功能。

关键要点
  • 大型语言模型(finetune Llama 3)在大量数据集上进行了预训练,能够生成和理解复杂文本
  • 虽然有用,但仅靠快速工程可能不足以完成所有分类任务;模型微调可以提供更好的性能
  • 正确加载、拆分和平衡数据集是模型训练前的基本步骤,以确保模型性能准确、公平
  • 定义自定义错误指标和训练循环对于处理序列分类任务中的类别权重等特定要求是必要的
  • 使用准确度和平衡准确度等指标进行训练前和训练后评估,可以深入了解模型性能和训练过程的有效性

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

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

相关文章

极域卸载不干净导致无法重新安装问题:独家解决方案

文章目录 一、问题二、解决1.网上常规方法2.本贴特殊之处 三、致谢 一、问题 极域卸载不干净,导致无法重新安装。 二、解决 1.网上常规方法 1.regedit命令注册表删除 topdomain、mythware、{5FB4EEDF-6A79-45C3-B049-EF327CA03FCD} 2.删除极域对应tmp文件 网上…

Go微服务: 分布式之通过可靠消息实现最终一致性

通过可靠消息实现最终一致性 可靠消息,就是靠普消息,还是基于之前的这个案例 比如这个订单服务,无论你是先发送消息,还是先新建订单,它其实都是发送的不可靠消息就是说如果这个消息,像mysql事务那样&#…

德克萨斯大学奥斯汀分校自然语言处理硕士课程汉化版(第七周) - 结构化预测

结构化预测 0. 写在大模型前面的话1. 词法分析 1.1. 分词1.2. 词性标注 2.2. 句法分析 2.3. 成分句法分析2.3. 依存句法分析 3. 序列标注 3.1. 使用分类器进行标注 4. 语义分析 0. 写在大模型前面的话 在介绍大语言模型之前,先把自然语言处理中遗漏的结构化预测补…

【机器学习】机器学习与医疗健康在智能诊疗中的融合应用与性能优化新探索

文章目录 引言机器学习与医疗健康的基本概念机器学习概述监督学习无监督学习强化学习 医疗健康概述疾病预测诊断辅助个性化治疗方案制定 机器学习与医疗健康的融合应用实时健康监测数据预处理特征工程 疾病预测与优化模型训练模型评估 诊断辅助与优化深度学习应用 个性化治疗方…

接口自动化Requests+Pytest基础实现

目录 1. 数据库以及数据库操作1.1 概念1.2 分类1.3 作用 2 python操作数据库的相关实现2.1 背景2.2 相关实现 3. pymysql基础3.1 整个流程3.2 案例3.3 Pymysql工具类封装 4 事务4.1 案例4.2 事务概念4.3 事务特征 5. requests库5.1 概念5.2 角色定位5.3 安装5.4 校验5.5 reques…

“中新美”三重身份,能帮SHEIN解决上市问题吗?

一家公司的海外上市之路能有多复杂?辗转多地的SHEIN,可能是当前最有话语权回答这个问题的公司。最近,它又有了新消息。 在上市信息多次更改后,伦敦正在成为SHEIN最有可能的“着陆”点。巴伦周刊援引英国天空新闻报道称&#xff0…

Python01 -分解整包数据到各个变量操作和生成器

Python 的星号表达式可以用来解决这个问题。比如,你在学习一门课程,在学期末的时候,你想统计下家庭作业的平均成绩,但是排除掉第一个和最后一个分数。如果只有四个分数,你可能就直接去简单的手动赋值,但如果…

5、搭建前端项目

5.1 使用vite vue搭建 win r 打开终端 切换到你想要搭建的盘 npm init vitelatest跟着以下步骤取名即可 cd fullStackBlognpm installnpm run dev默认在 http://localhost:5173/ 下启动了 5.2 用vscode打开项目并安装需要的插件 1、删除多余的 HelloWorld.vue 文件 2、安装…

【Vue3】理解toRef() 和 toRefs()

历史小剧场 知道可能面对的困难和痛苦,在死亡的恐惧中不断挣扎,却仍然能战胜自己,选择这条道路,这才是真正的勇气。----《明朝那些事儿》 前言 toRef 和 toRefs 是Vue3中的响应式转换工具函数 toRef: 不影响源对象的情况下&#x…

【数据结构】AVLTree实现详解

目录 一.什么是AVLTree 二.AVLTree的实现 1.树结点的定义 2.类的定义 3.插入结点 ①按二叉搜索树规则插入结点 ②更新平衡因子 更新平衡因子情况分析 ③判断是否要旋转 左单旋 右单旋 左右单旋 右左双旋 4.删除、查找和修改函数 查找结点 三.测试 1.判断是否是搜索树 …

面试题-Vue2和Vue3的区别

文章目录 1. 响应式系统2. 组合式 API (Composition API)3. Fragment (碎片)4. Teleport (传送门) 5. 性能改进6. 移除或改变的功能7. 构建工具8. TypeScript 支持 Vue 2 和 Vue 3 之间存在许多重要的区别,这些区别涵盖了性能、API 设计、组合式 API(Com…

AndroidStudio无法识别连接夜神模拟器

方法一(无法从根本上解决) ①进入夜神模拟器安装路径下的bin路径(安装路径可以带有中文路径) ②打开cmd窗口,输入以下代码(一定要打开模拟器) nox_adb.exe connect 127.0.0.1:62001 方法二(根本上解决) 原因:Android Studio的adb版本与夜神模拟器的adb版本不一致 ①打开And…

技术架构的发展

技术架构的演进 主要方向: ​ 1.提高单位时间内的吞吐量,提高并发度; ​ 2.对应用服务代码进行解耦合,使得开发效率得到提高; ​ 3.运维成本降低; ​ 4.成本降低,如购买云厂商资源&#xf…

Cortex-M7——NVIC

Cortex-M7——NVIC 小狼http://blog.csdn.net/xiaolangyangyang 一、NVIC架构 二、中断及异常编号 三、中断屏蔽寄存器(__disable_irq和__enable_irq操作的是PRIMASK寄存器) 四、中断分组寄存器(SCB->AIRCR[10:8]) 五、NVIC寄…

常用的Linux命令,linux下文件的读、写、打开、关闭append用法

vim demoq.c打开写的.c文件 内容为 按a可以编辑页面代码。按ESC退出编辑然后按shift:wq保存文件并退出 Linux 系统中采用三位十进制数表示权限,如0755, 0644.7 124(可读、可写、可执行) 5 14(可读、不可写、可执行) …

苹果手机微信如何直接打印文件

在快节奏的工作和生活中,打印文件的需求无处不在。但你是否曾经遇到过这样的困扰:打印店价格高昂,让你望而却步?今天,我要给大家介绍一款神奇的微信小程序——琢贝云打印,让你的苹果手机微信直接变身移动打…

Docker配置Redis集群以及主从扩容与缩容

基础镜像拉取 docker run -p 6379:6379 -d redis:6.0.8 配置文件以及数据卷挂载 # 开启密码验证(可选) requirepass 1234 # 允许redis外地连接,需要注释掉绑定的IP # bind 127.0.0.1 # 关闭保护模式(可选) protected-m…

6.18云服务器大促盘点,错过一次,再等一年!

随着云计算技术的飞速发展,云服务器已成为企业和个人构建和扩展在线业务的首选平台。特别是在大型促销活动如618年中大促期间,云服务提供商纷纷推出极具吸引力的优惠,以降低用户上云的门槛。以下是对当前市场上几个主流云服务提供商的优惠活动…

德克萨斯大学奥斯汀分校自然语言处理硕士课程汉化版(第六周) - 预训练模型

预训练模型 1. 预训练模型介绍 1.1. ELMo1.2. GPT1.3. BERT 2. Seq2Seq 2.1. T52.2. BART 3. Tokenization 1. 预训练模型介绍 在预训练语言模型出现之前,统计语言模型(如N-gram模型)是主流方法。这些模型利用统计方法来预测文本中的下一个…

设计模式-外观(门面)模式(结构型)

外观模式 外观模式又称门面模式(结构型模式),它是一个可以屏蔽系统复杂性的设计模式。俗话说没有什么问题是加一层“介质”解决不了的,如果有那就在加一层。在开发过程中肯定封装过Utils类,我认为这就是一种门面模式&…