利用大模型构造数据集,并微调大模型

一、前言

目前大模型的微调方法有很多,而且大多可以在消费级显卡上进行,每个人都可以在自己的电脑上微调自己的大模型。

但是在微调时我们时常面对一个问题,就是数据集问题。网络上有许多开源数据集,但是很多时候我们并不想用这些数据集微调模型,我们更希望使用某本书、某个作者的作品、我们自己的聊天记录、某个角色的对话来微调模型。

用于微调的数据通常是成千上万的问答对,如果手工搜集,需要花费大量时间。

文本将介绍一种方式,利用大模型来构造自己的数据集,并使用我们构造的数据集来微调大模型。

二、构造数据集

2.1 目的

数据集通常是问答对形式,比如alpaca数据集的形式如下:

  `{       "instruction": "保持健康的三个提示。",       "input": "",       "output": "以下是保持健康的三个提示:\n\n1. 保持身体活动。每天做适当的身体运动,如散步、跑步或游泳,能促进心血管健康,增强肌肉力量,并有助于减少体重。\n\n2. 均衡饮食。每天食用新鲜的蔬菜、水果、全谷物和脂肪含量低的蛋白质食物,避免高糖、高脂肪和加工食品,以保持健康的饮食习惯。\n\n3. 睡眠充足。睡眠对人体健康至关重要,成年人每天应保证 7-8 小时的睡眠。良好的睡眠有助于减轻压力,促进身体恢复,并提高注意力和记忆力。"     }`

但是实际上我们能拿到的数据通常是一大段文本的形式,比如:

    `小时候,那时我还只有6岁,看到一本描写原始森林壮观景象的书,名叫真实的故事。书里有一幅很精彩的插画,画的是一条大蟒蛇正在吞食一只动物,下面就是那幅插画的复制品。          这本书上说:“大蟒蛇把它们的猎物不加咀嚼地整个吞下去,之后,就再也不动了,然后通过长达六个月的睡眠来消化掉这些食物。”   	...`

现在我们要做的就是把大段文本形式的数据转换成alpaca的形式。

在以往我们只能通过人工的方式完成,而现在我们可以借助大模型的能力。大致思路就是让大模型根据文本,总结出对话、问答内容。这点可以通过Prompt工程实现。

2.2 Prompt设计

在系统Prompt中,我们需要强调根据上下文内容,让模型提取对话、问答等内容。比如:

QA_PAIRS_SYSTEM_PROMPT = """     <Context></Context> 标记中是一段文本,学习和分析它,并整理学习成果:     - 提出问题并给出每个问题的答案。     - 答案需详细完整,尽可能保留原文描述。     - 答案可以包含普通文字、链接、代码、表格、公示、媒体链接等 Markdown 元素。     - 最多提出 30 个问题。     """   

这样就可以让模型自己提问,自己回答。然后我们需要规定输出的格式,我们希望得到字典数组,所以用户Prompt可以设置成:

QA_PAIRS_HUMAN_PROMPT = """     请按以下格式整理学习成果:     <Context>     文本     </Context>     [     {{"question": "问题1","answer":"答案1"}},     {{"question": "问题2","answer":"答案2"}},     ]     ------          我们开始吧!          <Context>     {text}     <Context/>     """   

根据问题不同,可以对上面的内容进行一些调整。下面可以开始编写代码。

2.3 处理文档

首先导入需要用到的模块:

import json     from typing import List          from tqdm import tqdm     from langchain_core.prompts import ChatPromptTemplate     from langchain_core.pydantic_v1 import BaseModel, Field     from langchain_core.output_parsers import JsonOutputParser     from langchain_openai import AzureChatOpenAI     from langchain_community.document_loaders import UnstructuredFileLoader     from langchain_text_splitters import RecursiveCharacterTextSplitter   

在构建chain前,我们先完成文档处理的操作。我们希望传入的内容是文本数据,这里可以是txt等文件形式。我们这里以txt为例:

def split_document(filepath):     	loader = UnstructuredFileLoader(filepath)     	text_spliter = RecursiveCharacterTextSplitter(     		chunk_size=2048,     		chunk_overlap=128     	)     	documents = loader.load_and_split(text_spliter)     	return documents   

使用上面的函数,可以返回大段的文本片段。

2.4 构建chain

下面就是构建用于生成数据集的chain,包括Prompt、LLM、Outputparser三个部分内容分别如下:

2.4.1 Prompt

我们使用ChatPromptTemplate将上面的Prompt整合起来,代码如下:

QA_PAIRS_SYSTEM_PROMPT = "..."   QA_PAIRS_HUMAN_PROMPT = "..."   prompt = ChatPromptTemplate.from_messages([     	("system", QA_PAIRS_SYSTEM_PROMPT),     	("human", QA_PAIRS_HUMAN_PROMPT)     ])   

在QA_PAIRS_HUMAN_PROMPT中我们添加了{text}占位,invoke时需要传入{“text”: “xxx”}。

2.4.2 LLM

大模型的选择非常多,一般的建议是选择长上下文、且能力比你要微调的模型强的模型。这里使用GPT-3.5-16k,代码如下:

llm = AzureChatOpenAI(     	azure_endpoint=endpoint,     	deployment_name=deployment_name,     	openai_api_key=api_key,     	openai_api_version="2024-02-01",     )   

2.4.3 OutputParser

最后是提取出结果,我们定义结果的Model:

class QaPair(BaseModel):     	question: str = Field(description='问题内容')     	answer: str = Field(description='问题的回答')     	          class QaPairs(BaseModel):     	qas: List[QaPair] = Field(description='问答对列表')         parser = JsonOutputParser(pydantic_object=QaPairs)   

最后将三者连接起来:

chain = prompt | llm | parser   

我们把构建chain的操作写成create_chain函数:

def create_chain():     	prompt = ChatPromptTemplate.from_messages([     		("system", QA_PAIRS_SYSTEM_PROMPT),     		("human", QA_PAIRS_HUMAN_PROMPT)     	])     	llm = AzureChatOpenAI(     		azure_endpoint=endpoint,     		deployment_name=deployment_name,     		openai_api_key=api_key,     		openai_api_version="2024-02-01",     	)     	parser = JsonOutputParser(pydantic_object=QaPairs)     	chain = prompt | llm | parser     	return chain   

下面我们可以来试一试效果:

def main():     	chain = create_chain()     	documents = split_document('The.Little.Prince.txt')     	with open(f'dataset.json', 'w', encoding='utf-8') as f:     	datas = []     	bar = tqdm(total=len(documents))     	for idx, doc in enumerate(documents):     		bar.update(idx + 1)     		out = chain.invoke({'text': doc.page_content})     		datas += out     		f.write(json.dumps(datas, ensure_ascii=False))               if __name__ == '__main__':     	main()   

我使用小王子的书作为测试,下面是生成的部分数据集:

[     	{     		"question": "作者小时候看了一本关于什么的书?",     		"answer": "描写原始森林壮观景象的书"     	},     	{     		"question": "这本书上说大蟒蛇通过什么方式来消化食物?",     		"answer": "通过长达六个月的睡眠来消化食物"     	}   	...   ]   

我们可以收集同一作者的大量书籍,使用上面的方式构建数据集。在构建过程中,每次执行后,结果可能不一样,因此可以通过多次构建的方式生成更多样本。

三、微调模型

在准备好数据集后,我们就可以进行微调了,我们可以使用已有的项目进行微调,比如LLaMA-Factory就是一个不错的选择,链接如下:

https://github.com/hiyouga/LLaMA-Factory

具体的微调方式可以参考项目文档。

本文选择使用peft模块实现微调操作,其实其它项目也是使用这个项目来完成。先导入必要的模块:

from peft import LoraConfig, TaskType     from transformers import Trainer     from datasets import load_dataset     from transformers import AutoModelForCausalLM, TrainingArguments, AutoTokenizer     from peft import get_peft_model   

3.1 加载模型和配置LoRA

首先需要加载模型以及配置微调模型,我们选择使用LoRA进行微调:

# 配置参数     peft_config = LoraConfig(task_type=TaskType.SEQ_2_SEQ_LM, inference_mode=False, r=8, lora_alpha=32, lora_dropout=0.1)     # 加载模型     model = AutoModelForCausalLM.from_pretrained(     	"microsoft/Phi-3-mini-4k-instruct",     	trust_remote_code=True     )     tokenizer = AutoTokenizer.from_pretrained("microsoft/Phi-3-mini-4k-instruct")     model = get_peft_model(model, peft_config)     model.print_trainable_parameters()   

关于LoRA的原理,可以参考:https://juejin.cn/post/7280436307914407976

3.2 加载数据集

接下来加载我们创建的数据集:

def tokenize_function(example):     	encoded = tokenizer(   		example['question'],    		truncation=True,    		padding='max_length',    		max_length=128   	)     	encoded["labels"] = tokenizer(   		example["answer"],    		truncation=True,    		padding="max_length",    		max_length=128   	)["input_ids"]     	return encoded         # 加载数据集     data_files = {"train": "train.json", "validation": "train.json"}     dataset = load_dataset('./dataset', data_files=data_files)     tokenized_dataset = dataset.map(tokenize_function, batched=True)   

3.3 配置训练参数并训练

接下来配置训练参数开始训练:

training_args = TrainingArguments(     	output_dir="outputs",     	learning_rate=1e-3,     	per_device_train_batch_size=4,     	per_device_eval_batch_size=4,     	num_train_epochs=2,     	weight_decay=0.01,     	evaluation_strategy="epoch",     	save_strategy="epoch",     	load_best_model_at_end=True,     )     trainer = Trainer(     	model=model,     	args=training_args,     	train_dataset=tokenized_dataset["train"],     	eval_dataset=tokenized_dataset["validation"],     	tokenizer=tokenizer,     )          trainer.train()     model.save_pretrained("outputs")   

我们可以根据硬件情况调整per_device_train_batch_size和per_device_eval_batch_size。现在只需要运行代码,等待片刻即可训练完成。

四、推理

接下来我们要做的就是推理了。LoRA是一个旁支网络,我们需要在原有的模型上,添加LoRA,添加方式如下:

model.load_adapter('outputs', adapter_name='lora01')     model.set_adapter("lora01")   

调用上面代码后,model的推理操作就是添加LoRA后的推理。推理的完整代码如下:

from transformers import AutoModelForCausalLM, AutoTokenizer          model = AutoModelForCausalLM.from_pretrained("microsoft/Phi-3-mini-4k-instruct")     tokenizer = AutoTokenizer.from_pretrained("microsoft/Phi-3-mini-4k-instruct")          model = model.to("cuda")     model.load_adapter('outputs', adapter_name='lora01')     model.set_adapter("lora01")     model.eval()     inputs = tokenizer("作者小时候看了一本关于什么的书?", return_tensors="pt")          outputs = model.generate(input_ids=inputs["input_ids"].to("cuda"), max_new_tokens=50)     print(tokenizer.batch_decode(outputs.detach().cpu().numpy(), skip_special_tokens=True)[0])   

最后我们可以和使用正常的AutoModelForCausalLM模型一样使用微调后的模型。

那么,如何系统的去学习大模型LLM?

我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

作为一名热心肠的互联网老兵,我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。

但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

所有资料 ⚡️ ,朋友们如果有需要全套 《LLM大模型入门+进阶学习资源包》,扫码获取~

篇幅有限,部分资料如下:

👉LLM大模型学习指南+路线汇总👈

💥大模型入门要点,扫盲必看!
在这里插入图片描述
💥既然要系统的学习大模型,那么学习路线是必不可少的,这份路线能帮助你快速梳理知识,形成自己的体系。

路线图很大就不一一展示了 (文末领取)
在这里插入图片描述

👉大模型入门实战训练👈

💥光学理论是没用的,要学会跟着一起做,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。
在这里插入图片描述

👉国内企业大模型落地应用案例👈

💥两本《中国大模型落地应用案例集》 收录了近两年151个优秀的大模型落地应用案例,这些案例覆盖了金融、医疗、教育、交通、制造等众多领域,无论是对于大模型技术的研究者,还是对于希望了解大模型技术在实际业务中如何应用的业内人士,都具有很高的参考价值。 (文末领取)
在这里插入图片描述

👉GitHub海量高星开源项目👈

💥收集整理了海量的开源项目,地址、代码、文档等等全都下载共享给大家一起学习!
在这里插入图片描述

👉LLM大模型学习视频👈

💥观看零基础学习书籍和视频,看书籍和视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。 (文末领取)
在这里插入图片描述

👉640份大模型行业报告(持续更新)👈

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

👉获取方式:

这份完整版的大模型 LLM 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

😝有需要的小伙伴,可以Vx扫描下方二维码免费领取🆓

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值