大模型微调定义
大模型微调(Fine-tuning)是指在已经预训练好的大型语言模型基础上,使用特定的数据集进行进一步的训练,以使模型适应特定任务或领域。
预训练模型(Pre-trained Model),或者说基础模型(Foundation Model),已经可以完成很多任务,比如问答,生成代码,生成文案等。但是行业内的专业问答、关于某个企业自身的知识等,是通用大模型所无法触及的。在这种情况下,就需要使用特定的数据集,对合适的基础模型进行微调,以完成特定的任务、回答特定的问题等。在这种情况下,微调就成了重要的手段。
大模型微调的方法
大模型微调的方法主要有两种:
- 全微调(Full Fine-tuning):全微调是指对整个预训练模型进行微调,包括所有的模型参数。
-
- 预训练模型的所有层和参数都会被更新和优化,以适应目标任务的需求。
- 适用于任务和预训练模型之间存在较大差异的情况,或者任务需要模型具有高度灵活性和自适应能力的情况。
- 需要较大的计算资源和时间,但可以获得更好的性能。
- 部分微调(Repurposing):部分微调是指在微调过程中只更新模型的顶层或少数几层,而保持预训练模型的底层参数不变。
-
- 保留预训练模型的通用知识的同时,通过微调顶层来适应特定任务。
- 适用于目标任务与预训练模型之间有一定相似性的情况,或者任务数据集较小的情况。
- 由于只更新少数层,Repurposing相对于Full Fine-tuning需要较少的计算资源和时间,但在某些情况下性能可能会有所降低。
大模型微调的类型
大模型微调还可以分为监督微调和无监督微调两种:
- 监督微调(Supervised Fine-tuning):监督微调是指在进行微调时使用有标签的训练数据集。
-
- 这些标签提供了模型在微调过程中的目标输出。
- 在监督微调中,通常使用带有标签的任务特定数据集,例如分类任务的数据集,其中每个样本都有一个与之关联的标签。
- 通过使用这些标签来指导模型的微调,可以使模型更好地适应特定任务。
- 无监督微调(Unsupervised Fine-tuning):无监督微调是指在进行微调时使用无标签的训练数据集。
-
- 这意味着在微调过程中,模型只能利用输入数据本身的信息,而没有明确的目标输出。
- 这些方法通过学习数据的内在结构或生成数据来进行微调,以提取有用的特征或改进模型的表示能力。
大模型微调的步骤
所有的大模型微调都是基于huggingface来进行微调
大模型微调步骤参考了:
准备数据集
数据集格式:jsonl
swift
{"instruction": "\n请参考下面内容中的甄嬛的说话风格和语气,回答我的问题。甄嬛的说话风格需要是口语化的,回复内容不要超过30个字,尽可能字数简短一些。\n对话风格案例内容:\n```用户:这首歌虽未直写男女相悦,可字字写着两心相悦后女子的欢喜神态,而且"双双金鹧鹄"也是并蒂成双之意。\n用户:既然如此,安常在怎么就没唱出花好之情?难不成是看见皇上跟本宫在一起,心有不悦才唱不好的吗?\n甄嬛:回禀华妃娘娘,安常在早上受了风寒,嗓子有些不适。\n\n用户:你不是要看院子里的白梅吗,怎么那么快就回来了?\n甄嬛:雪景看久了反倒眼晕,四郎本是好意在园子里种植白梅,可是一下雪反倒与雪景融为一色,倒看不出来了。```\n", "input": "小姐,别的秀女都在求中选,唯有咱们小姐想被撂牌子,菩萨一定记得真真儿的------", "output": "嘘------都说许愿说破是不灵的。"}
{"instruction": "\n请参考下面内容中的甄嬛的说话风格和语气,回答我的问题。甄嬛的说话风格需要是口语化的,回复内容不要超过30个字,尽可能字数简短一些。\n对话风格案例内容:\n```用户:这首歌虽未直写男女相悦,可字字写着两心相悦后女子的欢喜神态,而且"双双金鹧鹄"也是并蒂成双之意。\n用户:既然如此,安常在怎么就没唱出花好之情?难不成是看见皇上跟本宫在一起,心有不悦才唱不好的吗?\n甄嬛:回禀华妃娘娘,安常在早上受了风寒,嗓子有些不适。\n\n用户:你不是要看院子里的白梅吗,怎么那么快就回来了?\n甄嬛:雪景看久了反倒眼晕,四郎本是好意在园子里种植白梅,可是一下雪反倒与雪景融为一色,倒看不出来了。```\n", "input": "这个温太医啊,也是古怪,谁不知太医不得皇命不能为皇族以外的人请脉诊病,他倒好,十天半月便往咱们府里跑。", "output": "你们俩话太多了,我该和温太医要一剂药,好好治治你们。"}
{"instruction": "\n请参考下面内容中的甄嬛的说话风格和语气,回答我的问题。甄嬛的说话风格需要是口语化的,回复内容不要超过30个字,尽可能字数简短一些。\n对话风格案例内容:\n```用户:这首歌虽未直写男女相悦,可字字写着两心相悦后女子的欢喜神态,而且"双双金鹧鹄"也是并蒂成双之意。\n用户:既然如此,安常在怎么就没唱出花好之情?难不成是看见皇上跟本宫在一起,心有不悦才唱不好的吗?\n甄嬛:回禀华妃娘娘,安常在早上受了风寒,嗓子有些不适。\n\n用户:你不是要看院子里的白梅吗,怎么那么快就回来了?\n甄嬛:雪景看久了反倒眼晕,四郎本是好意在园子里种植白梅,可是一下雪反倒与雪景融为一色,倒看不出来了。```\n", "input": "嬛妹妹,刚刚我去府上请脉,听甄伯母说你来这里进香了。", "output": "出来走走,也是散心。"}
{"instruction": "\n请参考下面内容中的甄嬛的说话风格和语气,回答我的问题。甄嬛的说话风格需要是口语化的,回复内容不要超过30个字,尽可能字数简短一些。\n对话风格案例内容:\n```用户:这首歌虽未直写男女相悦,可字字写着两心相悦后女子的欢喜神态,而且"双双金鹧鹄"也是并蒂成双之意。\n用户:既然如此,安常在怎么就没唱出花好之情?难不成是看见皇上跟本宫在一起,心有不悦才唱不好的吗?\n甄嬛:回禀华妃娘娘,安常在早上受了风寒,嗓子有些不适。\n\n用户:你不是要看院子里的白梅吗,怎么那么快就回来了?\n甄嬛:雪景看久了反倒眼晕,四郎本是好意在园子里种植白梅,可是一下雪反倒与雪景融为一色,倒看不出来了。```\n", "input": "嬛妹妹,我虽是一介御医,俸禄微薄,可是我保证会一生一世对你好,疼爱你,保护你,永远事事以你为重。本来没半月一次到府上去请脉,能够偶尔见一次妹妹的笑靥,已经心满意足了,可谁知------而且我也知道,妹妹心里是不愿意去殿选的。", "output": "实初哥哥这么说,就枉顾我们一直以来的兄妹情谊了,嬛儿没有哥哥,一直把你当作自己的亲哥哥一样看待,自然相信哥哥会待妹妹好的------自然了,以后有了嫂子,你也会对嫂子更好。"}
参考:raw.githubusercontent.com/datawhalech...
Lora 训练的数据是需要经过格式化、编码之后再输入给模型进行训练的,如果是熟悉 Pytorch 模型训练流程的同学会知道,我们一般需要将输入文本编码为 input_ids,将输出文本编码为 labels,编码之后的结果都是多维的向量。我们首先定义一个预处理函数,这个函数用于对每一个样本,编码其输入、输出文本并返回一个编码后的字典:
python
def process_func(example):
MAX_LENGTH = 384 # Llama分词器会将一个中文字切分为多个token,因此需要放开一些最大长度,保证数据的完整性
input_ids, attention_mask, labels = [], [], []
instruction = tokenizer(f"User: {example['instruction']+example['input']}\n\n", add_special_tokens=False) # add_special_tokens 不在开头加 special_tokens
response = tokenizer(f"Assistant: {example['output']}<|end▁of▁sentence|>", add_special_tokens=False)
input_ids = instruction["input_ids"] + response["input_ids"] + [tokenizer.pad_token_id]
attention_mask = instruction["attention_mask"] + response["attention_mask"] + [1] # 因为eos token咱们也是要关注的所以 补充为1
labels = [-100] * len(instruction["input_ids"]) + response["input_ids"] + [tokenizer.pad_token_id]
if len(input_ids) > MAX_LENGTH: # 做一个截断
input_ids = input_ids[:MAX_LENGTH]
attention_mask = attention_mask[:MAX_LENGTH]
labels = labels[:MAX_LENGTH]
return {
"input_ids": input_ids,
"attention_mask": attention_mask,
"labels": labels
}
加载分词器和半精度模型
模型以半精度形式加载,如果你的显卡比较新的话,可以用torch.bfolat形式加载。对于自定义的模型一定要指定trust_remote_code参数为True。
python
tokenizer = AutoTokenizer.from_pretrained('./deepseek-ai/deepseek-llm-7b-chat/', use_fast=False, trust_remote_code=True)
tokenizer.padding_side = 'right' # padding在右边
model = AutoModelForCausalLM.from_pretrained('./deepseek-ai/deepseek-llm-7b-chat/', trust_remote_code=True, torch_dtype=torch.half, device_map="auto")
model.generation_config = GenerationConfig.from_pretrained('./deepseek-ai/deepseek-llm-7b-chat/')
model.generation_config.pad_token_id = model.generation_config.eos_token_id
定义lora配置
LoraConfig这个类中可以设置很多参数,比较常见的有
- task_type:模型类型
- target_modules:需要训练的模型层的名字,主要就是attention部分的层,不同的模型对应的层的名字不同,可以传入数组,也可以字符串,也可以正则表达式。
- r:lora的秩,具体可以看Lora原理
- lora_alpha:Lora alaph,具体作用参见 Lora 原理
Lora的缩放就是lora_alpha/r, 在这个LoraConfig中缩放就是4倍。
python
config = LoraConfig(
task_type=TaskType.CAUSAL_LM,
target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"],
inference_mode=False, # 训练模式
r=8, # Lora 秩
lora_alpha=32, # Lora alaph,具体作用参见 Lora 原理
lora_dropout=0.1# Dropout 比例
)
训练
训练参数:
TrainingArguments,常用的参数有。
- output_dir:模型的输出路径
- per_device_train_batch_size:顾名思义 batch_size
- gradient_accumulation_steps: 梯度累加,如果你的显存比较小,那可以把 batch_size 设置小一点,梯度累加增大一些。
- logging_steps:多少步,输出一次log
- num_train_epochs:顾名思义 epoch
- gradient_checkpointing:梯度检查,这个一旦开启,模型就必须执行
- model.enable_input_require_grads(),这个原理大家可以自行探索,这里就不细说了。
python
args = TrainingArguments(
output_dir="./output/DeepSeek",
per_device_train_batch_size=8,
gradient_accumulation_steps=2,
logging_steps=10,
num_train_epochs=3,
save_steps=100,
learning_rate=1e-4,
save_on_each_node=True,
gradient_checkpointing=True
)
开始训练
python
trainer = Trainer(
model=model,
args=args,
train_dataset=tokenized_id,
data_collator=DataCollatorForSeq2Seq(tokenizer=tokenizer, padding=True),
)
trainer.train()
模型推理
python
text = "小姐,别的秀女都在求中选,唯有咱们小姐想被撂牌子,菩萨一定记得真真儿的------"
inputs = tokenizer(f"User: {text}\n\n", return_tensors="pt")
outputs = model.generate(**inputs.to(model.device), max_new_tokens=100)
result = tokenizer.decode(outputs[0], skip_special_tokens=True)
print(result)