面对文本分类任务(557 类)的挑战,尝试了三种不同的方案,最终 Lora 微调 Qwen3 模型脱颖而出,实现了约 65% 的三级分类准确率(有提升空间)。

01.任务描述

文本分类任务,利用训练数据,构建分类模型,实现文本的多级分类。

类别标签分为三级:“类别 1_类别 2_类别 3”,且标签呈树状结构。一级类别 11 类,二级类别 104 类,三级类别 557 类。

数据格式为:“[{"text":text,"label":类别1_类别2_类别3},...]”

02.方案

最近随着各种生成式大模型不断产生,恰逢公司需要迭代之前使用 Bert+prompt 实现的文本分类任务(准确率低低低~)。

针对该任务尝试了各种分类框架,分为三类:

  • 方案一:针对历史标注数据构建向量库,向量匹配。

  • 方案二:传统 NLP 框架,Embedding+attention 模型。

  • 方案三:Lora 微调 Qwen3 模型。

先说结果,方案一和方案二准确率相对偏低,三级分类准确率在 40% 左右,与 Bert+prompt 相近,方案三准确率在 65% 左右。

03.实现

方案一:构建文本向量库检索匹配实现文本分类

使用腾讯的 TencentBAC/Conan-embedding-v1 +faiss 构建文本向量库。

def build_case(self): """构建nrfl faiss 数据库(伪代码块)""" if os.path.exists(self.index_path):        shutil.rmtree(self.index_path)    path = Path(self.index_path)    path.mkdir(parents=True, exist_ok=True) if id.endswith("0000"):    fenlei1_embs.append(self.emb.encode(XF_CATEGORY_FULLTEXTXF[nrflmc]))    fenlei1_ids.append(int(id)) elif id.endswith("00") and not id.endswith("0000"):    fenlei2_embs[id[:2]].append(self.emb.encode(nrflmc))    fenlei2_ids[id[:2]].append(id) else:    fenlei3_embs[id[:4]].append(self.emb.encode(nrflmc))    fenlei3_ids[id[:4]].append(id) self.save_faiss_vec('yijifenlei', fenlei1_embs, fenlei1_ids) for cls1 in nrfl1:     self.save_faiss_vec(cls1[:2], fenlei2_embs[cls1[:2]], fenlei2_ids[cls1[:2]]) for cls2 in nrfl2:     self.save_faiss_vec(cls2[:4], fenlei3_embs[cls2[:4]], fenlei3_ids[cls2[:4]]) return "success"

这里构建了分层的向量库,实现层级检索,因为不需要训练模型,这是一种比较快的通过构建向量库检索实现文本分类的方案。

由于是一种无监督的实现方案,所以准确率有限,如果类别比较少,类别间特征明显,那么这种方案也是一种不错的尝试。

方案二:embedding+Attention 实现文本分类

构建了一个三级层次化分类模型,用于对文本进行分类。

模型基于"TencentBAC/Conan-embedding-v1"预训练模型,采集文本特征,引入注意力机制提取文本表示中的重要信息,最后通过三个线性层实现层级预测。​​​​​​​

class HierarchicalClassifier(nn.Module):    def __init__(self, pretrained_model, hidden_dim, num_level1_classes, num_level2_classes, num_level3_classes,                 dropout=0.1):        super(HierarchicalClassifier, self).__init__()        # 预训练模型        self.pretrained_model = pretrained_model        self.embedding_dim = pretrained_model.config.hidden_size        # 投影层,将预训练模型的输出映射到指定维度        self.projection = nn.Linear(self.embedding_dim, hidden_dim)        # 注意力层        self.attention = AttentionLayer(hidden_dim)        # 一级分类器        self.level1_classifier = nn.Sequential(            nn.Linear(hidden_dim, hidden_dim),            nn.LayerNorm(hidden_dim),            nn.ReLU(),            nn.Dropout(dropout),            nn.Linear(hidden_dim, num_level1_classes)        )        # 二级分类器 (使用一级分类结果作为条件)        self.level2_classifier = nn.Sequential(            nn.Linear(hidden_dim + num_level1_classes, hidden_dim),            nn.LayerNorm(hidden_dim),            nn.ReLU(),            nn.Dropout(dropout),            nn.Linear(hidden_dim, num_level2_classes)        )        # 三级分类器 (使用一级和二级分类结果作为条件)        self.level3_classifier = nn.Sequential(            nn.Linear(hidden_dim + num_level1_classes + num_level2_classes, hidden_dim),            nn.LayerNorm(hidden_dim),            nn.ReLU(),            nn.Dropout(dropout),            nn.Linear(hidden_dim, num_level3_classes)        )

经过训练,推理准确率一直较低,考虑是因为推理过程中后续分类依赖前一分类的推理结果,会存在错误累积。

这份完整版的大模型 AI 学习和面试资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】

因此,拆分分类器,构建了一个底层向量表征,基于此表征对每层进行独立训练预测,效果变差,考虑表征层太过简单,模型一直欠拟合。​​​​​​​

# 共享表征层self.shared_encoder = nn.Sequential(    nn.Linear(hidden_dim, hidden_dim),    nn.LayerNorm(hidden_dim),    nn.ReLU(),    nn.Dropout(dropout))# 加载层级关系with open('label_hierarchy.json', 'r', encoding='utf-8') as f:    self.hierarchy = json.load(f)with open('label_encoders.json', 'r', encoding='utf-8') as f:    self.label_encoders = json.load(f)# 一级分类器 - 独立分类器self.level1_classifier = nn.Sequential(    nn.Linear(hidden_dim, hidden_dim),    nn.LayerNorm(hidden_dim),    nn.ReLU(),    nn.Dropout(dropout),    nn.Linear(hidden_dim, num_level1_classes))# 移除层次依赖的二级和三级分类器# self.level2_fc = nn.Sequential(...)# self.level3_fc = nn.Sequential(...)# 保留独立的二级分类器self.level2_classifier = nn.Sequential(    nn.Linear(hidden_dim, hidden_dim),    nn.LayerNorm(hidden_dim),    nn.ReLU(),    nn.Dropout(dropout),    nn.Linear(hidden_dim, num_level2_classes))# 保留独立的三级分类器self.level3_classifier = nn.Sequential(    nn.Linear(hidden_dim, hidden_dim),    nn.LayerNorm(hidden_dim),    nn.ReLU(),    nn.Dropout(dropout),    nn.Linear(hidden_dim, num_level3_classes))

方案三:Lora 微调 Qwen3 实现文本分类

考虑到后期上线部署资源问题,使用的 Qwen3-1.7b 模型,参数量适中,占用显存资源较少。

训练集 100w 余条数据,使用 accelerate 混合精度并行训练加速,在 3 张 NVIDIA A100 显卡上跑了 50 个小时。

直接上参数:​​​​​​​

MAX_LENGTH=512  # 减小最大长度以加快训练BATCH_SIZE=32    # 根据显存调整批次大小LEARNING_RATE=5e-5NUM_EPOCHS=10LORA_R=16  # 减小LoRA的秩以减少参数量LORA_ALPHA=32  # 调整alpha与r的比例保持2:1LORA_DROPOUT=0.05NUM_LAYERS_TO_TUNE=6  # 只微调最后6层TARGET_MODULES="q_proj,v_proj,o_proj"  # 指定要微调的模块。TOTAL_LAYERS=28  MIXED_PRECISION="fp16"  # 使用fp16混合精度训练,这里推荐使用 bf16 训练GRADIENT_ACCUMULATION_STEPS=1  # 梯度累积步数,当你在学习率中设置了warmup_ratio,一定计算好预热步数。USE_TENSORBOARD=true  # 使用TensorBoard记录实验TENSORBOARD_DIR="./runs/qwen3_experiment"  # TensorBoard日志目录RUN_NAME="qwen3_lora_last10layers_fp16"  # 实验名称

简单贴一下模型部分代码:​​​​​​​

def create_model(model_name_or_path, num_labels, lora_config=None):    """    创建模型,可选择是否使用LoRA    Args:        model_name_or_path: 预训练模型的名称或路径        num_labels: 分类标签数量        lora_config: LoRA配置,如果为None则不使用LoRA    Returns:        model: 创建的模型    """    # 加载模型配置    config = AutoConfig.from_pretrained(        model_name_or_path,        num_labels=num_labels,        trust_remote_code=True    )        # 加载预训练模型    model = AutoModelForSequenceClassification.from_pretrained(        model_name_or_path,        config=config,        trust_remote_code=True    )    # 如果提供了LoRA配置,则应用LoRA    if lora_config is not None:        model = get_peft_model(model, lora_config)        model.print_trainable_parameters()    return modeldef create_lora_config(    r=8,    lora_alpha=16,    lora_dropout=0.05,    model_name_or_path=None,    target_modules=None,    num_layers_to_tune=None,    layer_names=None,    total_layers=None):    """    创建LoRA配置    Args:        r: LoRA的秩        lora_alpha: LoRA的缩放参数        lora_dropout: LoRA的dropout率        model_name_or_path: 模型名称或路径,用于确定目标模块        target_modules: 要应用LoRA的模块名称列表,如果为None则根据模型自动选择        num_layers_to_tune: 要微调的层数(从最后一层开始计数),如果为None则微调所有层        layer_names: 要微调的层的名称格式,如果为None则使用默认格式        total_layers: 模型的总层数,如果为None则根据模型自动检测    Returns:        lora_config: LoRA配置对象    """    # 如果没有指定target_modules,则根据模型类型自动选择    if target_modules is None:        if model_name_or_path and "qwen3" in model_name_or_path.lower():            # 平衡配置:微调查询、值和输出投影            target_modules = ["q_proj", "v_proj", "o_proj"]        else:            # 默认配置            target_modules = ["q_proj", "v_proj", "o_proj"]    # 创建LoRA配置参数    config_args = {        "r": r,        "lora_alpha": lora_alpha,        "lora_dropout": lora_dropout,        "task_type": TaskType.SEQ_CLS,        "bias": "none",        "modules_to_save": ["classifier"]    }    # 如果指定了要微调的层数,则只微调最后几层    if num_layers_to_tune is not None and model_name_or_path and "qwen3" in model_name_or_path.lower():        # 根据模型名称确定总层数        if total_layers is None:            if "1.7b" in model_name_or_path.lower() or "1.7B" in model_name_or_path:                total_layers = 28  # Qwen3-1.7B 有28层            elif "4b" in model_name_or_path.lower() or "4B" in model_name_or_path:                total_layers = 36  # Qwen3-4B 有36层            elif "7b" in model_name_or_path.lower() or "7B" in model_name_or_path:                total_layers = 40  # Qwen3-7B 有40层            elif "14b" in model_name_or_path.lower() or "14B" in model_name_or_path:                total_layers = 48  # Qwen3-14B 有48层            elif "72b" in model_name_or_path.lower() or "72B" in model_name_or_path:                total_layers = 80  # Qwen3-72B 有80层            else:                total_layers = 36  # 默认使用36层            print(f"自动检测到模型 {model_name_or_path} 的层数为: {total_layers}")        # 计算要微调的层的索引        start_layer = total_layers - num_layers_to_tune        # 创建目标模块列表,只包含指定的层        if layer_names is None:            # 默认的层名称格式            layer_names = "layers.{layer_num}.self_attn.{target_module}"        target_modules_with_layers = []        for layer_num in range(start_layer, total_layers):            for module in target_modules:                target_modules_with_layers.append(                    layer_names.format(layer_num=layer_num, target_module=module)                )        # 使用指定的目标模块        config_args["target_modules"] = target_modules_with_layers    else:        # 使用普通的目标模块配置        config_args["target_modules"] = target_modules    # 创建LoRA配置    config = LoraConfig(**config_args)    return config 

结果:

学习率和损失

验证集参数

测试集参数

最终测试集准确率:

  • 一级分类准确率:0.8210 

  • 二级分类准确率:0.7190 

  • 三级分类准确率:0.6483

TODO:大家可能看到训练时 loss 下降缓慢,考虑有如下原因接下来进行验证(后续完善):

  • Qwen3 使用的损失函数是 CrossEntropyLoss ,对于样本不均衡训练集中的难负样例并不友好,接下来尝试使用 FocalLoss 动态调整损失权重。

  • 样本量大,学习率设置过低,增大学习率。

04.如何学习AI大模型?

我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。
这份完整版的大模型 AI 学习和面试资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】
在这里插入图片描述

在这里插入图片描述

第一阶段: 从大模型系统设计入手,讲解大模型的主要方法;

第二阶段: 在通过大模型提示词工程从Prompts角度入手更好发挥模型的作用;

第三阶段: 大模型平台应用开发借助阿里云PAI平台构建电商领域虚拟试衣系统;

第四阶段: 大模型知识库应用开发以LangChain框架为例,构建物流行业咨询智能问答系统;

第五阶段: 大模型微调开发借助以大健康、新零售、新媒体领域构建适合当前领域大模型;

第六阶段: 以SD多模态大模型为主,搭建了文生图小程序案例;

第七阶段: 以大模型平台应用与开发为主,通过星火大模型,文心大模型等成熟大模型构建大模型行业应用。

在这里插入图片描述

👉学会后的收获:👈

• 基于大模型全栈工程实现(前端、后端、产品经理、设计、数据分析等),通过这门课可获得不同能力;

• 能够利用大模型解决相关实际项目需求: 大数据时代,越来越多的企业和机构需要处理海量数据,利用大模型技术可以更好地处理这些数据,提高数据分析和决策的准确性。因此,掌握大模型应用开发技能,可以让程序员更好地应对实际项目需求;

• 基于大模型和企业数据AI应用开发,实现大模型理论、掌握GPU算力、硬件、LangChain开发框架和项目实战技能, 学会Fine-tuning垂直训练大模型(数据准备、数据蒸馏、大模型部署)一站式掌握;

• 能够完成时下热门大模型垂直领域模型训练能力,提高程序员的编码能力: 大模型应用开发需要掌握机器学习算法、深度学习框架等技术,这些技术的掌握可以提高程序员的编码能力和分析能力,让程序员更加熟练地编写高质量的代码。

在这里插入图片描述

1.AI大模型学习路线图
2.100套AI大模型商业化落地方案
3.100集大模型视频教程
4.200本大模型PDF书籍
5.LLM面试题合集
6.AI产品经理资源合集

👉获取方式:
😝有需要的小伙伴,可以保存图片到wx扫描二v码免费领取【保证100%免费】🆓

在这里插入图片描述

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐