4种实现方式的区别:
1- 随机森林
机器学习的方式。代码开发、模型训练等非常简单;因为模型比较简单,所以预测准确率一般般
工作中拿到需求以后,短时间内想要快速看到效果,用该方式
2- Fasttext
它实际就是个简单的深度学习网络模型,内部结构:输入层、一层隐藏层、输出层。
工作中拿到需求以后,短时间内想要快速看到效果,而且想以深度学习的方式实现,用该方式
3- Bert
Bert的网络结构、参数量比上面的两种都要复杂。也就是代码开发量、训练耗时等都要复杂一些,但是能够进行非常丰富的模型调优。
如果想要达到比较高的准确率,同时开发时间比较充裕,就用该方式
4- LLM大模型
如果只想通过写提示词的方式快速实现
代码结构图

配置文件类
# 该py脚本中 主要封装的是 原始数据路径(5个), 处理后的数据路径(6个), 模型保存路径(1, 父目录), 类别字典(1个)
class Config:
def __init__(self):
# 1.项目根目录
self.root_path = 'C:/Users/RockyChen/Desktop/新建文件夹/02-代码/TMF_Project/'
# 2.原始数据路径
self.train_datapath = self.root_path + '01-data/data/train.txt'
self.test_datapath = self.root_path + '01-data/data/test.txt'
self.dev_datapath = self.root_path + '01-data/data/dev.txt'
# 类别文档
self.class_doc_path = self.root_path + "01-data/data/class.txt"
# 3.数据处理保存路径
# 字符级别fasttext
self.process_train_datapath_char = "final_data/train_process_char.txt"
self.process_test_datapath_char = "final_data/test_process_char.txt"
self.process_dev_datapath_char = "final_data/dev_process_char.txt"
# 词级别fasttext
self.process_train_datapath_word = "final_data/train_process_word.txt"
self.process_test_datapath_word = "final_data/test_process_word.txt"
self.process_dev_datapath_word = "final_data/dev_process_word.txt"
# 4.模型路径
self.ft_model_save_path = 'save_models'
# 5.处理完的数据(用于训练)
self.final_data = 'final_data'
# 6.类别字典, 格式为: {0: 'business', 1: 'entertainment', 2: 'sports', 3: 'tech'...}
self.id2class_dict = {i:line.strip() for i, line in enumerate(open(self.class_doc_path))}
# 测试代码
if __name__ == '__main__':
config = Config()
print(config.train_datapath)
# {0: 'finance', 1: 'realty', 2: 'stocks', 3: 'education', 4: 'science', 5: 'society', 6: 'politics', 7: 'sports',
# 8: 'game', 9: 'entertainment'}
print(config.id2class_dict)
注意:上面配置文件中的路径,全部改成自己的。特别是注意root_path
数据预处理
使用 fastText 工具解决文本分类任务时,存放数据集的文本文件必须满足以下两个条件:
- 文本文件中的每一行对应一个文档;
- 文档的类别标签以
__label__name为前缀放在文档的最前面;
下面举两个符合条件的小例子。
单标签数据集:
__label__1 i love you
__label__0 i hate you
上面的单标签数据集中一共有 2 个文档(每一行一个文档),第一个文档 “i love you”,对应的类别标签为 1(具体类别名为 前缀后面的文本),第二个文档 “i hate you”,对应的类别标签为 0。
多标签数据集:
__label__baking __label__food-safety __label__substitutions __label__peanuts how to seperate peanut oil from roasted peanuts at home?
__label__chocolate American equivalent for British chocolate terms
__label__baking __label__oven __label__convection Fan bake vs bake
__label__sauce __label__storage-lifetime __label__acidity __label__mayonnaise Regulation and balancing of readymade packed mayonnaise and other sauces
多标签数据集中的不同的类别标签用空格来分割。比如:对于 “Regulation and balancing of readymade packed mayonnaise and other sauces” 文档的类别标签有 sauce、storage-lifetime、acidity 和 mayonnaise 5 个。
**单标签和多标签数据集在 fastText 的使用上并没有区别 **
所以需要将数据处理成上述形式。
"""
数据预处理要求:
原始数据:今天天气真的很好,8
处理后数据:__label__game 今天 天气 真的 很好
"""
import jieba
from config import Config
config = Config()
def preprocessing(datapath, process_datapath, is_char=True):
"""
FastText中有监督学习的数据预处理
:param datapath: 原始文件路径
:param process_datapath: 预处理后的文件路径
:param is_char: 是否是字级别的处理,默认True,也就是字级别。False使用jieba分词,词级别
:return: None
"""
# 1- 读取原始文件内容
with open(datapath,mode="r",encoding="UTF-8") as f:
lines = f.readlines()
# 2- 预处理
with open(process_datapath, mode="w", encoding="UTF-8") as f:
# 2.1- 遍历原始文件内容
for line in lines:
# 去除空行
# 注意:需要先执行strip(),避免空行中有空格的情况
line = line.strip()
if line=="":
continue
# 2.2- 拆分得到新闻标题和目标值
title,label = line.split("\t")
# 2.3- 对新闻标题进行处理
if is_char:
title = " ".join(list(title))
else:
title = " ".join(jieba.lcut(title))
# 2.4- 对目标值进行处理
# 字符串类型转成数字
label = int(label)
# 通过key获取对应的类别名称
label_name = config.id2label[label]
# 2.5- 目标值和新闻标题拼接成如下的格式
# __label__目标值 处理后的新闻标题
new_line = f"__label__{label_name} {title}\n"
# 2.6- 写入到新文件中
f.write(new_line)
if __name__ == '__main__':
# 字符级
preprocessing(datapath=config.train_datapath, process_datapath=config.process_char_train_datapath, is_char=True)
preprocessing(datapath=config.dev_datapath, process_datapath=config.process_char_dev_datapath, is_char=True)
preprocessing(datapath=config.test_datapath, process_datapath=config.process_char_test_datapath, is_char=True)
# 词级
preprocessing(datapath=config.train_datapath, process_datapath=config.process_word_train_datapath, is_char=False)
preprocessing(datapath=config.dev_datapath, process_datapath=config.process_word_dev_datapath, is_char=False)
preprocessing(datapath=config.test_datapath, process_datapath=config.process_word_test_datapath, is_char=False)
模型训练
字符级训练
手动指定参数
import fasttext
from config import Config
config = Config()
"""
使用Fasttext实现如下四种模型训练:
1- 字符级
1.1- 手动设置超参数 char_manual_train
1.2- 自动调整超参数 char_auto_train
2- 词级
2.1- 手动设置超参数 word_manual_train
2.2- 自动调整超参数 word_auto_train
"""
def char_manual_train():
# 1- 模型训练:有监督学习
"""
参数解释:
dim:词向量维度
epoch:训练轮次
minn、maxn:是n-gram中n的取值范围,左右都是闭区间。不管你输入进来的是啥,先在内容的前后增加<>,然后再分词
"""
model = fasttext.train_supervised(
input=config.process_char_train_datapath,
dim=100,
epoch=50,
minn=1,
maxn=4
)
# 2- 保存训练好的模型
model.save_model(config.model_char_manual_train)
# 3- 模型评估
# test返回值解释:样本条数、精确率、召回率
result = model.test(config.process_char_test_datapath)
print(f"字符级_手动设置超参数_评估结果:{result}")
# 4- 其他操作
# 4.1- 使用训练好的模型进行预测
pred_result = model.predict("房 山 纯 新 盘 绿 地 新 都 会 国 际 花 都 1 1 月 开 盘")
print(f"预测结果:{pred_result}")
# 注意:预测结果是一个列表,每个元素是一个元组,元组的第一个元素是类别名称,第二个元素是该类别别的概率
# 所以,如果要查看预测结果,需要遍历列表,打印每个元组的第一个元素
for item in pred_result:
print(item[0])
# 4.2- 查看模型词表信息
words = model.words
print(type(words)) # List列表
print(len(words))
print(words[:10])
# 4.3- 子词:查看minn和maxn的作用
print("子词",model.get_subwords("ab"))
# 4.4- 词的维度
print("词的维度",model.get_dimension())
参数自动调优
def char_auto_train():
# 1- 模型训练
"""
参数解释:
verbose:用来控制自动调参过程中日志的展示级别。该值越大,信息越丰富
"""
model = fasttext.train_supervised(
input=config.process_char_train_datapath,
autotuneValidationFile=config.process_char_dev_datapath,
autotuneDuration=3*60,
seed=115,
verbose=3
)
# 2- 保存训练好的模型
model.save_model(config.model_char_auto_train)
# 3- 评估
result = model.test(config.process_char_test_datapath)
print(f"字符级_自动设置超参数_评估结果:{result}")
词级训练
手动指定参数
def word_manual_train():
# 1- 模型训练:有监督学习
model = fasttext.train_supervised(
input=config.process_word_train_datapath,
dim=100,
epoch=50,
minn=1,
maxn=4
)
# 2- 保存训练好的模型
model.save_model(config.model_word_manual_train)
# 3- 模型评估
# test返回值解释:样本条数、精确率、召回率
result = model.test(config.process_word_test_datapath)
print(f"词级_手动设置超参数_评估结果:{result}")
# 4- 子词:查看minn和maxn的作用
print("子词", model.get_subwords("人工智能"))
参数自动调优
def word_auto_train():
# 1- 模型训练
"""
参数解释:
input:训练数据文件路径
autotuneValidationFile:验证集文件路径,用于自动调参过程中评估模型效果
autotuneDuration:自动调参的总时长(单位:秒),3*60=180秒=3分钟。时间越长,搜索的超参数组合越多,效果可能越好
seed:随机种子,保证每次自动调参的结果可复现
verbose:日志输出级别。值越大,输出的调参过程信息越详细
"""
model = fasttext.train_supervised(
input=config.process_word_train_datapath,
autotuneValidationFile=config.process_word_dev_datapath,
autotuneDuration=3 * 60,
seed=115,
verbose=3
)
# 2- 保存训练好的模型
model.save_model(config.model_word_auto_train)
# 3- 评估
result = model.test(config.process_word_test_datapath)
print(f"词级_自动设置超参数_评估结果:{result}")
测试代码
if __name__ == '__main__':
# 1- 字符级
# 手动设置超参数
# 字符级_手动设置超参数_评估结果:(10000, 0.8714, 0.8714)
char_manual_train()
# 自动调整超参数
# 字符级_自动设置超参数_评估结果:(10000, 0.873, 0.873)
char_auto_train()
# 2- 词级
# 手动设置超参数
# 词级_手动设置超参数_评估结果:(10000, 0.9103, 0.9103)
word_manual_train()
# 自动调整超参数
# 词级_自动设置超参数_评估结果:(10000, 0.9143, 0.9143)
word_auto_train()
模型预测
from config import Config
import fasttext
import jieba
config = Config()
# 1- 加载训练好的模型:因为词级的模型效果最好
model = fasttext.load_model(config.model_word_auto_train)
# 2- 预测函数
def predict(news_data):
"""
对用户输入的新闻标题进行分类预测
:param news_data: 字典。格式:{"title":新闻标题}
:return: 字典。格式:{"title":新闻标题, "pred_class":分类预测结果名称}
"""
# 1- 【可选】增加健壮性的代码
if not news_data.__contains__("title"):
news_data["error"] = "传递的参数中没有title字段"
return news_data
# 2- 取出新闻标题;数据预处理,也就是分词
title = " ".join(jieba.lcut(news_data["title"]))
# 3- 预测
# 返回值类型是嵌套元组。格式:(('__label__science',), array([0.81338769]))
pred_result = model.predict(title)
# print(type(pred_result))
# print(pred_result)
# 4- 取出预测结果
result = pred_result[0][0].replace("__label__","")
# 5- 返回结果
news_data["pred_class"] = result
return news_data
if __name__ == '__main__':
# news_data = {"title":"体验2D巅峰 倚天屠龙记十大创新概览"}
news_data = {"aaaa":"体验2D巅峰 倚天屠龙记十大创新概览"}
result = predict(news_data)
print(result)
模型部署
代码几乎与随机森林的相同。唯一的地方是将
from rf_predict_service import predict
改为
from ft_predict_service import predict