使用 QLoRa 微調 Llama2(附代碼實戰)
本文將介紹使用 PEFT 庫和 QLoRa 方法對 Llama 27b 預訓練模型進行微調。我們將使用自定義數據集來構建情感分析模型。只有可以對數據進行微調我們纔可以將這種大模型進行符合我們數據集的定製化。
一些前置的知識
如果熟悉 Google Colab、Weights & Biases (W&B)、HF 庫,可以跳過這一節。
雖然 Google Colab(託管的 Jupyter 筆記本環境) 不是真正的先決條件,但我們建議使用它來訪問 GPU 並進行快速實驗。如果是付費的用戶,則可以使用高級 GPU 訪問,比如 A100 這樣的 GPU。
W&B 帳戶的作用是記錄進度和訓練指標,這個如果不需要也可以用 tensorboard 替代,但是我們是演示 Google Colab 環境所以直接用它。
然後就是需要一個 HF 帳戶。然後轉到 settings,創建至少具有讀權限的 API 令牌。因爲在訓練腳本時將使用它下載預訓練的 Llama 2 模型和數據集。
最後就是請求訪問 Llama 2 模型。等待 Meta AI 和 HF 的郵件。這可能要 1-2 天。
準備數據集
指令微調是一種常用技術,用於爲特定的下游用例微調基本 LLM。訓練示例如下:
Below is an instruction that describes a sentiment analysis task...
### Instruction:
Analyze the following comment and classify the tone as...
### Input:
I love reading your articles...
### Response:
friendly & constructive
我們建議使用 json,因爲這樣比較靈活。比如爲每個示例創建一個 JSON 對象,其中只有一個文本字段。像這樣:
{ "text": "Below is an instruction ... ### Instruction: Analyze the... ### Input: I love... ### Response: friendly" },
{ "text": "Below is an instruction ... ### Instruction: ..." }
有很多很多方法可以提取原始數據、處理和創建訓練數據集作爲 json 文件。下面是一個簡單的腳本:
with open('train.jsonl', 'a') as outfile:
for example in raw_data:
text = '<process_example>'
# now append entry to the jsonl file.
outfile.write('{"text": "' + text + '"}')
outfile.write('\n')
如 HF 的 Datasets 庫也是一個選擇,但是我個人覺得他不好用。
在我們開始訓練之前,我們要將文件作爲數據集存儲庫推送到 HF。可以直接使用 huggingface-cli 上傳數據集。
訓練
Parameter-Efficient Fine-Tuning(PEFT) 可以用於在不觸及 LLM 的所有參數的情況下對 LLM 進行有效的微調。PEFT 支持 QLoRa 方法,通過 4 位量化對 LLM 參數的一小部分進行微調。
Transformer Reinforcement Learning (TRL)是一個使用強化學習來訓練語言模型的庫。TRL 也提供的監督微調 (SFT) 訓練器 API 可以讓我們快速的微調模型。
!pip install -q huggingface_hub
!pip install -q -U trl transformers accelerate peft
!pip install -q -U datasets bitsandbytes einops wandb
# Uncomment to install new features that support latest models like Llama 2
# !pip install git+https://github.com/huggingface/peft.git
# !pip install git+https://github.com/huggingface/transformers.git
# When prompted, paste the HF access token you created earlier.
from huggingface_hub import notebook_login
notebook_login()
from datasets import load_dataset
import torch
from transformers import AutoModelForCausalLM, BitsAndBytesConfig, AutoTokenizer, TrainingArguments
from peft import LoraConfig
from trl import SFTTrainer
dataset_name = "<your_hf_dataset>"
dataset = load_dataset(dataset_name, split="train")
base_model_name = "meta-llama/Llama-2-7b-hf"
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.float16,
)
device_map = {"": 0}
base_model = AutoModelForCausalLM.from_pretrained(
base_model_name,
quantization_config=bnb_config,
device_map=device_map,
trust_remote_code=True,
use_auth_token=True
)
base_model.config.use_cache = False
# More info: https://github.com/huggingface/transformers/pull/24906
base_model.config.pretraining_tp = 1
peft_config = LoraConfig(
lora_alpha=16,
lora_dropout=0.1,
r=64,
bias="none",
task_type="CAUSAL_LM",
)
tokenizer = AutoTokenizer.from_pretrained(base_model_name, trust_remote_code=True)
tokenizer.pad_token = tokenizer.eos_token
output_dir = "./results"
training_args = TrainingArguments(
output_dir=output_dir,
per_device_train_batch_size=4,
gradient_accumulation_steps=4,
learning_rate=2e-4,
logging_steps=10,
max_steps=500
)
max_seq_length = 512
trainer = SFTTrainer(
model=base_model,
train_dataset=dataset,
peft_config=peft_config,
dataset_text_field="text",
max_seq_length=max_seq_length,
tokenizer=tokenizer,
args=training_args,
)
trainer.train()
import os
output_dir = os.path.join(output_dir, "final_checkpoint")
trainer.model.save_pretrained(output_dir)
上面的腳本就是一個微調的簡單代碼,這裏可以添加命令行參數解析器模塊,如 HfArgumentParser,這樣就不必硬編碼這些值。
quantization_config 是用於量化(quantization)模型的配置參數。量化是一種將浮點模型轉換爲具有低位精度(如 8 位整數)的模型的技術,以減少模型的內存使用和推斷時間,並在硬件上實現加速。
在 Hugging Face Transformers 庫中,quantization_config 是可選參數,可以傳遞給 AutoModel.from_pretrained()、AutoModelForSequenceClassification.from_pretrained() 等函數,用於指定量化模型的具體方式。具體來說,該參數是一個字典,可以包含以下鍵值對:
-
weight: 用於量化模型權重的配置。可以是字符串 "qconfig" 或自定義的 QConfig 對象。
-
activation: 用於量化激活值的配置。可以是字符串 "qconfig" 或自定義的 QConfig 對象。
-
bias: 用於量化偏置值的配置。可以是字符串 "qconfig" 或自定義的 QConfig 對象。
-
static:是否使用靜態量化。如果爲 True,則在訓練期間計算模型的統計量,然後將這些統計量用於量化。如果爲 False,則在推理時計算統計量。
-
dynamic:是否使用動態量化。如果爲 True,則在推理時計算統計量,並根據這些統計量進行量化。
-
dtype: 量化後權重的數據類型。可以是 torch.qint8 或 torch.qint32。
-
reduce_range: 是否對權重的值進行縮放,以使其適合量化後的數據類型的範圍。如果爲 True,則在量化過程中將權重的範圍縮小到 [-128, 127] 或[-2^31, 2^31-1],具體取決於數據類型。如果爲 False,則不進行範圍縮放。
-
equalization: 是否使用均衡化(equalization)技術來量化權重。均衡化是一種將權重分配到不同的量化級別的技術,以使得不同的權重值之間的差異最小化。
-
float16: 是否將權重量化爲 float16 數據類型。
需要注意的是,quantization_config 參數只有在使用支持量化的硬件或庫時纔有意義。如果使用不支持量化的硬件或庫,則該參數將被忽略。此外,量化可能會對模型的精度造成一定的影響,因此需要根據具體情況進行權衡。
傳遞給 quantization_config 的配置解釋如下:
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.float16,
)
這段代碼是用於配置 BitsAndBytes 量化模型的參數。BitsAndBytes 是一種基於 pytorch 的量化方法,可以將模型的權重和激活值量化爲多種不同位數的整數,並將其存儲爲字節流形式,從而減少模型的內存佔用和推理時間。具體來說,該代碼使用 BitsAndBytesConfig 類來創建一個配置對象,並設置了以下參數:
-
load_in_4bit: 是否將模型中的 4 位量化權重加載到模型中。如果爲 True,則會從模型中加載 4 位量化權重,否則會加載 8 位量化權重。
-
bnb_4bit_quant_type: 4 位量化的類型。可以是字符串 "nf4",表示使用 near-float4 的量化方法;也可以是字符串 "tf",表示使用 TensorFlow 的量化方法。
-
bnb_4bit_compute_dtype: 用於計算 4 位量化權重的數據類型。可以是 torch.float16,表示使用半精度浮點數來計算量化權重。
需要注意的是,BitsAndBytes 量化方法是一種基於權重的量化方法,只對模型的權重進行量化,並不對激活值進行量化。因此,對於一些激活值範圍較大的模型,使用 BitsAndBytes 量化方法可能會導致精度下降。另外,需要根據具體的應用場景和模型要求進行權衡和選擇,選擇合適的量化方法和參數。
測試
下面時一個簡單的加載模型並進行完整性測試的快速方法。
from peft import AutoPeftModelForCausalLM
model = AutoPeftModelForCausalLM.from_pretrained(output_dir, device_map=device_map, torch_dtype=torch.bfloat16)
text = "..."
inputs = tokenizer(text, return_tensors="pt").to(device)
outputs = model.generate(input_ids=inputs["input_ids"].to("cuda"), attention_mask=inputs["attention_mask"], max_new_tokens=50, pad_token_id=tokenizer.eos_token_id)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))
這樣就能夠查看我們的結果了。
本文作者: UD
原文地址:
https://ukey.co/blog/finetune-llama-2-peft-qlora-huggingface/
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/EI9Y8mVdlq3UN45nKKOgNQ