大模型在传统 NLP 文本分类任务中的应用实践
本文探讨了大模型在传统 NLP 文本分类任务中的多种应用方式,对比了纯 Prompt 工程、指令微调(SFT)以及 BERT 式微调的效果。实验基于金融新闻事件分类数据集,结果显示纯 Prompt 工程效果不如传统 BERT 模型;结合 LoRA 的 BERT 式微调在 Qwen 1.8B 模型上取得了最佳精度,尤其在小样本类别表现优异。文章提供了具体的训练流程、参数配置及多 LoRA 部署策略,为大模型落地提供实践参考。

本文探讨了大模型在传统 NLP 文本分类任务中的多种应用方式,对比了纯 Prompt 工程、指令微调(SFT)以及 BERT 式微调的效果。实验基于金融新闻事件分类数据集,结果显示纯 Prompt 工程效果不如传统 BERT 模型;结合 LoRA 的 BERT 式微调在 Qwen 1.8B 模型上取得了最佳精度,尤其在小样本类别表现优异。文章提供了具体的训练流程、参数配置及多 LoRA 部署策略,为大模型落地提供实践参考。

以 ChatGPT 为起始节点的大模型技术经过了两年左右的发展,大致沉淀了一些较为确定的研究领域。首先是基座大模型的研究,主要是国内外大厂集中大量财力、人力、算力进行大模型军备竞赛,企图将大模型的基础能力(包括推理能力)上限逐步提升到更高的层次。当然也有一些研究机构致力于改进 Transformer 的架构或者提出其他更先进的基础模型结构,在性能或者效率上做文章,例如 MoE、Mamba 等;多模态模型,让大模型同时能够理解并生成图像、音频、视频、文字等多种模态的信息,例如 Sora。
其次是大模型的微调对齐研究,主要是基座大模型通过指令微调、强化学习等技术将其变成一个应用友好、用户友好的能力模型,也可以将模型长文本、长上下文能力的提升也包含在该方向内;另外,还有大模型的高效部署和推理计算,在降低大模型服务成本的同时,提升大模型服务的实时性,提升用户体验;最后,则是大模型在各种细分场景领域的应用落地,能够将大模型封装成一个成熟的应用产品,真正的将大模型用起来,当然也可以将 Agent 相关的技术研究归纳在这个方向上,因为 Agent 的目标就是将大模型的能力充分利用起来,帮助人类更好地使用大模型。
本人目前主要精力集中在大模型的应用落地,对大模型在传统 NLP 应用任务上的效果非常感兴趣。借着这个机会,我对大模型在文本分类任务上的应用方式和对应效果进行了研究,有了一些初步的结论。本文希望通过描述上述研究过程与结果,总结出大模型在文本分类任务上的最佳实践,并推广到更多类似的应用上,为业界做大模型应用时提供一些落地的参考。
在谈具体的研究内容前,需要先明确一下研究的问题类型。目前对于可能会应用到大模型的传统 NLP 应用,我自己将其分为两种不同的情况:
本文主要讨论的是第二种场景,这也是很多有一定数字化、智能化基础的公司比较关注的类型。他们在大模型提出之前,已经通过一些规则、统计机器学习、深度神经网络等算法模型技术构建了一些分类服务,有些行业头部团队在此基础上通过一些技巧(数据增强,对抗训练等)进行了优化,将算法指标提升到了某个瓶颈线。然而,业务用户对于算法的精度提升要求是持续性的,因此在大模型出现之前的一段时间,算法人员疲于应付业务用户对于场景效果的高要求。
截止 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 以及英文的数据集,为了验证国内开源的大模型是否在中文数据集上是否也有类似的结论,下面我将根据相关的目标应用场景以一个具体的数据集的实验来说明。
目标应用场景:新闻事件分类任务。任务特点:
由于一些原因,不能拿到相关真实场景数据,因此搜寻了网上的公开数据集,最终找到了一个比较贴近上述任务特点的数据集:CKKS 2022 任务八数据集。
数据集简介:数据主要来自金融领域的公开新闻、报道,数量在 5 万 + 左右。原始数据集的任务是'给定 100+ 事件类型及其事件主体公司,训练数据中对其中 16 个事件类型只保留 10 条左右的训练样本,测试集中包含这 16 个类型的大量待抽取样本。'
本次的验证为了简化问题,不会采用上述的任务形式,而是采用最基本的全类别分类数据集的处理方式,从而验证模型在这种类型的数据集上的整体效果,以及在一些小样本类别上的效果。
由于目前只有训练集有标注标签,因此只能针对标注数据集进行分析。具体做法是根据标注数据分布划分了训练集,测试集(5000+),其中测试集只用于评测模型的最终结果。
备注:该数据集存在一定的标注质量问题,前期通过一些人力检测与校正,提升了部分的标注质量。
数据示例如下:
{
"textId": "2333e4ef53762e498cc79c7613d6ac6f",
"text": "科锐国际:2018 年年度权益分派实施公告",
"eventTags": [{"eventType": "公司权益分派", "eventCompany": "科锐国际"}]
}
事件标签数量为 174 个,均为金融相关的事件标签。
对数据集进行分析后,发现其具备典型的长尾分布特征,与实际的业务数据分布比较类似。由于类别比较多,以每个类别为粒度进行画图不够直观,因此将所有标签类别按照从大到小顺序排序后,以 10 为一组进行分组,按照组的粒度画出的柱状图如下:
以下是出于长尾位置的部分事件标签样例:
为了验证大模型的相关方案与传统的 NLP 方案相比是否有提升,因此选定了 BERT 簇的分类方案作为 baseline 来进行对比。
BERT 也是一个以 Transformer 为模型架构的预训练语言模型。
具体来说,本次实验的 BERT 模型选择了哈工大的 macbert-base 和 macbert-large 两种体量的模型。
具体训练方式:
最终,base 和 large 模型的指标如下:
将 LLM 大模型直接应用于文本多标签分类任务,实际上就是编写提示词指令,让大模型去生成最终的事件标签结果。整体还是一个文本生成的过程。
提示词模版样例如下:
f"作为一个多标签新闻分类专家,你的任务是识别出新闻中的所有相关事件标签。 事件标签列表:{event_tags}。新闻内容:{text}。该新闻对应的所有事件标签是什么?"
其中,event_tags 需要把体系中的事件标签填入。这里涉及到两个问题:
基于当前最新的技术发展,有的开源大模型已经能够处理超过 128K 的上下文,对于 170+ 的标签文本是能够覆盖的。当然,能处理和处理好是两种概念,对于大模型来说,肯定是标签范围越小越容易解决问题,因此也可以通过先将事件标签进行分级分组,然后逐级进行大模型的分析,两种方式均可。
为了能够充分利用已有的标注数据集和大模型的能力,在上述 prompt 中,还可以引入示例样本(一般论文里面都叫 demonstrations),从而激发大模型的 In-context learning 能力。为此,对整体训练数据集设计了如下的工作流程:
该工作流程的主要核心思想是将示例样本的选择问题转化成 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 还未出,但根据其他任务的分析,可以推测不会相差太多)
具体指标如下:
根据指标结果,可以看到纯 Prompt 工程的方式,即使是使用百亿级别参数量的模型,还是离传统 BERT 方式的效果差不少。因为 LLM 大模型的训练方式与 BERT 不同,以文本生成为目标,是单向构建上下文(从左到右);而 BERT 训练是以完形填空式任务为目标。相比于 LLM,能够在双向(向左向右)构建上下文理解,本身就适配自然语言理解任务(文本分类,信息抽取等均为理解任务)。
通过分析大模型的错误 case,可以发现很多样本都是因为指令遵循能力不够(比如格式未按要求,生成了无关的分析解释内容等),导致格式处理后的结果是错的。因此,推测如果对大模型进行训练样本的 SFT,应该还能够在指标上有不少的提升。
既然要指令微调了,那么基于硬件成本限制,就只能选择一些性价比高的开源模型来做验证了。因此,最终选择了 qwen-7b-chat 和 qwen-14b-chat 来做实验。针对当前的数据集,结合 Prompt 工程和指令微调技术,设计了如下的大模型文本分类流程:
与 Prompt 工程的方案相比,本方案加入了指令微调的步骤。具体来说就是对训练集进行数据筛选和处理后,筛选出高质量的训练数据集,然后通过 LoRA 的方式进行低成本的指令微调模型,最后在微调后的模型上使用 Prompt 工程来完成样本的分类。整个流程中,有几个重要节点的详细说明如下:
这些方法除去一些不太方便实现的(例如要训练一个 reward 模型,标注成本太高),基本都实现了一下,在当前的数据集上效果都不是很理想,猜想应该是上面的方法对于目标是复杂生成的任务会更有效。
实际上,探究数据集精选的本质,不外乎以下两点:(1)样本多样性高;(2)对于任务的重要性或者增益程度尽量高。其实,之前做文本摘要的时候,对摘要句子的选取也是遵循这两个原则,因此自然而然就想到可以借用文本摘要的思想来选择:
(1)先将所有样本根据标签类别分成不同的簇(当然,也可以对样本进行聚类分析,得到的簇可能更偏文本本身的语义相似性聚合) (2)对每个簇中的样本,采用 MMR 算法进行样本的排序。MMR 综合考虑了样本的多样性和相关性,因此我们可以根据分数从高到低选择一定数量的样本放到训练集中。 (3)对于包含多个标签的样本,以及样本数量本身就很少的标签均采用白名单模式,即全部加入样本集合中。这也是为了让大模型对多标签、小样本的情况能够尽可能多的学习。
通过上述方式,选择了 4000+ 的样本用于训练。(每个标签数据都会覆盖到)
我们将上述筛选后的训练样本集与全量训练样本集进行了大模型微调的对比实验,可以发现一些有趣但并不意外的结果。
根据上述的对比实验,可以看到当标注数据量比较充裕的时候,LLM 即使经过微调、提示词精心设计等步骤后,整体的效果还是不如 BERT 模型的微调效果。除了上一小节提到的'LLM 大模型的训练方式与 BERT 不同'的原因外,可能还有以下这个因素:
BERT 在数据量充足的条件下,能够充分'过拟合'下游任务信息,从而在任务上达到不错的效果。但是微调后的模型完全无法去做其他任务;而 LLM 大模型的目标本就是通用人工智能,不会为了某个具体任务而丧失通用性,因此经过一定的指令微调后,并不会充分'过拟合'某个任务。
当然,在标注数据量不是非常充分的情况下,使用大模型做指令微调配合 Prompt 工程,确实能在小样本场景下有不错的效果。实际的应用场景中,有些小样本的事件标签虽然出现次数不多,但业务属性却非常重要,提升这些数据的效果,可能对整体的评测效果没有明显的影响,但对业务使用来说是能够提升体验的。
大模型 + 指令微调的组合终究与追求精度提升的文本理解类任务不太契合。在足量的标注数据场景下,精度上难以匹敌传统的 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 的时候会报错。
整个训练流程其实与传统文本任务相似,但是有一些训练中的细节内容,我想在下面着重分享一下。
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 # 文本分类使用该类型
)
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 式微调与前述的方法效果对比。
可以看到,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 指标对比。
注意!!!以下所列指标为本人自己训练后的结果,比公开出来的数据指标会低一点,因为我不太喜欢干调参的活,就随机选了超参数,不过 BERT 与 Qwen 两者训练的通用参数是保持一致,目标是验证 Qwen 是否能够对 BERT 有效果的提升,所以不建议与公开榜单指标做对比。
可以看到,qwen1.5-1.8B+BERT 式微调+LoRA 在其他分类任务上的精度相较于 BERT-large 来说还是能有不错的提升。
答案是肯定的。实际上,我还尝试了 qwen1.5-4B,qwen1.5-7B,chatglm3-6B,minicpm 等模型结果,下面列出部分数据集的效果。
随着大模型参数量的增加,BERT 式微调的效果似乎并没有随着参数显著得提升,可以看到的是即使是 BERT 式微调方法,也无法利用大模型更多的参数知识了。结合应用实际成本的考量,选择 qwen1.5-1.8B 似乎是当前性价比最高的。
当然,我对上述结果也不是完全没有疑问的。最大的变数在于这些国内大模型是否在预训练的时候将这些开源的数据集包含进去了。如果在训练的时候就见过这些数据,那么对上述结果的真实性就需要进一步验证了。
采用 BERT 式的微调方式,由于是让模型尽量过拟合某个下游任务,微调后它就无法适配其他类型的任务了,因此在实际应用时,对于不同的任务会微调部署多个独立的模型。对于大模型来说,如果每个任务都单独部署一个模型从应用成本上来看显然是不可控的。但通过上述的 LoRA 微调,可以有效得降低应用部署的显存成本。
其实我尝试过 MTDNN 的多任务同时训练的方式,即增加 LoRA 的参数规模,然后同时训练不同的分类任务,目的是用一个模型 cover 多个任务。具体做法是在数据预处理 batch 的时候,根据不同任务的数据量比例通过采样的方式采样某个任务的 1batch 数据参与当前 step 的训练。然后通过在模型定义时,指定对应任务与任务 dense 层的映射关系来保证每个任务都能使用正确的。
class MTDNNForSequenceClassification(Qwen2PreTrainedModel):
def __init__(self, config,task_configs):
super().__init__(config)
self.model = Qwen2Model(config)
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)
self.post_init()
然而我尝试了各种不同的参数组合,对上述提到的所有数据集进行了实验,发现都无法保证所有的数据集都能得到理想的效果,推测还是因为数据集之间会存在'拖后腿'的情况,这种方法要成功最好是找一些特征类似的数据,才能得到互相增强的效果。最后,还是决定每个任务使用独立的 LoRA 单独训练。
简单来说就是对 multi-lora 进行切换的操作。不过,这种方式可能会增加单次预测的推理时延(额外增加了 LoRA 卸载和装载的操作时间),可以综合当前硬件情况以及应用服务的使用频次,对高频次、时延要求比较高的任务单独部署独立的模型服务,对于低频次、时延要求低的任务采用上述 multi-lora 切换的模式。
本文主要目的是探讨大模型应用在传统 NLP 任务上的有效性和增益,通过一个细分的文本理解任务——文本分类,研究了大模型应用的不同'姿势'。最终发现,将大模型结合 BERT 式微调的方法在标注语料比较充分的时候,相对于已有的 BERT 类方法还能有进一步的精度提升,同时在部署推理成本上的投入也是可控的;另外,对于小样本标签类别的学习能力也能够帮助提升对于边界 case 的处理。当整体的标注数据语料比较匮乏的时候,也不妨可以应用大模型+SFT+Prompt 工程的模式,辅助技术团队进行冷启动,在积累一定的标注语料后,可以切换成上述 BERT 式的微调方式,以提升任务的精度。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online