LLM系列:SFT微调demo

392 阅读3分钟

1 prompt工程

例如:做一个天气预报系统,用户可以提问并查询某个城市、某个日期的天气。

系统实现非常简单:写一个prompt工程提取用户query中关键词:日期+城市,调用天气预报API查询天气(日期+城市)。

用户查询天气的query:

91日北京天气预报
830日杭州天气怎么样?
上海92日的天气情况
...

为什么需要prompt工程? A:为了让大模型更好理解用户问题。
prompt工程样例如下,把用户问题query转换成prompt,传入大模型可以得到更准确的结果。

prompt_template='''
分析问题中出现过的城市和日期

交互格式如下:

问题:用户的原始问题,里面可能包含城市和日期信息
回答:提炼问题中出现的城市名和日期,按格式整理返回,
   城市:值是城市的名字
   日期:值是具体日期
   
现在开始。

问题:%s
回答:
'''
prompt=prompt_template%(Q,)
print(prompt)

生成的prompt如下:

分析问题中出现过的城市和日期

交互格式如下:

问题:用户的原始问题,里面可能包含城市和日期信息
回答:提炼问题中出现的城市名和日期,按格式整理返回,
   城市:值是城市的名字
   日期:值是具体日期
   
现在开始。

问题:8月29日杭州天气预报
回答:

城市: 杭州
日期: 8月29日

没有微调的初始化模型,执行多次回答格式并不稳定,会出现如下回答:

杭州:城市名 - 杭州,日期 - 2021年8月29日

2 SFT微调

监督式微调,即提供足够多训练数据(上述Q-A),让模型学习解析结构化数据日期、城市的能力。

步骤1 生成训练数据

随机生成1000个样本,每个样本按照SFT微调数据格式拼接,样例代码如下:

for i in range(100):
    Q=Q_list[random.randint(0,len(Q_list)-1)]  ## 选择问题格式
    city=city_list[random.randint(0,len(city_list)-1)] ## 随机选择城市
    year=random.randint(1990,2025) ## 随机选择日期

    Q=Q[0].format(city=city,year=year,month=month,day=day) # 问题
    A='城市:%s\n日期:%s'%(city, date_field)
    
    example={
      "id": 'identity_{}'.format(i),
      'conversations': {
        {
          "from": "user",
          "value": prompt_template%(Q,),
        },
        {
          "from": "assistant",
          "value": A,
        },
      }
    }
    # print(example)
    train_data.append(example)

步骤2 训练

Qwen提供如下微调脚本

本案例使用Q-LoRA微调,参照官方文档执行.

bash finetune/finetune_qlora_single_gpu.sh -m qwen/Qwen-1_8B-Chat-Int4/ -d sft_weather/train.txt

单卡训练大概20几分钟。

3 加载SFT模型

按照文档

from peft import AutoPeftModelForCausalLM

model = AutoPeftModelForCausalLM.from_pretrained(
    'Qwen-main/output_qwen', # path to the output directory
    device_map="auto",
    trust_remote_code=True
).eval()

测试SFT后的效果

Q_list=['2024年9月1号北京天晴?''西安有个xx明星演唱会,5月2日,你打算去不?']
for Q in  Q_list:
  prompt=prompt_template%(Q,)
    A,hist=model.chat(tokenizer,prompt,history=None)

执行结果满足要求。如下:

image.png

参考:
github.com/owenliang/q…