全国免费咨询:

13245491521

VR图标白色 VR图标黑色
X

中高端软件定制开发服务商

与我们取得联系

13245491521     13245491521

2024-05-31_利用大模型构造数据集,并微调大模型

您的位置:首页 >> 新闻 >> 行业资讯

利用大模型构造数据集,并微调大模型 ?“本文为稀土掘金技术社区首发签约文章,30天内禁止转载,30天后未获授权禁止转载,侵权必究!” ?一、前言目前大模型的微调方法有很多,而且大多可以在消费级显卡上进行,每个人都可以在自己的电脑上微调自己的大模型。 但是在微调时我们时常面对一个问题,就是数据集问题。网络上有许多开源数据集,但是很多时候我们并不想用这些数据集微调模型,我们更希望使用某本书、某个作者的作品、我们自己的聊天记录、某个角色的对话来微调模型。 用于微调的数据通常是成千上万的问答对,如果手工搜集,需要花费大量时间。 文本将介绍一种方式,利用大模型来构造自己的数据集,并使用我们构造的数据集来微调大模型。 二、构造数据集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模型一样使用微调后的模型。 点击关注公众号,“技术干货”及时达! 阅读原文

上一篇:2022-07-09_LeCun领导下的Meta AI,押注自监督 下一篇:2023-09-11_灵隐寺卖奶茶,玄学尽头是营销

TAG标签:

18
网站开发网络凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设网站改版域名注册主机空间手机网站建设网站备案等方面的需求...
请立即点击咨询我们或拨打咨询热线:13245491521 13245491521 ,我们会详细为你一一解答你心中的疑难。
项目经理在线

相关阅读 更多>>

猜您喜欢更多>>

我们已经准备好了,你呢?
2022我们与您携手共赢,为您的企业营销保驾护航!

不达标就退款

高性价比建站

免费网站代备案

1对1原创设计服务

7×24小时售后支持

 

全国免费咨询:

13245491521

业务咨询:13245491521 / 13245491521

节假值班:13245491521()

联系地址:

Copyright © 2019-2025      ICP备案:沪ICP备19027192号-6 法律顾问:律师XXX支持

在线
客服

技术在线服务时间:9:00-20:00

在网站开发,您对接的直接是技术员,而非客服传话!

电话
咨询

13245491521
7*24小时客服热线

13245491521
项目经理手机

微信
咨询

加微信获取报价