一、项目背景
- 对于目前海量的金融资讯数据,公司内部传统的基于机器学习算法的文本分类平台(1.x版本)受限于特征提取的准确性和泛化能力,难以满足实际应用的需求,需要开发一种基于深度学习的高效准确的金融资讯分类处理系统(2.0版本),以提升公司内部的信息处理能力,来满足分析师和投资经理对数据的要求。
二、项目目标
- 2.0版本分类平台相对1.x在文本分类,精确率需要提高至少5%,f1_score至少在90%;
- 具有较好的响应速率,不影响用户使用。
三、项目构建
项目搭建过程中,先对数据进行分析、然后选用fastText模型作为Baseline,,随后使用Bert大模型进行训练,之后以Bert模型为Teacher,用TextCNN模型为Student做模型蒸馏,最后将蒸馏好的TextCNN模型部署上线。
- 数据分析
- fastText模型(Baseline)
- Bert模型
- TextCNN模型(知识蒸馏)
3.1 数据分析
- 数据描述
- 现有20000条数据源,以CSV格式文件表示,每条样本由新闻标题(文本)和新闻类别对应数字(标签)构成,每个类别数据各有40,000条数据
- 新闻类别标签及对应数字表示:
- 数据预处理:
- 数据清洗:用正则去除乱码、去除英文字母等
- 对于数据进行训练集、验证集、测试集划分,比例为8:1:1
- 对样本进行分词以及标签按照对应格式转化(不同模型处理方式不一)
- 数据分析
- 样本分布:均衡分别,各标签类别为40,000条数据
- 词长度分布:统计文本的长度的均值和标准差,样本长度基本在30左右
3.2 基线模型搭建
在本次版本迭代中,选择fastText模型作为Baseline,以快速看出深度学习模型的分类效果,同时供后面用Bert大模型做分类提供指标参考。
3.2.1 导入工具类
3.2.2 数据准备
使用fastText做文本分类任务,数据集中文本文件需要满足两种要求:
- 文本文件中的每一行对应一个文档;
- 文档的类别标签以 __label__name 为前缀放在文档的最前面;
对文本进行分词,既可以用jieba按照词性进行分词,也可用list内建函数,按照字符进行分词,实际按照模型效果好坏进行选择。
在源数据中,样本的标签为标签名对应的数值,这里读取class.text文件,获取标签值到标签名的索引.
3.2.3 模型搭建、训练及预测
结果:在10000条测试集上,训练得出的fastText模型的f1_score为88%。
3.2.4 模型优化
通过超参数搜索的方式对模型进行参数进行调优,从而尝试提升模型指标:
通过调优,模型提升0.5点,f1_score达到88.5%,调优效果较好。但是离项目指标<90%的指标还有待提升。
3.3 Bert模型训练
3.3.1 Config配置器
需要通过Config类保存数据处理、模型训练等各种参数,进行集中管理
- 定义了模型名称、数据集路径、训练集、验证集、测试集文件路径、类别名单等信息。
- 包含模型训练结果和量化模型存储结果的路径。
- 配置了训练设备(GPU或CPU)、类别数、epoch数、mini-batch大小、句子长度等。
- BERT预训练模型的路径、分词器、BERT模型配置、隐藏层大小等。
3.3.2 构建数据集函数
在Bert模型中,我们需要将样本基于字符进行分词,然后构建数据集工具build_dataset函数以及迭代器build_iterator函数
- build_dataset() 自定义数据集
- 根据配置信息构建用于模型训练的数据集;
- 通过加载文本文件、分词、添加特殊标记(bert模型要求,包括[PAD]、[CLS]、 [UNK]),生成包含词汇索引、标签、序列长度和填充掩码的数据集;
- 最终,函数返回训练集、验证集和测试集,以供模型使用。
- build_iterator
DatasetIterater
类:__init__
:接收批次数据、批次大小、设备类型和模型名称,设置相关属性。_to_tensor
函数:将批次数据转换为 PyTorch 的 Tensor 格式。__next__
函数:获取下一个批次的样本,处理不规则批次和索引溢出。__iter__
函数:返回迭代器对象本身。__len__
函数:获取迭代器的长度。-
build_iterator
函数: - 根据配置信息和给定的数据集构建数据集迭代器对象。
- 返回数据集迭代器
3.3.3 Bert模型搭建
构建Bert模型类,主要实现以下内容:
BertModel
类继承自nn.Module
,实现了一个基于BERT的文本分类模型。
- 在初始化方法中,加载预训练的BERT模型和配置,并定义了一个全连接层用于文本分类。
- 在前向传播方法中,通过BERT模型获取句子的表示,然后通过全连接层进行分类
3.3.4 Bert模型训练、评估和测试
训练函数
train
实现了模型的训练过程,使用了交叉熵损失函数和Adam优化器。具体包括以下内容:- 优化器设置: 使用AdamW优化器,并设置了参数的权重衰减。
- 训练循环: 遍历每个epoch和每个batch,进行前向传播、计算损失、反向传播、参数更新。
- 评估: 每100个batch输出在训练集和验证集上的效果,包括训练损失、训练准确率、验证损失、验证准确率等。
- 保存模型: 若验证集上的损失更低,保存当前模型的参数。
- 时间计算: 计算训练的总时间。
模型验证函数
evaluate
,用于在验证集或测试集上评估模型的性能。主要功能包括:- 损失计算: 通过循环遍历数据集,计算模型在每个样本上的损失,并累加得到总损失。
- 预测结果记录: 记录模型对每个样本的预测结果和真实标签。
- 准确率计算: 根据记录的预测结果和真实标签计算模型的准确率。
- 测试集评估: 如果是测试集评估,额外计算分类报告和混淆矩阵。
测试函数
test
用于在测试集上进行最终的模型测试。它调用了之前定义的 evaluate
函数,然后输出测试集上的损失、准确率、分类报告和混淆矩阵等信息。3.3.4 构建模型训练主入口
结果:BERT模型在测试集上的表现是Test f1_score: 93% , 对比Baseline的fasttext模型最好的表现88.5%, 有了4.5%的提升, 效果显著性提升了,但是训练出的模型大小高达400M,模型较庞大,不符合项目上线要求,需要做蒸馏。
3.4 TextCNN
在工业级的应用中, 除了要求模型要有好的预测效果之外, 往往还希望它的"消耗"足够小. 也就是说一般希望部署在线上的应用模型消耗较小的资源. 这些资源包括存储空间, 包括算力。在该项目当中,我们以已经训练好的Bert模型为Teacher模型,以TextCNN模型为Student进行模型蒸馏。
3.4.1 配置Student的Config类
3.4.2 TextCNN模型构建(Student)
TextCNN(卷积神经网络用于文本分类)模型包含词嵌入层、多个卷积核大小的卷积层、池化层、随机失活层和全连接层。其中,卷积层通过不同大小的卷积核捕捉不同范围的文本信息,随机失活层用于防止过拟合,全连接层用于输出最终的分类结果。
3.4.3 模型损失构建
以下是模型蒸馏的基本训练步骤:
- 准备教师模型(bert大模型): 使用一个较大的模型进行训练, 这个模型在任务上表现很好。
- 使用教师模型生成软目标: 对训练数据集进行推理,得到教师模型的输出概率分布(软目标)。这些概率分布包含了模型对每个类别的置信度信息。
- 准备学生模型(textcnn小模型): 初始化一个较小的模型,这是我们要训练的目标模型。
- 使用软目标和硬标签进行训练: 使用原始的硬标签(实际标签)和教师模型生成的软目标来训练学生模型。损失函数由两部分组成:
- 硬标签损失(通常为交叉熵损失): 学生模型的输出与实际标签之间的差距。(交叉熵损失)
- 软目标损失: 学生模型的输出与教师模型生成的软目标之间的差距。这通常使用 KL 散度(Kullback-Leibler Divergence)来度量。
- 调整温度参数: KL 散度的计算涉及一个温度参数,该参数可以调整软目标的分布。温度较高会使分布更加平滑。在训练过程中,可以逐渐降低温度以提高蒸馏效果。
构建Teacher模型输出(软目标)
- 将教师模型设置为评估(推断)模式,通过
teacher_model.eval()
实现。在评估模式下,模型不会计算梯度,这有助于提高推断速度并减少内存消耗。
- 创建一个空列表
teacher_outputs
,用于存储教师模型对训练集每个批次的输出。
- 遍历训练集迭代器
train_iter
,对每个批次的数据调用教师模型,获取模型的输出。
- 将每个批次的输出添加到
teacher_outputs
列表中。
- 最后,返回包含教师模型对训练集所有批次输出的结果。
构建损失函数
通常采用的交叉熵损失函数, 有一点需要注意, F.cross_entropy()对输入有限制, 要求label必须是one-hot格式的. 但Teacher网络的输出soft targets是概率分布的形式, 不匹配,因此采用KL散度作为soft targets的loss, 注意: Pytorch中的KL散度函数可以接收概率分布形式的label.包含的步骤是:
loss_fn
是用于一般的交叉熵损失函数,适用于训练 BERT 模型。
criterion
是定义 KL 散度损失的 PyTorch 损失类。
loss_fn_kd
是蒸馏损失函数,用于蒸馏训练。它接受三个参数:outputs
(学生模型的输出),labels
(真实标签),teacher_outputs
(教师模型的输出)。
- 设置两个超参数:
alpha
控制软损失和硬损失的权重,T
是温度参数,影响软化的程度。
- 计算学生模型(Student)的输出分布值和教师模型(Teacher)的输出分布值。对学生模型的输出进行 log_softmax 处理,对教师模型的输出进行 softmax 处理。
- 计算软损失,即学生模型和教师模型的输出分布之间的 KL 散度损失。
- 计算硬损失,即学生模型和真实标签的交叉熵损失。
- 计算总损失,通过加权软损失和硬损失得到。
3.4.4 知识蒸馏函数构建
使用知识蒸馏(Knowledge Distillation)的方式训练深度学习模型的训练函数完成的任务如下所示:
- 初始化优化器和其他训练参数,将CNN模型设置为训练模式,BERT模型设置为评估模式。
- 获取BERT模型的输出,作为教师模型的预测结果。
- 遍历每个epoch,对CNN模型进行训练。计算蒸馏损失(软损失)和交叉熵损失(硬损失)的组合,并进行反向传播和优化。
- 在训练过程中输出训练信息,包括训练损失、准确率以及在验证集上的表现。保存在验证集上表现最好的CNN模型。
- 在训练结束后,使用测试集对最终的CNN模型进行测试。
结论:
- 模型大小只有24M,相比之下,模型大小明显减小
- 模型准确率为91.55%,指标下降较小,在可接受范围内
4. 项目总结(问题罗列)
- bert模型的整体架构
- bert模型的两大预训练任务
- 说一下transformer模型的基本架构
- 什么是模型量化
- 模型量化的实现方式
- 模型蒸馏的损失函数
- 介绍下LSTM模型
- RNN和LSTM对比的优缺点
- 简述下自我注意力机制原理
- 在transformer中自注意力机制的计算方式
- 什么是Word2Vec
- bert和transformer模型的位置编码器有什么区别
- python语言面向对象的特性
- 什么是TextCNN模型
- 怎么实现两个句子文本相似度的计算
- 谈谈你对attention的理解
- 什么是GBDT算法
- 交叉熵损失的公式
- 什么是逻辑回归算法
- 二分类损失函数的表达式是什么
- tranformer的掩码分为哪几种?
- transfomer自注意力机制的时候处以根号下dk
- fasttext的作用是什么
- 缓解模型过拟合的方法有哪些
- L1和L2正则化有什么区别?
- 多文本多分类的任务的损失函数是什么?
- 解释下什么是tf-idf