AI算法 | 如何訓(xùn)練自己的大模型?
1、第一階段:二次預(yù)訓(xùn)練
模型選擇與轉(zhuǎn)換
在開始訓(xùn)練之前,需要選擇一個(gè)合適的基礎(chǔ)模型。本文以LLaMA-7B為例,簡(jiǎn)單介紹下。為了方便后續(xù)的操作,將LLaMA-7B模型轉(zhuǎn)換為Hugging Face格式。
from transformers import AutoModelForCausalLM, AutoTokenizer
# 加載原始LLaMA模型
model_path = "original_llama_7b"
tokenizer = AutoTokenizer.from_pretrained(model_path)
model = AutoModelForCausalLM.from_pretrained(model_path)
# 保存為Hugging Face格式
hf_path = "llama_7b_hf"
model.save_pretrained(hf_path)
tokenizer.save_pretrained(hf_path)
此外,為了更好地處理中文文本,還需要擴(kuò)充中文詞表??梢詤⒖糃hinese-LLaMA項(xiàng)目,它在原始詞表的基礎(chǔ)上新增了大量漢字token,從而讓模型能夠更好地理解和生成中文內(nèi)容。
from transformers import AddedToken
# 加載原始tokenizer
tokenizer = AutoTokenizer.from_pretrained("llama_7b_hf")
# 添加中文字符
new_tokens = ["中文", "中國(guó)", "人工智能"] # 實(shí)際應(yīng)用中需要更全面的詞表
new_tokens = [AddedToken(token) for token in new_tokens]
# 擴(kuò)充詞表
tokenizer.add_tokens(new_tokens)
model.resize_token_embeddings(len(tokenizer))
# 保存擴(kuò)充后的tokenizer
tokenizer.save_pretrained("llama_7b_zh_extended")
數(shù)據(jù)準(zhǔn)備
數(shù)據(jù)是訓(xùn)練模型的關(guān)鍵。需要根據(jù)任務(wù)需求收集海量的中文文本數(shù)據(jù)。例如,這些數(shù)據(jù)可以來(lái)自中文維基百科、新聞文章、小說(shuō)等多個(gè)領(lǐng)域。這樣可以確保模型能夠?qū)W習(xí)到豐富的知識(shí)。在收集數(shù)據(jù)之后,還需要對(duì)數(shù)據(jù)進(jìn)行清洗和預(yù)處理,去除其中的噪聲和無(wú)關(guān)內(nèi)容,以保證數(shù)據(jù)的質(zhì)量。
下面是一個(gè)簡(jiǎn)單的清晰流程實(shí)例:
def clean_text(text):
# 去除HTML標(biāo)簽
text = re.sub(r'<[^>]+>', '', text)
# 去除特殊字符和多余空格
text = re.sub(r'\s+', ' ', text).strip()
# 其他自定義清洗規(guī)則
return text
# 假設(shè)我們有一個(gè)文本文件列表
text_files = ["data/wiki_zh.txt", "data/news_zh.txt"]
cleaned_data = []
for file in text_files:
with open(file, 'r', encoding='utf-8') as f:
for line in tqdm(f):
cleaned = clean_text(line)
if len(cleaned) > 10: # 過(guò)濾過(guò)短文本
cleaned_data.append(cleaned)
# 保存清洗后的數(shù)據(jù)
with open("cleaned_zh_data.txt", 'w', encoding='utf-8') as f:
f.write('\n'.join(cleaned_data))
訓(xùn)練設(shè)置
為了降低計(jì)算資源的需求,可以使用LoRA(Low-Rank Adaptation)技術(shù)進(jìn)行二次預(yù)訓(xùn)練。LoRA通過(guò)在模型中添加低秩矩陣來(lái)實(shí)現(xiàn)高效的微調(diào),大大減少了需要訓(xùn)練的參數(shù)數(shù)量。例如,原本全參微調(diào)7B模型需要8卡A100,使用LoRA后,單卡3090就足夠了。此外,還需要設(shè)置合適的超參數(shù),如學(xué)習(xí)率、批次大小等。這些超參數(shù)可以根據(jù)實(shí)驗(yàn)結(jié)果進(jìn)行調(diào)整,以達(dá)到更好的訓(xùn)練效果。
from transformers import Trainer, TrainingArguments
from peft import LoraConfig, get_peft_model
# 配置LoRA
lora_config = LoraConfig(
r=8, # 低秩矩陣的維度
lora_alpha=32,
target_modules=["q_proj", "v_proj"], # 對(duì)query和value矩陣進(jìn)行適配
lora_dropout=0.05,
bias="none",
task_type="CAUSAL_LM"
)
# 應(yīng)用LoRA到模型
model = get_peft_model(model, lora_config)
model.print_trainable_parameters() # 查看可訓(xùn)練參數(shù)數(shù)量
# 準(zhǔn)備訓(xùn)練參數(shù)
training_args = TrainingArguments(
output_dir="./output",
overwrite_output_dir=True,
num_train_epochs=3,
per_device_train_batch_size=4,
save_steps=10_000,
save_total_limit=2,
learning_rate=1e-4,
fp16=True,
logging_steps=100,
evaluation_strategy="steps",
eval_steps=5_000,
load_best_model_at_end=True
)
# 創(chuàng)建數(shù)據(jù)集
from datasets import load_dataset
dataset = load_dataset("text", data_files={"train": "cleaned_zh_data.txt"})
# 開始訓(xùn)練
trainer = Trainer(
model=model,
args=training_args,
train_dataset=dataset["train"],
tokenizer=tokenizer
)
trainer.train()
2、第二階段:指令微調(diào)
數(shù)據(jù)準(zhǔn)備
在第一階段的預(yù)訓(xùn)練之后,需要對(duì)模型進(jìn)行指令微調(diào),以使其能夠更好地理解和執(zhí)行指令。為此,需要構(gòu)造指令微調(diào)數(shù)據(jù)集,這些數(shù)據(jù)集包括中文指令和對(duì)應(yīng)的回答??梢詤⒖糀lpaca-CoT項(xiàng)目,它提供了豐富的指令數(shù)據(jù)集。如果模型需要應(yīng)用于特定的領(lǐng)域,如金融領(lǐng)域,還可以收集相關(guān)的領(lǐng)域指令數(shù)據(jù)。
訓(xùn)練設(shè)置
在第一階段的預(yù)訓(xùn)練模型基礎(chǔ)上進(jìn)行指令微調(diào)。同樣可以使用LoRA技術(shù),進(jìn)一步降低計(jì)算成本。如果希望模型更好地理解下游任務(wù)信息,可以將指令微調(diào)數(shù)據(jù)集拼接成文檔格式,放入第一階段進(jìn)行增量預(yù)訓(xùn)練。
訓(xùn)練過(guò)程
使用FT(Full-Tuning)+LoRA SFT(Sparse Fine-Tuning)的方式進(jìn)行微調(diào)。在訓(xùn)練過(guò)程中,模型會(huì)學(xué)習(xí)如何更好地理解和執(zhí)行指令。為了確保模型的性能,需要定期評(píng)估模型在指令微調(diào)數(shù)據(jù)集上的表現(xiàn),并根據(jù)評(píng)估結(jié)果調(diào)整訓(xùn)練策略。
from transformers import DataCollatorForLanguageModeling
# 加載預(yù)訓(xùn)練模型
model = AutoModelForCausalLM.from_pretrained("./output/checkpoint-final")
tokenizer = AutoTokenizer.from_pretrained("llama_7b_zh_extended")
# 準(zhǔn)備數(shù)據(jù)集
def preprocess_function(examples):
texts = []
for inst in examples["text"]:
try:
data = json.loads(inst)
text = f"指令:{data['instruction']}\n輸入:{data['input']}\n輸出:{data['output']}"
texts.append(text)
except:
continue
return tokenizer(texts, truncatinotallow=True, max_length=512)
dataset = load_dataset("json", data_files={"train": "instruction_data.json"})
tokenized_dataset = dataset.map(preprocess_function, batched=True)
# 數(shù)據(jù)收集器
data_collator = DataCollatorForLanguageModeling(
tokenizer=tokenizer,
mlm=False
)
# 微調(diào)參數(shù)
training_args = TrainingArguments(
output_dir="./sft_output",
per_device_train_batch_size=4,
num_train_epochs=5,
learning_rate=5e-5,
fp16=True,
save_steps=10_000,
logging_steps=100,
evaluation_strategy="no",
)
# 開始微調(diào)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=tokenized_dataset["train"],
data_collator=data_collator,
tokenizer=tokenizer
)
trainer.train()
低成本方案
例如8-bit優(yōu)化:
from transformers import BitsAndBytesConfig
quantization_config = BitsAndBytesConfig(
load_in_8bit=True,
llm_int8_threshold=6.0
)
model = AutoModelForCausalLM.from_pretrained(
"llama_7b_hf",
quantization_cnotallow=quantization_config
)
3、注意事項(xiàng)
- 數(shù)據(jù)質(zhì)量:在實(shí)際應(yīng)用中,數(shù)據(jù)清洗和預(yù)處理的邏輯可能需要根據(jù)具體數(shù)據(jù)進(jìn)行調(diào)整。
- 超參數(shù)調(diào)整:超參數(shù)(如學(xué)習(xí)率、批次大小、LoRA的秩等)需要根據(jù)實(shí)驗(yàn)結(jié)果進(jìn)行調(diào)整。
- 模型評(píng)估:在訓(xùn)練過(guò)程中,建議定期在驗(yàn)證集上評(píng)估模型性能,以確保模型沒有過(guò)擬合。