[本科项目实训] P-tuning v2技术介绍, Prompt设计与尝试

to 2024 / 05 / 13

P-tuning概述

关于 prompt tuning 和 p-tuning 技术有大量的相关博客,我在参考资料中给出对于本项目具有一定启发性的内容并在此做简单总结。

prompt-tuning 为区别于最开始 pre-training + fine-tuning 的大语言模型微调范式,其希望通过添加模板的方式避免引入额外参数,使得语言模型在小样本场景下达到理想的效果。受限于算力,该技术比 fine-tuning 更适合当前项目。

P-tuning v2 相较于 P-tuning不使用 BiLSTM 或 MLP 对 prompt进行表征,直接对这部分 token 对应的深层模型参数进行微调,其本身即为生成式模型,不需要 verbalizer 进行概率预测。

Prompt设计

Pattern的构建方式有人工构建、启发式、生成式、词向量微调、伪标记等,这里由于目标任务不算复杂,有较为明显的结构,因而尝试先使用人工构建的方式,再逐步丰富Pattern类型,从而达到一个较好的预测效果。

基于当前电网任务拆解和总结的步骤,设置了如下三个 Pattern:

content_prompt_0 = "步骤#问候\*语音#%s"

content_prompt_1 = "步骤#理解并基于输入拆分函数参数\*语音#%s"

content_prompt_2 = "步骤#基于函数调用结果进行总结\*工单查询#应到%s人\*目标检测#实到%s人\*任务类型#%s"

然后在此基础上,给出了一些可能的 content 和 summary 的模板:

content_template_0 = [
    "你好", "您好", "早上好", "中午好", "晚上好", "好久不见", "你是谁",
    "你叫什么名字", "自我介绍下", "简单自我介绍下", "你能做什么", "你的用途",
]

summary_template_0 = "您好,我是电网大模型的语言核心,用于拆解执行行为库并向您汇报结果"

content_template_1 = [
    "请尝试查看%s的工地的人数情况",
    "输出工地%s人数情况",
    "尝试查%s的人数",
    "查查在%s工地人数嘛",

    "开始检查%s的安全状况",
    "试试看输出%s携带安全帽的情况",
    "进行在%s的安全帽检测工作",
    "检测在%s的安全帽佩戴情况啊",

    "检测在%s的电笔配备情况",
    "检查%s有没有设备异常",
    "请输出%s工地的设备检查结果",
    "告诉我%s配备电笔检查结果",
]

summary_template_1 = [
    "因为出现地名为%s, 所以函数一参数为%s; 因为出现人数要求, 所以函数二参数为人数检测",
    "因为出现地名为%s, 所以函数一参数为%s; 因为出现安全要求, 所以函数二参数为安全检查",
    "因为出现地名为%s, 所以函数一参数为%s; 因为出现设备要求, 所以函数二参数为设备检查",
]

summary_template_2 = [
    "[人数检测] 应到%d人, 实到%d人, 无人缺勤, 正常出工",
    "[人数检测] 应到%d人, 实到%d人, 有人缺勤",
    "[人数检测] 应到%d人, 实到%d人, 人数异常, 可能存在非法进入",
    "[人数检测] 应到%d人, 实到%d人, 无工单出工, 可能存在非法进入",
    "[安全检查] 实到%d人, 均佩戴安全帽",
    "[安全检查] 实到%d人, %d人佩戴安全帽, 存在安全隐患",
    "[安全检查] 实到%d人, %d人佩戴安全帽, 存在安全隐患",
    "[安全检查] 现场无人施工",
    "[设备检查] 实到%d人, 均正常携带设备",
    "[设备检查] 实到%d人, %d人未携带设备",
    "[设备检查] 实到%d人, %d人未携带设备",
    "[设备检查] 现场无人施工",
]

content_template_2 = ["人数检测","安全检查","设备检查",]

采用random.randint进行训练数据的随机化,为模拟语音识别模型带来的不稳定性,在训练时使用随机 mask 方式提高模型的鲁棒性,采用random.suffle的方式打乱训练测试集内任务顺序:

if train_f:
	tmp_s = list(content_template_0[data_num%12])
	tmp_s[random.randint(0,len(tmp_s)-1)] = mask_template[random.randint(0,mask_num-1)]
	data["content"] = const_content_prompt_0 % "".join(tmp_s)
	data_list.append(data)

最后将数据按json格式写回:

with open(file_path, 'w', encoding='utf-8') as f:
    json.dump(data_list, f, indent = 4, sort_keys = True, ensure_ascii=False)

结果测试

训练参数设置:

PRE_SEQ_LEN=48
LR=2e-2

CUDA_VISIBLE_DEVICES=0 python3 main.py \
    --do_train \
    --train_file train.json \
    --validation_file dev.json \
    --prompt_column content \
    --response_column summary \
    --overwrite_cache \
    --model_name_or_path /home/lyc/workspace/ChatGLM-6B/chatglm-6b \
    --output_dir output/adgen-chatglm-6b-pt-$PRE_SEQ_LEN-$LR \
    --overwrite_output_dir \
    --max_source_length 64 \
    --max_target_length 64 \
    --per_device_train_batch_size 4 \
    --per_device_eval_batch_size 1 \
    --gradient_accumulation_steps 16 \
    --predict_with_generate \
    --max_steps 1500 \
    --logging_steps 20 \
    --save_steps 500 \
    --learning_rate $LR \
    --pre_seq_len $PRE_SEQ_LEN \
    --quantization_bit 4

微调前结果:

用户:您好,请简单自我介绍一下

ChatGLM-6B:您好,我是 ChatGLM-6B,是清华大学KEG实验室和智谱AI公司共同训练的语言模型。我的目标是通过回答用户提出的问题来帮助他们解决问题。由于我是一个计算机程序,所以我没有自我意识,也不能像人类一样感知世界。我只能通过分析我所学到的信息来回答问题。

用户:步骤#理解并基于输入拆分函数参数\\*语音#尝试查寻济南工地的人数

ChatGLM-6B:要查寻济南工地的人数,需要先理解并基于输入的拆分函数参数(语音)进行拆分,然后将拆分后的语音转换为数字。具体步骤如下:

1. 理解并基于输入拆分函数参数(语音)进行拆分:将输入的语音转换为小写字母和数字的组合。可以使用语音合成软件将语音转换为小写字母,然后再将小写字母转换为数字。

2. 将拆分后的语音转换为数字:将小写字母和数字组合转换为数字。可以使用自然语言处理技术,将每个小写字母转换为一个数字,并将所有数字组合起来。

3. 查询济南工地的人数:可以使用数据库来查询济南工地的人数。可以使用 SQL 语句来查询数据库中的人数信息。

请注意,这是一个非常具体的任务,可能需要使用一些高级的自然语言处理技术来完成。

用户:步骤#基于函数调用结果进行总结\\*工单查询#应到47人\\*目标检测#实到34人\\*任务类型#人数检查

ChatGLM-6B:基于函数调用结果进行总结的步骤如下:

1. 调用工单查询函数:根据输入的信息,调用工单查询函数来查询工地的工单信息。

2. 应到47人,说明查询到的结果是有47人。

3. 调用目标检测函数:根据输入的信息,调用目标检测函数来检测目标。

4. 实到34人,说明检测到的结果是有34人,但是实际上只有34人。

5. 调用任务类型函数:根据输入的信息,调用任务类型函数来确定任务的类型。

6. 说明这个任务是人数检查任务,因为只有34人,所以人数检查是失败的。

总结起来,这个任务需要调用多个函数来实现,根据函数调用的结果,可以对任务进行总结。

微调后结果:

用户:您好,请简单自我介绍一下

ChatGLM-6B:您好,我是电网大模型的语言核心,用于拆解执行行为库并向您汇报结果

用户:步骤#理解并基于输入拆分函数参数\\*语音#尝试查寻济南工地的人数

ChatGLM-6B:因为出现地名为济南, 所以函数一参数为济南; 因为出现人数要求, 所以函数二参数为人数检测

用户:步骤#基于函数调用结果进行总结\\*工单查询#应到47人\\*目标检测#实到34人\\*任务类型#人数检查

ChatGLM-6B:[人数检查] 应到47人, 实到34人, 有人缺勤

可以看到微调前后具有明显区别,通过人工设计的 prompt 进行训练,微调后的 LLM 能够基本满足任务需求。

后续(本科项目实训)

构建具体的行动库,并根据与行动库的交互规则设置更合适的 prompt 进行训练,采用人工和生成并举的方式构建多种类型的 pattern 来提高模型的适应能力。

参考资料

[1] 参数高效微调PEFT(二)快速入门P-Tuning、P-Tuning V2-CSDN博客

[2] 论文解读:P-Tuning v2: Prompt Tuning Can Be Comparable to Finetuning Universally Across Scales and Tasks_p-tuning和prompt tuning-CSDN博客

[3] 何以动摇Fine-tune?一文综述Prompt Tuning发展-CSDN博客

[4] Prompt-Tuning——深度解读一种新的微调范式_prompt tuning-CSDN博客

[5] AI大模型探索之路-训练篇23:ChatGLM3微调实战-基于P-Tuning V2技术的实践指南_p-tuning 微调实战glm3

posted @ 2024-05-31 11:18  yicheng_liu0219  阅读(339)  评论(0)    收藏  举报