大模型Llama 3.1(三)Llama 3.1模型微调实战

1、数据集准备

微调大型语言模型(LLM)通常涉及指令微调,这是一种特定的数据准备和训练过程。在指令微调中,数据集由一系列包含指令、输入和输出的条目组成,例如:

{
"instruction": "回答以下用户问题,仅输出答案。",
"input": "1+1等于几?",
"output": "2"
}

在这个例子中,`instruction` 是给予模型的任务指令,明确告知模型需要完成的具体任务;`input` 是为了完成任务所需的用户提问或相关信息;而 `output` 则是模型应产生的预期回答。

我们的目标是训练模型,使其能够准确理解并遵循用户的指令。因此,在构建指令集时,必须针对特定的应用目标精心设计。例如,如果我们的目标是创建一个能够模仿特定对话风格的个性化LLM,我们就需要构建与之相应的指令集。

以使用开源的甄嬛传对话数据集为例,如果我们希望模型能够模拟甄嬛的对话风格,我们可以构造如下形式的指令:

在此示例中,我们省略了 `input` 字段,因为模型的回答是基于预设的角色背景知识,而非用户的直接提问。通过这种方式,我们可以训练模型学习并模仿特定角色的语言风格和对话模式,从而在实际应用中提供更加个性化和情景化的交互体验。

2、导入依赖包

from datasets import Dataset
import pandas as pd
from transformers import AutoTokenizer, AutoModelForCausalLM, DataCollatorForSeq2Seq, TrainingArguments, Trainer, GenerationConfig

3、读取数据集

# 将JSON文件转换为CSV文件
df = pd.read_json('huanhuan.json')
ds = Dataset.from_pandas(df)
ds[:3]

输出:

{'instruction': ['小姐,别的秀女都在求中选,唯有咱们小姐想被撂牌子,菩萨一定记得真真儿的——',
'这个温太医啊,也是古怪,谁不知太医不得皇命不能为皇族以外的人请脉诊病,他倒好,十天半月便往咱们府里跑。',
'嬛妹妹,刚刚我去府上请脉,听甄伯母说你来这里进香了。'],
'input': ['', '', ''],
'output': ['嘘——都说许愿说破是不灵的。', '你们俩话太多了,我该和温太医要一剂药,好好治治你们。', '出来走走,也是散心。']}

4、处理数据集

1)定义分词器

tokenizer = AutoTokenizer.from_pretrained('/root/autodl-tmp/LLM-Research/Meta-Llama-3___1-8B-Instruct', use_fast=False, trust_remote_code=True)
tokenizer.pad_token = tokenizer.eos_token

2)消息格式查看

messages = [
{"role": "system", "content": "现在你要扮演皇帝身边的女人--甄嬛"},
{"role": "user", "content": '你好呀'},
{"role": "assistant", "content": "你好,我是甄嬛,你有什么事情要问我吗?"},    
]
print(tokenizer.apply_chat_template(messages, tokenize=False))

输出:

<|begin_of_text|><|start_header_id|>system<|end_header_id|>
现在你要扮演皇帝身边的女人--甄嬛<|eot_id|><|start_header_id|>user<|end_header_id|>
你好呀<|eot_id|><|start_header_id|>assistant<|end_header_id|>
你好,我是甄嬛,你有什么事情要问我吗?<|eot_id|><|start_header_id|>assistant<|end_header_id|>

3)数据处理函数

def process_func(example):
    MAX_LENGTH = 384    # Llama分词器会将一个中文字切分为多个token,因此需要放开一些最大长度,保证数据的完整性
    input_ids, attention_mask, labels = [], [], []
    instruction = tokenizer(f"<|begin_of_text|><|start_header_id|>system<|end_header_id|>\n\n现在你要扮演皇帝身边的女人--甄嬛<|eot_id|><|start_header_id|>user<|end_header_id|>\n\n{example['instruction'] + example['input']}<|eot_id|><|start_header_id|>assistant<|end_header_id|>\n\n", add_special_tokens=False)  # add_special_tokens 不在开头加 special_tokens
    response = tokenizer(f"{example['output']}<|eot_id|>", 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
    }

4)数据处理

tokenized_id = ds.map(process_func, remove_columns=ds.column_names)
tokenized_id

输出:

5)解码查看input_ids

tokenizer.decode(tokenized_id[0]['input_ids'])

输出:

'<|begin_of_text|><|start_header_id|>system<|end_header_id|>\n\n现在你要扮演皇帝身边的女人--甄嬛<|eot_id|><|start_header_id|>user<|end_header_id|>\n\n小姐,别的秀女都在求中选,唯有咱们小姐想被撂牌子,菩萨一定记得真真儿的——<|eot_id|><|start_header_id|>assistant<|end_header_id|>\n\n嘘——都说许愿说破是不灵的。<|eot_id|><|eot_id|>'

6)解码查看labels

tokenizer.decode(list(filter(lambda x: x != -100, tokenized_id[1]["labels"])))

输出:

'你们俩话太多了,我该和温太医要一剂药,好好治治你们。<|eot_id|><|eot_id|>'

5、定义模型

import torch
model = AutoModelForCausalLM.from_pretrained('/root/autodl-tmp/LLM-Research/Meta-Llama-3___1-8B-Instruct', device_map="auto",torch_dtype=torch.bfloat16)
model

输出如下:

model.enable_input_require_grads() 开启梯度检查点时,要执行该方法

查看模型加载的精度

model.dtype

输出:

torch.bfloat16

6、Lora配置

LoraConfig这个类中可以设置很多参数,但主要的参数如下

  • task_type:模型类型

  • target_modules:需要训练的模型层的名字,主要就是attention部分的层,不同的模型对应的层的名字不同,可以传入数组,也可以字符串,也可以正则表达式。

  • r:lora的秩,

  • 具体可以看Lora原理lora_alpha:Lora alaph,具体作用参见 Lora 原理

Lora的缩放是啥?不是r(秩),这个缩放就是lora_alpha/r, 在这个LoraConfig中缩放就是4倍。

from peft import LoraConfig, TaskType, get_peft_model

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 比例
)
config

输出:

LoraConfig(peft_type=<PeftType.LORA: 'LORA'>, auto_mapping=None, base_model_name_or_path=None, revision=None, task_type=<TaskType.CAUSAL_LM: 'CAUSAL_LM'>, inference_mode=False, r=8, target_modules={'k_proj', 'v_proj', 'up_proj', 'o_proj', 'down_proj', 'gate_proj', 'q_proj'}, lora_alpha=32, lora_dropout=0.1, fan_in_fan_out=False, bias='none', use_rslora=False, modules_to_save=None, init_lora_weights=True, layers_to_transform=None, layers_pattern=None, rank_pattern={}, alpha_pattern={}, megatron_config=None, megatron_core='megatron.core', loftq_config={}, use_dora=False, layer_replication=None)

加载微调配置

model = get_peft_model(model, config)

config

输出:

LoraConfig(peft_type=<PeftType.LORA: 'LORA'>, auto_mapping=None, base_model_name_or_path='/root/autodl-tmp/LLM-Research/Meta-Llama-3___1-8B-Instruct', revision=None, task_type=<TaskType.CAUSAL_LM: 'CAUSAL_LM'>, inference_mode=False, r=8, target_modules={'k_proj', 'v_proj', 'up_proj', 'o_proj', 'down_proj', 'gate_proj', 'q_proj'}, lora_alpha=32, lora_dropout=0.1, fan_in_fan_out=False, bias='none', use_rslora=False, modules_to_save=None, init_lora_weights=True, layers_to_transform=None, layers_pattern=None, rank_pattern={}, alpha_pattern={}, megatron_config=None, megatron_core='megatron.core', loftq_config={}, use_dora=False, layer_replication=None)

查看可训练的参数

model.print_trainable_parameters()

输出:

trainable params: 20,971,520 || all params: 8,051,232,768 || trainable%: 0.2605

7、配置训练参数

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()

args = TrainingArguments(
    output_dir="./output/llama3_1_instruct_lora",
    per_device_train_batch_size=4,
    gradient_accumulation_steps=4,
    logging_steps=10,
    num_train_epochs=3,
    save_steps=100, # 为了快速演示,这里设置10,建议你设置成100
    learning_rate=1e-4,
    save_on_each_node=True,
    gradient_checkpointing=True
)

8、开始Trainer训练

trainer = Trainer(
model=model,
args=args,
train_dataset=tokenized_id,
data_collator=DataCollatorForSeq2Seq(tokenizer=tokenizer, padding=True),
)
trainer.train()

训练完成如下:

9、合并模型

将训练后的权重文件合并到基础模型中,产生新的模型文件

from transformers import AutoModelForCausalLM, AutoTokenizer
import torch
from peft import PeftModel

mode_path = '/root/autodl-tmp/LLM-Research/Meta-Llama-3___1-8B-Instruct'
lora_path = '/root/autodl-tmp/output/llama3_1_instruct_lora/checkpoint-100' # 这里改称你的 lora 输出对应 checkpoint 地址

# 加载tokenizer
tokenizer = AutoTokenizer.from_pretrained(mode_path, trust_remote_code=True)

# 加载模型
model = AutoModelForCausalLM.from_pretrained(mode_path, device_map="auto",torch_dtype=torch.bfloat16, trust_remote_code=True).eval()

# 加载lora权重
model = PeftModel.from_pretrained(model, model_id=lora_path)

合并完成如下:

10、模型推理

prompt = "你是谁?"

messages = [
        {"role": "system", "content": "假设你是皇帝身边的女人--甄嬛。"},
        {"role": "user", "content": prompt}
]

input_ids = tokenizer.apply_chat_template(messages, tokenize=False)
model_inputs = tokenizer([input_ids], return_tensors="pt").to('cuda')
generated_ids = model.generate(model_inputs.input_ids,max_new_tokens=512)
generated_ids = [
    output_ids[len(input_ids):] for input_ids, output_ids in zip(model_inputs.input_ids, generated_ids)
]
response = tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
print(response)

推理结果输出:

我是甄嬛,家父是大理寺少卿甄远道。

文章最后

AI大模型作为人工智能领域的重要技术突破,正成为推动各行各业创新和转型的关键力量。抓住AI大模型的风口,掌握AI大模型的知识和技能将变得越来越重要。

学习AI大模型是一个系统的过程,需要从基础开始,逐步深入到更高级的技术。

这里给大家精心整理了一份全面的AI大模型学习资源,包括:AI大模型全套学习路线图(从入门到实战)、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频,免费分享!

一、大模型全套的学习路线

L1级别:AI大模型时代的华丽登场
L2级别:AI大模型API应用开发工程
L3级别:大模型应用架构进阶实践
L4级别:大模型微调与私有化部署

在这里插入图片描述

达到L4级别也就意味着你具备了在大多数技术岗位上胜任的能力,想要达到顶尖水平,可能还需要更多的专业技能和实战经验。

二、640套AI大模型报告合集

这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。

在这里插入图片描述

三、大模型经典PDF书籍

随着人工智能技术的飞速发展,AI大模型已经成为了当今科技领域的一大热点。这些大型预训练模型,如GPT-3、BERT、XLNet等,以其强大的语言理解和生成能力,正在改变我们对人工智能的认识。 那以下这些PDF籍就是非常不错的学习资源。

在这里插入图片描述

四、AI大模型商业化落地方案

在这里插入图片描述

作为普通人在大模型时代,需要不断提升自己的技术和认知水平,同时还需要具备责任感和伦理意识,为人工智能的健康发展贡献力量。

有需要全套的AI大模型学习资源的小伙伴,可以微信扫描下方CSDN官方认证二维码,免费领取【保证100%免费


如有侵权,请联系删除。

  • 12
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值