大模型微调介绍

大模型微调定义

大模型微调(Fine-tuning)是指在已经预训练好的大型语言模型基础上,使用特定的数据集进行进一步的训练,以使模型适应特定任务或领域。

预训练模型(Pre-trained Model),或者说基础模型(Foundation Model),已经可以完成很多任务,比如问答,生成代码,生成文案等。但是行业内的专业问答、关于某个企业自身的知识等,是通用大模型所无法触及的。在这种情况下,就需要使用特定的数据集,对合适的基础模型进行微调,以完成特定的任务、回答特定的问题等。在这种情况下,微调就成了重要的手段。

大模型微调的方法

大模型微调的方法主要有两种:

  1. 全微调(Full Fine-tuning):全微调是指对整个预训练模型进行微调,包括所有的模型参数。
    1. 预训练模型的所有层和参数都会被更新和优化,以适应目标任务的需求。
    2. 适用于任务和预训练模型之间存在较大差异的情况,或者任务需要模型具有高度灵活性和自适应能力的情况。
    3. 需要较大的计算资源和时间,但可以获得更好的性能。
  1. 部分微调(Repurposing):部分微调是指在微调过程中只更新模型的顶层或少数几层,而保持预训练模型的底层参数不变。
    1. 保留预训练模型的通用知识的同时,通过微调顶层来适应特定任务。
    2. 适用于目标任务与预训练模型之间有一定相似性的情况,或者任务数据集较小的情况。
    3. 由于只更新少数层,Repurposing相对于Full Fine-tuning需要较少的计算资源和时间,但在某些情况下性能可能会有所降低。

大模型微调的类型

大模型微调还可以分为监督微调和无监督微调两种:

  • 监督微调(Supervised Fine-tuning):监督微调是指在进行微调时使用有标签的训练数据集。
    • 这些标签提供了模型在微调过程中的目标输出。
    • 在监督微调中,通常使用带有标签的任务特定数据集,例如分类任务的数据集,其中每个样本都有一个与之关联的标签。
    • 通过使用这些标签来指导模型的微调,可以使模型更好地适应特定任务。
  • 无监督微调(Unsupervised Fine-tuning):无监督微调是指在进行微调时使用无标签的训练数据集。
    • 这意味着在微调过程中,模型只能利用输入数据本身的信息,而没有明确的目标输出。
    • 这些方法通过学习数据的内在结构或生成数据来进行微调,以提取有用的特征或改进模型的表示能力。

大模型微调的步骤

所有的大模型微调都是基于huggingface来进行微调

huggingface.co/

huggingface.co/docs/transf...

大模型微调步骤参考了:

github.com/datawhalech...

准备数据集

数据集格式: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)

模型导出和部署

参考:zhuanlan.zhihu.com/p/228601279...

相关推荐
是店小二呀3 分钟前
AI前沿:资本狂潮下的技术暗战:巨头博弈、开源革命与生态重构
人工智能·重构·开源
snowfoootball36 分钟前
基于 Ollama DeepSeek、Dify RAG 和 Fay 框架的高考咨询 AI 交互系统项目方案
前端·人工智能·后端·python·深度学习·高考
云和数据.ChenGuang44 分钟前
机器学习之回归算法
人工智能·机器学习·回归
odoo中国1 小时前
深度学习 Deep Learning 第15章 表示学习
人工智能·深度学习·学习·表示学习
橙色小博1 小时前
长短期记忆神经网络(LSTM)基础学习与实例:预测序列的未来
人工智能·python·深度学习·神经网络·lstm
深蓝学院1 小时前
闭环SOTA!北航DiffAD:基于扩散模型实现端到端自动驾驶「多任务闭环统一」
人工智能·机器学习·自动驾驶
jimmyleeee1 小时前
人工智能基础知识笔记七:随机变量的几种分布
人工智能·笔记·概率论
仙人掌_lz1 小时前
机器学习ML极简指南
人工智能·python·算法·机器学习·面试·强化学习
weixin_435208162 小时前
论文浅尝 | Interactive-KBQA:基于大语言模型的多轮交互KBQA(ACL2024)
人工智能·语言模型·自然语言处理
碣石潇湘无限路2 小时前
【奇点时刻】GPT-4o新生图特性深度洞察报告
人工智能·经验分享·chatgpt·gpt4o·新生图特性