微调大语言模型
本文记录大语言模型微调流程,供自己学习使用。
LLMs通过使用深度学习技术在大量文本数据上进行训练。这些模型能够生成类人的文本并执行各种自然语言处理(NLP)任务。最棒的部分是,你可以使用像Falcon、Llama-2、Mistral、Phi-2等LLMs进行研究和商业用途。
在本文中,对微软的Phi-2进行微调。
在开始微调之前,先了解一下LLM的训练过程。
在大型语言模型中,有两个主要的过程:预训练和微调。
预训练
预训练是模型训练的初期阶段,此时模型会接触到大量的未标记文本数据。在这一阶段,模型通过预测序列中的下一个词或填补缺失的词来学习语言中的结构、模式和关系。这一过程使模型能够建立对语法、句法和语义的基本理解,为后续的具体任务训练打下坚实的基础。
微调
另一方面,微调或指令调整是指在预训练模型的基础上,进一步在较小的数据集上进行训练,以适应特定任务或领域的过程。这一过程调整模型的参数,使其能够执行特定任务。例如,一个在多样化网页文章上预训练的模型可能在医疗问答任务上表现不佳。微调过程包括以下两种方法:
-
监督式微调(SFT):在SFT中,模型在标记数据集上进行训练。这些数据集通常包含与任务相关的指令(输入)和响应(输出)对。通过这个过程,模型学习如何针对特定指令做出响应。
-
通过人类反馈的强化学习(RLHF):在RLHF中,模型与用户互动,生成响应,并以强化信号的形式接收反馈。基本上,模型根据接收到的反馈来学习和提高性能。
相较于SFT,RLHF是一种更复杂且成本更高的微调技术,但对于难度较大的任务可能更有效。
首先导入相关库:
import os
import torch
from datasets import load_dataset
from transformers import (
AutoModelForCausalLM,
AutoTokenizer,
BitsAndBytesConfig,
AutoTokenizer,
TrainingArguments,
pipeline,
)
from peft import LoraConfig, PeftModel, prepare_model_for_kbit_training
from trl import SFTTrainer
数据准备:
---
导入模型:
# Config to load model with a 4-bit quantization, Quantization configuration
bnb_config = BitsAndBytesConfig(load_in_4bit=True,
bnb_4bit_quant_type='nf4',
bnb_4bit_compute_dtype='float32',
bnb_4bit_use_double_quant=True)
# Read PHI-2 model and tokenizer, load base model
model = AutoModelForCausalLM.from_pretrained(MODEL_PATH,
trust_remote_code=True,
quantization_config=bnb_config)
tokenizer = AutoTokenizer.from_pretrained(MODEL_PATH,
trust_remote_code=True)
tokenizer.pad_token = tokenizer.eos_token
上述代码配置并加载了一个使用4位量化的大型语言模型,具体步骤和各部分代码的功能如下:
-
配置量化(Quantization)参数:
bnb_config = BitsAndBytesConfig(load_in_4bit=True, ...)
load_in_4bit=True
: 这个参数指定模型加载时应用4位量化。4位量化可以减少模型大小和加速计算,但可能会影响精度。bnb_4bit_quant_type='nf4'
: 指定4位量化的类型,nf4
可能是一种特定的量化技术。bnb_4bit_compute_dtype='float32'
: 在进行量化计算时使用的数据类型为float32
。bnb_4bit_use_double_quant=True
: 可能意味着在量化过程中使用双重量化策略,以改善性能或精度。
-
加载预训练的模型:
model = AutoModelForCausalLM.from_pretrained(MODEL_PATH, ...)
AutoModelForCausalLM
: 这是一个自动化的模型加载器,用于因果语言模型(Causal Language Model),适用于生成任务如文本继续生成等。from_pretrained
: 这个函数负责加载预训练模型。MODEL_PATH
: 模型存储路径,指定从哪里加载模型。trust_remote_code=True
: 允许执行模型包中的远程代码,通常用于自定义的模型或特殊配置。quantization_config=bnb_config
: 应用上面定义的量化配置。
-
加载分词器(Tokenizer):
tokenizer = AutoTokenizer.from_pretrained(MODEL_PATH, ...)
AutoTokenizer
: 自动化的分词器加载器,根据模型需求自动选择合适的分词器。trust_remote_code=True
: 同模型加载,允许执行分词器代码中的远程代码。
tokenizer.pad_token = tokenizer.eos_token
- 这行代码将分词器的填充令牌(pad token)设置为结束令牌(eos token),这在某些语言模型中用于处理输入长度不一的情况,通过将结束令牌用作填充,保持一致性。
上述代码主要用于在资源受限的环境下(如较小的服务器或边缘设备),通过量化技术优化模型的存储和计算性能,同时尝试保持较高的模型精度和功能完整性。
训练过程:
# Prepare model for QLoRA
model = prepare_model_for_kbit_training(model, use_gradient_checkpointing=True)
# LoRA configuration
peft_config = LoraConfig(task_type="CAUSAL_LM",
r=16, # reduce if running into out-of-memory issues
lora_alpha=32,
target_modules=['q_proj', 'k_proj', 'v_proj', 'dense'],
lora_dropout=0.05)
peft_model = get_peft_model(model, peft_config)
# Set training arguments, data collator for LLMs and Trainer
training_args = TrainingArguments(output_dir=TUNED_MODEL_PATH,
learning_rate=1e-3,
per_device_train_batch_size=8, # reduce if running into out-of-memory issues
num_train_epochs=3, # reduce if running into out-of-memory issues
weight_decay=0.01,
eval_strategy='epoch',
logging_steps=20,
fp16=True,
save_strategy='no')
data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False)
trainer = Trainer(model=peft_model,
args=training_args,
train_dataset=tokenized_dataset['train'],
eval_dataset=tokenized_dataset['test'],
tokenizer=tokenizer,
data_collator=data_collator)
# Fine-tune the model
trainer.train()
model_final = trainer.model
# Save the fine-tuned model
model_final.save_pretrained(TUNED_MODEL_PATH)
上述代码演示了如何使用QLoRA和LoRA(Low-Rank Adaptation)技术为大型语言模型(LLM)进行训练和微调,包括准备模型、配置训练参数、设置数据整理器,以及执行和保存训练结果。以下是每一部分的详细解释:
-
准备模型:
model = prepare_model_for_kbit_training(model, use_gradient_checkpointing=True)
prepare_model_for_kbit_training
用于准备和优化模型结构,使其适用于k位训练,其中use_gradient_checkpointing=True
选项启用梯度检查点,这有助于减少显存使用量,避免内存溢出问题。
-
LoRA配置:
peft_config = LoraConfig(...)
- LoRA配置包括任务类型、LoRA参数如r(秩的大小)、alpha(学习率放大因子)、目标模块(模型中将要调整的部分),以及dropout率。
- 这些设置主要影响模型的微调过程,通过只更新模型中的小部分参数来实现高效训练。
-
创建PEFT模型:
peft_model = get_peft_model(model, peft_config)
- 通过应用LoRA配置来获得PEFT模型,这种方法专门用于对预训练模型进行参数效率的调整。
-
设置训练参数、数据整理器和训练器:
training_args = TrainingArguments(...)
- 配置训练的各项参数,如输出目录、学习率、批次大小、训练轮次、权重衰减、评估策略、日志记录步骤、使用半精度训练和保存策略。
data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False)
- 数据整理器用于生成合适的训练数据批次,这里设置为非掩码语言模型任务(即直接语言生成)。
trainer = Trainer(...)
- 设置训练器,用于管理模型训练的整个过程,包括提供训练和评估数据集、使用的分词器和数据整理器。
-
执行微调:
trainer.train()
- 开始模型的训练过程。
-
保存微调后的模型:
model_final = trainer.model
model_final.save_pretrained(TUNED_MODEL_PATH)
- 训练完成后,将微调好的模型保存到指定路径。
整个过程涉及模型的优化、训练调整和结果保存,以实现对特定任务的高效和针对性的调整,减少对原始模型大量参数的全面训练需求,从而节省资源和时间。