训练模型(微调)
1. 安装必要的依赖库
py !pip3 install -q -U bitsandbytes==0.42.0 !pip3 install -q -U peft==0.8.2 !pip3 install -q -U trl==0.7.10 !pip3 install -q -U accelerate==0.27.1 !pip3 install -q -U datasets==2.17.0 !pip3 install -q -U transformers==4.38.0
2. Python脚本引入必要的依赖项
py import os import transformers import torch from google.colab import userdata from datasets import load_dataset from trl import SFTTrainer from peft import LoraConfig from transformers import AutoTokenizer, AutoModelForCausalLM from transformers import BitsAndBytesConfig, GemmaTokenizer
3. 引入Huggingface token到环境变量
py os.environ["HF_TOKEN"] = userdata.get('HF_TOKEN')
4. 配置4位量化模型
设置一个4位量化模型的配置。首先指定了模型的ID为"google/gemma-2b"。然后创建了一个BitsAndBytesConfig对象,这是用来设置模型的参数。
py model_id = "google/gemma-2b" bnb_config = BitsAndBytesConfig( load_in_4bit=True, bnb_4bit_quant_type="nf4", bnb_4bit_compute_dtype=torch.bfloat16 )
参数解释
load_in_4bit
设置为True,表示在加载模型时使用4位量化。这种量化可以减少模型的存储和计算需求,从而提高效率。bnb_4bit_quant_type
设置为"nf4",这是一个特定的4位量化类型。bnb_4bit_compute_dtype
设置为torch.bfloat16,这是一种半精度浮点数数据类型,用于在计算过程中保存4位量化的结果。这种数据类型可以进一步减少计算需求,提高效率。
5. 加载并配置预训练模型
这段代码主要是在加载一个预训练模型,并进行一些配置。首先,使用AutoTokenizer.from_pretrained方法加载指定ID(即"google/gemma-2b")的预训练模型的分词器。分词器是用于将输入的文本转化为模型可以理解的形式(即token)。这里的token是从环境变量'HF_TOKEN'中获取的。
然后,使用AutoModelForCausalLM.from_pretrained方法加载预训练模型。
py tokenizer = AutoTokenizer.from_pretrained(model_id, token=os.environ['HF_TOKEN']) model = AutoModelForCausalLM.from_pretrained(model_id, quantization_config=bnb_config, device_map={"":0}, token=os.environ['HF_TOKEN'])
在加载过程中,设置了一些参数:
quantization_config
参数设置为前面定义的bnb_config,这是指定模型的量化配置。device_map
参数设置为{"":0},这可能是指定模型在哪个设备上运行,0通常表示第一个可用的设备。token
参数仍然是从环境变量'HF_TOKEN'中获取的。
6. 生成和解码文本序列
这段代码是用于生成和解码文本序列的。
```py text = "Quote: Our doubts are traitors," device = "cuda:0" inputs = tokenizer(text, return_tensors="pt").to(device)
outputs = model.generate(**inputs, maxnewtokens=20) print(tokenizer.decode(outputs[0], skipspecialtokens=True)) ```
首先,它将一个文本字符串 "Quote: Our doubts are traitors," 作为输入。然后,这个输入被分词器(tokenizer)处理,转化为模型可以理解的形式,也就是一个包含了词语编号的张量(tensor)。
将处理后的输入数据移动到设备(device)"cuda:0",这通常指的是第一个GPU设备。在深度学习模型训练和推理中,通常会使用GPU来加速计算。
然后,该输入数据被提供给模型,模型会根据输入数据生成一个新的文本序列,最大生成20个新的词语。
最后,生成的输出序列被解码回文本形式并打印出来。在解码过程中,特殊的词语(如分词器添加的开始、结束标记)会被跳过。 输出
7. 配置LoRA和加载数据集
这段代码首先设置环境变量"WANDB_DISABLED"为"false",这可能是为了启用或禁用Weights & Biases(W\&B)的日志记录功能。W\&B是一个用于机器学习项目的实验跟踪工具。
然后,创建一个名为lora_config的LoRA(Low-Rank Adaptive)配置对象。LoRA是一种用于改进Transformer模型的技术,它通过对模型中的特定模块(如"q_proj", "o_proj", "k_proj", "v_proj", "gate_proj", "up_proj", "down_proj")进行低秩适应,以提升模型的性能。参数'r'设为8,表示适应的秩。'task_type'设为"CAUSAL_LM",表示该任务是因果语言模型。
接着,加载名为"b-mc2/sql-create-context"
的数据集。这是使用Hugging Face的datasets库的load_dataset函数加载的预处理过的数据集。
最后,使用map函数对数据集进行预处理,将问题和上下文通过分词器进行处理。这里的lambda函数将每个样本的"question"
和"context"
字段作为输入,并将其转化为模型可以理解的形式。参数batched=True表示在处理时会将数据分批处理,以提高效率。
py os.environ["WANDB_DISABLED"] = "false" lora_config = LoraConfig( r = 8, target_modules = ["q_proj", "o_proj", "k_proj", "v_proj", "gate_proj", "up_proj", "down_proj"], task_type = "CAUSAL_LM", ) data = load_dataset("b-mc2/sql-create-context") data = data.map(lambda samples: tokenizer(samples["question"], samples["context"]), batched=True)
执行成功
8. 初始化和配置SFTTrainer进行模型训练
这段代码主要用于配置和初始化一个SFTTrainer,用于训练一个模型。
```py def formatting_func(example): text = f"Question: {example['question'][0]}\nContext: {example['context'][0]}\nAnswer: {example['answer'][0]}" return [text]
trainer = SFTTrainer( model=model, traindataset=data["train"], args=transformers.TrainingArguments( perdevicetrainbatchsize=4, gradientaccumulationsteps=4, warmupsteps=2, maxsteps=75, learningrate=2e-4, fp16=True, loggingsteps=1, outputdir="outputs", optim="pagedadamw8bit" ), peftconfig=loraconfig, formattingfunc=formattingfunc, )
trainer.train() ```
首先定义了一个函数formatting_func,这个函数接收一个例子(example)作为输入,然后将其格式化为一个特定的字符串格式。这个字符串包括问题(Question)、上下文(Context)和答案(Answer)。
然后,使用SFTTrainer
来创建一个训练器。这个训练器需要以下参数:
model
:需要训练的模型。train_dataset
:用于训练的数据集,这里使用的是data["train"]。args
:训练参数,这里使用的是transformers.TrainingArguments。这些参数包括每个设备的训练批次大小(per_device_train_batch_size)、梯度累积步骤(gradient_accumulation_steps)、预热步骤(warmup_steps)、最大步骤(max_steps)、学习率(learning_rate)、是否使用16位浮点数(fp16)、日志步骤(logging_steps)、输出目录(output_dir)和优化器(optim)。peft_config
:Lora的配置,Lora是一种用于压缩BERT模型的技术。formatting_func
:格式化函数,这里使用的是之前定义的formatting_func。 执行成功
9. 生成SQL查询语句
这段代码主要是用于生成一个SQL查询语句,该语句用于查询平均工作马匹数量,对应的农场总马匹数量大于45。
```py text = """Question: What is the average number of working horses of farms with greater than 45 total number of horses? Context: CREATE TABLE farm (WorkingHorses INTEGER, TotalHorses INTEGER)""" device = "cuda:0" inputs = tokenizer(text, return_tensors="pt").to(device)
outputs = model.generate(**inputs, maxnewtokens=20) print(tokenizer.decode(outputs[0], skipspecialtokens=True)) ```
首先,定义了一个包含问题和上下文的字符串text。问题是"农场总马匹数量大于45的工作马匹的平均数量是多少?",上下文是一个创建表格的SQL语句。
然后,将text输入到tokenizer中,将其转换为模型可以理解的输入格式,并将其移动到指定的设备上(这里是GPU)。
接下来,将处理后的输入传递给模型,使用generate方法生成输出。max_new_tokens=20参数限制了生成的新令牌的数量。
最后,使用tokenizer.decode方法将模型生成的令牌解码为人类可读的文本,并打印出来。这个文本就是模型生成的SQL查询语句。 执行成功
最后总结
如果要训练出业务相关的自然语言转SQL的查询语句可采取以下的步骤:
- 第一步,准备可生成数据集的相关数据,包括表结构(建表Schema)、字段业务含义、表的示例数据以及查询事例SQL等。
- 第二步,将以上的数据整合成Prompt交给能力优秀的大模型(比如GPT-4-32K,Claude-3),使其生成成对的{Answer,Question,Context} 的训练数据集。
- 第三步,构建脚本去执行语句或者人为检查,去核对生成的SQL查询语句的准确性,确保数据集的真实有效性。
- 第四步,通过Lora 低秩微调技术在Gemma-2B模型上去做微调训练,在这个过程中检查Loss指标然后去适应性调整迭代周期,训练参数。
- 第五步,通过前期准备的测试数据集,去验证训练的效果,如果效果不满意,继续调整训练参数和数据集,去再训练。
如果训练出的模型达到理想的效果,接下来就可以去实现更复杂的解决方案,包括但不限于:
- 执行生成的SQL查询语句获取数据,然后转换成指定的数据结构在前端渲染动态的图表(动态表单渲染)。
- 直接将SQL查询的数据给到前端,减少后端实现数据库查询的成本 (自然语言查询数据库,表单管理)。
- 解读SQL查询语句,反向生成具体的业务含义(解读报告)。