探讨 | 大模型在传统NLP任务的使用姿势

发布于 2024-10-24 14:37
浏览
0收藏

以chatgpt为起始节点的大模型技术经过了两年左右的发展,大致沉淀了一些较为确定的研究领域。首先是基座大模型的研究,主要是国内外大厂集中大量财力、人力、算力进行大模型军备竞赛,企图将大模型的基础能力(包括推理能力)上限逐步提升到更高的层次。当然也有一些研究机构致力于改进transformer的架构或者提出其他更先进的基础模型结构,在性能或者效率上做文章,例如MOE,Mamba等;多模态模型,让大模型同时能够理解并生成图像、音频、视频、文字等多种模态的信息,例如大火的Sora。其次是大模型的微调对齐研究,主要是基座大模型通过指令微调、强化学习等技术将其变成一个应用友好、用户友好的能力模型,也可以将模型长文本、长上下文能力的提升也包含在该方向内;另外,还有大模型的高效部署和推理计算,在降低大模型服务成本的同时,提升大模型服务的实时性,提升用户体验;最后,则是大模型在各种细分场景领域的应用落地,能够将大模型封装成一个成熟的应用产品,真正的将大模型用起来,当然也可以将agent相关的技术研究归纳在这个方向上,因为agent的目标就是将大模型的能力充分利用起来,帮助人类更好地使用大模型。详见下图所示:

探讨 | 大模型在传统NLP任务的使用姿势-AI.x社区

本人目前主要精力集中在大模型的应用落地,对大模型在传统NLP应用任务上的效果非常感兴趣。正好前段时间,有潜在客户希望我们研究是否能够通过大模型提升新闻事件分类的效果。借着这个机会,我对大模型在文本分类任务上的应用方式和对应效果进行了研究,有了一些初步的结论。本文希望通过描述上述研究过程与结果,总结出大模型在文本分类任务上的最佳实践,并推广到更多类似的应用上,为业界做大模型应用时提供一些落地的参考。

应用场景分类

在谈具体的研究内容前,需要先明确一下研究的问题类型。目前对于可能会应用到大模型的传统NLP应用,我自己将其分为两种不同的情况:

(1)开荒式业务场景。这种场景主要出现在那些刚刚完成数字化还未进行智能化的机构、或者业务场景本身比较复杂、传统技术无法在该场景中匹配最低的用户使用体验要求的情况。特点:数据积累不成熟(也就是没有足够的训练语料用于场景专用模型的训练)、硬件资源不足(没有足够的GPU用于训练模型)等。

(2)优化提升式业务场景。这种场景主要出现在那些已经有一定智能化基础的机构、或者业务场景中已经使用了一些传统NLP技术解决了部分问题的情况。特点:需要提升已有方法的应用效果和用户体验(如准确率、召回率等),当前方法继续优化的难度较大。

本文主要讨论的是第二种场景,这也是很多有一定数字化、智能化基础的公司比较关注的类型。他们在大模型提出之前,已经通过一些规则、统计机器学习、深度神经网络等算法模型技术构建了一些分类服务,有些行业头部团队在此基础上通过一些技巧(数据增强,对抗训练等)进行了优化,将算法指标提升到了某个瓶颈线。然而,业务用户对于算法的精度提升要求是持续性的,因此在大模型出现之前的一段时间,算法人员疲于应付业务用户对于场景效果的高要求。

只用prompt工程足够吗?

截止2024年,我浏览过很多应用大模型研究传统NLP任务的工作,大多集中在如何利用prompt技术、few-shot技术等直接将大模型应用在这些传统任务中。例如这一篇:Can ChatGPT Understand Too? A Comparative Study on ChatGPT and Fine-tuned BERT,通过prompt工程对比ChatGPT与Fine-tuned Roberta在GLUE数据集上的效果,最终的结论是Fine-tuned Roberta在文本理解任务上仍然无法被超越。然而我也看到有一些观点认为这些传统任务直接用大模型一把梭就能搞定,只要prompt写的足够好,就能得到一个足够好的语言理解分析服务。本人并不反对这种观点,而且还支持对过去的一些应用模式进行革新,从而让大模型能够充分发挥其特性。不过在目前的阶段,很多企业或者业务场景基于安全、成本、时延等因素,无法使用综合能力强的模型(GPT4,国内模型的付费版公有云服务、超过14B的开源模型等),而通过纯prompt工程使用类似7B的模型还无法完全替代已经在足量数据上训练过的BERT类模型。由于上述提到的研究是使用ChatGPT以及英文的数据集,为了验证国内开源的大模型是否在中文数据集上是否也有类似的结论,下面我将根据相关的目标应用场景以一个具体的数据集的实验来说明。

应用场景与数据集

目标应用场景:新闻事件分类任务。任务特点:

(1)多标签分类任务,即一个新闻可能会对应多个事件类别;

(2)事件标签体系庞大,且有比较严重的类别不均衡问题。出现频次高的类别容易累积训练数据,而低频长尾类别属于典型的小样本问题。

由于一些原因,不能拿到相关真实场景数据,因此搜寻了网上的公开数据集,最终找到了一个比较贴近上述任务特点的数据集:ccks 2022 任务八数据集。

数据链接见:https://tianchi.aliyun.com/dataset/136800

数据集简介:数据主要来自金融领域的公开新闻、报道,数量在5万+左右。原始数据集的任务是“给定100+事件类型及其事件主体公司,训练数据中对其中16个事件类型只保留10条左右的训练样本,测试集中包含这16个类型的大量待抽取样本。

本次的验证为了简化问题,不会采用上述的任务形式,而是采用最基本的全类别分类数据集的处理方式,从而验证模型在这种类型的数据集上的整体效果,以及在一些小样本类别上的效果。

由于目前只有训练集有标注标签,因此只能针对标注数据集进行分析。具体做法是根据标注数据分布划分了训练集,测试集(5000+),其中测试集只用于评测模型的最终结果。

备注:该数据集存在一定的标注质量问题,前期通过一些人力检测与校正,提升了部分的标注质量。

数据示例如下:

{"textId": "2333e4ef53762e498cc79c7613d6ac6f", "text": "科锐国际:2018年年度权益分派实施公告", "eventTags": [{"eventType": "公司权益分派", "eventCompany": "科锐国际"}]}
{
    "textId": "35a726ecec33a755abea4ff6fd5464ec",
    "text": "讷河软式透水管有限责任—讷河公司;湘潭招聘/万达集团招聘信息;多次延期后,ST康美终于披露回覆函",
    "eventTags": [
        {
            "eventType": "延期信息披露",
            "eventCompany": "ST康美"
        },
        {
            "eventType": "当地招募员工",
            "eventCompany": "万达集团"
        }
    ]
}

事件标签数量为174个,均为金融相关的事件标签。以下为部分事件标签样例。

探讨 | 大模型在传统NLP任务的使用姿势-AI.x社区

对数据集进行分析后,发现其具备典型的长尾分布特征,与实际的业务数据分布比较类似。由于类别比较多,以每个类别为粒度进行画图不够直观,因此将所有标签类别按照从大到小顺序排序后,以10为一组进行分组,按照组的粒度画出的柱状图如下(图由GPT-4生成):

探讨 | 大模型在传统NLP任务的使用姿势-AI.x社区

以下是出于长尾位置的部分事件标签样例:

  • 产品虚假宣传: 9
  • 产品亏损: 3
  • 行业排名下降: 41
  • 责令转让所持证券公司股权: 21
  • 新增分支机构: 38
  • 分支机构被警方调查: 11
  • 非法集资: 8
  • 发放贷款出现坏账: 27
  • 挤兑: 41
  • 诉讼仲裁-败诉: 29
  • 澄清辟谣: 9
  • 停产停业: 10
  • 上市前融资: 33
  • 销量下降: 48
  • 行政处分: 33
  • 薪酬福利下降: 16
  • 被盗: 44
  • 实际控制人违规: 10
  • 发布新产品延期: 24
  • 其他经营不善: 39
  • 贷款用途变更: 17
  • 第一大股东变化: 8
  • 客户管理不善: 29
  • 市场份额减少: 28
  • 产品质量问题: 10
  • 股东借款: 4
  • 财务报表更正: 8
  • 经营资质瑕疵: 8
  • 引入新股东: 9
  • 停止批准增设分支机构: 24
  • 授信额度上升: 10
  • 资金紧张: 7
  • 在当地撤资: 22
  • 股权融资失败: 19

基于BERT的baseline

为了验证大模型的相关方案与传统的NLP方案相比是否有提升,因此选定了BERT簇的分类方案作为baseline来进行对比。

BERT也是一个以Transformer为模型架构的预训练语言模型。

  • 参数量相比LLM大模型更小,基本在亿级参数以下
  • 训练方式与LLM大模型不同,更注重语义理解类任务,而不是文本生成式任务
  • 一般需要适量的下游任务训练数据进行微调,并在基座模型的基础上设计针对下游任务的额外组件,从而得到一个任务专用的模型。微调难度较小。
  • LLM大模型出世之前,业界主流的方法

BERT与GPT在语言模型训练任务上的区别如下图所示:

探讨 | 大模型在传统NLP任务的使用姿势-AI.x社区

探讨 | 大模型在传统NLP任务的使用姿势-AI.x社区

具体来说,本次实验的BERT模型选择了哈工大的macbert-base和macbert-large两种体量的模型。

模型链接如下:https://github.com/ymcui/MacBERT

具体训练方式:

输入:新闻文本

输出:事件标签列表

loss函数:BCEWithLogitsLoss

将所有训练数据(5万+)灌入模型进行训练

最终,base和large模型的指标如下:

探讨 | 大模型在传统NLP任务的使用姿势-AI.x社区

基于Prompt工程的LLM方法

将LLM大模型直接应用于文本多标签分类任务,实际上就是编写提示词指令,让大模型去生成最终的事件标签结果。整体还是一个文本生成的过程。

提示词模版样例如下:

f"作为一个多标签新闻分类专家,你的任务是识别出新闻中的所有相关事件标签。
事件标签列表:{event_tags}。新闻内容:{text}。该新闻对应的所有事件标签是什么?"

其中,event_tags需要把体系中的事件标签填入。这里涉及到两个问题:

  • 如果事件标签体系很庞大,把所有事件标签装进去不太现实,超过了大模型能够处理的文本长度上限。
  • 把所有标签装进去会增加大模型分析处理文本的难度

基于当前最新的技术发展,有的开源大模型已经能够处理超过128K的上下文,对于170+的标签文本是能够覆盖的。当然,能处理和处理好是两种概念,对于大模型来说,肯定是标签范围越小越容易解决问题,因此也可以通过先将事件标签进行分级分组,然后逐级进行大模型的分析,两种方式均可。

引入Few-shot sample

为了能够充分利用已有的标注数据集和大模型的能力,在上述prompt中,还可以引入示例样本(一般论文里面都叫demonstrations),从而激发大模型的In-context learning能力。为此,对整体训练数据集设计了如下的工作流程:

探讨 | 大模型在传统NLP任务的使用姿势-AI.x社区

该工作流程的主要核心思想是将示例样本的选择问题转化成RAG(Retrieve-Augmented-Generation),将训练样本集合向量化存储后,对于每个测试样本的分析,通过召回+排序的方式做知识库的检索,根据预设的示例样本数量(实验中设置为10),选择语义最相似的标注样本填充到prompt中。

示例样本填充顺序重要吗?

在选择示例样本后,还有个容易被忽略的问题:示例样本填充入prompt的顺序需要关注吗?

之前,有一些文章提到过,RAG得到的召回样本在prompt中,如果较为相似的召回内容离用户问题越近,大模型的回答质量会更高。我也尝试了这样的处理方式,将相似度高的样本放置在了与待预测的新闻文本接近的位置。提示词模版样例如下:

你是一个先进的大语言模型,专门用于理解和分类金融新闻资讯,现在需要你根据提供的新闻内容,
将其分类到预定义的事件标签中。任务要求:
1、仔细阅读新闻内容,理解新闻主题和核心内容。
2、只使用给定的事件标签列表进行分类,若新闻属于多个事件标签,则使用竖线|来分隔不同的事件标签,
若没有合适的事件标签,则分类为others。
3、只需要输出事件标签名字,其他内容不需要输出。
事件标签列表如下,使用英文逗号分隔:\n{event_tags}
下面是给你提供的人工标注过的参考样例:
{demonstrations}待分类的新闻内容如下:{text}
该新闻事件标签为:

其中demonstrations存放的顺序为按照示例与待预测样本相似度的正序排列,即相似度越高的排得越后,离待预测样本text越近。

通过上述处理方式,确实能够在这个任务上有比较微小的提升,虽然提升幅度不大,但操作成本上也几乎可以忽略,因此推荐使用。

结果

基于纯Prompt工程的方式采用了开源的qwen-7b-chat,Yi-34b-chat-int4,闭源的qwen-72b-chat接口(百炼平台)三种大模型来验证。(实验的时候,qwen1.5还未出,但根据其他任务的分析,可以推测不会相差太多)

具体指标如下:

探讨 | 大模型在传统NLP任务的使用姿势-AI.x社区

根据指标结果,可以看到纯Prompt工程的方式,即使是使用百亿级别参数量的模型,还是离传统BERT方式的效果差不少。因为LLM大模型的训练方式与BERT不同,以文本生成为目标,是单向构建上下文(从左到右);而BERT训练是以完形填空式任务为目标。相比于LLM,能够在双向(向左向右)构建上下文理解,本身就适配自然语言理解任务(文本分类,信息抽取等均为理解任务)。

通过分析大模型的错误case,可以发现很多样本都是因为指令遵循能力不够(比如格式未按要求,生成了无关的分析解释内容等),导致格式处理后的结果是错的。因此,推测如果对大模型进行训练样本的sft,应该还能够在指标上有不少的提升。

Prompt工程+指令微调

方法描述

既然要指令微调了,那么基于硬件成本限制,就只能选择一些性价比高的开源模型来做验证了。因此,最终选择了qwen-7b-chat和qwen-14b-chat来做实验。针对当前的数据集,结合Prompt工程和指令微调技术,设计了如下的大模型文本分类流程:

探讨 | 大模型在传统NLP任务的使用姿势-AI.x社区

与Prompt工程的方案相比,本方案加入了指令微调的步骤。具体来说就是对训练集进行数据筛选和处理后,筛选出高质量的训练数据集,然后通过lora的方式进行低成本的指令微调模型,最后在微调后的模型上使用Prompt工程来完成样本的分类。整个流程中,有几个重要节点的详细说明如下:

  • 构建指令形式的训练数据集时,需要生成指令提示词模版,并将每个样本填充到提示词模版中。一般的做法是一种任务都用同一个提示词模版。不过,这样处理可能会让微调后的大模型对指令的理解能力不够鲁棒。因此,我通过ChatGPT,让其为我生成了适合该分类任务色50+个提示词模版,并为每个样本随机分配一个。通过这种方式,能够让大模型对指令的遵循能力更好。
  • 关于高质量数据筛选的问题,其实我做了两个不同的方法实验。一个是全量数据的微调(5w+),另一个是采用一些数据选择的方法,得到适量的样本子集用于训练。

这些方法除去一些不太方便实现的(例如要训练一个reward模型,标注成本太高),基本都实现了一下,在当前的数据集上效果都不是很理想,猜想应该是上面的方法对于目标是复杂生成的任务会更有效。

实际上,探究数据集精选的本质,不外乎以下两点:(1)样本多样性高;(2)对于任务的重要性或者增益程度尽量高。其实,之前做文本摘要的时候,对摘要句子的选取也是遵循这两个原则,因此自然而然就想到可以借用文本摘要的思想来选择:

(1)先将所有样本根据标签类别分成不同的簇(当然,也可以对样本进行聚类分析,得到的簇可能更偏文本本身的语义相似性聚合)

(2)对每个簇中的样本,采用MMR算法进行样本的排序。MMR综合考虑了样本的多样性和相关性,因此我们可以根据分数从高到低选择一定数量的样本放到训练集中。

MMR算法:https://zhuanlan.zhihu.com/p/83596443

(3)对于包含多个标签的样本,以及样本数量本身就很少的标签均采用白名单模式,即全部加入样本集合中。这也是为了让大模型对多标签、小样本的情况能够尽可能多的学习。

通过上述方式,选择了4000+的样本用于训练。(每个标签数据都会覆盖到)

结果

我们将上述筛选后的训练样本集与全量训练样本集进行了大模型微调的对比实验,可以发现一些有趣但并不意外的结果。

探讨 | 大模型在传统NLP任务的使用姿势-AI.x社区

  • 结论1:大模型的参数量越大,整体的指标效果越好。但限于使用成本,通常没办法无限制提升模型的参数量级。
  • 结论2:当标注数据比较少的时候,大模型微调后的效果还是会优于BERT簇模型,在小样本类别的效果上,也要更好。
  • 结论3:全量数据集微调在整体指标上比子集微调要更好,但是在小样本标签类别上的效果不一定,会根据使用的模型而定。

根据上述的对比实验,可以看到当标注数据量比较充裕的时候,LLM即使经过微调、提示词精心设计等步骤后,整体的效果还是不如BERT模型的微调效果。除了上一小节提到的“LLM大模型的训练方式与BERT不同”的原因外,可能还有以下这个因素:

BERT在数据量充足的条件下,能够充分“过拟合”下游任务信息,从而在任务上达到不错的效果。但是微调后的模型完全无法去做其他任务;而LLM大模型的目标本就是通用人工智能,不会为了某个具体任务而丧失通用性,因此经过一定的指令微调后,并不会充分“过拟合”某个任务。

当然,在标注数据量不是非常充分的情况下,使用大模型做指令微调配合Prompt工程,确实能在小样本场景下有不错的效果。实际的应用场景中,有些小样本的事件标签虽然出现次数不多,但业务属性却非常重要,提升这些数据的效果,可能对整体的评测效果没有明显的影响,但对业务使用来说是能够提升体验的。

大模型+BERT式微调

大模型+指令微调的组合终究与追求精度提升的文本理解类任务不太契合。在足量的标注数据场景下,精度上难以匹敌传统的BERT式微调方法。但是大模型毕竟在参数量和学习的知识信息量级上要远超过往的BERT簇模型,所以从理论上来看,只要能够充分利用大模型庞大的知识量,其在文本理解能力上必然是超越BERT簇模型的。指令微调+Prompt工程的大模型生成式方法在文本理解类任务上并没有充分利用到大模型的丰富知识,那么能否参考BERT式的微调方法,将大模型的参数权重作为基座,去针对性适配下游任务呢?答案是可行的,因为大模型本质也是一个transformer模型网络,只不过预训练的方式不同而已,只需要在网络的最后一层添加对应的任务层即可。不过在实际落地时,这种方式可能面临这样的问题:

目前主流的大模型参数通常在7B以上的量级,使用这种参数量的模型即使是使用lora微调,训练和在线推理预测的成本也是不小的,为了某个单个任务的精度提升而去过拟合一个大模型看上去得不偿失。

不过,上述问题在通义千问发布了0.5B、1.8B的模型后得到了极大的缓解。相对于7B的参数量,1.8B左右的模型在训练成本与推理的时延等方面都能得到足够的控制。因此,本次实验就以qwen1.5-1.8B为基准模型,来探索它结合了BERT式微调方法后的效果。

方法描述

大模型使用BERT式的微调方法其实很简单,甚至transformers的库都已经帮我们写好了,直接使用"Qwen2ForSequenceClassification"即可,其他的流程就跟传统的文本分类流程一样就行了。另外需要手动指定tokenizer的pad_token_id,否则在构建Dataset数据进行tokenize的时候会报错。

整个训练流程其实与传统文本任务相似,但是有一些训练中的细节内容,我想在下面着重分享一下。

  • base模型通常比chat模型的微调效果更好。我在不同参数量的模型上均做了一些训练尝试,发现base模型的效果通过会比chat模型要好。这是因为chat模型通常会对base模型进行一些对齐训练,使其在安全性、幻觉程度、用户友好程度等方面得到提升,但是会因为一些“对齐税”,导致模型丧失部分基础能力或者知识。
  • NEFT方法,在微调中的增益效果是稳定的。NEFT简单来说就是在embedding层引入一些噪声,从而增强模型的鲁棒性。我感觉这个方法与之前竞赛中常用的对抗训练技巧(FGM)有类似的思想。简单来说就是在前向计算的时候给embedding层增加噪声扰动,在梯度计算结束和参数更新之间要将embedding还原回去,通过这种方式增强模型的鲁棒性。

NEFT方法: https://arxiv.org/pdf/2310.05914.pdf
FGM方法: https://zhuanlan.zhihu.com/p/91269728
  • 建议使用lora微调。通过实验对比发现,lora微调和全参数微调的效果几乎没有明显差距。那么训练参数更少的lora方式显然更值得推荐,使用lora后微调的参数(340M)恰好与bert-large参数量相当;在设置lora参数时,建议将embedding参数也加入训练。我使用的参数配置见下:

lora_config = LoraConfig(
        r=32,  # low rank
        lora_alpha=64,  # alpha scaling, scale lora weights/outputs
        target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"], #if you know
        lora_dropout=0.1,
        bias="none",
        modules_to_save=["score","embed_tokens"],
        task_type=TaskType.SEQ_CLS # 文本分类使用该类型
    )
  • 如果使用chatglm3进行BERT式微调时,如果使用bf16精度,可能会遇到一个bug。它的modeling_chatglm.py脚本中,没有指定对任务dense层的参数进行正确的参数初始化,在训练的时候任务dense层的参数都会精度溢出,从而导致loss一直是nan。修改的方式也很简单,增加指定的参数初始化方法就行。代码行15-18的部分就是新增的代码。

class ChatGLMPreTrainedModel(PreTrainedModel):
    """
    An abstract class to handle weights initialization and
    a simple interface for downloading and loading pretrained models.
    """

    is_parallelizable = False
    supports_gradient_checkpointing = True
    config_class = ChatGLMConfig
    base_model_prefix = "transformer"
    _no_split_modules = ["GLMBlock"]

    def _init_weights(self, module: nn.Module):
        """Initialize the weights."""
        if isinstance(module, nn.Linear):
            module.weight.data.normal_(mean=0.0, std=self.config.initializer_range)
            if module.bias is not None:
                module.bias.data.zero_()
        return

结果

下面列出使用qwen1.5-1.8B模型进行BERT式微调与前述的方法效果对比。

探讨 | 大模型在传统NLP任务的使用姿势-AI.x社区

可以看到,qwen1.5-1.8B+BERT式微调+lora的组合在整体F1精度和小样本标签类别的F1精度都是最好的。当整体数据集的量级比较少的时候,qwen1.5-1.8B+BERT式微调+lora对于小样本标签类别的表现也是不错的,证明其在小样本学习能力上也是有提升的。

结论是否适用其他分类任务?

当然,仅在一个任务上的实验结果肯定是不足以支持上述的结论的,为了验证这种方式是否能够在文本分类通用任务上有不错的效果,我又在两个开源的数据集上进行了验证,分别是THUCnews数据集以及Iflytek文本分类数据集。下面列出BERT-baseline以及qwen1.5-1.8B+BERT式微调+lora的组合的分类F1指标对比。

THUCnews数据集: http://thuctc.thunlp.org/#%E4%B8%AD%E6%96%87%E6%96%87%E6%9C%AC%E5%88%86%E7%B1%BB%E6%95%B0%E6%8D%AE%E9%9B%86THUCNews
Iflytek数据集: https://aistudio.baidu.com/datasetdetail/243969

注意!!!以下所列指标为本人自己训练后的结果,比公开出来的数据指标会低一点,因为我不太喜欢干调参的活,就随机选了超参数,不过bert与qwen两者训练的通用参数是保持一致,目标是验证qwen是否能够对bert有效果的提升,所以不建议与公开榜单指标做对比。

探讨 | 大模型在传统NLP任务的使用姿势-AI.x社区

可以看到,qwen1.5-1.8B+BERT式微调+lora在其他分类任务上的精度相较于bert-large来说还是能有不错的提升。

结论适用于其他参数量的模型吗?

答案是肯定的。实际上,我还尝试了qwen1.5-4B,qwen1.5-7B,chatglm3-6B,minicpm等模型结果,下面列出部分数据集的效果。

探讨 | 大模型在传统NLP任务的使用姿势-AI.x社区

随着大模型参数量的增加,BERT式微调的效果似乎并没有随着参数显著得提升,可以看到的是即使是BERT式微调方法,也无法利用大模型更多的参数知识了。结合应用实际成本的考量,选择qwen1.5-1.8B似乎是当前性价比最高的。

当然,我对上述结果也不是完全没有疑问的。最大的变数在于这些国内大模型是否在预训练的时候将这些开源的数据集包含进去了。如果在训练的时候就见过这些数据,那么对上述结果的真实性就需要进一步验证了。

应用落地的“新姿势” 采用BERT式的微调方式,由于是让模型尽量过拟合某个下游任务,微调后它就无法适配其他类型的任务了,因此在实际应用时,对于不同的任务会微调部署多个独立的模型。对于大模型来说,如果每个任务都单独部署一个模型从应用成本上来看显然是不可控的。但通过上述的lora微调,可以有效得降低应用部署的显存成本。

1、训练阶段,针对不同的任务,使用不同lora单独进行训练,得到独立的lora权重。

其实我尝试过MTDNN的多任务同时训练的方式,即增加lora的参数规模,然后同时训练不同的分类任务,目的是用一个模型cover多个任务。具体做法是在数据预处理batch的时候,根据不同任务的数据量比例通过采样的方式采样某个任务的1batch数据参与当前step的训练。然后通过在模型定义时,指定对应任务与任务dense层的映射关系来保证每个任务都能使用正确的。

MTDNN方法: https://github.com/microsoft/MT-DNN

class MTDNNForSequenceClassification(Qwen2PreTrainedModel):
    def __init__(self, config,task_configs):
        super().__init__(config)
        # self.num_labels = config.num_labels
        self.model = Qwen2Model(config)
        # self.score = nn.Linear(config.hidden_size, self.num_labels, bias=False)
        self.task_heads = nn.ModuleDict({
            f"task_{task_name}": nn.Linear(config.hidden_size, config_task["num_labels"])
            for task_name, config_task in task_configs.items()
        })
        self.task_configs = task_configs
        self.dropout = nn.Dropout(config.classifier_dropout)
        # Initialize weights and apply final processing
        self.post_init()

然而我尝试了各种不同的参数组合,对上述提到的所有数据集进行了实验,发现都无法保证所有的数据集都能得到理想的效果,推测还是因为数据集之间会存在“拖后腿”的情况,这种方法要成功最好是找一些特征类似的数据,才能得到互相增强的效果。最后,还是决定每个任务使用独立的lora单独训练。

2、在部署推理的时候,我们只需要先将一个qwen1.5-1.8B的基础模型加载到显存中,然后根据任务类型,来动态决定使用哪个lora权重合并到基础模型中,具体可参考这篇博文:

https://zhuanlan.zhihu.com/p/691710751

简单来说就是对multi-lora进行切换的操作。不过,这种方式可能会增加单次预测的推理时延(额外增加了lora卸载和装载的操作时间),可以综合当前硬件情况以及应用服务的使用频次,对高频次、时延要求比较高的任务单独部署独立的模型服务,对于低频次、时延要求低的任务采用上述multi-lora切换的模式。

小结

本文主要目的是探讨大模型应用在传统NLP任务上的有效性和增益,通过一个细分的文本理解任务——文本分类,研究了大模型应用的不同“姿势”。最终发现,将大模型结合BERT式微调的方法在标注语料比较充分的时候,相对于已有的BERT类方法还能有进一步的精度提升,同时在部署推理成本上的投入也是可控的;另外,对于小样本标签类别的学习能力也能够帮助提升对于边界case的处理。当整体的标注数据语料比较匮乏的时候,也不妨可以应用大模型+sft+prompt工程的模式,辅助技术团队进行冷启动,在积累一定的标注语料后,可以切换成上述BERT式的微调方式,以提升任务的精度。

本文转载自 NLP工作站​,作者: 邱震宇

收藏
回复
举报
回复
相关推荐