日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > windows >内容正文

windows

在灾难推文分析场景上比较用 LoRA 微调 Roberta、Llama 2 和 Mistral 的过程及表现

發(fā)布時間:2023/12/24 windows 31 coder
生活随笔 收集整理的這篇文章主要介紹了 在灾难推文分析场景上比较用 LoRA 微调 Roberta、Llama 2 和 Mistral 的过程及表现 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

引言

自然語言處理 (NLP) 領(lǐng)域的進(jìn)展日新月異,你方唱罷我登場。因此,在實際場景中,針對特定的任務(wù),我們經(jīng)常需要對不同的語言模型進(jìn)行比較,以尋找最適合的模型。本文主要比較 3 個模型: RoBERTa、Mistral-7B 及 Llama-2-7B。我們用它們來解決一個常見問題 —— 對災(zāi)難相關(guān)的推文進(jìn)行分類。值得注意的是,Mistral 和 Llama 2 是 70 億參數(shù)的大模型。相形之下,RoBERTa-large (355M 參數(shù)) 只是一個小模型,我們用它作為比較的基線。

本文,我們使用 PEFT (Parameter-Efficient Fine-Tuning,參數(shù)高效微調(diào)) 技術(shù): LoRA (Low-Rank Adaptation,低秩適配) 來微調(diào)帶序列分類任務(wù)頭的預(yù)訓(xùn)練模型。LoRA 旨在顯著減少可訓(xùn)參數(shù)量,同時保持強(qiáng)大的下游任務(wù)性能。

本文的主要目標(biāo)是通過對 Hugging Face 的三個預(yù)訓(xùn)練模型進(jìn)行 LoRA 微調(diào),使之適用于序列分類任務(wù)。這三個預(yù)訓(xùn)練模型分別是: meta-llama/Llama-2-7b-hf、mistralai/Mistral-7B-v0.1 及 roberta-large。

使用的硬件

  • 節(jié)點數(shù): 1
  • 每個節(jié)點的 GPU 數(shù): 1
  • GPU 類型: A6000
  • GPU 顯存: 48GB

目標(biāo)

  • 使用 LoRA PEFT 方法對預(yù)訓(xùn)練 LLM 進(jìn)行微調(diào)。
  • 了解如何使用 Hugging Face 的各種 API (transformers、peft 以及 datasets)。
  • 使用 Weights & Biases 進(jìn)行超參調(diào)優(yōu)以及實驗日志記錄。

軟件依賴

datasets
evaluate
peft
scikit-learn
torch
transformers
wandb

注意: 要準(zhǔn)確重現(xiàn)本文結(jié)果,請注意確保軟件版本與 wandb 報告 的一致。

預(yù)訓(xùn)練模型

RoBERTa

RoBERTa (Robustly Optimized BERT Approach) 是 Meta AI 研究團(tuán)隊提出的改進(jìn)版 BERT 模型。BERT 是一種基于 transformer 的語言模型,其基于自注意力機(jī)制對單詞進(jìn)行上下文感知的表征,并基于掩碼語言模型目標(biāo)進(jìn)行訓(xùn)練。請注意,BERT 作為編碼器模型,僅可用于自然語言理解任務(wù) (例如序列分類和詞元分類)。

RoBERTa 是一種流行的可微調(diào)模型,很適合作為我們實驗的基線。欲了解更多信息,你可以查閱其 Hugging Face 模型卡。

Llama 2

Llama 2 (Large Language Model Meta AI) 是 Meta AI 推出的一系列大語言模型 (LLM),其模型大小各異,參數(shù)量從 70 億到 650 億不等。

Llama 2 是一種基于 transformer 解碼器架構(gòu)的自回歸語言模型。Llama 2 接受單詞序列作為輸入,并基于滑動窗口迭代預(yù)測下一個詞元,從而實現(xiàn)文本生成的功能。

Llama 2 的架構(gòu)與 GPT-3 等模型略有不同。舉幾個例子,Llama 2 采用 SwiGLU 激活函數(shù)而不是 ReLU,另外其位置嵌入使用的是旋轉(zhuǎn)位置嵌入而不是可訓(xùn)絕對位置嵌入。

最近發(fā)布的 Llama 2 還對架構(gòu)進(jìn)行了改進(jìn),其將支持的最大上下文長度擴(kuò)展到 4096 個詞元,并使用分組查詢注意 (grouped-query attention,GQA) 解碼機(jī)制來更好地利用長序列。

Mistral 7B

Mistral 7B v0.1 有 73 億個參數(shù),是 Mistral AI 推出的第一個 LLM。

Mistral 7B 架構(gòu)使用的新技術(shù)主要有:

  • 滑窗注意力: 用基于滑動窗口的注意力替換完整注意力 (平方級計算成本),其中每個詞元最多可以關(guān)注上一層的 4096 個詞元 (線性計算成本)。這樣,多層以后,Mistral 7B 的實際關(guān)注詞元數(shù)會疊加,因此更高層的注意力實際關(guān)注的總歷史詞元數(shù)會超過 4096。
  • 分組查詢注意力: Llama 2 也使用了該技術(shù),其通過緩存先前解碼的詞元的鍵向量和值向量來優(yōu)化推理過程 (減少處理時間)。

LoRA

PEFT (Parameter Efficient Fine-Tuning,參數(shù)高效微調(diào)) 包含 p-tuning、前綴微調(diào) (prefix-tuning) 、IA3、適配器微調(diào)以及 LoRA 等一系列技術(shù),其旨在通過僅微調(diào)大模型的一個小參數(shù)集,就能達(dá)到全模型微調(diào)的性能水平。

LoRA (Low-Rank Adaptation,低階適配) 的方法與添加適配層類似。其主要目標(biāo)是減少模型的可訓(xùn)參數(shù)量。LoRA 的主要做法是凍結(jié)預(yù)訓(xùn)練權(quán)重,僅更新一個新增的低秩矩陣。

環(huán)境設(shè)置

RoBERTa 支持的最大序列長度為 512,為公平起見,對所有模型,我們統(tǒng)一設(shè)定 MAX_LEN=512

MAX_LEN = 512
roberta_checkpoint = "roberta-large"
mistral_checkpoint = "mistralai/Mistral-7B-v0.1"
llama_checkpoint = "meta-llama/Llama-2-7b-hf"

數(shù)據(jù)準(zhǔn)備

數(shù)據(jù)加載

從 Hugging Face 加載數(shù)據(jù)集:

from datasets import load_dataset
dataset = load_dataset("mehdiiraqui/twitter_disaster")

將數(shù)據(jù)集分為訓(xùn)練集和驗證集,同時加載測試集:

from datasets import Dataset
# 將數(shù)據(jù)集的訓(xùn)練集劃分為訓(xùn)練集和驗證集
data = dataset['train'].train_test_split(train_size=0.8, seed=42)
# 把劃分而得的測試集重命名為驗證集
data['val'] = data.pop("test")
# 將原數(shù)據(jù)集的測試集仍作為測試集
data['test'] = dataset['test']

以下是數(shù)據(jù)集概覽:

DatasetDict({
    train: Dataset({
        features: ['id', 'keyword', 'location', 'text', 'target'],
        num_rows: 6090
    })
    val: Dataset({
        features: ['id', 'keyword', 'location', 'text', 'target'],
        num_rows: 1523
    })
    test: Dataset({
        features: ['id', 'keyword', 'location', 'text', 'target'],
        num_rows: 3263
    })
})

首先,檢查一下數(shù)據(jù)分布:

import pandas as pd

data['train'].to_pandas().info()
data['test'].to_pandas().info()
  • 訓(xùn)練集
RangeIndex: 7613 entries, 0 to 7612
Data columns (total 5 columns):
 # Column Non-Null Count Dtype
--- ------ -------------- -----
 0 id 7613 non-null int64
 1 keyword 7552 non-null object
 2 location 5080 non-null object
 3 text 7613 non-null object
 4 target 7613 non-null int64
dtypes: int64(2), object(3)
memory usage: 297.5+ KB
  • 測試集
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 3263 entries, 0 to 3262
Data columns (total 5 columns):
 # Column Non-Null Count Dtype
--- ------ -------------- -----
 0 id 3263 non-null int64
 1 keyword 3237 non-null object
 2 location 2158 non-null object
 3 text 3263 non-null object
 4 target 3263 non-null int64
dtypes: int64(2), object(3)
memory usage: 127.6+ KB

訓(xùn)練集中標(biāo)簽分布情況:

target
0 4342
1 3271
Name: count, dtype: int64

由于類別不平衡,我們計算一下正負(fù)類權(quán)重,以用于稍后的損失計算:

pos_weights = len(data['train'].to_pandas()) / (2 * data['train'].to_pandas().target.value_counts()[1])
neg_weights = len(data['train'].to_pandas()) / (2 * data['train'].to_pandas().target.value_counts()[0])

計算出的權(quán)重為:

POS_WEIGHT, NEG_WEIGHT = (1.1637114032405993, 0.8766697374481806)

接著,我們計算文本序列的最大長度:

# 字符數(shù)
max_char = data['train'].to_pandas()['text'].str.len().max()
# 詞數(shù)
max_words = data['train'].to_pandas()['text'].str.split().str.len().max()
The maximum number of characters is 152.
The maximum number of words is 31.

數(shù)據(jù)處理

以一條訓(xùn)練數(shù)據(jù)為例:

data['train'][0]
{'id': 5285,
 'keyword': 'fear',
 'location': 'Thibodaux, LA',
 'text': 'my worst fear. https://t.co/iH8UDz8mq3',
 'target': 0}

該數(shù)據(jù)中包括關(guān)鍵字、位置和推文。為了簡單起見,我們選擇 text 特征作為 LLM 的唯一輸入。

本階段的目標(biāo)是為 LLM 微調(diào)準(zhǔn)備所需的 Hugging Face 格式的訓(xùn)練集、驗證集和測試集。然后是定義用于訓(xùn)練的詞元數(shù)據(jù)集,使用合適的分詞器將 text 特征轉(zhuǎn)換為詞元 id 和注意力掩碼序列這兩個張量。由于每個模型都有其特定的分詞器,因此我們需要生成三個不同的數(shù)據(jù)集,每個模型一個。

我們首先定義 RoBERTa 模型的數(shù)據(jù)加載器:

  • 加載與分詞:
from transformers import AutoTokenizer
roberta_tokenizer = AutoTokenizer.from_pretrained(roberta_checkpoint, add_prefix_space=True)

注意: RoBERTa 分詞器經(jīng)過訓(xùn)練已將空格視為詞元的一部分。因此,如果句子的第一個單詞前面沒有空格,則其編碼會有所不同。為了確保第一個單詞包含空格,我們設(shè)置 add_prefix_space=True 。同時,為了保持三個模型的預(yù)處理一致,我們將 Llama 2 和 Mistral 7B 的相應(yīng)參數(shù)也設(shè)為 True

  • 定義每條數(shù)據(jù)的預(yù)處理函數(shù):
def roberta_preprocessing_function(examples):
    return roberta_tokenizer(examples['text'], truncation=True, max_length=MAX_LEN)

將預(yù)處理函數(shù)應(yīng)用于訓(xùn)練數(shù)據(jù)集的第一條數(shù)據(jù),我們得到了分詞后的輸入 ( input_ids ) 及其注意力掩碼:

roberta_preprocessing_function(data['train'][0])
{'input_ids': [0, 127, 2373, 2490, 4, 1205, 640, 90, 4, 876, 73, 118, 725, 398, 13083, 329, 398, 119, 1343, 246, 2], 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}
  • 現(xiàn)在,將預(yù)處理函數(shù)應(yīng)用于整個數(shù)據(jù)集:
col_to_delete = ['id', 'keyword','location', 'text']
# 刪除不需要的列,并應(yīng)用預(yù)處理函數(shù)
roberta_tokenized_datasets = data.map(roberta_preprocessing_function, batched=True, remove_columns=col_to_delete)
# 按照 HuggingFace 的要求,將 `target` 列  重命名為 `label` 列
roberta_tokenized_datasets = roberta_tokenized_datasets.rename_column("target", "label")
# 數(shù)據(jù)集格式設(shè)為 "torch"
roberta_tokenized_datasets.set_format("torch")

注意: 我們從數(shù)據(jù)中刪除了不需要的列: id 、 keywordlocationtext 。刪除 text 的原因是我們已經(jīng)將其轉(zhuǎn)換為輸入 id 和注意力掩碼:

分詞后的訓(xùn)練數(shù)據(jù)集中的數(shù)據(jù)如下:

roberta_tokenized_datasets['train'][0]
{'label': tensor(0),
 'input_ids': tensor([ 0, 127, 2373, 2490, 4, 1205, 640, 90, 4, 876,
            73, 118, 725, 398, 13083, 329, 398, 119, 1343, 246,
             2]),
 'attention_mask': tensor([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1])}
  • 為了生成訓(xùn)練 batch 數(shù)據(jù),我們還需要對給定 batch 中的序列進(jìn)行填充,以使 batch 中所有序列的長度都等于本 batch 最長序列的長度。為此,我們使用了 DataCollat??orWithPadding 類:
# 數(shù)據(jù)整理器將所有數(shù)據(jù)統(tǒng)一填充至 batch 內(nèi)最長序列的長度
from transformers import DataCollatorWithPadding
roberta_data_collator = DataCollatorWithPadding(tokenizer=roberta_tokenizer)

用相同的流程為 Mistral 7B 和 Llama 2 模型準(zhǔn)備數(shù)據(jù):

注意 Llama 2 和 Mistral 7B 沒有默認(rèn)的 pad_token_id ,我們將其設(shè)為 eos_token_id 。

  • Mistral 7B:
# 加載 Mistral 7B 分詞器
from transformers import AutoTokenizer, DataCollatorWithPadding
mistral_tokenizer = AutoTokenizer.from_pretrained(mistral_checkpoint, add_prefix_space=True)
mistral_tokenizer.pad_token_id = mistral_tokenizer.eos_token_id
mistral_tokenizer.pad_token = mistral_tokenizer.eos_token

def mistral_preprocessing_function(examples):
    return mistral_tokenizer(examples['text'], truncation=True, max_length=MAX_LEN)

mistral_tokenized_datasets = data.map(mistral_preprocessing_function, batched=True, remove_columns=col_to_delete)
mistral_tokenized_datasets = mistral_tokenized_datasets.rename_column("target", "label")
mistral_tokenized_datasets.set_format("torch")

# 序列填充
mistral_data_collator = DataCollatorWithPadding(tokenizer=mistral_tokenizer)
  • Llama 2:
# 加載 Llama 2 分詞器
from transformers import AutoTokenizer, DataCollatorWithPadding
llama_tokenizer = AutoTokenizer.from_pretrained(llama_checkpoint, add_prefix_space=True)
llama_tokenizer.pad_token_id = llama_tokenizer.eos_token_id
llama_tokenizer.pad_token = llama_tokenizer.eos_token

def llama_preprocessing_function(examples):
    return llama_tokenizer(examples['text'], truncation=True, max_length=MAX_LEN)

llama_tokenized_datasets = data.map(llama_preprocessing_function, batched=True, remove_columns=col_to_delete)
llama_tokenized_datasets = llama_tokenized_datasets.rename_column("target", "label")
llama_tokenized_datasets.set_format("torch")

# 序列填充
llama_data_collator = DataCollatorWithPadding(tokenizer=llama_tokenizer)

至此,我們已經(jīng)準(zhǔn)備好了分詞后的數(shù)據(jù)集,下一節(jié)我們將討論如何加載預(yù)訓(xùn)練 LLM 檢查點以及如何設(shè)置 LoRA 權(quán)重。

模型

RoBERTa

為分類任務(wù)加載 RoBERTa 檢查點

我們使用 Hugging Face AutoModelForSequenceClassification 類加載帶有序列分類頭的預(yù)訓(xùn)練 RoBERTa 模型:

from transformers import AutoModelForSequenceClassification
roberta_model = AutoModelForSequenceClassification.from_pretrained(roberta_checkpoint, num_labels=2)

RoBERTa 分類器的 LoRA 設(shè)置

我們?yōu)?RoBERTa 分類器設(shè)置 LoRA 參數(shù):

  • TaskType: 序列分類
  • r(rank): 分解矩陣的秩
  • lora_alpha: 用于對習(xí)得權(quán)重進(jìn)行縮放的 alpha 參數(shù)。LoRA 論文建議將 alpha 固定為 16
  • lora_dropout: LoRA 層的 Dropout 概率
  • bias: 是否向 LoRA 層添加偏置

以下代碼使用了 LoRA 論文 的推薦設(shè)置。后文 我們還將用 wandb 對這些超參進(jìn)行調(diào)優(yōu)。

from peft import get_peft_model, LoraConfig, TaskType
roberta_peft_config = LoraConfig(
    task_type=TaskType.SEQ_CLS, r=2, lora_alpha=16, lora_dropout=0.1, bias="none",
)
roberta_model = get_peft_model(roberta_model, roberta_peft_config)
roberta_model.print_trainable_parameters()

可以看到,可訓(xùn)參數(shù)量僅占 RoBERTa 模型參數(shù)量的 0.64%:

trainable params: 2,299,908 || all params: 356,610,052 || trainable%: 0.6449363911929212

Mistral

為分類任務(wù)加載檢查點

加載帶有序列分類頭的預(yù)訓(xùn)練 Mistral-7B 模型:

from transformers import AutoModelForSequenceClassification
import torch
mistral_model =  AutoModelForSequenceClassification.from_pretrained(
  pretrained_model_name_or_path=mistral_checkpoint,
  num_labels=2,
  device_map="auto"
)

設(shè)置填充詞元 id,因為 Mistral 7B 沒有默認(rèn)填充詞元。

mistral_model.config.pad_token_id = mistral_model.config.eos_token_id

Mistral 7B 分類器的 LoRA 設(shè)置

對 Mistral 7B 模型而言,我們需要指定 target_modules (我們將其指定為注意力模塊的查詢向量映射層和值向量映射層):

from peft import get_peft_model, LoraConfig, TaskType

mistral_peft_config = LoraConfig(
    task_type=TaskType.SEQ_CLS, r=2, lora_alpha=16, lora_dropout=0.1, bias="none",
    target_modules=[
        "q_proj",
        "v_proj",
    ],
)

mistral_model = get_peft_model(mistral_model, mistral_peft_config)
mistral_model.print_trainable_parameters()

可訓(xùn)參數(shù)量僅占 Mistral 模型參數(shù)量的 0.024%:

trainable params: 1,720,320 || all params: 7,112,380,416 || trainable%: 0.02418768259540745

Llama 2

為分類任務(wù)加載檢查點

加載帶有序列分類頭的預(yù)訓(xùn)練 Llama 2 模型。

from transformers import AutoModelForSequenceClassification
import torch
llama_model =  AutoModelForSequenceClassification.from_pretrained(
  pretrained_model_name_or_path=llama_checkpoint,
  num_labels=2,
  device_map="auto",
  offload_folder="offload",
  trust_remote_code=True
)

設(shè)置填充詞元 id,因為 Llama 2 沒有默認(rèn)填充詞元。

llama_model.config.pad_token_id = llama_model.config.eos_token_id

Llama 2 分類器的 LoRA 設(shè)置

使用與 Mistral 相同的 LoRA 參數(shù):

from peft import get_peft_model, LoraConfig, TaskType
llama_peft_config = LoraConfig(
    task_type=TaskType.SEQ_CLS, r=16, lora_alpha=16, lora_dropout=0.05, bias="none",
    target_modules=[
        "q_proj",
        "v_proj",
    ],
)

llama_model = get_peft_model(llama_model, llama_peft_config)
llama_model.print_trainable_parameters()

可訓(xùn)參數(shù)量僅占 Llama 2 模型參數(shù)量的 0.12%:

trainable params: 8,404,992 || all params: 6,615,748,608 || trainable%: 0.1270452143516515

至此,我們定義了用于訓(xùn)練的詞元數(shù)據(jù)集及 LoRA 設(shè)置。下面,我們介紹如何使用 Hugging Face 的 Trainer 類啟動訓(xùn)練。

設(shè)置 Trainer

評估指標(biāo)

首先,我們定義用于對三個模型的性能進(jìn)行比較的指標(biāo): F1 分?jǐn)?shù)、召回率、精確度和準(zhǔn)確度:

import evaluate
import numpy as np

def compute_metrics(eval_pred):
    # HF `evaluate` 包已支持我們所要的所有指標(biāo)
    precision_metric = evaluate.load("precision")
    recall_metric = evaluate.load("recall")
    f1_metric= evaluate.load("f1")
    accuracy_metric = evaluate.load("accuracy")

    logits, labels = eval_pred
    # eval_pred 是模型返回的預(yù)測值和實際值元組
    predictions = np.argmax(logits, axis=-1)
    precision = precision_metric.compute(predictions=predictions, references=labels)["precision"]
    recall = recall_metric.compute(predictions=predictions, references=labels)["recall"]
    f1 = f1_metric.compute(predictions=predictions, references=labels)["f1"]
    accuracy = accuracy_metric.compute(predictions=predictions, references=labels)["accuracy"]

    # `Trainer` 要求將指標(biāo)組織為一個字典,其鍵為指標(biāo)名,值為分?jǐn)?shù)。
    return {"precision": precision, "recall": recall, "f1-score": f1, 'accuracy': accuracy}

基于加權(quán)損失的自定義 Trainer

前文提到,數(shù)據(jù)集正負(fù)類分布并不平衡。因此,我們用加權(quán)交叉熵?fù)p失來訓(xùn)練模型以解決這個問題。 Trainer 類本身的實現(xiàn)中不支持自定義損失,因為它期望直接從模型的輸出中獲取損失。

因此,我們需要定義一個自定義的 WeightedCELossTrainer ,以重寫 compute_loss 方法,該方法可以根據(jù)模型的預(yù)測和標(biāo)簽計算加權(quán)交叉熵?fù)p失:

from transformers import Trainer

class WeightedCELossTrainer(Trainer):
    def compute_loss(self, model, inputs, return_outputs=False):
        labels = inputs.pop("labels")
        # Get model's predictions
        outputs = model(**inputs)
        logits = outputs.get("logits")
        # Compute custom loss
        loss_fct = torch.nn.CrossEntropyLoss(weight=torch.tensor([neg_weights, pos_weights], device=model.device, dtype=logits.dtype))
        loss = loss_fct(logits.view(-1, self.model.config.num_labels), labels.view(-1))
        return (loss, outputs) if return_outputs else loss

Trainer 設(shè)置

我們?yōu)槿齻€模型分別設(shè)置訓(xùn)練超參及訓(xùn)練器。

RoBERTa

第一步,把模型搬到 GPU 設(shè)備上。

roberta_model = roberta_model.cuda()
roberta_model.device()

It will print the following:

device(type='cuda', index=0)

然后,設(shè)置訓(xùn)練超參:

from transformers import TrainingArguments

lr = 1e-4
batch_size = 8
num_epochs = 5

training_args = TrainingArguments(
    output_dir="roberta-large-lora-token-classification",
    learning_rate=lr,
    lr_scheduler_type= "constant",
    warmup_ratio= 0.1,
    max_grad_norm= 0.3,
    per_device_train_batch_size=batch_size,
    per_device_eval_batch_size=batch_size,
    num_train_epochs=num_epochs,
    weight_decay=0.001,
    evaluation_strategy="epoch",
    save_strategy="epoch",
    load_best_model_at_end=True,
    report_to="wandb",
    fp16=False,
    gradient_checkpointing=True,
)

最后,我們將模型、訓(xùn)練超參和詞元數(shù)據(jù)集一起作為參數(shù)來實例化一個 RoBERTa 訓(xùn)練器:

roberta_trainer = WeightedCELossTrainer(
    model=roberta_model,
    args=training_args,
    train_dataset=roberta_tokenized_datasets['train'],
    eval_dataset=roberta_tokenized_datasets["val"],
    data_collator=roberta_data_collator,
    compute_metrics=compute_metrics
)

Mistral-7B

與 RoBERTa 類似,我們用如下代碼初始化 WeightedCELossTrainer :

from transformers import TrainingArguments, Trainer

mistral_model = mistral_model.cuda()

lr = 1e-4
batch_size = 8
num_epochs = 5

training_args = TrainingArguments(
    output_dir="mistral-lora-token-classification",
    learning_rate=lr,
    lr_scheduler_type= "constant",
    warmup_ratio= 0.1,
    max_grad_norm= 0.3,
    per_device_train_batch_size=batch_size,
    per_device_eval_batch_size=batch_size,
    num_train_epochs=num_epochs,
    weight_decay=0.001,
    evaluation_strategy="epoch",
    save_strategy="epoch",
    load_best_model_at_end=True,
    report_to="wandb",
    fp16=True,
    gradient_checkpointing=True,
)

mistral_trainer = WeightedCELossTrainer(
    model=mistral_model,
    args=training_args,
    train_dataset=mistral_tokenized_datasets['train'],
    eval_dataset=mistral_tokenized_datasets["val"],
    data_collator=mistral_data_collator,
    compute_metrics=compute_metrics
)

注意,我們需要將 fp16 設(shè)為 True 以啟用半精度訓(xùn)練。主要原因是 Mistral-7B 很大,如果使用 fp32 精度,其權(quán)重?zé)o法放進(jìn)單塊 GPU 的顯存 (48GB) 中。

Llama 2

與 Mistral 7B 類似,我們用如下代碼定義訓(xùn)練器:

from transformers import TrainingArguments, Trainer

llama_model = llama_model.cuda()

lr = 1e-4
batch_size = 8
num_epochs = 5
training_args = TrainingArguments(
    output_dir="llama-lora-token-classification",
    learning_rate=lr,
    lr_scheduler_type= "constant",
    warmup_ratio= 0.1,
    max_grad_norm= 0.3,
    per_device_train_batch_size=batch_size,
    per_device_eval_batch_size=batch_size,
    num_train_epochs=num_epochs,
    weight_decay=0.001,
    evaluation_strategy="epoch",
    save_strategy="epoch",
    load_best_model_at_end=True,
    report_to="wandb",
    fp16=True,
    gradient_checkpointing=True,
)

llama_trainer = WeightedCELossTrainer(
    model=llama_model,
    args=training_args,
    train_dataset=llama_tokenized_datasets['train'],
    eval_dataset=llama_tokenized_datasets["val"],
    data_collator=llama_data_collator,
    compute_metrics=compute_metrics
)

超參調(diào)優(yōu)

我們用 Wandb Sweep API 通過貝葉斯搜索策略來進(jìn)行超參調(diào)優(yōu) (30 次運行),待調(diào)優(yōu)的超參搜索空間如下:

方法 指標(biāo) lora_alpha lora_bias lora_dropout lora_rank lr max_length
bayes 目標(biāo): maximize 分布: categorical 分布: categorical 分布: uniform 分布: categorical 分布: uniform 分布: categorical
目標(biāo)名: eval/f1-score 取值集合:
-16
-32
-64
取值集合: None -最大值: 0.1
-最小值: 0
取值集合:
-4
-8
-16
-32
-最大值: 2e-04
-最小值: 1e-05
取值集合: 512

欲了解更多信息,可以查看 資源 一節(jié)中的 Wandb 實驗報告。

結(jié)果

模型 F1 分?jǐn)?shù) 訓(xùn)練時間 內(nèi)存消耗 可訓(xùn)參數(shù)量
RoBERTa 0.8077 538 秒 GPU1: 9.1 GB
GPU2: 8.3 GB
0.64%
Mistral 7B 0.7364 2030 秒 GPU1: 29.6 Gb
GPU2: 29.5 GB
0.024%
Llama 2 0.7638 2052 秒 GPU1: 35 GB
GPU2: 33.9 GB
0.12%

總結(jié)

本文我們用 LoRA 對三個大語言模型 (LLM) (RoBERTa、Mistral 7B 及 Llama 2) 針對災(zāi)難推文分類任務(wù)進(jìn)行微調(diào)。從性能結(jié)果來看,RoBERTa 的性能大幅優(yōu)于 Mistral 7B 和 Llama 2。這就提出了一個問題: 我們是否真的需要一個大而復(fù)雜的 LLM 來完成諸如短序列二分類這樣的簡單任務(wù)?

一個重要的啟示是,在選擇要使用的 LLM 模型時應(yīng)該考慮具體的項目要求、可用資源和性能需求。

此外,對于針對短序列的相對 簡單 的預(yù)測任務(wù),小的基礎(chǔ)模型 (例如 RoBERTa) 仍然具有競爭力。

最后,我們還通過例子展示了 LoRA 方法的通用性,其既可應(yīng)用于編碼器 (RoBERTa) 模型,還可應(yīng)用于解碼器 (Llama 2 及 Mistral 7B) 模型。

資源

  1. 本文代碼均已在該 Github 項目。
  2. 下面是各模型的 Wandb 超參調(diào)優(yōu)實驗報告:
  • RoBERTa
  • Mistral 7B
  • Llama 2

英文原文: https://hf.co/blog/Lora-for-sequence-classification-with-Roberta-Llama-Mistral

原文作者: Mehdi Iraqi

譯者: Matrix Yao (姚偉峰),英特爾深度學(xué)習(xí)工程師,工作方向為 transformer-family 模型在各模態(tài)數(shù)據(jù)上的應(yīng)用及大規(guī)模模型的訓(xùn)練推理。

總結(jié)

以上是生活随笔為你收集整理的在灾难推文分析场景上比较用 LoRA 微调 Roberta、Llama 2 和 Mistral 的过程及表现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。