久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

LLM+LoRa微調加速技術原理及基于PEFT的動手實踐:一些思考和mt0-large+lora完整案例

 520jefferson 2023-04-18 發(fā)布于日本

如何花費較少的算力成本來進行微調訓練,,十分重要,,當前關于LLaMA、Alpaca,、Instruct微調、LoRa微調等多個概念大家講的很多,最近也在學習,,也看到幾個有趣的話題(主要參考于(https://github.com/ymcui/Chinese-LLaMA-Alpaca):

首先,來看關于Instruct微調和LoRa微調

Instruct微調和LoRa微調是兩種不同的技術,。 Instruct微調是指在深度神經網絡訓練過程中調整模型參數的過程,,以優(yōu)化模型的性能,。在微調過程中,使用一個預先訓練好的模型作為基礎模型,,然后在新的數據集上對該模型進行微調,。Instruct微調是一種通過更新預訓練模型的所有參數來完成的微調方法,通過微調使其適用于多個下游應用,。

LoRa微調則是指對低功耗廣域網(LoRaWAN)中的LoRa節(jié)點參數進行微調的過程,,以提高節(jié)點的傳輸效率。在LoRa微調中,,需要了解節(jié)點的硬件和網絡部署情況,,并通過對節(jié)點參數進行微小調整來優(yōu)化傳輸效率。

與Instruct微調相比,,LoRA在每個Transformer塊中注入可訓練層,,因為不需要為大多數模型權重計算梯度,大大減少了需要訓練參數的數量并且降低了GPU內存的要求,。 研究發(fā)現,,使用LoRA進行的微調質量與全模型微調相當,速度更快并且需要更少的計算,。因此,,如果有低延遲和低內存需求的情況,建議使用LoRA微調,。

其次,,我們再來看看為什么會有LLaMA模型和LoRA兩種模型

如上所述,模型的微調方式有很多種,,基于LoRA的微調產生保存了新的權重,,可以將生成的LoRA權重認為是一個原來LLaMA模型的補丁權重 。至于LLaMA 權重,,它則是由Mean公司開源的大模型預訓練權重,。

最后,我們來看看關于詞表擴充,,為什么要擴充詞表,,直接在原版LLaMA上用中文預訓練不行?

本身LLaMA對中文支持不是很好,,大多數相關衍生工作是直接在原版上進行pretrain/finetune的,,從而采取了更大膽的策略——增加中文詞表,可能進一步加劇中文訓練不充分的問題,,但從長遠看是否有利于后續(xù)進一步預訓練就得靠時間檢驗了,,加入詞表是有一定破壞性的,一是破壞原有分詞體系,,二是增加了未訓練的權重,。所以如果不能進行充分訓練的話,,可能會有比較大的問題。如果不是特別專的領域(比如生物醫(yī)學等涉及很多專業(yè)詞匯的領域)沒有太大必要去擴充英文詞表,。

原版LLaMA模型的詞表大小是32K,,其主要針對英語進行訓練(具體詳見LLaMA論文),對多語種支持不是特別理想(可以對比一下多語言經典模型XLM-R的詞表大小為250K),。通過初步統(tǒng)計發(fā)現,,LLaMA詞表中僅包含很少的中文字符,所以在切詞時會把中文切地更碎,,需要多個byte token才能拼成一個完整的漢字,,進而導致信息密度降低。

比如,,在擴展詞表后的模型中,,單個漢字傾向于被切成1個token,而在原版LLaMA中可能就需要2-3個才能組合成一個漢字,,顯著降低編解碼的效率,。

由于原版LLaMA對中文的支持非常有限,Chinese-LLaMA-Alpaca項目在原版LLaMA的基礎上進一步擴充了中文詞表,。在通用中文語料上訓練了基于sentencepiece的20K中文詞表并與原版LLaMA模型的32K詞表進行合并,,排除重復的token后,得到的最終中文LLaMA詞表大小為49953,。需要注意的是,,在fine-tune階段Alpaca比LLaMA多一個pad token,所以中文Alpaca的詞表大小為49954,。

為了進一步加深對lora的理解,,本文主要從LoRA基本原理及PEFT中的實現、基于mt0-large+lora的完整實踐兩方面進行介紹,,供大家一起參考,。

一,、LoRA基本原理及PEFT中的實現

當前,已經出現了很多l(xiāng)ora作為adapter的微調模型,,如Alpaca LoRA,,Chinese-LLaMA-Alpaca等,其在公開時會注明:中文LLaMA/Alpaca LoRA模型無法單獨使用,,需要搭配原版LLaMA模型,,發(fā)布的是LoRA權重,可以理解為原LLaMA模型上的一個“補丁”,,兩者進行合并即可獲得完整版權重,。

圖片

LoRA的實現原理在于,凍結預訓練模型權重,,并將可訓練的秩分解矩陣注入到Transformer層的每個權重中,,大大減少了下游任務的可訓練參數數量。直白的來說,,實際上是增加了右側的“旁支”,,也就是先用一個Linear層A,將數據從 d維降到r,,再用第二個Linear層B,,將數據從r變回d維。最后再將左右兩部分的結果相加融合,,得到輸出的hidden_state,。

圖片

如上圖所示,左邊是預訓練模型的權重,,輸入輸出維度都是d,,在訓練期間被凍結,不接受梯度更新,。右邊部分對A使用隨機的高斯初始化,,B在訓練開始時為零,r是秩,,會對△Wx做縮放 α/r,。

圖片

幸運的是,HuggingFace的PEFT(Parameter-Efficient Fine-Tuning,,地址:https://github.com/huggingface/peft)中提供了模型微調加速的方法,,參數高效微調(PEFT)方法能夠使預先訓練好的語言模型(PLMs)有效地適應各種下游應用,而不需要對模型的所有參數進行微調,。

對大規(guī)模的PLM進行微調往往成本過高,,在這方面,PEFT方法只對少數(額外的)模型參數進行微調,基本思想在于僅微調少量 (額外) 模型參數,,同時凍結預訓練 LLM 的大部分參數,,從而大大降低了計算和存儲成本,這也克服了災難性遺忘的問題,,這是在 LLM 的全參數微調期間觀察到的一種現象PEFT 方法也顯示出在低數據狀態(tài)下比微調更好,,可以更好地泛化到域外場景。

例如,,使用PEFT-lora進行加速微調的效果如下,,從中我們可以看到該方案的優(yōu)勢:

圖片

例如,其對LoRA做了封裝支持,,幾步即可使用:

from peft import get_peft_model, LoraConfig, TaskType

peft_config = LoraConfig(
    task_type=TaskType.CAUSAL_LM, 
    inference_mode=False, 
    r=8, 
    lora_alpha=32, 
    lora_dropout=0.1,
    target_modules=['query_key_value']
)

model = "加載的模型"
model = get_peft_model(model, peft_config)
model.print_trainable_parameters()

論文中提到了LoRA的一些優(yōu)勢:

1)一個預先訓練好的模型可以被共享,,并用于為不同的任務建立許多小的LoRA模塊??梢詢鼋Y共享模型,,并通過替換圖中的矩陣A和B來有效地切換任務,大大降低了存儲需求和任務切換的難度,。

2)在使用自適應優(yōu)化器時,,LoRA使訓練更加有效,并將硬件進入門檻降低了3倍,,因為我們不需要計算梯度或維護大多數參數的優(yōu)化器狀態(tài),。相反,我們只優(yōu)化注入的,、小得多的低秩矩陣,。

3)簡單的線性設計允許在部署時將可訓練矩陣與凍結權重合并,與完全微調的模型相比,,在結構上沒有引入推理延遲,。

4)LoRA與許多先前的方法是正交的,可以與許多方法結合,,如前綴調整,。我們在附錄E中提供了一個例子。

1,、引入開源組件

”+”表示增加代碼:

  from transformers import AutoModelForSeq2SeqLM
+ from peft import get_peft_model, LoraConfig, TaskType 
  model_name_or_path = "bigscience/mt0-large"
  tokenizer_name_or_path = "bigscience/mt0-large"

2,、引入lora配置信息

peft_config = LoraConfig(
    task_type=TaskType.SEQ_2_SEQ_LM, 
    inference_mode=False, 
    r=8, 
    lora_alpha=32, 
    lora_dropout=0.1
)

3、進行推理

  from transformers import AutoModelForSeq2SeqLM
+ from peft import PeftModel, PeftConfig

  peft_model_id = "smangrul/twitter_complaints_bigscience_T0_3B_LORA_SEQ_2_SEQ_LM"
  config = PeftConfig.from_pretrained(peft_model_id)
  model = AutoModelForSeq2SeqLM.from_pretrained(config.base_model_name_or_path)
+ model = PeftModel.from_pretrained(model, peft_model_id)
  tokenizer = AutoTokenizer.from_pretrained(config.base_model_name_or_path)

  model = model.to(device)
  model.eval()
  inputs = tokenizer("Tweet text : @HondaCustSvc Your customer service has been horrible during the recall process. I will never purchase a Honda again. Label :", return_tensors="pt")

  with torch.no_grad():
      outputs = model.generate(input_ids=inputs["input_ids"].to("cuda"), max_new_tokens=10)
      print(tokenizer.batch_decode(outputs.detach().cpu().numpy(), skip_special_tokens=True)[0])
# 'complaint'

二,、基于mt0-large+lora的完整實踐

接下來,,我們來使用huggingface-peft庫來進行一個lora的實踐。

首先,,在模型方面,,我們選用mt0-large模型為例(只有1.2b),,進行實驗,,模型地址:https:///bigscience/mt0-large,。

模型權重地址:https:///bigscience/mt0-large/tree/main

圖片

先看看mt0-large是什么。多任務提示微調(MTF)已被證明可以幫助大型語言模型在zero-shot的環(huán)境下生成新的任務,,但到目前為止,,MTF的探索主要集中在英語數據和模型上,將MTF應用于預訓練的多語言BLOOM和mT5模型系列,,就產生稱為BLOOMZ和mT0的微調變體,。

具體的,總共生產了三種不同尺寸的核心型號:

  • BLOOMZ-P3 / mT0-P3:在純英語的P3上進行微調的模型,。

  • BLOOMZ / mT0: 在xP3上進行微調的模型,,xP3由帶有英語提示的多語言數據集組成。

  • BLOOMZ-MT / mT0-MT: 在xP3mt上進行模型微調,,xP3mt由多語言數據集和機器翻譯的提示語組成,。

圖片

其次,在任務方面,,我們選用金融領域情感分析任務financial_sentiment_analysis,,給定一個句子,要求識別出該句子是negative,、positive還是neutral三個中的哪一個,,其中的數據樣式如下:

{'sentence'"The 10,000-odd square metre plot that Stockmann has bought for the Nevsky Center shopping center is located on Nevsky Prospect , St Petersburg 's high street , next to the Vosstaniya Square underground station , in the immediate vicinity of Moscow Station .",
 'label': 1,
 'text_label''neutral'}

我們可以通過datasests組件進行調用。

1,、引入組件并設置參數

from transformers import AutoModelForSeq2SeqLM
from peft import get_peft_config, get_peft_model, get_peft_model_state_dict, LoraConfig, TaskType
import torch
from datasets import load_dataset
import os
os.environ["TOKENIZERS_PARALLELISM"] = "false"
from transformers import AutoTokenizer
from torch.utils.data import DataLoader
from transformers import default_data_collator, get_linear_schedule_with_warmup
from tqdm import tqdm
from datasets import load_dataset
device = "cuda"
model_name_or_path = "bigscience/mt0-large"
tokenizer_name_or_path = "bigscience/mt0-large"
checkpoint_name = "financial_sentiment_analysis_lora_v1.pt"
text_column = "sentence"
label_column = "text_label"
max_length = 128
lr = 1e-3
num_epochs = 3
batch_size = 8

2,、搭建模型

peft_config = LoraConfig(task_type=TaskType.SEQ_2_SEQ_LM, inference_mode=False, r=8, lora_alpha=32, lora_dropout=0.1)

model = AutoModelForSeq2SeqLM.from_pretrained(model_name_or_path)
model = get_peft_model(model, peft_config)
model.print_trainable_parameters()

3、加載數據

dataset = load_dataset("financial_phrasebank""sentences_allagree")
dataset = dataset["train"].train_test_split(test_size=0.1)
dataset["validation"] = dataset["test"]
del dataset["test"]

classes = dataset["train"].features["label"].names
dataset = dataset.map(
    lambda x: {"text_label": [classes[label] for label in x["label"]]},
    batched=True,
    num_proc=1,
)

4,、訓練數據預處理

tokenizer = AutoTokenizer.from_pretrained(model_name_or_path)

def preprocess_function(examples):
    inputs = examples[text_column]
    targets = examples[label_column]
    model_inputs = tokenizer(inputs, max_length=max_length, padding="max_length", truncation=True, return_tensors="pt")
    labels = tokenizer(targets, max_length=3, padding="max_length", truncation=True, return_tensors="pt")
    labels = labels["input_ids"]
    labels[labels == tokenizer.pad_token_id] = -100
    model_inputs["labels"] = labels
    return model_inputs


processed_datasets = dataset.map(
    preprocess_function,
    batched=True,
    num_proc=1,
    remove_columns=dataset["train"].column_names,
    load_from_cache_file=False,
    desc="Running tokenizer on dataset",
)

train_dataset = processed_datasets["train"]
eval_dataset = processed_datasets["validation"]

train_dataloader = DataLoader(
    train_dataset, shuffle=True, collate_fn=default_data_collator, batch_size=batch_size, pin_memory=True
)
eval_dataloader = DataLoader(eval_dataset, collate_fn=default_data_collator, batch_size=batch_size, pin_memory=True)

5,、設定優(yōu)化器和正則項

optimizer = torch.optim.AdamW(model.parameters(), lr=lr)
lr_scheduler = get_linear_schedule_with_warmup(
    optimizer=optimizer,
    num_warmup_steps=0,
    num_training_steps=(len(train_dataloader) * num_epochs),
)

6、訓練與評估

model = model.to(device)

for epoch in range(num_epochs):
    model.train()
    total_loss = 0
    for step, batch in enumerate(tqdm(train_dataloader)):
        batch = {k: v.to(device) for k, v in batch.items()}
        outputs = model(**batch)
        loss = outputs.loss
        total_loss += loss.detach().float()
        loss.backward()
        optimizer.step()
        lr_scheduler.step()
        optimizer.zero_grad()

    model.eval()
    eval_loss = 0
    eval_preds = []
    for step, batch in enumerate(tqdm(eval_dataloader)):
        batch = {k: v.to(device) for k, v in batch.items()}
        with torch.no_grad():
            outputs = model(**batch)
        loss = outputs.loss
        eval_loss += loss.detach().float()
        eval_preds.extend(
            tokenizer.batch_decode(torch.argmax(outputs.logits, -1).detach().cpu().numpy(), skip_special_tokens=True)
        )

    eval_epoch_loss = eval_loss / len(eval_dataloader)
    eval_ppl = torch.exp(eval_epoch_loss)
    train_epoch_loss = total_loss / len(train_dataloader)
    train_ppl = torch.exp(train_epoch_loss)
    print(f"{epoch=}: {train_ppl=} {train_epoch_loss=} {eval_ppl=} {eval_epoch_loss=}")

執(zhí)行訓練日志輸出如下:

100%|████████████████████████████████████████████████████████████████████████████████████████| 255/255 [02:21<00:00,  1.81it/s]
100%|██████████████████████████████████████████████████████████████████████████████████████████| 29/29 [00:07<00:00,  4.13it/s]
epoch=0: train_ppl=tensor(14.6341, device='cuda:0') train_epoch_loss=tensor(2.6834, device='cuda:0') eval_ppl=tensor(1.0057, device='cuda:0') eval_epoch_loss=tensor(0.0057, device='cuda:0')
100%|████████████████████████████████████████████████████████████████████████████████████████| 255/255 [02:00<00:00,  2.11it/s]
100%|██████████████████████████████████████████████████████████████████████████████████████████| 29/29 [00:05<00:00,  5.66it/s]
epoch=1: train_ppl=tensor(1.7576, device='cuda:0') train_epoch_loss=tensor(0.5640, device='cuda:0') eval_ppl=tensor(1.0052, device='cuda:0') eval_epoch_loss=tensor(0.0052, device='cuda:0')
100%|████████████████████████████████████████████████████████████████████████████████████████| 255/255 [01:33<00:00,  2.74it/s]
100%|██████████████████████████████████████████████████████████████████████████████████████████| 29/29 [00:04<00:00,  6.23it/s]
epoch=2: train_ppl=tensor(1.3830, device='cuda:0') train_epoch_loss=tensor(0.3243, device='cuda:0') eval_ppl=tensor(1.0035, device='cuda:0') eval_epoch_loss=tensor(0.0035, device='cuda:0')

7,、模型保存

peft_model_id = f"{model_name_or_path}_{peft_config.peft_type}_{peft_config.task_type}"
model.save_pretrained(peft_model_id)

8,、模型推理預測

from peft import PeftModel, PeftConfig
peft_model_id = f"{model_name_or_path}_{peft_config.peft_type}_{peft_config.task_type}"
config = PeftConfig.from_pretrained(peft_model_id)
model = AutoModelForSeq2SeqLM.from_pretrained(config.base_model_name_or_path)
model = PeftModel.from_pretrained(model, peft_model_id)
model.eval()

inputs = tokenizer(dataset["validation"][text_column][i], return_tensors="pt")
print(dataset["validation"][text_column][i])
print(inputs)
with torch.no_grad():
    outputs = model.generate(input_ids=inputs["input_ids"], max_new_tokens=10)
    print(outputs)
    print(tokenizer.batch_decode(outputs.detach().cpu().numpy(), skip_special_tokens=True))
    

運行實例,例如輸入:

Demand for fireplace products was lower than expected , especially in Germany .

輸出:


{'input_ids': tensor([[  259,   264,   259, 82903,   332,  1090, 10040, 10371,   639,   259,
         19540,  2421,   259, 25505,   259,   261,   259, 21230,   281, 17052,
           259,   260,     1]]), 'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]])}
tensor([[    0,   259, 32588,     1]])
['negative']

總結

本文主要從LoRA基本原理及PEFT中的實現,、基于mt0-large+lora的完整實踐兩方面進行了介紹,。關于進一步的細節(jié),我們可以熟悉原理后,,可以進行動手實踐,,加深理解。

參考文獻

1,、https://zhuanlan.zhihu.com/p/400790006
2,、https://blog.csdn.net/qq_39388410/article/details/121036309
3,、https://github.com/ymcui/Chinese-LLaMA-Alpaca

關于我們

老劉,劉煥勇,,NLP開源愛好者與踐行者,,主頁:https://liuhuanyong.。

就職于360人工智能研究院,、曾就職于中國科學院軟件研究所,。

老劉說NLP,將定期發(fā)布語言資源,、工程實踐,、技術總結等內容,歡迎關注,。

,。

    本站是提供個人知識管理的網絡存儲空間,所有內容均由用戶發(fā)布,,不代表本站觀點,。請注意甄別內容中的聯系方式、誘導購買等信息,,謹防詐騙,。如發(fā)現有害或侵權內容,請點擊一鍵舉報,。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章