一、前言
想要轻松快速地使用您自己的数据微调和培训大型语言模型(LLM)?我们知道训练大型语言模型具有挑战性并需要耗费大量计算资源,包括收集和优化数据集、确定合适的模型及编写训练代码等。今天我们将介绍一种实验性新方法,实现特定任务高性能模型的训练。
我们的目标是最大程度地简化模型微调训练过程,使您能够在最短时间内从构思转化为高性能的完全训练的模型。以微调开源模型LLaMa 2为例,整个过程**++只需提供任务描述,系统便会为您生成数据集、解析成正确的数据格式并微调 LLaMA 2 模型++**。轻松实现快速的微调和推理过程!
二、GPT-LLM-Trainer 介绍
++GPT-LLM-Trainer++ 是一种全新、经济实惠且最简单的方法来训练大型语言模型。这个项目旨在探索一种新的训练高性能任务专用模型的流程,摆脱所有复杂的步骤,使你更容易从一个想法转变为完全训练好的模型。你只需输入任务描述,系统就会从头开始生成数据集,将其转换为你想要的任何格式,并为你进行模型微调。你可以在Google Colab上轻松的训练大型语言模型。GPT-LLM-Trainer 模型训练器利用 GPT-4 模型来简化整个过程,包括以下三个关键阶段:
- 数据生成阶段:利用 GPT-4 模型根据提供的输入用例生成多样化的提示和响应数据。
- 系统消息生成:通过为模型的交互设计最佳系统提示。
- 微调模型过程:生成数据集后,系统会自动将其拆分为训练集和验证集,为您微调模型,并为推理做好准备。
GPT大型语言模型训练器的主要优势在于它可以摆脱复杂的步骤,让用户更容易地从一个想法转变为完全训练好的模型。你只需输入任务描述,系统就会从头开始生成数据集,将其转换为你想要的任何格式,并为你进行模型微调。在这种情况下,你将使用LLaMa 2进行微调。
三、如何使用自己的数据微调LLM
这里主要介绍如何在Google Colab上训练LLaMA 2大型语言模型的实现步骤。首先,我们需要收集和整理数据集,将其格式化并选择合适的模型。接下来,我们需要编写训练代码,并将所有这些整合在一起进行训练。这个过程可能会遇到很多困难和挑战,但是通过使用GPT大型语言模型训练器,我们可以大大简化这个过程。
3.1、描述你的模型
我们通过尝试一种新的方法,可以轻松地根据你输入的任务描述来构建特定任务的模型。首先,尽可能的使用GPU,可以在Google Colab中设置可用的 GPU,然后创建模型,只需要在提示中描述您想要构建的模型。 具有描述性且清晰。你可以通过更改 Hyperparameters 单元格中的 model_name 来更改要微调的模型。
3.2、数据生成步骤
在这里写下您的prompt提示。 描述性越强、越清晰越好!
然后,选择生成数据时使用的temperature(0 到 1 之间)。 较低的值非常适合精确的任务,例如编写代码,而较大的值更适合创造性的任务,例如编写故事。
最后,选择您想要生成的示例数量。 生成的数据越多,a) 花费的时间就越长,b) 数据生成的成本就越高。 但一般来说,更多的例子会产生更高质量的模型。 100 通常是最低启动值。
python
prompt = "一个能够接收中文中类似猜灯谜的问题,并用经过深思熟虑、逐步推理的方式以中文回答的模型。"
temperature = .4
number_of_examples = 100
先安装OpenAI依赖。
bash
!pip install openai
一旦你确定了提示,就可以执行下面的代码生成数据集。这可能需要比预期更长的时间。
python
import os
import openai
import random
openai.api_key = "YOUR KEY HERE"
def generate_example(prompt, prev_examples, temperature=.5):
messages=[
{
"role": "system",
"content": f"您正在生成将用于训练机器学习模型的数据。\n\n您将获得我们想要训练的模型的高级描述,并由此生成数据样本,每个样本都有一个提示/ 响应对。\n\n您将按照以下格式执行此操作:\n````\nprompt\n------------\n$prompt_goes_here\n---------- -\n\nresponse\n-----------\n$response_goes_here\n------------\n```\n\n只能有一对提示/响应 每轮都会生成。\n\n对于每一轮,使示例比上一轮稍微复杂一点,同时确保多样性。\n\n确保您的样本是独特且多样化的,但高质量和复杂性足以训练一个良好的样本 执行模型。\n\n这是我们要训练的模型类型:\n`{prompt}`"
}
]
if len(prev_examples) > 0:
if len(prev_examples) > 10:
prev_examples = random.sample(prev_examples, 10)
for example in prev_examples:
messages.append({
"role": "assistant",
"content": example
})
response = openai.ChatCompletion.create(
model="gpt-4",
messages=messages,
temperature=temperature,
max_tokens=1354,
)
return response.choices[0].message['content']
# Generate examples
prev_examples = []
for i in range(number_of_examples):
print(f'Generating example {i}')
example = generate_example(prompt, prev_examples, temperature)
prev_examples.append(example)
print(prev_examples)
生成完数据集,我们还需要生成系统消息。
python
def generate_system_message(prompt):
response = openai.ChatCompletion.create(
model="gpt-4",
messages=[
{
"role": "system",
"content": "您将获得我们正在训练的模型的高级描述,并据此生成一个简单的系统提示以供该模型使用。 请记住,您不是生成用于数据生成的系统消息 - 您正在生成用于推理的系统消息。 一个好的格式是"给定 $INPUT_DATA,您将 $WHAT_THE_MODEL_SHOULD_DO。"。\n\n使其尽可能简洁。 在响应中只包含系统提示符。\n\n例如,切勿编写:`\"$SYSTEM_PROMPT_HERE\"`。\n\n应该类似于:`$SYSTEM_PROMPT_HERE`。"
},
{
"role": "user",
"content": prompt.strip(),
}
],
temperature=temperature,
max_tokens=500,
)
return response.choices[0].message['content']
system_message = generate_system_message(prompt)
print(f'系统消息: `{system_message}`。 如果您想要更好的结果,请随意重新运行此单元格。')
接下来,我们将示例放入数据框中,并将它们转换为最终的数据集对。
python
import pandas as pd
# 初始化列表以存储提示和响应
prompts = []
responses = []
# 从示例中解析出提示和响应
for example in prev_examples:
try:
split_example = example.split('-----------')
prompts.append(split_example[1].strip())
responses.append(split_example[3].strip())
except:
pass
# 创建数据框
df = pd.DataFrame({
'prompt': prompts,
'response': responses
})
# 删除重复项
df = df.drop_duplicates()
print('有 ' + str(len(df)) + ' 成功生成的示例。 以下是前几个:')
df.head()
将数据分为训练集和测试集。
python
# 将数据分为训练集和测试集,其中 90% 在训练集中
train_df = df.sample(frac=0.9, random_state=42)
test_df = df.drop(train_df.index)
# 将数据帧保存到 .jsonl 文件
train_df.to_json('train.jsonl', orient='records', lines=True)
test_df.to_json('test.jsonl', orient='records', lines=True)
3.3、安装必要的库
bash
!pip install -q accelerate==0.21.0 peft==0.4.0 bitsandbytes==0.40.2 transformers==4.31.0 trl==0.4.7
python
import os
import torch
from datasets import load_dataset
from transformers import (
AutoModelForCausalLM,
AutoTokenizer,
BitsAndBytesConfig,
HfArgumentParser,
TrainingArguments,
pipeline,
logging,
)
from peft import LoraConfig, PeftModel
from trl import SFTTrainer
3.4、定义超参数
python
model_name = "NousResearch/llama-2-7b-chat-hf" # 如果您有权访问官方 LLaMA 2 模型"meta-llama/Llama-2-7b-chat-hf",请使用此选项,但请记住,您需要传递 Hugging Face 键参数
dataset_name = "/content/train.jsonl"
new_model = "llama-2-7b-custom"
lora_r = 64
lora_alpha = 16
lora_dropout = 0.1
use_4bit = True
bnb_4bit_compute_dtype = "float16"
bnb_4bit_quant_type = "nf4"
use_nested_quant = False
output_dir = "./results"
num_train_epochs = 1
fp16 = False
bf16 = False
per_device_train_batch_size = 4
per_device_eval_batch_size = 4
gradient_accumulation_steps = 1
gradient_checkpointing = True
max_grad_norm = 0.3
learning_rate = 2e-4
weight_decay = 0.001
optim = "paged_adamw_32bit"
lr_scheduler_type = "constant"
max_steps = -1
warmup_ratio = 0.03
group_by_length = True
save_steps = 25
logging_steps = 5
max_seq_length = None
packing = False
device_map = {"": 0}
3.5、加载数据集并训练
python
# 加载数据集
train_dataset = load_dataset('json', data_files='/content/train.jsonl', split="train")
valid_dataset = load_dataset('json', data_files='/content/test.jsonl', split="train")
# 预处理数据集
train_dataset_mapped = train_dataset.map(lambda examples: {'text': [f'[INST] <<SYS>>\n{system_message.strip()}\n<</SYS>>\n\n' + prompt + ' [/INST] ' + response for prompt, response in zip(examples['prompt'], examples['response'])]}, batched=True)
valid_dataset_mapped = valid_dataset.map(lambda examples: {'text': [f'[INST] <<SYS>>\n{system_message.strip()}\n<</SYS>>\n\n' + prompt + ' [/INST] ' + response for prompt, response in zip(examples['prompt'], examples['response'])]}, batched=True)
compute_dtype = getattr(torch, bnb_4bit_compute_dtype)
bnb_config = BitsAndBytesConfig(
load_in_4bit=use_4bit,
bnb_4bit_quant_type=bnb_4bit_quant_type,
bnb_4bit_compute_dtype=compute_dtype,
bnb_4bit_use_double_quant=use_nested_quant,
)
model = AutoModelForCausalLM.from_pretrained(
model_name,
quantization_config=bnb_config,
device_map=device_map
)
model.config.use_cache = False
model.config.pretraining_tp = 1
tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"
peft_config = LoraConfig(
lora_alpha=lora_alpha,
lora_dropout=lora_dropout,
r=lora_r,
bias="none",
task_type="CAUSAL_LM",
)
# 设置训练参数
training_arguments = TrainingArguments(
output_dir=output_dir,
num_train_epochs=num_train_epochs,
per_device_train_batch_size=per_device_train_batch_size,
gradient_accumulation_steps=gradient_accumulation_steps,
optim=optim,
save_steps=save_steps,
logging_steps=logging_steps,
learning_rate=learning_rate,
weight_decay=weight_decay,
fp16=fp16,
bf16=bf16,
max_grad_norm=max_grad_norm,
max_steps=max_steps,
warmup_ratio=warmup_ratio,
group_by_length=group_by_length,
lr_scheduler_type=lr_scheduler_type,
report_to="all",
evaluation_strategy="steps",
eval_steps=5 # 每 20 步评估一次
)
# 设置监督微调参数
trainer = SFTTrainer(
model=model,
train_dataset=train_dataset_mapped,
eval_dataset=valid_dataset_mapped, # 在此处传递验证数据集
peft_config=peft_config,
dataset_text_field="text",
max_seq_length=max_seq_length,
tokenizer=tokenizer,
args=training_arguments,
packing=packing,
)
trainer.train()
trainer.model.save_pretrained(new_model)
# 单元 4:测试模型
logging.set_verbosity(logging.CRITICAL)
prompt = f"[INST] <<SYS>>\n{system_message}\n<</SYS>>\n\n编写一个反转字符串的函数。 [/INST]" # 将此处的命令替换为与您的任务相关的命令
pipe = pipeline(task="text-generation", model=model, tokenizer=tokenizer, max_length=200)
result = pipe(prompt)
print(result[0]['generated_text'])
3.6、运行推理
python
from transformers import pipeline
prompt = f"[INST] <<SYS>>\n{system_message}\n<</SYS>>\n\n编写一个反转字符串的函数。 [/INST]" # 将此处的命令替换为与您的任务相关的命令
num_new_tokens = 100 # 更改为您想要生成的新令牌的数量
# 计算提示中的标记数量
num_prompt_tokens = len(tokenizer(prompt)['input_ids'])
# 计算一代的最大长度
max_length = num_prompt_tokens + num_new_tokens
gen = pipeline('text-generation', model=model, tokenizer=tokenizer, max_length=max_length)
result = gen(prompt)
print(result[0]['generated_text'].replace(prompt, ''))
3.7、合并模型并存储在 Google Drive 中
python
# 合并并保存微调后的模型
from google.colab import drive
drive.mount('/content/drive')
model_path = "/content/drive/MyDrive/llama-2-7b-custom" # 更改为您的首选路径
# 在 FP16 中重新加载模型并将其与 LoRA 权重合并
base_model = AutoModelForCausalLM.from_pretrained(
model_name,
low_cpu_mem_usage=True,
return_dict=True,
torch_dtype=torch.float16,
device_map=device_map,
)
model = PeftModel.from_pretrained(base_model, new_model)
model = model.merge_and_unload()
# 重新加载分词器以保存它
tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"
# 保存合并后的模型
model.save_pretrained(model_path)
tokenizer.save_pretrained(model_path)
3.8、从 Drive 加载微调模型并运行推理
python
from google.colab import drive
from transformers import AutoModelForCausalLM, AutoTokenizer
drive.mount('/content/drive')
model_path = "/content/drive/MyDrive/llama-2-7b-custom" # 更改为保存模型的路径
model = AutoModelForCausalLM.from_pretrained(model_path)
tokenizer = AutoTokenizer.from_pretrained(model_path)
3.9、测试微调训练后的模型
python
from transformers import pipeline
prompt = "请问,哪个字一年四季都不会凋零?" # 更改为您想要的提示
gen = pipeline('text-generation', model=model, tokenizer=tokenizer)
result = gen(prompt)
print(result[0]['generated_text'])
四、总结
本文主要介绍了如何使用GPT大型语言模型训练器来训练你自己的大型语言模型;如何利用GPT-4的强大功能来简化训练过程,并确保你的模型能够实现最佳性能;最后介绍了如何在谷歌Colab上训练大型语言模型的实用技巧和步骤。GPT-LLM-Trainer 是一款经济实惠且易于使用的工具,用于使用您自己的数据训练大型语言模型。它简化了收集、提炼、格式化、选择和训练数据集的复杂过程,并根据您的任务描述为您微调模型。使用此工具,您可以生成各种提示、优化系统提示、拆分数据集、定义超参数以及在 Google Colab 或本地 Jupyter Notebook 上高效运行推理。
五、References
- GPT-LLM-Trainer Github Repo: https://github.com/mshumer/gpt-llm-trainer
- Jupyter Notebook 的完整代码: https://github.com/Crossme0809/frenzyTechAI/blob/main/fine-tuned-llm-trainer/How_to_Fine_Tune_and_Train_LLMs_With_FAST_GPT_LLM_Trainer.ipynb