前言
用LLM大模型来finetune处理传统的文本分类任务。分类任务当作生成式任务来做, 有点大炮打蚊子。但还是非常想尝试下,该文记录算法工程师做整个任务的过程。
第一步:base基座模型选择。
大概就三个: Qwen2-7B/internlm2_5-7b-chat/glm-4-9b-chat.
我们拿出50个case对三个模型进行zero-shot测试, 测之前我是对Qwen2-7B非常期待的, 但测出来glm-4-9b-chat效果最好。因此,我们选择glm4-9B为我们的基准模型。
第二步: 熟悉finetune方法(卡限制只考虑PEFT)
Lora/Ada-Lora/Prefix-tuning等等。
第三步: 数据集准备
两个情感标签数据集:
- 大众点评评价数据: http://www.modelscope.cn/datasets/DAMO_NLP/yf_dianping.git
- 京东商品评论数据集: https://modelscope.cn/models/iic/nlp_structbert_sentiment-classification_chinese-large
我们要转为生成数据集的格式:
大概就是: system(交代背景)
Usr: 评论
Assistant: AI给出回答
def question_reprocess(sentence, label):
global reprocess_data
sys_prom = f'''你是情感判断专家。我们将给出一段对于商品的文本评论, 你需要判断该评论是: "积极评论。",还是: "消极评论。"。如果该评论是对商品满意, 请回答: "积极评论。"。如果该评论是对商品不满意, 请回答: "消极评论。"。以下,我将给出一个商品的评论:'''
usr_prom = f'''{sentence}'''
if label == 0:
answer_prom = f'''消极评论。'''
else:
answer_prom = f'''积极评论。'''
messages_e_json = dict()
messages_e_json['messages']= [
{
"role": "system",
"content": sys_prom,
},
{
"role": "user",
"content": usr_prom
},
{
"role": "assistant",
"content": answer_prom
}
]
reprocess_data.append(messages_e_json)
第四步: 跑出baseline,再提升。
- 傻瓜式的Baseline
目前finetune的框架太多, 很多只需要你用命令行就可以训练。基本上只用调超参数就行。
但这样的方式有几个缺陷:
- 几乎没法加自己的训练策略,有点low, 体现不了工作量,被质疑"你干了个啥?"
- metrics也很难评测
为此,我们用源码训练。
同样的:
- 定义训练格式 json解码
- 增加metrics评测,因为是情感标签 我们采用简单的ACC
- Baseline 我们采用Lora
- 增加点自己东西, training with COT data, 由基准模型生成COT数据
def question_reprocess_cot(sentence, label, cot_json):
global reprocess_data
cot = eval(cot_json)['cot']
sys_prom = f'''你是情感判断专家。我们将给出一段对于商品的文本评论, 你需要判断该评论是: "积极评论。",还是: "消极评论。"。如果该评论是对商品满意, 请回答: "积极评论。"。如果该评论是对商品不满意, 请回答: "消极评论。"。以下,我将给出一个商品的评论,你回答情感标签并给出推理过程。'''
usr_prom = f'''{sentence}'''
if label == 0:
answer_prom = f'''消极评论。{cot}'''
else:
answer_prom = f'''积极评论。{cot}'''
messages_e_json = dict()
messages_e_json['messages']= [
{
"role": "system",
"content": sys_prom,
},
{
"role": "user",
"content": usr_prom
},
{
"role": "assistant",
"content": answer_prom
}
]
#print(messages_e_json)
reprocess_data.append(messages_e_json)
再来点工作量, 本质上是个分类任务, 我们对标签评论上loss。
- cl_loss (分类loss)
- kl_loss (kl约束分布)
Todo:
- 蒸馏我觉得应该很有效
*DPO or RL 等,可能有效 - prompt应该可以再修改提升
总结:
感觉大模型还是能再提升的,比起专门structBERT我们只在本数据集下能够达到差不多的水准。
第五步: 用openai-api部署训练好的server。
if __name__ == "__main__":
tokenizer = AutoTokenizer.from_pretrained(MODEL_PATH, trust_remote_code=True)
engine_args = AsyncEngineArgs(
model=MODEL_PATH,
tokenizer=MODEL_PATH,
enable_lora=True,
tensor_parallel_size=1,
dtype="bfloat16",
trust_remote_code=True,
gpu_memory_utilization=0.9,
enforce_eager=True,
worker_use_ray=True,
engine_use_ray=False,
disable_log_requests=True,
max_model_len=MAX_MODEL_LENGTH,
)
engine = AsyncLLMEngine.from_engine_args(engine_args)
uvicorn.run(app, host='0.0.0.0', port=8080, workers=1)
先添加基准模型,再添加LoRARequest。