一、LoRA
? ? ? ? ? ?簡單來說,LoRA不直接調整個大模型的全部參數(那樣太費資源),而是在模型的某些層(通常是注意力層)加個“旁路”——兩個小的矩陣(低秩矩陣)。訓練時只更新這倆小矩陣,原模型凍住不動。這樣既省內存,又能快速適配新任務。
? ? ? ?大模型就像一座豪華大宅,里面房間多、家具全,但裝修風格已經固定。LoRA就像給某些關鍵房間(比如客廳、廚房)加裝了智能化的小設備(比如智能燈、智能窗簾)。你不用翻新整個大宅,只調整這些小設備,就能讓房子適應新的生活需求,比如自動調節燈光或開窗通風。雖然改動不大,但住起來照樣舒服,甚至更適合你的習慣。
舉個例子
? ? ? ? 假設你部署的是LLaMA-7B
,想讓它學會用中文寫詩:
- 數據:收集1000首中文古詩,格式是純文本。
- LoRA配置:
r=16
,?target_modules=["q_proj", "v_proj"]
。 - 訓練:跑3輪,每輪500步,顯存8GB夠用。
- 結果:輸入“春風”,它能生成“春風拂面柳絲輕”之類。
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import LoraConfig, get_peft_model
import torch
from datasets import load_dataset# 加載 LLaMA-7B 模型和分詞器
model_name = "meta-llama/Llama-2-7b-hf" # 假設使用 LLaMA-7B
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(model_name, torch_dtype=torch.float16, device_map="auto")# 配置 LoRA
lora_config = LoraConfig(r=16, # 低秩矩陣的秩lora_alpha=32, # 縮放因子target_modules=["q_proj", "v_proj"], # 目標模塊lora_dropout=0.05, # Dropoutbias="none",task_type="CAUSAL_LM"
)# 應用 LoRA 到模型
model = get_peft_model(model, lora_config)# 加載中文古詩數據集(假設是純文本格式)
dataset = load_dataset("text", data_files={"train": "chinese_poetry.txt"})
def tokenize_function(examples):return tokenizer(examples["text"], padding="max_length", truncation=True, max_length=128)tokenized_dataset = dataset.map(tokenize_function, batched=True)# 配置訓練參數
from transformers import TrainingArguments, Trainertraining_args = TrainingArguments(output_dir="./lora_poetry",num_train_epochs=3, # 訓練 3 輪per_device_train_batch_size=4,save_steps=500,logging_steps=100,learning_rate=2e-4,fp16=True, # 使用混合精度訓練
)# 初始化 Trainer
trainer = Trainer(model=model,args=training_args,train_dataset=tokenized_dataset["train"],
)# 開始訓練
trainer.train()# 保存微調后的模型
model.save_pretrained("./lora_poetry_model")# 測試生成
input_text = "春風"
inputs = tokenizer(input_text, return_tensors="pt").to("cuda")
outputs = model.generate(**inputs, max_length=50)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))
# 輸出示例:春風拂面柳絲輕
二、P-Tuning
? ? ? ??P-Tuning不是直接改模型的權重,而是在輸入里加一些特殊的“虛擬詞”(可訓練的嵌入向量),這些詞的作用就像給模型下個指令,告訴它接下來該怎么處理任務。訓練時,只更新這些虛擬詞的參數,原模型保持凍結。這樣既省資源,又能快速適配新需求。
? ? ? ? 大模型是個聰明但固執的廚師,P-Tuning就像在菜譜開頭加幾句特別的“口令”(比如“做中式”、“少放鹽”),廚師不用改自己的烹飪習慣,但能按你的要求調整菜的風格。
舉個例子
假設你用的是LLaMA-7B,想讓它生成更幽默的中文對話:
- 數據:收集1000條幽默對話的文本數據。
- P-Tuning配置:添加10個虛擬詞(prompt tokens),嵌入維度與模型一致。
- 訓練:跑5輪,每輪300步,顯存6GB足以。
- 結果:輸入“今天心情如何?”,它可能回復“心情像Wi-Fi信號,滿格但偶爾掉線!”
通過這些虛擬詞,模型就像被“調教”出幽默風格,效果精準又高效。
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import PromptTuningConfig, get_peft_model, PromptTuningInit
import torch
from datasets import load_dataset# 加載模型和分詞器
model_name = "meta-llama/Llama-2-7b-hf"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(model_name, torch_dtype=torch.float16, device_map="auto")# 配置 P-Tuning
ptuning_config = PromptTuningConfig(task_type="CAUSAL_LM",prompt_tuning_init=PromptTuningInit.RANDOM,num_virtual_tokens=10, # 10 個虛擬詞tokenizer_name_or_path=model_name,
)# 應用 P-Tuning
model = get_peft_model(model, ptuning_config)# 加載幽默對話數據集
dataset = load_dataset("text", data_files={"train": "humor_dialog.txt"})
def tokenize_function(examples):return tokenizer(examples["text"], padding="max_length", truncation=True, max_length=128)tokenized_dataset = dataset.map(tokenize_function, batched=True)# 訓練參數
from transformers import TrainingArguments, Trainertraining_args = TrainingArguments(output_dir="./ptuning_humor",num_train_epochs=5,per_device_train_batch_size=4,save_steps=300,logging_steps=100,learning_rate=3e-4,fp16=True,
)# 初始化 Trainer
trainer = Trainer(model=model,args=training_args,train_dataset=tokenized_dataset["train"],
)# 訓練
trainer.train()# 保存模型
model.save_pretrained("./ptuning_humor_model")# 測試生成
input_text = "今天心情如何?"
inputs = tokenizer(input_text, return_tensors="pt").to("cuda")
outputs = model.generate(**inputs, max_length=50)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))
# 輸出示例:心情像Wi-Fi信號,滿格但偶爾掉線!