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

news2024/12/27 1:21:15

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

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

汇总合集:

  • 《大模型面试宝典》(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_dataset

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

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

在这里插入图片描述

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

import pandas as pd

df = 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 torch

class_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, AutoModelForSequenceClassification

quantization_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_model

lora_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 AutoTokenizer

model_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_report

def get_metrics_result(test_df):
    y_test = test_df.label
    y_pred = test_df.predictions

    print("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 DataCollatorWithPadding

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

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

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

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

def compute_metrics(evaluations):
    predictions, labels = evaluations
    predictions = 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 = None

    def 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.coloradmin.cn/o/1804155.html

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

相关文章

GDPU unity游戏开发 寻路与导航

学会寻路,出门在外,身份不是他给的,他做不了你一直的导航。 角色寻路 角色控制器替换为普通的角色控制器,给实验九的地形增加NavMesh Surface组件,然后给角色增加NavMesh Agent组件,并选择合适的参数。通过…

Ubuntu24.04基本配置

目录 0. 前言1. 连接网络2. 更新源3. 安装并配置vim4. 设置用户sudo免密5. 同步双系统时间6. 设置终端颜色主题7. 设置中文输入法8. 调整Dock位置等9. 设置Grub10. 其它美化设置10.1 夜灯10.2 壁纸10.3 终端加强gnome-tweaks10.4 字体 11. 常用工具11.1 邮箱配置11.2 翻译工具1…

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

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

【C++11】多线程常用知识

知识体系 thread C++ thread中最常用的两个函数是join和detach,怎么选择呢,简单来说,如果希望等待线程结束,用join,如果希望异步执行,且不等待执行结果,那么就用detach;thread_local可以简单理解为一个线程级别的全局变量;线程id在调试多线程程序时是非常有用的东西;…

Responder工具

简介 Responder是一种网络安全工具,用于嗅探和抓取网络流量中的凭证信息(如用户名、密码等)。它可以在本地网络中创建一个伪造的服务(如HTTP、SMB等),并捕获客户端与该服务的通信中的凭证信息。 Responder工…

华为云耀云服务器L实例规则配置教程(亲自实操经验)

我刚买了这个最基础的36¥的L实例的云服务器,这个实例是自带公网ip的,不需要额外购买。我准备先配置好,能够通过公网ip访问,以便之后上传javaweb项目可以直接访问,不过中途遇到了点问题,但是已解…

Linux内核下网卡硬件 MAC 和PHY分析笔记

1 简介 通常CPU自带的以太网接口是MAC控制器,为了实现完整的功能,外围硬件还需要增加一个PHY芯片。 PHY芯片在建立网络连接时负责协商确定网速、全双工 或者 半双工等。在正常通讯时负责在MAC控制器的MII信号 与 网线中的信号之间做转换。 本文的内核代…

pyinstall 打包 paddleocr 成为.exe文件步骤

一、首先进入虚拟环境 使用pip安装pyinstaller pip install pyinstaller我的已经安装完成 二、用cmd进入当前打包文件夹下,新建使spec文件内容如下 注意:其中需要修改的部分是pathex中文件所在路径文件内容摘抄自另一篇博文(❄点击可查看❄) # -*- m…

第二讲笔记:隐私计算助力数据要素流通

1、数据要素流转与数据 2、数据外循环中的信任 焦虑 信任焦虑背后的代表性案例 内鬼门 : 2023 年 , 美国科技公司 Ubiquiti在2021年1月曝出数据泄露事 件, “攻击者”在随后的“谈判”中试 图向该企业勒索近200万美元(50比特 币&…

Steam游戏如何选择适合的服务器

在Steam平台上,玩家可以享受到来自世界各地开发者的游戏作品。然而,要获得最佳的游戏体验,选择合适的服务器至关重要。本文将从网络延迟、服务器位置、游戏类型和个人偏好等多个方面,为玩家提供选择Steam游戏服务器的实用指南。 如…

设计模式-中介者(调停者)模式(行为型)

中介者模式 中介者模式是一种行为型模式,又叫调停者模式,它是为了解决多个对象之间,多个类之间通信的复杂性,定义一个中介者对象来封装一些列对象之间的交互,使各个对象之间不同持有对方的引用就可以实现交互&#xf…

湖南源点(市场研究咨询)如何产出更加有意义的竞品调研

湖南源点咨询认为:当前,任何项目都不能盲目开始,前期的准备工作必不可少。在基础架构搭建的同时,设计上对于前端功能、用户体验的调研就优先开始了。在这个阶段,大部分设计师都会分配很多调研任务,疯狂对竞…

BC C language

题目汇总 No.1 打印有规律的字符(牛牛的字符菱形) 代码展示 #include<stdio.h> int main() {char ch0;scanf("%c",&ch);for(int i0;i<5;i){for(int j0;j<5;j){if((i0||i4)&&j2)printf("%c", ch);else if ((i 1||i3) &&…

大疆智图_空三二维重建成果传输

一、软件环境 1.1 所需软件 1、 大疆智图&#xff1a;点击下载&#xff1b;   2、 ArcGIS Pro 3.1.5&#xff1a;点击下载&#xff0c;建议使用IDM或Aria2等多线程下载器&#xff1b;   3、 IDM下载器&#xff1a;点击下载&#xff0c;或自行搜索&#xff1b;   4、 Fas…

最近一直没动静的Pika Labs原来在筹集融资,加快构建视频基础模型

Pika 筹集了 8000 万美元&#xff0c;因此任何人都可以根据命令制作视频。 今天对我们来说是一个重要的日子。自从我们从斯坦福大学退学去构建 Pika 以来已经一年了&#xff0c;在这段时间里&#xff0c;我们在 Discord 上进行了秘密发布&#xff0c;发布了我们的 1.0 模型和 …

找了半天,还不如自己写一个图片转ico格式的程序

关于jpg、png等图片转ICO格式 最近突然急需一张ico格式的文件&#xff0c;就拿着处理好的png图片出网上找在线转换器&#xff0c;找了一个小时&#xff0c;绝了&#xff0c;不是需要注册充钱就是下载不下来&#xff0c;好不容易下载下来还是个文件错误。想着找个PS插件直接导出…

2024 cicsn ezbuf

文章目录 参考protobuf逆向学习复原结构思路exp 参考 https://www.y4ng.cn/posts/pwn/protobuf/#ciscn-2024-ezbuf protobuf 当时压根不知道用了protobuf这个玩意&#xff0c;提取工具也没提取出来&#xff0c;还是做题做太少了&#xff0c;很多关键性的结构都没看出来是pro…

WEB漏洞服务能提供哪些帮助

在数字化浪潮的推动下&#xff0c;Web应用程序已成为企业展示形象、提供服务、与用户进行交互的重要平台。然而&#xff0c;随着技术的飞速发展&#xff0c;Web应用程序中的安全漏洞也日益显现&#xff0c;成为网络安全的重大隐患。这些漏洞一旦被恶意攻击者利用&#xff0c;可…

极简主义在UI设计中的应用及解析

极简主义&#xff0c;即“少就是多”。在设计中&#xff0c;极简主义是许多艺术概念之一&#xff0c;它描述了一种内容形式&#xff0c;可以在许多方面使用。现在移动UI界面和网页设计中的极简主义设计越来越多。即时设计认为&#xff0c;极简主义UI界面不仅美观&#xff0c;而…

The 18th Northeast Collegiate Programming Contest(5/9/13)

心得 赛中ac&#xff1a;5&#xff0c;目前ac&#xff1a;9&#xff0c;题目总数&#xff1a;13 中档可做题还是很多的&#xff0c;可惜遇到了难绷的queueforces&#xff0c; 最后15min才判出来&#xff0c;oi赛制5wa4遗憾离场&#xff0c;赛后把几个题都给调过了&#xff0…